I just hacked this up last night so no guarantees that it's perfect...but here's a twisted_main_loop that's very similar in nature and functionality to the generic_main_loop in the current urwid checkout -- except that everything run from inside of it happens in the context of a Twisted reactor.

It places a blocking input loop in a separate thread, but arranges for the actual input processing to happen inside the main reactor thread so that this shouldn't cause any real issues.

It definitely needs some refinement, but I thought I'd make it available in case anyone has a use for it.

--
Walter Mundt
[EMAIL PROTECTED]
# Urwid Twisted-based main loop function
# (c) 2008 Walter Mundt

import threading
import sys
import os

import urwid

from twisted.internet import reactor, threads
from twisted.internet.defer import Deferred
from twisted.python.failure import Failure

class TwistedLoopManager(object):
    def __init__(self, screen, topmost_widget, input_filter, unhandled_input, need_stop):
        self.screen = screen
        self.topmost_widget = topmost_widget
        self.failure = None
        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 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.running = False
        except:
            self.running = False
            self.failure = Failure()

    def onShutdown(self):
        self.running = False
        if self.need_stop:
            self.screen.stop()
        if self.failure:
            self.d.errback(self.failure)
        else:
            self.d.callback(True)

    def run(self):
        self.d = Deferred()
        self.size = self.screen.get_cols_rows()
        self.running = True
        self.refresh()
        self.inputThread = threading.Thread(target=self.inputLoop, name="inputLoop")
        reactor.addSystemEventTrigger('before', 'shutdown', self.onShutdown)
        self.inputThread.start()
        return self.d

    def inputLoop(self):
        try:
            while self.running:
                threads.blockingCallFromThread(reactor, self.refresh)
                events = None
                while not events and self.running:
                    events = self.screen.get_input()
                if self.running:
                    for event in events:
                        threads.blockingCallFromThread(reactor, self.onInput, event)
        finally:
            reactor.callFromThread(reactor.stop)
            
    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.running = False
        except:
            self.running = False
            self.failure = Failure()

def twisted_main_loop(topmost_widget, palette=[], screen=None,
               handle_mouse=True, input_filter=None, unhandled_input=None):
    if not screen:
        import urwid.raw_display
        screen = urwid.raw_display.Screen()

    if palette:
        screen.register_palette(palette)

    handleStartStop = not screen.started
    if handleStartStop:
        screen.start()
        needStop = True

    global mgr
    mgr = TwistedLoopManager(screen, topmost_widget, input_filter, unhandled_input, needStop)

    if handle_mouse:
        screen.set_mouse_tracking()

    d = mgr.run()
    d.addErrback(lambda x: True)
    reactor.run()
    if mgr.failure:
        mgr.failure.printTraceback()


_______________________________________________
Urwid mailing list
[email protected]
http://lists.excess.org/mailman/listinfo/urwid

Reply via email to