commit 3f93c66d2536ae85a0880b98425fedb507ad8503
Author: Damian Johnson <atagar(a)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()