1
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2
# See LICENSE for details.
6
A modified gtk2 reactor with a Glade dialog in-process that allows you to stop,
7
suspend, resume and inspect transports interactively.
13
from twisted.python import log, threadable, runtime, failure, util, reflect
14
from twisted.internet.gtk2reactor import Gtk2Reactor as sup
20
COLUMN_DESCRIPTION = 0
26
class GladeReactor(sup):
27
"""GTK+-2 event loop reactor with GUI.
30
def listenTCP(self, port, factory, backlog=50, interface=''):
31
from _inspectro import LoggingFactory
32
factory = LoggingFactory(factory)
33
return sup.listenTCP(self, port, factory, backlog, interface)
35
def connectTCP(self, host, port, factory, timeout=30, bindAddress=None):
36
from _inspectro import LoggingFactory
37
factory = LoggingFactory(factory)
38
return sup.connectTCP(self, host, port, factory, timeout, bindAddress)
40
def listenSSL(self, port, factory, contextFactory, backlog=50, interface=''):
41
from _inspectro import LoggingFactory
42
factory = LoggingFactory(factory)
43
return sup.listenSSL(self, port, factory, contextFactory, backlog, interface)
45
def connectSSL(self, host, port, factory, contextFactory, timeout=30, bindAddress=None):
46
from _inspectro import LoggingFactory
47
factory = LoggingFactory(factory)
48
return sup.connectSSL(self, host, port, factory, contextFactory, timeout, bindAddress)
50
def connectUNIX(self, address, factory, timeout=30):
51
from _inspectro import LoggingFactory
52
factory = LoggingFactory(factory)
53
return sup.connectUNIX(self, address, factory, timeout)
55
def listenUNIX(self, address, factory, backlog=50, mode=0666):
56
from _inspectro import LoggingFactory
57
factory = LoggingFactory(factory)
58
return sup.listenUNIX(self, address, factory, backlog, mode)
60
def on_disconnect_clicked(self, w):
61
store, iter = self.servers.get_selection().get_selected()
62
store[iter][COLUMN_TRANSPORT].loseConnection()
64
def on_viewlog_clicked(self, w):
65
store, iter = self.servers.get_selection().get_selected()
67
from _inspectro import LogViewer
68
if hasattr(data, "protocol") and not data.protocol.logViewer:
69
LogViewer(data.protocol)
71
def on_inspect_clicked(self, w):
72
store, iter = self.servers.get_selection().get_selected()
74
from _inspectro import Inspectro
77
def on_suspend_clicked(self, w):
78
store, iter = self.servers.get_selection().get_selected()
80
sup.removeReader(self, data[1])
81
sup.removeWriter(self, data[1])
82
if data[COLUMN_DESCRIPTION].endswith('(suspended)'):
83
if data[COLUMN_READING]:
84
sup.addReader(self, data[COLUMN_TRANSPORT])
85
if data[COLUMN_WRITING]:
86
sup.addWriter(self, data[COLUMN_TRANSPORT])
87
data[COLUMN_DESCRIPTION] = str(data[COLUMN_TRANSPORT])
88
self.toggle_suspend(1)
90
data[0] += ' (suspended)'
91
self.toggle_suspend(0)
93
def toggle_suspend(self, suspending=0):
94
stock, nonstock = [('gtk-redo', 'Resume'),
95
('gtk-undo', 'Suspend')][suspending]
96
b = self.xml.get_widget("suspend")
99
b.get_child().get_child().get_children()[1].set_label(nonstock)
101
def servers_selection_changed(self, w):
102
store, iter = w.get_selected()
104
self.xml.get_widget("suspend").set_sensitive(0)
105
self.xml.get_widget('disconnect').set_sensitive(0)
108
self.toggle_suspend(not
109
data[COLUMN_DESCRIPTION].endswith('(suspended)'))
110
self.xml.get_widget("suspend").set_sensitive(1)
111
self.xml.get_widget('disconnect').set_sensitive(1)
113
def on_quit_clicked(self, w):
117
self.xml = gtk.glade.XML(util.sibpath(__file__,"gladereactor.glade"))
119
for m in reflect.prefixedMethods(self, "on_"):
120
d[m.im_func.__name__] = m
121
self.xml.signal_autoconnect(d)
122
self.xml.get_widget('window1').connect('destroy',
123
lambda w: self.stop())
124
self.servers = self.xml.get_widget("servertree")
125
sel = self.servers.get_selection()
126
sel.set_mode(gtk.SELECTION_SINGLE)
127
sel.connect("changed",
128
self.servers_selection_changed)
129
## argh coredump: self.servers_selection_changed(sel)
130
self.xml.get_widget('suspend').set_sensitive(0)
131
self.xml.get_widget('disconnect').set_sensitive(0)
132
# setup model, connect it to my treeview
133
self.model = gtk.ListStore(str, object, gobject.TYPE_BOOLEAN,
134
gobject.TYPE_BOOLEAN)
135
self.servers.set_model(self.model)
136
self.servers.set_reorderable(1)
137
self.servers.set_headers_clickable(1)
138
# self.servers.set_headers_draggable(1)
141
gtk.TreeViewColumn('Server',
142
gtk.CellRendererText(),
144
gtk.TreeViewColumn('Reading',
145
gtk.CellRendererToggle(),
147
gtk.TreeViewColumn('Writing',
148
gtk.CellRendererToggle(),
151
self.servers.append_column(col)
155
def addReader(self, reader):
156
sup.addReader(self, reader)
157
## gtk docs suggest this - but it's stupid
158
## self.model.set(self.model.append(),
161
self._maybeAddServer(reader, read=1)
163
def _goAway(self,reader):
164
for p in range(len(self.model)):
165
if self.model[p][1] == reader:
166
self.model.remove(self.model.get_iter_from_string(str(p)))
170
def _maybeAddServer(self, reader, read=0, write=0):
181
if not (x[2] or x[3]):
182
x[0] = x[0] + '(disconnected)'
183
self.callLater(5, self._goAway, reader)
188
write = max(write, 0)
190
self.model.append((reader,reader,read,write))
192
def addWriter(self, writer):
193
sup.addWriter(self, writer)
194
self._maybeAddServer(writer, write=1)
196
def removeReader(self, reader):
197
sup.removeReader(self, reader)
198
self._maybeAddServer(reader, read=-1)
200
def removeWriter(self, writer):
201
sup.removeWriter(self, writer)
202
self._maybeAddServer(writer, write=-1)
207
def run(self, installSignalHandlers=1):
208
self.startRunning(installSignalHandlers=installSignalHandlers)
214
"""Configure the twisted mainloop to be run inside the gtk mainloop.
216
reactor = GladeReactor()
217
from twisted.internet.main import installReactor
218
installReactor(reactor)