diffstat of debian/ for twisted_11.1.0-1 twisted_11.1.0-1ubuntu2 changelog | 15 control | 3 patches/00_gi_gtk3reactor.patch | 981 ++++++++++++++++++++++++++++++++++++++++ patches/01_posix_wakeups.patch | 114 ++++ patches/series | 2 5 files changed, 1114 insertions(+), 1 deletion(-) diff -Nru twisted-11.1.0/debian/changelog twisted-11.1.0/debian/changelog --- twisted-11.1.0/debian/changelog 2011-12-21 11:35:04.000000000 +0000 +++ twisted-11.1.0/debian/changelog 2012-03-09 15:08:00.000000000 +0000 @@ -1,3 +1,18 @@ +twisted (11.1.0-1ubuntu2) precise; urgency=low + + * debian/patches/01_posix_wakeups.patch: + - Backport wakeup change from trunk gtk2refactoring (LP: #935756) + + -- Rodney Dawes Thu, 08 Mar 2012 11:25:48 -0500 + +twisted (11.1.0-1ubuntu1) precise; urgency=low + + * debian/patches/00_gi_gtk3reactor.patch: + - Backport gireactor/gtk3reactor and gtk2reactor refactor from svn + (LP: #571648, LP: #851187) + + -- Rodney Dawes Wed, 15 Feb 2012 21:39:07 -0500 + twisted (11.1.0-1) unstable; urgency=low * New upstream version. diff -Nru twisted-11.1.0/debian/control twisted-11.1.0/debian/control --- twisted-11.1.0/debian/control 2011-12-21 11:34:51.000000000 +0000 +++ twisted-11.1.0/debian/control 2012-02-16 14:52:56.000000000 +0000 @@ -1,7 +1,8 @@ Source: twisted Section: python Priority: optional -Maintainer: Matthias Klose +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Matthias Klose Uploaders: Free Ekanayaka Build-Depends: debhelper (>= 5.0.37.1), python-all-dev (>= 2.6.5-13~), python-all-dbg, python-zope.interface-dbg, patch Build-Conflicts: python-setuptools diff -Nru twisted-11.1.0/debian/patches/00_gi_gtk3reactor.patch twisted-11.1.0/debian/patches/00_gi_gtk3reactor.patch --- twisted-11.1.0/debian/patches/00_gi_gtk3reactor.patch 1970-01-01 00:00:00.000000000 +0000 +++ twisted-11.1.0/debian/patches/00_gi_gtk3reactor.patch 2012-02-16 14:52:33.000000000 +0000 @@ -0,0 +1,981 @@ +=== added file 'twisted/internet/_glibbase.py' +--- old/twisted/internet/_glibbase.py 1970-01-01 00:00:00 +0000 ++++ new/twisted/internet/_glibbase.py 2012-02-16 02:35:00 +0000 +@@ -0,0 +1,368 @@ ++# -*- test-case-name: twisted.internet.test -*- ++# Copyright (c) Twisted Matrix Laboratories. ++# See LICENSE for details. ++ ++""" ++This module provides base support for Twisted to interact with the glib/gtk ++mainloops. ++ ++The classes in this module should not be used directly, but rather you should ++import gireactor or gtk3reactor for GObject Introspection based applications, ++or glib2reactor or gtk2reactor for applications using legacy static bindings. ++""" ++ ++import signal ++ ++from twisted.internet import base, posixbase, selectreactor ++from twisted.internet.interfaces import IReactorFDSet ++from twisted.python import log, runtime ++from twisted.python.compat import set ++from zope.interface import implements ++ ++ ++class GlibSignalMixin(object): ++ ++ if runtime.platformType == 'posix': ++ ++ def _handleSignals(self): ++ # Let the base class do its thing, but pygtk is probably ++ # going to stomp on us so go beyond that and set up some ++ # signal handling which pygtk won't mess with. This would ++ # be better done by letting this reactor select a ++ # different implementation of installHandler for ++ # _SIGCHLDWaker to use. Then, at least, we could fall ++ # back to our extension module. See #4286. ++ from twisted.internet.process import ( ++ reapAllProcesses as _reapAllProcesses) ++ base._SignalReactorMixin._handleSignals(self) ++ signal.signal(signal.SIGCHLD, ++ lambda *a: self.callFromThread(_reapAllProcesses)) ++ if getattr(signal, "siginterrupt", None) is not None: ++ signal.siginterrupt(signal.SIGCHLD, False) ++ # Like the base, reap processes now in case a process ++ # exited before the handlers above were installed. ++ _reapAllProcesses() ++ ++ ++ ++class GlibWaker(posixbase._UnixWaker): ++ """ ++ Run scheduled events after waking up. ++ """ ++ ++ def doRead(self): ++ posixbase._UnixWaker.doRead(self) ++ self.reactor._simulate() ++ ++ ++ ++class GlibReactorBase(GlibSignalMixin, ++ posixbase.PosixReactorBase, posixbase._PollLikeMixin): ++ """ ++ Base class for GObject event loop reactors. ++ ++ Notification for I/O events (reads and writes on file descriptors) is done ++ by the the gobject-based event loop. File descriptors are registered with ++ gobject with the appropriate flags for read/write/disconnect notification. ++ ++ Time-based events, the results of C{callLater} and C{callFromThread}, are ++ handled differently. Rather than registering each event with gobject, a ++ single gobject timeout is registered for the earliest scheduled event, the ++ output of C{reactor.timeout()}. For example, if there are timeouts in 1, 2 ++ and 3.4 seconds, a single timeout is registered for 1 second in the ++ future. When this timeout is hit, C{_simulate} is called, which calls the ++ appropriate Twisted-level handlers, and a new timeout is added to gobject ++ by the C{_reschedule} method. ++ ++ To handle C{callFromThread} events, we use a custom waker that calls ++ C{_simulate} whenever it wakes up. ++ ++ @ivar _sources: A dictionary mapping L{FileDescriptor} instances to ++ GSource handles. ++ ++ @ivar _reads: A set of L{FileDescriptor} instances currently monitored for ++ reading. ++ ++ @ivar _writes: A set of L{FileDescriptor} instances currently monitored for ++ writing. ++ ++ @ivar _simtag: A GSource handle for the next L{simulate} call. ++ """ ++ implements(IReactorFDSet) ++ ++ # Install a waker that knows it needs to call C{_simulate} in order to run ++ # callbacks queued from a thread: ++ _wakerFactory = GlibWaker ++ ++ def __init__(self, glib_module, gtk_module, useGtk=False): ++ self._simtag = None ++ self._reads = set() ++ self._writes = set() ++ self._sources = {} ++ self._glib = glib_module ++ self._gtk = gtk_module ++ posixbase.PosixReactorBase.__init__(self) ++ ++ self._source_remove = self._glib.source_remove ++ self._timeout_add = self._glib.timeout_add ++ ++ def _mainquit(): ++ if self._gtk.main_level(): ++ self._gtk.main_quit() ++ ++ if useGtk: ++ self._pending = self._gtk.events_pending ++ self._iteration = self._gtk.main_iteration_do ++ self._crash = _mainquit ++ self._run = self._gtk.main ++ else: ++ self.context = self._glib.main_context_default() ++ self._pending = self.context.pending ++ self._iteration = self.context.iteration ++ self.loop = self._glib.MainLoop() ++ self._crash = lambda: self._glib.idle_add(self.loop.quit) ++ self._run = self.loop.run ++ ++ ++ # The input_add function in pygtk1 checks for objects with a ++ # 'fileno' method and, if present, uses the result of that method ++ # as the input source. The pygtk2 input_add does not do this. The ++ # function below replicates the pygtk1 functionality. ++ ++ # In addition, pygtk maps gtk.input_add to _gobject.io_add_watch, and ++ # g_io_add_watch() takes different condition bitfields than ++ # gtk_input_add(). We use g_io_add_watch() here in case pygtk fixes this ++ # bug. ++ def input_add(self, source, condition, callback): ++ if hasattr(source, 'fileno'): ++ # handle python objects ++ def wrapper(source, condition, real_s=source, real_cb=callback): ++ return real_cb(real_s, condition) ++ return self._glib.io_add_watch(source.fileno(), condition, wrapper) ++ else: ++ return self._glib.io_add_watch(source, condition, callback) ++ ++ ++ def _ioEventCallback(self, source, condition): ++ """ ++ Called by event loop when an I/O event occurs. ++ """ ++ log.callWithLogger( ++ source, self._doReadOrWrite, source, source, condition) ++ return True # True = don't auto-remove the source ++ ++ ++ def _add(self, source, primary, other, primaryFlag, otherFlag): ++ """ ++ Add the given L{FileDescriptor} for monitoring either for reading or ++ writing. If the file is already monitored for the other operation, we ++ delete the previous registration and re-register it for both reading ++ and writing. ++ """ ++ if source in primary: ++ return ++ flags = primaryFlag ++ if source in other: ++ self._source_remove(self._sources[source]) ++ flags |= otherFlag ++ self._sources[source] = self.input_add( ++ source, flags, self._ioEventCallback) ++ primary.add(source) ++ ++ ++ def addReader(self, reader): ++ """ ++ Add a L{FileDescriptor} for monitoring of data available to read. ++ """ ++ self._add(reader, self._reads, self._writes, ++ self.INFLAGS, self.OUTFLAGS) ++ ++ ++ def addWriter(self, writer): ++ """ ++ Add a L{FileDescriptor} for monitoring ability to write data. ++ """ ++ self._add(writer, self._writes, self._reads, ++ self.OUTFLAGS, self.INFLAGS) ++ ++ ++ def getReaders(self): ++ """ ++ Retrieve the list of current L{FileDescriptor} monitored for reading. ++ """ ++ return list(self._reads) ++ ++ ++ def getWriters(self): ++ """ ++ Retrieve the list of current L{FileDescriptor} monitored for writing. ++ """ ++ return list(self._writes) ++ ++ ++ def removeAll(self): ++ """ ++ Remove monitoring for all registered L{FileDescriptor}s. ++ """ ++ return self._removeAll(self._reads, self._writes) ++ ++ ++ def _remove(self, source, primary, other, flags): ++ """ ++ Remove monitoring the given L{FileDescriptor} for either reading or ++ writing. If it's still monitored for the other operation, we ++ re-register the L{FileDescriptor} for only that operation. ++ """ ++ if source not in primary: ++ return ++ self._source_remove(self._sources[source]) ++ primary.remove(source) ++ if source in other: ++ self._sources[source] = self.input_add( ++ source, flags, self._ioEventCallback) ++ else: ++ self._sources.pop(source) ++ ++ ++ def removeReader(self, reader): ++ """ ++ Stop monitoring the given L{FileDescriptor} for reading. ++ """ ++ self._remove(reader, self._reads, self._writes, self.OUTFLAGS) ++ ++ ++ def removeWriter(self, writer): ++ """ ++ Stop monitoring the given L{FileDescriptor} for writing. ++ """ ++ self._remove(writer, self._writes, self._reads, self.INFLAGS) ++ ++ ++ def iterate(self, delay=0): ++ """ ++ One iteration of the event loop, for trial's use. ++ ++ This is not used for actual reactor runs. ++ """ ++ self.runUntilCurrent() ++ while self._pending(): ++ self._iteration(0) ++ ++ ++ def crash(self): ++ """ ++ Crash the reactor. ++ """ ++ posixbase.PosixReactorBase.crash(self) ++ self._crash() ++ ++ ++ def stop(self): ++ """ ++ Stop the reactor. ++ """ ++ posixbase.PosixReactorBase.stop(self) ++ # The base implementation only sets a flag, to ensure shutting down is ++ # not reentrant. Unfortunately, this flag is not meaningful to the ++ # gobject event loop. We therefore call wakeUp() to ensure the event ++ # loop will call back into Twisted once this iteration is done. This ++ # will result in self.runUntilCurrent() being called, where the stop ++ # flag will trigger the actual shutdown process, eventually calling ++ # crash() which will do the actual gobject event loop shutdown. ++ self.wakeUp() ++ ++ ++ def run(self, installSignalHandlers=True): ++ """ ++ Run the reactor. ++ """ ++ self.callWhenRunning(self._reschedule) ++ self.startRunning(installSignalHandlers=installSignalHandlers) ++ if self._started: ++ self._run() ++ ++ ++ def callLater(self, *args, **kwargs): ++ """ ++ Schedule a C{DelayedCall}. ++ """ ++ result = posixbase.PosixReactorBase.callLater(self, *args, **kwargs) ++ # Make sure we'll get woken up at correct time to handle this new ++ # scheduled call: ++ self._reschedule() ++ return result ++ ++ ++ def _reschedule(self): ++ """ ++ Schedule a glib timeout for C{_simulate}. ++ """ ++ if self._simtag is not None: ++ self._source_remove(self._simtag) ++ self._simtag = None ++ timeout = self.timeout() ++ if timeout is not None: ++ self._simtag = self._timeout_add(int(timeout * 1000), ++ self._simulate) ++ ++ ++ def _simulate(self): ++ """ ++ Run timers, and then reschedule glib timeout for next scheduled event. ++ """ ++ self.runUntilCurrent() ++ self._reschedule() ++ ++ ++ ++class PortableGlibReactorBase(GlibSignalMixin, selectreactor.SelectReactor): ++ """ ++ Base class for GObject event loop reactors that works on Windows. ++ ++ Sockets aren't supported by GObject's input_add on Win32. ++ """ ++ def __init__(self, glib_module, gtk_module, useGtk=False): ++ self._simtag = None ++ self._glib = glib_module ++ self._gtk = gtk_module ++ selectreactor.SelectReactor.__init__(self) ++ ++ self._source_remove = self._glib.source_remove ++ self._timeout_add = self._glib.timeout_add ++ ++ def _mainquit(): ++ if self._gtk.main_level(): ++ self._gtk.main_quit() ++ ++ if useGtk: ++ self._crash = _mainquit ++ self._run = self._gtk.main ++ else: ++ self.loop = self._glib.MainLoop() ++ self._crash = lambda: self._glib.idle_add(self.loop.quit) ++ self._run = self.loop.run ++ ++ ++ def crash(self): ++ selectreactor.SelectReactor.crash(self) ++ self._crash() ++ ++ ++ def run(self, installSignalHandlers=True): ++ self.startRunning(installSignalHandlers=installSignalHandlers) ++ self._timeout_add(0, self.simulate) ++ if self._started: ++ self._run() ++ ++ ++ def simulate(self): ++ """ ++ Run simulation loops and reschedule callbacks. ++ """ ++ if self._simtag is not None: ++ self._source_remove(self._simtag) ++ self.iterate() ++ timeout = min(self.timeout(), 0.01) ++ if timeout is None: ++ timeout = 0.01 ++ self._simtag = self._timeout_add(int(timeout * 1000), self.simulate) + +=== added file 'twisted/internet/gireactor.py' +--- old/twisted/internet/gireactor.py 1970-01-01 00:00:00 +0000 ++++ new/twisted/internet/gireactor.py 2012-02-16 02:35:00 +0000 +@@ -0,0 +1,93 @@ ++# Copyright (c) Twisted Matrix Laboratories. ++# See LICENSE for details. ++ ++""" ++This module provides support for Twisted to interact with the glib ++mainloop via GObject Introspection. ++ ++In order to use this support, simply do the following:: ++ ++ from twisted.internet import gireactor ++ gireactor.install() ++ ++Then use twisted.internet APIs as usual. The other methods here are not ++intended to be called directly. ++""" ++ ++import sys ++ ++if 'gobject' in sys.modules: ++ raise ImportError( ++ "Introspected and static glib/gtk bindings must not be mixed; can't " ++ "import gireactor since pygtk2 module is already imported.") ++ ++from gi.repository import GLib ++GLib.threads_init() ++ ++from twisted.internet import _glibbase ++from twisted.python import runtime ++ ++# We need to override sys.modules with these to prevent imports. ++# This is required, as importing these can result in SEGFAULTs. ++sys.modules['glib'] = None ++sys.modules['gobject'] = None ++sys.modules['gio'] = None ++sys.modules['gtk'] = None ++ ++ ++ ++class GIReactor(_glibbase.GlibReactorBase): ++ """ ++ GObject-introspection event loop reactor. ++ """ ++ _POLL_DISCONNECTED = (GLib.IOCondition.HUP | GLib.IOCondition.ERR | ++ GLib.IOCondition.NVAL) ++ _POLL_IN = GLib.IOCondition.IN ++ _POLL_OUT = GLib.IOCondition.OUT ++ ++ # glib's iochannel sources won't tell us about any events that we haven't ++ # asked for, even if those events aren't sensible inputs to the poll() ++ # call. ++ INFLAGS = _POLL_IN | _POLL_DISCONNECTED ++ OUTFLAGS = _POLL_OUT | _POLL_DISCONNECTED ++ ++ def __init__(self, useGtk=False): ++ _gtk = None ++ if useGtk is True: ++ from gi.repository import Gtk as _gtk ++ ++ _glibbase.GlibReactorBase.__init__(self, GLib, _gtk, useGtk=useGtk) ++ ++ ++ ++class PortableGIReactor(_glibbase.PortableGlibReactorBase): ++ """ ++ Portable GObject Introspection event loop reactor. ++ """ ++ def __init__(self, useGtk=False): ++ _gtk = None ++ if useGtk is True: ++ from gi.repository import Gtk as _gtk ++ ++ _glibbase.PortableGlibReactorBase.__init__(self, GLib, _gtk, ++ useGtk=useGtk) ++ ++ ++def install(useGtk=False): ++ """ ++ Configure the twisted mainloop to be run inside the glib mainloop. ++ ++ @param useGtk: should GTK+ rather than glib event loop be ++ used (this will be slightly slower but does support GUI). ++ """ ++ if runtime.platform.getType() == 'posix': ++ reactor = GIReactor(useGtk=useGtk) ++ else: ++ reactor = PortableGIReactor(useGtk=useGtk) ++ ++ from twisted.internet.main import installReactor ++ installReactor(reactor) ++ return reactor ++ ++ ++__all__ = ['install'] + +=== modified file 'twisted/internet/gtk2reactor.py' +--- old/twisted/internet/gtk2reactor.py 2011-12-21 12:29:38 +0000 ++++ new/twisted/internet/gtk2reactor.py 2012-02-16 02:35:00 +0000 +@@ -9,21 +9,23 @@ mainloop. + + In order to use this support, simply do the following:: + +- | from twisted.internet import gtk2reactor +- | gtk2reactor.install() ++ from twisted.internet import gtk2reactor ++ gtk2reactor.install() + + Then use twisted.internet APIs as usual. The other methods here are not + intended to be called directly. +- +-When installing the reactor, you can choose whether to use the glib +-event loop or the GTK+ event loop which is based on it but adds GUI +-integration. + """ + + # System Imports +-import sys, signal ++import sys ++ ++if 'gi' in sys.modules: ++ raise ImportError( ++ "Introspected and static glib/gtk bindings must not be mixed; can't " ++ "import gtk2reactor since gi module is already imported.") + +-from zope.interface import implements ++# Disable gi imports to avoid potential problems. ++sys.modules['gi'] = None + + try: + if not hasattr(sys, 'frozen'): +@@ -32,6 +34,7 @@ try: + pygtk.require('2.0') + except (ImportError, AttributeError): + pass # maybe we're using pygtk before this hack existed. ++ + import gobject + if hasattr(gobject, "threads_init"): + # recent versions of python-gtk expose this. python-gtk=2.4.1 +@@ -40,309 +43,46 @@ if hasattr(gobject, "threads_init"): + gobject.threads_init() + + # Twisted Imports +-from twisted.python import log, runtime +-from twisted.python.compat import set +-from twisted.internet.interfaces import IReactorFDSet +-from twisted.internet import base, posixbase, selectreactor +- +-POLL_DISCONNECTED = gobject.IO_HUP | gobject.IO_ERR | gobject.IO_NVAL +- +-# glib's iochannel sources won't tell us about any events that we haven't +-# asked for, even if those events aren't sensible inputs to the poll() +-# call. +-INFLAGS = gobject.IO_IN | POLL_DISCONNECTED +-OUTFLAGS = gobject.IO_OUT | POLL_DISCONNECTED +- +- +- +-def _our_mainquit(): +- # XXX: gtk.main_quit() (which is used for crash()) raises an exception if +- # gtk.main_level() == 0; however, all the tests freeze if we use this +- # function to stop the reactor. what gives? (I believe this may have been +- # a stupid mistake where I forgot to import gtk here... I will remove this +- # comment if the tests pass) +- import gtk +- if gtk.main_level(): +- gtk.main_quit() ++from twisted.internet import _glibbase ++from twisted.python import runtime + + +- +-class _Gtk2SignalMixin(object): +- if runtime.platformType == 'posix': +- def _handleSignals(self): +- # Let the base class do its thing, but pygtk is probably +- # going to stomp on us so go beyond that and set up some +- # signal handling which pygtk won't mess with. This would +- # be better done by letting this reactor select a +- # different implementation of installHandler for +- # _SIGCHLDWaker to use. Then, at least, we could fall +- # back to our extension module. See #4286. +- from twisted.internet.process import reapAllProcesses as _reapAllProcesses +- base._SignalReactorMixin._handleSignals(self) +- signal.signal(signal.SIGCHLD, lambda *a: self.callFromThread(_reapAllProcesses)) +- if getattr(signal, "siginterrupt", None) is not None: +- signal.siginterrupt(signal.SIGCHLD, False) +- # Like the base, reap processes now in case a process +- # exited before the handlers above were installed. +- _reapAllProcesses() +- +- +- +-class Gtk2Reactor(_Gtk2SignalMixin, posixbase.PosixReactorBase, posixbase._PollLikeMixin): ++class Gtk2Reactor(_glibbase.GlibReactorBase): + """ +- GTK+-2 event loop reactor. +- +- @ivar _sources: A dictionary mapping L{FileDescriptor} instances to gtk +- watch handles. +- +- @ivar _reads: A set of L{FileDescriptor} instances currently monitored for +- reading. +- +- @ivar _writes: A set of L{FileDescriptor} instances currently monitored for +- writing. +- +- @ivar _simtag: A gtk timeout handle for the next L{simulate} call. ++ PyGTK+ 2 event loop reactor. + """ +- implements(IReactorFDSet) +- +- _POLL_DISCONNECTED = POLL_DISCONNECTED ++ _POLL_DISCONNECTED = gobject.IO_HUP | gobject.IO_ERR | gobject.IO_NVAL + _POLL_IN = gobject.IO_IN + _POLL_OUT = gobject.IO_OUT + ++ # glib's iochannel sources won't tell us about any events that we haven't ++ # asked for, even if those events aren't sensible inputs to the poll() ++ # call. ++ INFLAGS = _POLL_IN | _POLL_DISCONNECTED ++ OUTFLAGS = _POLL_OUT | _POLL_DISCONNECTED ++ + def __init__(self, useGtk=True): +- self._simtag = None +- self._reads = set() +- self._writes = set() +- self._sources = {} +- posixbase.PosixReactorBase.__init__(self) +- # pre 2.3.91 the glib iteration and mainloop functions didn't release +- # global interpreter lock, thus breaking thread and signal support. +- if getattr(gobject, "pygtk_version", ()) >= (2, 3, 91) and not useGtk: +- self.context = gobject.main_context_default() +- self.__pending = self.context.pending +- self.__iteration = self.context.iteration +- self.loop = gobject.MainLoop() +- self.__crash = self.loop.quit +- self.__run = self.loop.run +- else: +- import gtk +- self.__pending = gtk.events_pending +- self.__iteration = gtk.main_iteration +- self.__crash = _our_mainquit +- self.__run = gtk.main +- +- +- # The input_add function in pygtk1 checks for objects with a +- # 'fileno' method and, if present, uses the result of that method +- # as the input source. The pygtk2 input_add does not do this. The +- # function below replicates the pygtk1 functionality. +- +- # In addition, pygtk maps gtk.input_add to _gobject.io_add_watch, and +- # g_io_add_watch() takes different condition bitfields than +- # gtk_input_add(). We use g_io_add_watch() here in case pygtk fixes this +- # bug. +- def input_add(self, source, condition, callback): +- if hasattr(source, 'fileno'): +- # handle python objects +- def wrapper(source, condition, real_s=source, real_cb=callback): +- return real_cb(real_s, condition) +- return gobject.io_add_watch(source.fileno(), condition, wrapper) +- else: +- return gobject.io_add_watch(source, condition, callback) +- +- +- def _add(self, source, primary, other, primaryFlag, otherFlag): +- """ +- Add the given L{FileDescriptor} for monitoring either for reading or +- writing. If the file is already monitored for the other operation, we +- delete the previous registration and re-register it for both reading +- and writing. +- """ +- if source in primary: +- return +- flags = primaryFlag +- if source in other: +- gobject.source_remove(self._sources[source]) +- flags |= otherFlag +- self._sources[source] = self.input_add(source, flags, self.callback) +- primary.add(source) +- +- +- def addReader(self, reader): +- """ +- Add a L{FileDescriptor} for monitoring of data available to read. +- """ +- self._add(reader, self._reads, self._writes, INFLAGS, OUTFLAGS) +- +- +- def addWriter(self, writer): +- """ +- Add a L{FileDescriptor} for monitoring ability to write data. +- """ +- self._add(writer, self._writes, self._reads, OUTFLAGS, INFLAGS) +- +- +- def getReaders(self): +- """ +- Retrieve the list of current L{FileDescriptor} monitored for reading. +- """ +- return list(self._reads) +- +- +- def getWriters(self): +- """ +- Retrieve the list of current L{FileDescriptor} monitored for writing. +- """ +- return list(self._writes) +- +- +- def removeAll(self): +- """ +- Remove monitoring for all registered L{FileDescriptor}s. +- """ +- return self._removeAll(self._reads, self._writes) +- +- +- def _remove(self, source, primary, other, flags): +- """ +- Remove monitoring the given L{FileDescriptor} for either reading or +- writing. If it's still monitored for the other operation, we +- re-register the L{FileDescriptor} for only that operation. +- """ +- if source not in primary: +- return +- gobject.source_remove(self._sources[source]) +- primary.remove(source) +- if source in other: +- self._sources[source] = self.input_add( +- source, flags, self.callback) +- else: +- self._sources.pop(source) +- +- +- def removeReader(self, reader): +- """ +- Stop monitoring the given L{FileDescriptor} for reading. +- """ +- self._remove(reader, self._reads, self._writes, OUTFLAGS) +- +- +- def removeWriter(self, writer): +- """ +- Stop monitoring the given L{FileDescriptor} for writing. +- """ +- self._remove(writer, self._writes, self._reads, INFLAGS) +- +- +- doIterationTimer = None +- +- def doIterationTimeout(self, *args): +- self.doIterationTimer = None +- return 0 # auto-remove +- +- +- def doIteration(self, delay): +- # flush some pending events, return if there was something to do +- # don't use the usual "while self.context.pending(): self.context.iteration()" +- # idiom because lots of IO (in particular test_tcp's +- # ProperlyCloseFilesTestCase) can keep us from ever exiting. +- log.msg(channel='system', event='iteration', reactor=self) +- if self.__pending(): +- self.__iteration(0) +- return +- # nothing to do, must delay +- if delay == 0: +- return # shouldn't delay, so just return +- self.doIterationTimer = gobject.timeout_add(int(delay * 1000), +- self.doIterationTimeout) +- # This will either wake up from IO or from a timeout. +- self.__iteration(1) # block +- # note: with the .simulate timer below, delays > 0.1 will always be +- # woken up by the .simulate timer +- if self.doIterationTimer: +- # if woken by IO, need to cancel the timer +- gobject.source_remove(self.doIterationTimer) +- self.doIterationTimer = None +- +- +- def crash(self): +- posixbase.PosixReactorBase.crash(self) +- self.__crash() +- +- +- def run(self, installSignalHandlers=1): +- self.startRunning(installSignalHandlers=installSignalHandlers) +- gobject.timeout_add(0, self.simulate) +- if self._started: +- self.__run() +- +- +- def callback(self, source, condition): +- log.callWithLogger( +- source, self._doReadOrWrite, source, source, condition) +- self.simulate() # fire Twisted timers +- return 1 # 1=don't auto-remove the source +- +- +- def simulate(self): +- """ +- Run simulation loops and reschedule callbacks. +- """ +- if self._simtag is not None: +- gobject.source_remove(self._simtag) +- self.runUntilCurrent() +- timeout = min(self.timeout(), 0.1) +- if timeout is None: +- timeout = 0.1 +- # grumble +- self._simtag = gobject.timeout_add(int(timeout * 1010), self.simulate) ++ _gtk = None ++ if useGtk is True: ++ import gtk as _gtk ++ ++ _glibbase.GlibReactorBase.__init__(self, gobject, _gtk, useGtk=useGtk) + + + +-class PortableGtkReactor(_Gtk2SignalMixin, selectreactor.SelectReactor): ++class PortableGtkReactor(_glibbase.PortableGlibReactorBase): + """ + Reactor that works on Windows. + + Sockets aren't supported by GTK+'s input_add on Win32. + """ +- _simtag = None +- +- def crash(self): +- selectreactor.SelectReactor.crash(self) +- import gtk +- # mainquit is deprecated in newer versions +- if gtk.main_level(): +- if hasattr(gtk, 'main_quit'): +- gtk.main_quit() +- else: +- gtk.mainquit() +- +- +- def run(self, installSignalHandlers=1): +- import gtk +- self.startRunning(installSignalHandlers=installSignalHandlers) +- gobject.timeout_add(0, self.simulate) +- # mainloop is deprecated in newer versions +- if self._started: +- if hasattr(gtk, 'main'): +- gtk.main() +- else: +- gtk.mainloop() +- +- +- def simulate(self): +- """ +- Run simulation loops and reschedule callbacks. +- """ +- if self._simtag is not None: +- gobject.source_remove(self._simtag) +- self.iterate() +- timeout = min(self.timeout(), 0.1) +- if timeout is None: +- timeout = 0.1 +- # grumble +- self._simtag = gobject.timeout_add(int(timeout * 1010), self.simulate) ++ def __init__(self, useGtk=True): ++ _gtk = None ++ if useGtk is True: ++ import gtk as _gtk + ++ _glibbase.PortableGlibReactorBase.__init__(self, gobject, _gtk, ++ useGtk=useGtk) + + + def install(useGtk=True): +@@ -358,7 +98,6 @@ def install(useGtk=True): + return reactor + + +- + def portableInstall(useGtk=True): + """ + Configure the twisted mainloop to be run inside the gtk mainloop. +@@ -369,10 +108,8 @@ def portableInstall(useGtk=True): + return reactor + + +- + if runtime.platform.getType() != 'posix': + install = portableInstall + + +- + __all__ = ['install'] + +=== added file 'twisted/internet/gtk3reactor.py' +--- old/twisted/internet/gtk3reactor.py 1970-01-01 00:00:00 +0000 ++++ new/twisted/internet/gtk3reactor.py 2012-02-16 02:35:00 +0000 +@@ -0,0 +1,60 @@ ++# Copyright (c) Twisted Matrix Laboratories. ++# See LICENSE for details. ++ ++""" ++This module provides support for Twisted to interact with the gtk3 mainloop ++via Gobject introspection. This is like gi, but slightly slower and requires a ++working $DISPLAY. ++ ++In order to use this support, simply do the following:: ++ ++ from twisted.internet import gtk3reactor ++ gtk3reactor.install() ++ ++Then use twisted.internet APIs as usual. ++""" ++ ++from twisted.internet import gireactor ++from twisted.python import runtime ++ ++ ++class Gtk3Reactor(gireactor.GIReactor): ++ """ ++ A reactor using the gtk3+ event loop. ++ """ ++ ++ def __init__(self): ++ """ ++ Override init to set the C{useGtk} flag. ++ """ ++ gireactor.GIReactor.__init__(self, useGtk=True) ++ ++ ++ ++class PortableGtk3Reactor(gireactor.PortableGIReactor): ++ """ ++ Portable GTK+ 3.x reactor. ++ """ ++ def __init__(self): ++ """ ++ Override init to set the C{useGtk} flag. ++ """ ++ gireactor.PortableGIReactor.__init__(self, useGtk=True) ++ ++ ++ ++def install(): ++ """ ++ Configure the Twisted mainloop to be run inside the gtk3+ mainloop. ++ """ ++ if runtime.platform.getType() == 'posix': ++ reactor = Gtk3Reactor() ++ else: ++ reactor = PortableGtk3Reactor() ++ ++ from twisted.internet.main import installReactor ++ installReactor(reactor) ++ return reactor ++ ++ ++__all__ = ['install'] + +=== modified file 'twisted/internet/test/reactormixins.py' +--- old/twisted/internet/test/reactormixins.py 2011-12-21 12:29:38 +0000 ++++ new/twisted/internet/test/reactormixins.py 2012-02-16 02:36:29 +0000 +@@ -56,20 +56,26 @@ class ReactorBuilder: + # it's not _really_ worth it to support on other platforms, + # since no one really wants to use it on other platforms. + _reactors.extend([ ++ "twisted.internet.gireactor.PortableGIReactor", ++ "twisted.internet.gtk3reactor.PortableGtk3Reactor", + "twisted.internet.gtk2reactor.PortableGtkReactor", + "twisted.internet.win32eventreactor.Win32Reactor", + "twisted.internet.iocpreactor.reactor.IOCPReactor"]) + else: + _reactors.extend([ ++ "twisted.internet.gireactor.GIReactor", ++ "twisted.internet.gtk3reactor.Gtk3Reactor", + "twisted.internet.glib2reactor.Glib2Reactor", +- "twisted.internet.gtk2reactor.Gtk2Reactor", +- "twisted.internet.kqreactor.KQueueReactor"]) ++ "twisted.internet.gtk2reactor.Gtk2Reactor"]) + if platform.isMacOSX(): + _reactors.append("twisted.internet.cfreactor.CFReactor") + else: + _reactors.extend([ + "twisted.internet.pollreactor.PollReactor", +- "twisted.internet.epollreactor.EPollReactor"]) ++ "twisted.internet.epollreactor.EPollReactor", ++ # Support KQueue on non-OS-X POSIX platforms for now. ++ "twisted.internet.kqreactor.KQueueReactor", ++ ]) + + reactorFactory = None + originalHandler = None + +=== modified file 'twisted/plugins/twisted_reactors.py' +--- old/twisted/plugins/twisted_reactors.py 2011-12-21 12:29:38 +0000 ++++ new/twisted/plugins/twisted_reactors.py 2012-02-16 02:35:28 +0000 +@@ -11,6 +11,10 @@ select = Reactor( + 'select', 'twisted.internet.selectreactor', 'select(2)-based reactor.') + wx = Reactor( + 'wx', 'twisted.internet.wxreactor', 'wxPython integration reactor.') ++gi = Reactor( ++ 'gi', 'twisted.internet.gireactor', 'GObject Introspection integration reactor.') ++gtk3 = Reactor( ++ 'gtk3', 'twisted.internet.gtk3reactor', 'Gtk3 integration reactor.') + gtk = Reactor( + 'gtk', 'twisted.internet.gtkreactor', 'Gtk1 integration reactor.') + gtk2 = Reactor( + diff -Nru twisted-11.1.0/debian/patches/01_posix_wakeups.patch twisted-11.1.0/debian/patches/01_posix_wakeups.patch --- twisted-11.1.0/debian/patches/01_posix_wakeups.patch 1970-01-01 00:00:00.000000000 +0000 +++ twisted-11.1.0/debian/patches/01_posix_wakeups.patch 2012-03-09 15:08:00.000000000 +0000 @@ -0,0 +1,114 @@ +=== modified file 'twisted/internet/posixbase.py' +--- old/twisted/internet/posixbase.py 2011-10-16 19:13:26 +0000 ++++ new/twisted/internet/posixbase.py 2011-12-08 03:37:41 +0000 +@@ -265,6 +265,11 @@ class PosixReactorBase(_SignalReactorMix + self.removeWriter(selectable) + selectable.connectionLost(failure.Failure(why)) + ++ ++ # Callable that creates a waker, overrideable so that subclasses can ++ # substitute their own implementation: ++ _wakerFactory = _Waker ++ + def installWaker(self): + """ + Install a `waker' to allow threads and signals to wake up the IO thread. +@@ -273,7 +278,7 @@ class PosixReactorBase(_SignalReactorMix + the reactor. On Windows we use a pair of sockets. + """ + if not self.waker: +- self.waker = _Waker(self) ++ self.waker = self._wakerFactory(self) + self._internalReaders.add(self.waker) + self.addReader(self.waker) + + +=== modified file 'twisted/internet/test/test_threads.py' +--- old/twisted/internet/test/test_threads.py 2011-06-13 22:20:22 +0000 ++++ new/twisted/internet/test/test_threads.py 2011-12-08 03:37:41 +0000 +@@ -8,7 +8,7 @@ Tests for implementations of L{IReactorT + __metaclass__ = type + + from weakref import ref +-import gc ++import gc, threading + + from twisted.python.threadable import isInIOThread + from twisted.internet.test.reactormixins import ReactorBuilder +@@ -104,6 +104,24 @@ class ThreadTestsBuilder(ReactorBuilder) + self.assertTrue(after - before < 30) + + ++ def test_callFromThread(self): ++ """ ++ A function scheduled with L{IReactorThreads.callFromThread} invoked ++ from another thread is run in the reactor thread. ++ """ ++ reactor = self.buildReactor() ++ result = [] ++ ++ def threadCall(): ++ result.append(threading.currentThread()) ++ reactor.stop() ++ reactor.callLater(0, reactor.callInThread, ++ reactor.callFromThread, threadCall) ++ self.runReactor(reactor, 5) ++ ++ self.assertEquals(result, [threading.currentThread()]) ++ ++ + def test_stopThreadPool(self): + """ + When the reactor stops, L{ReactorBase._stopThreadPool} drops the + +=== modified file 'twisted/internet/test/test_time.py' +--- old/twisted/internet/test/test_time.py 2011-02-14 04:45:15 +0000 ++++ new/twisted/internet/test/test_time.py 2011-12-08 03:37:41 +0000 +@@ -7,6 +7,7 @@ Tests for implementations of L{IReactorT + + __metaclass__ = type + ++from twisted.python.runtime import platform + from twisted.internet.test.reactormixins import ReactorBuilder + + +@@ -23,4 +24,38 @@ class TimeTestsBuilder(ReactorBuilder): + reactor.run() + + ++ ++class GlibTimeTestsBuilder(ReactorBuilder): ++ """ ++ Builder for defining tests relating to L{IReactorTime} for reactors based ++ off glib. ++ """ ++ if platform.isWindows(): ++ _reactors = ["twisted.internet.gtk2reactor.PortableGtkReactor"] ++ else: ++ _reactors = ["twisted.internet.glib2reactor.Glib2Reactor", ++ "twisted.internet.gtk2reactor.Gtk2Reactor"] ++ ++ def test_timeout_add(self): ++ """ ++ A C{reactor.callLater} call scheduled from a C{gobject.timeout_add} ++ call is run on time. ++ """ ++ import gobject ++ reactor = self.buildReactor() ++ ++ result = [] ++ def gschedule(): ++ reactor.callLater(0, callback) ++ return 0 ++ def callback(): ++ result.append(True) ++ reactor.stop() ++ ++ reactor.callWhenRunning(gobject.timeout_add, 10, gschedule) ++ self.runReactor(reactor, 5) ++ self.assertEqual(result, [True]) ++ ++ + globals().update(TimeTestsBuilder.makeTestCaseClasses()) ++globals().update(GlibTimeTestsBuilder.makeTestCaseClasses()) + diff -Nru twisted-11.1.0/debian/patches/series twisted-11.1.0/debian/patches/series --- twisted-11.1.0/debian/patches/series 2011-02-24 03:51:45.000000000 +0000 +++ twisted-11.1.0/debian/patches/series 2012-03-09 15:08:00.000000000 +0000 @@ -1 +1,3 @@ +00_gi_gtk3reactor.patch +01_posix_wakeups.patch tap2deb.diff