wardi/urwid — pull request #67 by eevee (2014-06-04 03:13:38+00:00)
Title: Make loop wrapping simpler, and make Screen easier to plug into async loops

I may have gone a little overboard here. And I'm sure I'm missing some obscure edge cases (e.g. would someone want to stop the `MainLoop` but not the screen?).

The goal was to make a basic asyncio example (run a server, serve an urwid app to an arbitrary number of clients) with a minimum of overriding obscure plumbing (cf: the Twisted example). I think I've done that :)

I shuffled things around a bit between `MainLoop` and `Screen`, made it possible to start and stop both without affecting the event loop, basically got rid of `run_wrapper`, rearranged `Screen`'s input-watching guts to be easier to override, and added an asyncio event loop implementation.

I tried to document what I was doing, and tried _extra hard_ to preserve compatibility — both with the existing loops and screens, and with any plausible subclasses that exist in the wild. The tour still works, even via `web_display`, and the Twisted example does as well. Alas, I don't have a Crystalfontz 635 LCD on hand. :)

I didn't manage to get rid of `enter_idle`, since it's not clear to me how `widget._invalidate()` could cleanly signal to the `MainLoop` that we need a redraw. So the asyncio implementation uses basically the same "idle" hack as Twisted.

I suspect a lot of the stuff in `raw_display.Screen` (and maybe `curses_display` as well?) could go away — there's a lot of code that exists for the case of not having an external event loop, but the same class _supports_ external event loops, so there's no reason that code should ever be called. Similarly, I wonder if the other screen implementations could just be made to work with an event loop now, and the duplicated `_run_screen_event_loop` code could go away too.