Ian Ward wrote:
It's a good start. I was hoping this could be done with
get_input_descriptors[1] and get_input_nonblocking[2] instead of using
threads.
[1] http://excess.org/urwid/reference.html#Screen-get_input_descriptors
[2] http://excess.org/urwid/reference.html#Screen-get_input_nonblocking
Done. Also, this version adds a handle_reactor parameter. If False,
rather than looping the function simply returns a twisted Deferred that
will trigger when the UI shuts down, whether via an ExitMainLoop call
(callback True) or a different unhandled exception in one of the
handlers passed in (errback).
-Walter
# Urwid Twisted-based main loop function
# (c) 2008 Walter Mundt
import urwid
from twisted.internet import reactor
from twisted.internet.defer import Deferred
from twisted.python.failure import Failure
from twisted.internet.abstract import FileDescriptor
class InputDescriptor(FileDescriptor):
def __init__(self, fd, cb):
self._fileno = fd
self.cb = cb
FileDescriptor.__init__(self, reactor)
def fileno(self):
return self._fileno
def doRead(self):
return self.cb()
class TwistedLoopManager(object):
def __init__(self, screen, topmost_widget, input_filter, unhandled_input,
need_stop, handle_reactor):
self.screen = screen
self.topmost_widget = topmost_widget
self.failure = None
self.handle_reactor = handle_reactor
if input_filter:
self.input_filter = input_filter
if unhandled_input:
self.unhandled_input = unhandled_input
self.need_stop = need_stop
def input_filter(self, k):
return k
def unhandled_input(self, k):
pass
def stop(self, failure=None):
if self.need_stop:
self.screen.stop()
self.need_stop = False
self.running = False
if failure:
self.d.errback(failure)
else:
self.d.callback(True)
if self.handle_reactor:
reactor.stop()
self.handle_reactor = False
elif self.triggerid:
self.removeSystemEventTrigger(self.triggerid)
self.triggerid = None
def refresh(self):
if not self.running:
return
try:
canvas = self.topmost_widget.render(self.size, focus=True)
self.screen.draw_screen(self.size, canvas)
except urwid.main_loop.ExitMainLoop:
self.stop()
except:
self.stop(Failure())
def onShutdown(self):
if self.need_stop:
self.screen.stop()
self.need_stop = False
if self.running:
self.stop()
def inputCallback(self):
if self.running:
timeout, events, raw = self.screen.get_input_nonblocking()
if events:
for event in events:
self.onInput(event)
self.refresh()
def run(self):
self.d = Deferred()
self.running = True
self.triggerid = reactor.addSystemEventTrigger('before', 'shutdown', self.onShutdown)
self.size = self.screen.get_cols_rows()
self.refresh()
for desc in self.screen.get_input_descriptors():
id = InputDescriptor(desc, self.inputCallback)
reactor.addReader(id)
return self.d
def onInput(self, event):
if not self.running:
return
try:
if event == 'window resize':
self.size = self.screen.get_cols_rows()
event = self.input_filter(event)
if urwid.is_mouse_event(event):
if self.topmost_widget.mouse_event(self.size, focus=True, *event):
event = None
else:
event = self.topmost_widget.keypress(self.size, event)
if event:
self.unhandled_input(event)
except urwid.main_loop.ExitMainLoop:
self.stop()
except:
self.stop(Failure())
def twisted_main_loop(topmost_widget, palette=[], screen=None,
handle_mouse=True, input_filter=None, unhandled_input=None,
handle_reactor=True):
if not screen:
import urwid.raw_display
screen = urwid.raw_display.Screen()
if palette:
screen.register_palette(palette)
needstop = False
handleStartStop = not screen.started
if handleStartStop:
screen.start()
needstop = True
global mgr
mgr = TwistedLoopManager(screen, topmost_widget, input_filter,
unhandled_input, needstop, handle_reactor)
if handle_mouse:
screen.set_mouse_tracking()
d = mgr.run()
if handle_reactor:
d.addErrback(lambda fail: fail.printTraceback())
reactor.run()
else:
return d
_______________________________________________
Urwid mailing list
[email protected]
http://lists.excess.org/mailman/listinfo/urwid