diff --git a/remotinator b/remotinator index b81c663d..91371fd7 100755 --- a/remotinator +++ b/remotinator @@ -20,6 +20,7 @@ import os import sys +import argparse from terminatorlib.util import dbg, err try: @@ -27,40 +28,60 @@ try: except ImportError: err('Unable to initialise Terminator remote library. This probably means dbus is not available') sys.exit(1) +from terminatorlib.translation import _ APP_NAME='remotinator' APP_VERSION='0.97' COMMANDS={ - 'hsplit': ['terminal_hsplit', 'Split the current terminal horizontally'], - 'vsplit': ['terminal_vsplit', 'Split the current terminal vertically'], - 'terminals': ['get_terminals', 'Get a list of all terminals'], - 'terminal_tab': ['get_terminal_tab', 'Get the UUID of a parent tab'], - 'terminal_tab_title': ['get_terminal_tab_title', 'Get the title of a parent tab'], - } + # Command uuid req. Description + 'new_window': [False, _('Open a new window')], + 'new_tab': [True, _('Open a new tab')], + 'hsplit': [True, _('Split the current terminal horizontally')], + 'vsplit': [True, _('Split the current terminal vertically')], + 'get_terminals': [False, _('Get a list of all terminals')], + 'get_window': [True, _('Get the UUID of a parent window')], + 'get_window_title': [True, _('Get the title of a parent window')], + 'get_tab': [True, _('Get the UUID of a parent tab')], + 'get_tab_title': [True, _('Get the title of a parent tab')], + } if __name__ == '__main__': dbg ("%s starting up, version %s" % (APP_NAME, APP_VERSION)) - if sys.argv[0].split('/')[-1] == APP_NAME: - if len(sys.argv) <2 or sys.argv[1] in ['-h', '--help']: - print "Usage: %s COMMAND" % sys.argv[0] - print " Commands:" - for command in COMMANDS: - print " %s : %s" % (command, COMMANDS[command][1]) + command_desc='' + for command in sorted(COMMANDS.keys()): + command_desc += " %-*s %s %s\n" % (max([len(x) for x in COMMANDS.keys()]), + command, + COMMANDS[command][0] and '*' or ' ', + COMMANDS[command][1]) + + # Parse args + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + usage='%(prog)s command [options]', + description=_('Run one of the following Terminator DBus commands:\n\n%s') % (command_desc), + epilog=_('* These entries require either TERMINATOR_UUID environment var,\n or the --uuid option must be used.')) + parser.add_argument('-u', '--uuid', dest='uuid', type=str, metavar='UUID', default=argparse.SUPPRESS, + help=_('Terminal UUID for when not in env var TERMINATOR_UUID')) + parser.add_argument('command', type=str, nargs=1, choices=sorted(COMMANDS.keys()), + help=argparse.SUPPRESS) + parser.add_argument('-v', '--version', action='version', version='%%(prog)s %s' %(APP_VERSION)) + options = vars(parser.parse_args()) # Straight to dict + + # Pull out the command + command = options['command'][0] + del options['command'] + + func = getattr(ipc, command) + + uuid_required = COMMANDS[command][0] + if uuid_required: + uuid = options.get('uuid', os.environ.get('TERMINATOR_UUID')) + if uuid: + func(uuid, options) + else: + err("$TERMINATOR_UUID is not set, or passed as an option.") sys.exit(1) - command = sys.argv[1] else: - command = sys.argv[0].split('/')[-1] - - if not command in COMMANDS or not hasattr(ipc, COMMANDS[command][0]): - err("Unknown command: %s" % command) - sys.exit(1) - - if not os.environ.has_key('TERMINATOR_UUID'): - err("$TERMINATOR_UUID is not set. Are you definitely running inside Terminator?") - sys.exit(1) - - func = getattr(ipc, COMMANDS[command][0]) - func(os.environ['TERMINATOR_UUID']) - + func(options) diff --git a/terminator b/terminator index 9576cc32..77e8071e 100755 --- a/terminator +++ b/terminator @@ -70,13 +70,11 @@ if __name__ == '__main__': # being False will cause us to continue without the dbus server and open a # window. try: - dbg('dbus not fixed for GTK3 yet') - raise ImportError if OPTIONS.nodbus: dbg('dbus disabled by command line') raise ImportError from terminatorlib import ipc - from gi import DBus # VERIFY FOR GTK3 + import dbus try: dbus_service = ipc.DBusService() except ipc.DBusException: @@ -91,13 +89,13 @@ if __name__ == '__main__': if val == True: val = 'True' optionslist[opt] = val and '%s'%val or '' - optionslist = DBus.Dictionary(optionslist, signature='ss') # VERIFY FOR GTK3 + optionslist = dbus.Dictionary(optionslist, signature='ss') if OPTIONS.new_tab: dbg('Requesting a new tab') - ipc.new_tab(optionslist) + ipc.new_tab_cmdline(optionslist) else: dbg('Requesting a new window') - ipc.new_window(optionslist) + ipc.new_window_cmdline(optionslist) sys.exit() except ImportError: dbg('dbus not imported') diff --git a/terminatorlib/ipc.py b/terminatorlib/ipc.py index 61bd486a..540cd22b 100644 --- a/terminatorlib/ipc.py +++ b/terminatorlib/ipc.py @@ -3,8 +3,10 @@ # GPL v2 only """ipc.py - DBus server and API calls""" -from gi.repository import Gtk -from gi.repository import DBus, DBusGLib # VERIFY/FIXME FOR GTK3: DBusException?? Replace all "dbus" with "DBus" in this file, and stuff?? +from gi.repository import Gdk +import dbus.service +from dbus.exceptions import DBusException +import dbus.glib from borg import Borg from terminator import Terminator from config import Config @@ -17,8 +19,8 @@ if not CONFIG['dbus']: dbg('dbus disabled') raise ImportError -BUS_BASE = 'net.tenshu.Terminator' -BUS_PATH = '/net/tenshu/Terminator' +BUS_BASE = 'net.tenshu.Terminator2' +BUS_PATH = '/net/tenshu/Terminator2' try: # Try and include the X11 display name in the dbus bus name DISPLAY = hex(hash(Gdk.get_display())).replace('-', '_') @@ -58,7 +60,7 @@ class DBusService(Borg, dbus.service.Object): self.terminator = Terminator() @dbus.service.method(BUS_NAME, in_signature='a{ss}') - def new_window(self, options=dbus.Dictionary()): + def new_window_cmdline(self, options=dbus.Dictionary()): """Create a new Window""" dbg('dbus method called: new_window with parameters %s'%(options)) oldopts = self.terminator.config.options_get() @@ -68,7 +70,7 @@ class DBusService(Borg, dbus.service.Object): self.terminator.layout_done() @dbus.service.method(BUS_NAME, in_signature='a{ss}') - def new_tab(self, options=dbus.Dictionary()): + def new_tab_cmdline(self, options=dbus.Dictionary()): """Create a new tab""" dbg('dbus method called: new_tab with parameters %s'%(options)) oldopts = self.terminator.config.options_get() @@ -78,35 +80,78 @@ class DBusService(Borg, dbus.service.Object): window.tab_new() @dbus.service.method(BUS_NAME) - def terminal_hsplit(self, uuid=None): - """Split a terminal horizontally, by UUID""" - return self.terminal_split(uuid, True) + def new_window(self): + """Create a new Window""" + terminals_before = set(self.get_terminals()) + self.terminator.new_window() + terminals_after = set(self.get_terminals()) + new_terminal_set = list(terminals_after - terminals_before) + if len(new_terminal_set) != 1: + "ERROR: Cannot determine the UUID of the added terminal" + else: + return new_terminal_set[0] @dbus.service.method(BUS_NAME) - def terminal_vsplit(self, uuid=None): - """Split a terminal vertically, by UUID""" - return self.terminal_split(uuid, False) + def new_tab(self, uuid=None): + """Create a new tab""" + return self.new_terminal(uuid, 'tab') - def terminal_split(self, uuid, horiz): + @dbus.service.method(BUS_NAME) + def hsplit(self, uuid=None): + """Split a terminal horizontally, by UUID""" + return self.new_terminal(uuid, 'hsplit') + + @dbus.service.method(BUS_NAME) + def vsplit(self, uuid=None): + """Split a terminal vertically, by UUID""" + return self.new_terminal(uuid, 'vsplit') + + def new_terminal(self, uuid, type): """Split a terminal horizontally or vertically, by UUID""" - dbg('dbus method called: terminal_hsplit') + dbg('dbus method called: %s' % type) if not uuid: return "ERROR: No UUID specified" terminal = self.terminator.find_terminal_by_uuid(uuid) + terminals_before = set(self.get_terminals()) if not terminal: return "ERROR: Terminal with supplied UUID not found" - if horiz: + elif type == 'tab': + terminal.key_new_tab() + elif type == 'hsplit': terminal.key_split_horiz() - else: + elif type == 'vsplit': terminal.key_split_vert() + else: + return "ERROR: Unknown type \"%s\" specified" % (type) + terminals_after = set(self.get_terminals()) + # Detect the new terminal UUID + new_terminal_set = list(terminals_after - terminals_before) + if len(new_terminal_set) != 1: + return "ERROR: Cannot determine the UUID of the added terminal" + else: + return new_terminal_set[0] @dbus.service.method(BUS_NAME) - def get_terminals(self, uuid): + def get_terminals(self): """Return a list of all the terminals""" return [x.uuid.urn for x in self.terminator.terminals] @dbus.service.method(BUS_NAME) - def get_terminal_tab(self, uuid): + def get_window(self, uuid=None): + """Return the UUID of the parent window of a given terminal""" + terminal = self.terminator.find_terminal_by_uuid(uuid) + window = terminal.get_toplevel() + return window.uuid.urn + + @dbus.service.method(BUS_NAME) + def get_window_title(self, uuid=None): + """Return the title of a parent window of a given terminal""" + terminal = self.terminator.find_terminal_by_uuid(uuid) + window = terminal.get_toplevel() + return window.get_title() + + @dbus.service.method(BUS_NAME) + def get_tab(self, uuid=None): """Return the UUID of the parent tab of a given terminal""" maker = Factory() terminal = self.terminator.find_terminal_by_uuid(uuid) @@ -116,7 +161,7 @@ class DBusService(Borg, dbus.service.Object): return root_widget.uuid.urn @dbus.service.method(BUS_NAME) - def get_terminal_tab_title(self, uuid): + def get_tab_title(self, uuid=None): """Return the title of a parent tab of a given terminal""" maker = Factory() terminal = self.terminator.find_terminal_by_uuid(uuid) @@ -134,38 +179,58 @@ def with_proxy(func): func(proxy, *args, **argd) return _exec +@with_proxy +def new_window_cmdline(session, options): + """Call the dbus method to open a new window""" + session.new_window_cmdline(options) + +@with_proxy +def new_tab_cmdline(session, options): + """Call the dbus method to open a new tab in the first window""" + session.new_tab_cmdline(options) + @with_proxy def new_window(session, options): """Call the dbus method to open a new window""" - session.new_window(options) + print session.new_window() @with_proxy -def new_tab(session, options): +def new_tab(session, uuid, options): """Call the dbus method to open a new tab in the first window""" - session.new_tab(options) + print session.new_tab(uuid) @with_proxy -def terminal_hsplit(session, uuid): +def hsplit(session, uuid, options): """Call the dbus method to horizontally split a terminal""" - session.terminal_hsplit(uuid) + print session.hsplit(uuid) @with_proxy -def terminal_vsplit(session, uuid): +def vsplit(session, uuid, options): """Call the dbus method to vertically split a terminal""" - print session.terminal_vsplit(uuid) + print session.vsplit(uuid) @with_proxy -def get_terminals(session, uuid): +def get_terminals(session, options): """Call the dbus method to return a list of all terminals""" - print '\n'.join(session.get_terminals(uuid)) + print '\n'.join(session.get_terminals()) @with_proxy -def get_terminal_tab(session, uuid): +def get_window(session, uuid, options): """Call the dbus method to return the toplevel tab for a terminal""" - print session.get_terminal_tab(uuid) + print session.get_window(uuid) @with_proxy -def get_terminal_tab_title(session, uuid): +def get_window_title(session, uuid, options): """Call the dbus method to return the title of a tab""" - print session.get_terminal_tab_title(uuid) + print session.get_window_title(uuid) + +@with_proxy +def get_tab(session, uuid, options): + """Call the dbus method to return the toplevel tab for a terminal""" + print session.get_tab(uuid) + +@with_proxy +def get_tab_title(session, uuid, options): + """Call the dbus method to return the title of a tab""" + print session.get_tab_title(uuid) diff --git a/terminatorlib/terminal.py b/terminatorlib/terminal.py index ec3dc689..1cafb639 100755 --- a/terminatorlib/terminal.py +++ b/terminatorlib/terminal.py @@ -849,8 +849,7 @@ class Terminal(Gtk.VBox): return(False) if mapping and mapping not in ['close_window', - 'full_screen', - 'new_tab']: + 'full_screen']: dbg('Terminal::on_keypress: lookup found: %r' % mapping) # handle the case where user has re-bound copy to ctrl+ # we only copy if there is a selection otherwise let it fall through @@ -1753,6 +1752,9 @@ class Terminal(Gtk.VBox): def key_new_window(self): self.terminator.new_window(self.get_cwd()) + def key_new_tab(self): + self.get_toplevel().tab_new(self) + def key_new_terminator(self): spawn_new_terminator(self.origcwd, ['-u']) diff --git a/terminatorlib/window.py b/terminatorlib/window.py index c5dfdfc9..7cefb4f8 100755 --- a/terminatorlib/window.py +++ b/terminatorlib/window.py @@ -79,8 +79,8 @@ class Window(Container, Gtk.Window): if options.role: self.set_role(options.role) - if options.classname is not None: - self.set_wmclass(options.classname, self.wmclass_class) +# if options.classname is not None: +# self.set_wmclass(options.classname, self.wmclass_class) if options.forcedicon is not None: icon_to_apply = options.forcedicon @@ -208,8 +208,6 @@ class Window(Container, Gtk.Window): Gdk.Event(Gdk.DELETE)): self.on_destroy_event(window, Gdk.Event(Gdk.DESTROY)) - elif mapping == 'new_tab': - self.tab_new(self.get_focussed_terminal()) else: return(False) return(True)