summaryrefslogtreecommitdiff
path: root/urwid/raw_display.py
diff options
context:
space:
mode:
Diffstat (limited to 'urwid/raw_display.py')
-rw-r--r--urwid/raw_display.py139
1 files changed, 101 insertions, 38 deletions
diff --git a/urwid/raw_display.py b/urwid/raw_display.py
index f267e4f..58b3112 100644
--- a/urwid/raw_display.py
+++ b/urwid/raw_display.py
@@ -54,6 +54,7 @@ class Screen(BaseScreen, RealTerminal):
"""
super(Screen, self).__init__()
self._pal_escape = {}
+ self._pal_attrspec = {}
signals.connect_signal(self, UPDATE_PALETTE_ENTRY,
self._on_update_palette_entry)
self.colors = 16 # FIXME: detect this
@@ -68,11 +69,14 @@ class Screen(BaseScreen, RealTerminal):
self.maxrow = None
self.gpm_mev = None
self.gpm_event_pending = False
+ self._mouse_tracking_enabled = False
self.last_bstate = 0
self._setup_G1_done = False
self._rows_used = None
self._cy = 0
- self.bright_is_bold = os.environ.get('TERM',None) != "xterm"
+ term = os.environ.get('TERM', '')
+ self.bright_is_bold = not term.startswith("xterm")
+ self.back_color_erase = not term.startswith("screen")
self._next_timeout = None
self._term_output_file = sys.stdout
self._term_input_file = sys.stdin
@@ -82,8 +86,9 @@ class Screen(BaseScreen, RealTerminal):
def _on_update_palette_entry(self, name, *attrspecs):
# copy the attribute to a dictionary containing the escape seqences
- self._pal_escape[name] = self._attrspec_to_escape(
- attrspecs[{16:0,1:1,88:2,256:3}[self.colors]])
+ a = attrspecs[{16:0,1:1,88:2,256:3}[self.colors]]
+ self._pal_attrspec[name] = a
+ self._pal_escape[name] = self._attrspec_to_escape(a)
def set_input_timeouts(self, max_wait=None, complete_wait=0.125,
resize_wait=0.125):
@@ -115,38 +120,56 @@ class Screen(BaseScreen, RealTerminal):
os.write(self._resize_pipe_wr, B('R'))
self._resized = True
self.screen_buf = None
-
+
+ def _sigcont_handler(self, signum, frame):
+ self.stop()
+ self.start()
+ self._sigwinch_handler(None, None)
+
def signal_init(self):
"""
- Called in the startup of run wrapper to set the SIGWINCH
- signal handler to self._sigwinch_handler.
+ Called in the startup of run wrapper to set the SIGWINCH
+ and SIGCONT signal handlers.
Override this function to call from main thread in threaded
applications.
"""
signal.signal(signal.SIGWINCH, self._sigwinch_handler)
-
+ signal.signal(signal.SIGCONT, self._sigcont_handler)
+
def signal_restore(self):
"""
Called in the finally block of run wrapper to restore the
- SIGWINCH handler to the default handler.
+ SIGWINCH and SIGCONT signal handlers.
Override this function to call from main thread in threaded
applications.
"""
+ signal.signal(signal.SIGCONT, signal.SIG_DFL)
signal.signal(signal.SIGWINCH, signal.SIG_DFL)
-
- def set_mouse_tracking(self):
+
+ def set_mouse_tracking(self, enable=True):
"""
- Enable mouse tracking.
-
+ Enable (or disable) mouse tracking.
+
After calling this function get_input will include mouse
click events along with keystrokes.
"""
- self._term_output_file.write(escape.MOUSE_TRACKING_ON)
+ enable = bool(enable)
+ if enable == self._mouse_tracking_enabled:
+ return
+
+ self._mouse_tracking(enable)
+ self._mouse_tracking_enabled = enable
+
+ def _mouse_tracking(self, enable):
+ if enable:
+ self._term_output_file.write(escape.MOUSE_TRACKING_ON)
+ self._start_gpm_tracking()
+ else:
+ self._term_output_file.write(escape.MOUSE_TRACKING_OFF)
+ self._stop_gpm_tracking()
- self._start_gpm_tracking()
-
def _start_gpm_tracking(self):
if not os.path.isfile("/usr/bin/mev"):
return
@@ -158,12 +181,14 @@ class Screen(BaseScreen, RealTerminal):
close_fds=True)
fcntl.fcntl(m.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
self.gpm_mev = m
-
+
def _stop_gpm_tracking(self):
+ if not self.gpm_mev:
+ return
os.kill(self.gpm_mev.pid, signal.SIGINT)
os.waitpid(self.gpm_mev.pid, 0)
self.gpm_mev = None
-
+
def start(self, alternate_buffer=True):
"""
Initialize the screen and input mode.
@@ -193,7 +218,8 @@ class Screen(BaseScreen, RealTerminal):
super(Screen, self).start()
signals.emit_signal(self, INPUT_DESCRIPTORS_CHANGED)
-
+ # restore mouse tracking to previous state
+ self._mouse_tracking(self._mouse_tracking_enabled)
def stop(self):
"""
@@ -212,19 +238,19 @@ class Screen(BaseScreen, RealTerminal):
termios.tcsetattr(fd, termios.TCSADRAIN,
self._old_termios_settings)
+ self._mouse_tracking(False)
+
move_cursor = ""
- if self.gpm_mev:
- self._stop_gpm_tracking()
if self._alternate_buffer:
move_cursor = escape.RESTORE_NORMAL_BUFFER
elif self.maxrow is not None:
- move_cursor = escape.set_cursor_position(
+ move_cursor = escape.set_cursor_position(
0, self.maxrow)
- self._term_output_file.write(self._attrspec_to_escape(AttrSpec('',''))
+ self._term_output_file.write(
+ self._attrspec_to_escape(AttrSpec('',''))
+ escape.SI
- + escape.MOUSE_TRACKING_OFF
- + escape.SHOW_CURSOR
- + move_cursor + "\n" + escape.SHOW_CURSOR )
+ + move_cursor
+ + escape.SHOW_CURSOR)
self._input_iter = self._fake_input_iter()
if self._old_signal_keys:
@@ -235,7 +261,7 @@ class Screen(BaseScreen, RealTerminal):
def run_wrapper(self, fn, alternate_buffer=True):
"""
- Call start to initialize screen, then call fn.
+ Call start to initialize screen, then call fn.
When fn exits call stop to restore the screen to normal.
alternate_buffer -- use alternate screen buffer and restore
@@ -328,7 +354,7 @@ class Screen(BaseScreen, RealTerminal):
Return a list of integer file descriptors that should be
polled in external event loops to check for user input.
- Use this method if you are implementing yout own event loop.
+ Use this method if you are implementing your own event loop.
"""
if not self._started:
return []
@@ -357,7 +383,7 @@ class Screen(BaseScreen, RealTerminal):
def _run_input_iter(self):
def empty_resize_pipe():
# clean out the pipe used to signal external event loops
- # that a resize has occured
+ # that a resize has occurred
try:
while True: os.read(self._resize_pipe_rd, 1)
except OSError:
@@ -484,7 +510,18 @@ class Screen(BaseScreen, RealTerminal):
b |= mod
l.extend([ 27, ord('['), ord('M'), b+32, x+32, y+32 ])
- if ev == 20: # press
+ def determine_button_release( flag ):
+ if b & 4 and last & 1:
+ append_button( 0 + flag )
+ next |= 1
+ if b & 2 and last & 2:
+ append_button( 1 + flag )
+ next |= 2
+ if b & 1 and last & 4:
+ append_button( 2 + flag )
+ next |= 4
+
+ if ev == 20 or ev == 36 or ev == 52: # press
if b & 4 and last & 1 == 0:
append_button( 0 )
next |= 1
@@ -511,7 +548,21 @@ class Screen(BaseScreen, RealTerminal):
if b & 1 and last & 4:
append_button( 2 + escape.MOUSE_RELEASE_FLAG )
next &= ~ 4
-
+ if ev == 40: # double click (release)
+ if b & 4 and last & 1:
+ append_button( 0 + escape.MOUSE_MULTIPLE_CLICK_FLAG )
+ if b & 2 and last & 2:
+ append_button( 1 + escape.MOUSE_MULTIPLE_CLICK_FLAG )
+ if b & 1 and last & 4:
+ append_button( 2 + escape.MOUSE_MULTIPLE_CLICK_FLAG )
+ elif ev == 52:
+ if b & 4 and last & 1:
+ append_button( 0 + escape.MOUSE_MULTIPLE_CLICK_FLAG*2 )
+ if b & 2 and last & 2:
+ append_button( 1 + escape.MOUSE_MULTIPLE_CLICK_FLAG*2 )
+ if b & 1 and last & 4:
+ append_button( 2 + escape.MOUSE_MULTIPLE_CLICK_FLAG*2 )
+
self.last_bstate = next
return l
@@ -521,8 +572,14 @@ class Screen(BaseScreen, RealTerminal):
def get_cols_rows(self):
"""Return the terminal dimensions (num columns, num rows)."""
- buf = fcntl.ioctl(0, termios.TIOCGWINSZ, ' '*4)
- y, x = struct.unpack('hh', buf)
+ y, x = 80, 24
+ try:
+ buf = fcntl.ioctl(self._term_output_file.fileno(),
+ termios.TIOCGWINSZ, ' '*4)
+ y, x = struct.unpack('hh', buf)
+ except IOError:
+ # Term size could not be determined
+ pass
self.maxrow = y
return x, y
@@ -616,6 +673,10 @@ class Screen(BaseScreen, RealTerminal):
return self._attrspec_to_escape(
AttrSpec('default','default'))
+ def using_standout(a):
+ a = self._pal_attrspec.get(a, a)
+ return isinstance(a, AttrSpec) and a.standout
+
ins = None
o.append(set_cursor_home())
cy = 0
@@ -644,12 +705,14 @@ class Screen(BaseScreen, RealTerminal):
cy = y
whitespace_at_end = False
- if row and row[-1][2][-1:] == B(' '):
- whitespace_at_end = True
+ if row:
a, cs, run = row[-1]
- row = row[:-1] + [(a, cs, run.rstrip(B(' ')))]
- elif y == maxrow-1 and maxcol>1:
- row, back, ins = self._last_row(row)
+ if (run[-1:] == B(' ') and self.back_color_erase
+ and not using_standout(a)):
+ whitespace_at_end = True
+ row = row[:-1] + [(a, cs, run.rstrip(B(' ')))]
+ elif y == maxrow-1 and maxcol > 1:
+ row, back, ins = self._last_row(row)
first = True
lasta = lastcs = None
@@ -872,7 +935,7 @@ class Screen(BaseScreen, RealTerminal):
"""
entries - list of (index, red, green, blue) tuples.
- Attempt to set part of the terminal pallette (this does not work
+ Attempt to set part of the terminal palette (this does not work
on all terminals.) The changes are sent as a single escape
sequence so they should all take effect at the same time.