* Fix the DBus interface (gtk2-gtk3)
* Disable the wm_class feature. Seems not possible in GTK3, and breaks the DBus call for new_window. (trunk-1651) * As part of GTK3 fixup, some improvements to the DBus interface, and remotinator (Steve Boddy) * Can now open a window or tab using remotinator * Can get the window uuid, or title using remotinator * Moved new tab key handling into the terminal for consistency * Standardise response when a new term is created (split, win or tab) to reply with new terms uuid * For GTK3 gave the DBus a slightly different name so they it can run at same time as GTK2 * remotinator now uses argparse for commandline option handling, vastly improving the option handling * remotinator help strings are translatable now
This commit is contained in:
parent
e4c235dcd6
commit
7b769ae1d8
73
remotinator
73
remotinator
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import argparse
|
||||||
|
|
||||||
from terminatorlib.util import dbg, err
|
from terminatorlib.util import dbg, err
|
||||||
try:
|
try:
|
||||||
|
@ -27,40 +28,60 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
err('Unable to initialise Terminator remote library. This probably means dbus is not available')
|
err('Unable to initialise Terminator remote library. This probably means dbus is not available')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
from terminatorlib.translation import _
|
||||||
|
|
||||||
APP_NAME='remotinator'
|
APP_NAME='remotinator'
|
||||||
APP_VERSION='0.97'
|
APP_VERSION='0.97'
|
||||||
|
|
||||||
COMMANDS={
|
COMMANDS={
|
||||||
'hsplit': ['terminal_hsplit', 'Split the current terminal horizontally'],
|
# Command uuid req. Description
|
||||||
'vsplit': ['terminal_vsplit', 'Split the current terminal vertically'],
|
'new_window': [False, _('Open a new window')],
|
||||||
'terminals': ['get_terminals', 'Get a list of all terminals'],
|
'new_tab': [True, _('Open a new tab')],
|
||||||
'terminal_tab': ['get_terminal_tab', 'Get the UUID of a parent tab'],
|
'hsplit': [True, _('Split the current terminal horizontally')],
|
||||||
'terminal_tab_title': ['get_terminal_tab_title', 'Get the title of a parent tab'],
|
'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__':
|
if __name__ == '__main__':
|
||||||
dbg ("%s starting up, version %s" % (APP_NAME, APP_VERSION))
|
dbg ("%s starting up, version %s" % (APP_NAME, APP_VERSION))
|
||||||
|
|
||||||
if sys.argv[0].split('/')[-1] == APP_NAME:
|
command_desc=''
|
||||||
if len(sys.argv) <2 or sys.argv[1] in ['-h', '--help']:
|
for command in sorted(COMMANDS.keys()):
|
||||||
print "Usage: %s COMMAND" % sys.argv[0]
|
command_desc += " %-*s %s %s\n" % (max([len(x) for x in COMMANDS.keys()]),
|
||||||
print " Commands:"
|
command,
|
||||||
for command in COMMANDS:
|
COMMANDS[command][0] and '*' or ' ',
|
||||||
print " %s : %s" % (command, COMMANDS[command][1])
|
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)
|
sys.exit(1)
|
||||||
command = sys.argv[1]
|
|
||||||
else:
|
else:
|
||||||
command = sys.argv[0].split('/')[-1]
|
func(options)
|
||||||
|
|
||||||
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'])
|
|
||||||
|
|
||||||
|
|
10
terminator
10
terminator
|
@ -70,13 +70,11 @@ if __name__ == '__main__':
|
||||||
# being False will cause us to continue without the dbus server and open a
|
# being False will cause us to continue without the dbus server and open a
|
||||||
# window.
|
# window.
|
||||||
try:
|
try:
|
||||||
dbg('dbus not fixed for GTK3 yet')
|
|
||||||
raise ImportError
|
|
||||||
if OPTIONS.nodbus:
|
if OPTIONS.nodbus:
|
||||||
dbg('dbus disabled by command line')
|
dbg('dbus disabled by command line')
|
||||||
raise ImportError
|
raise ImportError
|
||||||
from terminatorlib import ipc
|
from terminatorlib import ipc
|
||||||
from gi import DBus # VERIFY FOR GTK3
|
import dbus
|
||||||
try:
|
try:
|
||||||
dbus_service = ipc.DBusService()
|
dbus_service = ipc.DBusService()
|
||||||
except ipc.DBusException:
|
except ipc.DBusException:
|
||||||
|
@ -91,13 +89,13 @@ if __name__ == '__main__':
|
||||||
if val == True:
|
if val == True:
|
||||||
val = 'True'
|
val = 'True'
|
||||||
optionslist[opt] = val and '%s'%val or ''
|
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:
|
if OPTIONS.new_tab:
|
||||||
dbg('Requesting a new tab')
|
dbg('Requesting a new tab')
|
||||||
ipc.new_tab(optionslist)
|
ipc.new_tab_cmdline(optionslist)
|
||||||
else:
|
else:
|
||||||
dbg('Requesting a new window')
|
dbg('Requesting a new window')
|
||||||
ipc.new_window(optionslist)
|
ipc.new_window_cmdline(optionslist)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
dbg('dbus not imported')
|
dbg('dbus not imported')
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
# GPL v2 only
|
# GPL v2 only
|
||||||
"""ipc.py - DBus server and API calls"""
|
"""ipc.py - DBus server and API calls"""
|
||||||
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gdk
|
||||||
from gi.repository import DBus, DBusGLib # VERIFY/FIXME FOR GTK3: DBusException?? Replace all "dbus" with "DBus" in this file, and stuff??
|
import dbus.service
|
||||||
|
from dbus.exceptions import DBusException
|
||||||
|
import dbus.glib
|
||||||
from borg import Borg
|
from borg import Borg
|
||||||
from terminator import Terminator
|
from terminator import Terminator
|
||||||
from config import Config
|
from config import Config
|
||||||
|
@ -17,8 +19,8 @@ if not CONFIG['dbus']:
|
||||||
dbg('dbus disabled')
|
dbg('dbus disabled')
|
||||||
raise ImportError
|
raise ImportError
|
||||||
|
|
||||||
BUS_BASE = 'net.tenshu.Terminator'
|
BUS_BASE = 'net.tenshu.Terminator2'
|
||||||
BUS_PATH = '/net/tenshu/Terminator'
|
BUS_PATH = '/net/tenshu/Terminator2'
|
||||||
try:
|
try:
|
||||||
# Try and include the X11 display name in the dbus bus name
|
# Try and include the X11 display name in the dbus bus name
|
||||||
DISPLAY = hex(hash(Gdk.get_display())).replace('-', '_')
|
DISPLAY = hex(hash(Gdk.get_display())).replace('-', '_')
|
||||||
|
@ -58,7 +60,7 @@ class DBusService(Borg, dbus.service.Object):
|
||||||
self.terminator = Terminator()
|
self.terminator = Terminator()
|
||||||
|
|
||||||
@dbus.service.method(BUS_NAME, in_signature='a{ss}')
|
@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"""
|
"""Create a new Window"""
|
||||||
dbg('dbus method called: new_window with parameters %s'%(options))
|
dbg('dbus method called: new_window with parameters %s'%(options))
|
||||||
oldopts = self.terminator.config.options_get()
|
oldopts = self.terminator.config.options_get()
|
||||||
|
@ -68,7 +70,7 @@ class DBusService(Borg, dbus.service.Object):
|
||||||
self.terminator.layout_done()
|
self.terminator.layout_done()
|
||||||
|
|
||||||
@dbus.service.method(BUS_NAME, in_signature='a{ss}')
|
@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"""
|
"""Create a new tab"""
|
||||||
dbg('dbus method called: new_tab with parameters %s'%(options))
|
dbg('dbus method called: new_tab with parameters %s'%(options))
|
||||||
oldopts = self.terminator.config.options_get()
|
oldopts = self.terminator.config.options_get()
|
||||||
|
@ -78,35 +80,78 @@ class DBusService(Borg, dbus.service.Object):
|
||||||
window.tab_new()
|
window.tab_new()
|
||||||
|
|
||||||
@dbus.service.method(BUS_NAME)
|
@dbus.service.method(BUS_NAME)
|
||||||
def terminal_hsplit(self, uuid=None):
|
def new_window(self):
|
||||||
"""Split a terminal horizontally, by UUID"""
|
"""Create a new Window"""
|
||||||
return self.terminal_split(uuid, True)
|
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)
|
@dbus.service.method(BUS_NAME)
|
||||||
def terminal_vsplit(self, uuid=None):
|
def new_tab(self, uuid=None):
|
||||||
"""Split a terminal vertically, by UUID"""
|
"""Create a new tab"""
|
||||||
return self.terminal_split(uuid, False)
|
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"""
|
"""Split a terminal horizontally or vertically, by UUID"""
|
||||||
dbg('dbus method called: terminal_hsplit')
|
dbg('dbus method called: %s' % type)
|
||||||
if not uuid:
|
if not uuid:
|
||||||
return "ERROR: No UUID specified"
|
return "ERROR: No UUID specified"
|
||||||
terminal = self.terminator.find_terminal_by_uuid(uuid)
|
terminal = self.terminator.find_terminal_by_uuid(uuid)
|
||||||
|
terminals_before = set(self.get_terminals())
|
||||||
if not terminal:
|
if not terminal:
|
||||||
return "ERROR: Terminal with supplied UUID not found"
|
return "ERROR: Terminal with supplied UUID not found"
|
||||||
if horiz:
|
elif type == 'tab':
|
||||||
|
terminal.key_new_tab()
|
||||||
|
elif type == 'hsplit':
|
||||||
terminal.key_split_horiz()
|
terminal.key_split_horiz()
|
||||||
else:
|
elif type == 'vsplit':
|
||||||
terminal.key_split_vert()
|
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)
|
@dbus.service.method(BUS_NAME)
|
||||||
def get_terminals(self, uuid):
|
def get_terminals(self):
|
||||||
"""Return a list of all the terminals"""
|
"""Return a list of all the terminals"""
|
||||||
return [x.uuid.urn for x in self.terminator.terminals]
|
return [x.uuid.urn for x in self.terminator.terminals]
|
||||||
|
|
||||||
@dbus.service.method(BUS_NAME)
|
@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"""
|
"""Return the UUID of the parent tab of a given terminal"""
|
||||||
maker = Factory()
|
maker = Factory()
|
||||||
terminal = self.terminator.find_terminal_by_uuid(uuid)
|
terminal = self.terminator.find_terminal_by_uuid(uuid)
|
||||||
|
@ -116,7 +161,7 @@ class DBusService(Borg, dbus.service.Object):
|
||||||
return root_widget.uuid.urn
|
return root_widget.uuid.urn
|
||||||
|
|
||||||
@dbus.service.method(BUS_NAME)
|
@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"""
|
"""Return the title of a parent tab of a given terminal"""
|
||||||
maker = Factory()
|
maker = Factory()
|
||||||
terminal = self.terminator.find_terminal_by_uuid(uuid)
|
terminal = self.terminator.find_terminal_by_uuid(uuid)
|
||||||
|
@ -134,38 +179,58 @@ def with_proxy(func):
|
||||||
func(proxy, *args, **argd)
|
func(proxy, *args, **argd)
|
||||||
return _exec
|
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
|
@with_proxy
|
||||||
def new_window(session, options):
|
def new_window(session, options):
|
||||||
"""Call the dbus method to open a new window"""
|
"""Call the dbus method to open a new window"""
|
||||||
session.new_window(options)
|
print session.new_window()
|
||||||
|
|
||||||
@with_proxy
|
@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"""
|
"""Call the dbus method to open a new tab in the first window"""
|
||||||
session.new_tab(options)
|
print session.new_tab(uuid)
|
||||||
|
|
||||||
@with_proxy
|
@with_proxy
|
||||||
def terminal_hsplit(session, uuid):
|
def hsplit(session, uuid, options):
|
||||||
"""Call the dbus method to horizontally split a terminal"""
|
"""Call the dbus method to horizontally split a terminal"""
|
||||||
session.terminal_hsplit(uuid)
|
print session.hsplit(uuid)
|
||||||
|
|
||||||
@with_proxy
|
@with_proxy
|
||||||
def terminal_vsplit(session, uuid):
|
def vsplit(session, uuid, options):
|
||||||
"""Call the dbus method to vertically split a terminal"""
|
"""Call the dbus method to vertically split a terminal"""
|
||||||
print session.terminal_vsplit(uuid)
|
print session.vsplit(uuid)
|
||||||
|
|
||||||
@with_proxy
|
@with_proxy
|
||||||
def get_terminals(session, uuid):
|
def get_terminals(session, options):
|
||||||
"""Call the dbus method to return a list of all terminals"""
|
"""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
|
@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"""
|
"""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
|
@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"""
|
"""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)
|
||||||
|
|
||||||
|
|
|
@ -849,8 +849,7 @@ class Terminal(Gtk.VBox):
|
||||||
return(False)
|
return(False)
|
||||||
|
|
||||||
if mapping and mapping not in ['close_window',
|
if mapping and mapping not in ['close_window',
|
||||||
'full_screen',
|
'full_screen']:
|
||||||
'new_tab']:
|
|
||||||
dbg('Terminal::on_keypress: lookup found: %r' % mapping)
|
dbg('Terminal::on_keypress: lookup found: %r' % mapping)
|
||||||
# handle the case where user has re-bound copy to ctrl+<key>
|
# handle the case where user has re-bound copy to ctrl+<key>
|
||||||
# we only copy if there is a selection otherwise let it fall through
|
# 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):
|
def key_new_window(self):
|
||||||
self.terminator.new_window(self.get_cwd())
|
self.terminator.new_window(self.get_cwd())
|
||||||
|
|
||||||
|
def key_new_tab(self):
|
||||||
|
self.get_toplevel().tab_new(self)
|
||||||
|
|
||||||
def key_new_terminator(self):
|
def key_new_terminator(self):
|
||||||
spawn_new_terminator(self.origcwd, ['-u'])
|
spawn_new_terminator(self.origcwd, ['-u'])
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,8 @@ class Window(Container, Gtk.Window):
|
||||||
if options.role:
|
if options.role:
|
||||||
self.set_role(options.role)
|
self.set_role(options.role)
|
||||||
|
|
||||||
if options.classname is not None:
|
# if options.classname is not None:
|
||||||
self.set_wmclass(options.classname, self.wmclass_class)
|
# self.set_wmclass(options.classname, self.wmclass_class)
|
||||||
|
|
||||||
if options.forcedicon is not None:
|
if options.forcedicon is not None:
|
||||||
icon_to_apply = options.forcedicon
|
icon_to_apply = options.forcedicon
|
||||||
|
@ -208,8 +208,6 @@ class Window(Container, Gtk.Window):
|
||||||
Gdk.Event(Gdk.DELETE)):
|
Gdk.Event(Gdk.DELETE)):
|
||||||
self.on_destroy_event(window,
|
self.on_destroy_event(window,
|
||||||
Gdk.Event(Gdk.DESTROY))
|
Gdk.Event(Gdk.DESTROY))
|
||||||
elif mapping == 'new_tab':
|
|
||||||
self.tab_new(self.get_focussed_terminal())
|
|
||||||
else:
|
else:
|
||||||
return(False)
|
return(False)
|
||||||
return(True)
|
return(True)
|
||||||
|
|
Loading…
Reference in New Issue