diff --git a/terminatorlib/container.py b/terminatorlib/container.py index e9be2d92..a0914bfd 100755 --- a/terminatorlib/container.py +++ b/terminatorlib/container.py @@ -10,6 +10,7 @@ from factory import Factory from config import Config from util import dbg, err from translation import _ +from signalman import Signalman # pylint: disable-msg=R0921 class Container(object): @@ -20,13 +21,13 @@ class Container(object): children = None config = None signals = None - cnxids = None + signalman = None def __init__(self): """Class initialiser""" self.children = [] self.signals = [] - self.cnxids = {} + self.cnxids = Signalman() self.config = Config() def register_signals(self, widget): @@ -49,28 +50,14 @@ class Container(object): err('Container:: registering signal for %s on %s failed' % (signal['name'], widget)) - def connect_child(self, widget, signal, handler, data=None): + def connect_child(self, widget, signal, handler, *args): """Register the requested signal and record its connection ID""" - if not self.cnxids.has_key(widget): - self.cnxids[widget] = [] - - if data is not None: - self.cnxids[widget].append(widget.connect(signal, handler, data)) - dbg('Container::connect_child: connecting %s(%s) for %s::%s' % - (handler.__name__, data, widget.__class__.__name__, signal)) - else: - self.cnxids[widget].append(widget.connect(signal, handler)) - dbg('Container::connect_child: registering %s to handle %s::%s' % - (handler.__name__, widget.__class__.__name__, signal)) + self.cnxids.new(widget, signal, handler, *args) + return def disconnect_child(self, widget): """De-register the signals for a child""" - if self.cnxids.has_key(widget): - for cnxid in self.cnxids[widget]: - dbg('Container::disconnect_child: removing handler on %s' % - type(widget)) - widget.disconnect(cnxid) - del(self.cnxids[widget]) + self.cnxids.remove_widget(widget) def get_offspring(self): """Return a list of child widgets, if any""" diff --git a/terminatorlib/paned.py b/terminatorlib/paned.py index cbc5c1c4..914acec2 100755 --- a/terminatorlib/paned.py +++ b/terminatorlib/paned.py @@ -37,8 +37,7 @@ class Paned(Container): dbg("Paned::set_initial_position: Setting position to: %d" % position) self.set_position(position) - self.disconnect(self.cnxids['init']) - del(self.cnxids['init']) + self.cnxids.remove_signal(self, 'expose-event') # pylint: disable-msg=W0613 def split_axis(self, widget, vertical=True, sibling=None): @@ -78,7 +77,6 @@ class Paned(Container): else: raise ValueError('Paned widgets can only have two children') - self.cnxids[widget] = [] if maker.isinstance(widget, 'Terminal'): top_window = get_top_window(self) @@ -92,8 +90,7 @@ class Paned(Container): for signal in signals: self.connect_child(widget, signal, signals[signal]) - self.connect_child(widget, 'maximise', top_window.zoom, - False) + self.connect_child(widget, 'maximise', top_window.zoom, False) widget.grab_focus() @@ -176,8 +173,7 @@ class HPaned(Paned, gtk.HPaned): Paned.__init__(self) gtk.HPaned.__init__(self) self.register_signals(HPaned) - self.cnxids['init'] = self.connect('expose-event', - self.set_initial_position) + self.cnxids.new(self, 'expose-event', self.set_initial_position) class VPaned(Paned, gtk.VPaned): """Merge gtk.VPaned into our base Paned Container""" @@ -186,8 +182,7 @@ class VPaned(Paned, gtk.VPaned): Paned.__init__(self) gtk.VPaned.__init__(self) self.register_signals(VPaned) - self.cnxids['init'] = self.connect('expose-event', - self.set_initial_position) + self.cnxids.new(self, 'expose-event', self.set_initial_position) gobject.type_register(HPaned) gobject.type_register(VPaned) diff --git a/terminatorlib/signalman.py b/terminatorlib/signalman.py new file mode 100755 index 00000000..70de7d2a --- /dev/null +++ b/terminatorlib/signalman.py @@ -0,0 +1,54 @@ +#!/usr/bin/python +# Terminator by Chris Jones +# GPL v2 only +"""signalman.py - class providing a glib signal tracker""" + +from util import dbg, err + +class Signalman(object): + """Class providing glib signal tracking and management""" + + cnxids = None + + def __init__(self): + """Class initialiser""" + self.cnxids = {} + + def __del__(self): + """Class destructor""" + if len(self.cnxids.keys()) > 0: + err('Signals remain. This is likely a bug: %s' % self.cnxids) + + def new(self, widget, signal, handler, *args): + """Register a new signal on a widget""" + if not self.cnxids.has_key(widget): + dbg('creating new bucket for %s' % type(widget)) + self.cnxids[widget] = {} + + if self.cnxids[widget].has_key(signal): + err('%s already has a handler for %s' % (id(widget), signal)) + + self.cnxids[widget][signal] = widget.connect(signal, handler, *args) + dbg('connected %s::%s to %s' % (type(widget), signal, handler)) + + def remove_signal(self, widget, signal): + """Remove a signal handler""" + if not self.cnxids[widget].has_key(signal): + err('%s not registered for %s' % (signal, type(widget))) + return + dbg('removing %s::%s' % (type(widget), signal)) + widget.disconnect(self.cnxids[widget][signal]) + del(self.cnxids[widget][signal]) + if len(self.cnxids[widget].keys()) == 0: + dbg('no more signals for widget') + del(self.cnxids[widget]) + + def remove_widget(self, widget): + """Remove all signal handlers for a widget""" + if not self.cnxids.has_key(widget): + dbg('%s not registered' % widget) + return + signals = self.cnxids[widget].keys() + for signal in signals: + self.remove_signal(widget, signal) + diff --git a/terminatorlib/terminal.py b/terminatorlib/terminal.py index 18b3bc12..8ae2b018 100755 --- a/terminatorlib/terminal.py +++ b/terminatorlib/terminal.py @@ -97,6 +97,7 @@ class Terminal(gtk.VBox): self.connect('focus-in', self.terminator.focus_changed) self.matches = {} + # FIXME: Port cnxids to using Signalman self.cnxids = {} self.config = Config() diff --git a/terminatorlib/tests/test_doctests.py b/terminatorlib/tests/test_doctests.py index fd964210..ff5165c4 100644 --- a/terminatorlib/tests/test_doctests.py +++ b/terminatorlib/tests/test_doctests.py @@ -11,6 +11,7 @@ def test_suite(): 'cwd', 'factory', 'util', + 'testsignalman', ): suite.addTest(DocTestSuite('terminatorlib.' + name)) return suite diff --git a/terminatorlib/testsignalman.py b/terminatorlib/testsignalman.py new file mode 100755 index 00000000..8aa6971e --- /dev/null +++ b/terminatorlib/testsignalman.py @@ -0,0 +1,56 @@ +#!/usr/bin/python +# Terminator by Chris Jones +# GPL v2 only +"""testsignalman.py - Test the signalman class + +>>> widget = TestWidget() +>>> signalman = Signalman() +>>> signalman.new(widget, 'test1', handler) +>>> signalman.cnxids[widget].keys() +['test1'] +>>> widget.signals.values() +['test1'] +>>> signalman.remove_widget(widget) +>>> signalman.cnxids.has_key(widget) +False +>>> widget.signals.values() +[] +>>> signalman.new(widget, 'test2', handler) +>>> signalman.new(widget, 'test3', handler) +>>> signalman.remove_signal(widget, 'test2') +>>> signalman.cnxids[widget].keys() +['test3'] +>>> widget.signals.values() +['test3'] +>>> signalman.remove_widget(widget) +>>> + +""" + +from signalman import Signalman + +class TestWidget(): + signals = None + count = None + + def __init__(self): + self.signals = {} + self.count = 0 + + def connect(self, signal, handler, *args): + self.count = self.count + 1 + self.signals[self.count] = signal + return(self.count) + + def disconnect(self, signalid): + del(self.signals[signalid]) + +def handler(): + print "I am a test handler" + +if __name__ == '__main__': + import sys + import doctest + (failed, attempted) = doctest.testmod() + print "%d/%d tests failed" % (failed, attempted) + sys.exit(failed)