commit 5d9c3dde6315b1ceb9ba9017823ea036501b909c Author: Damian Johnson atagar@torproject.org Date: Thu Mar 17 09:53:18 2016 -0700
Move raw curses usage behind raw_screen()
Providing a function for raw access to the curses screen rather than passing a reference around. This is an intermediate step since we want to abstract this all away but for now better to have them go through nyx.curses to get this. --- nyx/controller.py | 46 +++++++++++++++++----------------------------- nyx/curses.py | 35 ++++++++++++++++++++++++++++++++--- nyx/panel/__init__.py | 14 ++++++++------ nyx/panel/config.py | 4 ++-- nyx/panel/connection.py | 4 ++-- nyx/panel/graph.py | 4 ++-- nyx/panel/header.py | 4 ++-- nyx/panel/log.py | 4 ++-- nyx/panel/torrc.py | 4 ++-- nyx/popups.py | 2 +- 10 files changed, 70 insertions(+), 51 deletions(-)
diff --git a/nyx/controller.py b/nyx/controller.py index 602c85e..32f4db5 100644 --- a/nyx/controller.py +++ b/nyx/controller.py @@ -63,8 +63,8 @@ class LabelPanel(nyx.panel.Panel): Panel that just displays a single line of text. """
- def __init__(self, stdscr): - nyx.panel.Panel.__init__(self, stdscr, 'msg', 0, height=1) + def __init__(self): + nyx.panel.Panel.__init__(self, 'msg', 0, height=1) self.msg_text = '' self.msg_attr = NORMAL
@@ -92,41 +92,36 @@ class Controller: Tracks the global state of the interface """
- def __init__(self, stdscr): + def __init__(self): """ Creates a new controller instance. Panel lists are ordered as they appear, top to bottom on the page. - - Arguments: - stdscr - curses window """
- self._screen = stdscr - self._sticky_panels = [ - nyx.panel.header.HeaderPanel(stdscr), - LabelPanel(stdscr), + nyx.panel.header.HeaderPanel(), + LabelPanel(), ]
self._page_panels, first_page_panels = [], []
if CONFIG['features.panels.show.graph']: - first_page_panels.append(nyx.panel.graph.GraphPanel(stdscr)) + first_page_panels.append(nyx.panel.graph.GraphPanel())
if CONFIG['features.panels.show.log']: - first_page_panels.append(nyx.panel.log.LogPanel(stdscr)) + first_page_panels.append(nyx.panel.log.LogPanel())
if first_page_panels: self._page_panels.append(first_page_panels)
if CONFIG['features.panels.show.connection']: - self._page_panels.append([nyx.panel.connection.ConnectionPanel(stdscr)]) + self._page_panels.append([nyx.panel.connection.ConnectionPanel()])
if CONFIG['features.panels.show.config']: - self._page_panels.append([nyx.panel.config.ConfigPanel(stdscr)]) + self._page_panels.append([nyx.panel.config.ConfigPanel()])
if CONFIG['features.panels.show.torrc']: - self._page_panels.append([nyx.panel.torrc.TorrcPanel(stdscr)]) + self._page_panels.append([nyx.panel.torrc.TorrcPanel()])
self.quit_signal = False self._page = 0 @@ -135,13 +130,6 @@ class Controller: self._last_drawn = 0 self.set_msg() # initializes our control message
- def get_screen(self): - """ - Provides our curses window. - """ - - return self._screen - def get_page_count(self): """ Provides the number of pages the interface has. This may be zero if all @@ -306,7 +294,8 @@ class Controller: # https://trac.torproject.org/projects/tor/ticket/2830#comment:9
if force: - self._screen.clear() + with nyx.curses.raw_screen() as stdscr: + stdscr.clear()
for panel_impl in display_panels: panel_impl.redraw(force) @@ -365,17 +354,14 @@ class Controller: return halt_thread
-def start_nyx(stdscr): +def start_nyx(): """ Main draw loop context. - - Arguments: - stdscr - curses window """
global NYX_CONTROLLER
- NYX_CONTROLLER = Controller(stdscr) + NYX_CONTROLLER = Controller() control = get_controller()
if not CONFIG['features.acsSupport']: @@ -411,7 +397,9 @@ def start_nyx(stdscr): # redraws the interface if it's needed
control.redraw(False) - stdscr.refresh() + + with nyx.curses.raw_screen() as stdscr: + stdscr.refresh()
# wait for user keyboard input until timeout, unless an override was set
diff --git a/nyx/curses.py b/nyx/curses.py index 97ad02a..4d9571b 100644 --- a/nyx/curses.py +++ b/nyx/curses.py @@ -9,6 +9,7 @@ if we want Windows support in the future too. ::
start - initializes curses with the given function + raw_screen - provides direct access to the curses screen key_input - get keypress by user curses_attr - curses encoded text attribute
@@ -139,8 +140,7 @@ CONFIG = stem.util.conf.config_dict('nyx', {
def start(function, transparent_background = False, cursor = True): """ - Starts a curses interface, delegating to the given function. The function - should accept a single argument for the curses screen. + Starts a curses interface, delegating to the given function.
:param funtion: function to invoke when curses starts :param bool transparent_background: allows background transparency @@ -164,11 +164,40 @@ def start(function, transparent_background = False, cursor = True): except curses.error: pass
- function(stdscr) + function()
curses.wrapper(_wrapper)
+def raw_screen(): + """ + Provides the curses screen. This can only be called after + :func:`~nyx.curses.start`, and is used as follows... + + :: + + with nyx.curses.raw_screen() as stdscr: + ... work with curses... + + In the future this will never be called directly. This is just an + intermediate function as we migrate. + """ + + class _Wrapper(object): + def __enter__(self): + # TODO: We should be wrapping this with CURSES_LOCK.acquire/release(), + # but doing so seems to be causing frequent terminal gliches when + # shutting down. Strange since this should be strictly safer. Oh well - + # something to dig into later. + + return CURSES_SCREEN + + def __exit__(self, exit_type, value, traceback): + pass + + return _Wrapper() + + def key_input(input_timeout = None): """ Gets a key press from the user. diff --git a/nyx/panel/__init__.py b/nyx/panel/__init__.py index 176eea9..bab0cc7 100644 --- a/nyx/panel/__init__.py +++ b/nyx/panel/__init__.py @@ -122,12 +122,11 @@ class Panel(object): redraw(). """
- def __init__(self, parent, name, top, left = 0, height = -1, width = -1): + def __init__(self, name, top, left = 0, height = -1, width = -1): """ Creates a durable wrapper for a curses subwindow in the given parent.
Arguments: - parent - parent curses window name - identifier for the panel top - positioning of top within parent left - positioning of the left edge within the parent @@ -140,7 +139,6 @@ class Panel(object): # might chose their height based on its parent's current width).
self.panel_name = name - self.parent = parent self.visible = False self.title_visible = True
@@ -358,7 +356,9 @@ class Panel(object): returns a tuple of (height, width). """
- new_height, new_width = self.parent.getmaxyx() + with nyx.curses.raw_screen() as stdscr: + new_height, new_width = stdscr.getmaxyx() + set_height, set_width = self.get_height(), self.get_width() new_height = max(0, new_height - self.top) new_width = max(0, new_width - self.left) @@ -601,7 +601,8 @@ class Panel(object):
display_width = self.get_preferred_size()[1]
- input_subwindow = self.parent.subwin(1, display_width - x, self.top + y, self.left + x) + with nyx.curses.raw_screen() as stdscr: + input_subwindow = stdscr.subwin(1, display_width - x, self.top + y, self.left + x)
# blanks the field's area, filling it with the font in case it's hilighting
@@ -744,7 +745,8 @@ class Panel(object): # would mean far more complicated code and no more selective refreshing)
if recreate: - self.win = self.parent.subwin(new_height, new_width, self.top, self.left) + with nyx.curses.raw_screen() as stdscr: + self.win = stdscr.subwin(new_height, new_width, self.top, self.left)
# note: doing this log before setting win produces an infinite loop stem.util.log.debug("recreating panel '%s' with the dimensions of %i/%i" % (self.get_name(), new_height, new_width)) diff --git a/nyx/panel/config.py b/nyx/panel/config.py index 5b8a636..fc6dad1 100644 --- a/nyx/panel/config.py +++ b/nyx/panel/config.py @@ -118,8 +118,8 @@ class ConfigPanel(nyx.panel.Panel): Editor for tor's configuration. """
- def __init__(self, stdscr): - nyx.panel.Panel.__init__(self, stdscr, 'configuration', 0) + def __init__(self): + nyx.panel.Panel.__init__(self, 'configuration', 0)
self._contents = [] self._scroller = nyx.curses.CursorScroller() diff --git a/nyx/panel/connection.py b/nyx/panel/connection.py index e3124d9..09efafb 100644 --- a/nyx/panel/connection.py +++ b/nyx/panel/connection.py @@ -259,8 +259,8 @@ class ConnectionPanel(nyx.panel.Panel, threading.Thread): the current consensus and other data sources. """
- def __init__(self, stdscr): - nyx.panel.Panel.__init__(self, stdscr, 'connections', 0) + def __init__(self): + nyx.panel.Panel.__init__(self, 'connections', 0) threading.Thread.__init__(self) self.setDaemon(True)
diff --git a/nyx/panel/graph.py b/nyx/panel/graph.py index 20a64c0..e4a0ce7 100644 --- a/nyx/panel/graph.py +++ b/nyx/panel/graph.py @@ -381,8 +381,8 @@ class GraphPanel(nyx.panel.Panel): Panel displaying graphical information of GraphCategory instances. """
- def __init__(self, stdscr): - nyx.panel.Panel.__init__(self, stdscr, 'graph', 0) + def __init__(self): + nyx.panel.Panel.__init__(self, 'graph', 0)
self._displayed_stat = None if CONFIG['features.graph.type'] == 'none' else CONFIG['features.graph.type'] self._update_interval = CONFIG['features.graph.interval'] diff --git a/nyx/panel/header.py b/nyx/panel/header.py index 51245ee..c3bba36 100644 --- a/nyx/panel/header.py +++ b/nyx/panel/header.py @@ -37,8 +37,8 @@ class HeaderPanel(nyx.panel.Panel, threading.Thread): Top area containing tor settings and system information. """
- def __init__(self, stdscr): - nyx.panel.Panel.__init__(self, stdscr, 'header', 0) + def __init__(self): + nyx.panel.Panel.__init__(self, 'header', 0) threading.Thread.__init__(self) self.setDaemon(True)
diff --git a/nyx/panel/log.py b/nyx/panel/log.py index 3ab53f3..d6e00de 100644 --- a/nyx/panel/log.py +++ b/nyx/panel/log.py @@ -64,8 +64,8 @@ class LogPanel(nyx.panel.Panel, threading.Thread): from tor's log file if it exists. """
- def __init__(self, stdscr): - nyx.panel.Panel.__init__(self, stdscr, 'log', 0) + def __init__(self): + nyx.panel.Panel.__init__(self, 'log', 0) threading.Thread.__init__(self) self.setDaemon(True)
diff --git a/nyx/panel/torrc.py b/nyx/panel/torrc.py index 033fd94..f52b6fb 100644 --- a/nyx/panel/torrc.py +++ b/nyx/panel/torrc.py @@ -20,8 +20,8 @@ class TorrcPanel(panel.Panel): area. """
- def __init__(self, stdscr): - panel.Panel.__init__(self, stdscr, 'torrc', 0) + def __init__(self): + panel.Panel.__init__(self, 'torrc', 0)
self._scroller = nyx.curses.Scroller() self._show_line_numbers = True # shows left aligned line numbers diff --git a/nyx/popups.py b/nyx/popups.py index f29c9c8..6190a09 100644 --- a/nyx/popups.py +++ b/nyx/popups.py @@ -54,7 +54,7 @@ def popup_window(height = -1, width = -1, top = 0, left = 0, below_static = True else: sticky_height = 0
- popup = nyx.panel.Panel(control.get_screen(), 'popup', top + sticky_height, left, height, width) + popup = nyx.panel.Panel('popup', top + sticky_height, left, height, width) popup.set_visible(True)
# Redraws the popup to prepare a subwindow instance. If none is spawned then
tor-commits@lists.torproject.org