~hudson-openstack/nova/trunk

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/internet/wxreactor.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2001-2006 Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
"""
 
5
This module provides wxPython event loop support for Twisted.
 
6
 
 
7
In order to use this support, simply do the following::
 
8
 
 
9
    |  from twisted.internet import wxreactor
 
10
    |  wxreactor.install()
 
11
 
 
12
Then, when your root wxApp has been created::
 
13
 
 
14
    | from twisted.internet import reactor
 
15
    | reactor.registerWxApp(yourApp)
 
16
    | reactor.run()
 
17
 
 
18
Then use twisted.internet APIs as usual. Stop the event loop using
 
19
reactor.stop(), not yourApp.ExitMainLoop().
 
20
 
 
21
IMPORTANT: tests will fail when run under this reactor. This is
 
22
expected and probably does not reflect on the reactor's ability to run
 
23
real applications.
 
24
 
 
25
Maintainer: Itamar Shtull-Trauring
 
26
"""
 
27
 
 
28
import Queue
 
29
try:
 
30
    from wx import PySimpleApp as wxPySimpleApp, CallAfter as wxCallAfter, \
 
31
         Timer as wxTimer
 
32
except ImportError:
 
33
    # older version of wxPython:
 
34
    from wxPython.wx import wxPySimpleApp, wxCallAfter, wxTimer
 
35
 
 
36
from twisted.python import log, runtime
 
37
from twisted.internet import _threadedselect
 
38
 
 
39
 
 
40
class ProcessEventsTimer(wxTimer):
 
41
    """
 
42
    Timer that tells wx to process pending events.
 
43
 
 
44
    This is necessary on OS X, probably due to a bug in wx, if we want
 
45
    wxCallAfters to be handled when modal dialogs, menus, etc.  are open.
 
46
    """
 
47
    def __init__(self, wxapp):
 
48
        wxTimer.__init__(self)
 
49
        self.wxapp = wxapp
 
50
    
 
51
 
 
52
    def Notify(self):
 
53
        """
 
54
        Called repeatedly by wx event loop.
 
55
        """
 
56
        self.wxapp.ProcessPendingEvents()
 
57
 
 
58
 
 
59
 
 
60
class WxReactor(_threadedselect.ThreadedSelectReactor):
 
61
    """
 
62
    wxPython reactor.
 
63
 
 
64
    wxPython drives the event loop, select() runs in a thread.
 
65
    """
 
66
 
 
67
    _stopping = False
 
68
 
 
69
    def registerWxApp(self, wxapp):
 
70
        """
 
71
        Register wxApp instance with the reactor.
 
72
        """
 
73
        self.wxapp = wxapp
 
74
 
 
75
    def _installSignalHandlersAgain(self):
 
76
        """
 
77
        wx sometimes removes our own signal handlers, so re-add them.
 
78
        """
 
79
        try:
 
80
            # make _handleSignals happy:
 
81
            import signal
 
82
            signal.signal(signal.SIGINT, signal.default_int_handler)
 
83
        except ImportError:
 
84
            return
 
85
        self._handleSignals()
 
86
 
 
87
    def stop(self):
 
88
        """
 
89
        Stop the reactor.
 
90
        """
 
91
        if self._stopping:
 
92
            return
 
93
        self._stopping = True
 
94
        _threadedselect.ThreadedSelectReactor.stop(self)
 
95
 
 
96
    def _runInMainThread(self, f):
 
97
        """
 
98
        Schedule function to run in main wx/Twisted thread.
 
99
 
 
100
        Called by the select() thread.
 
101
        """
 
102
        if hasattr(self, "wxapp"):
 
103
            wxCallAfter(f)
 
104
        else:
 
105
            # wx shutdown but twisted hasn't
 
106
            self._postQueue.put(f)
 
107
 
 
108
    def _stopWx(self):
 
109
        """
 
110
        Stop the wx event loop if it hasn't already been stopped.
 
111
 
 
112
        Called during Twisted event loop shutdown.
 
113
        """
 
114
        if hasattr(self, "wxapp"):
 
115
            self.wxapp.ExitMainLoop()
 
116
 
 
117
    def run(self, installSignalHandlers=True):
 
118
        """
 
119
        Start the reactor.
 
120
        """
 
121
        self._postQueue = Queue.Queue()
 
122
        if not hasattr(self, "wxapp"):
 
123
            log.msg("registerWxApp() was not called on reactor, "
 
124
                    "registering my own wxApp instance.")
 
125
            self.registerWxApp(wxPySimpleApp())
 
126
 
 
127
        # start select() thread:
 
128
        self.interleave(self._runInMainThread,
 
129
                        installSignalHandlers=installSignalHandlers)
 
130
        if installSignalHandlers:
 
131
            self.callLater(0, self._installSignalHandlersAgain)
 
132
 
 
133
        # add cleanup events:
 
134
        self.addSystemEventTrigger("after", "shutdown", self._stopWx)
 
135
        self.addSystemEventTrigger("after", "shutdown",
 
136
                                   lambda: self._postQueue.put(None))
 
137
 
 
138
        # On Mac OS X, work around wx bug by starting timer to ensure
 
139
        # wxCallAfter calls are always processed. We don't wake up as
 
140
        # often as we could since that uses too much CPU.
 
141
        if runtime.platform.isMacOSX():
 
142
            t = ProcessEventsTimer(self.wxapp)
 
143
            t.Start(2) # wake up every 2ms
 
144
        
 
145
        self.wxapp.MainLoop()
 
146
        wxapp = self.wxapp
 
147
        del self.wxapp
 
148
 
 
149
        if not self._stopping:
 
150
            # wx event loop exited without reactor.stop() being
 
151
            # called.  At this point events from select() thread will
 
152
            # be added to _postQueue, but some may still be waiting
 
153
            # unprocessed in wx, thus the ProcessPendingEvents()
 
154
            # below.
 
155
            self.stop()
 
156
            wxapp.ProcessPendingEvents() # deal with any queued wxCallAfters
 
157
            while 1:
 
158
                try:
 
159
                    f = self._postQueue.get(timeout=0.01)
 
160
                except Queue.Empty:
 
161
                    continue
 
162
                else:
 
163
                    if f is None:
 
164
                        break
 
165
                    try:
 
166
                        f()
 
167
                    except:
 
168
                        log.err()
 
169
 
 
170
 
 
171
def install():
 
172
    """
 
173
    Configure the twisted mainloop to be run inside the wxPython mainloop.
 
174
    """
 
175
    reactor = WxReactor()
 
176
    from twisted.internet.main import installReactor
 
177
    installReactor(reactor)
 
178
    return reactor
 
179
 
 
180
 
 
181
__all__ = ['install']