| Viewing file:  gireactor.py (5.98 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
# 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()
 
 If you wish to use a GApplication, register it with the reactor::
 
 from twisted.internet import reactor
 reactor.registerGApplication(app)
 
 Then use twisted.internet APIs as usual.
 
 On Python 3, pygobject v3.4 or later is required.
 """
 
 from __future__ import division, absolute_import
 
 from twisted.python.compat import _PY3
 from twisted.internet.error import ReactorAlreadyRunning
 from twisted.internet import _glibbase
 from twisted.python import runtime
 
 if _PY3:
 # We require a sufficiently new version of pygobject, so always exists:
 _pygtkcompatPresent = True
 else:
 # We can't just try to import gi.pygtkcompat, because that would import
 # gi, and the goal here is to not import gi in cases where that would
 # cause segfault.
 from twisted.python.modules import theSystemPath
 _pygtkcompatPresent = True
 try:
 theSystemPath["gi.pygtkcompat"]
 except KeyError:
 _pygtkcompatPresent = False
 
 
 # Modules that we want to ensure aren't imported if we're on older versions of
 # GI:
 _PYGTK_MODULES = ['gobject', 'glib', 'gio', 'gtk']
 
 def _oldGiInit():
 """
 Make sure pygtk and gi aren't loaded at the same time, and import Glib if
 possible.
 """
 # We can't immediately prevent imports, because that confuses some buggy
 # code in gi:
 _glibbase.ensureNotImported(
 _PYGTK_MODULES,
 "Introspected and static glib/gtk bindings must not be mixed; can't "
 "import gireactor since pygtk2 module is already imported.")
 
 global GLib
 from gi.repository import GLib
 if getattr(GLib, "threads_init", None) is not None:
 GLib.threads_init()
 
 _glibbase.ensureNotImported([], "",
 preventImports=_PYGTK_MODULES)
 
 
 if not _pygtkcompatPresent:
 # Older versions of gi don't have compatibility layer, so just enforce no
 # imports of pygtk and gi at same time:
 _oldGiInit()
 else:
 # Newer version of gi, so we can try to initialize compatibility layer; if
 # real pygtk was already imported we'll get ImportError at this point
 # rather than segfault, so unconditional import is fine.
 import gi.pygtkcompat
 gi.pygtkcompat.enable()
 # At this point importing gobject will get you gi version, and importing
 # e.g. gtk will either fail in non-segfaulty way or use gi version if user
 # does gi.pygtkcompat.enable_gtk(). So, no need to prevent imports of
 # old school pygtk modules.
 from gi.repository import GLib
 if getattr(GLib, "threads_init", None) is not None:
 GLib.threads_init()
 
 
 
 class GIReactor(_glibbase.GlibReactorBase):
 """
 GObject-introspection event loop reactor.
 
 @ivar _gapplication: A C{Gio.Application} instance that was registered
 with C{registerGApplication}.
 """
 _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
 
 # By default no Application is registered:
 _gapplication = None
 
 
 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)
 
 
 def registerGApplication(self, app):
 """
 Register a C{Gio.Application} or C{Gtk.Application}, whose main loop
 will be used instead of the default one.
 
 We will C{hold} the application so it doesn't exit on its own. In
 versions of C{python-gi} 3.2 and later, we exit the event loop using
 the C{app.quit} method which overrides any holds. Older versions are
 not supported.
 """
 if self._gapplication is not None:
 raise RuntimeError(
 "Can't register more than one application instance.")
 if self._started:
 raise ReactorAlreadyRunning(
 "Can't register application after reactor was started.")
 if not hasattr(app, "quit"):
 raise RuntimeError("Application registration is not supported in"
 " versions of PyGObject prior to 3.2.")
 self._gapplication = app
 def run():
 app.hold()
 app.run(None)
 self._run = run
 
 self._crash = app.quit
 
 
 
 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 registerGApplication(self, app):
 """
 Register a C{Gio.Application} or C{Gtk.Application}, whose main loop
 will be used instead of the default one.
 """
 raise NotImplementedError("GApplication is not currently supported on Windows.")
 
 
 
 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']
 
 |