Initial cut of layout launcher. It 'aint pretty, but it works

This commit is contained in:
Stephen Boddy 2013-08-28 23:09:17 +02:00
parent c8b6268835
commit e14cd19690
10 changed files with 269 additions and 26 deletions

View File

@ -45,7 +45,9 @@ based on the wishes of the child shell.
Specifies the preferred size and position of Terminator's window; see X(7).
.TP
.B \-e, \-\-command=COMMAND
Runs the specified command instead of your default shell or profile specified command
Runs the specified command instead of your default shell or profile specified command. Note: if
Terminator is launched as x-terminal-emulator \-e behaves like \-x, and the longform becomes
\-\-execute2=COMMAND
.TP
.B \-x, \-\-execute COMMAND [ARGS]
Runs \fBthe rest of the command line\fR instead of your default shell or profile specified command.
@ -63,6 +65,9 @@ Set a custom name (WM_CLASS) property on the window
Start Terminator with a specific layout. The argument here is the name
of a saved layout.
.TP
.B \-s, \-\-select-layout=LAYOUT
Open the layout launcher window instead of the normal terminal.
.TP
.B \-p, \-\-profile=PROFILE
Use a different profile as the default
.TP
@ -94,10 +99,10 @@ used to spawn a new tab in the first Terminator window.
The following keybindings can be used to control Terminator:
.TP
.B Super+R
\fBR\fotate terminals clockwise.
\fBR\fRotate terminals clockwise.
.TP
.B Super+Shift+R
\fBR\fotate terminals counter-clockwise.
\fBR\fRotate terminals counter-clockwise.
.TP
.B Ctrl+Shift+O
Split terminals H\fBo\fRrizontally.

View File

@ -47,6 +47,7 @@ from terminatorlib.terminator import Terminator
from terminatorlib.factory import Factory
from terminatorlib.version import APP_NAME, APP_VERSION
from terminatorlib.util import dbg, err
from terminatorlib.layoutlauncher import LayoutLauncher
if __name__ == '__main__':
dbus_service = None
@ -97,13 +98,17 @@ if __name__ == '__main__':
TERMINATOR.set_origcwd(ORIGCWD)
TERMINATOR.set_dbus_data(dbus_service)
TERMINATOR.reconfigure()
try:
dbg('Creating a terminal with layout: %s' % OPTIONS.layout)
TERMINATOR.create_layout(OPTIONS.layout)
except (KeyError,ValueError), ex:
err('layout creation failed, creating a window ("%s")' % ex)
TERMINATOR.new_window()
TERMINATOR.layout_done()
if OPTIONS.select:
# launch gui, return selection
LAYOUTLAUNCHER=LayoutLauncher()
else:
try:
dbg('Creating a terminal with layout: %s' % OPTIONS.layout)
TERMINATOR.create_layout(OPTIONS.layout)
except (KeyError,ValueError), ex:
err('layout creation failed, creating a window ("%s")' % ex)
TERMINATOR.new_window()
TERMINATOR.layout_done()
if OPTIONS.debug > 2:
import terminatorlib.debugserver as debugserver

View File

@ -173,7 +173,8 @@ DEFAULTS = {
'broadcast_all' : '',
'insert_number' : '',
'insert_padded' : '',
'edit_window_title': ''
'edit_window_title': '',
'layout_launcher' : ''
},
'profiles': {
'default': {

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.18"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="layoutlauncherwin">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Terminator Layout Launcher</property>
<signal name="destroy-event" handler="on_destroy_event" swapped="no"/>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">7</property>
<property name="spacing">7</property>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="label_yalign">0</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="layoutlist">
<property name="width_request">150</property>
<property name="height_request">200</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">layoutstore</property>
<property name="headers_clickable">False</property>
<property name="search_column">0</property>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn1">
<property name="title" translatable="yes">Layout</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="launchbutton">
<property name="label" translatable="yes">Launch</property>
<property name="width_request">100</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_launchbutton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkListStore" id="layoutstore">
<columns>
<!-- column-name layoutname -->
<column type="gchararray"/>
</columns>
</object>
</interface>

103
terminatorlib/layoutlauncher.py Executable file
View File

@ -0,0 +1,103 @@
#!/usr/bin/python
"""Layout Launcher for Terminator.
Load a UIBuilder config file, display it, populate it with our current layouts,
then allow launching it as a new instance
"""
import os
import gtk
from util import dbg, err, spawn_new_terminator
import config
from translation import _
from terminator import Terminator
from plugin import PluginRegistry
class LayoutLauncher:
"""Class implementing the various parts of the preferences editor"""
terminator = None
config = None
registry = None
plugins = None
keybindings = None
window = None
builder = None
layouttreeview = None
layouttreestore = None
def __init__ (self): #, term):
self.terminator = Terminator()
self.terminator.register_launcher_window(self)
self.config = config.Config()
#self.term = term
self.builder = gtk.Builder()
#self.keybindings = Keybindings()
try:
# Figure out where our library is on-disk so we can open our
(head, _tail) = os.path.split(config.__file__)
librarypath = os.path.join(head, 'layoutlauncher.glade')
gladefile = open(librarypath, 'r')
gladedata = gladefile.read()
except Exception, ex:
print "Failed to find layoutlauncher.glade"
print ex
return
self.builder.add_from_string(gladedata)
self.window = self.builder.get_object('layoutlauncherwin')
#self.layouteditor = LayoutEditor(self.builder)
self.builder.connect_signals(self)
self.window.connect('destroy', self.on_destroy_event)
#self.layouteditor.prepare()
self.window.show_all()
self.layouttreeview = self.builder.get_object('layoutlist')
self.layouttreestore = self.builder.get_object('layoutstore')
self.update_layouts()
try:
#self.config.inhibit_save()
#self.set_values()
pass
except Exception, e:
err('Unable to set values: %s' % e)
#self.config.uninhibit_save()
def on_destroy_event(self, widget, data=None):
"""Handle window destruction"""
dbg('destroying self')
self.terminator.deregister_launcher_window(self)
self.window.destroy()
del(self.window)
def update_layouts(self):
"""Update the contents of the layout"""
self.layouttreestore.clear()
layouts = self.config.list_layouts()
for layout in sorted(layouts, cmp=lambda x,y: cmp(x.lower(), y.lower())):
if layout != "default":
self.layouttreestore.append([layout])
else:
self.layouttreestore.prepend([layout])
def on_launchbutton_clicked(self, widget):
"""Launch the selected layout as new instance"""
dbg('We have takeoff!')
selection=self.layouttreeview.get_selection()
(listmodel, rowiter) = selection.get_selected()
if not rowiter:
# Something is wrong, just jump to the first item in the list
selection.select_iter(self.layouttreestore.get_iter_first())
(listmodel, rowiter) = selection.get_selected()
layout = listmodel.get_value(rowiter, 0)
dbg('Clicked for %s' % layout)
spawn_new_terminator(self.terminator.origcwd, ['-u', '-l', layout])
if __name__ == '__main__':
import util
util.DEBUG = True
import terminal
LAYOUTLAUNCHER = LayoutLauncher()
gtk.main()

View File

@ -86,7 +86,9 @@ icon for the window (by file or name)'))
parser.add_option('-r', '--role', dest='role',
help=_('Set a custom WM_WINDOW_ROLE property on the window'))
parser.add_option('-l', '--layout', dest='layout',
help=_('Select a layout'))
help=_('Launch with the given layout'))
parser.add_option('-s', '--select-layout', action='store_true',
dest='select', help=_('Select a layout from a list'))
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',

View File

@ -143,7 +143,8 @@ class PrefsEditor:
'broadcast_all' : 'Broadcast key events to all',
'insert_number' : 'Insert terminal number',
'insert_padded' : 'Insert zero padded terminal number',
'edit_window_title': 'Edit window title'
'edit_window_title': 'Edit window title',
'layout_launcher' : 'Open layout launcher window'
}
def __init__ (self, term):

View File

@ -15,7 +15,7 @@ import pango
import subprocess
import urllib
from util import dbg, err, gerr
from util import dbg, err, gerr, spawn_new_terminator
import util
from config import Config
from cwd import get_default_cwd
@ -27,6 +27,7 @@ from searchbar import Searchbar
from translation import _
from signalman import Signalman
import plugin
from terminatorlib.layoutlauncher import LayoutLauncher
try:
import vte
@ -1680,18 +1681,7 @@ class Terminal(gtk.VBox):
self.terminator.new_window(self.terminator.pid_cwd(self.pid))
def key_new_terminator(self):
cmd = sys.argv[0]
if not os.path.isabs(cmd):
# Command is not an absolute path. Figure out where we are
cmd = os.path.join (self.origcwd, sys.argv[0])
if not os.path.isfile(cmd):
# we weren't started as ./terminator in a path. Give up
err('Terminal::key_new_window: Unable to locate Terminator')
return False
dbg("Terminal::key_new_window: Spawning: %s" % cmd)
subprocess.Popen([cmd, '-u'])
spawn_new_terminator(self.origcwd, ['-u'])
def key_broadcast_off(self):
self.set_groupsend(None, self.terminator.groupsend_type['off'])
@ -1742,6 +1732,9 @@ class Terminal(gtk.VBox):
dialog.destroy()
return
def key_layout_launcher(self):
LAYOUTLAUNCHER=LayoutLauncher()
def key_page_up(self):
self.scroll_by_page(-1)

View File

@ -19,6 +19,7 @@ class Terminator(Borg):
"""master object for the application"""
windows = None
launcher_windows = None
windowtitle = None
terminals = None
groups = None
@ -48,6 +49,8 @@ class Terminator(Borg):
if not self.windows:
self.windows = []
if not self.launcher_windows:
self.launcher_windows = []
if not self.terminals:
self.terminals = []
if not self.groups:
@ -129,6 +132,27 @@ class Terminator(Borg):
dbg('no windows remain, quitting')
gtk.main_quit()
def register_launcher_window(self, window):
"""Register a new launcher window widget"""
if window not in self.launcher_windows:
dbg('Terminator::register_launcher_window: registering %s:%s' % (id(window),
type(window)))
self.launcher_windows.append(window)
def deregister_launcher_window(self, window):
"""de-register a launcher window widget"""
dbg('Terminator::deregister_launcher_window: de-registering %s:%s' %
(id(window), type(window)))
if window in self.launcher_windows:
self.launcher_windows.remove(window)
else:
err('%s is not in registered window list' % window)
if len(self.launcher_windows) == 0 and len(self.windows) == 0:
# We have no windows left, we should exit
dbg('no windows remain, quitting')
gtk.main_quit()
def register_terminal(self, terminal):
"""Register a new terminal widget"""
if terminal not in self.terminals:

View File

@ -29,6 +29,7 @@ import os
import pwd
import inspect
import uuid
import subprocess
# set this to true to enable debugging output
DEBUG = False
@ -289,3 +290,17 @@ def inject_uuid(target):
else:
dbg("Object already has a UUID: %s" % target)
def spawn_new_terminator(cwd, args):
"""Start a new terminator instance with the given arguments"""
cmd = sys.argv[0]
if not os.path.isabs(cmd):
# Command is not an absolute path. Figure out where we are
cmd = os.path.join (cwd, sys.argv[0])
if not os.path.isfile(cmd):
# we weren't started as ./terminator in a path. Give up
err('Unable to locate Terminator')
return False
dbg("Spawning: %s" % cmd)
subprocess.Popen([cmd]+args)