[Python-modules-team] Bug#789767: urwid uploaded to DELAYED/15

Gianfranco Costamagna costamagnagianfranco at yahoo.it
Wed Sep 16 10:03:31 UTC 2015


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi,

since there has been no maintainer response since months, I did
prepare an update (Team Upload, since the package is team maintained)
and pushed on DELAYED/15.

Please review it (I'm attaching the full debdiff and the Debian only
debdiff for your best convenience), and let me know if I should cancel
it or delay any longer.

List of changes:
  * Team upload.
  * Refactor rules file to use pybuild.
  * Remove cdbs to build.
  * New upstream release. (Closes: #789767)
  * watch file: use pypi debian redirectory
  * Bump compat level to 9
  * Update standard version to 3.9.6, no changes required.


This refactor also fixed some issues, e.g. wrong permission bits for
the installed files.


cheers,

Gianfranco
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQIcBAEBCAAGBQJV+T5yAAoJEPNPCXROn13ZZjIP/1WWTmxQxqpzu6gnnr+T2Ujm
2te/AOw2bKg5D2SqAEVsO4Vrzu9wzrqKvHjnEPSXhiJtqroxhNIQGt53qrDvJ3Ez
T52AfF41QB2i4y7ifc4lY/RUBxxw4ItQ4D17CROhfPk+GltejMLyuHFPsuJzp6mW
Wp2mEavbiPDuxJszDSKGNlQVbpJdxSU1eRWwAXYGlfPtAJKCgxURAxch0PY3j567
2pTU/dVqZWcYwLdR80Y3CTDF5u5Jv1iq830V5KIssIvIhFLw4ZlmQp0JYUoVpSpb
v8KOUGnGQMvwUfnFbIl/w0IYXTbfLx/AHhUKaXQ+3O4UI3iJSFEV5Lh7emLM9ZTH
PLR5u5kns8E/BCvn71eKjoBcbP/XaaJIV5whhfSRvzs78hzYWhdiYHsNHXdHrAj3
k0SbOUYq0uTQuFF4B2bQRrYc8iVKN83oxPElm0F4IbsHyuoQorbNzLqFNGZcM4PT
OyPY7vJQ1ZMey8FXjCZdG6vl1mz2nDbYwQziEGLwvZ1aKbcg4wiyOjFGPs5Xh2VE
b8BN0sCUS/2fbXLHsk4kpQODi03lY7udqcnYVCY2mbZgeUvcgHj6KYZntfFNFGws
21kD3UD9lYdFdtdpcQB9HT8PgsCgmppOlSQjFNGd2Cux7gvSoaYAJs3sOs8BYa00
y0e/dEHMizfmpIGJTiCq
=5PL5
-----END PGP SIGNATURE-----
-------------- next part --------------
diff -Nru urwid-1.2.1/debian/changelog urwid-1.3.0/debian/changelog
--- urwid-1.2.1/debian/changelog	2014-05-18 11:08:47.000000000 +0200
+++ urwid-1.3.0/debian/changelog	2015-09-16 11:57:47.000000000 +0200
@@ -1,3 +1,15 @@
+urwid (1.3.0-1) unstable; urgency=medium
+
+  * Team upload.
+  * Refactor rules file to use pybuild.
+  * Remove cdbs to build.
+  * New upstream release. (Closes: #789767)
+  * watch file: use pypi debian redirectory
+  * Bump compat level to 9
+  * Update standard version to 3.9.6, no changes required.
+
+ -- Gianfranco Costamagna <locutusofborg at debian.org>  Tue, 15 Sep 2015 16:04:33 +0200
+
 urwid (1.2.1-2) unstable; urgency=medium
 
   * Team upload.
diff -Nru urwid-1.2.1/debian/compat urwid-1.3.0/debian/compat
--- urwid-1.2.1/debian/compat	2014-04-04 18:49:51.000000000 +0200
+++ urwid-1.3.0/debian/compat	2015-09-16 11:57:09.000000000 +0200
@@ -1 +1 @@
-5
+9
diff -Nru urwid-1.2.1/debian/control urwid-1.3.0/debian/control
--- urwid-1.2.1/debian/control	2014-04-04 19:08:58.000000000 +0200
+++ urwid-1.3.0/debian/control	2015-09-16 11:57:09.000000000 +0200
@@ -4,8 +4,7 @@
 Maintainer: Debian Python Modules Team <python-modules-team at lists.alioth.debian.org>
 Uploaders: Ian Ward <ian at excess.org>
 Build-Depends:
- cdbs (>= 0.4.90~),
- debhelper (>= 5.0.37.2),
+ debhelper (>= 9),
  python-all-dev (>= 2.6.6-3~),
  python-gobject,
  python-setuptools (>= 0.6.16),
@@ -13,7 +12,7 @@
  python-twisted,
  python3-all-dev (>= 3.2),
  python3-setuptools
-Standards-Version: 3.9.5
+Standards-Version: 3.9.6
 Homepage: http://excess.org/urwid/
 Vcs-Svn: svn://anonscm.debian.org/python-modules/packages/urwid/trunk/
 Vcs-Browser: http://anonscm.debian.org/viewvc/python-modules/packages/urwid/trunk/
diff -Nru urwid-1.2.1/debian/python3-urwid.install urwid-1.3.0/debian/python3-urwid.install
--- urwid-1.2.1/debian/python3-urwid.install	2014-04-04 19:02:24.000000000 +0200
+++ urwid-1.3.0/debian/python3-urwid.install	1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-debian/tmp/usr/lib/python3*
diff -Nru urwid-1.2.1/debian/python-urwid.install urwid-1.3.0/debian/python-urwid.install
--- urwid-1.2.1/debian/python-urwid.install	2014-04-04 19:02:24.000000000 +0200
+++ urwid-1.3.0/debian/python-urwid.install	1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-debian/tmp/usr/lib/python2*
diff -Nru urwid-1.2.1/debian/rules urwid-1.3.0/debian/rules
--- urwid-1.2.1/debian/rules	2014-05-18 11:07:29.000000000 +0200
+++ urwid-1.3.0/debian/rules	2015-09-16 11:57:09.000000000 +0200
@@ -1,35 +1,10 @@
 #!/usr/bin/make -f
 
-DEB_PYTHON_DISTUTILS_INSTALLDIR_SKEL=/usr/lib/@PYTHONBINARY@/dist-packages/
-DEB_PYTHON_INSTALL_ARGS_ALL=--prefix=/usr --no-compile -O0 --install-layout=deb
+export PYBUILD_NAME=urwid
 
-include /usr/share/cdbs/1/rules/debhelper.mk
-DEB_INSTALL_CHANGELOGS_ALL=docs/changelog.rst
-include /usr/share/cdbs/1/class/python-distutils.mk
+%:
+	dh $@ --with python2,python3 --buildsystem=pybuild
 
-build/python-urwid:: build-docs-test-stamp
-build-docs-test-stamp:
-ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
-	set -e; for python in $(shell pyversions -r) $(shell py3versions -r); do \
-		echo Testing with $$python; \
-		$$python setup.py test; \
-	done;
-else
-	@echo "** tests disabled"
-endif
+override_dh_auto_build:
 	python setup.py build_sphinx
-	touch build-docs-test-stamp
-
-install/python-urwid::
-	chmod a+x debian/tmp/usr/lib/python*/dist-packages/urwid/*.py
-	chmod a-x debian/tmp/usr/lib/python*/dist-packages/urwid/version.py
-
-install/python3-urwid::
-	mv debian/tmp/usr/lib/$(shell py3versions -d) debian/tmp/usr/lib/python3
-	-cp debian/tmp/usr/lib/python3.*/dist-packages/urwid/*.so debian/tmp/usr/lib/python3/dist-packages/urwid/
-	rm -rf debian/tmp/usr/lib/python3.*
-
-clean::
-	rm -rf build build-docs-test-stamp urwid.egg-info
-	rm -f urwid/tests/test_vterm.py
-	find . -name '*.so' -delete
+	dh_auto_build
diff -Nru urwid-1.2.1/debian/watch urwid-1.3.0/debian/watch
--- urwid-1.2.1/debian/watch	2014-04-04 18:49:51.000000000 +0200
+++ urwid-1.3.0/debian/watch	2015-09-16 11:57:09.000000000 +0200
@@ -1,2 +1,3 @@
 version=3
-http://pypi.python.org/packages/source/u/urwid/urwid-(.*).tar.gz
+opts=uversionmangle=s/(rc|a|b|c)/~$1/ \
+https://pypi.debian.net/urwid/urwid-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
diff -Nru urwid-1.2.1/docs/changelog.rst urwid-1.3.0/docs/changelog.rst
--- urwid-1.2.1/docs/changelog.rst	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/changelog.rst	2014-10-17 20:09:04.000000000 +0200
@@ -2,6 +2,40 @@
 Changelog
 ---------
 
+Urwid 1.3.0
+===========
+
+2014-10-17
+
+ * New AsyncioEventLoop for Python 3.4, Python 3.x with asyncio
+   package or Python 2 with trollius package (by Alex Munroe,
+   Jonas Wielicki, with earlier work by Kelketek Rritaa)
+
+ * Screen classes now call back to MainLoop using event loop alarms
+   instead of passing timeout values to MainLoop (by Alex Munroe)
+
+ * Add support for bright backgrounds on linux console
+   (by Russell Warren)
+
+ * Allow custom sorting of MonitoredList (by Tony Cebzanov)
+
+ * Fix support for negative indexes with MonitoredFocusList
+   (by Heiko Noordhof)
+
+ * Documentation fixes (by Ismail, Matthew Mosesohn)
+
+Urwid 1.2.2
+===========
+
+2014-10-05
+
+ * Fix for a serious raw_display performance regression
+   (by Anton Khirnov)
+
+ * Fix for high color palette detection (by extempo)
+
+ * Small changes to enable windows support (by Jeanpierre Devin)
+
 
 Urwid 1.2.1
 ===========
diff -Nru urwid-1.2.1/docs/examples/bigtext.py urwid-1.3.0/docs/examples/bigtext.py
--- urwid-1.2.1/docs/examples/bigtext.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/examples/bigtext.py	2014-10-17 20:09:04.000000000 +0200
@@ -50,7 +50,7 @@
         ('chars',        'light gray', 'black'),
         ('exit',         'white',      'dark cyan'),
         ]
-        
+
     def create_radio_button(self, g, name, font, fn):
         w = urwid.RadioButton(g, name, False, on_state_change=fn)
         w.font = font
@@ -61,7 +61,7 @@
         w = urwid.Text("    " + name + " (UTF-8 mode required)")
         w = urwid.AttrWrap(w, 'button disabled')
         return w
-    
+
     def create_edit(self, label, text, fn):
         w = urwid.Edit(label, text)
         urwid.connect_signal(w, 'change', fn)
@@ -94,35 +94,35 @@
                     chosen_font_rb = rb
                     exit_font = font
             self.font_buttons.append( rb )
-        
+
         # Create BigText
         self.bigtext = urwid.BigText("", None)
         bt = SwitchingPadding(self.bigtext, 'left', None)
         bt = urwid.AttrWrap(bt, 'bigtext')
         bt = urwid.Filler(bt, 'bottom', None, 7)
         bt = urwid.BoxAdapter(bt, 7)
-        
+
         # Create chars_avail
         cah = urwid.Text("Characters Available:")
         self.chars_avail = urwid.Text("", wrap='any')
         ca = urwid.AttrWrap(self.chars_avail, 'chars')
-        
+
         chosen_font_rb.set_state(True) # causes set_font_event call
-    
+
         # Create Edit widget
         edit = self.create_edit("", "Urwid "+urwid.__version__,
             self.edit_change_event)
-        
+
         # ListBox
         chars = urwid.Pile([cah, ca])
         fonts = urwid.Pile([urwid.Text("Fonts:")] + self.font_buttons,
             focus_item=1)
-        col = urwid.Columns([('fixed',16,chars), fonts], 3, 
+        col = urwid.Columns([('fixed',16,chars), fonts], 3,
             focus_column=1)
         bt = urwid.Pile([bt, edit], focus_item=1)
         l = [bt, urwid.Divider(), col]
         w = urwid.ListBox(urwid.SimpleListWalker(l))
-        
+
         # Frame
         w = urwid.AttrWrap(w, 'body')
         hdr = urwid.Text("Urwid BigText example program - F8 exits.")
@@ -137,10 +137,10 @@
 
     def main(self):
         self.view, self.exit_view = self.setup_view()
-        self.loop = urwid.MainLoop(self.view, self.palette, 
+        self.loop = urwid.MainLoop(self.view, self.palette,
             unhandled_input=self.unhandled_input)
         self.loop.run()
-    
+
     def unhandled_input(self, key):
         if key == 'f8':
             self.loop.widget = self.exit_view
@@ -152,10 +152,10 @@
         if key in ('n', 'N'):
             self.loop.widget = self.view
             return True
-    
+
 
 def main():
     BigTextDisplay().main()
-    
+
 if '__main__'==__name__:
     main()
diff -Nru urwid-1.2.1/docs/examples/graph.py urwid-1.3.0/docs/examples/graph.py
--- urwid-1.2.1/docs/examples/graph.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/examples/graph.py	2014-10-17 20:09:04.000000000 +0200
@@ -20,7 +20,7 @@
 # Urwid web site: http://excess.org/urwid/
 
 """
-Urwid example demonstrating use of the BarGraph widget and creating a 
+Urwid example demonstrating use of the BarGraph widget and creating a
 floating-window appearance.  Also shows use of alarms to create timed
 animation.
 """
@@ -33,12 +33,12 @@
 UPDATE_INTERVAL = 0.2
 
 def sin100( x ):
-    """ 
+    """
     A sin function that returns values between 0 and 100 and repeats
     after x == 100.
     """
     return 50 + 50 * math.sin( x * math.pi / 50 )
-    
+
 class GraphModel:
     """
     A class responsible for storing the data that will be displayed
@@ -46,14 +46,14 @@
     """
 
     data_max_value = 100
-    
+
     def __init__(self):
         data = [ ('Saw', range(0,100,2)*2),
             ('Square', [0]*30 + [100]*30),
             ('Sine 1', [sin100(x) for x in range(100)] ),
-            ('Sine 2', [(sin100(x) + sin100(x*2))/2 
+            ('Sine 2', [(sin100(x) + sin100(x*2))/2
                 for x in range(100)] ),
-            ('Sine 3', [(sin100(x) + sin100(x*3))/2 
+            ('Sine 3', [(sin100(x) + sin100(x*3))/2
                 for x in range(100)] ),
             ]
         self.modes = []
@@ -61,13 +61,13 @@
         for m, d in data:
             self.modes.append(m)
             self.data[m] = d
-    
+
     def get_modes(self):
         return self.modes
-    
+
     def set_mode(self, m):
         self.current_mode = m
-    
+
     def get_data(self, offset, r):
         """
         Return the data in [offset:offset+r], the maximum value
@@ -108,11 +108,11 @@
         ('pg complete',  'white',      'dark magenta'),
         ('pg smooth',     'dark magenta','black')
         ]
-        
+
     graph_samples_per_bar = 10
     graph_num_bars = 5
     graph_offset_per_second = 5
-    
+
     def __init__(self, controller):
         self.controller = controller
         self.started = True
@@ -146,7 +146,7 @@
             else:
                 l.append([value,0])
         self.graph.set_data(l,max_value)
-        
+
         # also update progress
         if (o//repeat)&1:
             # show 100% for first half, 0 for second half
@@ -171,8 +171,8 @@
             self.started = True
             self.start_time = time.time()
             self.controller.animate_graph()
-            
-    
+
+
     def on_reset_button(self, w):
         self.offset = 0
         self.start_time = time.time()
@@ -199,13 +199,13 @@
         self.animate_progress = self.progress_bar( state )
         self.animate_progress_wrap._w = self.animate_progress
         self.update_graph( True )
-        
+
 
     def main_shadow(self, w):
         """Wrap a shadow and background around widget w."""
         bg = urwid.AttrWrap(urwid.SolidFill(u"\u2592"), 'screen edge')
         shadow = urwid.AttrWrap(urwid.SolidFill(u" "), 'main shadow')
-        
+
         bg = urwid.Overlay( shadow, bg,
             ('fixed left', 3), ('fixed right', 1),
             ('fixed top', 2), ('fixed bottom', 1))
@@ -213,7 +213,7 @@
             ('fixed left', 2), ('fixed right', 3),
             ('fixed top', 1), ('fixed bottom', 2))
         return w
-        
+
     def bar_graph(self, smooth=False):
         satt = None
         if smooth:
@@ -233,7 +233,7 @@
 
     def progress_bar(self, smooth=False):
         if smooth:
-            return urwid.ProgressBar('pg normal', 'pg complete', 
+            return urwid.ProgressBar('pg normal', 'pg complete',
                 0, 1, 'pg smooth')
         else:
             return urwid.ProgressBar('pg normal', 'pg complete',
@@ -255,11 +255,11 @@
         self.on_animate_button( self.animate_button )
         self.offset = 0
         self.animate_progress = self.progress_bar()
-        animate_controls = urwid.GridFlow( [ 
+        animate_controls = urwid.GridFlow( [
             self.animate_button,
             self.button("Reset", self.on_reset_button),
             ], 9, 2, 0, 'center')
-        
+
         if urwid.get_encoding_mode() == "utf8":
             unicode_checkbox = urwid.CheckBox(
                 "Enable Unicode Graphics",
@@ -267,10 +267,10 @@
         else:
             unicode_checkbox = urwid.Text(
                 "UTF-8 encoding not detected")
-            
+
         self.animate_progress_wrap = urwid.WidgetWrap(
             self.animate_progress)
-        
+
         l = [    urwid.Text("Mode",align="center"),
             ] + self.mode_buttons + [
             urwid.Divider(),
@@ -285,7 +285,7 @@
         w = urwid.ListBox(urwid.SimpleListWalker(l))
         return w
 
-    def main_window(self): 
+    def main_window(self):
         self.graph = self.bar_graph()
         self.graph_wrap = urwid.WidgetWrap( self.graph )
         vline = urwid.AttrWrap( urwid.SolidFill(u'\u2502'), 'line')
@@ -299,7 +299,7 @@
         w = urwid.AttrWrap(w,'line')
         w = self.main_shadow(w)
         return w
-        
+
 
 class GraphController:
     """
@@ -320,17 +320,17 @@
     def get_modes(self):
         """Allow our view access to the list of modes."""
         return self.model.get_modes()
-    
+
     def set_mode(self, m):
         """Allow our view to set the mode."""
         rval = self.model.set_mode( m )
         self.view.update_graph(True)
         return rval
-    
+
     def get_data(self, offset, range):
         """Provide data to our view for the graph."""
         return self.model.get_data( offset, range )
-    
+
 
     def main(self):
         self.loop = urwid.MainLoop(self.view, self.view.palette)
@@ -347,10 +347,10 @@
         if self.animate_alarm:
             self.loop.remove_alarm(self.animate_alarm)
         self.animate_alarm = None
-    
+
 
 def main():
     GraphController().main()
-    
+
 if '__main__'==__name__:
     main()
diff -Nru urwid-1.2.1/docs/examples/palette_test.py urwid-1.3.0/docs/examples/palette_test.py
--- urwid-1.2.1/docs/examples/palette_test.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/examples/palette_test.py	2014-10-17 20:09:04.000000000 +0200
@@ -34,10 +34,10 @@
 brown__   dark_red_   dark_magenta_   dark_blue_   dark_cyan_   dark_green_
 yellow_   light_red   light_magenta   light_blue   light_cyan   light_green
 
-              #00f#06f#08f#0af#0df#0ff        black_______    dark_gray___   
+              #00f#06f#08f#0af#0df#0ff        black_______    dark_gray___
             #60f#00d#06d#08d#0ad#0dd#0fd        light_gray__    white_______
-          #80f#60d#00a#06a#08a#0aa#0da#0fa        
-        #a0f#80d#60a#008#068#088#0a8#0d8#0f8        
+          #80f#60d#00a#06a#08a#0aa#0da#0fa
+        #a0f#80d#60a#008#068#088#0a8#0d8#0f8
       #d0f#a0d#80d#608#006#066#086#0a6#0d6#0f6
     #f0f#d0d#a0a#808#606#000#060#080#0a0#0d0#0f0#0f6#0f8#0fa#0fd#0ff
       #f0d#d0a#a08#806#600#660#680#6a0#6d0#6f0#6f6#6f8#6fa#6fd#6ff#0df
@@ -50,29 +50,29 @@
     #86d#66a#68a#6aa#6da                #f80#f86#f88#f8a#f8d#f8f#d6f#a0f
   #a6d#86a#668#688#6a8#6d8                #f60#f66#f68#f6a#f6d#f6f#d0f
 #d6d#a6a#868#666#686#6a6#6d6#6d8#6da#6dd    #f00#f06#f08#f0a#f0d#f0f
-  #d6a#a68#866#886#8a6#8d6#8d8#8da#8dd#6ad       
-    #d68#a66#a86#aa6#ad6#ad8#ada#add#8ad#68d   
-      #d66#d86#da6#dd6#dd8#dda#ddd#aad#88d#66d        g78_g82_g85_g89_g93_g100  
+  #d6a#a68#866#886#8a6#8d6#8d8#8da#8dd#6ad
+    #d68#a66#a86#aa6#ad6#ad8#ada#add#8ad#68d
+      #d66#d86#da6#dd6#dd8#dda#ddd#aad#88d#66d        g78_g82_g85_g89_g93_g100
                     #da6#da8#daa#dad#a8d#86d        g52_g58_g62_g66_g70_g74_
       #88a#8aa        #d86#d88#d8a#d8d#a6d        g27_g31_g35_g38_g42_g46_g50_
     #a8a#888#8a8#8aa    #d66#d68#d6a#d6d        g0__g3__g7__g11_g15_g19_g23_
-      #a88#aa8#aaa#88a                        
+      #a88#aa8#aaa#88a
             #a88#a8a
-"""                    
+"""
 
 CHART_88 = """
 brown__   dark_red_   dark_magenta_   dark_blue_   dark_cyan_   dark_green_
 yellow_   light_red   light_magenta   light_blue   light_cyan   light_green
 
-      #00f#08f#0cf#0ff            black_______    dark_gray___             
-    #80f#00c#08c#0cc#0fc            light_gray__    white_______           
+      #00f#08f#0cf#0ff            black_______    dark_gray___
+    #80f#00c#08c#0cc#0fc            light_gray__    white_______
   #c0f#80c#008#088#0c8#0f8
-#f0f#c0c#808#000#080#0c0#0f0#0f8#0fc#0ff            #88c#8cc        
-  #f0c#c08#800#880#8c0#8f0#8f8#8fc#8ff#0cf        #c8c#888#8c8#8cc   
+#f0f#c0c#808#000#080#0c0#0f0#0f8#0fc#0ff            #88c#8cc
+  #f0c#c08#800#880#8c0#8f0#8f8#8fc#8ff#0cf        #c8c#888#8c8#8cc
     #f08#c00#c80#cc0#cf0#cf8#cfc#cff#8cf#08f        #c88#cc8#ccc#88c
-      #f00#f80#fc0#ff0#ff8#ffc#fff#ccf#88f#00f            #c88#c8c        
-                    #fc0#fc8#fcc#fcf#c8f#80f    
-                      #f80#f88#f8c#f8f#c0f        g62_g74_g82_g89_g100  
+      #f00#f80#fc0#ff0#ff8#ffc#fff#ccf#88f#00f            #c88#c8c
+                    #fc0#fc8#fcc#fcf#c8f#80f
+                      #f80#f88#f8c#f8f#c0f        g62_g74_g82_g89_g100
                         #f00#f08#f0c#f0f        g0__g19_g35_g46_g52
 """
 
@@ -80,7 +80,7 @@
 brown__   dark_red_   dark_magenta_   dark_blue_   dark_cyan_   dark_green_
 yellow_   light_red   light_magenta   light_blue   light_cyan   light_green
 
-black_______    dark_gray___    light_gray__    white_______           
+black_______    dark_gray___    light_gray__    white_______
 """
 
 ATTR_RE = re.compile("(?P<whitespace>[ \n]*)(?P<entry>[^ \n]+)")
@@ -115,7 +115,7 @@
             attr, text = attrtext
             out.append((attr, text.ljust(elen)))
     return out
-            
+
 def foreground_chart(chart, background, colors):
     """
     Create text markup for a foreground colour chart
@@ -199,7 +199,7 @@
         if state:
             is_foreground_chart = chart_radio_buttons[0].state
             set_mode(colors, is_foreground_chart)
-            
+
     def mode_rb(text, colors, state=False):
         # mode radio buttons
         rb = urwid.RadioButton(mode_radio_buttons, text, state)
@@ -209,10 +209,10 @@
     def on_chart_change(rb, state):
         # handle foreground check box state change
         set_mode(screen.colors, state)
-        
+
     def click_exit(button):
         raise urwid.ExitMainLoop()
-    
+
     lb.extend([
         urwid.AttrMap(urwid.Text("Urwid Palette Test"), 'header'),
         urwid.AttrMap(urwid.Columns([
@@ -238,7 +238,7 @@
         ])
 
     set_mode(16, True) # displays the chart
-    
+
     def unhandled_input(key):
         if key in ('Q','q','esc'):
             raise urwid.ExitMainLoop()
diff -Nru urwid-1.2.1/docs/examples/real_browse.py urwid-1.3.0/docs/examples/real_browse.py
--- urwid-1.2.1/docs/examples/real_browse.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/examples/real_browse.py	2014-10-17 20:09:04.000000000 +0200
@@ -93,7 +93,7 @@
 
     def get_display_text(self):
         return self.get_node().get_key()
-    
+
 
 
 class EmptyWidget(urwid.TreeWidget):
@@ -164,7 +164,7 @@
         else:
             depth = path.count(dir_sep())
             key = os.path.basename(path)
-        urwid.ParentNode.__init__(self, path, key=key, parent=parent, 
+        urwid.ParentNode.__init__(self, path, key=key, parent=parent,
                                   depth=depth)
 
     def load_parent(self):
@@ -186,7 +186,7 @@
                     files.append(a)
         except OSError, e:
             depth = self.get_depth() + 1
-            self._children[None] = ErrorNode(self, parent=self, key=None, 
+            self._children[None] = ErrorNode(self, parent=self, key=None,
                                              depth=depth)
             return [None]
 
@@ -199,7 +199,7 @@
         keys = dirs + files
         if len(keys) == 0:
             depth=self.get_depth() + 1
-            self._children[None] = EmptyNode(self, parent=self, key=None, 
+            self._children[None] = EmptyNode(self, parent=self, key=None,
                                              depth=depth)
             keys = [None]
         return keys
@@ -226,7 +226,7 @@
         ('body', 'black', 'light gray'),
         ('flagged', 'black', 'dark green', ('bold','underline')),
         ('focus', 'light gray', 'dark blue', 'standout'),
-        ('flagged focus', 'yellow', 'dark cyan', 
+        ('flagged focus', 'yellow', 'dark cyan',
                 ('bold','standout','underline')),
         ('head', 'yellow', 'black', 'standout'),
         ('foot', 'light gray', 'black'),
@@ -236,7 +236,7 @@
         ('flag', 'dark gray', 'light gray'),
         ('error', 'dark red', 'light gray'),
         ]
-    
+
     footer_text = [
         ('title', "Directory Browser"), "    ",
         ('key', "UP"), ",", ('key', "DOWN"), ",",
@@ -246,12 +246,12 @@
         ('key', "+"), ",",
         ('key', "-"), "  ",
         ('key', "LEFT"), "  ",
-        ('key', "HOME"), "  ", 
+        ('key', "HOME"), "  ",
         ('key', "END"), "  ",
         ('key', "Q"),
         ]
-    
-    
+
+
     def __init__(self):
         cwd = os.getcwd()
         store_initial_cwd(cwd)
@@ -261,17 +261,17 @@
         self.footer = urwid.AttrWrap(urwid.Text(self.footer_text),
             'foot')
         self.view = urwid.Frame(
-            urwid.AttrWrap(self.listbox, 'body'), 
-            header=urwid.AttrWrap(self.header, 'head'), 
+            urwid.AttrWrap(self.listbox, 'body'),
+            header=urwid.AttrWrap(self.header, 'head'),
             footer=self.footer)
 
     def main(self):
         """Run the program."""
-        
+
         self.loop = urwid.MainLoop(self.view, self.palette,
             unhandled_input=self.unhandled_input)
         self.loop.run()
-    
+
         # on exit, write the flagged filenames to the console
         names = [escape_filename_sh(x) for x in get_flagged_names()]
         print " ".join(names)
@@ -299,13 +299,13 @@
 
 def get_flagged_names():
     """Return a list of all filenames marked as flagged."""
-    
+
     l = []
     for w in _widget_cache.values():
         if w.flagged:
             l.append(w.get_node().get_value())
     return l
-            
+
 
 
 ######
@@ -314,7 +314,7 @@
 
 def store_initial_cwd(name):
     """Store the initial current working directory path components."""
-    
+
     global _initial_cwd
     _initial_cwd = name.split(dir_sep())
 
@@ -323,14 +323,14 @@
 
     if name is '/':
         return True
-    
+
     l = name.split(dir_sep())
     if len(l) > len(_initial_cwd):
         return False
-    
+
     if l != _initial_cwd[:len(l)]:
         return False
-    
+
     return True
 
 
@@ -338,11 +338,11 @@
     """Return a hopefully safe shell-escaped version of a filename."""
 
     # check whether we have unprintable characters
-    for ch in name: 
-        if ord(ch) < 32: 
+    for ch in name:
+        if ord(ch) < 32:
             # found one so use the ansi-c escaping
             return escape_filename_sh_ansic(name)
-            
+
     # all printable characters, so return a double-quoted version
     name.replace('\\','\\\\')
     name.replace('"','\\"')
@@ -353,7 +353,7 @@
 
 def escape_filename_sh_ansic(name):
     """Return an ansi-c shell-escaped version of a filename."""
-    
+
     out =[]
     # gather the escaped characters into a list
     for ch in name:
@@ -363,7 +363,7 @@
             out.append('\\\\')
         else:
             out.append(ch)
-            
+
     # slap them back together in an ansi-c quote  $'...'
     return "$'" + "".join(out) + "'"
 
@@ -383,6 +383,6 @@
     return getattr(os.path,'sep','/')
 
 
-if __name__=="__main__": 
+if __name__=="__main__":
     main()
-        
+
diff -Nru urwid-1.2.1/docs/examples/real_edit.py urwid-1.3.0/docs/examples/real_edit.py
--- urwid-1.2.1/docs/examples/real_edit.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/examples/real_edit.py	2014-10-17 20:09:04.000000000 +0200
@@ -37,30 +37,30 @@
 
 class LineWalker(urwid.ListWalker):
     """ListWalker-compatible class for lazily reading file contents."""
-    
+
     def __init__(self, name):
         self.file = open(name)
         self.lines = []
         self.focus = 0
-    
-    def get_focus(self): 
+
+    def get_focus(self):
         return self._get_at_pos(self.focus)
-    
+
     def set_focus(self, focus):
         self.focus = focus
         self._modified()
-    
+
     def get_next(self, start_from):
         return self._get_at_pos(start_from + 1)
-    
+
     def get_prev(self, start_from):
         return self._get_at_pos(start_from - 1)
 
     def read_next_line(self):
         """Read another line from the file."""
-        
+
         next_line = self.file.readline()
-        
+
         if not next_line or next_line[-1:] != '\n':
             # no newline on last line of file
             self.file = None
@@ -69,22 +69,22 @@
             next_line = next_line[:-1]
 
         expanded = next_line.expandtabs()
-        
+
         edit = urwid.Edit("", expanded, allow_tab=True)
         edit.set_edit_pos(0)
         edit.original_text = next_line
         self.lines.append(edit)
 
         return next_line
-        
-    
+
+
     def _get_at_pos(self, pos):
         """Return a widget for the line number passed."""
-        
+
         if pos < 0:
             # line 0 is the start of the file, no more above
             return None, None
-            
+
         if len(self.lines) > pos:
             # we have that line so return it
             return self.lines[pos], pos
@@ -96,12 +96,12 @@
         assert pos == len(self.lines), "out of order request?"
 
         self.read_next_line()
-        
+
         return self.lines[-1], pos
-    
+
     def split_focus(self):
         """Divide the focus edit widget at the cursor location."""
-        
+
         focus = self.lines[self.focus]
         pos = focus.edit_pos
         edit = urwid.Edit("",focus.edit_text[pos:], allow_tab=True)
@@ -117,7 +117,7 @@
         if above is None:
             # already at the top
             return
-        
+
         focus = self.lines[self.focus]
         above.set_edit_pos(len(above.edit_text))
         above.set_edit_text(above.edit_text + focus.edit_text)
@@ -131,7 +131,7 @@
         if below is None:
             # already at bottom
             return
-        
+
         focus = self.lines[self.focus]
         focus.set_edit_text(focus.edit_text + below.edit_text)
         del self.lines[self.focus+1]
@@ -143,16 +143,16 @@
         ('foot','dark cyan', 'dark blue', 'bold'),
         ('key','light cyan', 'dark blue', 'underline'),
         ]
-        
+
     footer_text = ('foot', [
         "Text Editor    ",
         ('key', "F5"), " save  ",
         ('key', "F8"), " quit",
         ])
-    
+
     def __init__(self, name):
         self.save_name = name
-        self.walker = LineWalker(name) 
+        self.walker = LineWalker(name)
         self.listbox = urwid.ListBox(self.walker)
         self.footer = urwid.AttrWrap(urwid.Text(self.footer_text),
             "foot")
@@ -163,7 +163,7 @@
         self.loop = urwid.MainLoop(self.view, self.palette,
             unhandled_input=self.unhandled_keypress)
         self.loop.run()
-    
+
     def unhandled_keypress(self, k):
         """Last resort for keypresses."""
 
@@ -197,11 +197,11 @@
         else:
             return
         return True
-            
+
 
     def save_file(self):
         """Write the file out to disk."""
-        
+
         l = []
         walk = self.walker
         for edit in walk.lines:
@@ -210,14 +210,14 @@
                 l.append(edit.original_text)
             else:
                 l.append(re_tab(edit.edit_text))
-        
+
         # then the rest
         while walk.file is not None:
             l.append(walk.read_next_line())
-            
+
         # write back to disk
         outfile = open(self.save_name, "w")
-        
+
         prefix = ""
         for line in l:
             outfile.write(prefix + line)
@@ -249,7 +249,7 @@
         sys.stderr.write(__doc__)
         return
     EditDisplay(name).main()
-    
 
-if __name__=="__main__": 
+
+if __name__=="__main__":
     main()
diff -Nru urwid-1.2.1/docs/manual/canvascache.rst urwid-1.3.0/docs/manual/canvascache.rst
--- urwid-1.2.1/docs/manual/canvascache.rst	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/manual/canvascache.rst	2014-10-17 20:09:04.000000000 +0200
@@ -12,7 +12,7 @@
 rendered for each update.
 
 The :class:`Widget` base class uses some metaclass magic to
-capture the canvas objects returned :meth:`Widget.render` is called and return
+capture the canvas objects returned when :meth:`Widget.render` is called and return
 them the next time :meth:`Widget.render` is called again with the same parameters. The
 :meth:`Widget._invalidate` method is provided as a way to remove cached widgets so
 that changes to the widget are visible the next time the screen is redrawn.
@@ -26,7 +26,7 @@
 
 When container and decoration widgets are rendered, they collect the canvases
 returned by their children and arrange them into a composite canvas. Composite
-canvases may are nested to form a tree with the topmost widget's :meth:`Widget.render`
+canvases are nested to form a tree with the topmost widget's :meth:`Widget.render`
 method returning the root of the tree. That canvas is sent to the display
 module to be rendered on the screen.
 
diff -Nru urwid-1.2.1/docs/manual/mainloop.rst urwid-1.3.0/docs/manual/mainloop.rst
--- urwid-1.2.1/docs/manual/mainloop.rst	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/manual/mainloop.rst	2014-10-17 20:09:04.000000000 +0200
@@ -59,7 +59,7 @@
 
 Urwid's event loop classes handle waiting for things for the
 :class:`MainLoop`. The different event loops allow you to
-integrate with Twisted_, Glib_, Tornado_ libraries,
+integrate with Twisted_, Glib_, Tornado_, Asyncio_ libraries,
 or use a simple ``select``-based
 loop. Event loop classes abstract the particulars of waiting for input and
 calling functions as a result of timeouts.
@@ -76,6 +76,7 @@
 .. _Twisted: http://twistedmatrix.com/trac/
 .. _Glib: http://developer.gnome.org/glib/stable/
 .. _Tornado: http://www.tornadoweb.org/
+.. _Asyncio: https://docs.python.org/3/library/asyncio.html
 
 ``SelectEventLoop``
 -------------------
@@ -132,9 +133,27 @@
 ::
 
     from tornado.ioloop import IOLoop
-    evl = urwid.TornadoEventLoop(IOLoop()
+    evl = urwid.TornadoEventLoop(IOLoop())
     loop = urwid.MainLoop(widget, event_loop=evl)
 
 .. seealso::
 
-  :class`TornadoEventLoop reference <TornadoEventLoop>`
+  :class:`TornadoEventLoop reference <TornadoEventLoop>`
+
+``AsyncioEventLoop``
+--------------------
+
+This event loop integrates with the asyncio module in Python 3.4,
+the asyncio package available for Python 3.3 or the trollius
+package available for Python 2.
+
+::
+
+    import asyncio
+    evl = urwid.AsyncioEventLoop(loop=asyncio.get_event_loop())
+    loop = urwid.MainLoop(widget, event_loop=evl)
+
+.. seealso::
+
+  :class:`AsyncioEventLoop reference <AsyncioEventLoop>`
+
diff -Nru urwid-1.2.1/docs/manual/widgets.rst urwid-1.3.0/docs/manual/widgets.rst
--- urwid-1.2.1/docs/manual/widgets.rst	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/manual/widgets.rst	2014-10-17 20:09:04.000000000 +0200
@@ -29,7 +29,7 @@
 7. *(a)* possibly modifies the canvas from *(b)* and returns it
 
 Widgets *(a)*, *(b)* and *(e)* are called container widgets because they
-contain other widgets. Container widgets choose the size and position their
+contain other widgets. Container widgets choose the size and position of their
 contained widgets.
 
 Container widgets must also keep track of which one of their contained widgets
@@ -315,7 +315,7 @@
 The Overlay widget always treats the top widget as the one in focus. All
 keyboard input will be passed to the top widget.
 
-If you want to use a flow flow widget for the top widget, first wrap the flow
+If you want to use a flow widget for the top widget, first wrap the flow
 widget with a :class:`Filler` widget.
 
 
diff -Nru urwid-1.2.1/docs/reference/main_loop.rst urwid-1.3.0/docs/reference/main_loop.rst
--- urwid-1.2.1/docs/reference/main_loop.rst	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/reference/main_loop.rst	2014-10-17 20:09:04.000000000 +0200
@@ -28,3 +28,7 @@
 
 .. autoclass:: TornadoEventLoop
 
+AsyncioEventLoop
+----------------
+
+.. autoclass:: AsyncioEventLoop
diff -Nru urwid-1.2.1/docs/tools/templates/indexcontent.html urwid-1.3.0/docs/tools/templates/indexcontent.html
--- urwid-1.2.1/docs/tools/templates/indexcontent.html	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/tools/templates/indexcontent.html	2014-10-17 20:09:04.000000000 +0200
@@ -42,6 +42,7 @@
 <li>python-gi for GlibEventLoop (optional)</li>
 <li>Twisted for TwistedEventLoop (optional)</li>
 <li>Tornado for TornadoEventLoop (optional)</li>
+<li>asyncio or trollius for AsyncioEventLoop (optional)</li>
 <li>Apache for web_display module (optional)</li>
 <li>ncurses for curses_display module (optional)</li>
 </ul>
@@ -51,6 +52,7 @@
 <h3>Similar projects</h3>
 <ul>
 <li><a href="http://www.npcole.com/npyscreen/">npyscreen</a></li>
+<li><a href="https://github.com/thomasballinger/curtsies">curtsies</a></li>
 </ul>
 </div>
 </div>
diff -Nru urwid-1.2.1/examples/asyncio_socket_server.py urwid-1.3.0/examples/asyncio_socket_server.py
--- urwid-1.2.1/examples/asyncio_socket_server.py	1970-01-01 01:00:00.000000000 +0100
+++ urwid-1.3.0/examples/asyncio_socket_server.py	2014-10-17 20:09:04.000000000 +0200
@@ -0,0 +1,186 @@
+"""Demo of using urwid with Python 3.4's asyncio.
+
+This code works on older Python 3.x if you install `asyncio` from PyPI, and
+even Python 2 if you install `trollius`!
+"""
+from __future__ import print_function
+
+import asyncio
+from datetime import datetime
+import sys
+import weakref
+
+import urwid
+from urwid.raw_display import Screen
+
+
+loop = asyncio.get_event_loop()
+
+
+# -----------------------------------------------------------------------------
+# General-purpose setup code
+
+def build_widgets():
+    input1 = urwid.Edit('What is your name? ')
+    input2 = urwid.Edit('What is your quest? ')
+    input3 = urwid.Edit('What is the capital of Assyria? ')
+    inputs = [input1, input2, input3]
+
+    def update_clock(widget_ref):
+        widget = widget_ref()
+        if not widget:
+            # widget is dead; the main loop must've been destroyed
+            return
+
+        widget.set_text(datetime.now().isoformat())
+
+        # Schedule us to update the clock again in one second
+        loop.call_later(1, update_clock, widget_ref)
+
+    clock = urwid.Text('')
+    update_clock(weakref.ref(clock))
+
+    return urwid.Filler(urwid.Pile([clock] + inputs), 'top')
+
+
+def unhandled(key):
+    if key == 'ctrl c':
+        raise urwid.ExitMainLoop
+
+
+# -----------------------------------------------------------------------------
+# Demo 1
+
+def demo1():
+    """Plain old urwid app.  Just happens to be run atop asyncio as the event
+    loop.
+
+    Note that the clock is updated using the asyncio loop directly, not via any
+    of urwid's facilities.
+    """
+    main_widget = build_widgets()
+
+    urwid_loop = urwid.MainLoop(
+        main_widget,
+        event_loop=urwid.AsyncioEventLoop(loop=loop),
+        unhandled_input=unhandled,
+    )
+    urwid_loop.run()
+
+
+# -----------------------------------------------------------------------------
+# Demo 2
+
+class AsyncScreen(Screen):
+    """An urwid screen that speaks to an asyncio stream, rather than polling
+    file descriptors.
+    """
+    def __init__(self, reader, writer):
+        self.reader = reader
+        self.writer = writer
+
+        Screen.__init__(self, None, None)
+
+    _pending_task = None
+
+    def write(self, data):
+        self.writer.write(data)
+
+    def flush(self):
+        pass
+
+    def hook_event_loop(self, event_loop, callback):
+        # Wait on the reader's read coro, and when there's data to read, call
+        # the callback and then wait again
+        def pump_reader(fut=None):
+            if fut is None:
+                # First call, do nothing
+                pass
+            elif fut.cancelled():
+                # This is in response to an earlier .read() call, so don't
+                # schedule another one!
+                return
+            elif fut.exception():
+                pass
+            else:
+                try:
+                    self.parse_input(
+                        event_loop, callback, bytearray(fut.result()))
+                except urwid.ExitMainLoop:
+                    # This will immediately close the transport and thus the
+                    # connection, which in turn calls connection_lost, which
+                    # stops the screen and the loop
+                    self.writer.abort()
+
+            # asyncio.async() schedules a coroutine without using `yield from`,
+            # which would make this code not work on Python 2
+            self._pending_task = asyncio.async(
+                self.reader.read(1024), loop=event_loop._loop)
+            self._pending_task.add_done_callback(pump_reader)
+
+        pump_reader()
+
+    def unhook_event_loop(self, event_loop):
+        if self._pending_task:
+            self._pending_task.cancel()
+            del self._pending_task
+
+
+class UrwidProtocol(asyncio.Protocol):
+    def connection_made(self, transport):
+        print("Got a client!")
+        self.transport = transport
+
+        # StreamReader is super convenient here; it has a regular method on our
+        # end (feed_data), and a coroutine on the other end that will
+        # faux-block until there's data to be read.  We could also just call a
+        # method directly on the screen, but this keeps the screen somewhat
+        # separate from the protocol.
+        self.reader = asyncio.StreamReader(loop=loop)
+        screen = AsyncScreen(self.reader, transport)
+
+        main_widget = build_widgets()
+        self.urwid_loop = urwid.MainLoop(
+            main_widget,
+            event_loop=urwid.AsyncioEventLoop(loop=loop),
+            screen=screen,
+            unhandled_input=unhandled,
+        )
+
+        self.urwid_loop.start()
+
+    def data_received(self, data):
+        self.reader.feed_data(data)
+
+    def connection_lost(self, exc):
+        print("Lost a client...")
+        self.reader.feed_eof()
+        self.urwid_loop.stop()
+
+
+def demo2():
+    """Urwid app served over the network to multiple clients at once, using an
+    asyncio Protocol.
+    """
+    coro = loop.create_server(UrwidProtocol, port=12345)
+    loop.run_until_complete(coro)
+    print("OK, good to go!  Try this in another terminal (or two):")
+    print()
+    print("    socat TCP:127.0.0.1:12345 STDIN,raw")
+    print()
+    loop.run_forever()
+
+
+if __name__ == '__main__':
+    if len(sys.argv) == 2:
+        which = sys.argv[1]
+    else:
+        which = None
+
+    if which == '1':
+        demo1()
+    elif which == '2':
+        demo2()
+    else:
+        print("Please run me with an argument of either 1 or 2.")
+        sys.exit(1)
diff -Nru urwid-1.2.1/examples/bigtext.py urwid-1.3.0/examples/bigtext.py
--- urwid-1.2.1/examples/bigtext.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/bigtext.py	2014-10-17 20:09:04.000000000 +0200
@@ -50,7 +50,7 @@
         ('chars',        'light gray', 'black'),
         ('exit',         'white',      'dark cyan'),
         ]
-        
+
     def create_radio_button(self, g, name, font, fn):
         w = urwid.RadioButton(g, name, False, on_state_change=fn)
         w.font = font
@@ -61,7 +61,7 @@
         w = urwid.Text("    " + name + " (UTF-8 mode required)")
         w = urwid.AttrWrap(w, 'button disabled')
         return w
-    
+
     def create_edit(self, label, text, fn):
         w = urwid.Edit(label, text)
         urwid.connect_signal(w, 'change', fn)
@@ -94,35 +94,35 @@
                     chosen_font_rb = rb
                     exit_font = font
             self.font_buttons.append( rb )
-        
+
         # Create BigText
         self.bigtext = urwid.BigText("", None)
         bt = SwitchingPadding(self.bigtext, 'left', None)
         bt = urwid.AttrWrap(bt, 'bigtext')
         bt = urwid.Filler(bt, 'bottom', None, 7)
         bt = urwid.BoxAdapter(bt, 7)
-        
+
         # Create chars_avail
         cah = urwid.Text("Characters Available:")
         self.chars_avail = urwid.Text("", wrap='any')
         ca = urwid.AttrWrap(self.chars_avail, 'chars')
-        
+
         chosen_font_rb.set_state(True) # causes set_font_event call
-    
+
         # Create Edit widget
         edit = self.create_edit("", "Urwid "+urwid.__version__,
             self.edit_change_event)
-        
+
         # ListBox
         chars = urwid.Pile([cah, ca])
         fonts = urwid.Pile([urwid.Text("Fonts:")] + self.font_buttons,
             focus_item=1)
-        col = urwid.Columns([('fixed',16,chars), fonts], 3, 
+        col = urwid.Columns([('fixed',16,chars), fonts], 3,
             focus_column=1)
         bt = urwid.Pile([bt, edit], focus_item=1)
         l = [bt, urwid.Divider(), col]
         w = urwid.ListBox(urwid.SimpleListWalker(l))
-        
+
         # Frame
         w = urwid.AttrWrap(w, 'body')
         hdr = urwid.Text("Urwid BigText example program - F8 exits.")
@@ -137,10 +137,10 @@
 
     def main(self):
         self.view, self.exit_view = self.setup_view()
-        self.loop = urwid.MainLoop(self.view, self.palette, 
+        self.loop = urwid.MainLoop(self.view, self.palette,
             unhandled_input=self.unhandled_input)
         self.loop.run()
-    
+
     def unhandled_input(self, key):
         if key == 'f8':
             self.loop.widget = self.exit_view
@@ -152,10 +152,10 @@
         if key in ('n', 'N'):
             self.loop.widget = self.view
             return True
-    
+
 
 def main():
     BigTextDisplay().main()
-    
+
 if '__main__'==__name__:
     main()
diff -Nru urwid-1.2.1/examples/browse.py urwid-1.3.0/examples/browse.py
--- urwid-1.2.1/examples/browse.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/browse.py	2014-10-17 20:09:04.000000000 +0200
@@ -93,7 +93,7 @@
 
     def get_display_text(self):
         return self.get_node().get_key()
-    
+
 
 
 class EmptyWidget(urwid.TreeWidget):
@@ -164,7 +164,7 @@
         else:
             depth = path.count(dir_sep())
             key = os.path.basename(path)
-        urwid.ParentNode.__init__(self, path, key=key, parent=parent, 
+        urwid.ParentNode.__init__(self, path, key=key, parent=parent,
                                   depth=depth)
 
     def load_parent(self):
@@ -186,7 +186,7 @@
                     files.append(a)
         except OSError, e:
             depth = self.get_depth() + 1
-            self._children[None] = ErrorNode(self, parent=self, key=None, 
+            self._children[None] = ErrorNode(self, parent=self, key=None,
                                              depth=depth)
             return [None]
 
@@ -199,7 +199,7 @@
         keys = dirs + files
         if len(keys) == 0:
             depth=self.get_depth() + 1
-            self._children[None] = EmptyNode(self, parent=self, key=None, 
+            self._children[None] = EmptyNode(self, parent=self, key=None,
                                              depth=depth)
             keys = [None]
         return keys
@@ -226,7 +226,7 @@
         ('body', 'black', 'light gray'),
         ('flagged', 'black', 'dark green', ('bold','underline')),
         ('focus', 'light gray', 'dark blue', 'standout'),
-        ('flagged focus', 'yellow', 'dark cyan', 
+        ('flagged focus', 'yellow', 'dark cyan',
                 ('bold','standout','underline')),
         ('head', 'yellow', 'black', 'standout'),
         ('foot', 'light gray', 'black'),
@@ -236,7 +236,7 @@
         ('flag', 'dark gray', 'light gray'),
         ('error', 'dark red', 'light gray'),
         ]
-    
+
     footer_text = [
         ('title', "Directory Browser"), "    ",
         ('key', "UP"), ",", ('key', "DOWN"), ",",
@@ -246,12 +246,12 @@
         ('key', "+"), ",",
         ('key', "-"), "  ",
         ('key', "LEFT"), "  ",
-        ('key', "HOME"), "  ", 
+        ('key', "HOME"), "  ",
         ('key', "END"), "  ",
         ('key', "Q"),
         ]
-    
-    
+
+
     def __init__(self):
         cwd = os.getcwd()
         store_initial_cwd(cwd)
@@ -261,17 +261,17 @@
         self.footer = urwid.AttrWrap(urwid.Text(self.footer_text),
             'foot')
         self.view = urwid.Frame(
-            urwid.AttrWrap(self.listbox, 'body'), 
-            header=urwid.AttrWrap(self.header, 'head'), 
+            urwid.AttrWrap(self.listbox, 'body'),
+            header=urwid.AttrWrap(self.header, 'head'),
             footer=self.footer)
 
     def main(self):
         """Run the program."""
-        
+
         self.loop = urwid.MainLoop(self.view, self.palette,
             unhandled_input=self.unhandled_input)
         self.loop.run()
-    
+
         # on exit, write the flagged filenames to the console
         names = [escape_filename_sh(x) for x in get_flagged_names()]
         print " ".join(names)
@@ -299,13 +299,13 @@
 
 def get_flagged_names():
     """Return a list of all filenames marked as flagged."""
-    
+
     l = []
     for w in _widget_cache.values():
         if w.flagged:
             l.append(w.get_node().get_value())
     return l
-            
+
 
 
 ######
@@ -314,7 +314,7 @@
 
 def store_initial_cwd(name):
     """Store the initial current working directory path components."""
-    
+
     global _initial_cwd
     _initial_cwd = name.split(dir_sep())
 
@@ -323,14 +323,14 @@
 
     if name is '/':
         return True
-    
+
     l = name.split(dir_sep())
     if len(l) > len(_initial_cwd):
         return False
-    
+
     if l != _initial_cwd[:len(l)]:
         return False
-    
+
     return True
 
 
@@ -338,11 +338,11 @@
     """Return a hopefully safe shell-escaped version of a filename."""
 
     # check whether we have unprintable characters
-    for ch in name: 
-        if ord(ch) < 32: 
+    for ch in name:
+        if ord(ch) < 32:
             # found one so use the ansi-c escaping
             return escape_filename_sh_ansic(name)
-            
+
     # all printable characters, so return a double-quoted version
     name.replace('\\','\\\\')
     name.replace('"','\\"')
@@ -353,7 +353,7 @@
 
 def escape_filename_sh_ansic(name):
     """Return an ansi-c shell-escaped version of a filename."""
-    
+
     out =[]
     # gather the escaped characters into a list
     for ch in name:
@@ -363,7 +363,7 @@
             out.append('\\\\')
         else:
             out.append(ch)
-            
+
     # slap them back together in an ansi-c quote  $'...'
     return "$'" + "".join(out) + "'"
 
@@ -383,6 +383,6 @@
     return getattr(os.path,'sep','/')
 
 
-if __name__=="__main__": 
+if __name__=="__main__":
     main()
-        
+
diff -Nru urwid-1.2.1/examples/calc.py urwid-1.3.0/examples/calc.py
--- urwid-1.2.1/examples/calc.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/calc.py	2014-10-17 20:09:04.000000000 +0200
@@ -44,7 +44,7 @@
 
 def div_or_none(a,b):
     """Divide a by b.  Return result or None on divide by zero."""
-    if b == 0: 
+    if b == 0:
         return None
     return a/b
 
@@ -72,8 +72,8 @@
 E_cant_combine = "Cannot combine cells with sub-expressions."
 E_invalid_in_parent_cell = "Cannot enter numbers into parent cell."
 E_invalid_in_help_col = [
-    "Help Column is in focus.  Press ", 
-    ('key',COLUMN_KEYS[1]),"-",('key',COLUMN_KEYS[-1]), 
+    "Help Column is in focus.  Press ",
+    ('key',COLUMN_KEYS[1]),"-",('key',COLUMN_KEYS[-1]),
     " to select another column."]
 
 # Shared layout object
@@ -82,12 +82,12 @@
 
 class CalcEvent(Exception):
     """Events triggered by user input."""
-    
+
     attr = 'event'
-    
+
     def __init__(self, message):
         self.message = message
-    
+
     def widget(self):
         """Return a widget containing event information"""
         text = urwid.Text( self.message, 'center' )
@@ -115,24 +115,24 @@
         self.child = None
         self.setup_edit()
         self.result = urwid.Text("", layout=CALC_LAYOUT)
-    
+
     def show_result(self, next_cell):
         """Return whether this widget should display its result.
 
         next_cell -- the cell following self or None"""
-        
-        if self.is_top: 
+
+        if self.is_top:
             return False
         if next_cell is None:
             return True
         if self.op == "+" and next_cell.op == "+":
             return False
         return True
-        
-    
+
+
     def setup_edit(self):
         """Create the standard edit widget for this cell."""
-        
+
         self.edit = urwid.IntEdit()
         if not self.is_top:
             self.edit.set_caption( self.op + " " )
@@ -140,38 +140,38 @@
 
     def get_value(self):
         """Return the numeric value of the cell."""
-        
+
         if self.child is not None:
             return self.child.get_result()
         else:
             return long("0"+self.edit.edit_text)
-    
+
     def get_result(self):
         """Return the numeric result of this cell's operation."""
-        
+
         if self.is_top:
             return self.get_value()
-        if self.result.text == "": 
+        if self.result.text == "":
             return None
         return long(self.result.text)
 
     def set_result(self, result):
         """Set the numeric result for this cell."""
-        
+
         if result == None:
             self.result.set_text("")
         else:
             self.result.set_text( "%d" %result )
-    
+
     def become_parent(self, column, letter):
         """Change the edit widget to a parent cell widget."""
-        
+
         self.child = column
         self.edit = ParentEdit( self.op, letter )
-    
+
     def remove_child(self):
         """Change the edit widget back to a standard edit widget."""
-        
+
         self.child = None
         self.setup_edit()
 
@@ -183,39 +183,39 @@
 
 class ParentEdit(urwid.Edit):
     """Edit widget modified to link to a child column"""
-    
+
     def __init__(self, op, letter):
         """Use the operator and letter of the child column as caption
-        
+
         op -- operator or None
         letter -- letter of child column
         remove_fn -- function to call when user wants to remove child
                      function takes no parameters
         """
-        
+
         urwid.Edit.__init__(self, layout=CALC_LAYOUT)
         self.op = op
         self.set_letter( letter )
-    
+
     def set_letter(self, letter):
         """Set the letter of the child column for display."""
-        
+
         self.letter = letter
         caption = "("+letter+")"
         if self.op is not None:
             caption = self.op+" "+caption
         self.set_caption(caption)
-        
+
     def keypress(self, size, key):
-        """Disable usual editing, allow only removing of child""" 
-        
+        """Disable usual editing, allow only removing of child"""
+
         if key == "backspace":
             raise ColumnDeleteEvent(self.letter, from_parent=True)
         elif key in list("0123456789"):
             raise CalcEvent, E_invalid_in_parent_cell
         else:
             return key
-        
+
 
 class CellWalker(urwid.ListWalker):
     def __init__(self, content):
@@ -243,13 +243,13 @@
             return self.div, pos
         else:
             return self.content[i].result, pos
-    
+
     def get_focus(self):
         return self._get_at_pos(self.focus)
-    
+
     def set_focus(self, focus):
         self.focus = focus
-    
+
     def get_next(self, start_from):
         i, sub = start_from
         assert sub in (0,1,2)
@@ -264,7 +264,7 @@
             return self._get_at_pos( (i, 2) )
         else:
             return self._get_at_pos( (i+1, 0) )
-    
+
     def get_prev(self, start_from):
         i, sub = start_from
         assert sub in (0,1,2)
@@ -280,8 +280,8 @@
             return self._get_at_pos( (i, 0) )
         else:
             return self._get_at_pos( (i, 1) )
-    
-            
+
+
 class CellColumn( urwid.WidgetWrap ):
     def __init__(self, letter):
         self.walker = CellWalker([Cell(None)])
@@ -289,55 +289,55 @@
         self.listbox = urwid.ListBox( self.walker )
         self.set_letter( letter )
         urwid.WidgetWrap.__init__(self, self.frame)
-    
+
     def set_letter(self, letter):
         """Set the column header with letter."""
-        
+
         self.letter = letter
         header = urwid.AttrWrap(
             urwid.Text( ["Column ",('key',letter)],
             layout = CALC_LAYOUT), 'colhead' )
         self.frame = urwid.Frame( self.listbox, header )
-            
+
     def keypress(self, size, key):
         key = self.frame.keypress( size, key)
-        if key is None: 
+        if key is None:
             changed = self.update_results()
             if changed:
                 raise UpdateParentEvent()
             return
-        
+
         f, (i, sub) = self.walker.get_focus()
-        if sub != 0: 
+        if sub != 0:
             # f is not an edit widget
             return key
-        if OPERATORS.has_key(key):
+        if key in OPERATORS:
             # move trailing text to new cell below
             edit = self.walker.get_cell(i).edit
             cursor_pos = edit.edit_pos
             tail = edit.edit_text[cursor_pos:]
             edit.set_edit_text( edit.edit_text[:cursor_pos] )
-            
+
             new_cell = Cell( key )
             new_cell.edit.set_edit_text( tail )
             self.content[i+1:i+1] = [new_cell]
-            
+
             changed = self.update_results()
             self.move_focus_next( size )
             self.content[i+1].edit.set_edit_pos(0)
             if changed:
                 raise UpdateParentEvent()
             return
-            
+
         elif key == 'backspace':
             # unhandled backspace, we're at beginning of number
             # append current number to cell above, removing operator
             above = self.walker.get_cell(i-1)
             if above is None:
                 # we're the first cell
-                raise ColumnDeleteEvent( self.letter, 
+                raise ColumnDeleteEvent( self.letter,
                     from_parent=False )
-            
+
             edit = self.walker.get_cell(i).edit
             # check that we can combine
             if above.child is not None:
@@ -346,7 +346,7 @@
                     # ..and current not empty, no good
                     raise CalcEvent, E_cant_combine
                 above_pos = 0
-            else:    
+            else:
                 # above is normal number cell
                 above_pos = len(above.edit.edit_text)
                 above.edit.set_edit_text( above.edit.edit_text +
@@ -359,7 +359,7 @@
             if changed:
                 raise UpdateParentEvent()
             return
-        
+
         elif key == 'delete':
             # pull text from next cell into current
             cell = self.walker.get_cell(i)
@@ -373,7 +373,7 @@
             if below.child is not None:
                 # cell below is a parent
                 raise CalcEvent, E_cant_combine
-            
+
             edit = self.walker.get_cell(i).edit
             edit.set_edit_text( edit.edit_text +
                 below.edit.edit_text )
@@ -385,53 +385,53 @@
             return
         return key
 
-    
+
     def move_focus_next(self, size):
         f, (i, sub) = self.walker.get_focus()
         assert i<len(self.content)-1
-        
+
         ni = i
         while ni == i:
             self.frame.keypress(size, 'down')
             nf, (ni, nsub) = self.walker.get_focus()
-    
+
     def move_focus_prev(self, size):
         f, (i, sub) = self.walker.get_focus()
         assert i>0
-        
+
         ni = i
         while ni == i:
             self.frame.keypress(size, 'up')
             nf, (ni, nsub) = self.walker.get_focus()
-            
-            
+
+
     def update_results( self, start_from=None ):
         """Update column.  Return True if final result changed.
-        
+
         start_from -- Cell to start updating from or None to start from
                       the current focus (default None)
         """
-        
+
         if start_from is None:
             f, (i, sub) = self.walker.get_focus()
         else:
             i = self.content.index(start_from)
             if i == None: return False
-        
+
         focus_cell = self.walker.get_cell(i)
-        
+
         if focus_cell.is_top:
             x = focus_cell.get_value()
             last_op = None
-        else:    
+        else:
             last_cell = self.walker.get_cell(i-1)
             x = last_cell.get_result()
-            
+
             if x is not None and focus_cell.op is not None:
-                x = OPERATORS[focus_cell.op]( x, 
+                x = OPERATORS[focus_cell.op]( x,
                     focus_cell.get_value() )
             focus_cell.set_result(x)
-        
+
         for cell in self.content[i+1:]:
             if cell.op is None:
                 x = None
@@ -443,11 +443,11 @@
 
         return True
 
-    
+
     def create_child( self, letter ):
         """Return (parent cell,child column) or None,None on failure."""
         f, (i, sub) = self.walker.get_focus()
-        if sub != 0: 
+        if sub != 0:
             # f is not an edit widget
             return None, None
 
@@ -467,10 +467,10 @@
 
         return len(self.content)==1 and self.content[0].is_empty()
 
-    
+
     def get_expression(self):
         """Return the expression as a printable string."""
-        
+
         l = []
         for c in self.content:
             if c.op is not None: # only applies to first cell
@@ -479,16 +479,16 @@
                 l.append("("+c.child.get_expression()+")")
             else:
                 l.append("%d"%c.get_value())
-                
+
         return "".join(l)
 
     def get_result(self):
         """Return the result of the last cell in the column."""
-        
+
         return self.content[-1].get_result()
-        
 
-        
+
+
 
 class HelpColumn(urwid.BoxWidget):
     help_text = [
@@ -507,8 +507,8 @@
         "",
         [ "Sub-expressions: ", ('key', "("), " and ", ('key', ")") ],
         "",
-        [ "Columns: ", ('key', COLUMN_KEYS[0]), " and ", 
-            ('key',COLUMN_KEYS[1]), "-", 
+        [ "Columns: ", ('key', COLUMN_KEYS[0]), " and ",
+            ('key',COLUMN_KEYS[1]), "-",
             ('key',COLUMN_KEYS[-1]) ],
         "",
         [ "Exit: ", ('key', "Q") ],
@@ -516,39 +516,39 @@
         "",
         ["Column Calculator does operations in the order they are ",
             "typed, not by following usual precedence rules.  ",
-            "If you want to calculate ", ('key', "12 - 2 * 3"), 
+            "If you want to calculate ", ('key', "12 - 2 * 3"),
             " with the multiplication happening before the ",
-            "subtraction you must type ", 
+            "subtraction you must type ",
             ('key', "12 - (2 * 3)"), " instead."],
         ]
-        
+
     def __init__(self):
         self.head = urwid.AttrWrap(
             urwid.Text(["Help Column ", ('key',"?")],
                 layout = CALC_LAYOUT),
             'help')
-        self.foot = urwid.AttrWrap( 
+        self.foot = urwid.AttrWrap(
             urwid.Text(["[text continues.. press ",
             ('key',"?"), " then scroll]"]), 'helpnote' )
         self.items = [urwid.Text(x) for x in self.help_text]
         self.listbox = urwid.ListBox(urwid.SimpleListWalker(self.items))
         self.body = urwid.AttrWrap( self.listbox, 'help' )
         self.frame = urwid.Frame( self.body, header=self.head)
-    
+
     def render(self, size, focus=False):
         maxcol, maxrow = size
         head_rows = self.head.rows((maxcol,))
-        if "bottom" in self.listbox.ends_visible( 
+        if "bottom" in self.listbox.ends_visible(
             (maxcol, maxrow-head_rows) ):
             self.frame.footer = None
         else:
             self.frame.footer = self.foot
 
         return self.frame.render( (maxcol, maxrow), focus)
-    
+
     def keypress( self, size, key ):
         return self.frame.keypress( size, key )
-        
+
 
 class CalcDisplay:
     palette = [
@@ -563,7 +563,7 @@
         ('event', 'light red', 'black', 'standout'),
         ('confirm', 'yellow', 'black', 'bold'),
         ]
-    
+
     def __init__(self):
         self.columns = urwid.Columns([HelpColumn(), CellColumn("A")], 1)
         self.col_list = self.columns.widget_list
@@ -586,7 +586,7 @@
     def input_filter(self, input, raw_input):
         if 'q' in input or 'Q' in input:
             raise urwid.ExitMainLoop()
-        
+
         # handle other keystrokes
         for k in input:
             try:
@@ -597,51 +597,51 @@
                 # display any message
                 self.event = e
                 self.view.footer = e.widget()
-        
+
         # remove all input from further processing by MainLoop
         return []
-            
+
     def wrap_keypress(self, key):
         """Handle confirmation and throw event on bad input."""
-        
+
         try:
             key = self.keypress(key)
-            
+
         except ColumnDeleteEvent, e:
             if e.letter == COLUMN_KEYS[1]:
                 # cannot delete the first column, ignore key
                 return
-            
+
             if not self.column_empty( e.letter ):
                 # need to get two in a row, so check last event
                 if not isinstance(self.event,ColumnDeleteEvent):
                     # ask for confirmation
                     raise e
             self.delete_column(e.letter)
-            
+
         except UpdateParentEvent, e:
             self.update_parent_columns()
             return
-        
+
         if key is None:
             return
 
         if self.columns.get_focus_column() == 0:
             if key not in ('up','down','page up','page down'):
                 raise CalcEvent, E_invalid_in_help_col
-        
+
         if key not in EDIT_KEYS and key not in MOVEMENT_KEYS:
             raise CalcEvent, E_invalid_key % key.upper()
-        
+
     def keypress(self, key):
         """Handle a keystroke."""
 
         self.loop.process_input([key])
-        
+
         if key.upper() in COLUMN_KEYS:
             # column switch
             i = COLUMN_KEYS.index(key.upper())
-            if i >= len( self.col_list ): 
+            if i >= len( self.col_list ):
                 raise CalcEvent, E_no_such_column % key.upper()
             self.columns.set_focus_column( i )
             return
@@ -650,7 +650,7 @@
             if len( self.col_list ) >= len(COLUMN_KEYS):
                 raise CalcEvent, E_no_more_columns
             i = self.columns.get_focus_column()
-            if i == 0: 
+            if i == 0:
                 # makes no sense in help column
                 return key
             col = self.col_list[i]
@@ -662,7 +662,7 @@
             self.col_list.append(child)
             self.set_link( parent, col, child )
             self.columns.set_focus_column(len(self.col_list)-1)
-        
+
         elif key == ")":
             i = self.columns.get_focus_column()
             if i == 0:
@@ -670,43 +670,43 @@
                 return key
             col = self.col_list[i]
             parent, pcol = self.get_parent( col )
-            if parent is None: 
+            if parent is None:
                 # column has no parent
                 raise CalcEvent, E_no_parent_column
-            
+
             new_i = self.col_list.index( pcol )
             self.columns.set_focus_column( new_i )
         else:
             return key
-    
+
     def set_link( self, parent, pcol, child ):
         """Store the link between a parent cell and child column.
-        
+
         parent -- parent Cell object
         pcol -- CellColumn where parent resides
         child -- child CellColumn object"""
 
         self.col_link[ child ] = parent, pcol
-    
+
     def get_parent( self, child ):
         """Return the parent and parent column for a given column."""
 
         return self.col_link.get( child, (None,None) )
-    
+
     def column_empty(self, letter):
         """Return True if the column passed is empty."""
-        
+
         i = COLUMN_KEYS.index(letter)
         col = self.col_list[i]
         return col.is_empty()
-        
-    
+
+
     def delete_column(self, letter):
         """Delete the column with the given letter."""
-        
+
         i = COLUMN_KEYS.index(letter)
         col = self.col_list[i]
-        
+
         parent, pcol = self.get_parent( col )
 
         f = self.columns.get_focus_column()
@@ -714,11 +714,11 @@
             # move focus to the parent column
             f = self.col_list.index(pcol)
             self.columns.set_focus_column(f)
-        
+
         parent.remove_child()
         pcol.update_results(parent)
         del self.col_list[i]
-        
+
         # delete children of this column
         keep_right_cols = []
         remove_cols = [col]
@@ -732,7 +732,7 @@
             # remove the links
             del self.col_link[rc]
         # keep only the non-children
-        self.col_list[i:] = keep_right_cols        
+        self.col_list[i:] = keep_right_cols
 
         # fix the letter assignments
         for j in range(i, len(self.col_list)):
@@ -750,21 +750,21 @@
         col = self.col_list[f]
         while 1:
             parent, pcol = self.get_parent(col)
-            if pcol is None: 
+            if pcol is None:
                 return
 
             changed = pcol.update_results( start_from = parent )
-            if not changed: 
+            if not changed:
                 return
             col = pcol
-            
-            
+
+
     def get_expression_result(self):
         """Return (expression, result) as strings."""
-        
+
         col = self.col_list[1]
         return col.get_expression(), "%d"%col.get_result()
-            
+
 
 
 class CalcNumLayout(urwid.TextLayout):
@@ -800,19 +800,19 @@
 
         return l
 
-    
-        
-        
+
+
+
 def main():
     """Launch Column Calculator."""
     global CALC_LAYOUT
     CALC_LAYOUT = CalcNumLayout()
-    
+
     urwid.web_display.set_preferences("Column Calculator")
     # try to handle short web requests quickly
     if urwid.web_display.handle_short_request():
         return
-    
+
     CalcDisplay().main()
 
 if '__main__'==__name__ or urwid.web_display.is_web_request():
diff -Nru urwid-1.2.1/examples/dialog.py urwid-1.3.0/examples/dialog.py
--- urwid-1.2.1/examples/dialog.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/dialog.py	2014-10-17 20:09:04.000000000 +0200
@@ -42,7 +42,7 @@
         ('focus','white','dark blue','bold'),
         ('focustext','light gray','dark blue'),
         ]
-        
+
     def __init__(self, text, height, width, body=None):
         width = int(width)
         if width <= 0:
@@ -50,7 +50,7 @@
         height = int(height)
         if height <= 0:
             height = ('relative', 80)
-    
+
         self.body = body
         if body is None:
             # fill space with nothing
@@ -61,24 +61,24 @@
             self.frame.header = urwid.Pile( [urwid.Text(text),
                 urwid.Divider()] )
         w = self.frame
-        
+
         # pad area around listbox
         w = urwid.Padding(w, ('fixed left',2), ('fixed right',2))
         w = urwid.Filler(w, ('fixed top',1), ('fixed bottom',1))
         w = urwid.AttrWrap(w, 'body')
-        
+
         # "shadow" effect
         w = urwid.Columns( [w,('fixed', 2, urwid.AttrWrap(
             urwid.Filler(urwid.Text(('border','  ')), "top")
             ,'shadow'))])
-        w = urwid.Frame( w, footer = 
+        w = urwid.Frame( w, footer =
             urwid.AttrWrap(urwid.Text(('border','  ')),'shadow'))
 
         # outermost border area
         w = urwid.Padding(w, 'center', width )
         w = urwid.Filler(w, 'middle', height )
         w = urwid.AttrWrap( w, 'border' )
-        
+
         self.view = w
 
 
@@ -102,10 +102,10 @@
             self.loop.run()
         except DialogExit, e:
             return self.on_exit( e.args[0] )
-        
+
     def on_exit(self, exitcode):
         return exitcode, ""
-        
+
 
 
 class InputDialogDisplay(DialogDisplay):
@@ -113,11 +113,11 @@
         self.edit = urwid.Edit()
         body = urwid.ListBox([self.edit])
         body = urwid.AttrWrap(body, 'selectable','focustext')
-        
+
         DialogDisplay.__init__(self, text, height, width, body)
-        
+
         self.frame.set_focus('body')
-    
+
     def unhandled_key(self, size, k):
         if k in ('up','page up'):
             self.frame.set_focus('body')
@@ -127,11 +127,11 @@
             # pass enter to the "ok" button
             self.frame.set_focus('footer')
             self.view.keypress( size, k )
-    
+
     def on_exit(self, exitcode):
         return exitcode, self.edit.get_edit_text()
 
-    
+
 class TextDialogDisplay(DialogDisplay):
     def __init__(self, file, height, width):
         l = []
@@ -154,20 +154,20 @@
 class ListDialogDisplay(DialogDisplay):
     def __init__(self, text, height, width, constr, items, has_default):
         j = []
-        if has_default:    
+        if has_default:
             k, tail = 3, ()
-        else:    
+        else:
             k, tail = 2, ("no",)
         while items:
             j.append( items[:k] + tail )
             items = items[k:]
-                    
+
         l = []
         self.items = []
         for tag, item, default in j:
             w = constr( tag, default=="on" )
             self.items.append(w)
-            w = urwid.Columns( [('fixed', 12, w), 
+            w = urwid.Columns( [('fixed', 12, w),
                 urwid.Text(item)], 2 )
             w = urwid.AttrWrap(w, 'selectable','focus')
             l.append(w)
@@ -175,9 +175,9 @@
         lb = urwid.ListBox(l)
         lb = urwid.AttrWrap( lb, "selectable" )
         DialogDisplay.__init__(self, text, height, width, lb )
-        
+
         self.frame.set_focus('body')
-    
+
     def unhandled_key(self, size, k):
         if k in ('up','page up'):
             self.frame.set_focus('body')
@@ -199,14 +199,14 @@
                 s = i.get_label()
                 break
         return exitcode, s
-        
-    
-    
+
+
+
 
 class CheckListDialogDisplay(ListDialogDisplay):
     def on_exit(self, exitcode):
         """
-        Mimic dialog(1)'s --checklist exit. 
+        Mimic dialog(1)'s --checklist exit.
         Put each checked item in double quotes with a trailing space.
         """
         if exitcode != 0:
@@ -250,7 +250,7 @@
     d = CheckListDialogDisplay( text, height, width, constr, items, True)
     d.add_buttons([    ("OK", 0), ("Cancel", 1) ])
     return d
-    
+
 def do_inputbox(text, height, width):
     d = InputDialogDisplay( text, height, width )
     d.add_buttons([    ("Exit", 0) ])
@@ -286,22 +286,22 @@
     d.add_buttons([    ("Yes", 0), ("No", 1) ])
     return d
 
-MODES={    '--checklist':    (do_checklist, 
+MODES={    '--checklist':    (do_checklist,
         "text height width list-height [ tag item status ] ..."),
-    '--inputbox':    (do_inputbox, 
+    '--inputbox':    (do_inputbox,
         "text height width"),
-    '--menu':    (do_menu, 
+    '--menu':    (do_menu,
         "text height width menu-height [ tag item ] ..."),
-    '--msgbox':    (do_msgbox, 
+    '--msgbox':    (do_msgbox,
         "text height width"),
-    '--radiolist':    (do_radiolist, 
+    '--radiolist':    (do_radiolist,
         "text height width list-height [ tag item status ] ..."),
     '--textbox':    (do_textbox,
         "file height width"),
-    '--yesno':    (do_yesno, 
+    '--yesno':    (do_yesno,
         "text height width"),
     }
-    
+
 
 def show_usage():
     """
@@ -310,7 +310,7 @@
     modelist = [(mode, help) for (mode, (fn, help)) in MODES.items()]
     modelist.sort()
     sys.stdout.write(
-        __doc__ + 
+        __doc__ +
         "\n".join(["%-15s %s"%(mode,help) for (mode,help) in modelist])
         + """
 
@@ -321,23 +321,23 @@
 
 
 def main():
-    if len(sys.argv) < 2 or not MODES.has_key(sys.argv[1]):
+    if len(sys.argv) < 2 or sys.argv[1] not in MODES:
         show_usage()
         return
-    
+
     # Create a DialogDisplay instance
     fn, help = MODES[sys.argv[1]]
     d = fn( * sys.argv[2:] )
-    
+
     # Run it
     exitcode, exitstring = d.main()
-    
+
     # Exit
     if exitstring:
         sys.stderr.write(exitstring+"\n")
-    
+
     sys.exit(exitcode)
-        
 
-if __name__=="__main__": 
+
+if __name__=="__main__":
     main()
diff -Nru urwid-1.2.1/examples/edit.py urwid-1.3.0/examples/edit.py
--- urwid-1.2.1/examples/edit.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/edit.py	2014-10-17 20:09:04.000000000 +0200
@@ -37,30 +37,30 @@
 
 class LineWalker(urwid.ListWalker):
     """ListWalker-compatible class for lazily reading file contents."""
-    
+
     def __init__(self, name):
         self.file = open(name)
         self.lines = []
         self.focus = 0
-    
-    def get_focus(self): 
+
+    def get_focus(self):
         return self._get_at_pos(self.focus)
-    
+
     def set_focus(self, focus):
         self.focus = focus
         self._modified()
-    
+
     def get_next(self, start_from):
         return self._get_at_pos(start_from + 1)
-    
+
     def get_prev(self, start_from):
         return self._get_at_pos(start_from - 1)
 
     def read_next_line(self):
         """Read another line from the file."""
-        
+
         next_line = self.file.readline()
-        
+
         if not next_line or next_line[-1:] != '\n':
             # no newline on last line of file
             self.file = None
@@ -69,22 +69,22 @@
             next_line = next_line[:-1]
 
         expanded = next_line.expandtabs()
-        
+
         edit = urwid.Edit("", expanded, allow_tab=True)
         edit.set_edit_pos(0)
         edit.original_text = next_line
         self.lines.append(edit)
 
         return next_line
-        
-    
+
+
     def _get_at_pos(self, pos):
         """Return a widget for the line number passed."""
-        
+
         if pos < 0:
             # line 0 is the start of the file, no more above
             return None, None
-            
+
         if len(self.lines) > pos:
             # we have that line so return it
             return self.lines[pos], pos
@@ -96,12 +96,12 @@
         assert pos == len(self.lines), "out of order request?"
 
         self.read_next_line()
-        
+
         return self.lines[-1], pos
-    
+
     def split_focus(self):
         """Divide the focus edit widget at the cursor location."""
-        
+
         focus = self.lines[self.focus]
         pos = focus.edit_pos
         edit = urwid.Edit("",focus.edit_text[pos:], allow_tab=True)
@@ -117,7 +117,7 @@
         if above is None:
             # already at the top
             return
-        
+
         focus = self.lines[self.focus]
         above.set_edit_pos(len(above.edit_text))
         above.set_edit_text(above.edit_text + focus.edit_text)
@@ -131,7 +131,7 @@
         if below is None:
             # already at bottom
             return
-        
+
         focus = self.lines[self.focus]
         focus.set_edit_text(focus.edit_text + below.edit_text)
         del self.lines[self.focus+1]
@@ -143,16 +143,16 @@
         ('foot','dark cyan', 'dark blue', 'bold'),
         ('key','light cyan', 'dark blue', 'underline'),
         ]
-        
+
     footer_text = ('foot', [
         "Text Editor    ",
         ('key', "F5"), " save  ",
         ('key', "F8"), " quit",
         ])
-    
+
     def __init__(self, name):
         self.save_name = name
-        self.walker = LineWalker(name) 
+        self.walker = LineWalker(name)
         self.listbox = urwid.ListBox(self.walker)
         self.footer = urwid.AttrWrap(urwid.Text(self.footer_text),
             "foot")
@@ -163,7 +163,7 @@
         self.loop = urwid.MainLoop(self.view, self.palette,
             unhandled_input=self.unhandled_keypress)
         self.loop.run()
-    
+
     def unhandled_keypress(self, k):
         """Last resort for keypresses."""
 
@@ -197,11 +197,11 @@
         else:
             return
         return True
-            
+
 
     def save_file(self):
         """Write the file out to disk."""
-        
+
         l = []
         walk = self.walker
         for edit in walk.lines:
@@ -210,14 +210,14 @@
                 l.append(edit.original_text)
             else:
                 l.append(re_tab(edit.edit_text))
-        
+
         # then the rest
         while walk.file is not None:
             l.append(walk.read_next_line())
-            
+
         # write back to disk
         outfile = open(self.save_name, "w")
-        
+
         prefix = ""
         for line in l:
             outfile.write(prefix + line)
@@ -249,7 +249,7 @@
         sys.stderr.write(__doc__)
         return
     EditDisplay(name).main()
-    
 
-if __name__=="__main__": 
+
+if __name__=="__main__":
     main()
diff -Nru urwid-1.2.1/examples/fib.py urwid-1.3.0/examples/fib.py
--- urwid-1.2.1/examples/fib.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/fib.py	2014-10-17 20:09:04.000000000 +0200
@@ -28,32 +28,32 @@
 """
 
 import urwid
-        
+
 class FibonacciWalker(urwid.ListWalker):
     """ListWalker-compatible class for browsing fibonacci set.
-    
+
     positions returned are (value at position-1, value at position) tuples.
     """
     def __init__(self):
         self.focus = (0L,1L)
         self.numeric_layout = NumericLayout()
-    
+
     def _get_at_pos(self, pos):
         """Return a widget and the position passed."""
         return urwid.Text("%d"%pos[1], layout=self.numeric_layout), pos
-    
-    def get_focus(self): 
+
+    def get_focus(self):
         return self._get_at_pos(self.focus)
-    
+
     def set_focus(self, focus):
         self.focus = focus
         self._modified()
-    
+
     def get_next(self, start_from):
         a, b = start_from
         focus = b, a+b
         return self._get_at_pos(focus)
-    
+
     def get_prev(self, start_from):
         a, b = start_from
         focus = b-a, a
@@ -66,7 +66,7 @@
         ('key','light cyan', 'black', 'underline'),
         ('title', 'white', 'black',),
         ]
-        
+
     footer_text = [
         ('title', "Fibonacci Set Viewer"), "    ",
         ('key', "UP"), ", ", ('key', "DOWN"), ", ",
@@ -74,7 +74,7 @@
         " move view  ",
         ('key', "Q"), " exits",
         ]
-    
+
     def exit_on_q(input):
         if input in ('q', 'Q'):
             raise urwid.ExitMainLoop()
@@ -108,5 +108,5 @@
             return [[(width, x, x+width)] for x in linestarts]
 
 
-if __name__=="__main__": 
+if __name__=="__main__":
     main()
diff -Nru urwid-1.2.1/examples/graph.py urwid-1.3.0/examples/graph.py
--- urwid-1.2.1/examples/graph.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/graph.py	2014-10-17 20:09:04.000000000 +0200
@@ -20,7 +20,7 @@
 # Urwid web site: http://excess.org/urwid/
 
 """
-Urwid example demonstrating use of the BarGraph widget and creating a 
+Urwid example demonstrating use of the BarGraph widget and creating a
 floating-window appearance.  Also shows use of alarms to create timed
 animation.
 """
@@ -33,12 +33,12 @@
 UPDATE_INTERVAL = 0.2
 
 def sin100( x ):
-    """ 
+    """
     A sin function that returns values between 0 and 100 and repeats
     after x == 100.
     """
     return 50 + 50 * math.sin( x * math.pi / 50 )
-    
+
 class GraphModel:
     """
     A class responsible for storing the data that will be displayed
@@ -46,14 +46,14 @@
     """
 
     data_max_value = 100
-    
+
     def __init__(self):
         data = [ ('Saw', range(0,100,2)*2),
             ('Square', [0]*30 + [100]*30),
             ('Sine 1', [sin100(x) for x in range(100)] ),
-            ('Sine 2', [(sin100(x) + sin100(x*2))/2 
+            ('Sine 2', [(sin100(x) + sin100(x*2))/2
                 for x in range(100)] ),
-            ('Sine 3', [(sin100(x) + sin100(x*3))/2 
+            ('Sine 3', [(sin100(x) + sin100(x*3))/2
                 for x in range(100)] ),
             ]
         self.modes = []
@@ -61,13 +61,13 @@
         for m, d in data:
             self.modes.append(m)
             self.data[m] = d
-    
+
     def get_modes(self):
         return self.modes
-    
+
     def set_mode(self, m):
         self.current_mode = m
-    
+
     def get_data(self, offset, r):
         """
         Return the data in [offset:offset+r], the maximum value
@@ -108,11 +108,11 @@
         ('pg complete',  'white',      'dark magenta'),
         ('pg smooth',     'dark magenta','black')
         ]
-        
+
     graph_samples_per_bar = 10
     graph_num_bars = 5
     graph_offset_per_second = 5
-    
+
     def __init__(self, controller):
         self.controller = controller
         self.started = True
@@ -146,7 +146,7 @@
             else:
                 l.append([value,0])
         self.graph.set_data(l,max_value)
-        
+
         # also update progress
         if (o//repeat)&1:
             # show 100% for first half, 0 for second half
@@ -171,8 +171,8 @@
             self.started = True
             self.start_time = time.time()
             self.controller.animate_graph()
-            
-    
+
+
     def on_reset_button(self, w):
         self.offset = 0
         self.start_time = time.time()
@@ -199,13 +199,13 @@
         self.animate_progress = self.progress_bar( state )
         self.animate_progress_wrap._w = self.animate_progress
         self.update_graph( True )
-        
+
 
     def main_shadow(self, w):
         """Wrap a shadow and background around widget w."""
         bg = urwid.AttrWrap(urwid.SolidFill(u"\u2592"), 'screen edge')
         shadow = urwid.AttrWrap(urwid.SolidFill(u" "), 'main shadow')
-        
+
         bg = urwid.Overlay( shadow, bg,
             ('fixed left', 3), ('fixed right', 1),
             ('fixed top', 2), ('fixed bottom', 1))
@@ -213,7 +213,7 @@
             ('fixed left', 2), ('fixed right', 3),
             ('fixed top', 1), ('fixed bottom', 2))
         return w
-        
+
     def bar_graph(self, smooth=False):
         satt = None
         if smooth:
@@ -233,7 +233,7 @@
 
     def progress_bar(self, smooth=False):
         if smooth:
-            return urwid.ProgressBar('pg normal', 'pg complete', 
+            return urwid.ProgressBar('pg normal', 'pg complete',
                 0, 1, 'pg smooth')
         else:
             return urwid.ProgressBar('pg normal', 'pg complete',
@@ -255,11 +255,11 @@
         self.on_animate_button( self.animate_button )
         self.offset = 0
         self.animate_progress = self.progress_bar()
-        animate_controls = urwid.GridFlow( [ 
+        animate_controls = urwid.GridFlow( [
             self.animate_button,
             self.button("Reset", self.on_reset_button),
             ], 9, 2, 0, 'center')
-        
+
         if urwid.get_encoding_mode() == "utf8":
             unicode_checkbox = urwid.CheckBox(
                 "Enable Unicode Graphics",
@@ -267,10 +267,10 @@
         else:
             unicode_checkbox = urwid.Text(
                 "UTF-8 encoding not detected")
-            
+
         self.animate_progress_wrap = urwid.WidgetWrap(
             self.animate_progress)
-        
+
         l = [    urwid.Text("Mode",align="center"),
             ] + self.mode_buttons + [
             urwid.Divider(),
@@ -285,7 +285,7 @@
         w = urwid.ListBox(urwid.SimpleListWalker(l))
         return w
 
-    def main_window(self): 
+    def main_window(self):
         self.graph = self.bar_graph()
         self.graph_wrap = urwid.WidgetWrap( self.graph )
         vline = urwid.AttrWrap( urwid.SolidFill(u'\u2502'), 'line')
@@ -299,7 +299,7 @@
         w = urwid.AttrWrap(w,'line')
         w = self.main_shadow(w)
         return w
-        
+
 
 class GraphController:
     """
@@ -320,17 +320,17 @@
     def get_modes(self):
         """Allow our view access to the list of modes."""
         return self.model.get_modes()
-    
+
     def set_mode(self, m):
         """Allow our view to set the mode."""
         rval = self.model.set_mode( m )
         self.view.update_graph(True)
         return rval
-    
+
     def get_data(self, offset, range):
         """Provide data to our view for the graph."""
         return self.model.get_data( offset, range )
-    
+
 
     def main(self):
         self.loop = urwid.MainLoop(self.view, self.view.palette)
@@ -347,10 +347,10 @@
         if self.animate_alarm:
             self.loop.remove_alarm(self.animate_alarm)
         self.animate_alarm = None
-    
+
 
 def main():
     GraphController().main()
-    
+
 if '__main__'==__name__:
     main()
diff -Nru urwid-1.2.1/examples/input_test.py urwid-1.3.0/examples/input_test.py
--- urwid-1.2.1/examples/input_test.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/input_test.py	2014-10-17 20:09:04.000000000 +0200
@@ -63,9 +63,9 @@
                 t += ["("] + out + [")"]
             else:
                 t += ["'",('key',k),"' "]
-        
+
         rawt = urwid.Text(", ".join(["%d"%r for r in raw]))
-        
+
         if t:
             lw.append(
                 urwid.Columns([
@@ -87,8 +87,8 @@
         loop.run()
     finally:
         screen.tty_signal_keys(*old)
-    
-                
+
+
 
 
 def main():
@@ -96,7 +96,7 @@
     if urwid.web_display.handle_short_request():
         return
     key_test()
-    
+
 
 if '__main__'==__name__ or urwid.web_display.is_web_request():
     main()
diff -Nru urwid-1.2.1/examples/lcd_cf635.py urwid-1.3.0/examples/lcd_cf635.py
--- urwid-1.2.1/examples/lcd_cf635.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/lcd_cf635.py	2014-10-17 20:09:04.000000000 +0200
@@ -13,7 +13,7 @@
 ...... ...... ......
   0x11   0xd0   0xbb
 
-By adding the characters in CGRAM below we can use them as part of a 
+By adding the characters in CGRAM below we can use them as part of a
 horizontal slider control, selected check box and selected radio button
 respectively.
 """
@@ -22,14 +22,14 @@
 import urwid.lcd_display
 
 CGRAM = """
-...... ...... ...... ...... ..X... ...... ...... ...... 
-XXXXXX XXXXXX XXXXXX XXXXXX X.XX.. .XXXXX ..XXX. .....X 
-...... XX.... XXXX.. XXXXXX X.XXX. .X...X .X...X ....XX 
-...... XX.... XXXX.. XXXXXX X.XXXX .X...X .X...X .X.XX. 
-...... XX.... XXXX.. XXXXXX X.XXX. .X...X .X...X .XXX.. 
-XXXXXX XXXXXX XXXXXX XXXXXX X.XX.. .XXXXX ..XXX. ..X... 
-...... ...... ...... ...... ..X... ...... ...... ...... 
-...... ...... ...... ...... ...... ...... ...... ...... 
+...... ...... ...... ...... ..X... ...... ...... ......
+XXXXXX XXXXXX XXXXXX XXXXXX X.XX.. .XXXXX ..XXX. .....X
+...... XX.... XXXX.. XXXXXX X.XXX. .X...X .X...X ....XX
+...... XX.... XXXX.. XXXXXX X.XXXX .X...X .X...X .X.XX.
+...... XX.... XXXX.. XXXXXX X.XXX. .X...X .X...X .XXX..
+XXXXXX XXXXXX XXXXXX XXXXXX X.XX.. .XXXXX ..XXX. ..X...
+...... ...... ...... ...... ..X... ...... ...... ......
+...... ...... ...... ...... ...... ...... ...... ......
 """
 
 def program_cgram(screen):
@@ -94,11 +94,11 @@
         filled = urwid.int_scale(self.value, self.range, steps)
         full_segments = int(filled / (len(self.segments) - 1))
         last_char = filled % (len(self.segments) - 1) + 1
-        s = (self.segments[-1] * full_segments + 
+        s = (self.segments[-1] * full_segments +
             self.segments[last_char] +
             self.segments[0] * (maxcol -full_segments - 1))
         return urwid.Text(s).render(size)
-        
+
     def move_position(self, size, direction):
         """
         Update and return the value one step +ve or -ve, based on
@@ -166,7 +166,7 @@
             ('fixed', 1, urwid.SelectableIcon('\xdf', cursor_position=0)),
             self._label])
 
-        urwid.connect_signal(self, 'click', 
+        urwid.connect_signal(self, 'click',
             lambda option: show_menu(submenu))
 
     def keypress(self, size, key):
@@ -214,10 +214,10 @@
             apply an exponential transformation to values sent so
             that apparent brightness increases in a natural way.
             """
-            return lambda value: screen.set_led_pin(index, rg, 
-                [0, 1, 2, 3, 4, 5, 6, 8, 11, 14, 18, 
+            return lambda value: screen.set_led_pin(index, rg,
+                [0, 1, 2, 3, 4, 5, 6, 8, 11, 14, 18,
                 23, 29, 38, 48, 61, 79, 100][value])
-            
+
         return urwid.Columns([
             ('fixed', 2, urwid.Text('%dR' % index)),
             LCDHorizontalSlider(18, 0, exp_scale_led(0)),
@@ -228,15 +228,15 @@
     menu_structure = [
         ('Display Settings', [
             display_setting('Brightness', 101, screen.set_backlight),
-            display_setting('Contrast', 76, 
+            display_setting('Contrast', 76,
                 lambda x: screen.set_lcd_contrast(x + 75)),
             ]),
         ('Cursor Settings', [
             cursor_option('Block', screen.CURSOR_BLINKING_BLOCK),
             cursor_option('Underscore', screen.CURSOR_UNDERSCORE),
-            cursor_option('Block + Underscore', 
+            cursor_option('Block + Underscore',
                 screen.CURSOR_BLINKING_BLOCK_UNDERSCORE),
-            cursor_option('Inverting Block', 
+            cursor_option('Inverting Block',
                 screen.CURSOR_INVERTING_BLINKING_BLOCK),
             ]),
         ('LEDs', [
@@ -279,7 +279,7 @@
 # set up our font
 program_cgram(screen)
 loop = urwid.MainLoop(build_menus(), screen=screen)
-# FIXME: want screen to know it is in narrow mode, or better yet, 
+# FIXME: want screen to know it is in narrow mode, or better yet,
 # do the unicode conversion for us
 urwid.set_encoding('narrow')
 
diff -Nru urwid-1.2.1/examples/palette_test.py urwid-1.3.0/examples/palette_test.py
--- urwid-1.2.1/examples/palette_test.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/palette_test.py	2014-10-17 20:09:04.000000000 +0200
@@ -34,10 +34,10 @@
 brown__   dark_red_   dark_magenta_   dark_blue_   dark_cyan_   dark_green_
 yellow_   light_red   light_magenta   light_blue   light_cyan   light_green
 
-              #00f#06f#08f#0af#0df#0ff        black_______    dark_gray___   
+              #00f#06f#08f#0af#0df#0ff        black_______    dark_gray___
             #60f#00d#06d#08d#0ad#0dd#0fd        light_gray__    white_______
-          #80f#60d#00a#06a#08a#0aa#0da#0fa        
-        #a0f#80d#60a#008#068#088#0a8#0d8#0f8        
+          #80f#60d#00a#06a#08a#0aa#0da#0fa
+        #a0f#80d#60a#008#068#088#0a8#0d8#0f8
       #d0f#a0d#80d#608#006#066#086#0a6#0d6#0f6
     #f0f#d0d#a0a#808#606#000#060#080#0a0#0d0#0f0#0f6#0f8#0fa#0fd#0ff
       #f0d#d0a#a08#806#600#660#680#6a0#6d0#6f0#6f6#6f8#6fa#6fd#6ff#0df
@@ -50,29 +50,29 @@
     #86d#66a#68a#6aa#6da                #f80#f86#f88#f8a#f8d#f8f#d6f#a0f
   #a6d#86a#668#688#6a8#6d8                #f60#f66#f68#f6a#f6d#f6f#d0f
 #d6d#a6a#868#666#686#6a6#6d6#6d8#6da#6dd    #f00#f06#f08#f0a#f0d#f0f
-  #d6a#a68#866#886#8a6#8d6#8d8#8da#8dd#6ad       
-    #d68#a66#a86#aa6#ad6#ad8#ada#add#8ad#68d   
-      #d66#d86#da6#dd6#dd8#dda#ddd#aad#88d#66d        g78_g82_g85_g89_g93_g100  
+  #d6a#a68#866#886#8a6#8d6#8d8#8da#8dd#6ad
+    #d68#a66#a86#aa6#ad6#ad8#ada#add#8ad#68d
+      #d66#d86#da6#dd6#dd8#dda#ddd#aad#88d#66d        g78_g82_g85_g89_g93_g100
                     #da6#da8#daa#dad#a8d#86d        g52_g58_g62_g66_g70_g74_
       #88a#8aa        #d86#d88#d8a#d8d#a6d        g27_g31_g35_g38_g42_g46_g50_
     #a8a#888#8a8#8aa    #d66#d68#d6a#d6d        g0__g3__g7__g11_g15_g19_g23_
-      #a88#aa8#aaa#88a                        
+      #a88#aa8#aaa#88a
             #a88#a8a
-"""                    
+"""
 
 CHART_88 = """
 brown__   dark_red_   dark_magenta_   dark_blue_   dark_cyan_   dark_green_
 yellow_   light_red   light_magenta   light_blue   light_cyan   light_green
 
-      #00f#08f#0cf#0ff            black_______    dark_gray___             
-    #80f#00c#08c#0cc#0fc            light_gray__    white_______           
+      #00f#08f#0cf#0ff            black_______    dark_gray___
+    #80f#00c#08c#0cc#0fc            light_gray__    white_______
   #c0f#80c#008#088#0c8#0f8
-#f0f#c0c#808#000#080#0c0#0f0#0f8#0fc#0ff            #88c#8cc        
-  #f0c#c08#800#880#8c0#8f0#8f8#8fc#8ff#0cf        #c8c#888#8c8#8cc   
+#f0f#c0c#808#000#080#0c0#0f0#0f8#0fc#0ff            #88c#8cc
+  #f0c#c08#800#880#8c0#8f0#8f8#8fc#8ff#0cf        #c8c#888#8c8#8cc
     #f08#c00#c80#cc0#cf0#cf8#cfc#cff#8cf#08f        #c88#cc8#ccc#88c
-      #f00#f80#fc0#ff0#ff8#ffc#fff#ccf#88f#00f            #c88#c8c        
-                    #fc0#fc8#fcc#fcf#c8f#80f    
-                      #f80#f88#f8c#f8f#c0f        g62_g74_g82_g89_g100  
+      #f00#f80#fc0#ff0#ff8#ffc#fff#ccf#88f#00f            #c88#c8c
+                    #fc0#fc8#fcc#fcf#c8f#80f
+                      #f80#f88#f8c#f8f#c0f        g62_g74_g82_g89_g100
                         #f00#f08#f0c#f0f        g0__g19_g35_g46_g52
 """
 
@@ -80,7 +80,7 @@
 brown__   dark_red_   dark_magenta_   dark_blue_   dark_cyan_   dark_green_
 yellow_   light_red   light_magenta   light_blue   light_cyan   light_green
 
-black_______    dark_gray___    light_gray__    white_______           
+black_______    dark_gray___    light_gray__    white_______
 """
 
 ATTR_RE = re.compile("(?P<whitespace>[ \n]*)(?P<entry>[^ \n]+)")
@@ -115,7 +115,7 @@
             attr, text = attrtext
             out.append((attr, text.ljust(elen)))
     return out
-            
+
 def foreground_chart(chart, background, colors):
     """
     Create text markup for a foreground colour chart
@@ -199,7 +199,7 @@
         if state:
             is_foreground_chart = chart_radio_buttons[0].state
             set_mode(colors, is_foreground_chart)
-            
+
     def mode_rb(text, colors, state=False):
         # mode radio buttons
         rb = urwid.RadioButton(mode_radio_buttons, text, state)
@@ -209,10 +209,10 @@
     def on_chart_change(rb, state):
         # handle foreground check box state change
         set_mode(screen.colors, state)
-        
+
     def click_exit(button):
         raise urwid.ExitMainLoop()
-    
+
     lb.extend([
         urwid.AttrMap(urwid.Text("Urwid Palette Test"), 'header'),
         urwid.AttrMap(urwid.Columns([
@@ -238,7 +238,7 @@
         ])
 
     set_mode(16, True) # displays the chart
-    
+
     def unhandled_input(key):
         if key in ('Q','q','esc'):
             raise urwid.ExitMainLoop()
diff -Nru urwid-1.2.1/examples/treesample.py urwid-1.3.0/examples/treesample.py
--- urwid-1.2.1/examples/treesample.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/treesample.py	2014-10-17 20:09:04.000000000 +0200
@@ -78,7 +78,7 @@
         ('flag', 'dark gray', 'light gray'),
         ('error', 'dark red', 'light gray'),
         ]
-    
+
     footer_text = [
         ('title', "Example Data Browser"), "    ",
         ('key', "UP"), ",", ('key', "DOWN"), ",",
@@ -87,7 +87,7 @@
         ('key', "+"), ",",
         ('key', "-"), "  ",
         ('key', "LEFT"), "  ",
-        ('key', "HOME"), "  ", 
+        ('key', "HOME"), "  ",
         ('key', "END"), "  ",
         ('key', "Q"),
         ]
@@ -99,14 +99,14 @@
         self.header = urwid.Text( "" )
         self.footer = urwid.AttrWrap( urwid.Text( self.footer_text ),
             'foot')
-        self.view = urwid.Frame( 
-            urwid.AttrWrap( self.listbox, 'body' ), 
-            header=urwid.AttrWrap(self.header, 'head' ), 
+        self.view = urwid.Frame(
+            urwid.AttrWrap( self.listbox, 'body' ),
+            header=urwid.AttrWrap(self.header, 'head' ),
             footer=self.footer )
 
     def main(self):
         """Run the program."""
-        
+
         self.loop = urwid.MainLoop(self.view, self.palette,
             unhandled_input=self.unhandled_input)
         self.loop.run()
@@ -123,7 +123,7 @@
         retval['children'].append({"name":"child " + str(i)})
         retval['children'][i]['children']=[]
         for j in range(10):
-            retval['children'][i]['children'].append({"name":"grandchild " + 
+            retval['children'][i]['children'].append({"name":"grandchild " +
                                                       str(i) + "." + str(j)})
     return retval
 
@@ -133,6 +133,6 @@
     ExampleTreeBrowser(sample).main()
 
 
-if __name__=="__main__": 
+if __name__=="__main__":
     main()
 
diff -Nru urwid-1.2.1/examples/twisted_serve_ssh.py urwid-1.3.0/examples/twisted_serve_ssh.py
--- urwid-1.2.1/examples/twisted_serve_ssh.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/twisted_serve_ssh.py	2014-10-17 20:09:04.000000000 +0200
@@ -34,6 +34,7 @@
 import os
 
 import urwid
+from urwid.raw_display import Screen
 
 from zope.interface import Interface, Attribute, implements
 from twisted.application.service import Application
@@ -159,7 +160,7 @@
 
 
 
-class TwistedScreen(urwid.BaseScreen):
+class TwistedScreen(Screen):
     """A Urwid screen which knows about the Twisted terminal protocol that is
     driving it.
 
@@ -180,7 +181,7 @@
         # We will need these later
         self.terminalProtocol = terminalProtocol
         self.terminal = terminalProtocol.terminal
-        urwid.BaseScreen.__init__(self)
+        Screen.__init__(self)
         self.colors = 16
         self._pal_escape = {}
         self.bright_is_bold = True
@@ -235,13 +236,22 @@
 
     # twisted handles polling, so we don't need the loop to do it, we just
     # push what we get to the loop from dataReceived.
-    def get_input_descriptors(self):
-        return []
+    def hook_event_loop(self, event_loop, callback):
+        self._urwid_callback = callback
+        self._evl = event_loop
+
+    def unhook_event_loop(self, event_loop):
+        pass
 
     # Do nothing here either. Not entirely sure when it gets called.
     def get_input(self, raw_keys=False):
         return
 
+    def get_available_raw_input(self):
+        data = self._data
+        self._data = []
+        return data
+
     # Twisted driven
     def push(self, data):
         """Receive data from Twisted and push it into the urwid main loop.
@@ -254,9 +264,8 @@
         3. Pass the calculated keys as a list to the Urwid main loop.
         4. Redraw the screen
         """
-        keys = self.loop.input_filter(data, [])
-        keys, remainder = urwid.escape.process_keyqueue(map(ord, keys), True)
-        self.loop.process_input(keys)
+        self._data = list(map(ord, data))
+        self.parse_input(self._evl, self._urwid_callback)
         self.loop.draw_screen()
 
     # Convenience
diff -Nru urwid-1.2.1/PKG-INFO urwid-1.3.0/PKG-INFO
--- urwid-1.2.1/PKG-INFO	2014-04-04 17:55:41.000000000 +0200
+++ urwid-1.3.0/PKG-INFO	2014-10-17 20:27:53.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: urwid
-Version: 1.2.1
+Version: 1.3.0
 Summary: A full-featured console (xterm et al.) user interface library
 Home-page: http://urwid.org/
 Author: Ian Ward
diff -Nru urwid-1.2.1/urwid/canvas.py urwid-1.3.0/urwid/canvas.py
--- urwid-1.2.1/urwid/canvas.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/canvas.py	2014-10-17 20:09:04.000000000 +0200
@@ -30,13 +30,13 @@
 class CanvasCache(object):
     """
     Cache for rendered canvases.  Automatically populated and
-    accessed by Widget render() MetaClass magic, cleared by 
+    accessed by Widget render() MetaClass magic, cleared by
     Widget._invalidate().
 
     Stores weakrefs to the canvas objects, so an external class
     must maintain a reference for this cache to be effective.
-    At present the Screen classes store the last topmost canvas 
-    after redrawing the screen, keeping the canvases from being 
+    At present the Screen classes store the last topmost canvas
+    after redrawing the screen, keeping the canvases from being
     garbage collected.
 
     _widgets[widget] = {(wcls, size, focus): weakref.ref(canvas), ...}
@@ -67,7 +67,7 @@
             Collect all child widgets for determining who we
             depend on.
             """
-            # FIXME: is this recursion necessary?  The cache 
+            # FIXME: is this recursion necessary?  The cache
             # invalidating might work with only one level.
             depends = []
             for x, y, c, pos in canv.children:
@@ -114,7 +114,7 @@
             cls.hits += 1 # more stats
         return canv
     fetch = classmethod(fetch)
-    
+
     def invalidate(cls, widget):
         """
         Remove all canvases cached for widget.
@@ -172,7 +172,7 @@
     clear = classmethod(clear)
 
 
-        
+
 class CanvasError(Exception):
     pass
 
@@ -198,12 +198,12 @@
         value1, value2, value3 -- if not None, raise a helpful error:
             the old Canvas class is now called TextCanvas.
         """
-        if value1 is not None: 
+        if value1 is not None:
             raise self._renamed_error
         self._widget_info = None
         self.coords = {}
         self.shortcuts = {}
-    
+
     def finalize(self, widget, size, focus):
         """
         Mark this canvas as finalized (should not be any future
@@ -226,7 +226,7 @@
 
     def _raise_old_repr_error(self, val=None):
         raise self._old_repr_error
-    
+
     def _text_content(self):
         """
         Return the text content of the canvas as a list of strings,
@@ -238,8 +238,8 @@
     text = property(_text_content, _raise_old_repr_error)
     attr = property(_raise_old_repr_error, _raise_old_repr_error)
     cs = property(_raise_old_repr_error, _raise_old_repr_error)
-    
-    def content(self, trim_left=0, trim_top=0, cols=None, rows=None, 
+
+    def content(self, trim_left=0, trim_top=0, cols=None, rows=None,
             attr=None):
         raise NotImplementedError()
 
@@ -248,7 +248,7 @@
 
     def rows(self):
         raise NotImplementedError()
-    
+
     def content_delta(self):
         raise NotImplementedError()
 
@@ -313,7 +313,7 @@
     """
     class for storing rendered text and attributes
     """
-    def __init__(self, text=None, attr=None, cs=None, 
+    def __init__(self, text=None, attr=None, cs=None,
         cursor=None, maxcol=None, check_width=True):
         """
         text -- list of strings, one for each line
@@ -324,7 +324,7 @@
         check_width -- check and fix width of all lines in text
         """
         Canvas.__init__(self)
-        if text == None: 
+        if text == None:
             text = []
 
         if check_width:
@@ -344,7 +344,7 @@
             else:
                 maxcol = 0
 
-        if attr == None: 
+        if attr == None:
             attr = [[] for x in range(len(text))]
         if cs == None:
             cs = [[] for x in range(len(text))]
@@ -352,7 +352,7 @@
         # pad text and attr to maxcol
         for i in range(len(text)):
             w = widths[i]
-            if w > maxcol: 
+            if w > maxcol:
                 raise CanvasError("Canvas text is wider than the maxcol specified \n%r\n%r\n%r"%(maxcol,widths,text))
             if w < maxcol:
                 text[i] = text[i] + bytes().rjust(maxcol-w)
@@ -361,13 +361,13 @@
                 raise CanvasError("Attribute extends beyond text \n%r\n%r" % (text[i],attr[i]) )
             if a_gap:
                 rle_append_modify( attr[i], (None, a_gap))
-            
+
             cs_gap = len(text[i]) - rle_len( cs[i] )
             if cs_gap < 0:
                 raise CanvasError("Character Set extends beyond text \n%r\n%r" % (text[i],cs[i]) )
             if cs_gap:
                 rle_append_modify( cs[i], (None, cs_gap))
-            
+
         self._attr = attr
         self._cs = cs
         self.cursor = cursor
@@ -383,7 +383,7 @@
     def cols(self):
         """Return the screen column width of this canvas."""
         return self._maxcol
-    
+
     def translated_coords(self,dx,dy):
         """
         Return cursor coords shifted by (dx, dy), or None if there
@@ -400,33 +400,33 @@
         Return the canvas content as a list of rows where each row
         is a list of (attr, cs, text) tuples.
 
-        trim_left, trim_top, cols, rows may be set by 
+        trim_left, trim_top, cols, rows may be set by
         CompositeCanvas when rendering a partially obscured
         canvas.
         """
         maxcol, maxrow = self.cols(), self.rows()
-        if not cols: 
+        if not cols:
             cols = maxcol - trim_left
         if not rows:
             rows = maxrow - trim_top
-            
+
         assert trim_left >= 0 and trim_left < maxcol
         assert cols > 0 and trim_left + cols <= maxcol
         assert trim_top >=0 and trim_top < maxrow
         assert rows > 0 and trim_top + rows <= maxrow
-        
+
         if trim_top or rows < maxrow:
             text_attr_cs = zip(
                 self._text[trim_top:trim_top+rows],
-                self._attr[trim_top:trim_top+rows], 
+                self._attr[trim_top:trim_top+rows],
                 self._cs[trim_top:trim_top+rows])
         else:
             text_attr_cs = zip(self._text, self._attr, self._cs)
-        
+
         for text, a_row, cs_row in text_attr_cs:
             if trim_left or cols < self._maxcol:
                 text, a_row, cs_row = trim_text_attr_cs(
-                    text, a_row, cs_row, trim_left, 
+                    text, a_row, cs_row, trim_left,
                     trim_left + cols)
             attr_cs = rle_product(a_row, cs_row)
             i = 0
@@ -437,20 +437,20 @@
                 row.append((a, cs, text[i:i+run]))
                 i += run
             yield row
-            
+
 
     def content_delta(self, other):
         """
         Return the differences between other and this canvas.
 
-        If other is the same object as self this will return no 
-        differences, otherwise this is the same as calling 
+        If other is the same object as self this will return no
+        differences, otherwise this is the same as calling
         content().
         """
         if other is self:
             return [self.cols()]*self.rows()
         return self.content()
-    
+
 
 
 class BlankCanvas(Canvas):
@@ -477,10 +477,10 @@
 
     def rows(self):
         raise NotImplementedError("BlankCanvas doesn't know its own size!")
-    
+
     def content_delta(self):
         raise NotImplementedError("BlankCanvas doesn't know its own size!")
-        
+
 blank_canvas = BlankCanvas()
 
 
@@ -496,14 +496,14 @@
         self._cs = cs[0][0]
         self.size = cols, rows
         self.cursor = None
-    
+
     def cols(self):
         return self.size[0]
-    
+
     def rows(self):
         return self.size[1]
 
-    def content(self, trim_left=0, trim_top=0, cols=None, rows=None, 
+    def content(self, trim_left=0, trim_top=0, cols=None, rows=None,
             attr=None):
         if cols is None:
             cols = self.size[0]
@@ -524,7 +524,7 @@
         if other is self:
             return [self.cols()]*self.rows()
         return self.content()
-        
+
 
 
 
@@ -538,15 +538,15 @@
 
         if canv is a CompositeCanvas, make a copy of its contents
         """
-        # a "shard" is a (num_rows, list of cviews) tuple, one for 
+        # a "shard" is a (num_rows, list of cviews) tuple, one for
         # each cview starting in this shard
 
         # a "cview" is a tuple that defines a view of a canvas:
         # (trim_left, trim_top, cols, rows, attr_map, canv)
 
         # a "shard tail" is a list of tuples:
-        # (col_gap, done_rows, content_iter, cview) 
-        
+        # (col_gap, done_rows, content_iter, cview)
+
         # tuples that define the unfinished cviews that are part of
         # shards following the first shard.
         Canvas.__init__(self)
@@ -559,7 +559,7 @@
                 self.shards = canv.shards
             else:
                 self.shards = [(canv.rows(), [
-                    (0, 0, canv.cols(), canv.rows(), 
+                    (0, 0, canv.cols(), canv.rows(),
                     None, canv)])]
             self.children = [(0, 0, canv, None)]
             self.coords.update(canv.coords)
@@ -583,7 +583,7 @@
         assert isinstance(cols, int)
         return cols
 
-        
+
     def content(self):
         """
         Return the canvas content as a list of rows where each row
@@ -598,11 +598,11 @@
             for i in range(num_rows):
                 yield shard_body_row(sbody)
 
-            # prepare next shard tail            
+            # prepare next shard tail
             shard_tail = shard_body_tail(num_rows, sbody)
 
-                    
-    
+
+
     def content_delta(self, other):
         """
         Return the differences between other and this canvas.
@@ -621,7 +621,7 @@
             # output rows
             row = []
             for i in range(num_rows):
-                # if whole shard is unchanged, don't keep 
+                # if whole shard is unchanged, don't keep
                 # calling shard_body_row
                 if len(row) != 1 or type(row[0]) != int:
                     row = shard_body_row(sbody)
@@ -629,8 +629,8 @@
 
             # prepare next shard tail
             shard_tail = shard_body_tail(num_rows, sbody)
-                
-    
+
+
     def trim(self, top, count=None):
         """Trim lines from the top and/or bottom of canvas.
 
@@ -642,7 +642,7 @@
             top, self.rows())
         if self.widget_info:
             raise self._finalized_error
-        
+
         if top:
             self.shards = shards_trim_top(self.shards, top)
 
@@ -653,10 +653,10 @@
 
         self.coords = self.translate_coords(0, -top)
 
-        
+
     def trim_end(self, end):
         """Trim lines from the bottom of the canvas.
-        
+
         end -- number of lines to remove from the end
         """
         assert end > 0, "invalid trim amount %d!"%end
@@ -664,14 +664,14 @@
             end, self.rows())
         if self.widget_info:
             raise self._finalized_error
-        
+
         self.shards = shards_trim_rows(self.shards, self.rows() - end)
 
-            
+
     def pad_trim_left_right(self, left, right):
         """
         Pad or trim this canvas on the left and right
-        
+
         values > 0 indicate screen columns to pad
         values < 0 indicate screen columns to trim
         """
@@ -721,24 +721,24 @@
                 [(0,0,cols,top,None,blank_canvas)])] + \
                 self.shards
             self.coords = self.translate_coords(0, top)
-        
+
         if bottom > 0:
             if orig_shards is self.shards:
                 self.shards = self.shards[:]
             self.shards.append((bottom,
                 [(0,0,cols,bottom,None,blank_canvas)]))
 
-        
+
     def overlay(self, other, left, top ):
         """Overlay other onto this canvas."""
         if self.widget_info:
             raise self._finalized_error
-        
+
         width = other.cols()
         height = other.rows()
         right = self.cols() - left - width
         bottom = self.rows() - top - height
-        
+
         assert right >= 0, "top canvas of overlay not the size expected!" + repr((other.cols(),left,right,width))
         assert bottom >= 0, "top canvas of overlay not the size expected!" + repr((other.rows(),top,bottom,height))
 
@@ -764,13 +764,13 @@
         if not self.rows():
             middle_shards = []
         elif left or right:
-            middle_shards = shards_join(left_shards + 
+            middle_shards = shards_join(left_shards +
                 [other.shards] + right_shards)
         else:
             middle_shards = other.shards
 
         self.shards = top_shards + middle_shards + bottom_shards
-        
+
         self.coords.update(other.translate_coords(left, top))
 
 
@@ -780,7 +780,7 @@
         attribute currently set to None, leaving other attributes
         intact."""
         self.fill_attr_apply({None:a})
-    
+
     def fill_attr_apply(self, mapping):
         """
         Apply an attribute-mapping dictionary to the canvas.
@@ -796,7 +796,7 @@
             for cv in original_cviews:
                 # cv[4] == attr_map
                 if cv[4] is None:
-                    new_cviews.append(cv[:4] + 
+                    new_cviews.append(cv[:4] +
                         (mapping,) + cv[5:])
                 else:
                     combined = dict(mapping)
@@ -859,7 +859,7 @@
 
 def shards_delta(shards, other_shards):
     """
-    Yield shards1 with cviews that are the same as shards2 
+    Yield shards1 with cviews that are the same as shards2
     having canv = None.
     """
     other_shards_iter = iter(other_shards)
@@ -910,11 +910,11 @@
 
 def shard_body(cviews, shard_tail, create_iter=True, iter_default=None):
     """
-    Return a list of (done_rows, content_iter, cview) tuples for 
+    Return a list of (done_rows, content_iter, cview) tuples for
     this shard and shard tail.
 
-    If a canvas in cviews is None (eg. when unchanged from 
-    shard_cviews_delta()) or if create_iter is False then no 
+    If a canvas in cviews is None (eg. when unchanged from
+    shard_cviews_delta()) or if create_iter is False then no
     iterator is created for content_iter.
 
     iter_default is the value used for content_iter when no iterator
@@ -938,7 +938,7 @@
                 raise CanvasError("cviews overflow gaps in"
                     " shard_tail!")
             if create_iter and canv:
-                new_iter = canv.content(trim_left, trim_top, 
+                new_iter = canv.content(trim_left, trim_top,
                     cols, rows, attr_map)
             else:
                 new_iter = iter_default
@@ -948,7 +948,7 @@
         (trim_left, trim_top, cols, rows, attr_map, canv) = \
             cview[:6]
         if create_iter and canv:
-            new_iter = canv.content(trim_left, trim_top, cols, rows, 
+            new_iter = canv.content(trim_left, trim_top, cols, rows,
                 attr_map)
         else:
             new_iter = iter_default
@@ -973,19 +973,19 @@
         top -= num_rows
     else:
         raise CanvasError("tried to trim shards out of existence")
-    
+
     sbody = shard_body(cviews, shard_tail, False)
     shard_tail = shard_body_tail(num_rows, sbody)
     # trim the top of this shard
     new_sbody = []
     for done_rows, content_iter, cv in sbody:
-        new_sbody.append((0, content_iter, 
+        new_sbody.append((0, content_iter,
             cview_trim_top(cv, done_rows+top)))
     sbody = new_sbody
-    
-    new_shards = [(num_rows-top, 
+
+    new_shards = [(num_rows-top,
         [cv for done_rows, content_iter, cv in sbody])]
-    
+
     # write out the rest of the shards
     new_shards.extend(shard_iter)
 
@@ -1005,7 +1005,7 @@
         new_cviews = []
         for cv in cviews:
             if cv[3] + done_rows > keep_rows:
-                new_cviews.append(cview_trim_rows(cv, 
+                new_cviews.append(cview_trim_rows(cv,
                     keep_rows - done_rows))
             else:
                 new_cviews.append(cv)
@@ -1214,13 +1214,13 @@
     t = []
     a = []
     c = []
-    
+
     class AttrWalk:
         pass
     aw = AttrWalk
     aw.k = 0 # counter for moving through elements of a
     aw.off = 0 # current offset into text of attr[ak]
-    
+
     def arange( start_offs, end_offs ):
         """Return an attribute list for the range of text specified."""
         if start_offs < aw.off:
@@ -1246,19 +1246,19 @@
             aw.off += run
         return o
 
-    
+
     for line_layout in ls:
         # trim the line to fit within maxcol
         line_layout = trim_line( line_layout, text, 0, maxcol )
-        
+
         line = []
         linea = []
         linec = []
-            
+
         def attrrange( start_offs, end_offs, destw ):
             """
             Add attributes based on attributes between
-            start_offs and end_offs. 
+            start_offs and end_offs.
             """
             if start_offs == end_offs:
                 [(at,run)] = arange(start_offs,end_offs)
@@ -1277,12 +1277,12 @@
                 tseg = text[o:o+run]
                 tseg, cs = apply_target_encoding( tseg )
                 segw = rle_len(cs)
-                
+
                 rle_append_modify( linea, ( at, segw ))
                 o += run
                 destw -= segw
-            
-            
+
+
         for seg in line_layout:
             #if seg is None: assert 0, ls
             s = LayoutSegment(seg)
diff -Nru urwid-1.2.1/urwid/container.py urwid-1.3.0/urwid/container.py
--- urwid-1.2.1/urwid/container.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/container.py	2014-10-17 20:09:04.000000000 +0200
@@ -130,7 +130,7 @@
     """
     The GridFlow widget is a flow widget that renders all the widgets it
     contains the same width and it arranges them from left to right and top to
-    bottom. 
+    bottom.
     """
     def sizing(self):
         return frozenset([FLOW])
@@ -284,7 +284,7 @@
         empty.
         """
         if not self.contents:
-            raise IndexError, "No focus_position, GridFlow is empty"
+            raise IndexError("No focus_position, GridFlow is empty")
         return self.contents.focus
     def _set_focus_position(self, position):
         """
@@ -296,7 +296,7 @@
             if position < 0 or position >= len(self.contents):
                 raise IndexError
         except (TypeError, IndexError):
-            raise IndexError, "No GridFlow child widget at position %s" % (position,)
+            raise IndexError("No GridFlow child widget at position %s" % (position,))
         self.contents.focus = position
     focus_position = property(_get_focus_position, _set_focus_position, doc="""
         index of child widget in focus. Raises :exc:`IndexError` if read when
@@ -342,14 +342,18 @@
                 if self.v_sep:
                     p.contents.append((divider, p.options()))
                 c = Columns([], self.h_sep)
+                column_focused = False
                 pad = Padding(c, self.align)
                 # extra attribute to reference contents position
                 pad.first_position = i
                 p.contents.append((pad, p.options()))
 
             c.contents.append((w, c.options(GIVEN, width_amount)))
-            if i == self.focus_position:
+            if ((i == self.focus_position) or
+                (not column_focused and w.selectable())):
                 c.focus_position = len(c.contents) - 1
+                column_focused = True
+            if i == self.focus_position:
                 p.focus_position = len(p.contents) - 1
             used_space = (sum(x[1][1] for x in c.contents) +
                 self.h_sep * len(c.contents))
@@ -607,7 +611,7 @@
         position -- index of child widget to be made focus
         """
         if position != 1:
-            raise IndexError, ("Overlay widget focus_position currently "
+            raise IndexError("Overlay widget focus_position currently "
                 "must always be set to 1, not %s" % (position,))
     focus_position = property(_get_focus_position, _set_focus_position,
         doc="index of child widget in focus, currently always 1")
@@ -871,10 +875,10 @@
         :type part: str
         """
         if part not in ('header', 'footer', 'body'):
-            raise IndexError, 'Invalid position for Frame: %s' % (part,)
+            raise IndexError('Invalid position for Frame: %s' % (part,))
         if (part == 'header' and self._header is None) or (
                 part == 'footer' and self._footer is None):
-            raise IndexError, 'This Frame has no %s' % (part,)
+            raise IndexError('This Frame has no %s' % (part,))
         self.focus_part = part
         self._invalidate()
 
@@ -1407,7 +1411,7 @@
         empty.
         """
         if not self.contents:
-            raise IndexError, "No focus_position, Pile is empty"
+            raise IndexError("No focus_position, Pile is empty")
         return self.contents.focus
     def _set_focus_position(self, position):
         """
@@ -1419,7 +1423,7 @@
             if position < 0 or position >= len(self.contents):
                 raise IndexError
         except (TypeError, IndexError):
-            raise IndexError, "No Pile child widget at position %s" % (position,)
+            raise IndexError("No Pile child widget at position %s" % (position,))
         self.contents.focus = position
     focus_position = property(_get_focus_position, _set_focus_position, doc="""
         index of child widget in focus. Raises :exc:`IndexError` if read when
@@ -1488,7 +1492,7 @@
                 l.append(0) # zero-weighted items treated as ('given', 0)
 
         if wtotal == 0:
-            raise PileError, "No weighted widgets found for Pile treated as a box widget"
+            raise PileError("No weighted widgets found for Pile treated as a box widget")
 
         if remaining < 0:
             remaining = 0
@@ -1957,7 +1961,7 @@
         empty.
         """
         if not self.widget_list:
-            raise IndexError, "No focus_position, Columns is empty"
+            raise IndexError("No focus_position, Columns is empty")
         return self.contents.focus
     def _set_focus_position(self, position):
         """
@@ -1969,7 +1973,7 @@
             if position < 0 or position >= len(self.contents):
                 raise IndexError
         except (TypeError, IndexError):
-            raise IndexError, "No Columns child widget at position %s" % (position,)
+            raise IndexError("No Columns child widget at position %s" % (position,))
         self.contents.focus = position
     focus_position = property(_get_focus_position, _set_focus_position, doc="""
         index of child widget in focus. Raises :exc:`IndexError` if read when
diff -Nru urwid-1.2.1/urwid/curses_display.py urwid-1.3.0/urwid/curses_display.py
--- urwid-1.2.1/urwid/curses_display.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/curses_display.py	2014-10-17 20:09:04.000000000 +0200
@@ -102,12 +102,10 @@
 
         self._mouse_tracking_enabled = enable
 
-    def start(self):
+    def _start(self):
         """
         Initialize the screen and input mode.
         """
-        assert self._started == False
-
         self.s = curses.initscr()
         self.has_color = curses.has_colors()
         if self.has_color:
@@ -126,44 +124,28 @@
         curses.meta(1)
         curses.halfdelay(10) # use set_input_timeouts to adjust
         self.s.keypad(0)
-        
+
         if not self._signal_keys_set:
             self._old_signal_keys = self.tty_signal_keys()
 
-        super(Screen, self).start()
+        super(Screen, self)._start()
 
-    
-    def stop(self):
+    def _stop(self):
         """
         Restore the screen.
         """
-        if self._started == False:
-            return
         curses.echo()
         self._curs_set(1)
         try:
             curses.endwin()
         except _curses.error:
             pass # don't block original error with curses error
-        
+
         if self._old_signal_keys:
             self.tty_signal_keys(*self._old_signal_keys)
 
-        super(Screen, self).stop()
+        super(Screen, self)._stop()
 
-    
-    def run_wrapper(self,fn):
-        """Call fn in fullscreen mode.  Return to normal on exit.
-        
-        This function should be called to wrap your main program loop.
-        Exception tracebacks will be displayed in normal mode.
-        """
-    
-        try:
-            self.start()
-            return fn()
-        finally:
-            self.stop()
 
     def _setup_colour_pairs(self):
         """
@@ -185,7 +167,7 @@
                 curses.init_pair(bg * 8 + 7 - fg, fg, bg)
 
     def _curs_set(self,x):
-        if self.cursor_state== "fixed" or x == self.cursor_state: 
+        if self.cursor_state== "fixed" or x == self.cursor_state:
             return
         try:
             curses.curs_set(x)
@@ -193,12 +175,12 @@
         except _curses.error:
             self.cursor_state = "fixed"
 
-    
+
     def _clear(self):
         self.s.clear()
         self.s.refresh()
-    
-    
+
+
     def _getch(self, wait_tenths):
         if wait_tenths==0:
             return self._getch_nodelay()
@@ -208,7 +190,7 @@
             curses.halfdelay(wait_tenths)
         self.s.nodelay(0)
         return self.s.getch()
-    
+
     def _getch_nodelay(self):
         self.s.nodelay(1)
         while 1:
@@ -218,17 +200,17 @@
                 break
             except _curses.error:
                 pass
-            
+
         return self.s.getch()
 
-    def set_input_timeouts(self, max_wait=None, complete_wait=0.1, 
+    def set_input_timeouts(self, max_wait=None, complete_wait=0.1,
         resize_wait=0.1):
         """
         Set the get_input timeout values.  All values have a granularity
         of 0.1s, ie. any value between 0.15 and 0.05 will be treated as
         0.1 and any value less than 0.05 will be treated as 0.  The
         maximum timeout value for this module is 25.5 seconds.
-    
+
         max_wait -- amount of time in seconds to wait for input when
             there is no input pending, wait forever if None
         complete_wait -- amount of time in seconds to wait when
@@ -295,14 +277,14 @@
         keys, raw = self._get_input( self.max_tenths )
 
         # Avoid pegging CPU at 100% when slowly resizing, and work
-        # around a bug with some braindead curses implementations that 
-        # return "no key" between "window resize" commands 
+        # around a bug with some braindead curses implementations that
+        # return "no key" between "window resize" commands
         if keys==['window resize'] and self.prev_input_resize:
             while True:
                 keys, raw2 = self._get_input(self.resize_tenths)
                 raw += raw2
                 if not keys:
-                    keys, raw2 = self._get_input( 
+                    keys, raw2 = self._get_input(
                         self.resize_tenths)
                     raw += raw2
                 if keys!=['window resize']:
@@ -310,33 +292,33 @@
             if keys[-1:]!=['window resize']:
                 keys.append('window resize')
 
-                
+
         if keys==['window resize']:
             self.prev_input_resize = 2
         elif self.prev_input_resize == 2 and not keys:
             self.prev_input_resize = 1
         else:
             self.prev_input_resize = 0
-        
+
         if raw_keys:
             return keys, raw
         return keys
-        
-        
+
+
     def _get_input(self, wait_tenths):
-        # this works around a strange curses bug with window resizing 
+        # this works around a strange curses bug with window resizing
         # not being reported correctly with repeated calls to this
         # function without a doupdate call in between
-        curses.doupdate() 
-        
+        curses.doupdate()
+
         key = self._getch(wait_tenths)
         resize = False
         raw = []
         keys = []
-        
+
         while key >= 0:
             raw.append(key)
-            if key==KEY_RESIZE: 
+            if key==KEY_RESIZE:
                 resize = True
             elif key==KEY_MOUSE:
                 keys += self._encode_mouse_event()
@@ -345,7 +327,7 @@
             key = self._getch_nodelay()
 
         processed = []
-        
+
         try:
             while keys:
                 run, keys = escape.process_keyqueue(keys, True)
@@ -354,7 +336,7 @@
             key = self._getch(self.complete_tenths)
             while key >= 0:
                 raw.append(key)
-                if key==KEY_RESIZE: 
+                if key==KEY_RESIZE:
                     resize = True
                 elif key==KEY_MOUSE:
                     keys += self._encode_mouse_event()
@@ -369,23 +351,23 @@
             processed.append('window resize')
 
         return processed, raw
-        
-        
+
+
     def _encode_mouse_event(self):
         # convert to escape sequence
         last = next = self.last_bstate
         (id,x,y,z,bstate) = curses.getmouse()
-        
+
         mod = 0
         if bstate & curses.BUTTON_SHIFT:    mod |= 4
         if bstate & curses.BUTTON_ALT:        mod |= 8
         if bstate & curses.BUTTON_CTRL:        mod |= 16
-        
+
         l = []
         def append_button( b ):
             b |= mod
             l.extend([ 27, ord('['), ord('M'), b+32, x+33, y+33 ])
-        
+
         if bstate & curses.BUTTON1_PRESSED and last & 1 == 0:
             append_button( 0 )
             next |= 1
@@ -410,7 +392,7 @@
         if bstate & curses.BUTTON4_RELEASED and last & 8:
             append_button( 64 + escape.MOUSE_RELEASE_FLAG )
             next &= ~ 8
-        
+
         if bstate & curses.BUTTON1_DOUBLE_CLICKED:
             append_button( 0 + escape.MOUSE_MULTIPLE_CLICK_FLAG )
         if bstate & curses.BUTTON2_DOUBLE_CLICKED:
@@ -431,7 +413,7 @@
 
         self.last_bstate = next
         return l
-            
+
 
     def _dbg_instr(self): # messy input string (intended for debugging)
         curses.echo()
@@ -440,17 +422,17 @@
         str = self.s.getstr()
         curses.noecho()
         return str
-        
+
     def _dbg_out(self,str): # messy output function (intended for debugging)
         self.s.clrtoeol()
         self.s.addstr(str)
         self.s.refresh()
         self._curs_set(1)
-        
+
     def _dbg_query(self,question): # messy query (intended for debugging)
         self._dbg_out(question)
         return self._dbg_instr()
-    
+
     def _dbg_refresh(self):
         self.s.refresh()
 
@@ -460,7 +442,7 @@
         """Return the terminal dimensions (num columns, num rows)."""
         rows,cols = self.s.getmaxyx()
         return cols,rows
-        
+
 
     def _setattr(self, a):
         if a is None:
@@ -502,19 +484,19 @@
     def draw_screen(self, (cols, rows), r ):
         """Paint screen with rendered canvas."""
         assert self._started
-        
+
         assert r.rows() == rows, "canvas size and passed size don't match"
-    
+
         y = -1
         for row in r.content():
             y += 1
             try:
                 self.s.move( y, 0 )
             except _curses.error:
-                # terminal shrunk? 
+                # terminal shrunk?
                 # move failed so stop rendering.
                 return
-            
+
             first = True
             lasta = None
             nr = 0
@@ -558,7 +540,7 @@
         else:
             self._curs_set(0)
             self.s.move(0,0)
-        
+
         self.s.refresh()
         self.keep_cache_alive_link = r
 
@@ -585,7 +567,7 @@
                 (c+" on light gray",c,'light gray', 'standout'),
                 ])
         self.ui.run_wrapper(self.run)
-        
+
     def run(self):
         class FakeRender: pass
         r = FakeRender()
@@ -593,12 +575,12 @@
         attr = [[],[]]
         r.coords = {}
         r.cursor = None
-        
+
         for c in self.l:
             t = ""
             a = []
             for p in c+" on black",c+" on dark blue",c+" on light gray":
-                
+
                 a.append((p,27))
                 t=t+ (p+27*" ")[:27]
             text.append( t )
@@ -624,13 +606,13 @@
                 t += "'"+k + "' "
                 a += [(None,1), ('yellow on dark blue',len(k)),
                     (None,2)]
-            
+
             text.append(t + ": "+ repr(raw))
             attr.append(a)
             text = text[-rows:]
             attr = attr[-rows:]
-                
-                
+
+
 
 
 if '__main__'==__name__:
diff -Nru urwid-1.2.1/urwid/display_common.py urwid-1.3.0/urwid/display_common.py
--- urwid-1.2.1/urwid/display_common.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/display_common.py	2014-10-17 20:09:04.000000000 +0200
@@ -20,9 +20,13 @@
 
 import os
 import sys
-import termios
 
-from urwid.util import int_scale
+try:
+    import termios
+except ImportError:
+    pass # windows
+
+from urwid.util import StoppingContext, int_scale
 from urwid import signals
 from urwid.compat import B, bytes3
 
@@ -63,11 +67,11 @@
     (0x5c, 0x5c, 0xff), (255, 0, 255), (0, 255, 255), (255, 255, 255)]
 
 _COLOR_VALUES_256 = (_BASIC_COLOR_VALUES +
-    [(r, g, b) for r in _CUBE_STEPS_256 for g in _CUBE_STEPS_256 
+    [(r, g, b) for r in _CUBE_STEPS_256 for g in _CUBE_STEPS_256
     for b in _CUBE_STEPS_256] +
     [(gr, gr, gr) for gr in _GRAY_STEPS_256])
 _COLOR_VALUES_88 = (_BASIC_COLOR_VALUES +
-    [(r, g, b) for r in _CUBE_STEPS_88 for g in _CUBE_STEPS_88 
+    [(r, g, b) for r in _CUBE_STEPS_88 for g in _CUBE_STEPS_88
     for b in _CUBE_STEPS_88] +
     [(gr, gr, gr) for gr in _GRAY_STEPS_88])
 
@@ -138,10 +142,10 @@
     """
     Generate a lookup table for finding the closest item in values.
     Lookup returns (index into values)+1
-    
+
     values -- list of values in ascending order, all < size
     size -- size of lookup table and maximum value
-    
+
     >>> _value_lookup_table([0, 7, 9], 10)
     [0, 0, 0, 0, 1, 1, 1, 1, 2, 2]
     """
@@ -177,11 +181,11 @@
     for n in range(101)]
 
 
-# The functions _gray_num_256() and _gray_num_88() do not include the gray 
-# values from the color cube so that the gray steps are an even width.  
-# The color cube grays are available by using the rgb functions.  Pure 
-# white and black are taken from the color cube, since the gray range does 
-# not include them, and the basic colors are more likely to have been 
+# The functions _gray_num_256() and _gray_num_88() do not include the gray
+# values from the color cube so that the gray steps are an even width.
+# The color cube grays are available by using the rgb functions.  Pure
+# white and black are taken from the color cube, since the gray range does
+# not include them, and the basic colors are more likely to have been
 # customized by an end-user.
 
 
@@ -258,7 +262,7 @@
     0..15 -> 'h0'..'h15' basic colors (as high-colors)
     16..79 -> '#000'..'#fff' color cube colors
     80..87 -> 'g18'..'g90' grays
-    
+
     >>> _color_desc_88(15)
     'h15'
     >>> _color_desc_88(16)
@@ -291,7 +295,7 @@
     '#000'..'#fff' -> 16..231 color cube colors
     'g0'..'g100' -> 16, 232..255, 231 grays and color cube black/white
     'g#00'..'g#ff' -> 16, 232...255, 231 gray and color cube black/white
-    
+
     Returns None if desc is invalid.
 
     >>> _parse_color_256('h142')
@@ -359,9 +363,9 @@
     '#000'..'#fff' -> 16..79 color cube colors
     'g0'..'g100' -> 16, 80..87, 79 grays and color cube black/white
     'g#00'..'g#ff' -> 16, 80...87, 79 gray and color cube black/white
-    
+
     Returns None if desc is invalid.
-    
+
     >>> _parse_color_88('h142')
     >>> _parse_color_88('h42')
     42
@@ -434,7 +438,7 @@
               'default' (use the terminal's default foreground),
               'black', 'dark red', 'dark green', 'brown', 'dark blue',
               'dark magenta', 'dark cyan', 'light gray', 'dark gray',
-              'light red', 'light green', 'yellow', 'light blue', 
+              'light red', 'light green', 'yellow', 'light blue',
               'light magenta', 'light cyan', 'white'
 
               High-color example values:
@@ -466,7 +470,7 @@
 
         colors -- the maximum colors available for the specification
 
-                   Valid values include: 1, 16, 88 and 256.  High-color 
+                   Valid values include: 1, 16, 88 and 256.  High-color
                    values are only usable with 88 or 256 colors.  With
                    1 color only the foreground settings may be used.
 
@@ -494,7 +498,7 @@
     foreground_number = property(lambda s: s._value & _FG_COLOR_MASK)
     background_basic = property(lambda s: s._value & _BG_BASIC_COLOR != 0)
     background_high = property(lambda s: s._value & _BG_HIGH_COLOR != 0)
-    background_number = property(lambda s: (s._value & _BG_COLOR_MASK) 
+    background_number = property(lambda s: (s._value & _BG_COLOR_MASK)
         >> _BG_SHIFT)
     bold = property(lambda s: s._value & _BOLD != 0)
     underline = property(lambda s: s._value & _UNDERLINE != 0)
@@ -552,7 +556,7 @@
                 # parse and store "settings"/attributes in flags
                 if flags & _ATTRIBUTES[part]:
                     raise AttrSpecError(("Setting %s specified more than" +
-                        "once in foreground (%s)") % (repr(part), 
+                        "once in foreground (%s)") % (repr(part),
                         repr(foreground)))
                 flags |= _ATTRIBUTES[part]
                 continue
@@ -591,7 +595,7 @@
         if self._value & _HIGH_88_COLOR:
             return _color_desc_88(self.background_number)
         return _color_desc_256(self.background_number)
-        
+
     def _set_background(self, background):
         flags = 0
         if background in ('', 'default'):
@@ -617,7 +621,7 @@
         Return (fg_red, fg_green, fg_blue, bg_red, bg_green, bg_blue) color
         components.  Each component is in the range 0-255.  Values are taken
         from the XTerm defaults and may not exactly match the user's terminal.
-        
+
         If the foreground or background is 'default' then all their compenents
         will be returned as None.
 
@@ -649,8 +653,8 @@
         super(RealTerminal,self).__init__()
         self._signal_keys_set = False
         self._old_signal_keys = None
-        
-    def tty_signal_keys(self, intr=None, quit=None, start=None, 
+
+    def tty_signal_keys(self, intr=None, quit=None, start=None,
         stop=None, susp=None, fileno=None):
         """
         Read and/or set the tty's signal character settings.
@@ -675,25 +679,25 @@
         skeys = (sattr[termios.VINTR], sattr[termios.VQUIT],
             sattr[termios.VSTART], sattr[termios.VSTOP],
             sattr[termios.VSUSP])
-        
+
         if intr == 'undefined': intr = 0
         if quit == 'undefined': quit = 0
         if start == 'undefined': start = 0
         if stop == 'undefined': stop = 0
         if susp == 'undefined': susp = 0
-        
+
         if intr is not None: tattr[6][termios.VINTR] = intr
         if quit is not None: tattr[6][termios.VQUIT] = quit
         if start is not None: tattr[6][termios.VSTART] = start
         if stop is not None: tattr[6][termios.VSTOP] = stop
         if susp is not None: tattr[6][termios.VSUSP] = susp
-        
+
         if intr is not None or quit is not None or \
             start is not None or stop is not None or \
             susp is not None:
             termios.tcsetattr(fileno, termios.TCSADRAIN, tattr)
             self._signal_keys_set = True
-        
+
         return skeys
 
 
@@ -714,12 +718,44 @@
 
     started = property(lambda self: self._started)
 
-    def start(self):
+    def start(self, *args, **kwargs):
+        """Set up the screen.  If the screen has already been started, does
+        nothing.
+
+        May be used as a context manager, in which case :meth:`stop` will
+        automatically be called at the end of the block:
+
+            with screen.start():
+                ...
+
+        You shouldn't override this method in a subclass; instead, override
+        :meth:`_start`.
+        """
+        if not self._started:
+            self._start(*args, **kwargs)
         self._started = True
+        return StoppingContext(self)
+
+    def _start(self):
+        pass
 
     def stop(self):
+        if self._started:
+            self._stop()
         self._started = False
 
+    def _stop(self):
+        pass
+
+    def run_wrapper(self, fn, *args, **kwargs):
+        """Start the screen, call a function, then stop the screen.  Extra
+        arguments are passed to `start`.
+
+        Deprecated in favor of calling `start` as a context manager.
+        """
+        with self.start(*args, **kwargs):
+            return fn()
+
 
     def register_palette(self, palette):
         """Register a set of palette entries.
@@ -746,7 +782,7 @@
                 raise ScreenError("Invalid register_palette entry: %s" %
                     repr(item))
             name, like_name = item
-            if not self._palette.has_key(like_name):
+            if like_name not in self._palette:
                 raise ScreenError("palette entry '%s' doesn't exist"%like_name)
             self._palette[name] = self._palette[like_name]
 
@@ -829,6 +865,8 @@
         def large_h(desc):
             if not desc.startswith('h'):
                 return False
+            if ',' in desc:
+            	desc = desc.split(',',1)[0]
             num = int(desc[1:], 10)
             return num > 15
         if large_h(foreground_high) or large_h(background_high):
diff -Nru urwid-1.2.1/urwid/escape.py urwid-1.3.0/urwid/escape.py
--- urwid-1.2.1/urwid/escape.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/escape.py	2014-10-17 20:09:04.000000000 +0200
@@ -63,7 +63,7 @@
 def escape_modifier( digit ):
     mode = ord(digit) - ord("1")
     return "shift "*(mode&1) + "meta "*((mode&2)//2) + "ctrl "*((mode&4)//4)
-    
+
 
 input_sequences = [
     ('[A','up'),('[B','down'),('[C','right'),('[D','left'),
@@ -74,7 +74,7 @@
     ('[7~','home'),('[8~','end'),
 
     ('[[A','f1'),('[[B','f2'),('[[C','f3'),('[[D','f4'),('[[E','f5'),
-    
+
     ('[11~','f1'),('[12~','f2'),('[13~','f3'),('[14~','f4'),
     ('[15~','f5'),('[17~','f6'),('[18~','f7'),('[19~','f8'),
     ('[20~','f9'),('[21~','f10'),('[23~','f11'),('[24~','f12'),
@@ -102,7 +102,7 @@
 ] + [
     # modified cursor keys + home, end, 5 -- [#X and [1;#X forms
     (prefix+digit+letter, escape_modifier(digit) + key)
-    for prefix in "[","[1;"
+    for prefix in ("[", "[1;")
     for digit in "12345678"
     for letter,key in zip("ABCDEFGH",
         ('up','down','right','left','5','end','5','home'))
@@ -111,7 +111,7 @@
     ("O"+digit+letter, escape_modifier(digit) + key)
     for digit in "12345678"
     for letter,key in zip("PQRS",('f1','f2','f3','f4'))
-] + [ 
+] + [
     # modified F1-F13 keys -- [XX;#~ form
     ("["+str(num)+";"+digit+"~", escape_modifier(digit) + key)
     for digit in "12345678"
@@ -133,29 +133,29 @@
         for s, result in sequences:
             assert type(result) != dict
             self.add(self.data, s, result)
-    
+
     def add(self, root, s, result):
         assert type(root) == dict, "trie conflict detected"
         assert len(s) > 0, "trie conflict detected"
-        
-        if root.has_key(ord(s[0])):
+
+        if ord(s[0]) in root:
             return self.add(root[ord(s[0])], s[1:], result)
         if len(s)>1:
             d = {}
             root[ord(s[0])] = d
             return self.add(d, s[1:], result)
         root[ord(s)] = result
-    
+
     def get(self, keys, more_available):
         result = self.get_recurse(self.data, keys, more_available)
         if not result:
             result = self.read_cursor_position(keys, more_available)
         return result
-    
+
     def get_recurse(self, root, keys, more_available):
         if type(root) != dict:
             if root == "mouse":
-                return self.read_mouse_info(keys, 
+                return self.read_mouse_info(keys,
                     more_available)
             return (root, keys)
         if not keys:
@@ -163,19 +163,19 @@
             if more_available:
                 raise MoreInputRequired()
             return None
-        if not root.has_key(keys[0]):
+        if keys[0] not in root:
             return None
         return self.get_recurse(root[keys[0]], keys[1:], more_available)
-    
+
     def read_mouse_info(self, keys, more_available):
         if len(keys) < 3:
             if more_available:
                 raise MoreInputRequired()
             return None
-        
+
         b = keys[0] - 32
         x, y = (keys[1] - 33)%256, (keys[2] - 33)%256  # supports 0-255
-        
+
         prefix = ""
         if b & 4:    prefix = prefix + "shift "
         if b & 8:    prefix = prefix + "meta "
@@ -186,7 +186,7 @@
         # 0->1, 1->2, 2->3, 64->4, 65->5
         button = ((b&64)/64*3) + (b & 3) + 1
 
-        if b & 3 == 3:    
+        if b & 3 == 3:
             action = "release"
             button = 0
         elif b & MOUSE_RELEASE_FLAG:
@@ -199,7 +199,7 @@
             action = "press"
 
         return ( (prefix + "mouse " + action, button, x, y), keys[3:] )
-    
+
     def read_cursor_position(self, keys, more_available):
         """
         Interpret cursor position information being sent by the
@@ -252,8 +252,8 @@
 
 
 # This is added to button value to signal mouse release by curses_display
-# and raw_display when we know which button was released.  NON-STANDARD 
-MOUSE_RELEASE_FLAG = 2048  
+# and raw_display when we know which button was released.  NON-STANDARD
+MOUSE_RELEASE_FLAG = 2048
 
 # This 2-bit mask is used to check if the mouse release from curses or gpm
 # is a double or triple release. 00 means single click, 01 double,
@@ -308,26 +308,26 @@
 def process_keyqueue(codes, more_available):
     """
     codes -- list of key codes
-    more_available -- if True then raise MoreInputRequired when in the 
-        middle of a character sequence (escape/utf8/wide) and caller 
+    more_available -- if True then raise MoreInputRequired when in the
+        middle of a character sequence (escape/utf8/wide) and caller
         will attempt to send more key codes on the next call.
-    
+
     returns (list of input, list of remaining key codes).
     """
     code = codes[0]
     if code >= 32 and code <= 126:
         key = chr(code)
         return [key], codes[1:]
-    if _keyconv.has_key(code):
+    if code in _keyconv:
         return [_keyconv[code]], codes[1:]
     if code >0 and code <27:
         return ["ctrl %s" % chr(ord('a')+code-1)], codes[1:]
     if code >27 and code <32:
         return ["ctrl %s" % chr(ord('A')+code-1)], codes[1:]
-    
+
     em = str_util.get_byte_encoding()
-    
-    if (em == 'wide' and code < 256 and  
+
+    if (em == 'wide' and code < 256 and
         within_double_byte(chr(code),0,0)):
         if not codes[1:]:
             if more_available:
@@ -363,7 +363,7 @@
             return [s.decode("utf-8")], codes[need_more+1:]
         except UnicodeDecodeError:
             return ["<%d>"%code], codes[1:]
-        
+
     if code >127 and code <256:
         key = chr(code)
         return [key], codes[1:]
@@ -371,19 +371,19 @@
         return ["<%d>"%code], codes[1:]
 
     result = input_trie.get(codes[1:], more_available)
-    
+
     if result is not None:
         result, remaining_codes = result
         return [result], remaining_codes
-    
+
     if codes[1:]:
         # Meta keys -- ESC+Key form
-        run, remaining_codes = process_keyqueue(codes[1:], 
+        run, remaining_codes = process_keyqueue(codes[1:],
             more_available)
         if run[0] == "esc" or run[0].find("meta ") >= 0:
             return ['esc']+run, remaining_codes
         return ['meta '+run[0]]+run[1:], remaining_codes
-        
+
     return ['esc'], codes[1:]
 
 
diff -Nru urwid-1.2.1/urwid/font.py urwid-1.3.0/urwid/font.py
--- urwid-1.2.1/urwid/font.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/font.py	2014-10-17 20:09:04.000000000 +0200
@@ -65,11 +65,11 @@
                 j += 1
             assert y + fill == end_col - start_col, \
                 repr((y, fill, end_col))
-            
+
             segment = l[jl[k]:j]
             if not SAFE_ASCII_DEC_SPECIAL_RE.match(segment):
                 utf8_required = True
-            
+
             out.append(segment + " " * fill)
             jl[k] = j
 
@@ -98,7 +98,7 @@
         self.utf8_required = False
         for gdata in self.data:
             self.add_glyphs(gdata)
-        
+
 
     def add_glyphs(self, gdata):
         d, utf8_required = separate_glyphs(gdata, self.height)
@@ -111,10 +111,10 @@
         return "".join(l)
 
     def char_width(self, c):
-        if self.char.has_key(c):
+        if c in self.char:
             return self.char[c][0]
         return 0
-    
+
     def char_data(self, c):
         return self.char[c][1]
 
@@ -128,13 +128,13 @@
             t, cs = apply_target_encoding(d)
             tl.append(t)
             csl.append(cs)
-        canv = TextCanvas(tl, None, csl, maxcol=width, 
+        canv = TextCanvas(tl, None, csl, maxcol=width,
             check_width=False)
         self.canvas[c] = canv
         return canv
-    
 
-        
+
+
 #safe_palette = u"┘┐┌└┼─├┤┴┬│"
 #more_palette = u"═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬○"
 #block_palette = u"▄#█#▀#▌#▐#▖#▗#▘#▙#▚#▛#▜#▝#▞#▟"
@@ -150,7 +150,7 @@
 """, ur"""
 "###$$$%%%'*++,--.///:;==???[[\\\]]^__`
 " ┼┼┌┼┐O /'         /.. _┌─┐┌ \   ┐^  `
-  ┼┼└┼┐ /  * ┼  ─  / ., _ ┌┘│  \  │     
+  ┼┼└┼┐ /  * ┼  ─  / ., _ ┌┘│  \  │
     └┼┘/ O    ,  ./       . └   \ ┘ ──
 """]
 add_font("Thin 3x3",Thin3x3Font)
@@ -169,57 +169,57 @@
     height = 4
     data = [u"""
 00000111112222233333444445555566666777778888899999  !!
-▄▀▀▄  ▄█  ▄▀▀▄ ▄▀▀▄ ▄  █ █▀▀▀ ▄▀▀  ▀▀▀█ ▄▀▀▄ ▄▀▀▄   █ 
-█  █   █    ▄▀   ▄▀ █▄▄█ █▄▄  █▄▄    ▐▌ ▀▄▄▀ ▀▄▄█   █ 
-█  █   █  ▄▀   ▄  █    █    █ █  █   █  █  █    █   ▀ 
- ▀▀   ▀▀▀ ▀▀▀▀  ▀▀     ▀ ▀▀▀   ▀▀    ▀   ▀▀   ▀▀    ▀ 
+▄▀▀▄  ▄█  ▄▀▀▄ ▄▀▀▄ ▄  █ █▀▀▀ ▄▀▀  ▀▀▀█ ▄▀▀▄ ▄▀▀▄   █
+█  █   █    ▄▀   ▄▀ █▄▄█ █▄▄  █▄▄    ▐▌ ▀▄▄▀ ▀▄▄█   █
+█  █   █  ▄▀   ▄  █    █    █ █  █   █  █  █    █   ▀
+ ▀▀   ▀▀▀ ▀▀▀▀  ▀▀     ▀ ▀▀▀   ▀▀    ▀   ▀▀   ▀▀    ▀
 """, u'''
 """######$$$$$$%%%%%&&&&&((()))******++++++,,,-----..////:::;;
-█▐▌ █ █  ▄▀█▀▄ ▐▌▐▌ ▄▀▄   █ █   ▄ ▄    ▄              ▐▌      
-   ▀█▀█▀ ▀▄█▄    █  ▀▄▀  ▐▌ ▐▌ ▄▄█▄▄ ▄▄█▄▄    ▄▄▄▄    █  ▀  ▀ 
-   ▀█▀█▀ ▄ █ █  ▐▌▄ █ ▀▄▌▐▌ ▐▌  ▄▀▄    █             ▐▌  ▀ ▄▀ 
-    ▀ ▀   ▀▀▀   ▀ ▀  ▀▀   ▀ ▀              ▄▀      ▀ ▀        
+█▐▌ █ █  ▄▀█▀▄ ▐▌▐▌ ▄▀▄   █ █   ▄ ▄    ▄              ▐▌
+   ▀█▀█▀ ▀▄█▄    █  ▀▄▀  ▐▌ ▐▌ ▄▄█▄▄ ▄▄█▄▄    ▄▄▄▄    █  ▀  ▀
+   ▀█▀█▀ ▄ █ █  ▐▌▄ █ ▀▄▌▐▌ ▐▌  ▄▀▄    █             ▐▌  ▀ ▄▀
+    ▀ ▀   ▀▀▀   ▀ ▀  ▀▀   ▀ ▀              ▄▀      ▀ ▀
 ''', ur"""
 <<<<<=====>>>>>?????@@@@@@[[[[\\\\]]]]^^^^____```{{{{||}}}}~~~~''´´´
-  ▄▀      ▀▄   ▄▀▀▄ ▄▀▀▀▄ █▀▀ ▐▌  ▀▀█ ▄▀▄     ▀▄  ▄▀ █ ▀▄   ▄  █ ▄▀ 
-▄▀   ▀▀▀▀   ▀▄   ▄▀ █ █▀█ █    █    █            ▄▀  █  ▀▄ ▐▐▌▌     
- ▀▄  ▀▀▀▀  ▄▀    ▀  █ ▀▀▀ █    ▐▌   █             █  █  █    ▀      
-   ▀      ▀      ▀   ▀▀▀  ▀▀▀   ▀ ▀▀▀     ▀▀▀▀     ▀ ▀ ▀            
+  ▄▀      ▀▄   ▄▀▀▄ ▄▀▀▀▄ █▀▀ ▐▌  ▀▀█ ▄▀▄     ▀▄  ▄▀ █ ▀▄   ▄  █ ▄▀
+▄▀   ▀▀▀▀   ▀▄   ▄▀ █ █▀█ █    █    █            ▄▀  █  ▀▄ ▐▐▌▌
+ ▀▄  ▀▀▀▀  ▄▀    ▀  █ ▀▀▀ █    ▐▌   █             █  █  █    ▀
+   ▀      ▀      ▀   ▀▀▀  ▀▀▀   ▀ ▀▀▀     ▀▀▀▀     ▀ ▀ ▀
 """, u'''
 AAAAABBBBBCCCCCDDDDDEEEEEFFFFFGGGGGHHHHHIIJJJJJKKKKK
-▄▀▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ █▀▀▀ █▀▀▀ ▄▀▀▄ █  █ █    █ █  █  
-█▄▄█ █▄▄▀ █    █  █ █▄▄  █▄▄  █    █▄▄█ █    █ █▄▀    
-█  █ █  █ █  ▄ █  █ █    █    █ ▀█ █  █ █ ▄  █ █ ▀▄  
-▀  ▀ ▀▀▀   ▀▀  ▀▀▀  ▀▀▀▀ ▀     ▀▀  ▀  ▀ ▀  ▀▀  ▀  ▀  
+▄▀▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ █▀▀▀ █▀▀▀ ▄▀▀▄ █  █ █    █ █  █
+█▄▄█ █▄▄▀ █    █  █ █▄▄  █▄▄  █    █▄▄█ █    █ █▄▀
+█  █ █  █ █  ▄ █  █ █    █    █ ▀█ █  █ █ ▄  █ █ ▀▄
+▀  ▀ ▀▀▀   ▀▀  ▀▀▀  ▀▀▀▀ ▀     ▀▀  ▀  ▀ ▀  ▀▀  ▀  ▀
 ''', u'''
 LLLLLMMMMMMNNNNNOOOOOPPPPPQQQQQRRRRRSSSSSTTTTT
 █    █▄ ▄█ ██ █ ▄▀▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ ▄▀▀▄ ▀▀█▀▀
-█    █ ▀ █ █▐▌█ █  █ █▄▄▀ █  █ █▄▄▀ ▀▄▄    █  
+█    █ ▀ █ █▐▌█ █  █ █▄▄▀ █  █ █▄▄▀ ▀▄▄    █
 █    █   █ █ ██ █  █ █    █ ▌█ █  █ ▄  █   █
 ▀▀▀▀ ▀   ▀ ▀  ▀  ▀▀  ▀     ▀▀▌ ▀  ▀  ▀▀    ▀
 ''', u'''
 UUUUUVVVVVVWWWWWWXXXXXXYYYYYYZZZZZ
-█  █ █   █ █   █ █   █ █   █ ▀▀▀█      
-█  █ ▐▌ ▐▌ █ ▄ █  ▀▄▀   ▀▄▀   ▄▀  
-█  █  █ █  ▐▌█▐▌ ▄▀ ▀▄   █   █    
- ▀▀    ▀    ▀ ▀  ▀   ▀   ▀   ▀▀▀▀     
+█  █ █   █ █   █ █   █ █   █ ▀▀▀█
+█  █ ▐▌ ▐▌ █ ▄ █  ▀▄▀   ▀▄▀   ▄▀
+█  █  █ █  ▐▌█▐▌ ▄▀ ▀▄   █   █
+ ▀▀    ▀    ▀ ▀  ▀   ▀   ▀   ▀▀▀▀
 ''', u'''
 aaaaabbbbbcccccdddddeeeeeffffggggghhhhhiijjjjkkkkk
      █            █       ▄▀▀     █    ▄   ▄ █
- ▀▀▄ █▀▀▄ ▄▀▀▄ ▄▀▀█ ▄▀▀▄ ▀█▀ ▄▀▀▄ █▀▀▄ ▄   ▄ █ ▄▀    
-▄▀▀█ █  █ █  ▄ █  █ █▀▀   █  ▀▄▄█ █  █ █   █ █▀▄   
- ▀▀▀ ▀▀▀   ▀▀   ▀▀▀  ▀▀   ▀   ▄▄▀ ▀  ▀ ▀ ▄▄▀ ▀  ▀  
+ ▀▀▄ █▀▀▄ ▄▀▀▄ ▄▀▀█ ▄▀▀▄ ▀█▀ ▄▀▀▄ █▀▀▄ ▄   ▄ █ ▄▀
+▄▀▀█ █  █ █  ▄ █  █ █▀▀   █  ▀▄▄█ █  █ █   █ █▀▄
+ ▀▀▀ ▀▀▀   ▀▀   ▀▀▀  ▀▀   ▀   ▄▄▀ ▀  ▀ ▀ ▄▄▀ ▀  ▀
 ''', u'''
 llmmmmmmnnnnnooooopppppqqqqqrrrrssssstttt
-█                                     █  
-█ █▀▄▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ ▄▀▀█ █▀▀ ▄▀▀▀ ▀█▀  
+█                                     █
+█ █▀▄▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ ▄▀▀█ █▀▀ ▄▀▀▀ ▀█▀
 █ █ █ █ █  █ █  █ █  █ █  █ █    ▀▀▄  █
 ▀ ▀   ▀ ▀  ▀  ▀▀  █▀▀   ▀▀█ ▀   ▀▀▀    ▀
 ''', u'''
 uuuuuvvvvvwwwwwwxxxxxxyyyyyzzzzz
-                           
+
 █  █ █  █ █ ▄ █ ▀▄ ▄▀ █  █ ▀▀█▀
-█  █ ▐▌▐▌ ▐▌█▐▌  ▄▀▄  ▀▄▄█ ▄▀   
+█  █ ▐▌▐▌ ▐▌█▐▌  ▄▀▄  ▀▄▄█ ▄▀
  ▀▀   ▀▀   ▀ ▀  ▀   ▀  ▄▄▀ ▀▀▀▀
 ''']
 add_font("Half Block 5x4",HalfBlock5x4Font)
@@ -253,34 +253,34 @@
     data = [u"""
 000000111111222222333333444444555555666666777777888888999999''
 ┌───┐   ┐   ┌───┐ ┌───┐    ┐  ┌───  ┌───  ┌───┐ ┌───┐ ┌───┐ │
-│   │   │       │     │ ┌  │  │     │         │ │   │ │   │  
-│ / │   │   ┌───┘    ─┤ └──┼─ └───┐ ├───┐     ┼ ├───┤ └───┤ 
-│   │   │   │         │    │      │ │   │     │ │   │     │ 
-└───┘   ┴   └───  └───┘    ┴   ───┘ └───┘     ┴ └───┘  ───┘ 
+│   │   │       │     │ ┌  │  │     │         │ │   │ │   │
+│ / │   │   ┌───┘    ─┤ └──┼─ └───┐ ├───┐     ┼ ├───┤ └───┤
+│   │   │   │         │    │      │ │   │     │ │   │     │
+└───┘   ┴   └───  └───┘    ┴   ───┘ └───┘     ┴ └───┘  ───┘
 
 """, ur'''
 !!   """######$$$$$$%%%%%%&&&&&&((()))******++++++
-│    ││  ┌ ┌  ┌─┼─┐ ┌┐  /  ┌─┐   / \      
+│    ││  ┌ ┌  ┌─┼─┐ ┌┐  /  ┌─┐   / \
 │       ─┼─┼─ │ │   └┘ /   │ │  │   │  \ /    │
-│        │ │  └─┼─┐   /   ┌─\┘  │   │ ──X── ──┼── 
+│        │ │  └─┼─┐   /   ┌─\┘  │   │ ──X── ──┼──
 │       ─┼─┼─   │ │  / ┌┐ │  \, │   │  / \    │
-.        ┘ ┘  └─┼─┘ /  └┘ └───\  \ /  
+.        ┘ ┘  └─┼─┘ /  └┘ └───\  \ /
 
 ''', ur"""
 ,,-----..//////::;;<<<<=====>>>>??????@@@@@@
              /                  ┌───┐ ┌───┐
             /  . .   / ──── \       │ │┌──┤
-  ────     /        /        \    ┌─┘ ││  │ 
+  ────     /        /        \    ┌─┘ ││  │
           /    . ,  \  ────  /    │   │└──┘
 ,      . /           \      /     .   └───┘
 
 """, ur"""
 [[\\\\\\]]^^^____``{{||}}~~~~~~
-┌ \     ┐ /\     \ ┌ │ ┐ 
+┌ \     ┐ /\     \ ┌ │ ┐
 │  \    │          │ │ │ ┌─┐
 │   \   │          ┤ │ ├   └─┘
-│    \  │          │ │ │ 
-└     \ ┘    ────  └ │ ┘ 
+│    \  │          │ │ │
+└     \ ┘    ────  └ │ ┘
 
 """, u"""
 AAAAAABBBBBBCCCCCCDDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIIJJJJJJ
@@ -300,15 +300,15 @@
                                        └
 """, u"""
 TTTTTTUUUUUUVVVVVVWWWWWWXXXXXXYYYYYYZZZZZZ
-┌─┬─┐ ┬   ┬ ┬   ┬ ┬   ┬ ┬   ┬ ┬   ┬ ┌───┐ 
-  │   │   │ │   │ │   │ └┐ ┌┘ │   │   ┌─┘ 
-  │   │   │ │   │ │ │ │  ├─┤  └─┬─┘  ┌┘  
-  │   │   │ └┐ ┌┘ │ │ │ ┌┘ └┐   │   ┌┘    
-  ┴   └───┘  └─┘  └─┴─┘ ┴   ┴   ┴   └───┘ 
-                                        
+┌─┬─┐ ┬   ┬ ┬   ┬ ┬   ┬ ┬   ┬ ┬   ┬ ┌───┐
+  │   │   │ │   │ │   │ └┐ ┌┘ │   │   ┌─┘
+  │   │   │ │   │ │ │ │  ├─┤  └─┬─┘  ┌┘
+  │   │   │ └┐ ┌┘ │ │ │ ┌┘ └┐   │   ┌┘
+  ┴   └───┘  └─┘  └─┴─┘ ┴   ┴   ┴   └───┘
+
 """, u"""
 aaaaaabbbbbbccccccddddddeeeeeefffgggggghhhhhhiijjj
-                              ┌─┐      
+                              ┌─┐
       │               │       │        │     .  .
 ┌───┐ ├───┐ ┌───┐ ┌───┤ ┌───┐ ┼  ┌───┐ ├───┐ ┐  ┐
 ┌───┤ │   │ │     │   │ ├───┘ │  │   │ │   │ │  │
@@ -316,16 +316,16 @@
                                  └───┘         ─┘
 """, u"""
 kkkkkkllmmmmmmnnnnnnooooooppppppqqqqqqrrrrrssssss
-                                
-│     │                                   
+
+│     │
 │ ┌─  │ ┬─┬─┐ ┬───┐ ┌───┐ ┌───┐ ┌───┐ ┬──┐ ┌───┐
 ├─┴┐  │ │ │ │ │   │ │   │ │   │ │   │ │    └───┐
 ┴  └─ └ ┴   ┴ ┴   ┴ └───┘ ├───┘ └───┤ ┴    └───┘
-                          │         │     
+                          │         │
 """, u"""
 ttttuuuuuuvvvvvvwwwwwwxxxxxxyyyyyyzzzzzz
-                
- │                        
+
+ │
 ─┼─ ┬   ┬ ┬   ┬ ┬   ┬ ─┐ ┌─ ┬   ┬ ────┬
  │  │   │ └┐ ┌┘ │ │ │  ├─┤  │   │ ┌───┘
  └─ └───┴  └─┘  └─┴─┘ ─┘ └─ └───┤ ┴────
@@ -340,92 +340,92 @@
 0000000111111122222223333333444444455555556666666777777788888889999999'''
  ▄███▄   ▐█▌   ▄███▄  ▄███▄     █▌ ▐█████▌ ▄███▄ ▐█████▌ ▄███▄  ▄███▄ ▐█
 ▐█   █▌  ▀█▌  ▐█   █▌▐█   █▌▐█  █▌ ▐█     ▐█         ▐█ ▐█   █▌▐█   █▌▐█
-▐█ ▐ █▌   █▌       █▌   ▐██ ▐█████▌▐████▄ ▐████▄     █▌  █████  ▀████▌  
-▐█ ▌ █▌   █▌     ▄█▀      █▌    █▌      █▌▐█   █▌   ▐█  ▐█   █▌     █▌  
-▐█   █▌   █▌   ▄█▀   ▐█   █▌    █▌      █▌▐█   █▌   █▌  ▐█   █▌     █▌  
- ▀███▀   ███▌ ▐█████▌ ▀███▀     █▌ ▐████▀  ▀███▀   ▐█    ▀███▀  ▀███▀ 
+▐█ ▐ █▌   █▌       █▌   ▐██ ▐█████▌▐████▄ ▐████▄     █▌  █████  ▀████▌
+▐█ ▌ █▌   █▌     ▄█▀      █▌    █▌      █▌▐█   █▌   ▐█  ▐█   █▌     █▌
+▐█   █▌   █▌   ▄█▀   ▐█   █▌    █▌      █▌▐█   █▌   █▌  ▐█   █▌     █▌
+ ▀███▀   ███▌ ▐█████▌ ▀███▀     █▌ ▐████▀  ▀███▀   ▐█    ▀███▀  ▀███▀
 
 """, u'''
 !!!   """""#######$$$$$$$%%%%%%%&&&&&&&(((())))*******++++++
-▐█    ▐█ █▌ ▐█ █▌    █    ▄  █▌   ▄█▄    █▌▐█   ▄▄ ▄▄    
+▐█    ▐█ █▌ ▐█ █▌    █    ▄  █▌   ▄█▄    █▌▐█   ▄▄ ▄▄
 ▐█    ▐█ █▌▐█████▌ ▄███▄ ▐█▌▐█   ▐█ █▌  ▐█  █▌  ▀█▄█▀   ▐█
 ▐█          ▐█ █▌ ▐█▄█▄▄  ▀ █▌    ███   █▌  ▐█ ▐█████▌ ████▌
-▐█         ▐█████▌ ▀▀█▀█▌  ▐█ ▄  ███▌▄  █▌  ▐█  ▄█▀█▄   ▐█ 
-            ▐█ █▌  ▀███▀   █▌▐█▌▐█  █▌  ▐█  █▌  ▀▀ ▀▀    
-▐█                   █    ▐█  ▀  ▀██▀█▌  █▌▐█ 
-                   
+▐█         ▐█████▌ ▀▀█▀█▌  ▐█ ▄  ███▌▄  █▌  ▐█  ▄█▀█▄   ▐█
+            ▐█ █▌  ▀███▀   █▌▐█▌▐█  █▌  ▐█  █▌  ▀▀ ▀▀
+▐█                   █    ▐█  ▀  ▀██▀█▌  █▌▐█
+
 ''', u"""
 ,,,------.../////:::;;;<<<<<<<======>>>>>>>???????@@@@@@@
-               █▌          ▄█▌      ▐█▄     ▄███▄  ▄███▄       
-              ▐█ ▐█ ▐█   ▄█▀  ▐████▌  ▀█▄  ▐█   █▌▐█ ▄▄█▌   
+               █▌          ▄█▌      ▐█▄     ▄███▄  ▄███▄
+              ▐█ ▐█ ▐█   ▄█▀  ▐████▌  ▀█▄  ▐█   █▌▐█ ▄▄█▌
    ▐████▌     █▌       ▐██              ██▌    █▌ ▐█▐█▀█▌
              ▐█  ▐█ ▐█   ▀█▄  ▐████▌  ▄█▀     █▌  ▐█▐█▄█▌
-             █▌     ▀      ▀█▌      ▐█▀           ▐█ ▀▀▀    
-▐█       ▐█ ▐█                                █▌   ▀███▀ 
-▀                          
+             █▌     ▀      ▀█▌      ▐█▀           ▐█ ▀▀▀
+▐█       ▐█ ▐█                                █▌   ▀███▀
+▀
 """, ur"""
 [[[[\\\\\]]]]^^^^^^^_____```{{{{{|||}}}}}~~~~~~~´´´
-▐██▌▐█   ▐██▌  ▐█▌       ▐█    █▌▐█ ▐█           █▌  
-▐█   █▌    █▌ ▐█ █▌       █▌  █▌ ▐█  ▐█   ▄▄    ▐█ 
+▐██▌▐█   ▐██▌  ▐█▌       ▐█    █▌▐█ ▐█           █▌
+▐█   █▌    █▌ ▐█ █▌       █▌  █▌ ▐█  ▐█   ▄▄    ▐█
 ▐█   ▐█    █▌▐█   █▌         ▄█▌ ▐█  ▐█▄ ▐▀▀█▄▄▌
 ▐█    █▌   █▌                ▀█▌ ▐█  ▐█▀     ▀▀
-▐█    ▐█   █▌                 █▌ ▐█  ▐█ 
-▐██▌   █▌▐██▌       █████      █▌▐█ ▐█  
-                                      
+▐█    ▐█   █▌                 █▌ ▐█  ▐█
+▐██▌   █▌▐██▌       █████      █▌▐█ ▐█
+
 """, u"""
 AAAAAAABBBBBBBCCCCCCCDDDDDDDEEEEEEEFFFFFFFGGGGGGGHHHHHHHIIIIJJJJJJJ
- ▄███▄ ▐████▄  ▄███▄ ▐████▄ ▐█████▌▐█████▌ ▄███▄ ▐█   █▌ ██▌     █▌ 
-▐█   █▌▐█   █▌▐█     ▐█   █▌▐█     ▐█     ▐█     ▐█   █▌ ▐█      █▌  
+ ▄███▄ ▐████▄  ▄███▄ ▐████▄ ▐█████▌▐█████▌ ▄███▄ ▐█   █▌ ██▌     █▌
+▐█   █▌▐█   █▌▐█     ▐█   █▌▐█     ▐█     ▐█     ▐█   █▌ ▐█      █▌
 ▐█████▌▐█████ ▐█     ▐█   █▌▐████  ▐████  ▐█     ▐█████▌ ▐█      █▌
 ▐█   █▌▐█   █▌▐█     ▐█   █▌▐█     ▐█     ▐█  ██▌▐█   █▌ ▐█      █▌
 ▐█   █▌▐█   █▌▐█     ▐█   █▌▐█     ▐█     ▐█   █▌▐█   █▌ ▐█ ▐█   █▌
-▐█   █▌▐████▀  ▀███▀ ▐████▀ ▐█████▌▐█      ▀███▀ ▐█   █▌ ██▌ ▀███▀ 
-                     
+▐█   █▌▐████▀  ▀███▀ ▐████▀ ▐█████▌▐█      ▀███▀ ▐█   █▌ ██▌ ▀███▀
+
 """, u"""
 KKKKKKKLLLLLLLMMMMMMMMNNNNNNNOOOOOOOPPPPPPPQQQQQQQRRRRRRRSSSSSSS
-▐█   █▌▐█      ▄█▌▐█▄ ▐██  █▌ ▄███▄ ▐████▄  ▄███▄ ▐████▄  ▄███▄ 
-▐█  █▌ ▐█     ▐█ ▐▌ █▌▐██▌ █▌▐█   █▌▐█   █▌▐█   █▌▐█   █▌▐█     
-▐█▄█▌  ▐█     ▐█ ▐▌ █▌▐█▐█ █▌▐█   █▌▐████▀ ▐█   █▌▐█████  ▀███▄ 
+▐█   █▌▐█      ▄█▌▐█▄ ▐██  █▌ ▄███▄ ▐████▄  ▄███▄ ▐████▄  ▄███▄
+▐█  █▌ ▐█     ▐█ ▐▌ █▌▐██▌ █▌▐█   █▌▐█   █▌▐█   █▌▐█   █▌▐█
+▐█▄█▌  ▐█     ▐█ ▐▌ █▌▐█▐█ █▌▐█   █▌▐████▀ ▐█   █▌▐█████  ▀███▄
 ▐█▀█▌  ▐█     ▐█    █▌▐█ █▌█▌▐█   █▌▐█     ▐█   █▌▐█   █▌     █▌
 ▐█  █▌ ▐█     ▐█    █▌▐█ ▐██▌▐█   █▌▐█     ▐█ █▌█▌▐█   █▌     █▌
-▐█   █▌▐█████▌▐█    █▌▐█  ██▌ ▀███▀ ▐█      ▀███▀ ▐█   █▌ ▀███▀ 
-                                               ▀▀ 
+▐█   █▌▐█████▌▐█    █▌▐█  ██▌ ▀███▀ ▐█      ▀███▀ ▐█   █▌ ▀███▀
+                                               ▀▀
 """, u"""
 TTTTTTTUUUUUUUVVVVVVVWWWWWWWWXXXXXXXYYYYYYYZZZZZZZ
- █████▌▐█   █▌▐█   █▌▐█    █▌▐█   █▌ █▌  █▌▐█████▌ 
-   █▌  ▐█   █▌ █▌ ▐█ ▐█    █▌ ▐█ █▌  ▐█ ▐█     █▌    
-   █▌  ▐█   █▌ ▐█ █▌ ▐█    █▌  ▐█▌    ▐██     █▌        
+ █████▌▐█   █▌▐█   █▌▐█    █▌▐█   █▌ █▌  █▌▐█████▌
+   █▌  ▐█   █▌ █▌ ▐█ ▐█    █▌ ▐█ █▌  ▐█ ▐█     █▌
+   █▌  ▐█   █▌ ▐█ █▌ ▐█    █▌  ▐█▌    ▐██     █▌
    █▌  ▐█   █▌  ███  ▐█ ▐▌ █▌  ███     █▌    █▌
    █▌  ▐█   █▌  ▐█▌  ▐█ ▐▌ █▌ █▌ ▐█    █▌   █▌
-   █▌   ▀███▀    █    ▀█▌▐█▀ ▐█   █▌   █▌  ▐█████▌       
-                                               
+   █▌   ▀███▀    █    ▀█▌▐█▀ ▐█   █▌   █▌  ▐█████▌
+
 """, u"""
 aaaaaaabbbbbbbcccccccdddddddeeeeeeefffffggggggghhhhhhhiiijjjj
        ▐█                 █▌         ▄█▌       ▐█      █▌  █▌
-       ▐█                 █▌        ▐█         ▐█            
+       ▐█                 █▌        ▐█         ▐█
  ▄███▄ ▐████▄  ▄███▄  ▄████▌ ▄███▄ ▐███  ▄███▄ ▐████▄ ▐█▌ ▐█▌
-  ▄▄▄█▌▐█   █▌▐█     ▐█   █▌▐█▄▄▄█▌ ▐█  ▐█   █▌▐█   █▌ █▌  █▌   
+  ▄▄▄█▌▐█   █▌▐█     ▐█   █▌▐█▄▄▄█▌ ▐█  ▐█   █▌▐█   █▌ █▌  █▌
 ▐█▀▀▀█▌▐█   █▌▐█     ▐█   █▌▐█▀▀▀   ▐█  ▐█▄▄▄█▌▐█   █▌ █▌  █▌
  ▀████▌▐████▀  ▀███▀  ▀████▌ ▀███▀  ▐█    ▀▀▀█▌▐█   █▌ █▌  █▌
-                                         ▀███▀           ▐██ 
+                                         ▀███▀           ▐██
 """, u"""
 kkkkkkkllllmmmmmmmmnnnnnnnooooooopppppppqqqqqqqrrrrrrsssssss
-▐█      ██                                                  
-▐█      ▐█                                                  
-▐█  ▄█▌ ▐█  ▄█▌▐█▄ ▐████▄  ▄███▄ ▐████▄  ▄████▌ ▄███▌ ▄███▄ 
-▐█▄█▀   ▐█ ▐█ ▐▌ █▌▐█   █▌▐█   █▌▐█   █▌▐█   █▌▐█    ▐█▄▄▄  
+▐█      ██
+▐█      ▐█
+▐█  ▄█▌ ▐█  ▄█▌▐█▄ ▐████▄  ▄███▄ ▐████▄  ▄████▌ ▄███▌ ▄███▄
+▐█▄█▀   ▐█ ▐█ ▐▌ █▌▐█   █▌▐█   █▌▐█   █▌▐█   █▌▐█    ▐█▄▄▄
 ▐█▀▀█▄  ▐█ ▐█ ▐▌ █▌▐█   █▌▐█   █▌▐█   █▌▐█   █▌▐█      ▀▀▀█▌
-▐█   █▌ ▐█▌▐█    █▌▐█   █▌ ▀███▀ ▐████▀  ▀████▌▐█     ▀███▀ 
+▐█   █▌ ▐█▌▐█    █▌▐█   █▌ ▀███▀ ▐████▀  ▀████▌▐█     ▀███▀
                                  ▐█          █▌
 """, u"""
 tttttuuuuuuuvvvvvvvwwwwwwwwxxxxxxxyyyyyyyzzzzzzz
   █▌
   █▌
- ███▌▐█   █▌▐█   █▌▐█    █▌▐█   █▌▐█   █▌▐█████▌  
-  █▌ ▐█   █▌ █▌ ▐█ ▐█    █▌ ▀█▄█▀ ▐█   █▌   ▄█▀ 
+ ███▌▐█   █▌▐█   █▌▐█    █▌▐█   █▌▐█   █▌▐█████▌
+  █▌ ▐█   █▌ █▌ ▐█ ▐█    █▌ ▀█▄█▀ ▐█   █▌   ▄█▀
   █▌ ▐█   █▌  ███  ▐█ ▐▌ █▌ ▄█▀█▄ ▐█▄▄▄█▌ ▄█▀
   █▌  ▀███▀   ▐█▌   ▀█▌▐█▀ ▐█   █▌  ▀▀▀█▌▐█████▌
-                                   ▀███▀ 
+                                   ▀███▀
 """]
 add_font("Half Block 7x7",HalfBlock7x7Font)
 
diff -Nru urwid-1.2.1/urwid/html_fragment.py urwid-1.3.0/urwid/html_fragment.py
--- urwid-1.2.1/urwid/html_fragment.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/html_fragment.py	2014-10-17 20:09:04.000000000 +0200
@@ -49,12 +49,12 @@
         self.colors = 16
         self.bright_is_bold = False # ignored
         self.has_underline = True # ignored
-        self.register_palette_entry(None, 
+        self.register_palette_entry(None,
             _default_foreground, _default_background)
 
     def set_terminal_properties(self, colors=None, bright_is_bold=None,
         has_underline=None):
-        
+
         if colors is None:
             colors = self.colors
         if bright_is_bold is None:
@@ -70,41 +70,31 @@
         """Not yet implemented"""
         pass
 
-    def start(self):
-        pass
-    
-    def stop(self):
-        pass
-    
     def set_input_timeouts(self, *args):
         pass
 
     def reset_default_terminal_palette(self, *args):
         pass
 
-    def run_wrapper(self,fn):
-        """Call fn."""
-        return fn()
-
     def draw_screen(self, (cols, rows), r ):
-        """Create an html fragment from the render object. 
+        """Create an html fragment from the render object.
         Append it to HtmlGenerator.fragments list.
         """
         # collect output in l
         l = []
-        
+
         assert r.rows() == rows
-    
+
         if r.cursor is not None:
             cx, cy = r.cursor
         else:
             cx = cy = None
-        
+
         y = -1
         for row in r.content():
             y += 1
             col = 0
-            
+
             for a, cs, run in row:
                 run = run.translate(_trans_table)
                 if isinstance(a, AttrSpec):
@@ -126,10 +116,10 @@
                     l.append(html_span(run, aspec))
 
             l.append("\n")
-                        
+
         # add the fragment to the list
         self.fragments.append( "<pre>%s</pre>" % "".join(l) )
-            
+
     def clear(self):
         """
         Force the screen to be completely repainted on the next
@@ -138,7 +128,7 @@
         (does nothing for html_fragment)
         """
         pass
-            
+
     def get_cols_rows(self):
         """Return the next screen size in HtmlGenerator.sizes."""
         if not self.sizes:
@@ -173,9 +163,9 @@
     def html_span(fg, bg, s):
         if not s: return ""
         return ('<span style="color:%s;'
-            'background:%s%s">%s</span>' % 
+            'background:%s%s">%s</span>' %
             (fg, bg, extra, html_escape(s)))
-    
+
     if cursor >= 0:
         c_off, _ign = util.calc_text_pos(s, 0, len(s), cursor)
         c2_off = util.move_next_char(s, c_off, len(s))
@@ -195,17 +185,17 @@
 
 def screenshot_init( sizes, keys ):
     """
-    Replace curses_display.Screen and raw_display.Screen class with 
+    Replace curses_display.Screen and raw_display.Screen class with
     HtmlGenerator.
-    
-    Call this function before executing an application that uses 
+
+    Call this function before executing an application that uses
     curses_display.Screen to have that code use HtmlGenerator instead.
-    
+
     sizes -- list of ( columns, rows ) tuples to be returned by each call
              to HtmlGenerator.get_cols_rows()
     keys -- list of lists of keys to be returned by each call to
             HtmlGenerator.get_input()
-    
+
     Lists of keys may include "window resize" to force the application to
     call get_cols_rows and read a new screen size.
 
@@ -228,7 +218,7 @@
             assert row>0 and col>0
     except (AssertionError, ValueError):
         raise Exception, "sizes must be in the form [ (col1,row1), (col2,row2), ...]"
-    
+
     try:
         for l in keys:
             assert type(l) == list
@@ -236,12 +226,12 @@
                 assert type(k) == str
     except (AssertionError, ValueError):
         raise Exception, "keys must be in the form [ [keyA1, keyA2, ..], [keyB1, ..], ...]"
-    
+
     import curses_display
     curses_display.Screen = HtmlGenerator
     import raw_display
     raw_display.Screen = HtmlGenerator
-    
+
     HtmlGenerator.sizes = sizes
     HtmlGenerator.keys = keys
 
@@ -252,4 +242,4 @@
     HtmlGenerator.fragments = []
     return l
 
-    
+
diff -Nru urwid-1.2.1/urwid/__init__.py urwid-1.3.0/urwid/__init__.py
--- urwid-1.2.1/urwid/__init__.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/__init__.py	2014-10-17 20:09:04.000000000 +0200
@@ -53,7 +53,7 @@
     CURSOR_PAGE_UP, CURSOR_PAGE_DOWN, CURSOR_MAX_LEFT, CURSOR_MAX_RIGHT,
     ACTIVATE)
 from urwid.main_loop import (ExitMainLoop, MainLoop, SelectEventLoop,
-    GLibEventLoop, TornadoEventLoop)
+    GLibEventLoop, TornadoEventLoop, AsyncioEventLoop)
 try:
     from urwid.main_loop import TwistedEventLoop
 except ImportError:
diff -Nru urwid-1.2.1/urwid/lcd_display.py urwid-1.3.0/urwid/lcd_display.py
--- urwid-1.2.1/urwid/lcd_display.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/lcd_display.py	2014-10-17 20:09:04.000000000 +0200
@@ -33,21 +33,12 @@
     def set_mouse_tracking(self, enable=True):
         pass
 
-    def start(self):
-        pass
-
-    def stop(self):
-        pass
-
     def set_input_timeouts(self, *args):
         pass
 
     def reset_default_terminal_palette(self, *args):
         pass
 
-    def run_wrapper(self,fn):
-        return fn()
-    
     def draw_screen(self, (cols, rows), r ):
         pass
 
@@ -68,7 +59,7 @@
         'right_press', 'enter_press', 'exit_press',
         'up_release', 'down_release', 'left_release',
         'right_release', 'enter_release', 'exit_release',
-        'ul_press', 'ur_press', 'll_press', 'lr_press', 
+        'ul_press', 'ur_press', 'll_press', 'lr_press',
         'ul_release', 'ur_release', 'll_release', 'lr_release']
     CMD_PING = 0
     CMD_VERSION = 1
@@ -146,15 +137,15 @@
 
     def _send_packet(self, command, data):
         """
-        low-level packet sending.  
-        Following the protocol requires waiting for ack packet between 
+        low-level packet sending.
+        Following the protocol requires waiting for ack packet between
         sending each packet to the device.
         """
         buf = chr(command) + chr(len(data)) + data
         crc = self.get_crc(buf)
         buf = buf + chr(crc & 0xff) + chr(crc >> 8)
         self._device.write(buf)
-    
+
     def _read_packet(self):
         """
         low-level packet reading.
@@ -171,7 +162,7 @@
                 self._unprocessed = unprocessed
                 return command, data
             except self.MoreDataRequired:
-                return 
+                return
             except self.InvalidPacket:
                 # throw out a byte and try to parse again
                 self._unprocessed = self._unprocessed[1:]
@@ -206,9 +197,9 @@
 
 class KeyRepeatSimulator(object):
     """
-    Provide simulated repeat key events when given press and 
+    Provide simulated repeat key events when given press and
     release events.
-    
+
     If two or more keys are pressed disable repeating until all
     keys are released.
     """
@@ -236,7 +227,7 @@
 
     def next_event(self):
         """
-        Return (remaining, key) where remaining is the number of seconds 
+        Return (remaining, key) where remaining is the number of seconds
         (float) until the key repeat event should be sent, or None if no
         events are pending.
         """
@@ -301,8 +292,8 @@
 
     cursor_style = CFLCDScreen.CURSOR_INVERTING_BLINKING_BLOCK
 
-    def __init__(self, device_path, baud=115200, 
-            repeat_delay=0.5, repeat_next=0.125, 
+    def __init__(self, device_path, baud=115200,
+            repeat_delay=0.5, repeat_next=0.125,
             key_map=['up', 'down', 'left', 'right', 'enter', 'esc']):
         """
         device_path -- eg. '/dev/ttyUSB0'
@@ -357,7 +348,7 @@
             if not packet:
                 break
             command, data = packet
-            
+
             if command == self.CMD_KEY_ACTIVITY and data:
                 d0 = ord(data[0])
                 if 1 <= d0 <= 12:
@@ -374,7 +365,7 @@
             elif command & 0xc0 == 0x40: # "ACK"
                 if command & 0x3f == self._last_command:
                     self._send_next_command()
-        
+
         next_repeat = self.key_repeat.next_event()
         if next_repeat:
             timeout, key = next_repeat
@@ -424,7 +415,7 @@
             sb.append(text)
             y += 1
 
-        if (self._previous_canvas and 
+        if (self._previous_canvas and
                 self._previous_canvas.cursor == canvas.cursor and
                 (not self._update_cursor or not canvas.cursor)):
             pass
@@ -489,6 +480,6 @@
         assert 0 <= led <= 3
         assert rg in (0, 1)
         assert 0 <= value <= 100
-        self.queue_command(self.CMD_GPO, chr(12 - 2 * led - rg) + 
+        self.queue_command(self.CMD_GPO, chr(12 - 2 * led - rg) +
             chr(value))
 
diff -Nru urwid-1.2.1/urwid/main_loop.py urwid-1.3.0/urwid/main_loop.py
--- urwid-1.2.1/urwid/main_loop.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/main_loop.py	2014-10-17 20:09:04.000000000 +0200
@@ -25,12 +25,16 @@
 import time
 import heapq
 import select
-import fcntl
 import os
 from functools import wraps
 from weakref import WeakKeyDictionary
 
-from urwid.util import is_mouse_event
+try:
+    import fcntl
+except ImportError:
+    pass # windows
+
+from urwid.util import StoppingContext, is_mouse_event
 from urwid.compat import PYTHON3
 from urwid.command_map import command_map, REDRAW_SCREEN
 from urwid.wimp import PopUpTarget
@@ -46,6 +50,9 @@
     """
     pass
 
+class CantUseExternalLoop(Exception):
+    pass
+
 class MainLoop(object):
     """
     This is the standard main loop implementation for a single interactive
@@ -112,7 +119,7 @@
         self._unhandled_input = unhandled_input
         self._input_filter = input_filter
 
-        if not hasattr(screen, 'get_input_descriptors'
+        if not hasattr(screen, 'hook_event_loop'
                 ) and event_loop is not None:
             raise NotImplementedError("screen object passed "
                 "%r does not support external event loops" % (screen,))
@@ -120,7 +127,6 @@
             event_loop = SelectEventLoop()
         self.event_loop = event_loop
 
-        self._input_timeout = None
         self._watch_pipes = {}
 
     def _set_widget(self, widget):
@@ -264,14 +270,12 @@
         Start the main loop handling input events and updating the screen. The
         loop will continue until an :exc:`ExitMainLoop` exception is raised.
 
-        This method will use :attr:`screen`'s run_wrapper() method if
-        :attr:`screen`'s start() method has not already been called.
+        If you would prefer to manage the event loop yourself, don't use this
+        method.  Instead, call :meth:`start` before starting the event loop,
+        and :meth:`stop` once it's finished.
         """
         try:
-            if self.screen.started:
-                self._run()
-            else:
-                self.screen.run_wrapper(self._run)
+            self._run()
         except ExitMainLoop:
             pass
 
@@ -289,101 +293,106 @@
         >>> evl.watch_file_rval = 2
         >>> ml = MainLoop(w, [], scr, event_loop=evl)
         >>> ml.run()    # doctest:+ELLIPSIS
+        screen.start()
         screen.set_mouse_tracking()
+        screen.unhook_event_loop(...)
+        screen.hook_event_loop(...)
+        event_loop.enter_idle(<bound method MainLoop.entering_idle...>)
+        event_loop.run()
+        event_loop.remove_enter_idle(1)
+        screen.unhook_event_loop(...)
+        screen.stop()
+        >>> ml.draw_screen()    # doctest:+ELLIPSIS
         screen.get_cols_rows()
         widget.render((20, 10), focus=True)
         screen.draw_screen((20, 10), 'fake canvas')
-        screen.get_input_descriptors()
-        event_loop.watch_file(42, <bound method ...>)
-        event_loop.enter_idle(<bound method ...>)
-        event_loop.run()
-        event_loop.remove_enter_idle(1)
-        event_loop.remove_watch_file(2)
-        >>> scr.started = False
-        >>> ml.run()    # doctest:+ELLIPSIS
-        screen.run_wrapper(<bound method ...>)
         """
 
-    def _run(self):
-        if self.handle_mouse:
-            self.screen.set_mouse_tracking()
+    def start(self):
+        """
+        Sets up the main loop, hooking into the event loop where necessary.
+        Starts the :attr:`screen` if it hasn't already been started.
 
-        if not hasattr(self.screen, 'get_input_descriptors'):
-            return self._run_screen_event_loop()
+        If you want to control starting and stopping the event loop yourself,
+        you should call this method before starting, and call `stop` once the
+        loop has finished.  You may also use this method as a context manager,
+        which will stop the loop automatically at the end of the block:
 
-        self.draw_screen()
+            with main_loop.start():
+                ...
 
-        fd_handles = []
-        def reset_input_descriptors(only_remove=False):
-            for handle in fd_handles:
-                self.event_loop.remove_watch_file(handle)
-            if only_remove:
-                del fd_handles[:]
-            else:
-                fd_handles[:] = [
-                    self.event_loop.watch_file(fd, self._update)
-                    for fd in self.screen.get_input_descriptors()]
-            if not fd_handles and self._input_timeout is not None:
-                self.event_loop.remove_alarm(self._input_timeout)
+        Note that some event loop implementations don't handle exceptions
+        specially if you manage the event loop yourself.  In particular, the
+        Twisted and asyncio loops won't stop automatically when
+        :exc:`ExitMainLoop` (or anything else) is raised.
+        """
+        self.screen.start()
+
+        if self.handle_mouse:
+            self.screen.set_mouse_tracking()
+
+        if not hasattr(self.screen, 'hook_event_loop'):
+            raise CantUseExternalLoop(
+                "Screen {0!r} doesn't support external event loops")
 
         try:
             signals.connect_signal(self.screen, INPUT_DESCRIPTORS_CHANGED,
-                reset_input_descriptors)
+                self._reset_input_descriptors)
         except NameError:
             pass
         # watch our input descriptors
-        reset_input_descriptors()
-        idle_handle = self.event_loop.enter_idle(self.entering_idle)
+        self._reset_input_descriptors()
+        self.idle_handle = self.event_loop.enter_idle(self.entering_idle)
 
-        # Go..
-        self.event_loop.run()
+        return StoppingContext(self)
 
-        # tidy up
-        self.event_loop.remove_enter_idle(idle_handle)
-        reset_input_descriptors(True)
+    def stop(self):
+        """
+        Cleans up any hooks added to the event loop.  Only call this if you're
+        managing the event loop yourself, after the loop stops.
+        """
+        self.event_loop.remove_enter_idle(self.idle_handle)
+        del self.idle_handle
         signals.disconnect_signal(self.screen, INPUT_DESCRIPTORS_CHANGED,
-            reset_input_descriptors)
+            self._reset_input_descriptors)
+        self.screen.unhook_event_loop(self.event_loop)
+
+        self.screen.stop()
+
+    def _reset_input_descriptors(self):
+        self.screen.unhook_event_loop(self.event_loop)
+        self.screen.hook_event_loop(self.event_loop, self._update)
+
+    def _run(self):
+        try:
+            self.start()
+        except CantUseExternalLoop:
+            try:
+                return self._run_screen_event_loop()
+            finally:
+                self.screen.stop()
 
-    def _update(self, timeout=False):
+        self.event_loop.run()
+        self.stop()
+
+    def _update(self, keys, raw):
         """
         >>> w = _refl("widget")
         >>> w.selectable_rval = True
         >>> w.mouse_event_rval = True
         >>> scr = _refl("screen")
         >>> scr.get_cols_rows_rval = (15, 5)
-        >>> scr.get_input_nonblocking_rval = 1, ['y'], [121]
         >>> evl = _refl("event_loop")
         >>> ml = MainLoop(w, [], scr, event_loop=evl)
         >>> ml._input_timeout = "old timeout"
-        >>> ml._update()    # doctest:+ELLIPSIS
-        event_loop.remove_alarm('old timeout')
-        screen.get_input_nonblocking()
-        event_loop.alarm(1, <function ...>)
+        >>> ml._update(['y'], [121])    # doctest:+ELLIPSIS
         screen.get_cols_rows()
         widget.selectable()
         widget.keypress((15, 5), 'y')
-        >>> scr.get_input_nonblocking_rval = None, [("mouse press", 1, 5, 4)
-        ... ], []
-        >>> ml._update()
-        screen.get_input_nonblocking()
+        >>> ml._update([("mouse press", 1, 5, 4)], [])
         widget.mouse_event((15, 5), 'mouse press', 1, 5, 4, focus=True)
-        >>> scr.get_input_nonblocking_rval = None, [], []
-        >>> ml._update()
-        screen.get_input_nonblocking()
-        """
-        if self._input_timeout is not None and not timeout:
-            # cancel the timeout, something else triggered the update
-            self.event_loop.remove_alarm(self._input_timeout)
-        self._input_timeout = None
-
-        max_wait, keys, raw = self.screen.get_input_nonblocking()
-        
-        if max_wait is not None:
-            # if get_input_nonblocking wants to be called back
-            # make sure it happens with an alarm
-            self._input_timeout = self.event_loop.alarm(max_wait, 
-                lambda: self._update(timeout=True)) 
-
+        >>> ml._update([], [])
+        """
         keys = self.input_filter(keys, raw)
 
         if keys:
@@ -415,7 +424,7 @@
                 else:
                     self.screen.set_input_timeouts(None)
                 keys, raw = self.screen.get_input(True)
-                if not keys and next_alarm: 
+                if not keys and next_alarm:
                     sec = next_alarm[0] - time.time()
                     if sec <= 0:
                         break
@@ -579,7 +588,7 @@
 
     def alarm(self, seconds, callback):
         """
-        Call callback() given time from from now.  No parameters are
+        Call callback() a given time from now.  No parameters are
         passed to callback.
 
         Returns a handle that may be passed to remove_alarm()
@@ -667,7 +676,7 @@
             while True:
                 try:
                     self._loop()
-                except select.error, e:
+                except select.error as e:
                     if e.args[0] != 4:
                         # not just something we need to retry
                         raise
@@ -683,7 +692,7 @@
             if self._alarms:
                 tm = self._alarms[0][0]
                 timeout = max(0, tm - time.time())
-            if self._did_something and (not self._alarms or 
+            if self._did_something and (not self._alarms or
                     (self._alarms and timeout > 0)):
                 timeout = 0
                 tm = 'idle'
@@ -726,7 +735,7 @@
 
     def alarm(self, seconds, callback):
         """
-        Call callback() given time from from now.  No parameters are
+        Call callback() a given time from now.  No parameters are
         passed to callback.
 
         Returns a handle that may be passed to remove_alarm()
@@ -1040,6 +1049,10 @@
            ``manage_reactor=False`` and take care of running/stopping the reactor
            at the beginning/ending of your program yourself.
 
+           You can also forego using :class:`MainLoop`'s run() entirely, and
+           instead call start() and stop() before and after starting the
+           reactor.
+
         .. _Twisted: http://twistedmatrix.com/trac/
         """
         if reactor is None:
@@ -1057,7 +1070,7 @@
 
     def alarm(self, seconds, callback):
         """
-        Call callback() given time from from now.  No parameters are
+        Call callback() a given time from now.  No parameters are
         passed to callback.
 
         Returns a handle that may be passed to remove_alarm()
@@ -1196,6 +1209,121 @@
         return wrapper
 
 
+class AsyncioEventLoop(object):
+    """
+    Event loop based on the standard library ``asyncio`` module.
+
+    ``asyncio`` is new in Python 3.4, but also exists as a backport on PyPI for
+    Python 3.3.  The ``trollius`` package is available for older Pythons with
+    slightly different syntax, but also works with this loop.
+    """
+    _we_started_event_loop = False
+
+    _idle_emulation_delay = 1.0/256  # a short time (in seconds)
+
+    def __init__(self, **kwargs):
+        if 'loop' in kwargs:
+            self._loop = kwargs.pop('loop')
+        else:
+            import asyncio
+            self._loop = asyncio.get_event_loop()
+
+    def alarm(self, seconds, callback):
+        """
+        Call callback() a given time from now.  No parameters are
+        passed to callback.
+
+        Returns a handle that may be passed to remove_alarm()
+
+        seconds -- time in seconds to wait before calling callback
+        callback -- function to call from event loop
+        """
+        return self._loop.call_later(seconds, callback)
+
+    def remove_alarm(self, handle):
+        """
+        Remove an alarm.
+
+        Returns True if the alarm exists, False otherwise
+        """
+        existed = not handle._cancelled
+        handle.cancel()
+        return existed
+
+    def watch_file(self, fd, callback):
+        """
+        Call callback() when fd has some data to read.  No parameters
+        are passed to callback.
+
+        Returns a handle that may be passed to remove_watch_file()
+
+        fd -- file descriptor to watch for input
+        callback -- function to call when input is available
+        """
+        self._loop.add_reader(fd, callback)
+        return fd
+
+    def remove_watch_file(self, handle):
+        """
+        Remove an input file.
+
+        Returns True if the input file exists, False otherwise
+        """
+        return self._loop.remove_reader(handle)
+
+    def enter_idle(self, callback):
+        """
+        Add a callback for entering idle.
+
+        Returns a handle that may be passed to remove_idle()
+        """
+        # XXX there's no such thing as "idle" in most event loops; this fakes
+        # it the same way as Twisted, by scheduling the callback to be called
+        # repeatedly
+        mutable_handle = [None]
+        def faux_idle_callback():
+            callback()
+            mutable_handle[0] = self._loop.call_later(
+                self._idle_emulation_delay, faux_idle_callback)
+
+        mutable_handle[0] = self._loop.call_later(
+            self._idle_emulation_delay, faux_idle_callback)
+
+        return mutable_handle
+
+    def remove_enter_idle(self, handle):
+        """
+        Remove an idle callback.
+
+        Returns True if the handle was removed.
+        """
+        # `handle` is just a list containing the current actual handle
+        return self.remove_alarm(handle[0])
+
+    _exc_info = None
+
+    def _exception_handler(self, loop, context):
+        exc = context.get('exception')
+        if exc:
+            loop.stop()
+            if not isinstance(exc, ExitMainLoop):
+                # Store the exc_info so we can re-raise after the loop stops
+                import sys
+                self._exc_info = sys.exc_info()
+        else:
+            loop.default_exception_handler(context)
+
+    def run(self):
+        """
+        Start the event loop.  Exit the loop when any callback raises
+        an exception.  If ExitMainLoop is raised, exit cleanly.
+        """
+        self._loop.set_exception_handler(self._exception_handler)
+        self._loop.run_forever()
+        if self._exc_info:
+            raise self._exc_info[0], self._exc_info[1], self._exc_info[2]
+            self._exc_info = None
+
 
 def _refl(name, rval=None, exit=False):
     """
diff -Nru urwid-1.2.1/urwid/monitored_list.py urwid-1.3.0/urwid/monitored_list.py
--- urwid-1.2.1/urwid/monitored_list.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/monitored_list.py	2014-10-17 20:09:04.000000000 +0200
@@ -158,9 +158,9 @@
             self._focus = 0
             return
         if index < 0 or index >= len(self):
-            raise IndexError, 'focus index is out of range: %s' % (index,)
+            raise IndexError('focus index is out of range: %s' % (index,))
         if index != int(index):
-            raise IndexError, 'invalid focus index: %s' % (index,)
+            raise IndexError('invalid focus index: %s' % (index,))
         index = int(index)
         if index != self._focus:
             self._focus_changed(index)
@@ -265,8 +265,10 @@
 
     def __delitem__(self, y):
         """
-        >>> ml = MonitoredFocusList([0,1,2,3], focus=2)
+        >>> ml = MonitoredFocusList([0,1,2,3,4], focus=2)
         >>> del ml[3]; ml
+        MonitoredFocusList([0, 1, 2, 4], focus=2)
+        >>> del ml[-1]; ml
         MonitoredFocusList([0, 1, 2], focus=2)
         >>> del ml[0]; ml
         MonitoredFocusList([1, 2], focus=1)
@@ -279,11 +281,19 @@
         MonitoredFocusList([5, 6, 5, 6, 5], focus=2)
         >>> del ml[::2]; ml
         MonitoredFocusList([6, 6], focus=1)
+        >>> ml = MonitoredFocusList([0,1,2,3,4,6,7], focus=2)
+        >>> del ml[-2:]; ml
+        MonitoredFocusList([0, 1, 2, 3, 4], focus=2)
+        >>> del ml[-4:-2]; ml
+        MonitoredFocusList([0, 3, 4], focus=1)
+        >>> del ml[:]; ml
+        MonitoredFocusList([], focus=None)
         """
         if isinstance(y, slice):
             focus = self._adjust_focus_on_contents_modified(y)
         else:
-            focus = self._adjust_focus_on_contents_modified(slice(y, y+1))
+            focus = self._adjust_focus_on_contents_modified(slice(y,
+                y+1 or None))
         rval = super(MonitoredFocusList, self).__delitem__(y)
         self._set_focus(focus)
         return rval
@@ -308,6 +318,14 @@
         range(1, 4, 2) <- [12, 13]
         >>> ml[::2] = [10, 11]
         range(0, 4, 2) <- [10, 11]
+        >>> ml[-3:-1] = [21, 22, 23]
+        range(1, 3, 1) <- [21, 22, 23]
+        >>> ml
+        MonitoredFocusList([10, 21, 22, 23, 13], focus=2)
+        >>> ml[:] = []
+        range(0, 5, 1) <- []
+        >>> ml
+        MonitoredFocusList([], focus=None)
         """
         if isinstance(i, slice):
             focus = self._adjust_focus_on_contents_modified(i, y)
@@ -319,51 +337,10 @@
 
     if not PYTHON3:
         def __delslice__(self, i, j):
-            """
-            >>> def modified(indices, new_items):
-            ...     print "range%r <- %r" % (indices, list(new_items))
-            >>> ml = MonitoredFocusList([0,1,2,3,4], focus=2)
-            >>> ml.set_validate_contents_modified(modified)
-            >>> del ml[3:5]
-            range(3, 5, 1) <- []
-            >>> ml
-            MonitoredFocusList([0, 1, 2], focus=2)
-            >>> del ml[:1]
-            range(0, 1, 1) <- []
-            >>> ml
-            MonitoredFocusList([1, 2], focus=1)
-            >>> del ml[1:]; ml
-            range(1, 2, 1) <- []
-            MonitoredFocusList([1], focus=0)
-            >>> del ml[:]; ml
-            range(0, 1, 1) <- []
-            MonitoredFocusList([], focus=None)
-            """
-            focus = self._adjust_focus_on_contents_modified(slice(i, j))
-            rval = super(MonitoredFocusList, self).__delslice__(i, j)
-            self._set_focus(focus)
-            return rval
+            return self.__delitem__(slice(i,j))
 
         def __setslice__(self, i, j, y):
-            """
-            >>> ml = MonitoredFocusList([0,1,2,3,4], focus=2)
-            >>> ml[3:5] = [-1]; ml
-            MonitoredFocusList([0, 1, 2, -1], focus=2)
-            >>> ml[0:1] = []; ml
-            MonitoredFocusList([1, 2, -1], focus=1)
-            >>> ml[1:] = [3, 4]; ml
-            MonitoredFocusList([1, 3, 4], focus=1)
-            >>> ml[1:] = [2]; ml
-            MonitoredFocusList([1, 2], focus=1)
-            >>> ml[0:1] = [9,9,9]; ml
-            MonitoredFocusList([9, 9, 9, 2], focus=3)
-            >>> ml[:] = []; ml
-            MonitoredFocusList([], focus=None)
-            """
-            focus = self._adjust_focus_on_contents_modified(slice(i, j), y)
-            rval = super(MonitoredFocusList, self).__setslice__(i, j, y)
-            self._set_focus(focus)
-            return rval
+            return self.__setitem__(slice(i, j), y)
 
     def __imul__(self, n):
         """
@@ -484,7 +461,7 @@
         self._set_focus(max(0, len(self) - self._focus - 1))
         return rval
 
-    def sort(self):
+    def sort(self, **kwargs):
         """
         >>> ml = MonitoredFocusList([-2,0,1,-3,2,-1,3], focus=4)
         >>> ml.sort(); ml
@@ -493,7 +470,7 @@
         if not self:
             return
         value = self[self._focus]
-        rval = super(MonitoredFocusList, self).sort()
+        rval = super(MonitoredFocusList, self).sort(**kwargs)
         self._set_focus(self.index(value))
         return rval
 
diff -Nru urwid-1.2.1/urwid/old_str_util.py urwid-1.3.0/urwid/old_str_util.py
--- urwid-1.2.1/urwid/old_str_util.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/old_str_util.py	2014-10-17 20:09:04.000000000 +0200
@@ -19,6 +19,7 @@
 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 # Urwid web site: http://excess.org/urwid/
+from __future__ import print_function
 
 import re
 
@@ -30,7 +31,7 @@
 _byte_encoding = None
 
 # GENERATED DATA
-# generated from 
+# generated from
 # http://www.unicode.org/Public/4.0-Update/EastAsianWidth-4.0.0.txt
 
 widths = [
@@ -92,7 +93,7 @@
     """
     assert isinstance(text, bytes), text
     b1 = ord2(text[pos])
-    if not b1 & 0x80: 
+    if not b1 & 0x80:
         return b1, pos+1
     error = ord("?"), pos+1
     lt = len(text)
@@ -189,7 +190,7 @@
         while i < end_offs:
             o, n = decode(text, i)
             w = get_width(o)
-            if w+sc > pref_col: 
+            if w+sc > pref_col:
                 return i, sc
             i = n
             sc += w
@@ -350,18 +351,18 @@
         if last is None:
             out.append((0, l))
             last = l
-        
+
         if last == l:
             out[-1] = (num, l)
         else:
             out.append( (num, l) )
             last = l
 
-    print "widths = ["
+    print("widths = [")
     for o in out[1:]:  # treat control characters same as ascii
-        print "\t%r," % (o,)
-    print "]"
-        
+        print("\t%r," % (o,))
+    print("]")
+
 if __name__ == "__main__":
     process_east_asian_width()
 
diff -Nru urwid-1.2.1/urwid/raw_display.py urwid-1.3.0/urwid/raw_display.py
--- urwid-1.2.1/urwid/raw_display.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/raw_display.py	2014-10-17 20:09:04.000000000 +0200
@@ -23,15 +23,19 @@
 Direct terminal UI implementation
 """
 
-import fcntl
-import termios
 import os
 import select
 import struct
 import sys
-import tty
 import signal
 
+try:
+    import fcntl
+    import termios
+    import tty
+except ImportError:
+    pass # windows
+
 from urwid import util
 from urwid import escape
 from urwid.display_common import BaseScreen, RealTerminal, \
@@ -44,14 +48,14 @@
 
 
 class Screen(BaseScreen, RealTerminal):
-    def __init__(self):
+    def __init__(self, input=sys.stdin, output=sys.stdout):
         """Initialize a screen that directly prints escape codes to an output
         terminal.
         """
         super(Screen, self).__init__()
         self._pal_escape = {}
         self._pal_attrspec = {}
-        signals.connect_signal(self, UPDATE_PALETTE_ENTRY, 
+        signals.connect_signal(self, UPDATE_PALETTE_ENTRY,
             self._on_update_palette_entry)
         self.colors = 16 # FIXME: detect this
         self.has_underline = True # FIXME: detect this
@@ -71,11 +75,15 @@
         self._rows_used = None
         self._cy = 0
         term = os.environ.get('TERM', '')
-        self.bright_is_bold = not term.startswith("xterm")
+        self.fg_bright_is_bold = not term.startswith("xterm")
+        self.bg_bright_is_blink = (term == "linux")
         self.back_color_erase = not term.startswith("screen")
         self._next_timeout = None
-        self._term_output_file = sys.stdout
-        self._term_input_file = sys.stdin
+
+        # Our connections to the world
+        self._term_output_file = output
+        self._term_input_file = input
+
         # pipe for signalling external event loops about resize events
         self._resize_pipe_rd, self._resize_pipe_wr = os.pipe()
         fcntl.fcntl(self._resize_pipe_rd, fcntl.F_SETFL, os.O_NONBLOCK)
@@ -86,12 +94,12 @@
         self._pal_attrspec[name] = a
         self._pal_escape[name] = self._attrspec_to_escape(a)
 
-    def set_input_timeouts(self, max_wait=None, complete_wait=0.125, 
+    def set_input_timeouts(self, max_wait=None, complete_wait=0.125,
         resize_wait=0.125):
         """
         Set the get_input timeout values.  All values are in floating
         point numbers of seconds.
-        
+
         max_wait -- amount of time in seconds to wait for input when
             there is no input pending, wait forever if None
         complete_wait -- amount of time in seconds to wait when
@@ -160,10 +168,10 @@
 
     def _mouse_tracking(self, enable):
         if enable:
-            self._term_output_file.write(escape.MOUSE_TRACKING_ON)
+            self.write(escape.MOUSE_TRACKING_ON)
             self._start_gpm_tracking()
         else:
-            self._term_output_file.write(escape.MOUSE_TRACKING_OFF)
+            self.write(escape.MOUSE_TRACKING_OFF)
             self._stop_gpm_tracking()
 
     def _start_gpm_tracking(self):
@@ -185,15 +193,14 @@
         os.waitpid(self.gpm_mev.pid, 0)
         self.gpm_mev = None
 
-    def start(self, alternate_buffer=True):
+    def _start(self, alternate_buffer=True):
         """
         Initialize the screen and input mode.
 
         alternate_buffer -- use alternate screen buffer
         """
-        assert not self._started
         if alternate_buffer:
-            self._term_output_file.write(escape.SWITCH_TO_ALTERNATE_BUFFER)
+            self.write(escape.SWITCH_TO_ALTERNATE_BUFFER)
             self._rows_used = None
         else:
             self._rows_used = 0
@@ -205,25 +212,22 @@
 
         self.signal_init()
         self._alternate_buffer = alternate_buffer
-        self._input_iter = self._run_input_iter()
         self._next_timeout = self.max_wait
 
         if not self._signal_keys_set:
             self._old_signal_keys = self.tty_signal_keys(fileno=fd)
 
-        super(Screen, self).start()
-
         signals.emit_signal(self, INPUT_DESCRIPTORS_CHANGED)
         # restore mouse tracking to previous state
         self._mouse_tracking(self._mouse_tracking_enabled)
 
-    def stop(self):
+        return super(Screen, self)._start()
+
+    def _stop(self):
         """
         Restore the screen.
         """
         self.clear()
-        if not self._started:
-            return
 
         signals.emit_signal(self, INPUT_DESCRIPTORS_CHANGED)
 
@@ -242,32 +246,33 @@
         elif self.maxrow is not None:
             move_cursor = escape.set_cursor_position(
                 0, self.maxrow)
-        self._term_output_file.write(
+        self.write(
             self._attrspec_to_escape(AttrSpec('',''))
             + escape.SI
             + move_cursor
             + escape.SHOW_CURSOR)
-        self._input_iter = self._fake_input_iter()
 
         if self._old_signal_keys:
             self.tty_signal_keys(*(self._old_signal_keys + (fd,)))
 
-        super(Screen, self).stop()
+        super(Screen, self)._stop()
+
 
+    def write(self, data):
+        """Write some data to the terminal.
 
-    def run_wrapper(self, fn, alternate_buffer=True):
+        You may wish to override this if you're using something other than
+        regular files for input and output.
         """
-        Call start to initialize screen, then call fn.
-        When fn exits call stop to restore the screen to normal.
+        self._term_output_file.write(data)
 
-        alternate_buffer -- use alternate screen buffer and restore
-            normal screen buffer on exit
+    def flush(self):
+        """Flush the output buffer.
+
+        You may wish to override this if you're using something other than
+        regular files for input and output.
         """
-        try:
-            self.start(alternate_buffer)
-            return fn()
-        finally:
-            self.stop()
+        self._term_output_file.flush()
 
     def get_input(self, raw_keys=False):
         """Return pending input as a list.
@@ -285,7 +290,7 @@
 
         Examples of keys returned:
 
-        * ASCII printable characters:  " ", "a", "0", "A", "-", "/" 
+        * ASCII printable characters:  " ", "a", "0", "A", "-", "/"
         * ASCII control characters:  "tab", "enter"
         * Escape sequences:  "up", "page up", "home", "insert", "f1"
         * Key combinations:  "shift f1", "meta a", "ctrl b"
@@ -305,7 +310,7 @@
 
         Examples of mouse events returned:
 
-        * Mouse button press: ('mouse press', 1, 15, 13), 
+        * Mouse button press: ('mouse press', 1, 15, 13),
                               ('meta mouse press', 2, 17, 23)
         * Mouse drag: ('mouse drag', 1, 16, 13),
                       ('mouse drag', 1, 17, 13),
@@ -316,17 +321,16 @@
         assert self._started
 
         self._wait_for_input_ready(self._next_timeout)
-        self._next_timeout, keys, raw = self._input_iter.next()
+        keys, raw = self.parse_input(None, None, self.get_available_raw_input())
 
         # Avoid pegging CPU at 100% when slowly resizing
         if keys==['window resize'] and self.prev_input_resize:
             while True:
                 self._wait_for_input_ready(self.resize_wait)
-                self._next_timeout, keys, raw2 = \
-                    self._input_iter.next()
+                keys, raw2 = self.parse_input(None, None, self.get_available_raw_input())
                 raw += raw2
                 #if not keys:
-                #    keys, raw2 = self._get_input( 
+                #    keys, raw2 = self._get_input(
                 #        self.resize_wait)
                 #    raw += raw2
                 if keys!=['window resize']:
@@ -360,71 +364,135 @@
             fd_list.append(self.gpm_mev.stdout.fileno())
         return fd_list
 
-    def get_input_nonblocking(self):
+    _current_event_loop_handles = ()
+
+    def unhook_event_loop(self, event_loop):
+        """
+        Remove any hooks added by hook_event_loop.
         """
-        Return a (next_input_timeout, keys_pressed, raw_keycodes)
-        tuple.
+        for handle in self._current_event_loop_handles:
+            event_loop.remove_watch_file(handle)
 
-        Use this method if you are implementing your own event loop.
+        if self._input_timeout:
+            event_loop.remove_alarm(self._input_timeout)
+            self._input_timeout = None
 
-        When there is input waiting on one of the descriptors returned
-        by get_input_descriptors() this method should be called to
-        read and process the input.
-
-        This method expects to be called in next_input_timeout seconds
-        (a floating point number) if there is no input waiting.
-        """
-        return self._input_iter.next()
-
-    def _run_input_iter(self):
-        def empty_resize_pipe():
-            # clean out the pipe used to signal external event loops
-            # that a resize has occurred
-            try:
-                while True: os.read(self._resize_pipe_rd, 1)
-            except OSError:
-                pass
+    def hook_event_loop(self, event_loop, callback):
+        """
+        Register the given callback with the event loop, to be called with new
+        input whenever it's available.  The callback should be passed a list of
+        processed keys and a list of unprocessed keycodes.
 
-        while True:
-            processed = []
-            codes = self._get_gpm_codes() + \
-                self._get_keyboard_codes()
+        Subclasses may wish to use parse_input to wrap the callback.
+        """
+        if hasattr(self, 'get_input_nonblocking'):
+            wrapper = self._make_legacy_input_wrapper(event_loop, callback)
+        else:
+            wrapper = lambda: self.parse_input(
+                event_loop, callback, self.get_available_raw_input())
+        fds = self.get_input_descriptors()
+        handles = []
+        for fd in fds:
+            event_loop.watch_file(fd, wrapper)
+        self._current_event_loop_handles = handles
 
-            original_codes = codes
-            try:
-                while codes:
-                    run, codes = escape.process_keyqueue(
-                        codes, True)
-                    processed.extend(run)
-            except escape.MoreInputRequired:
-                k = len(original_codes) - len(codes)
-                yield (self.complete_wait, processed,
-                    original_codes[:k])
-                empty_resize_pipe()
-                original_codes = codes
-                processed = []
-
-                codes += self._get_keyboard_codes() + \
-                    self._get_gpm_codes()
-                while codes:
-                    run, codes = escape.process_keyqueue(
-                        codes, False)
-                    processed.extend(run)
-            
-            if self._resized:
-                processed.append('window resize')
-                self._resized = False
+    _input_timeout = None
+    _partial_codes = None
 
-            yield (self.max_wait, processed, original_codes)
-            empty_resize_pipe()
+    def _make_legacy_input_wrapper(self, event_loop, callback):
+        """
+        Support old Screen classes that still have a get_input_nonblocking and
+        expect it to work.
+        """
+        def wrapper():
+            if self._input_timeout:
+                event_loop.remove_alarm(self._input_timeout)
+                self._input_timeout = None
+            timeout, keys, raw = self.get_input_nonblocking()
+            if timeout is not None:
+                self._input_timeout = event_loop.alarm(timeout, wrapper)
+
+            callback(keys, raw)
 
-    def _fake_input_iter(self):
+        return wrapper
+
+    def get_available_raw_input(self):
         """
-        This generator is a placeholder for when the screen is stopped
-        to always return that no input is available.
+        Return any currently-available input.  Does not block.
+
+        This method is only used by the default `hook_event_loop`
+        implementation; you can safely ignore it if you implement your own.
         """
-        while True:
-            yield (self.max_wait, [], [])
+        codes = self._get_gpm_codes() + self._get_keyboard_codes()
+
+        if self._partial_codes:
+            codes = self._partial_codes + codes
+            self._partial_codes = None
+
+        # clean out the pipe used to signal external event loops
+        # that a resize has occurred
+        try:
+            while True: os.read(self._resize_pipe_rd, 1)
+        except OSError:
+            pass
+
+        return codes
+
+    def parse_input(self, event_loop, callback, codes, wait_for_more=True):
+        """
+        Read any available input from get_available_raw_input, parses it into
+        keys, and calls the given callback.
+
+        The current implementation tries to avoid any assumptions about what
+        the screen or event loop look like; it only deals with parsing keycodes
+        and setting a timeout when an incomplete one is detected.
+
+        `codes` should be a sequence of keycodes, i.e. bytes.  A bytearray is
+        appropriate, but beware of using bytes, which only iterates as integers
+        on Python 3.
+        """
+        # Note: event_loop may be None for 100% synchronous support, only used
+        # by get_input.  Not documented because you shouldn't be doing it.
+        if self._input_timeout and event_loop:
+            event_loop.remove_alarm(self._input_timeout)
+            self._input_timeout = None
+
+        original_codes = codes
+        processed = []
+        try:
+            while codes:
+                run, codes = escape.process_keyqueue(
+                    codes, wait_for_more)
+                processed.extend(run)
+        except escape.MoreInputRequired:
+            # Set a timer to wait for the rest of the input; if it goes off
+            # without any new input having come in, use the partial input
+            k = len(original_codes) - len(codes)
+            processed_codes = original_codes[:k]
+            self._partial_codes = codes
+
+            def _parse_incomplete_input():
+                self._input_timeout = None
+                self._partial_codes = None
+                self.parse_input(
+                    event_loop, callback, codes, wait_for_more=False)
+            if event_loop:
+                self._input_timeout = event_loop.alarm(
+                    self.complete_wait, _parse_incomplete_input)
+
+        else:
+            processed_codes = original_codes
+            self._partial_codes = None
+
+        if self._resized:
+            processed.append('window resize')
+            self._resized = False
+
+        if callback:
+            callback(processed, processed_codes)
+        else:
+            # For get_input
+            return processed, processed_codes
 
     def _get_keyboard_codes(self):
         codes = []
@@ -440,7 +508,7 @@
         try:
             while self.gpm_mev is not None and self.gpm_event_pending:
                 codes.extend(self._encode_gpm_event())
-        except IOError, e:
+        except IOError as e:
             if e.args[0] != 11:
                 raise
         return codes
@@ -459,14 +527,14 @@
                     ready,w,err = select.select(
                         fd_list,[],fd_list, timeout)
                 break
-            except select.error, e:
-                if e.args[0] != 4: 
+            except select.error as e:
+                if e.args[0] != 4:
                     raise
                 if self._resized:
                     ready = []
                     break
-        return ready    
-        
+        return ready
+
     def _getch(self, timeout):
         ready = self._wait_for_input_ready(timeout)
         if self.gpm_mev is not None:
@@ -475,7 +543,7 @@
         if self._term_input_file.fileno() in ready:
             return ord(os.read(self._term_input_file.fileno(), 1))
         return -1
-    
+
     def _encode_gpm_event( self ):
         self.gpm_event_pending = False
         s = self.gpm_mev.stdout.readline().decode('ascii')
@@ -496,7 +564,7 @@
 
         last = next = self.last_bstate
         l = []
-        
+
         mod = 0
         if m & 1:    mod |= 4 # shift
         if m & 10:    mod |= 8 # alt
@@ -561,11 +629,11 @@
 
         self.last_bstate = next
         return l
-    
+
     def _getch_nodelay(self):
         return self._getch(0)
-    
-    
+
+
     def get_cols_rows(self):
         """Return the terminal dimensions (num columns, num rows)."""
         y, x = 80, 24
@@ -585,17 +653,17 @@
         """
         if self._setup_G1_done:
             return
-        
+
         while True:
             try:
-                self._term_output_file.write(escape.DESIGNATE_G1_SPECIAL)
-                self._term_output_file.flush()
+                self.write(escape.DESIGNATE_G1_SPECIAL)
+                self.flush()
                 break
             except IOError:
                 pass
         self._setup_G1_done = True
 
-    
+
     def draw_screen(self, (maxcol, maxrow), r ):
         """Paint screen with rendered canvas."""
         assert self._started
@@ -607,13 +675,13 @@
             return
 
         self._setup_G1()
-        
-        if self._resized: 
+
+        if self._resized:
             # handle resize before trying to draw screen
             return
-        
+
         o = [escape.HIDE_CURSOR, self._attrspec_to_escape(AttrSpec('',''))]
-        
+
         def partial_display():
             # returns True if the screen is in partial display mode
             # ie. only some rows belong to the display
@@ -633,9 +701,9 @@
         def set_cursor_home():
             if not partial_display():
                 return escape.set_cursor_position(0, 0)
-            return (escape.CURSOR_HOME_COL + 
+            return (escape.CURSOR_HOME_COL +
                 escape.move_cursor_up(cy))
-        
+
         def set_cursor_row(y):
             if not partial_display():
                 return escape.set_cursor_position(0, y)
@@ -651,7 +719,7 @@
             return ('\b' + escape.CURSOR_HOME_COL +
                 escape.move_cursor_down(y - cy) +
                 escape.move_cursor_right(x))
-        
+
         def is_blank_row(row):
             if len(row) > 1:
                 return False
@@ -678,7 +746,7 @@
         cy = 0
         for row in r.content():
             y += 1
-            if False and osb and osb[y] == row:
+            if osb and osb[y] == row:
                 # this row of the screen buffer matches what is
                 # currently displayed, so we can skip this line
                 sb.append( osb[y] )
@@ -743,7 +811,7 @@
                     icss = escape.IBMPC_ON
                 else:
                     icss = escape.SO
-                o += [    "\x08"*back, 
+                o += [    "\x08"*back,
                     ias, icss,
                     escape.INSERT_ON, inserttext,
                     escape.INSERT_OFF ]
@@ -766,9 +834,9 @@
             for l in o:
                 if isinstance(l, bytes) and PYTHON3:
                     l = l.decode('utf-8')
-                self._term_output_file.write(l)
-            self._term_output_file.flush()
-        except IOError, e:
+                self.write(l)
+            self.flush()
+        except IOError as e:
             # ignore interrupted syscall
             if e.args[0] != 4:
                 raise
@@ -791,21 +859,21 @@
         new_row = row[:-1]
         z_attr, z_cs, last_text = row[-1]
         last_cols = util.calc_width(last_text, 0, len(last_text))
-        last_offs, z_col = util.calc_text_pos(last_text, 0, 
+        last_offs, z_col = util.calc_text_pos(last_text, 0,
             len(last_text), last_cols-1)
         if last_offs == 0:
             z_text = last_text
             del new_row[-1]
             # we need another segment
             y_attr, y_cs, nlast_text = row[-2]
-            nlast_cols = util.calc_width(nlast_text, 0, 
+            nlast_cols = util.calc_width(nlast_text, 0,
                 len(nlast_text))
             z_col += nlast_cols
             nlast_offs, y_col = util.calc_text_pos(nlast_text, 0,
                 len(nlast_text), nlast_cols-1)
             y_text = nlast_text[nlast_offs:]
             if nlast_offs:
-                new_row.append((y_attr, y_cs, 
+                new_row.append((y_attr, y_cs,
                     nlast_text[:nlast_offs]))
         else:
             z_text = last_text[last_offs:]
@@ -818,12 +886,12 @@
             if nlast_offs:
                 new_row.append((y_attr, y_cs,
                     last_text[:nlast_offs]))
-        
+
         new_row.append((z_attr, z_cs, z_text))
         return new_row, z_col-y_col, (y_attr, y_cs, y_text)
 
-            
-    
+
+
     def clear(self):
         """
         Force the screen to be completely repainted on the next
@@ -832,7 +900,7 @@
         self.screen_buf = None
         self.setup_G1 = True
 
-        
+
     def _attrspec_to_escape(self, a):
         """
         Convert AttrSpec instance a to an escape sequence for the terminal
@@ -849,7 +917,7 @@
             fg = "38;5;%d" % a.foreground_number
         elif a.foreground_basic:
             if a.foreground_number > 7:
-                if self.bright_is_bold:
+                if self.fg_bright_is_bold:
                     fg = "1;%d" % (a.foreground_number - 8 + 30)
                 else:
                     fg = "%d" % (a.foreground_number - 8 + 90)
@@ -863,8 +931,11 @@
             bg = "48;5;%d" % a.background_number
         elif a.background_basic:
             if a.background_number > 7:
-                # this doesn't work on most terminals
-                bg = "%d" % (a.background_number - 8 + 100)
+                if self.bg_bright_is_blink:
+                    bg = "5;%d" % (a.background_number - 8 + 40)
+                else:
+                    # this doesn't work on most terminals
+                    bg = "%d" % (a.background_number + 100)
             else:
                 bg = "%d" % (a.background_number + 40)
         else:
@@ -877,7 +948,7 @@
         """
         colors -- number of colors terminal supports (1, 16, 88 or 256)
             or None to leave unchanged
-        bright_is_bold -- set to True if this terminal uses the bold 
+        bright_is_bold -- set to True if this terminal uses the bold
             setting to create bright colors (numbers 8-15), set to False
             if this Terminal can create bright colors without bold or
             None to leave unchanged
@@ -888,18 +959,18 @@
         if colors is None:
             colors = self.colors
         if bright_is_bold is None:
-            bright_is_bold = self.bright_is_bold
+            bright_is_bold = self.fg_bright_is_bold
         if has_underline is None:
             has_underline = self.has_underline
 
-        if colors == self.colors and bright_is_bold == self.bright_is_bold \
+        if colors == self.colors and bright_is_bold == self.fg_bright_is_bold \
             and has_underline == self.has_underline:
             return
 
         self.colors = colors
-        self.bright_is_bold = bright_is_bold
+        self.fg_bright_is_bold = bright_is_bold
         self.has_underline = has_underline
-            
+
         self.clear()
         self._pal_escape = {}
         for p,v in self._palette.items():
@@ -910,7 +981,7 @@
     def reset_default_terminal_palette(self):
         """
         Attempt to set the terminal palette to default values as taken
-        from xterm.  Uses number of colors from current 
+        from xterm.  Uses number of colors from current
         set_terminal_properties() screen setting.
         """
         if self.colors == 1:
@@ -934,21 +1005,21 @@
         Attempt to set part of the terminal palette (this does not work
         on all terminals.)  The changes are sent as a single escape
         sequence so they should all take effect at the same time.
-        
+
         0 <= index < 256 (some terminals will only have 16 or 88 colors)
         0 <= red, green, blue < 256
         """
 
         modify = ["%d;rgb:%02x/%02x/%02x" % (index, red, green, blue)
             for index, red, green, blue in entries]
-        self._term_output_file.write("\x1b]4;"+";".join(modify)+"\x1b\\")
-        self._term_output_file.flush()
+        self.write("\x1b]4;"+";".join(modify)+"\x1b\\")
+        self.flush()
 
 
     # shortcut for creating an AttrSpec with this screen object's
     # number of colors
     AttrSpec = lambda self, fg, bg: AttrSpec(fg, bg, self.colors)
-    
+
 
 def _test():
     import doctest
diff -Nru urwid-1.2.1/urwid/signals.py urwid-1.3.0/urwid/signals.py
--- urwid-1.2.1/urwid/signals.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/signals.py	2014-10-17 20:09:04.000000000 +0200
@@ -150,8 +150,8 @@
 
         sig_cls = obj.__class__
         if not name in self._supported.get(sig_cls, []):
-            raise NameError, "No such signal %r for object %r" % \
-                (name, obj)
+            raise NameError("No such signal %r for object %r" %
+                (name, obj))
 
         # Just generate an arbitrary (but unique) key
         key = Key()
diff -Nru urwid-1.2.1/urwid/split_repr.py urwid-1.3.0/urwid/split_repr.py
--- urwid-1.2.1/urwid/split_repr.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/split_repr.py	2014-10-17 20:09:04.000000000 +0200
@@ -97,9 +97,9 @@
 def remove_defaults(d, fn):
     """
     Remove keys in d that are set to the default values from
-    fn.  This method is used to unclutter the _repr_attrs() 
+    fn.  This method is used to unclutter the _repr_attrs()
     return value.
-    
+
     d will be modified by this function.
 
     Returns d.
diff -Nru urwid-1.2.1/urwid/tests/test_event_loops.py urwid-1.3.0/urwid/tests/test_event_loops.py
--- urwid-1.2.1/urwid/tests/test_event_loops.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/tests/test_event_loops.py	2014-10-17 20:09:04.000000000 +0200
@@ -34,6 +34,8 @@
         self.assertTrue(evl.remove_watch_file(handle))
         self.assertFalse(evl.remove_watch_file(handle))
 
+    _expected_idle_handle = 1
+
     def test_run(self):
         evl = self.evl
         out = []
@@ -50,10 +52,12 @@
             1/0
         handle = evl.alarm(0.01, exit_clean)
         handle = evl.alarm(0.005, say_hello)
-        self.assertEqual(evl.enter_idle(say_waiting), 1)
+        idle_handle = evl.enter_idle(say_waiting)
+        if self._expected_idle_handle is not None:
+            self.assertEqual(idle_handle, 1)
         evl.run()
-        self.assertIn("hello", out)
-        self.assertIn("clean exit", out)
+        self.assertTrue("hello" in out, out)
+        self.assertTrue("clean exit"in out, out)
         handle = evl.watch_file(rd, exit_clean)
         del out[:]
         evl.run()
@@ -125,7 +129,19 @@
             handle = evl.alarm(0.005, say_hello)
             self.assertEqual(evl.enter_idle(say_waiting), 1)
             evl.run()
-            self.assertIn("da", out)
-            self.assertIn("ta", out)
-            self.assertIn("hello", out)
-            self.assertIn("clean exit", out)
+            self.assertTrue("da" in out, out)
+            self.assertTrue("ta" in out, out)
+            self.assertTrue("hello" in out, out)
+            self.assertTrue("clean exit" in out, out)
+
+
+try:
+    import asyncio
+except ImportError:
+    pass
+else:
+    class AsyncioEventLoopTest(unittest.TestCase, EventLoopTestMixin):
+        def setUp(self):
+            self.evl = urwid.AsyncioEventLoop()
+
+        _expected_idle_handle = None
diff -Nru urwid-1.2.1/urwid/text_layout.py urwid-1.3.0/urwid/text_layout.py
--- urwid-1.2.1/urwid/text_layout.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/text_layout.py	2014-10-17 20:09:04.000000000 +0200
@@ -97,7 +97,7 @@
             if lw >= maxcol:
                 return maxcol
             maxwidth = max(maxwidth, lw)
-        return maxwidth            
+        return maxwidth
 
     def align_layout( self, text, width, segs, wrap, align ):
         """Convert the layout segs to an aligned layout."""
@@ -210,7 +210,7 @@
             else:
                 # unwrap previous line space if possible to
                 # fit more text (we're breaking a word anyway)
-                if b and (len(b[-1]) == 2 or ( len(b[-1])==1 
+                if b and (len(b[-1]) == 2 or ( len(b[-1])==1
                         and len(b[-1][0])==2 )):
                     # look for removed space above
                     if len(b[-1]) == 1:
@@ -225,7 +225,7 @@
                         # combine with previous line
                         del b[-1]
                         p = p_off
-                        pos, sc = calc_text_pos( 
+                        pos, sc = calc_text_pos(
                             text, p, n_cr, width )
                         b.append([(sc,p,pos)])
                         # check for trailing " " or "\n"
@@ -250,18 +250,18 @@
 default_layout = StandardTextLayout()
 ######################################
 
-    
+
 class LayoutSegment:
     def __init__(self, seg):
         """Create object from line layout segment structure"""
-        
+
         assert type(seg) == tuple, repr(seg)
         assert len(seg) in (2,3), repr(seg)
-        
+
         self.sc, self.offs = seg[:2]
-        
+
         assert type(self.sc) == int, repr(self.sc)
-        
+
         if len(seg)==3:
             assert type(self.offs) == int, repr(self.offs)
             assert self.sc > 0, repr(seg)
@@ -279,10 +279,10 @@
                 assert self.sc >= 0, repr(seg)
                 assert type(self.offs)==int
             self.text = self.end = None
-            
+
     def subseg(self, text, start, end):
         """
-        Return a "sub-segment" list containing segment structures 
+        Return a "sub-segment" list containing segment structures
         that make up a portion of this segment.
 
         A list is returned to handle cases where wide characters
@@ -337,18 +337,18 @@
     amount -- screen columns to shift right (+ve) or left (-ve)
     """
     assert type(amount)==int, repr(amount)
-    
+
     if segs and len(segs[0])==2 and segs[0][1]==None:
         # existing shift
         amount += segs[0][0]
         if amount:
             return [(amount,None)]+segs[1:]
         return segs[1:]
-            
+
     if amount:
         return [(amount,None)]+segs
     return segs
-    
+
 
 def trim_line( segs, text, start, end ):
     """
@@ -416,16 +416,16 @@
         s = LayoutSegment(seg)
         if s.offs is not None:
             if s.end is not None:
-                if (current_sc <= pref_col and 
+                if (current_sc <= pref_col and
                     pref_col < current_sc + s.sc):
                     # exact match within this segment
-                    return calc_text_pos( text, 
+                    return calc_text_pos( text,
                         s.offs, s.end,
                         pref_col - current_sc )[0]
                 elif current_sc <= pref_col:
                     closest_sc = current_sc + s.sc - 1
                     closest_pos = s
-                    
+
             if closest_sc is None or ( abs(pref_col-current_sc)
                     < abs(pref_col-closest_sc) ):
                 # this screen column is closer
@@ -435,7 +435,7 @@
                 # we're moving past
                 break
         current_sc += s.sc
-    
+
     if closest_pos is None or type(closest_pos) == int:
         return closest_pos
 
@@ -451,19 +451,19 @@
 
     if row < 0 or row >= len(layout):
         raise Exception("calculate_pos: out of layout row range")
-    
+
     pos = calc_line_pos( text, layout[row], pref_col )
     if pos is not None:
         return pos
-    
+
     rows_above = range(row-1,-1,-1)
     rows_below = range(row+1,len(layout))
     while rows_above and rows_below:
-        if rows_above: 
+        if rows_above:
             r = rows_above.pop(0)
             pos = calc_line_pos(text, layout[r], pref_col)
             if pos is not None: return pos
-        if rows_below: 
+        if rows_below:
             r = rows_below.pop(0)
             pos = calc_line_pos(text, layout[r], pref_col)
             if pos is not None: return pos
@@ -473,7 +473,7 @@
 def calc_coords( text, layout, pos, clamp=1 ):
     """
     Calculate the coordinates closest to position pos in text with layout.
-    
+
     text -- raw string or unicode string
     layout -- layout structure applied to text
     pos -- integer position into text
@@ -500,7 +500,7 @@
                 closest = distance, (x,y)
             x += s.sc
         y += 1
-    
+
     if closest:
         return closest[1]
     return 0,0
diff -Nru urwid-1.2.1/urwid/treetools.py urwid-1.3.0/urwid/treetools.py
--- urwid-1.2.1/urwid/treetools.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/treetools.py	2014-10-17 20:09:04.000000000 +0200
@@ -1,6 +1,6 @@
 #!/usr/bin/python
 #
-# Generic TreeWidget/TreeWalker class 
+# Generic TreeWidget/TreeWalker class
 #    Copyright (c) 2010  Rob Lanphier
 #    Copyright (C) 2004-2010  Ian Ward
 #
@@ -50,13 +50,13 @@
         self.expanded = True
         widget = self.get_indented_widget()
         self.__super.__init__(widget)
-    
+
     def selectable(self):
         """
         Allow selection of non-leaf nodes so children may be (un)expanded
         """
         return not self.is_leaf
-    
+
     def get_indented_widget(self):
         widget = self.get_inner_widget()
         if not self.is_leaf:
@@ -64,9 +64,9 @@
                 [self.unexpanded_icon, self.expanded_icon][self.expanded]),
                 widget], dividechars=1)
         indent_cols = self.get_indent_cols()
-        return urwid.Padding(widget, 
+        return urwid.Padding(widget,
             width=('relative', 100), left=indent_cols)
-    
+
     def update_expanded_icon(self):
         """Update display widget text for parent widgets"""
         # icon is first element in columns indented widget
@@ -83,12 +83,12 @@
 
     def load_inner_widget(self):
         return urwid.Text(self.get_display_text())
-        
+
     def get_node(self):
         return self._node
 
     def get_display_text(self):
-        return (self.get_node().get_key() + ": " + 
+        return (self.get_node().get_key() + ": " +
                 str(self.get_node().get_value()))
 
     def next_inorder(self):
@@ -140,7 +140,7 @@
         """Handle expand & collapse requests (non-leaf nodes)"""
         if self.is_leaf:
             return key
-        
+
         if key in ("+", "right"):
             self.expanded = True
             self.update_expanded_icon()
@@ -151,7 +151,7 @@
             return self.__super.keypress(size, key)
         else:
             return key
-    
+
     def mouse_event(self, size, event, button, col, row, focus):
         if self.is_leaf or event != 'mouse press' or button!=1:
             return False
@@ -160,12 +160,12 @@
             self.expanded = not self.expanded
             self.update_expanded_icon()
             return True
-        
+
         return False
 
     def first_child(self):
         """Return first child if expanded."""
-        if self.is_leaf or not self.expanded: 
+        if self.is_leaf or not self.expanded:
             return None
         else:
             if self._node.has_children():
@@ -193,7 +193,7 @@
 
 class TreeNode(object):
     """
-    Store tree contents and cache TreeWidget objects.  
+    Store tree contents and cache TreeWidget objects.
     A TreeNode consists of the following elements:
     *  key: accessor token for parent nodes
     *  value: subclass-specific data
@@ -215,14 +215,14 @@
 
     def load_widget(self):
         return TreeWidget(self)
-        
+
     def get_depth(self):
         if self._depth is None and self._parent is None:
             self._depth = 0
         elif self._depth is None:
             self._depth = self._parent.get_depth() + 1
         return self._depth
-            
+
     def get_index(self):
         if self.get_depth() == 0:
             return None
@@ -244,19 +244,19 @@
         if self._parent == None and self.get_depth() > 0:
             self._parent = self.load_parent()
         return self._parent
-        
+
     def load_parent(self):
         """Provide TreeNode with a parent for the current node.  This function
         is only required if the tree was instantiated from a child node
         (virtual function)"""
         raise TreeWidgetError("virtual function.  Implement in subclass")
-        
+
     def get_value(self):
         return self._value
 
     def is_root(self):
         return self.get_depth() == 0
-        
+
     def next_sibling(self):
         if self.get_depth() > 0:
             return self.get_parent().next_child(self.get_key())
@@ -274,8 +274,8 @@
         while root.get_parent() is not None:
             root = root.get_parent()
         return root
-        
-        
+
+
 class ParentNode(TreeNode):
     """Maintain sort order for TreeNodes."""
     def __init__(self, value, parent=None, key=None, depth=None):
@@ -297,7 +297,7 @@
 
     def get_child_widget(self, key):
         """Return the widget for a given key.  Create if necessary."""
-        
+
         child = self.get_child_node(key)
         return child.get_widget()
 
@@ -312,10 +312,10 @@
         raise TreeWidgetError("virtual function.  Implement in subclass")
 
     def set_child_node(self, key, node):
-        """Set the child node for a given key.  Useful for bottom-up, lazy 
+        """Set the child node for a given key.  Useful for bottom-up, lazy
         population of a tree.."""
         self._children[key]=node
-    
+
     def change_child_key(self, oldkey, newkey):
         if newkey in self._children:
             raise TreeWidgetError("%s is already in use" % newkey)
@@ -328,7 +328,7 @@
         except ValueError:
             errorstring = ("Can't find key %s in ParentNode %s\n" +
                            "ParentNode items: %s")
-            raise TreeWidgetError(errorstring % (key, self.get_key(), 
+            raise TreeWidgetError(errorstring % (key, self.get_key(),
                                   str(self.get_child_keys())))
 
     def next_child(self, key):
@@ -339,7 +339,7 @@
         if index is None:
             return None
         index += 1
-        
+
         child_keys = self.get_child_keys()
         if index < len(child_keys):
             # get the next item at same level
@@ -355,7 +355,7 @@
 
         child_keys = self.get_child_keys()
         index -= 1
-        
+
         if index >= 0:
             # get the previous item at same level
             return self.get_child_node(child_keys[index])
@@ -366,12 +366,12 @@
         """Return the first TreeNode in the directory."""
         child_keys = self.get_child_keys()
         return self.get_child_node(child_keys[0])
-    
+
     def get_last_child(self):
         """Return the last TreeNode in the directory."""
         child_keys = self.get_child_keys()
         return self.get_child_node(child_keys[-1])
-        
+
     def has_children(self):
         """Does this node have any children?"""
         return len(self.get_child_keys())>0
@@ -379,9 +379,9 @@
 
 class TreeWalker(urwid.ListWalker):
     """ListWalker-compatible class for displaying TreeWidgets
-    
+
     positions are TreeNodes."""
-    
+
     def __init__(self, start_from):
         """start_from: TreeNode with the initial focus."""
         self.focus = start_from
@@ -389,7 +389,7 @@
     def get_focus(self):
         widget = self.focus.get_widget()
         return widget, self.focus
-        
+
     def set_focus(self, focus):
         self.focus = focus
         self._modified()
@@ -431,13 +431,13 @@
             self.focus_end(size)
         else:
             return input
-                                        
+
     def collapse_focus_parent(self, size):
         """Collapse parent directory."""
 
         widget, pos = self.body.get_focus()
         self.move_focus_to_parent(size)
-        
+
         pwidget, ppos = self.body.get_focus()
         if pos != ppos:
             self.keypress(size, "-")
@@ -446,12 +446,12 @@
         """Move focus to parent of widget in focus."""
 
         widget, pos = self.body.get_focus()
-        
+
         parentpos = pos.get_parent()
-        
+
         if parentpos is None:
             return
-        
+
         middle, top, bottom = self.calculate_visible( size )
 
         row_offset, focus_widget, focus_pos, focus_rows, cursor = middle
@@ -464,7 +464,7 @@
                 return
 
         self.change_focus(size, pos.get_parent())
-        
+
     def focus_home(self, size):
         """Move focus to very top."""
 
diff -Nru urwid-1.2.1/urwid/util.py urwid-1.3.0/urwid/util.py
--- urwid-1.2.1/urwid/util.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/util.py	2014-10-17 20:09:04.000000000 +0200
@@ -45,7 +45,7 @@
         except locale.Error:
             pass
         return locale.getlocale()[1] or ""
-    except ValueError, e:
+    except ValueError as e:
         # with invalid LANG value python will throw ValueError
         if e.args and e.args[0].startswith("unknown locale"):
             return ""
@@ -72,7 +72,7 @@
 
     if encoding in ( 'utf-8', 'utf8', 'utf' ):
         str_util.set_byte_encoding("utf8")
-            
+
         _use_dec_special = False
     elif encoding in ( 'euc-jp' # JISX 0208 only
             , 'euc-kr', 'euc-cn', 'euc-tw' # CNS 11643 plain 1 only
@@ -80,7 +80,7 @@
             # these shouldn't happen, should they?
             , 'eucjp', 'euckr', 'euccn', 'euctw', 'cncb' ):
         str_util.set_byte_encoding("wide")
-            
+
         _use_dec_special = True
     else:
         str_util.set_byte_encoding("narrow")
@@ -88,7 +88,7 @@
 
     # if encoding is valid for conversion from unicode, remember it
     _target_encoding = 'ascii'
-    try:    
+    try:
         if encoding:
             u"".encode(encoding)
             _target_encoding = encoding
@@ -114,7 +114,7 @@
             s = s.translate( escape.DEC_SPECIAL_CHARMAP )
         except NotImplementedError:
             # python < 2.4 needs to do this the hard way..
-            for c, alt in zip(escape.DEC_SPECIAL_CHARS, 
+            for c, alt in zip(escape.DEC_SPECIAL_CHARS,
                     escape.ALT_DEC_SPECIAL_CHARS):
                 s = s.replace( c, escape.SO+alt+escape.SI )
 
@@ -136,10 +136,10 @@
     if sis0:
         sout.append( sis0 )
         cout.append( (None,len(sis0)) )
-    
+
     if len(sis)==1:
         return sis0, cout
-    
+
     for sn in sis[1:]:
         assert isinstance(sn, bytes)
         assert isinstance(SI, bytes)
@@ -200,7 +200,7 @@
         spos, sc = calc_text_pos( text, spos, end_offs, start_col )
         if sc < start_col:
             pad_left = 1
-            spos, sc = calc_text_pos( text, start_offs, 
+            spos, sc = calc_text_pos( text, start_offs,
                 end_offs, start_col+1 )
     run = end_col - start_col - pad_left
     pos, sc = calc_text_pos( text, spos, end_offs, run )
@@ -215,7 +215,7 @@
     """
     Return ( trimmed text, trimmed attr, trimmed cs ).
     """
-    spos, epos, pad_left, pad_right = calc_trim_text( 
+    spos, epos, pad_left, pad_right = calc_trim_text(
         text, 0, len(text), start_col, end_col )
     attrtr = rle_subseg( attr, spos, epos )
     cstr = rle_subseg( cs, spos, epos )
@@ -263,7 +263,7 @@
             break
         if x+run > end:
             run = end-x
-        x += run    
+        x += run
         l.append( (a, run) )
     return l
 
@@ -273,7 +273,7 @@
     Return the number of characters covered by a run length
     encoded attribute list.
     """
-    
+
     run = 0
     for v in rle:
         assert type(v) == tuple, repr(rle)
@@ -281,30 +281,32 @@
         run += r
     return run
 
-def rle_append_beginning_modify( rle, (a, r) ):
+def rle_append_beginning_modify(rle, a_r):
     """
-    Append (a, r) to BEGINNING of rle.
+    Append (a, r) (unpacked from *a_r*) to BEGINNING of rle.
     Merge with first run when possible
 
     MODIFIES rle parameter contents. Returns None.
     """
+    a, r = a_r
     if not rle:
         rle[:] = [(a, r)]
-    else:    
+    else:
         al, run = rle[0]
         if a == al:
             rle[0] = (a,run+r)
         else:
             rle[0:0] = [(al, r)]
-            
-            
-def rle_append_modify( rle, (a, r) ):
+
+
+def rle_append_modify(rle, a_r):
     """
-    Append (a,r) to the rle list rle.
+    Append (a, r) (unpacked from *a_r*) to the rle list rle.
     Merge with last run when possible.
-    
+
     MODIFIES rle parameter contents. Returns None.
     """
+    a, r = a_r
     if not rle or rle[-1][0] != a:
         rle.append( (a,r) )
         return
@@ -322,7 +324,7 @@
         return
     rle_append_modify(rle, rle2[0])
     rle += rle2[1:]
-        
+
 def rle_product( rle1, rle2 ):
     """
     Merge the runs of rle1 and rle2 like this:
@@ -337,7 +339,7 @@
     if not rle1 or not rle2: return []
     a1, r1 = rle1[0]
     a2, r2 = rle2[0]
-    
+
     l = []
     while r1 and r2:
         r = min(r1, r2)
@@ -350,7 +352,7 @@
         if r2 == 0 and i2< len(rle2):
             a2, r2 = rle2[i2]
             i2 += 1
-    return l    
+    return l
 
 
 def rle_factor( rle ):
@@ -381,13 +383,13 @@
 
 def _tagmarkup_recurse( tm, attr ):
     """Return (text list, attribute list) for tagmarkup passed.
-    
+
     tm -- tagmarkup
     attr -- current attribute or None"""
-    
+
     if type(tm) == list:
         # for lists recurse to process each subelement
-        rtl = [] 
+        rtl = []
         ral = []
         for element in tm:
             tl, al = _tagmarkup_recurse( element, attr )
@@ -401,18 +403,18 @@
             rtl += tl
             ral += al
         return rtl, ral
-        
+
     if type(tm) == tuple:
         # tuples mark a new attribute boundary
-        if len(tm) != 2: 
-            raise TagMarkupException, "Tuples must be in the form (attribute, tagmarkup): %r" % (tm,)
+        if len(tm) != 2:
+            raise TagMarkupException("Tuples must be in the form (attribute, tagmarkup): %r" % (tm,))
 
         attr, element = tm
         return _tagmarkup_recurse( element, attr )
-    
+
     if not isinstance(tm,(basestring, bytes)):
-        raise TagMarkupException, "Invalid markup element: %r" % tm
-    
+        raise TagMarkupException("Invalid markup element: %r" % tm)
+
     # text
     return [tm], [(attr, len(tm))]
 
@@ -431,15 +433,15 @@
     def __init__(cls, name, bases, d):
         super(MetaSuper, cls).__init__(name, bases, d)
         if hasattr(cls, "_%s__super" % name):
-            raise AttributeError, "Class has same name as one of its super classes"
+            raise AttributeError("Class has same name as one of its super classes")
         setattr(cls, "_%s__super" % name, super(cls))
 
 
-    
+
 def int_scale(val, val_range, out_range):
     """
-    Scale val in the range [0, val_range-1] to an integer in the range 
-    [0, out_range-1].  This implementation uses the "round-half-up" rounding 
+    Scale val in the range [0, val_range-1] to an integer in the range
+    [0, out_range-1].  This implementation uses the "round-half-up" rounding
     method.
 
     >>> "%x" % int_scale(0x7, 0x10, 0x10000)
@@ -456,3 +458,17 @@
     # if num % dem == 0 then we are exactly half-way and have rounded up.
     return num // dem
 
+
+class StoppingContext(object):
+    """Context manager that calls ``stop`` on a given object on exit.  Used to
+    make the ``start`` method on `MainLoop` and `BaseScreen` optionally act as
+    context managers.
+    """
+    def __init__(self, wrapped):
+        self._wrapped = wrapped
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, *exc_info):
+        self._wrapped.stop()
diff -Nru urwid-1.2.1/urwid/version.py urwid-1.3.0/urwid/version.py
--- urwid-1.2.1/urwid/version.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/version.py	2014-10-17 20:09:04.000000000 +0200
@@ -1,5 +1,5 @@
 
-VERSION = (1, 2, 1)
+VERSION = (1, 3, 0)
 __version__ = ''.join(['-.'[type(x) == int]+str(x) for x in VERSION])[1:]
 
 
diff -Nru urwid-1.2.1/urwid/vterm.py urwid-1.3.0/urwid/vterm.py
--- urwid-1.2.1/urwid/vterm.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/vterm.py	2014-10-17 20:09:04.000000000 +0200
@@ -22,18 +22,22 @@
 
 import os
 import sys
-import pty
 import time
 import copy
-import fcntl
 import errno
 import select
 import struct
 import signal
 import atexit
-import termios
 import traceback
 
+try:
+    import pty
+    import fcntl
+    import termios
+except ImportError:
+    pass # windows
+
 from urwid import util
 from urwid.escape import DEC_SPECIAL_CHARS, ALT_DEC_SPECIAL_CHARS
 from urwid.canvas import Canvas
@@ -1518,7 +1522,7 @@
             try:
                 select.select([self.master], [], [], timeout)
                 break
-            except select.error, e:
+            except select.error as e:
                 if e.args[0] != 4:
                     raise
         self.feed()
@@ -1528,7 +1532,7 @@
 
         try:
             data = os.read(self.master, 4096)
-        except OSError, e:
+        except OSError as e:
             if e.errno == 5: # End Of File
                 data = ''
             elif e.errno == errno.EWOULDBLOCK: # empty buffer
diff -Nru urwid-1.2.1/urwid/web_display.py urwid-1.3.0/urwid/web_display.py
--- urwid-1.2.1/urwid/web_display.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/web_display.py	2014-10-17 20:09:04.000000000 +0200
@@ -77,8 +77,8 @@
     33: "page up", 34: "page down", 35: "end", 36: "home",
     37: "left", 38: "up", 39: "right", 40: "down",
     45: "insert", 46: "delete",
-    112: "f1", 113: "f2", 114: "f3", 115: "f4", 
-    116: "f5", 117: "f6", 118: "f7", 119: "f8", 
+    112: "f1", 113: "f2", 114: "f3", 115: "f4",
+    116: "f5", 117: "f6", 118: "f7", 119: "f8",
     120: "f9", 121: "f10", 122: "f11", 123: "f12"
     };
 
@@ -179,16 +179,16 @@
         urwid_id = conn.getResponseHeader("X-Urwid-ID");
         if( send_queue_in != send_queue_out ){
             // keys waiting
-            do_send(); 
+            do_send();
         }
         if(update_method=="polling"){
             set_status("Polling");
         }else if(update_method=="multipart"){
             set_status("Connected");
         }
-    
+
     }
-    
+
     if( conn.responseText == "" ){
         if(update_method=="polling"){
             poll_again();
@@ -200,14 +200,14 @@
         update_method = null;
         return;
     }
-    
+
     var text = document.getElementById('text');
-    
+
     var last_screen = Array(text.childNodes.length);
     for( var i=0; i<text.childNodes.length; i++ ){
         last_screen[i] = text.childNodes[i];
     }
-    
+
     var frags = conn.responseText.split("\n");
     var ln = document.createElement('span');
     var k = 0;
@@ -244,7 +244,7 @@
     for( var i=k; i < text.childNodes.length; i++ ){
         text.removeChild(last_screen[i]);
     }
-    
+
     if(update_method=="polling"){
         poll_again();
     }
@@ -263,17 +263,17 @@
     }else{
         document_location = document.location;
     }
-    
+
     document.onkeypress = body_keypress;
     document.onkeydown = body_keydown;
     document.onresize = body_resize;
-    
+
     body_resize();
     send_queue_out = send_queue_in; // don't queue the first resize
 
     set_status("Connecting");
     setup_connection();
-    
+
     setTimeout("check_fontsize();",check_font_delay);
 }
 
@@ -288,7 +288,7 @@
     d.style.backgroundColor = colours[bg];
     d.style.color = colours[fg];
     d.appendChild(document.createTextNode(s));
-    
+
     return d;
 }
 
@@ -308,7 +308,7 @@
     if( e.shiftKey && e.charCode == 0 ){ mod = "shift " + mod; }
 
     key = keycodes[code];
-    
+
     if( key != undefined ){
         lastkeydown = key;
         send_key( mod + key );
@@ -332,7 +332,7 @@
     if( e.ctrlKey ){ mod = "ctrl " + mod; }
     if( e.altKey || e.metaKey ){ mod = "meta " + mod; }
     if( e.shiftKey && e.charCode == 0 ){ mod = "shift " + mod; }
-    
+
     if( e.charCode != null && e.charCode != 0 ){
         key = String.fromCharCode(e.charCode);
     }else if( e.charCode == null ){
@@ -345,7 +345,7 @@
             return false;
         }
     }
-    
+
     send_key( mod + key );
     stop_key_event(e);
     return false;
@@ -382,11 +382,11 @@
     if( ! urwid_id ){ return; }
     if( ! update_method ){ return; } // connection closed
     if( send_queue_in == send_queue_out ){ return; }
-    if( sending ){ 
+    if( sending ){
         //var queue_delta = send_queue_in - send_queue_out;
         //if( queue_delta < 0 ){ queue_delta += send_queue_max; }
-        //set_status("Sending (queued "+queue_delta+")"); 
-        return; 
+        //set_status("Sending (queued "+queue_delta+")");
+        return;
     }
     try{
         sending = true;
@@ -442,9 +442,9 @@
         alert("Error from server: "+send_conn.statusText);
         return;
     }
-    
+
     sending = false;
-    
+
     if( send_queue_out != send_queue_in ){
         send_more();
     }
@@ -479,12 +479,12 @@
     var avail_width = window_width-18;
     var avail_width_mod = avail_width % char_width;
     var x_size = (avail_width - avail_width_mod)/char_width;
-    
+
     char_height = t2.offsetTop - t.offsetTop;
     var avail_height = window_height-text.offsetTop-10;
     var avail_height_mod = avail_height % char_height;
     var y_size = (avail_height - avail_height_mod)/char_height;
-    
+
     text.style.width = x_size*char_width+"px";
     text.style.height = y_size*char_height+"px";
 
@@ -527,7 +527,7 @@
 _trans_table = "?" * 32 + "".join([chr(x) for x in range(32, 256)])
 
 _css_style = """
-body {    margin: 8px 8px 8px 8px; border: 0; 
+body {    margin: 8px 8px 8px 8px; border: 0;
     color: black; background-color: silver;
     font-family: fixed; overflow: hidden; }
 
@@ -554,7 +554,7 @@
 </head>
 <body id="body" onload="load_web_display()">
 <div style="position:absolute; visibility:hidden;">
-<br id="br"\> 
+<br id="br"\>
 <pre>The quick brown fox jumps over the lazy dog.<span id="testchar">X</span>
 <span id="testchar2">Y</span></pre>
 </div>
@@ -575,9 +575,9 @@
         self.palette = {}
         self.has_color = True
         self._started = False
-    
+
     started = property(lambda self: self._started)
-    
+
     def register_palette( self, l ):
         """Register a list of palette entries.
 
@@ -586,18 +586,18 @@
 
         calls self.register_palette_entry for each item in l
         """
-        
+
         for item in l:
             if len(item) in (3,4):
                 self.register_palette_entry( *item )
                 continue
             assert len(item) == 2, "Invalid register_palette usage"
             name, like_name = item
-            if not self.palette.has_key(like_name):
+            if like_name not in self.palette:
                 raise Exception("palette entry '%s' doesn't exist"%like_name)
             self.palette[name] = self.palette[like_name]
 
-    def register_palette_entry( self, name, foreground, background, 
+    def register_palette_entry( self, name, foreground, background,
         mono=None):
         """Register a single palette entry.
 
@@ -623,17 +623,18 @@
         pass
 
     def start(self):
-        """    
+        """
         This function reads the initial screen size, generates a
         unique id and handles cleanup when fn exits.
-        
+
         web_display.set_preferences(..) must be called before calling
         this function for the preferences to take effect
         """
         global _prefs
 
-        assert not self._started
-        
+        if self._started:
+            return util.StoppingContext(self)
+
         client_init = sys.stdin.read(50)
         assert client_init.startswith("window resize "),client_init
         ignore1,ignore2,x,y = client_init.split(" ",3)
@@ -642,26 +643,26 @@
         self._set_screen_size( x, y )
         self.last_screen = {}
         self.last_screen_width = 0
-    
+
         self.update_method = os.environ["HTTP_X_URWID_METHOD"]
         assert self.update_method in ("multipart","polling")
-    
+
         if self.update_method == "polling" and not _prefs.allow_polling:
             sys.stdout.write("Status: 403 Forbidden\r\n\r\n")
             sys.exit(0)
-        
+
         clients = glob.glob(os.path.join(_prefs.pipe_dir,"urwid*.in"))
         if len(clients) >= _prefs.max_clients:
             sys.stdout.write("Status: 503 Sever Busy\r\n\r\n")
             sys.exit(0)
-        
+
         urwid_id = "%09d%09d"%(random.randrange(10**9),
             random.randrange(10**9))
         self.pipe_name = os.path.join(_prefs.pipe_dir,"urwid"+urwid_id)
         os.mkfifo(self.pipe_name+".in",0600)
         signal.signal(signal.SIGTERM,self._cleanup_pipe)
-        
-        self.input_fd = os.open(self.pipe_name+".in", 
+
+        self.input_fd = os.open(self.pipe_name+".in",
             os.O_NONBLOCK | os.O_RDONLY)
         self.input_tail = ""
         self.content_head = ("Content-type: "
@@ -674,16 +675,20 @@
                 "Content-type: text/plain\r\n"
                 "X-Urwid-ID: "+urwid_id+"\r\n"
                 "\r\n\r\n")
-        
+
         signal.signal(signal.SIGALRM,self._handle_alarm)
         signal.alarm( ALARM_DELAY )
         self._started = True
 
+        return util.StoppingContext(self)
+
     def stop(self):
         """
-        Restore settings and clean up.  
+        Restore settings and clean up.
         """
-        assert self._started
+        if not self._started:
+            return
+
         # XXX which exceptions does this actually raise? EnvironmentError?
         try:
             self._close_connection()
@@ -692,7 +697,7 @@
         signal.signal(signal.SIGTERM,signal.SIG_DFL)
         self._cleanup_pipe()
         self._started = False
-        
+
     def set_input_timeouts(self, *args):
         pass
 
@@ -731,21 +736,21 @@
 
     def _set_screen_size(self, cols, rows ):
         """Set the screen size (within max size)."""
-        
+
         if cols > MAX_COLS:
             cols = MAX_COLS
         if rows > MAX_ROWS:
             rows = MAX_ROWS
         self.screen_size = cols, rows
-        
+
     def draw_screen(self, (cols, rows), r ):
         """Send a screen update to the client."""
-        
+
         if cols != self.last_screen_width:
             self.last_screen = {}
-    
+
         sendq = [self.content_head]
-        
+
         if self.update_method == "polling":
             send = sendq.append
         elif self.update_method == "polling child":
@@ -760,23 +765,23 @@
             send = sendq.append
             send("\r\n")
             self.content_head = ""
-        
+
         assert r.rows() == rows
-    
+
         if r.cursor is not None:
             cx, cy = r.cursor
         else:
             cx = cy = None
-        
+
         new_screen = {}
-        
+
         y = -1
         for row in r.content():
             y += 1
             row = list(row)
-            
+
             l = []
-            
+
             sig = tuple(row)
             if y == cy: sig = sig + (cx,)
             new_screen[sig] = new_screen.get(sig,[]) + [y]
@@ -788,7 +793,7 @@
                     old_line = old_line_numbers[0]
                 send( "<%d\n"%old_line )
                 continue
-            
+
             col = 0
             for (a, cs, run) in row:
                 run = run.translate(_trans_table)
@@ -797,7 +802,7 @@
                 else:
                     fg,bg,mono = self.palette[a]
                 if y == cy and col <= cx:
-                    run_width = util.calc_width(run, 0, 
+                    run_width = util.calc_width(run, 0,
                         len(run))
                     if col+run_width > cx:
                         l.append(code_span(run, fg, bg,
@@ -811,7 +816,7 @@
             send("".join(l)+"\n")
         self.last_screen = new_screen
         self.last_screen_width = cols
-        
+
         if self.update_method == "polling":
             sys.stdout.write("".join(sendq))
             sys.stdout.flush()
@@ -823,9 +828,9 @@
             send("\r\n--ZZ\r\n")
             sys.stdout.write("".join(sendq))
             sys.stdout.flush()
-        
+
         signal.alarm( ALARM_DELAY )
-    
+
 
     def clear(self):
         """
@@ -843,7 +848,7 @@
         Force parent process to exit.
         """
         daemonize( self.pipe_name +".err" )
-        self.input_fd = os.open(self.pipe_name+".in", 
+        self.input_fd = os.open(self.pipe_name+".in",
             os.O_NONBLOCK | os.O_RDONLY)
         self.update_method = "polling child"
         s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
@@ -851,7 +856,7 @@
         s.listen(1)
         s.settimeout(POLL_CONNECT)
         self.server_socket = s
-    
+
     def _handle_alarm(self, sig, frame):
         assert self.update_method in ("multipart","polling child")
         if self.update_method == "polling child":
@@ -866,8 +871,8 @@
             sys.stdout.write("\r\n\r\n--ZZ\r\n")
             sys.stdout.flush()
         signal.alarm( ALARM_DELAY )
-        
-            
+
+
     def get_cols_rows(self):
         """Return the screen size."""
         return self.screen_size
@@ -876,13 +881,13 @@
         """Return pending input as a list."""
         l = []
         resized = False
-        
+
         try:
             iready,oready,eready = select.select(
                 [self.input_fd],[],[],0.5)
-        except select.error, e:
+        except select.error as e:
             # return on interruptions
-            if e.args[0] == 4: 
+            if e.args[0] == 4:
                 if raw_keys:
                     return [],[]
                 return []
@@ -892,16 +897,16 @@
             if raw_keys:
                 return [],[]
             return []
-        
+
         keydata = os.read(self.input_fd, MAX_READ)
         os.close(self.input_fd)
-        self.input_fd = os.open(self.pipe_name+".in", 
+        self.input_fd = os.open(self.pipe_name+".in",
             os.O_NONBLOCK | os.O_RDONLY)
         #sys.stderr.write( repr((keydata,self.input_tail))+"\n" )
         keys = keydata.split("\n")
         keys[0] = self.input_tail + keys[0]
         self.input_tail = keys[-1]
-        
+
         for k in keys[:-1]:
             if k.startswith("window resize "):
                 ign1,ign2,x,y = k.split(" ",3)
@@ -913,16 +918,16 @@
                 l.append(k)
         if resized:
             l.append("window resize")
-        
+
         if raw_keys:
             return l, []
         return l
-    
+
 
 def code_span( s, fg, bg, cursor = -1):
     code_fg = _code_colours[ fg ]
     code_bg = _code_colours[ bg ]
-    
+
     if cursor >= 0:
         c_off, _ign = util.calc_text_pos(s, 0, len(s), cursor)
         c2_off = util.move_next_char(s, c_off, len(s))
@@ -941,12 +946,12 @@
     text = text.replace('>','>')
     return text
 
-    
+
 def is_web_request():
     """
     Return True if this is a CGI web request.
     """
-    return os.environ.has_key('REQUEST_METHOD')
+    return 'REQUEST_METHOD' in os.environ
 
 def handle_short_request():
     """
@@ -959,21 +964,21 @@
     function for the preferences to take effect
     """
     global _prefs
-    
+
     if not is_web_request():
         return False
-        
+
     if os.environ['REQUEST_METHOD'] == "GET":
         # Initial request, send the HTML and javascript.
         sys.stdout.write("Content-type: text/html\r\n\r\n" +
             html_escape(_prefs.app_name).join(_html_page))
         return True
-    
+
     if os.environ['REQUEST_METHOD'] != "POST":
         # Don't know what to do with head requests etc.
         return False
-    
-    if not os.environ.has_key('HTTP_X_URWID_ID'):
+
+    if 'HTTP_X_URWID_ID' not in os.environ:
         # If no urwid id, then the application should be started.
         return False
 
@@ -989,7 +994,7 @@
             #assert 0, "invalid chars in id!"
             sys.stdout.write("Status: 403 Forbidden\r\n\r\n")
             return True
-    
+
     if os.environ.get('HTTP_X_URWID_METHOD',None) == "polling":
         # this is a screen update request
         s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
@@ -1030,16 +1035,16 @@
 
 _prefs = _Preferences()
 
-def set_preferences( app_name, pipe_dir="/tmp", allow_polling=True, 
+def set_preferences( app_name, pipe_dir="/tmp", allow_polling=True,
     max_clients=20 ):
     """
     Set web_display preferences.
-    
+
     app_name -- application name to appear in html interface
-    pipe_dir -- directory for input pipes, daemon update sockets 
+    pipe_dir -- directory for input pipes, daemon update sockets
                 and daemon error logs
-    allow_polling -- allow creation of daemon processes for 
-                     browsers without multipart support 
+    allow_polling -- allow creation of daemon processes for
+                     browsers without multipart support
     max_clients -- maximum concurrent client connections. This
                pool is shared by all urwid applications
                using the same pipe_dir
diff -Nru urwid-1.2.1/urwid/widget.py urwid-1.3.0/urwid/widget.py
--- urwid-1.2.1/urwid/widget.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/widget.py	2014-10-17 20:09:04.000000000 +0200
@@ -171,7 +171,7 @@
 def nocache_widget_render_instance(self):
     """
     Return a function that wraps the cls.render() method
-    and finalizes the canvas that it returns, but does not 
+    and finalizes the canvas that it returns, but does not
     cache the canvas.
     """
     fn = self.render.original_fn
@@ -852,10 +852,10 @@
 
     def _repr_attrs(self):
         attrs = dict(self.__super._repr_attrs(),
-            align=self._align_mode, 
+            align=self._align_mode,
             wrap=self._wrap_mode)
         return remove_defaults(attrs, Text.__init__)
-    
+
     def _invalidate(self):
         self._cache_maxcol = None
         self.__super._invalidate()
@@ -1497,7 +1497,7 @@
             x,y = self.get_cursor_coords((maxcol,))
             pref_col = self.get_pref_col((maxcol,))
             assert pref_col is not None
-            #if pref_col is None: 
+            #if pref_col is None:
             #    pref_col = x
 
             if self._command_map[key] == CURSOR_UP: y -= 1
@@ -1511,7 +1511,7 @@
             if not self._delete_highlighted():
                 if p == 0: return key
                 p = move_prev_char(self.edit_text,0,p)
-                self.set_edit_text( self.edit_text[:p] + 
+                self.set_edit_text( self.edit_text[:p] +
                     self.edit_text[self.edit_pos:] )
                 self.set_edit_pos( p )
 
diff -Nru urwid-1.2.1/urwid/wimp.py urwid-1.3.0/urwid/wimp.py
--- urwid-1.2.1/urwid/wimp.py	2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/wimp.py	2014-10-17 20:09:04.000000000 +0200
@@ -566,7 +566,7 @@
 
     def create_pop_up(self):
         """
-        Subclass must override this method and have is return a widget
+        Subclass must override this method and return a widget
         to be used for the pop-up.  This method is called once each time
         the pop-up is opened.
         """
diff -Nru urwid-1.2.1/urwid.egg-info/PKG-INFO urwid-1.3.0/urwid.egg-info/PKG-INFO
--- urwid-1.2.1/urwid.egg-info/PKG-INFO	2014-04-04 17:55:41.000000000 +0200
+++ urwid-1.3.0/urwid.egg-info/PKG-INFO	2014-10-17 20:27:53.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: urwid
-Version: 1.2.1
+Version: 1.3.0
 Summary: A full-featured console (xterm et al.) user interface library
 Home-page: http://urwid.org/
 Author: Ian Ward
diff -Nru urwid-1.2.1/urwid.egg-info/SOURCES.txt urwid-1.3.0/urwid.egg-info/SOURCES.txt
--- urwid-1.2.1/urwid.egg-info/SOURCES.txt	2014-04-04 17:55:41.000000000 +0200
+++ urwid-1.3.0/urwid.egg-info/SOURCES.txt	2014-10-17 20:27:53.000000000 +0200
@@ -152,6 +152,7 @@
 docs/tutorial/smenu1.png
 docs/tutorial/smenu2.png
 docs/tutorial/smenu3.png
+examples/asyncio_socket_server.py
 examples/bigtext.py
 examples/browse.py
 examples/calc.py
-------------- next part --------------
--- urwid-1.2.1/debian/changelog	2014-05-18 11:08:47.000000000 +0200
+++ urwid-1.3.0/debian/changelog	2015-09-16 11:57:47.000000000 +0200
@@ -1,3 +1,15 @@
+urwid (1.3.0-1) unstable; urgency=medium
+
+  * Team upload.
+  * Refactor rules file to use pybuild.
+  * Remove cdbs to build.
+  * New upstream release. (Closes: #789767)
+  * watch file: use pypi debian redirectory
+  * Bump compat level to 9
+  * Update standard version to 3.9.6, no changes required.
+
+ -- Gianfranco Costamagna <locutusofborg at debian.org>  Tue, 15 Sep 2015 16:04:33 +0200
+
 urwid (1.2.1-2) unstable; urgency=medium
 
   * Team upload.
--- urwid-1.2.1/debian/compat	2014-04-04 18:49:51.000000000 +0200
+++ urwid-1.3.0/debian/compat	2015-09-16 11:57:09.000000000 +0200
@@ -1 +1 @@
-5
+9
--- urwid-1.2.1/debian/control	2014-04-04 19:08:58.000000000 +0200
+++ urwid-1.3.0/debian/control	2015-09-16 11:57:09.000000000 +0200
@@ -4,8 +4,7 @@
 Maintainer: Debian Python Modules Team <python-modules-team at lists.alioth.debian.org>
 Uploaders: Ian Ward <ian at excess.org>
 Build-Depends:
- cdbs (>= 0.4.90~),
- debhelper (>= 5.0.37.2),
+ debhelper (>= 9),
  python-all-dev (>= 2.6.6-3~),
  python-gobject,
  python-setuptools (>= 0.6.16),
@@ -13,7 +12,7 @@
  python-twisted,
  python3-all-dev (>= 3.2),
  python3-setuptools
-Standards-Version: 3.9.5
+Standards-Version: 3.9.6
 Homepage: http://excess.org/urwid/
 Vcs-Svn: svn://anonscm.debian.org/python-modules/packages/urwid/trunk/
 Vcs-Browser: http://anonscm.debian.org/viewvc/python-modules/packages/urwid/trunk/
--- urwid-1.2.1/debian/python3-urwid.install	2014-04-04 19:02:24.000000000 +0200
+++ urwid-1.3.0/debian/python3-urwid.install	1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-debian/tmp/usr/lib/python3*
--- urwid-1.2.1/debian/python-urwid.install	2014-04-04 19:02:24.000000000 +0200
+++ urwid-1.3.0/debian/python-urwid.install	1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-debian/tmp/usr/lib/python2*
--- urwid-1.2.1/debian/rules	2014-05-18 11:07:29.000000000 +0200
+++ urwid-1.3.0/debian/rules	2015-09-16 11:57:09.000000000 +0200
@@ -1,35 +1,10 @@
 #!/usr/bin/make -f
 
-DEB_PYTHON_DISTUTILS_INSTALLDIR_SKEL=/usr/lib/@PYTHONBINARY@/dist-packages/
-DEB_PYTHON_INSTALL_ARGS_ALL=--prefix=/usr --no-compile -O0 --install-layout=deb
+export PYBUILD_NAME=urwid
 
-include /usr/share/cdbs/1/rules/debhelper.mk
-DEB_INSTALL_CHANGELOGS_ALL=docs/changelog.rst
-include /usr/share/cdbs/1/class/python-distutils.mk
+%:
+	dh $@ --with python2,python3 --buildsystem=pybuild
 
-build/python-urwid:: build-docs-test-stamp
-build-docs-test-stamp:
-ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
-	set -e; for python in $(shell pyversions -r) $(shell py3versions -r); do \
-		echo Testing with $$python; \
-		$$python setup.py test; \
-	done;
-else
-	@echo "** tests disabled"
-endif
+override_dh_auto_build:
 	python setup.py build_sphinx
-	touch build-docs-test-stamp
-
-install/python-urwid::
-	chmod a+x debian/tmp/usr/lib/python*/dist-packages/urwid/*.py
-	chmod a-x debian/tmp/usr/lib/python*/dist-packages/urwid/version.py
-
-install/python3-urwid::
-	mv debian/tmp/usr/lib/$(shell py3versions -d) debian/tmp/usr/lib/python3
-	-cp debian/tmp/usr/lib/python3.*/dist-packages/urwid/*.so debian/tmp/usr/lib/python3/dist-packages/urwid/
-	rm -rf debian/tmp/usr/lib/python3.*
-
-clean::
-	rm -rf build build-docs-test-stamp urwid.egg-info
-	rm -f urwid/tests/test_vterm.py
-	find . -name '*.so' -delete
+	dh_auto_build
--- urwid-1.2.1/debian/watch	2014-04-04 18:49:51.000000000 +0200
+++ urwid-1.3.0/debian/watch	2015-09-16 11:57:09.000000000 +0200
@@ -1,2 +1,3 @@
 version=3
-http://pypi.python.org/packages/source/u/urwid/urwid-(.*).tar.gz
+opts=uversionmangle=s/(rc|a|b|c)/~$1/ \
+https://pypi.debian.net/urwid/urwid-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))


More information about the Python-modules-team mailing list