diff --git a/terminatorlib/newterminator.py b/terminatorlib/newterminator.py deleted file mode 100755 index 670b75c9..00000000 --- a/terminatorlib/newterminator.py +++ /dev/null @@ -1,222 +0,0 @@ -#!/usr/bin/python -# Terminator by Chris Jones -# GPL v2 only -"""terminator.py - class for the master Terminator singleton""" - -import gtk - -from borg import Borg -from config import Config -from keybindings import Keybindings -from util import dbg, get_top_window - -class Terminator(Borg): - """master object for the application""" - - windows = None - windowtitle = None - terminals = None - groups = None - config = None - keybindings = None - - groupsend = None - groupsend_type = {'all':0, 'group':1, 'off':2} - - def __init__(self): - """Class initialiser""" - - Borg.__init__(self, self.__class__.__name__) - self.prepare_attributes() - - def prepare_attributes(self): - """Initialise anything that isn't already""" - - if not self.windows: - self.windows = [] - if not self.terminals: - self.terminals = [] - if not self.groups: - self.groups = [] - if not self.groupsend: - self.groupsend = self.groupsend_type['group'] - if not self.config: - self.config = Config() - if not self.keybindings: - self.keybindings = Keybindings() - self.keybindings.configure(self.config['keybindings']) - - def register_window(self, window): - """Register a new window widget""" - if window not in self.windows: - dbg('Terminator::register_window: registering %s:%s' % (id(window), - type(window))) - self.windows.append(window) - - def deregister_window(self, window): - """de-register a window widget""" - dbg('Terminator::deregister_window: de-registering %s:%s' % - (id(window), type(window))) - self.windows.remove(window) - if len(self.windows) == 0: - # We have no windows left, we should exit - gtk.main_quit() - - def register_terminal(self, terminal): - """Register a new terminal widget""" - if terminal not in self.terminals: - dbg('Terminator::register_terminal: registering %s:%s' % - (id(terminal), type(terminal))) - self.terminals.append(terminal) - terminal.connect('ungroup-all', self.ungroup_all) - terminal.connect('navigate', self.navigate_terminal) - terminal.connect('tab-new', self.tab_new) - - def deregister_terminal(self, terminal): - """De-register a terminal widget""" - dbg('Terminator::deregister_terminal: de-registering %s:%s' % - (id(terminal), type(terminal))) - self.terminals.remove(terminal) - - if len(self.terminals) == 0: - for window in self.windows: - window.destroy() - else: - dbg('Terminator::deregister_terminal: %d terminals remain' % - len(self.terminals)) - - def reconfigure(self): - """Update configuration for the whole application""" - - # FIXME: Set handle_size here - - # Cause all the terminals to reconfigure - for terminal in self.terminals: - terminal.reconfigure() - - def tab_new(self, terminal): - """A terminal asked for a new tab. This function is an indirection - to the Window object""" - window = get_top_window(terminal) - window.tab_new() - - def navigate_terminal(self, terminal, direction): - """Nagivate around the terminals""" - current = self.terminals.index(terminal) - length = len(self.terminals) - next = None - - if length <= 1: - return - - print "Current term: %d" % current - print "Number of terms: %d" % length - - if direction == 'next': - next = current + 1 - if next >= length: - next = 0 - elif direction == 'prev': - next = current - 1 - if next < 0: - next = length - 1 - else: - raise NotImplementedError - # FIXME: Do the directional navigation - - if next is not None: - print "sending focus to term %d" % next - self.terminals[next].grab_focus() - - def create_group(self, name): - """Create a new group""" - if name not in self.groups: - dbg('Terminator::create_group: registering group %s' % name) - self.groups.append(name) - - def ungroup_all(self, widget): - """Remove all groups""" - for terminal in self.terminals: - terminal.set_group(None, None) - self.groups = [] - - def closegroupedterms(self, group): - """Close all terminals in a group""" - for terminal in self.terminals: - if terminal.group == group: - terminal.close() - - def group_hoover(self): - """Clean out unused groups""" - - if self.config['autoclean_groups']: - inuse = [] - todestroy = [] - - for terminal in self.terminals: - if terminal.group: - if not terminal.group in inuse: - inuse.append(terminal.group) - - for group in self.groups: - if not group in inuse: - todestroy.append(group) - - dbg('Terminator::group_hoover: %d groups, hoovering %d' % - (len(self.groups), len(todestroy))) - for group in todestroy: - self.groups.remove(group) - - def group_emit(self, terminal, group, type, event): - """Emit to each terminal in a group""" - dbg('Terminator::group_emit: emitting a keystroke for group %s' % - group) - for term in self.terminals: - if term != terminal and term.group == group: - term.vte.emit(type, event) - - def all_emit(self, terminal, type, event): - """Emit to all terminals""" - for term in self.terminals: - if term != terminal: - term.vte.emit(type, event) - - def do_enumerate(self, widget, pad): - """Insert the number of each terminal in a group, into that terminal""" - if pad: - numstr = '%0'+str(len(str(len(self.terminals))))+'d' - else: - numstr = '%d' - - for term in self.get_target_terms(widget): - idx = self.terminals.index(term) - term.feed(numstr % (idx + 1)) - - def get_target_terms(self, widget): - """Get the terminals we should currently be broadcasting to""" - if self.groupsend == self.groupsend_type['all']: - return(self.terminals) - elif self.groupsend == self.groupsend_type['group']: - termset = [] - for term in self.terminals: - if term == widget or (term.group != None and term.group == - widget.group): - termset.append(term) - return(termset) - else: - return([widget]) - - def group_tab(self, widget): - """Group all the terminals in a tab""" - pass - - def ungroup_tab(self, widget): - """Ungroup all the terminals in a tab""" - pass - - def focus_changed(self, widget): - """We just moved focus to a new terminal""" - for terminal in self.terminals: - terminal.titlebar.update() - return -# vim: set expandtab ts=4 sw=4: diff --git a/terminatorlib/notebook.py b/terminatorlib/notebook.py index 85fd0d14..8b10caee 100755 --- a/terminatorlib/notebook.py +++ b/terminatorlib/notebook.py @@ -6,7 +6,7 @@ import gobject import gtk -from newterminator import Terminator +from terminator import Terminator from config import Config from factory import Factory from container import Container diff --git a/terminatorlib/paned.py b/terminatorlib/paned.py index 47200b7a..cbc5c1c4 100755 --- a/terminatorlib/paned.py +++ b/terminatorlib/paned.py @@ -8,7 +8,7 @@ import gobject import gtk from util import dbg, err, get_top_window -from newterminator import Terminator +from terminator import Terminator from factory import Factory from container import Container diff --git a/terminatorlib/prefseditor.py b/terminatorlib/prefseditor.py index d7299083..5c73df57 100755 --- a/terminatorlib/prefseditor.py +++ b/terminatorlib/prefseditor.py @@ -8,7 +8,7 @@ from util import dbg import config from keybindings import Keybindings, KeymapError from translation import _ -from newterminator import Terminator +from terminator import Terminator # FIXME: We need to check that we have represented all of Config() below class PrefsEditor: diff --git a/terminatorlib/terminal.py b/terminatorlib/terminal.py index 1d0155c7..a6c11b79 100755 --- a/terminatorlib/terminal.py +++ b/terminatorlib/terminal.py @@ -17,7 +17,7 @@ from util import dbg, err, gerr, get_top_window import util from config import Config from cwd import get_default_cwd -from newterminator import Terminator +from terminator import Terminator from titlebar import Titlebar from terminal_popup_menu import TerminalPopupMenu from searchbar import Searchbar diff --git a/terminatorlib/terminator.py b/terminatorlib/terminator.py index 680c89c5..670b75c9 100755 --- a/terminatorlib/terminator.py +++ b/terminatorlib/terminator.py @@ -1,1548 +1,222 @@ #!/usr/bin/python -# Terminator - multiple gnome terminals in one window -# Copyright (C) 2006-2008 cmsj@tenshu.net -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2 only. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# Terminator by Chris Jones +# GPL v2 only +"""terminator.py - class for the master Terminator singleton""" -"""Terminator by Chris Jones """ -import time, re, sys, os, platform +import gtk -import pygtk -pygtk.require ("2.0") -import gobject, gtk, pango +from borg import Borg +from config import Config +from keybindings import Keybindings +from util import dbg, get_top_window -from version import APP_NAME, APP_VERSION -import config -from util import dbg, err, debug +class Terminator(Borg): + """master object for the application""" -from keybindings import TerminatorKeybindings -from terminatorterm import TerminatorTerm -from prefs_profile import ProfileEditor -from editablelabel import EditableLabel -import translation + windows = None + windowtitle = None + terminals = None + groups = None + config = None + keybindings = None -# FIXME: Move to notebook.py -class TerminatorNotebookTabLabel(gtk.HBox): - _terminator = None - _notebook = None - _icon = None - _label = None - _button = None - - def __init__(self, title, notebook, terminator): - gtk.HBox.__init__(self, False) - self._notebook = notebook - self._terminator = terminator - - self._label = EditableLabel(title) - self.update_angle() + groupsend = None + groupsend_type = {'all':0, 'group':1, 'off':2} - self.pack_start(self._label, True, True) + def __init__(self): + """Class initialiser""" - self._icon = gtk.Image() - self._icon.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU) - - self.update_closebut() + Borg.__init__(self, self.__class__.__name__) + self.prepare_attributes() - self.show_all() + def prepare_attributes(self): + """Initialise anything that isn't already""" - def update_closebut(self): - if self._terminator.conf.close_button_on_tab: - if not self._button: - self._button = gtk.Button() - self._button.set_relief(gtk.RELIEF_NONE) - self._button.set_focus_on_click(False) - self._button.set_relief(gtk.RELIEF_NONE) - self._button.add(self._icon) - self._button.connect('clicked', self.on_close) - self._button.set_name("terminator-tab-close-button") - self._button.connect("style-set", self.on_style_set) - if hasattr(self._button, "set_tooltip_text"): - self._button.set_tooltip_text(_("Close Tab")) - self.pack_start(self._button, False, False) - self.show_all() - else: - if self._button: - self._button.remove(self._icon) - self.remove(self._button) - del(self._button) - self._button = None + if not self.windows: + self.windows = [] + if not self.terminals: + self.terminals = [] + if not self.groups: + self.groups = [] + if not self.groupsend: + self.groupsend = self.groupsend_type['group'] + if not self.config: + self.config = Config() + if not self.keybindings: + self.keybindings = Keybindings() + self.keybindings.configure(self.config['keybindings']) - def update_angle(self): - tab_pos = self._notebook.get_tab_pos() - if tab_pos == gtk.POS_LEFT: - self._label.set_angle(90) - elif tab_pos == gtk.POS_RIGHT: - self._label.set_angle(270) - else: - self._label.set_angle(0) + def register_window(self, window): + """Register a new window widget""" + if window not in self.windows: + dbg('Terminator::register_window: registering %s:%s' % (id(window), + type(window))) + self.windows.append(window) - def on_style_set(self, widget, prevstyle): - x, y = gtk.icon_size_lookup_for_settings( self._button.get_settings(), gtk.ICON_SIZE_MENU) - self._button.set_size_request(x + 2,y + 2) + def deregister_window(self, window): + """de-register a window widget""" + dbg('Terminator::deregister_window: de-registering %s:%s' % + (id(window), type(window))) + self.windows.remove(window) + if len(self.windows) == 0: + # We have no windows left, we should exit + gtk.main_quit() - def on_close(self, widget): - nbpages = self._notebook.get_n_pages() - for i in xrange(0,nbpages): - if self._notebook.get_tab_label(self._notebook.get_nth_page(i)) == self: - #dbg("[Close from tab] Found tab at position [%d]" % i) - if not isinstance (self._notebook.get_nth_page(i), TerminatorTerm): - if self._terminator.confirm_close_multiple (self._terminator.window, _("tab")): - return False - term = self._terminator._notebook_first_term(self._notebook.get_nth_page(i)) - while term: - if term == self._notebook.get_nth_page(i): - self._terminator.closeterm(term) - break - self._terminator.closeterm(term) - term = self._terminator._notebook_first_term(self._notebook.get_nth_page(i)) - break + def register_terminal(self, terminal): + """Register a new terminal widget""" + if terminal not in self.terminals: + dbg('Terminator::register_terminal: registering %s:%s' % + (id(terminal), type(terminal))) + self.terminals.append(terminal) + terminal.connect('ungroup-all', self.ungroup_all) + terminal.connect('navigate', self.navigate_terminal) + terminal.connect('tab-new', self.tab_new) - def set_title(self, title, force=False): - self._label.set_text(title, force) + def deregister_terminal(self, terminal): + """De-register a terminal widget""" + dbg('Terminator::deregister_terminal: de-registering %s:%s' % + (id(terminal), type(terminal))) + self.terminals.remove(terminal) - def get_title(self): - return self._label.get_text() - - def height_request(self): - return self.size_request()[1] - - def width_request(self): - return self.size_request()[0] - - -class Terminator: - options = None - groupings = None - _urgency = False - origcwd = None - - def __init__ (self, profile = None, command = None, fullscreen = False, - maximise = False, borderless = False, no_gconf = False, - geometry = None, hidden = False, forcedtitle = None, role=None): - self.profile = profile - self.command = command - - self._zoomed = False - self._maximised = False - self._fullscreen = False - self._geometry = geometry - self.debugaddress = None - self.start_cwd = os.getcwd() - self._hidden = False - self.term_list = [] - self.gnome_client = None - self.groupsend = 1 # 0 off, 1 group (d), 2 all - self.splittogroup = 0 # 0 no group (d), 1 new takes orginators group - self.autocleangroups = 1 # 0 off, 1 on (d) - stores = [] - self.groupings = [] - - store = config.TerminatorConfValuestoreRC () - store.set_reconfigure_callback (self.reconfigure_vtes) - stores.append (store) - - self._tab_reorderable = True - if not hasattr(gtk.Notebook, "set_tab_reorderable") or not hasattr(gtk.Notebook, "get_tab_reorderable"): - self._tab_reorderable = False - - if not no_gconf: - try: - import gconf - if self.profile: - self.profile = gconf.escape_key (self.profile, -1) - store = config.TerminatorConfValuestoreGConf (self.profile) - store.set_reconfigure_callback (self.reconfigure_vtes) - dbg ('Terminator__init__: comparing %s and %s'%(self.profile, store.profile.split ('/').pop ())) - if self.profile == store.profile.split ('/').pop (): - # If we have been given a profile, and we loaded it, we should be higher priority than RC - dbg ('Terminator__init__: placing GConf before RC') - stores.insert (0, store) + if len(self.terminals) == 0: + for window in self.windows: + window.destroy() else: - stores.append (store) - except Exception, e: - # This should probably be ImportError; what else might it throw? - dbg("GConf setup threw exception %s" % str(e)) + dbg('Terminator::deregister_terminal: %d terminals remain' % + len(self.terminals)) - self.conf = config.TerminatorConfig (stores) + def reconfigure(self): + """Update configuration for the whole application""" - # Sort out cwd detection code, if available - self.pid_get_cwd = lambda pid: None - if platform.system() == 'FreeBSD': - try: - from terminatorlib import freebsd - self.pid_get_cwd = freebsd.get_process_cwd - dbg ('Using FreeBSD self.pid_get_cwd') - except (OSError, NotImplementedError, ImportError): - dbg ('FreeBSD version too old for self.pid_get_cwd') - elif platform.system() == 'Linux': - dbg ('Using Linux self.pid_get_cwd') - self.pid_get_cwd = lambda pid: os.path.realpath ('/proc/%s/cwd' % pid) - elif platform.system() == 'SunOS': - dbg ('Using SunOS self.pid_get_cwd') - self.pid_get_cwd = lambda pid: os.path.realpath ('/proc/%s/path/cwd' % pid) - else: - dbg ('Unable to set a self.pid_get_cwd, unknown system: %s' % platform.system) + # FIXME: Set handle_size here - # import a library for viewing URLs - try: - dbg ('Trying to import gnome for X session and backup URL handling support') - global gnome - import gnome, gnome.ui - self.gnome_program = gnome.init(APP_NAME, APP_VERSION) - self.url_show = gnome.url_show - - # X session saving support - self.gnome_client = gnome.ui.master_client() - self.gnome_client.connect_to_session_manager() - self.gnome_client.connect('save-yourself', self.save_yourself) - self.gnome_client.connect('die', self.die) - except ImportError: - # webbrowser.open() is not really useful, but will do as a fallback - dbg ('gnome not available, no X session support, backup URL handling via webbrowser module') - import webbrowser - self.url_show = webbrowser.open + # Cause all the terminals to reconfigure + for terminal in self.terminals: + terminal.reconfigure() - self.icon_theme = gtk.IconTheme () + def tab_new(self, terminal): + """A terminal asked for a new tab. This function is an indirection + to the Window object""" + window = get_top_window(terminal) + window.tab_new() - self.keybindings = TerminatorKeybindings() - if self.conf.f11_modifier: - config.DEFAULTS['keybindings']['full_screen'] = 'F11' - print "Warning: Config setting f11_modifier is deprecated and will be removed in version 1.0" - print "Please add the following to the end of your terminator config:" - print "[keybindings]" - print "full_screen = F11" - self.keybindings.configure(self.conf.keybindings) + def navigate_terminal(self, terminal, direction): + """Nagivate around the terminals""" + current = self.terminals.index(terminal) + length = len(self.terminals) + next = None - self.set_handle_size (self.conf.handle_size) - self.set_closebutton_style () + if length <= 1: + return - self.window = gtk.Window () - if role: - self.window.set_role(role) - self.windowtitle = TerminatorWindowTitle (self.window) - if forcedtitle: - self.windowtitle.force_title (forcedtitle) - self.windowtitle.update () + print "Current term: %d" % current + print "Number of terms: %d" % length - if self._geometry is not None: - dbg("Geometry=%s" % self._geometry) - if not self.window.parse_geometry(self._geometry): - err(_("Invalid geometry string %r") % self._geometry) - - try: - self.window.set_icon (self.icon_theme.load_icon (APP_NAME, 48, 0)) - except: - self.icon = self.window.render_icon (gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON) - self.window.set_icon (self.icon) - - self.window.connect ("key-press-event", self.on_key_press) - self.window.connect ("delete_event", self.on_delete_event) - self.window.connect ("destroy", self.on_destroy_event) - self.window.connect ("window-state-event", self.on_window_state_changed) - - self.window.set_property ('allow-shrink', True) - - if fullscreen or self.conf.fullscreen: - self.fullscreen_toggle () - - if maximise or self.conf.maximise: - self.maximize () - - if borderless or self.conf.borderless: - self.window.set_decorated (False) - - # Set RGBA colormap if possible so VTE can use real alpha - # channels for transparency. - self.enable_rgba(True) - - # Start out with just one terminal - # FIXME: This should be really be decided from some kind of profile - term = (TerminatorTerm (self, self.profile, self.command)) - self.term_list = [term] - - self.window.add (term) - term._titlebox.hide() - self.window.show () - term.spawn_child () - self.save_yourself () - - couldbind = False - try: - couldbind = bindkey.tomboy_keybinder_bind(self.conf.keybindings['hide_window'],self.cbkeyCloak,term) - except: - pass - if couldbind: - if hidden or self.conf.hidden: - self.hide() - else: - if hidden or self.conf.hidden: - self.window.iconify() - - def on_term_resized(self): - win_total_width, win_total_height = self.window.get_size () - dbg ('Resized window is %dx%d' % (win_total_width, win_total_height)) - - # FIXME: find first terminal - firstidx = 0 - - # Walk terminals across top edge to sum column geometries - prev = -1 - column_sum = 0 - width_extra = 0 - walker = firstidx - while (walker != None): - term = self.term_list[walker] - font_width, font_height, columns, rows = term.get_size_details () - column_sum += columns - dbg ('Geometry hints (term %d) column += %d characters' % (walker, columns)) - prev = walker - walker = self._select_right (walker) - - # Walk terminals down left edge to sum row geometries - prev = -1 - row_sum = 0 - height_extra = 0 - walker = firstidx - while (walker != None): - term = self.term_list[walker] - font_width, font_height, columns, rows = term.get_size_details () - row_sum += rows - dbg ('Geometry hints (term %d) row += %d characters' % (walker, rows)) - prev = walker - walker = self._select_down (walker) - - # adjust... - width_extra = win_total_width - (column_sum * font_width) - height_extra = win_total_height - (row_sum * font_height) - - dbg ('Geometry hints based on font size: %dx%d, columns: %d, rows: %d, extra width: %d, extra height: %d' % (font_width, font_height, column_sum, row_sum, width_extra, height_extra)) - - self.window.set_geometry_hints(self.window, -1, -1, -1, -1, width_extra, height_extra, font_width, font_height, -1.0, -1.0) - - def set_handle_size (self, size): - if size in xrange (0,6): - gtk.rc_parse_string(""" - style "terminator-paned-style" { - GtkPaned::handle_size = %s - } + if direction == 'next': + next = current + 1 + if next >= length: + next = 0 + elif direction == 'prev': + next = current - 1 + if next < 0: + next = length - 1 + else: + raise NotImplementedError + # FIXME: Do the directional navigation - class "GtkPaned" style "terminator-paned-style" - """ % self.conf.handle_size) - - def set_closebutton_style (self): - gtk.rc_parse_string(""" - style "terminator-tab-close-button-style" { - GtkWidget::focus-padding = 0 - GtkWidget::focus-line-width = 0 - xthickness = 0 - ythickness = 0 - } - widget "*.terminator-tab-close-button" style "terminator-tab-close-button-style" - """) + if next is not None: + print "sending focus to term %d" % next + self.terminals[next].grab_focus() - def enable_rgba (self, rgba = False): - screen = self.window.get_screen() - if rgba: - colormap = screen.get_rgba_colormap() - else: - colormap = screen.get_rgb_colormap() - if colormap: - self.window.set_colormap(colormap) + def create_group(self, name): + """Create a new group""" + if name not in self.groups: + dbg('Terminator::create_group: registering group %s' % name) + self.groups.append(name) - def die(self, *args): - gtk.main_quit () + def ungroup_all(self, widget): + """Remove all groups""" + for terminal in self.terminals: + terminal.set_group(None, None) + self.groups = [] - def save_yourself (self, *args): - """ Save as much of our state as possible for the X session manager """ - dbg("Saving session for xsm") - args = [sys.argv[0], - ("--geometry=%dx%d" % self.window.get_size()) + ("+%d+%d" % self.window.get_position())] + def closegroupedterms(self, group): + """Close all terminals in a group""" + for terminal in self.terminals: + if terminal.group == group: + terminal.close() - # OptionParser should really help us out here - drop_next_arg = False - geompatt = re.compile(r'^--geometry(=.+)?') - for arg in sys.argv[1:]: - mo = geompatt.match(arg) - if mo: - if not mo.group(1): - drop_next_arg = True - elif not drop_next_arg and arg not in ('--maximise', '-m', '--fullscreen', '-f'): - args.append(arg) - drop_next_arg = False + def group_hoover(self): + """Clean out unused groups""" - if self._maximised: - args.append('--maximise') + if self.config['autoclean_groups']: + inuse = [] + todestroy = [] - if self._fullscreen: - args.append('--fullscreen') + for terminal in self.terminals: + if terminal.group: + if not terminal.group in inuse: + inuse.append(terminal.group) - if self.gnome_client: - # We can't set an interpreter because Gnome unconditionally spams it with - # --sm-foo-bar arguments before our own argument list. *mutter* - # So, hopefully your #! line is correct. If not, we could write out - # a shell script with the interpreter name etc. - c = self.gnome_client - c.set_program(sys.argv[0]) - dbg("Session restart command: %s with args %r in %s" % (sys.argv[0], args, self.start_cwd)) + for group in self.groups: + if not group in inuse: + todestroy.append(group) - c.set_restart_style(gnome.ui.RESTART_IF_RUNNING) - c.set_current_directory(self.start_cwd) - try: - c.set_restart_command(args) - c.set_clone_command(args) - except (TypeError,AttributeError): - # Apparantly needed for some Fedora systems - # see http://trac.nicfit.net/mesk/ticket/137 - dbg("Gnome bindings have weird set_clone/restart_command") - c.set_restart_command(len(args), args) - c.set_clone_command(len(args), args) - return True + dbg('Terminator::group_hoover: %d groups, hoovering %d' % + (len(self.groups), len(todestroy))) + for group in todestroy: + self.groups.remove(group) - def show(self): - """Show the terminator window""" - # restore window position - self.window.move(self.pos[0],self.pos[1]) - #self.window.present() - self.window.show_now() - self._hidden = False + def group_emit(self, terminal, group, type, event): + """Emit to each terminal in a group""" + dbg('Terminator::group_emit: emitting a keystroke for group %s' % + group) + for term in self.terminals: + if term != terminal and term.group == group: + term.vte.emit(type, event) - def hide(self): - """Hide the terminator window""" - # save window position - self.pos = self.window.get_position() - self.window.hide() - self._hidden = True + def all_emit(self, terminal, type, event): + """Emit to all terminals""" + for term in self.terminals: + if term != terminal: + term.vte.emit(type, event) - def cbkeyCloak(self, data): - """Callback event for show/hide keypress""" - if self._hidden: - self.show() - else: - self.hide() - - def maximize (self): - """ Maximize the Terminator window.""" - self.window.maximize () - - def unmaximize (self): - """ Unmaximize the Terminator window.""" - self.window.unmaximize () - - def fullscreen_toggle (self): - """ Toggle the fullscreen state of the window. If it is in - fullscreen state, it will be unfullscreened. If it is not, it - will be set to fullscreen state. - """ - if self._fullscreen: - self.window.unfullscreen () - else: - self.window.fullscreen () - - def fullscreen_absolute (self, fullscreen): - """ Explicitly set the fullscreen state of the window. - """ - if self._fullscreen != fullscreen: - self.fullscreen_toggle () - - def on_window_state_changed (self, window, event): - self._fullscreen = bool (event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN) - self._maximised = bool (event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED) - dbg("window state changed: fullscreen: %s, maximised: %s" % (self._fullscreen, self._maximised)) - return (False) - - def on_delete_event (self, window, event, data=None): - if len (self.term_list) == 1: - return False - return self.confirm_close_multiple (window, _("window")) - - def confirm_close_multiple (self, window, type): - # show dialog - dialog = gtk.Dialog (_("Close?"), window, gtk.DIALOG_MODAL) - dialog.set_has_separator (False) - dialog.set_resizable (False) - - cancel = dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT) - close_all = dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_ACCEPT) - label = close_all.get_children()[0].get_children()[0].get_children()[1].set_label(_("Close _Terminals")) - - primairy = gtk.Label (_('Close multiple terminals?')) - primairy.set_use_markup (True) - primairy.set_alignment (0, 0.5) - secundairy = gtk.Label (_("This %s has several terminals open. Closing the %s will also close all terminals within it.") % (type, type)) - secundairy.set_line_wrap(True) - primairy.set_alignment (0, 0.5) - - labels = gtk.VBox () - labels.pack_start (primairy, False, False, 6) - labels.pack_start (secundairy, False, False, 6) - - image = gtk.image_new_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG) - image.set_alignment (0.5, 0) - - box = gtk.HBox() - box.pack_start (image, False, False, 6) - box.pack_start (labels, False, False, 6) - dialog.vbox.pack_start (box, False, False, 12) - - dialog.show_all () - result = dialog.run () - dialog.destroy () - return not (result == gtk.RESPONSE_ACCEPT) - - def on_destroy_event (self, widget, data=None): - self.die() - - def on_beep (self, terminal): - self.set_urgency (True) - - def set_urgency (self, on): - if on == self._urgency: - return - - self._urgency = on - self.window.set_urgency_hint (on) - - # keybindings for the whole terminal window (affects the main - # windows containing the splited terminals) - def on_key_press (self, window, event): - """ Callback for the window to determine what to do with special - keys. Currently handled key-combo's: - * F11: toggle fullscreen state of the window. - * CTRL - SHIFT - Q: close all terminals - """ - self.set_urgency (False) - mapping = self.keybindings.lookup(event) - - if mapping: - dbg("on_key_press: lookup found %r" % mapping) - if mapping == 'full_screen': - self.fullscreen_toggle () - elif mapping == 'close_window': - if not self.on_delete_event (window, gtk.gdk.Event (gtk.gdk.DELETE)): - self.on_destroy_event (window, gtk.gdk.Event (gtk.gdk.DESTROY)) - else: - return (False) - return (True) - - def set_window_title(self, title): - """ - Modifies Terminator window title - """ - self.windowtitle.set_title(title) - - def add(self, widget, terminal, pos = "bottom"): - """ - Add a term to another at position pos - """ - if pos in ("top", "bottom"): - pane = gtk.VPaned() - vertical = True - elif pos in ("left", "right"): - pane = gtk.HPaned() - vertical = False - else: - err('Terminator.add: massive pos fail: %s' % pos) - return - - # get the parent of the provided terminal - parent = widget.get_parent () - - if isinstance (parent, gtk.Window): - # We have just one term - parent.remove(widget) - if pos in ("top", "left"): - pane.pack1 (terminal, True, True) - pane.pack2 (widget, True, True) - else: - pane.pack1 (widget, True, True) - pane.pack2 (terminal, True, True) - parent.add (pane) - - position = (vertical) and parent.allocation.height \ - or parent.allocation.width - - if (isinstance (parent, gtk.Notebook) or isinstance (parent, gtk.Window)) and widget.conf.titlebars: - #not the only term in the notebook/window anymore, need to reshow the title - widget._titlebox.update() - terminal._titlebox.update() - - if isinstance (parent, gtk.Notebook): - page = -1 - - for i in xrange(0, parent.get_n_pages()): - if parent.get_nth_page(i) == widget: - page = i - break - - label = parent.get_tab_label (widget) - widget.reparent (pane) - if pos in ("top", "left"): - pane.remove(widget) - pane.pack1 (terminal, True, True) - pane.pack2 (widget, True, True) - else: - pane.pack1 (widget, True, True) - pane.pack2 (terminal, True, True) - #parent.remove_page(page) - pane.show() - parent.insert_page(pane, None, page) - parent.set_tab_label(pane,label) - parent.set_tab_label_packing(pane, not self.conf.scroll_tabbar, not self.conf.scroll_tabbar, gtk.PACK_START) - if self._tab_reorderable: - parent.set_tab_reorderable(pane, True) - parent.set_current_page(page) - - position = (vertical) and parent.allocation.height \ - or parent.allocation.width - - if isinstance (parent, gtk.Paned): - # We are inside a split term - position = (vertical) and widget.allocation.height \ - or widget.allocation.width - - if (widget == parent.get_child1 ()): - widget.reparent (pane) - parent.pack1 (pane, True, True) - else: - widget.reparent (pane) - parent.pack2 (pane, True, True) - - if pos in ("top", "left"): - pane.remove(widget) - pane.pack1 (terminal, True, True) - pane.pack2 (widget, True, True) - else: - pane.pack1 (widget, True, True) - pane.pack2 (terminal, True, True) - - pane.pack1 (widget, True, True) - pane.pack2 (terminal, True, True) - - # show all, set position of the divider - pane.show () - pane.set_position (position / 2) - terminal.show () - - # insert the term reference into the list - index = self.term_list.index (widget) - if pos in ('bottom', 'right'): - index = index + 1 - self.term_list.insert (index, terminal) - # make the new terminal grab the focus - terminal._vte.grab_focus () - - return (terminal) - - def on_page_reordered(self, notebook, child, page_num): - #page has been reordered, we need to get the - # first term and last term - dbg ("Reordered: %d"%page_num) - nbpages = notebook.get_n_pages() - if nbpages == 1: - dbg("[ERROR] only one page in on_page_reordered") - - first = self._notebook_first_term(notebook.get_nth_page(page_num)) - last = self._notebook_last_term(notebook.get_nth_page(page_num)) - firstidx = self.term_list.index(first) - lastidx = self.term_list.index(last) - termslice = self.term_list[firstidx:lastidx+1] - #remove them from the list - for term in termslice: - self.term_list.remove(term) - - if page_num == 0: - #first page, we insert before the first term of next page - nexttab = notebook.get_nth_page(1) - sibling = self._notebook_first_term(nexttab) - siblingindex = self.term_list.index(sibling) - for term in termslice: - self.term_list.insert(siblingindex, term) - siblingindex += 1 - else: - #other pages, we insert after the last term of previous page - previoustab = notebook.get_nth_page(page_num - 1) - sibling = self._notebook_last_term(previoustab) - siblingindex = self.term_list.index(sibling) - for term in termslice: - siblingindex += 1 - self.term_list.insert(siblingindex, term) - - #for page reorder, we need to get the first term of a notebook - def notebook_first_term(self, notebook): - return self._notebook_first_term(notebook.get_nth_page(0)) - - def _notebook_first_term(self, child): - if isinstance(child, TerminatorTerm): - return child - elif isinstance(child, gtk.Paned): - return self._notebook_first_term(child.get_child1()) - elif isinstance(child, gtk.Notebook): - return self._notebook_first_term(child.get_nth_page(0)) - - dbg("[ERROR] unsupported class %s in _notebook_first_term" % child.__class__.__name__) - return None - - #for page reorder, we need to get the last term of a notebook - def notebook_last_term(self, notebook): - return self._notebook_last_term(notebook.get_nth_page(notebook.get_n_pages()-1)) - - def _notebook_last_term(self, child): - if isinstance(child, TerminatorTerm): - return child - elif isinstance(child, gtk.Paned): - return self._notebook_last_term(child.get_child2()) - elif isinstance(child, gtk.Notebook): - return self._notebook_last_term(child.get_nth_page(child.get_n_pages()-1)) - - dbg("[ERROR] unsupported class %s in _notebook_last_term" % child.__class__.__name__) - return None - - def newtab(self,widget, toplevel = False, command = None): - if self._zoomed: - # We don't want to add a new tab while we are zoomed in on a terminal - dbg ("newtab function called, but Terminator was in zoomed terminal mode.") - return - - terminal = TerminatorTerm (self, self.profile, command, widget.get_cwd()) - #only one term, we don't show the title - terminal._titlebox.hide() - if self.conf.extreme_tabs and not toplevel: - parent = widget.get_parent () - child = widget - else: - child = self.window.get_children()[0] - parent = child.get_parent() - - if isinstance(parent, gtk.Paned) or (isinstance(parent, gtk.Window) - and - ((self.conf.extreme_tabs and not toplevel) or not isinstance(child, gtk.Notebook))): - #no notebook yet. - notebook = gtk.Notebook() - if self._tab_reorderable: - notebook.connect('page-reordered',self.on_page_reordered) - notebook.set_tab_reorderable(widget, True) - notebook.set_property('homogeneous', not self.conf.scroll_tabbar) - notebook.set_scrollable (self.conf.scroll_tabbar) - # Config validates this. - pos = getattr(gtk, "POS_%s" % self.conf.tab_position.upper()) - notebook.set_tab_pos(pos) - notebook.set_show_tabs (not self.conf.hide_tabbar) - - if isinstance(parent, gtk.Paned): - if parent.get_child1() == child: - child.reparent(notebook) - parent.pack1(notebook) + def do_enumerate(self, widget, pad): + """Insert the number of each terminal in a group, into that terminal""" + if pad: + numstr = '%0'+str(len(str(len(self.terminals))))+'d' else: - child.reparent(notebook) - parent.pack2(notebook) - elif isinstance(parent, gtk.Window): - child.reparent(notebook) - parent.add(notebook) - if self._tab_reorderable: - notebook.set_tab_reorderable(child,True) - notebooklabel = "" - if isinstance(child, TerminatorTerm): - child._titlebox.hide() - if widget.get_window_title() is not None: - notebooklabel = widget.get_window_title() - notebooktablabel = TerminatorNotebookTabLabel(notebooklabel, notebook, self) - notebook.set_tab_label(child, notebooktablabel) - notebook.set_tab_label_packing(child, not self.conf.scroll_tabbar, not self.conf.scroll_tabbar, gtk.PACK_START) + numstr = '%d' - wal = self.window.allocation - if not (self._maximised or self._fullscreen): - self.window.resize(wal.width, - min(wal.height + notebooktablabel.height_request(), gtk.gdk.screen_height())) + for term in self.get_target_terms(widget): + idx = self.terminals.index(term) + term.feed(numstr % (idx + 1)) - notebook.show() - elif isinstance(parent, gtk.Notebook): - notebook = parent - elif isinstance(parent, gtk.Window) and isinstance(child, gtk.Notebook): - notebook = child - else: - return (False) - - ## NOTE - ## Here we need to append to the notebook before we can - ## spawn the terminal (WINDOW_ID needs to be set) - - notebook.append_page(terminal,None) - terminal.show () - terminal.spawn_child () - notebooklabel = terminal.get_window_title() - notebooktablabel = TerminatorNotebookTabLabel(notebooklabel, notebook, self) - notebook.set_tab_label(terminal, notebooktablabel) - notebook.set_tab_label_packing(terminal, not self.conf.scroll_tabbar, not self.conf.scroll_tabbar, gtk.PACK_START) - if self._tab_reorderable: - notebook.set_tab_reorderable(terminal,True) - ## Now, we set focus on the new term - notebook.set_current_page(-1) - terminal._vte.grab_focus () - - #adding a new tab, thus we need to get the - # last term of the previous tab and add - # the new term just after - sibling = self._notebook_last_term(notebook.get_nth_page(notebook.page_num(terminal)-1)) - index = self.term_list.index(sibling) - self.term_list.insert (index + 1, terminal) - return (True) - - def splitaxis (self, widget, vertical=True, command=None): - """ Split the provided widget on the horizontal or vertical axis. """ - if self._zoomed: - # We don't want to split the terminal while we are in zoomed mode - dbg ("splitaxis function called, but Terminator was in zoomed mode.") - return - - # create a new terminal and parent pane. - terminal = TerminatorTerm (self, self.profile, command, widget.get_cwd()) - if self.splittogroup: - terminal.set_group (None, widget._group) - pos = vertical and "right" or "bottom" - self.add(widget, terminal, pos) - terminal.show () - terminal.spawn_child () - - return - - def remove(self, widget, keep = False): - """Remove a TerminatorTerm from the Terminator view and terms list - Returns True on success, False on failure""" - parent = widget.get_parent () - sibling = None - focus_on_close = 'prev' - if isinstance (parent, gtk.Window): - # We are the only term - if not self.on_delete_event (parent, gtk.gdk.Event (gtk.gdk.DELETE)): - self.on_destroy_event (parent, gtk.gdk.Event (gtk.gdk.DESTROY)) - return True - - elif isinstance (parent, gtk.Paned): - index = self.term_list.index (widget) - grandparent = parent.get_parent () - - # Discover sibling while all objects exist - if widget == parent.get_child1 (): - sibling = parent.get_child2 () - focus_on_close = 'next' - if widget == parent.get_child2 (): - sibling = parent.get_child1 () - - if not sibling: - # something is wrong, give up - err ("Error: %s is not a child of %s"%(widget, parent)) - return False - - parent.remove(widget) - if isinstance(grandparent, gtk.Notebook): - page = -1 - for i in xrange(0, grandparent.get_n_pages()): - if grandparent.get_nth_page(i) == parent: - page = i - break - label = grandparent.get_tab_label (parent) - parent.remove(sibling) - grandparent.remove_page(page) - grandparent.insert_page(sibling, None,page) - grandparent.set_tab_label(sibling, label) - grandparent.set_tab_label_packing(sibling, not self.conf.scroll_tabbar, not self.conf.scroll_tabbar, gtk.PACK_START) - if self._tab_reorderable: - grandparent.set_tab_reorderable(sibling, True) - grandparent.set_current_page(page) - else: - grandparent.remove (parent) - sibling.reparent (grandparent) - if not self._zoomed: - grandparent.resize_children() - if isinstance(sibling, TerminatorTerm) and isinstance(sibling.get_parent(), gtk.Notebook): - sibling._titlebox.hide() - - self.term_list.remove (widget) - if not keep: - widget._vte.get_parent().remove(widget._vte) - widget._vte = None - - elif isinstance (parent, gtk.Notebook): - parent.remove(widget) - nbpages = parent.get_n_pages() - index = self.term_list.index (widget) - - self.term_list.remove (widget) - if not keep: - widget._vte.get_parent().remove(widget._vte) - widget._vte = None - if nbpages == 1: - if self.window.allocation.height != gtk.gdk.screen_height(): - self.window.resize(self.window.allocation.width, min(self.window.allocation.height - parent.get_tab_label(parent.get_nth_page(0)).height_request(), gtk.gdk.screen_height())) - sibling = parent.get_nth_page(0) - parent.remove(sibling) - gdparent = parent.get_parent() - if isinstance(gdparent, gtk.Window): - gdparent.remove(parent) - gdparent.add(sibling) - elif isinstance(gdparent, gtk.Paned): - if gdparent.get_child1() == parent: - gdparent.remove(parent) - gdparent.pack1(sibling) - else: - gdparent.remove(parent) - gdparent.pack2(sibling) - elif isinstance(gdparent, gtk.Notebook): - # extreme_tabs is on :( - label = gdparent.get_tab_label(parent) - gdparent.remove(parent) - gdparent.insert_page(sibling, None, 0) - gdparent.set_tab_label(sibling, label) - gdparent.set_tab_label_packing(sibling, not self.conf.scroll_tabbar, not self.conf.scroll_tabbar, gtk.PACK_START) - if self._tab_reorderable: - gdparent.set_tab_reorderable(sibling, True) - gdparent.set_current_page(0) + def get_target_terms(self, widget): + """Get the terminals we should currently be broadcasting to""" + if self.groupsend == self.groupsend_type['all']: + return(self.terminals) + elif self.groupsend == self.groupsend_type['group']: + termset = [] + for term in self.terminals: + if term == widget or (term.group != None and term.group == + widget.group): + termset.append(term) + return(termset) else: - err('Unknown grandparent of %s (parent is a notebook)' % widget) - if isinstance(sibling, TerminatorTerm) and sibling.conf.titlebars and sibling.conf.extreme_tabs: - sibling._titlebox.show() - else: - err('Attempting to remove terminal from unknown parent: %s' % parent) - if self.conf.focus_on_close == 'prev' or ( self.conf.focus_on_close == 'auto' and focus_on_close == 'prev'): - if index == 0: index = 1 - self.term_list[index - 1]._vte.grab_focus () - self._set_current_notebook_page_recursive(self.term_list[index - 1]) - elif self.conf.focus_on_close == 'next' or ( self.conf.focus_on_close == 'auto' and focus_on_close == 'next'): - if index == len(self.term_list): index = index - 1 - self.term_list[index]._vte.grab_focus () - self._set_current_notebook_page_recursive(self.term_list[index]) - - if len(self.term_list) == 1: - self.term_list[0]._titlebox.hide() - - return True - - def closeterm (self, widget): - if self._zoomed: - # We are zoomed, pop back out to normal layout before closing - dbg ("closeterm function called while in zoomed mode. Restoring previous layout before closing.") - self.toggle_zoom(widget, not self._maximised) - - if self.remove(widget): - self.group_hoover() - return True - return False - - def closegroupedterms (self, widget): - if self._zoomed: - # We are zoomed, pop back out to normal layout before closing - dbg ("closeterm function called while in zoomed mode. Restoring previous layout before closing.") - self.toggle_zoom(widget, not self._maximised) - - widget_group = widget._group - all_closed = True - for term in self.term_list[:]: - if term._group == widget_group and not self.remove(term): - all_closed = False - self.group_hoover() - return all_closed - - def go_to (self, term, selector): - current = self.term_list.index (term) - target = selector (term) - if not target is None: - term = self.term_list[target] - ##we need to set the current page of each notebook - self._set_current_notebook_page_recursive(term) - term._vte.grab_focus () - - def _select_direction (self, term, matcher): - '''Return index of terminal in given direction''' - # Handle either TerminatorTerm or int index - if type(term) == int: - current = term - term = self.term_list[current] - else: - current = self.term_list.index (term) - current_geo = term.get_geometry () - best_index = None - best_geo = None - - for i in range(0,len(self.term_list)): - if i == current: - continue - possible = self.term_list[i] - possible_geo = possible.get_geometry () - - #import pprint - #print "I am %d" % (current) - #pprint.pprint(current_geo) - #print "I saw %d" % (i) - #pprint.pprint(possible_geo) - - try: - if matcher (current_geo, possible_geo, best_geo): - best_index = i - best_geo = possible_geo - except: - # Not being called on a Paned widget - pass - #if best_index is None: - # print "nothing best" - #else: - # print "sending %d" % (best_index) - return best_index - - def _match_up (self, current_geo, possible_geo, best_geo): - '''We want to find terminals that are fully above the top - border, but closest in the y direction, breaking ties via - the closest cursor x position.''' - if len(possible_geo.keys()) == 0: - dbg('_match_right: no possible geo, bailing') - return False - - #print "matching up..." - # top edge of the current terminal - edge = current_geo['origin_y'] - # botoom edge of the possible target - new_edge = possible_geo['origin_y']+possible_geo['span_y'] - - # Width of the horizontal bar that splits terminals - try: - horizontalBar = self.term_list[0].get_parent().style_get_property('handle-size') + self.term_list[0]._titlebox.get_allocation().height - except TypeError: - horizontalBar = 0 - # Vertical distance between two terminals - distance = current_geo['offset_y'] - (possible_geo['offset_y'] + possible_geo['span_y']) - if new_edge < edge: - #print "new_edge < edge" - if best_geo is None: - #print "first thing left" - return True - best_edge = best_geo['origin_y']+best_geo['span_y'] - if new_edge > best_edge and distance == horizontalBar: - #print "closer y" - return True - if new_edge == best_edge: - #print "same y" - - cursor = current_geo['origin_x'] + current_geo['cursor_x'] - new_cursor = possible_geo['origin_x'] + possible_geo['cursor_x'] - best_cursor = best_geo['origin_x'] + best_geo['cursor_x'] - - if abs(new_cursor - cursor) < abs(best_cursor - cursor): - #print "closer x" - return True - else: - if distance == horizontalBar: - return True - #print "fail" - return False - - def _match_down (self, current_geo, possible_geo, best_geo): - '''We want to find terminals that are fully below the bottom - border, but closest in the y direction, breaking ties via - the closest cursor x position.''' - if len(possible_geo.keys()) == 0: - dbg('_match_right: no possible geo, bailing') - return False - - #print "matching down..." - # bottom edge of the current terminal - edge = current_geo['origin_y']+current_geo['span_y'] - # top edge of the possible target - new_edge = possible_geo['origin_y'] - #print "edge: %d new_edge: %d" % (edge, new_edge) - - # Width of the horizontal bar that splits terminals - try: - horizontalBar = self.term_list[0].get_parent().style_get_property('handle-size') + self.term_list[0]._titlebox.get_allocation().height - except TypeError: - horizontalBar = 0 - # Vertical distance between two terminals - distance = possible_geo['offset_y'] - (current_geo['offset_y'] + current_geo['span_y']) - if new_edge > edge: - #print "new_edge > edge" - if best_geo is None: - #print "first thing right" - return True - best_edge = best_geo['origin_y'] - #print "best_edge: %d" % (best_edge) - if new_edge < best_edge and distance == horizontalBar: - #print "closer y" - return True - if new_edge == best_edge: - #print "same y" - - cursor = current_geo['origin_x'] + current_geo['cursor_x'] - new_cursor = possible_geo['origin_x'] + possible_geo['cursor_x'] - best_cursor = best_geo['origin_x'] + best_geo['cursor_x'] - - if abs(new_cursor - cursor) < abs(best_cursor - cursor): - #print "closer x" - return True - else: - if distance == horizontalBar: - return True - #print "fail" - return False - - def _match_left (self, current_geo, possible_geo, best_geo): - '''We want to find terminals that are fully to the left of - the left-side border, but closest in the x direction, breaking - ties via the closest cursor y position.''' - if len(possible_geo.keys()) == 0: - dbg('_match_right: no possible geo, bailing') - return False - - #print "matching left..." - # left-side edge of the current terminal - edge = current_geo['origin_x'] - # right-side edge of the possible target - new_edge = possible_geo['origin_x']+possible_geo['span_x'] - - # Width of the horizontal bar that splits terminals - try: - horizontalBar = self.term_list[0].get_parent().style_get_property('handle-size') + self.term_list[0]._titlebox.get_allocation().height - except TypeError: - horizontalBar = 0 - # Width of the vertical bar that splits terminals - if self.term_list[0].is_scrollbar_present(): - try: - verticalBar = self.term_list[0].get_parent().style_get_property('handle-size') + self.term_list[0].get_parent().style_get_property('scroll-arrow-vlength') - except TypeError: - verticalBar = 0 - else: - try: - verticalBar = self.term_list[0].get_parent().style_get_property('handle-size') - except TypeError: - verticalBar = 0 - # Horizontal distance between two terminals - distance = current_geo['offset_x'] - (possible_geo['offset_x'] + possible_geo['span_x']) - if new_edge <= edge: - #print "new_edge(%d) < edge(%d)" % (new_edge, edge) - if best_geo is None: - #print "first thing left" - return True - best_edge = best_geo['origin_x']+best_geo['span_x'] - if new_edge > best_edge and distance == verticalBar: - #print "closer x (new_edge(%d) > best_edge(%d))" % (new_edge, best_edge) - return True - if new_edge == best_edge: - #print "same x" - - cursor = current_geo['origin_y'] + current_geo['cursor_y'] - new_cursor = possible_geo['origin_y'] + possible_geo['cursor_y'] - best_cursor = best_geo['origin_y'] + best_geo['cursor_y'] - - if abs(new_cursor - cursor) < abs(best_cursor - cursor) and distance <> horizontalBar: - #print "closer y" - return True - #print "fail" - return False - - def _match_right (self, current_geo, possible_geo, best_geo): - '''We want to find terminals that are fully to the right of - the right-side border, but closest in the x direction, breaking - ties via the closest cursor y position.''' - if len(possible_geo.keys()) == 0: - dbg('_match_right: no possible geo, bailing') - return False - - #print "matching right..." - # right-side edge of the current terminal - edge = current_geo['origin_x']+current_geo['span_x'] - # left-side edge of the possible target - new_edge = possible_geo['origin_x'] - #print "edge: %d new_edge: %d" % (edge, new_edge) - - # Width of the horizontal bar that splits terminals - try: - horizontalBar = self.term_list[0].get_parent().style_get_property('handle-size') + self.term_list[0]._titlebox.get_allocation().height - except TypeError: - horizontalBar = 0 - # Width of the vertical bar that splits terminals - if self.term_list[0].is_scrollbar_present(): - try: - verticalBar = self.term_list[0].get_parent().style_get_property('handle-size') + self.term_list[0].get_parent().style_get_property('scroll-arrow-vlength') - except TypeError: - verticalBar = 0 - else: - try: - verticalBar = self.term_list[0].get_parent().style_get_property('handle-size') - except TypeError: - verticalBar = 0 - # Horizontal distance between two terminals - distance = possible_geo['offset_x'] - (current_geo['offset_x'] + current_geo['span_x']) - if new_edge >= edge: - #print "new_edge > edge" - if best_geo is None: - #print "first thing right" - return True - best_edge = best_geo['origin_x'] - #print "best_edge: %d" % (best_edge) - if new_edge < best_edge and distance == verticalBar: - #print "closer x" - return True - if new_edge == best_edge: - #print "same x" - - cursor = current_geo['origin_y'] + current_geo['cursor_y'] - new_cursor = possible_geo['origin_y'] + possible_geo['cursor_y'] - best_cursor = best_geo['origin_y'] + best_geo['cursor_y'] - - if abs(new_cursor - cursor) < abs(best_cursor - cursor) and distance <> horizontalBar: - #print "closer y" - return True - #print "fail" - return False - - def _select_up (self, term): - return self._select_direction (term, self._match_up) - - def _select_down (self, term): - return self._select_direction (term, self._match_down) - - def _select_left (self, term): - return self._select_direction (term, self._match_left) - - def _select_right (self, term): - return self._select_direction (term, self._match_right) - - def go_next (self, term): - self.go_to (term, self._select_next) - - def go_prev (self, term): - self.go_to (term, self._select_prev) - - def go_up (self, term): - self.go_to (term, self._select_up) - - def go_down (self, term): - self.go_to (term, self._select_down) - - def go_left (self, term): - self.go_to (term, self._select_left) - - def go_right (self, term): - self.go_to (term, self._select_right) - - def _select_next (self, term): - current = self.term_list.index (term) - next = None - if self.conf.cycle_term_tab: - notebookpage = self.get_first_notebook_page(term) - if notebookpage: - last = self._notebook_last_term(notebookpage[1]) - first = self._notebook_first_term(notebookpage[1]) - if term == last: - next = self.term_list.index(first) - - if next is None: - if current == len (self.term_list) - 1: - next = 0 - else: - next = current + 1 - return next - - def _select_prev (self, term): - current = self.term_list.index (term) - previous = None - if self.conf.cycle_term_tab: - notebookpage = self.get_first_notebook_page(term) - if notebookpage: - last = self._notebook_last_term(notebookpage[1]) - first = self._notebook_first_term(notebookpage[1]) - if term == first: - previous = self.term_list.index(last) - - if previous is None: - if current == 0: - previous = len (self.term_list) - 1 - else: - previous = current - 1 - return previous - - def _set_current_notebook_page_recursive(self, widget): - page = self.get_first_notebook_page(widget) - while page: - child = None - page_num = page[0].page_num(page[1]) - page[0].set_current_page(page_num) - page = self.get_first_notebook_page(page[0]) - - def resizeterm (self, widget, keyname): - if keyname in ('Up', 'Down'): - type = gtk.VPaned - elif keyname in ('Left', 'Right'): - type = gtk.HPaned - else: - err ("Invalid keytype: %s" % type) - return - - parent = self.get_first_parent_widget(widget, type) - if parent is None: - return - - #We have a corresponding parent pane - # - #allocation = parent.get_allocation() - - if keyname in ('Up', 'Down'): - maxi = parent.get_child1().get_allocation().height + parent.get_child2().get_allocation().height - 1 - - else: - maxi = parent.get_child1().get_allocation().width + parent.get_child2().get_allocation().width - 1 - move = 10 - if keyname in ('Up', 'Left'): - move = -10 - - move = max(2, parent.get_position() + move) - move = min(maxi, move) - - parent.set_position(move) - - def previous_tab(self, term): - notebook = self.get_first_parent_notebook(term) - if notebook: - cur = notebook.get_current_page() - pages = notebook.get_n_pages() - if cur == 0: - notebook.set_current_page(pages - 1) - else: - notebook.prev_page() - # This seems to be required in some versions of (py)gtk. - # Without it, the selection changes, but the displayed page doesn't change - # Seen in gtk-2.12.11 and pygtk-2.12.1 at least. - notebook.set_current_page(notebook.get_current_page()) - - def next_tab(self, term): - notebook = self.get_first_parent_notebook(term) - if notebook: - cur = notebook.get_current_page() - pages = notebook.get_n_pages() - if cur == pages - 1: - notebook.set_current_page(0) - else: - notebook.next_page() - notebook.set_current_page(notebook.get_current_page()) - - def switch_to_tab(self, term, index): - notebook = self.get_first_parent_notebook(term) - if notebook: - notebook.set_current_page(index) - notebook.set_current_page(notebook.get_current_page()) - - def move_tab(self, term, direction): - dbg("moving to direction %s" % direction) - data = self.get_first_notebook_page(term) - if data is None: - return False - (notebook, page) = data - page_num = notebook.page_num(page) - nbpages = notebook.get_n_pages() - #dbg ("%s %s %s %s" % (page_num, nbpages,notebook, page)) - if page_num == 0 and direction == 'left': - new_page_num = nbpages - elif page_num == nbpages - 1 and direction == 'right': - new_page_num = 0 - elif direction == 'left': - new_page_num = page_num - 1 - elif direction == 'right': - new_page_num = page_num + 1 - else: - dbg("[ERROR] unhandled combination in move_tab: direction = %s page_num = %d" % (direction, page_num)) - return False - notebook.reorder_child(page, new_page_num) - return True - - def get_first_parent_notebook(self, widget): - if isinstance (widget, gtk.Window): - return None - parent = widget.get_parent() - if isinstance (parent, gtk.Notebook): - return parent - return self.get_first_parent_notebook(parent) - - def get_first_parent_widget (self, widget, type): - """This method searches up through the gtk widget heirarchy - of 'widget' until it finds a parent widget of type 'type'""" - while not isinstance(widget.get_parent(), type): - widget = widget.get_parent() - if widget is None: - return widget - - return widget.get_parent() - - def get_first_notebook_page(self, widget): - if isinstance (widget, gtk.Window) or widget is None: - return None - parent = widget.get_parent() - if isinstance (parent, gtk.Notebook): - page = -1 - for i in xrange(0, parent.get_n_pages()): - if parent.get_nth_page(i) == widget: - return (parent, widget) - return self.get_first_notebook_page(parent) - - def reconfigure_vtes (self): - for term in self.term_list: - term.reconfigure_vte () - - def toggle_zoom(self, widget, fontscale = False): - if not self._zoomed: - widget._titlebars = widget._titlebox.get_property ('visible') - dbg ('toggle_zoom: not zoomed. remembered titlebar setting of %s'%widget._titlebars) - if widget._titlebars: - widget._titlebox.hide() - self.zoom_term (widget, fontscale) - else: - dbg ('toggle_zoom: zoomed. restoring titlebar setting of %s'%widget._titlebars) - self.unzoom_term (widget, True) - if widget._titlebars and \ - len(self.term_list) > 1 \ - and \ - (isinstance(widget, TerminatorTerm) and isinstance(widget.get_parent(),gtk.Paned))\ - : - widget._titlebox.show() - - widget._vte.grab_focus() - widget._titlebox.update() - - def zoom_term (self, widget, fontscale = False): - """Maximize to full window an instance of TerminatorTerm.""" - self.old_font = widget._vte.get_font () - self.old_char_height = widget._vte.get_char_height () - self.old_char_width = widget._vte.get_char_width () - self.old_allocation = widget._vte.get_allocation () - self.old_padding = widget._vte.get_padding () - self.old_columns = widget._vte.get_column_count () - self.old_rows = widget._vte.get_row_count () - self.old_parent = widget.get_parent() - - if isinstance(self.old_parent, gtk.Window): - return - if isinstance(self.old_parent, gtk.Notebook): - self.old_page = self.old_parent.get_current_page() - self.old_label = self.old_parent.get_tab_label (self.old_parent.get_nth_page (self.old_page)) - - self.window_child = self.window.get_children()[0] - self.window.remove(self.window_child) - self.old_parent.remove(widget) - self.window.add(widget) - self._zoomed = True - - if fontscale: - self.cnid = widget.connect ("size-allocate", self.zoom_scale_font) - else: - self._maximised = True - - widget._vte.grab_focus () - - def zoom_scale_font (self, widget, allocation): - # Disconnect ourself so we don't get called again - widget.disconnect (self.cnid) - - new_columns = widget._vte.get_column_count () - new_rows = widget._vte.get_row_count () - new_font = widget._vte.get_font () - new_allocation = widget._vte.get_allocation () - - old_alloc = { 'x': self.old_allocation.width - self.old_padding[0], - 'y': self.old_allocation.height - self.old_padding[1] }; - - dbg ('zoom_scale_font: I just went from %dx%d to %dx%d.'%(self.old_columns, self.old_rows, new_columns, new_rows)) - - if (new_rows == self.old_rows) or (new_columns == self.old_columns): - dbg ('zoom_scale_font: At least one of my axes didn not change size. Refusing to zoom') - return - - old_char_spacing = old_alloc['x'] - (self.old_columns * self.old_char_width) - old_line_spacing = old_alloc['y'] - (self.old_rows * self.old_char_height) - dbg ('zoom_scale_font: char. %d = %d - (%d * %d)' % (old_char_spacing, old_alloc['x'], self.old_columns, self.old_char_width)) - dbg ('zoom_scale_font: lines. %d = %d - (%d * %d)' % (old_line_spacing, old_alloc['y'], self.old_rows, self.old_char_height)) - dbg ('zoom_scale_font: Previously my char spacing was %d and my row spacing was %d' % (old_char_spacing, old_line_spacing)) - - old_area = self.old_columns * self.old_rows - new_area = new_columns * new_rows - area_factor = new_area / old_area - dbg ('zoom_scale_font: My area changed from %d characters to %d characters, a factor of %f.'%(old_area, new_area, area_factor)) - - dbg ('zoom_scale_font: Post-scale-factor, char spacing should be %d and row spacing %d' % (old_char_spacing * (area_factor/2), old_line_spacing * (area_factor/2))) - dbg ('zoom_scale_font: char width should be %d, it was %d' % ((new_allocation.width - (old_char_spacing * (area_factor / 2)))/self.old_columns, self.old_char_width)) - dbg ('zoom_scale_font: char height should be %d, it was %d' % ((new_allocation.height - (old_line_spacing * (area_factor / 2)))/self.old_rows, self.old_char_height)) - - new_char_width = (new_allocation.width - (old_char_spacing * (area_factor / 2)))/self.old_columns - new_char_height = (new_allocation.height - (old_line_spacing * (area_factor / 2)))/self.old_rows - font_scaling_factor = min (float(new_char_width) / float(self.old_char_width), float(new_char_height) / float(self.old_char_height)) - - new_font_size = self.old_font.get_size () * font_scaling_factor * 0.9 - if new_font_size < self.old_font.get_size (): - dbg ('zoom_scale_font: new font size would have been smaller. bailing.') - return - - new_font.set_size (new_font_size) - dbg ('zoom_scale_font: Scaled font from %f to %f'%(self.old_font.get_size () / pango.SCALE, new_font.get_size () / pango.SCALE)) - widget._vte.set_font (new_font) - - def unzoom_term (self, widget, fontscale = False): - """Proof of concept: Go back to previous application - widget structure. - """ - if self._zoomed: - if fontscale: - widget._vte.set_font (self.old_font) - self._zoomed = False - self._maximised = False - - self.window.remove(widget) - self.window.add(self.window_child) - if isinstance(self.old_parent, gtk.Notebook): - self.old_parent.insert_page(widget, None, self.old_page) - self.old_parent.set_tab_label(widget, self.old_label) - self.old_parent.set_tab_label_packing(widget, not self.conf.scroll_tabbar, not self.conf.scroll_tabbar, gtk.PACK_START) - if self._tab_reorderable: - self.old_parent.set_tab_reorderable(widget, True) - self.old_parent.set_current_page(self.old_page) - - else: - self.old_parent.add(widget) - - widget._vte.grab_focus () - - def edit_profile (self, widget): - if not self.options: - self.options = ProfileEditor(self) - self.options.go() - - def group_emit (self, terminatorterm, group, type, event): - for term in self.term_list: - if term != terminatorterm and term._group == group: - term._vte.emit (type, event) - - def all_emit (self, terminatorterm, type, event): - for term in self.term_list: - if term != terminatorterm: - term._vte.emit (type, event) - - def group_hoover (self): - if self.autocleangroups: - destroy = [] - for group in self.groupings: - save = False - for term in self.term_list: - if term._group == group: - save = True - - if not save: - destroy.append (group) - - for group in destroy: - self.groupings.remove (group) + return([widget]) + + def group_tab(self, widget): + """Group all the terminals in a tab""" + pass + + def ungroup_tab(self, widget): + """Ungroup all the terminals in a tab""" + pass + + def focus_changed(self, widget): + """We just moved focus to a new terminal""" + for terminal in self.terminals: + terminal.titlebar.update() + return +# vim: set expandtab ts=4 sw=4: diff --git a/terminatorlib/titlebar.py b/terminatorlib/titlebar.py index fc47df9c..569f3d74 100755 --- a/terminatorlib/titlebar.py +++ b/terminatorlib/titlebar.py @@ -8,7 +8,7 @@ import gobject from version import APP_NAME from util import dbg -from newterminator import Terminator +from terminator import Terminator from editablelabel import EditableLabel # pylint: disable-msg=R0904 diff --git a/terminatorlib/window.py b/terminatorlib/window.py index 55e7a6f1..663303db 100755 --- a/terminatorlib/window.py +++ b/terminatorlib/window.py @@ -13,7 +13,7 @@ from translation import _ from version import APP_NAME from container import Container from factory import Factory -from newterminator import Terminator +from terminator import Terminator try: import deskbar.core.keybinder as bindkey