From 9044ffabb0f146459dbf63dc00ea97b0a8d561d8 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 21 Jul 2010 23:17:34 +0100 Subject: [PATCH 1/3] Land a modified and extended patch from Andrea Corbellini that adds a dbus server and a new default behaviour to use the dbus server to make terminator processes singletons --- doc/terminator_config.5 | 4 ++ terminator | 15 +++++++ terminatorlib/config.py | 1 + terminatorlib/ipc.py | 71 +++++++++++++++++++++++++++++++++ terminatorlib/preferences.glade | 30 +++++++++++++- terminatorlib/prefseditor.py | 8 ++++ 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 terminatorlib/ipc.py diff --git a/doc/terminator_config.5 b/doc/terminator_config.5 index 07feaf1f..d01e96a3 100644 --- a/doc/terminator_config.5 +++ b/doc/terminator_config.5 @@ -32,6 +32,10 @@ Below are the individual sections that can exist in the config file: .SH "global_config" These are the options Terminator currently supports in the global_config section: .TP +.B dbus +Control whether or not Terminator will load its DBus server. When this server is loaded, running Terminator multiple times will cause the first Terminator process to open additional windows. If this configuration item is set to False, or the python dbus module is unavailable, running Terminator multiple times will run a separate Terminator process for each invocation. +Default value: \fBTrue\fR +.TP .B focus Control how focus is given to terminals. 'click' means the focus only moves to a terminal after you click in it. 'sloppy' means the focus will follow the mouse pointer. 'system' means the focus will match that used by a GNOME window manager. Default value: \fBclick\fR diff --git a/terminator b/terminator index ea153cca..db384948 100755 --- a/terminator +++ b/terminator @@ -50,6 +50,21 @@ if __name__ == '__main__': OPTIONS = terminatorlib.optionparse.parse_options() + # Attempt to import our dbus server. If one exists already we will just + # connect to that and ask for a new window. If not, we will create one and + # continue. Failure to import dbus, or the global config option "dbus" + # being False will cause us to continue without the dbus server and open a + # window. + try: + from terminatorlib import ipc + try: + ipc.DBusService() + except ipc.DBusException: + ipc.new_window() + sys.exit() + except ImportError: + pass + MAKER = Factory() TERMINATOR = Terminator() TERMINATOR.set_origcwd(ORIGCWD) diff --git a/terminatorlib/config.py b/terminatorlib/config.py index 61d964b9..4b888a96 100755 --- a/terminatorlib/config.py +++ b/terminatorlib/config.py @@ -76,6 +76,7 @@ except ImportError: DEFAULTS = { 'global_config': { + 'dbus' : True, 'focus' : 'click', 'handle_size' : -1, 'geometry_hinting' : True, diff --git a/terminatorlib/ipc.py b/terminatorlib/ipc.py new file mode 100644 index 00000000..d64bb6b5 --- /dev/null +++ b/terminatorlib/ipc.py @@ -0,0 +1,71 @@ +#!/usr/bin/python +# Terminator by Chris Jones +# GPL v2 only +"""ipc.py - DBus server and API calls""" + +import gtk +import dbus.service +from dbus.exceptions import DBusException +import dbus.glib +from borg import Borg +from terminator import Terminator +from config import Config + +CONFIG = Config() +if not CONFIG['dbus']: + # The config says we are not to load dbus, so pretend like we can't + raise ImportError + +BUS_BASE = 'net.tenshu.Terminator' +BUS_PATH = '/net/tenshu/Terminator' +try: + # Try and include the X11 display name in the dbus bus name + DISPLAY = gtk.gdk.get_display().replace(':', '').replace('.', '') + BUS_NAME = '%s%s' % (BUS_BASE, DISPLAY) +except: + BUS_NAME = BUS_BASE + +class DBusService(Borg, dbus.service.Object): + """DBus Server class. This is implemented as a Borg""" + bus_name = None + terminator = None + + def __init__(self): + """Class initialiser""" + self.prepare_attributes() + dbus.service.Object.__init__(self, self.bus_name, BUS_PATH) + + def prepare_attributes(self): + """Ensure we are populated""" + if not self.bus_name: + bus = dbus.SessionBus() + proxy = bus.get_object('org.freedesktop.DBus', + '/org/freedesktop/DBus') + flags = 1 | 4 # allow replacement | do not queue + if not proxy.RequestName(BUS_NAME, dbus.UInt32(flags)) in (1, 4): + raise dbus.exceptions.DBusException( + "Couldn't get DBus name %s: Name exists" % BUS_NAME) + self.bus_name = dbus.service.BusName(BUS_NAME, + bus=dbus.SessionBus()) + if not self.terminator: + self.terminator = Terminator() + + @dbus.service.method(BUS_NAME) + def new_window(self): + """Create a new Window""" + self.terminator.create_layout('default') + self.terminator.layout_done() + +def with_proxy(func): + """Decorator function to connect to the session dbus bus""" + def _exec(*args, **argd): + bus = dbus.SessionBus() + proxy = bus.get_object(BUS_NAME, BUS_PATH) + func(proxy, *args, **argd) + return _exec + +@with_proxy +def new_window(session): + """Call the dbus method to open a new window""" + session.new_window() + diff --git a/terminatorlib/preferences.glade b/terminatorlib/preferences.glade index 0f554010..b05f0a4e 100644 --- a/terminatorlib/preferences.glade +++ b/terminatorlib/preferences.glade @@ -298,7 +298,7 @@ True - 6 + 7 2 6 @@ -489,6 +489,34 @@ 20 + + + True + DBus server + + + 6 + 7 + + + + + True + True + False + True + True + + + + 1 + 2 + 6 + 7 + GTK_EXPAND + GTK_EXPAND + + 0 diff --git a/terminatorlib/prefseditor.py b/terminatorlib/prefseditor.py index c8edabda..03cf3465 100755 --- a/terminatorlib/prefseditor.py +++ b/terminatorlib/prefseditor.py @@ -215,6 +215,9 @@ class PrefsEditor: else: active = 0 widget.set_active(active) + # DBus Server + widget = guiget('dbuscheck') + widget.set_active(self.config['dbus']) ## Profile tab # Populate the profile list @@ -538,6 +541,11 @@ class PrefsEditor: self.config['geometry_hinting'] = widget.get_active() self.config.save() + def on_dbuscheck_toggled(self, widget): + """DBus server setting changed""" + self.config['dbus'] = widget.get_active() + self.config.save() + def on_winbordercheck_toggled(self, widget): """Window border setting changed""" self.config['borderless'] = not widget.get_active() From 93104c42a2db5793332adf2b4df9c888c3cbc006 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Thu, 22 Jul 2010 09:24:47 +0100 Subject: [PATCH 2/3] Add debugging and hash the X11 display (suggestion from Andrea) --- terminator | 2 ++ terminatorlib/ipc.py | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/terminator b/terminator index db384948..4b919a1e 100755 --- a/terminator +++ b/terminator @@ -60,9 +60,11 @@ if __name__ == '__main__': try: ipc.DBusService() except ipc.DBusException: + dbg('Unable to become master process, requesting a new window') ipc.new_window() sys.exit() except ImportError: + dbg('dbus not imported') pass MAKER = Factory() diff --git a/terminatorlib/ipc.py b/terminatorlib/ipc.py index d64bb6b5..cfec4dfa 100644 --- a/terminatorlib/ipc.py +++ b/terminatorlib/ipc.py @@ -10,17 +10,19 @@ import dbus.glib from borg import Borg from terminator import Terminator from config import Config +from util import dbg CONFIG = Config() if not CONFIG['dbus']: # The config says we are not to load dbus, so pretend like we can't + dbg('dbus disabled') raise ImportError BUS_BASE = 'net.tenshu.Terminator' BUS_PATH = '/net/tenshu/Terminator' try: # Try and include the X11 display name in the dbus bus name - DISPLAY = gtk.gdk.get_display().replace(':', '').replace('.', '') + DISPLAY = hex(hash(gtk.gdk.get_display())).replace('-', '_') BUS_NAME = '%s%s' % (BUS_BASE, DISPLAY) except: BUS_NAME = BUS_BASE @@ -32,17 +34,20 @@ class DBusService(Borg, dbus.service.Object): def __init__(self): """Class initialiser""" + Borg.__init__(self, self.__class__.__name__) self.prepare_attributes() dbus.service.Object.__init__(self, self.bus_name, BUS_PATH) def prepare_attributes(self): """Ensure we are populated""" if not self.bus_name: + dbg('Checking for bus name availability: %s' % BUS_NAME) bus = dbus.SessionBus() proxy = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus') flags = 1 | 4 # allow replacement | do not queue if not proxy.RequestName(BUS_NAME, dbus.UInt32(flags)) in (1, 4): + dbg('bus name unavailable: %s' % BUS_NAME) raise dbus.exceptions.DBusException( "Couldn't get DBus name %s: Name exists" % BUS_NAME) self.bus_name = dbus.service.BusName(BUS_NAME, @@ -53,11 +58,13 @@ class DBusService(Borg, dbus.service.Object): @dbus.service.method(BUS_NAME) def new_window(self): """Create a new Window""" + dbg('dbus method called') self.terminator.create_layout('default') self.terminator.layout_done() def with_proxy(func): """Decorator function to connect to the session dbus bus""" + dbg('dbus client call: %s' % func.func_name) def _exec(*args, **argd): bus = dbus.SessionBus() proxy = bus.get_object(BUS_NAME, BUS_PATH) From f20b437cafba8930ed8c0b72a0898a89fcd3db44 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Thu, 22 Jul 2010 13:59:06 +0100 Subject: [PATCH 3/3] Allow disabling of dbus from the command line, and make use of that when spawning a new terminator process --- terminator | 3 +++ terminatorlib/optionparse.py | 2 ++ terminatorlib/terminal.py | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/terminator b/terminator index 4b919a1e..5c344aca 100755 --- a/terminator +++ b/terminator @@ -56,6 +56,9 @@ if __name__ == '__main__': # being False will cause us to continue without the dbus server and open a # window. try: + if OPTIONS.nodbus: + dbg('dbus disabled by command line') + raise ImportError from terminatorlib import ipc try: ipc.DBusService() diff --git a/terminatorlib/optionparse.py b/terminatorlib/optionparse.py index 3d783cef..55cda32b 100755 --- a/terminatorlib/optionparse.py +++ b/terminatorlib/optionparse.py @@ -68,6 +68,8 @@ WM_WINDOW_ROLE property on the window') parser.add_option('-l', '--layout', dest='layout', help='Select a layout') parser.add_option('-p', '--profile', dest='profile', help='Use a \ different profile as the default') + parser.add_option('-u', '--no-dbus', action='store_true', dest='nodbus', + help='Disable DBus') parser.add_option('-d', '--debug', action='count', dest='debug', help='Enable debugging information (twice for debug server)') parser.add_option('--debug-classes', action='store', dest='debug_classes', diff --git a/terminatorlib/terminal.py b/terminatorlib/terminal.py index 43908c8a..528c8883 100755 --- a/terminatorlib/terminal.py +++ b/terminatorlib/terminal.py @@ -1509,7 +1509,7 @@ for %s (%s)' % (name, urlplugin.__class__.__name__)) return False dbg("Terminal::key_new_window: Spawning: %s" % cmd) - subprocess.Popen([cmd, ]) + subprocess.Popen([cmd, '-u']) def key_broadcast_off(self): self.set_groupsend(None, self.terminator.groupsend_type['off'])