[tor-commits] [arm/release] Periodically refreshing display

atagar at torproject.org atagar at torproject.org
Sun Sep 25 21:38:24 UTC 2011


commit 3f93c66d2536ae85a0880b98425fedb507ad8503
Author: Damian Johnson <atagar at torproject.org>
Date:   Mon Aug 8 08:30:48 2011 -0700

    Periodically refreshing display
    
    On some platforms the terminal gets into a screwed up state, displaying
    scrambled content (I haven't reproduced this on my system, but seen it on an
    Ubuntu netbook).
    
    Redrawing the display, reguardless of if the content has changed every five
    seconds so this glitches will correct themselves. Arm had previously done this
    but I took it out when the display code had stabilized (to cut down on load).
    However, this doesn't have a noticeable cpu cost so might as well put it back.
    
    This also simplifies some of the redrawing logic, centralizing it in the
    controller.
---
 armrc.sample                       |    5 ++
 src/cli/controller.py              |   75 +++++++++++++++++++-----------------
 src/cli/graphing/bandwidthStats.py |    2 +-
 src/cli/graphing/graphPanel.py     |    2 +-
 src/cli/headerPanel.py             |    2 +-
 src/cli/menu/item.py               |    2 +-
 src/cli/menu/menu.py               |    2 +-
 src/cli/wizard.py                  |    6 +-
 8 files changed, 53 insertions(+), 43 deletions(-)

diff --git a/armrc.sample b/armrc.sample
index 1edd024..d547b6c 100644
--- a/armrc.sample
+++ b/armrc.sample
@@ -57,6 +57,11 @@ features.showFdUsage false
 # Seconds to wait on user input before refreshing content
 features.redrawRate 5
 
+# Rate (seconds) to periodically redraw the screen, disabled if zero. This
+# shouldn't be necessary, but can correct issues if the terminal gets into a
+# funky state.
+features.refreshRate 5
+
 # Confirms promt to confirm when quiting if true
 features.confirmQuit true
 
diff --git a/src/cli/controller.py b/src/cli/controller.py
index 1554949..d2c9d73 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -37,6 +37,7 @@ CONFIG = {"startup.events": "N3",
           "features.panels.show.config": True,
           "features.panels.show.torrc": True,
           "features.redrawRate": 5,
+          "features.refreshRate": 5,
           "features.confirmQuit": True,
           "features.graph.type": 1,
           "features.graph.bw.prepopulate": True,
@@ -171,6 +172,7 @@ class Controller:
     self._forceRedraw = False
     self._isDone = False
     self._torManager = TorManager(self)
+    self._lastDrawn = 0
     self.setMsg() # initializes our control message
   
   def getScreen(self):
@@ -310,39 +312,49 @@ class Controller:
     
     return allPanels
   
-  def requestRedraw(self, immediate = False):
+  def redraw(self, force = True):
     """
-    Requests that all content is redrawn when the interface is next rendered.
+    Redraws the displayed panel content.
     
     Arguments:
-      immediate - redraws now if true, otherwise waits for when next normally
-                  drawn
+      force - redraws reguardless of if it's needed if true, otherwise ignores
+              the request when there arne't changes to be displayed
     """
     
-    if immediate:
-      displayPanels = self.getDisplayPanels()
-      
-      occupiedContent = 0
-      for panelImpl in displayPanels:
-        panelImpl.setTop(occupiedContent)
-        occupiedContent += panelImpl.getHeight()
-      
-      for panelImpl in displayPanels:
-        panelImpl.redraw(True)
-    else:
-      self._forceRedraw = True
+    force |= self._forceRedraw
+    self._forceRedraw = False
+    
+    currentTime = time.time()
+    if CONFIG["features.refreshRate"] != 0:
+      if self._lastDrawn + CONFIG["features.refreshRate"] <= currentTime:
+        force = True
+    
+    displayPanels = self.getDisplayPanels()
+    
+    occupiedContent = 0
+    for panelImpl in displayPanels:
+      panelImpl.setTop(occupiedContent)
+      occupiedContent += panelImpl.getHeight()
+    
+    for panelImpl in displayPanels:
+      panelImpl.redraw(force)
+    
+    if force: self._lastDrawn = currentTime
   
-  def isRedrawRequested(self, clearFlag = False):
+  def requestRedraw(self):
+    """
+    Requests that all content is redrawn when the interface is next rendered.
     """
-    True if a full redraw has been requested, false otherwise.
     
-    Arguments:
-      clearFlag - request clears the flag if true
+    self._forceRedraw = True
+  
+  def getLastRedrawTime(self):
+    """
+    Provides the time when the content was last redrawn, zero if the content
+    has never been drawn.
     """
     
-    returnValue = self._forceRedraw
-    if clearFlag: self._forceRedraw = False
-    return returnValue
+    return self._lastDrawn
   
   def setMsg(self, msg = None, attr = None, redraw = False):
     """
@@ -612,7 +624,9 @@ def startTorMonitor(startTime):
   
   # initializes interface configs
   config = conf.getConfig("arm")
-  config.update(CONFIG)
+  config.update(CONFIG, {
+    "features.redrawRate": 1,
+    "features.refreshRate": 0})
   
   cli.graphing.graphPanel.loadConfig(config)
   cli.connections.connEntry.loadConfig(config)
@@ -710,17 +724,8 @@ def drawTorMonitor(stdscr, startTime):
     for panelImpl in control.getAllPanels():
       panelImpl.setVisible(panelImpl in displayPanels)
     
-    # panel placement
-    occupiedContent = 0
-    for panelImpl in displayPanels:
-      panelImpl.setTop(occupiedContent)
-      occupiedContent += panelImpl.getHeight()
-    
-    # redraws visible content
-    forceRedraw = control.isRedrawRequested(True)
-    for panelImpl in displayPanels:
-      panelImpl.redraw(forceRedraw)
-    
+    # redraws the interface if it's needed
+    control.redraw(False)
     stdscr.refresh()
     
     # wait for user keyboard input until timeout, unless an override was set
diff --git a/src/cli/graphing/bandwidthStats.py b/src/cli/graphing/bandwidthStats.py
index 654443c..9782d9f 100644
--- a/src/cli/graphing/bandwidthStats.py
+++ b/src/cli/graphing/bandwidthStats.py
@@ -100,7 +100,7 @@ class BandwidthStats(graphPanel.GraphStats):
         self.isAccounting = isAccountingEnabled
         
         # redraws the whole screen since our height changed
-        cli.controller.getController().requestRedraw(True)
+        cli.controller.getController().redraw()
     
     # redraws to reflect changes (this especially noticeable when we have
     # accounting and shut down since it then gives notice of the shutdown)
diff --git a/src/cli/graphing/graphPanel.py b/src/cli/graphing/graphPanel.py
index b080871..76221ff 100644
--- a/src/cli/graphing/graphPanel.py
+++ b/src/cli/graphing/graphPanel.py
@@ -324,7 +324,7 @@ class GraphPanel(panel.Panel):
           self.setGraphHeight(self.graphHeight - 1)
         elif uiTools.isSelectionKey(key): break
         
-        control.requestRedraw(True)
+        control.redraw()
     finally:
       control.setMsg()
       panel.CURSES_LOCK.release()
diff --git a/src/cli/headerPanel.py b/src/cli/headerPanel.py
index e64a6de..4e78f6c 100644
--- a/src/cli/headerPanel.py
+++ b/src/cli/headerPanel.py
@@ -427,7 +427,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
         # We're toggling between being a relay and client, causing the height
         # of this panel to change. Redraw all content so we don't get
         # overlapping content.
-        cli.controller.getController().requestRedraw(True)
+        cli.controller.getController().redraw()
       else:
         # just need to redraw ourselves
         self.redraw(True)
diff --git a/src/cli/menu/item.py b/src/cli/menu/item.py
index f46cdbb..1ed3f1f 100644
--- a/src/cli/menu/item.py
+++ b/src/cli/menu/item.py
@@ -58,7 +58,7 @@ class MenuItem():
     if self._callback:
       control = cli.controller.getController()
       control.setMsg()
-      control.requestRedraw(True)
+      control.redraw()
       self._callback()
     return True
   
diff --git a/src/cli/menu/menu.py b/src/cli/menu/menu.py
index 8302551..a93a1e0 100644
--- a/src/cli/menu/menu.py
+++ b/src/cli/menu/menu.py
@@ -114,7 +114,7 @@ def showMenu():
       cursor.handleKey(key)
       
       # redraws the rest of the interface if we're rendering on it again
-      if not cursor.isDone(): control.requestRedraw(True)
+      if not cursor.isDone(): control.redraw()
   finally:
     control.setMsg()
     cli.popups.finalize()
diff --git a/src/cli/wizard.py b/src/cli/wizard.py
index f0c14a8..82b2825 100644
--- a/src/cli/wizard.py
+++ b/src/cli/wizard.py
@@ -342,7 +342,7 @@ def showWizard():
         generatedTorrc = getTorrc(relayType, config, disabledOpt)
         
         torrcLocation = manager.getTorrcPath()
-        controller.requestRedraw(True)
+        controller.redraw()
         confirmationSelection = showConfirmationDialog(generatedTorrc, torrcLocation)
         
         if confirmationSelection == NEXT:
@@ -463,7 +463,7 @@ def showWizard():
         elif confirmationSelection == CANCEL: break
     
     # redraws screen to clear away the dialog we just showed
-    cli.controller.getController().requestRedraw(True)
+    cli.controller.getController().redraw()
 
 def promptRelayType(initialSelection):
   """
@@ -621,7 +621,7 @@ def promptConfigOptions(relayType, config, disabledOpt):
             try: options[selection].setValue(newValue.strip())
             except ValueError, exc:
               cli.popups.showMsg(str(exc), 3)
-              cli.controller.getController().requestRedraw(True)
+              cli.controller.getController().redraw()
       elif key == 27: selection, key = -1, curses.KEY_ENTER # esc - cancel
   finally:
     cli.popups.finalize()





More information about the tor-commits mailing list