Don't modify status widgets outside of main thread
The sync module would indirectly modify the status widget (so that the count of sync actions would be up to date). If this happened while urwid was drawing the screen, urwid may invalidate cached information in mid-redraw, resulting in an exception and crash. This updates the StatusHeader widget so that changes are merely recorded to internal variables, and the actual widgets are updated by a refresh method called from within the main loop. Change-Id: I27043533d33d44aae31005670a1b727e9cc7bb90 Story: 260
This commit is contained in:
parent
949cea5475
commit
6f52a7c870
@ -53,27 +53,55 @@ class StatusHeader(urwid.WidgetWrap):
|
||||
def __init__(self, app):
|
||||
super(StatusHeader, self).__init__(urwid.Columns([]))
|
||||
self.app = app
|
||||
self.title = urwid.Text(u'Start')
|
||||
self.error = urwid.Text('')
|
||||
self.offline = urwid.Text('')
|
||||
self.sync = urwid.Text(u'Sync: 0')
|
||||
self._w.contents.append((self.title, ('pack', None, False)))
|
||||
self.title_widget = urwid.Text(u'Start')
|
||||
self.error_widget = urwid.Text('')
|
||||
self.offline_widget = urwid.Text('')
|
||||
self.sync_widget = urwid.Text(u'Sync: 0')
|
||||
self._w.contents.append((self.title_widget, ('pack', None, False)))
|
||||
self._w.contents.append((urwid.Text(u''), ('weight', 1, False)))
|
||||
self._w.contents.append((self.error, ('pack', None, False)))
|
||||
self._w.contents.append((self.offline, ('pack', None, False)))
|
||||
self._w.contents.append((self.sync, ('pack', None, False)))
|
||||
self._w.contents.append((self.error_widget, ('pack', None, False)))
|
||||
self._w.contents.append((self.offline_widget, ('pack', None, False)))
|
||||
self._w.contents.append((self.sync_widget, ('pack', None, False)))
|
||||
self.error = None
|
||||
self.offline = None
|
||||
self.title = None
|
||||
self.sync = None
|
||||
self._error = False
|
||||
self._offline = False
|
||||
self._title = ''
|
||||
self._sync = 0
|
||||
|
||||
def update(self, title=None, error=False, offline=None):
|
||||
if title:
|
||||
self.title.set_text(title)
|
||||
if error:
|
||||
self.error.set_text(('error', u'Error'))
|
||||
def update(self, title=None, error=None, offline=None, refresh=True):
|
||||
if title is not None:
|
||||
self.title = title
|
||||
if error is not None:
|
||||
self.error = error
|
||||
if offline is not None:
|
||||
if offline:
|
||||
self.error.set_text(u'Offline')
|
||||
self.offline = offline
|
||||
self.sync = self.app.sync.queue.qsize()
|
||||
if refresh:
|
||||
self.refresh()
|
||||
|
||||
def refresh(self):
|
||||
if self._title != self.title:
|
||||
self._title = self.title
|
||||
self.title_widget.set_text(self._title)
|
||||
if self._error != self.error:
|
||||
self._error = self.error
|
||||
if self.error:
|
||||
self.error_widget.set_text(('error', u'Error'))
|
||||
else:
|
||||
self.error.set_text(u'')
|
||||
self.sync.set_text(u' Sync: %i' % self.app.sync.queue.qsize())
|
||||
self.error_widget.set_text(u'')
|
||||
if self._offline != self.offline:
|
||||
self._offline = self.offline
|
||||
if self._offline:
|
||||
self.offline_widget.set_text(u'Offline')
|
||||
else:
|
||||
self.offline_widget.set_text(u'')
|
||||
if self._sync != self.sync:
|
||||
self._sync = self.sync
|
||||
self.sync_widget.set_text(u' Sync: %i' % self._sync)
|
||||
|
||||
|
||||
class SearchDialog(mywid.ButtonDialog):
|
||||
signals = ['search', 'cancel']
|
||||
@ -194,6 +222,7 @@ class App(object):
|
||||
self.loop.widget = widget
|
||||
|
||||
def refresh(self, data=None):
|
||||
self.status.refresh()
|
||||
widget = self.loop.widget
|
||||
while isinstance(widget, urwid.Overlay):
|
||||
widget = widget.contents[0][0]
|
||||
|
@ -790,16 +790,16 @@ class Sync(object):
|
||||
self.submitTask(SyncSubscribedProjectsTask(HIGH_PRIORITY))
|
||||
self.submitTask(UploadReviewsTask(HIGH_PRIORITY))
|
||||
self.offline = True
|
||||
self.app.status.update(offline=True)
|
||||
self.app.status.update(offline=True, refresh=False)
|
||||
os.write(pipe, 'refresh\n')
|
||||
time.sleep(30)
|
||||
return task
|
||||
except Exception:
|
||||
task.complete(False)
|
||||
self.log.exception('Exception running task %s' % (task,))
|
||||
self.app.status.update(error=True)
|
||||
self.app.status.update(error=True, refresh=False)
|
||||
self.offline = False
|
||||
self.app.status.update(offline=False)
|
||||
self.app.status.update(offline=False, refresh=False)
|
||||
os.write(pipe, 'refresh\n')
|
||||
return None
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user