~hudson-openstack/nova/trunk

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/internet/gtkreactor.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-2009 Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
"""
 
5
This module provides support for Twisted to interact with the PyGTK mainloop.
 
6
 
 
7
In order to use this support, simply do the following::
 
8
 
 
9
    |  from twisted.internet import gtkreactor
 
10
    |  gtkreactor.install()
 
11
 
 
12
Then use twisted.internet APIs as usual.  The other methods here are not
 
13
intended to be called directly.
 
14
"""
 
15
 
 
16
import sys
 
17
 
 
18
# System Imports
 
19
try:
 
20
    import pygtk
 
21
    pygtk.require('1.2')
 
22
except ImportError, AttributeError:
 
23
    pass # maybe we're using pygtk before this hack existed.
 
24
import gtk
 
25
 
 
26
from zope.interface import implements
 
27
 
 
28
# Twisted Imports
 
29
from twisted.python import log, runtime
 
30
from twisted.internet.interfaces import IReactorFDSet
 
31
 
 
32
# Sibling Imports
 
33
from twisted.internet import posixbase, selectreactor
 
34
 
 
35
 
 
36
class GtkReactor(posixbase.PosixReactorBase):
 
37
    """
 
38
    GTK+ event loop reactor.
 
39
 
 
40
    @ivar _reads: A dictionary mapping L{FileDescriptor} instances to gtk INPUT_READ
 
41
        watch handles.
 
42
 
 
43
    @ivar _writes: A dictionary mapping L{FileDescriptor} instances to gtk
 
44
        INTPUT_WRITE watch handles.
 
45
 
 
46
    @ivar _simtag: A gtk timeout handle for the next L{simulate} call.
 
47
    """
 
48
    implements(IReactorFDSet)
 
49
 
 
50
    def __init__(self):
 
51
        """
 
52
        Initialize the file descriptor tracking dictionaries and the base
 
53
        class.
 
54
        """
 
55
        self._simtag = None
 
56
        self._reads = {}
 
57
        self._writes = {}
 
58
        posixbase.PosixReactorBase.__init__(self)
 
59
 
 
60
 
 
61
    def addReader(self, reader):
 
62
        if reader not in self._reads:
 
63
            self._reads[reader] = gtk.input_add(reader, gtk.GDK.INPUT_READ, self.callback)
 
64
 
 
65
    def addWriter(self, writer):
 
66
        if writer not in self._writes:
 
67
            self._writes[writer] = gtk.input_add(writer, gtk.GDK.INPUT_WRITE, self.callback)
 
68
 
 
69
 
 
70
    def getReaders(self):
 
71
        return self._reads.keys()
 
72
 
 
73
 
 
74
    def getWriters(self):
 
75
        return self._writes.keys()
 
76
 
 
77
 
 
78
    def removeAll(self):
 
79
        return self._removeAll(self._reads, self._writes)
 
80
 
 
81
 
 
82
    def removeReader(self, reader):
 
83
        if reader in self._reads:
 
84
            gtk.input_remove(self._reads[reader])
 
85
            del self._reads[reader]
 
86
 
 
87
    def removeWriter(self, writer):
 
88
        if writer in self._writes:
 
89
            gtk.input_remove(self._writes[writer])
 
90
            del self._writes[writer]
 
91
 
 
92
    doIterationTimer = None
 
93
 
 
94
    def doIterationTimeout(self, *args):
 
95
        self.doIterationTimer = None
 
96
        return 0 # auto-remove
 
97
    def doIteration(self, delay):
 
98
        # flush some pending events, return if there was something to do
 
99
        # don't use the usual "while gtk.events_pending(): mainiteration()"
 
100
        # idiom because lots of IO (in particular test_tcp's
 
101
        # ProperlyCloseFilesTestCase) can keep us from ever exiting.
 
102
        log.msg(channel='system', event='iteration', reactor=self)
 
103
        if gtk.events_pending():
 
104
            gtk.mainiteration(0)
 
105
            return
 
106
        # nothing to do, must delay
 
107
        if delay == 0:
 
108
            return # shouldn't delay, so just return
 
109
        self.doIterationTimer = gtk.timeout_add(int(delay * 1000),
 
110
                                                self.doIterationTimeout)
 
111
        # This will either wake up from IO or from a timeout.
 
112
        gtk.mainiteration(1) # block
 
113
        # note: with the .simulate timer below, delays > 0.1 will always be
 
114
        # woken up by the .simulate timer
 
115
        if self.doIterationTimer:
 
116
            # if woken by IO, need to cancel the timer
 
117
            gtk.timeout_remove(self.doIterationTimer)
 
118
            self.doIterationTimer = None
 
119
 
 
120
    def crash(self):
 
121
        posixbase.PosixReactorBase.crash(self)
 
122
        gtk.mainquit()
 
123
 
 
124
    def run(self, installSignalHandlers=1):
 
125
        self.startRunning(installSignalHandlers=installSignalHandlers)
 
126
        gtk.timeout_add(0, self.simulate)
 
127
        gtk.mainloop()
 
128
 
 
129
    def _readAndWrite(self, source, condition):
 
130
        # note: gtk-1.2's gtk_input_add presents an API in terms of gdk
 
131
        # constants like INPUT_READ and INPUT_WRITE. Internally, it will add
 
132
        # POLL_HUP and POLL_ERR to the poll() events, but if they happen it
 
133
        # will turn them back into INPUT_READ and INPUT_WRITE. gdkevents.c
 
134
        # maps IN/HUP/ERR to INPUT_READ, and OUT/ERR to INPUT_WRITE. This
 
135
        # means there is no immediate way to detect a disconnected socket.
 
136
 
 
137
        # The g_io_add_watch() API is more suited to this task. I don't think
 
138
        # pygtk exposes it, though.
 
139
        why = None
 
140
        didRead = None
 
141
        try:
 
142
            if condition & gtk.GDK.INPUT_READ:
 
143
                why = source.doRead()
 
144
                didRead = source.doRead
 
145
            if not why and condition & gtk.GDK.INPUT_WRITE:
 
146
                # if doRead caused connectionLost, don't call doWrite
 
147
                # if doRead is doWrite, don't call it again.
 
148
                if not source.disconnected and source.doWrite != didRead:
 
149
                    why = source.doWrite()
 
150
                    didRead = source.doWrite # if failed it was in write
 
151
        except:
 
152
            why = sys.exc_info()[1]
 
153
            log.msg('Error In %s' % source)
 
154
            log.deferr()
 
155
 
 
156
        if why:
 
157
            self._disconnectSelectable(source, why, didRead == source.doRead)
 
158
 
 
159
    def callback(self, source, condition):
 
160
        log.callWithLogger(source, self._readAndWrite, source, condition)
 
161
        self.simulate() # fire Twisted timers
 
162
        return 1 # 1=don't auto-remove the source
 
163
 
 
164
    def simulate(self):
 
165
        """Run simulation loops and reschedule callbacks.
 
166
        """
 
167
        if self._simtag is not None:
 
168
            gtk.timeout_remove(self._simtag)
 
169
        self.runUntilCurrent()
 
170
        timeout = min(self.timeout(), 0.1)
 
171
        if timeout is None:
 
172
            timeout = 0.1
 
173
        # Quoth someone other than me, "grumble", yet I know not why. Try to be
 
174
        # more specific in your complaints, guys. -exarkun
 
175
        self._simtag = gtk.timeout_add(int(timeout * 1010), self.simulate)
 
176
 
 
177
 
 
178
 
 
179
class PortableGtkReactor(selectreactor.SelectReactor):
 
180
    """Reactor that works on Windows.
 
181
 
 
182
    input_add is not supported on GTK+ for Win32, apparently.
 
183
 
 
184
    @ivar _simtag: A gtk timeout handle for the next L{simulate} call.
 
185
    """
 
186
    _simtag = None
 
187
 
 
188
 
 
189
    def crash(self):
 
190
        selectreactor.SelectReactor.crash(self)
 
191
        gtk.mainquit()
 
192
 
 
193
    def run(self, installSignalHandlers=1):
 
194
        self.startRunning(installSignalHandlers=installSignalHandlers)
 
195
        self.simulate()
 
196
        gtk.mainloop()
 
197
 
 
198
    def simulate(self):
 
199
        """Run simulation loops and reschedule callbacks.
 
200
        """
 
201
        if self._simtag is not None:
 
202
            gtk.timeout_remove(self._simtag)
 
203
        self.iterate()
 
204
        timeout = min(self.timeout(), 0.1)
 
205
        if timeout is None:
 
206
            timeout = 0.1
 
207
 
 
208
        # See comment for identical line in GtkReactor.simulate.
 
209
        self._simtag = gtk.timeout_add((timeout * 1010), self.simulate)
 
210
 
 
211
 
 
212
 
 
213
def install():
 
214
    """Configure the twisted mainloop to be run inside the gtk mainloop.
 
215
    """
 
216
    reactor = GtkReactor()
 
217
    from twisted.internet.main import installReactor
 
218
    installReactor(reactor)
 
219
    return reactor
 
220
 
 
221
def portableInstall():
 
222
    """Configure the twisted mainloop to be run inside the gtk mainloop.
 
223
    """
 
224
    reactor = PortableGtkReactor()
 
225
    from twisted.internet.main import installReactor
 
226
    installReactor(reactor)
 
227
    return reactor
 
228
 
 
229
if runtime.platform.getType() != 'posix':
 
230
    install = portableInstall
 
231
 
 
232
__all__ = ['install']