2006-11-10 05:18:31 +00:00
#!/usr/bin/python
2007-07-28 01:33:48 +00:00
# Terminator - multiple gnome terminals in one window
# Copyright (C) 2006-2007 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
2007-08-26 23:24:32 +00:00
import os
import pwd
2006-11-10 05:18:31 +00:00
import sys
import string
2007-07-29 03:43:06 +00:00
import gobject
2006-11-10 05:18:31 +00:00
import gtk
2007-07-29 18:09:33 +00:00
try:
import vte
except:
print '''You need to install python bindings for libvte ("python-vte" in debian/ubuntu)'''
sys.exit (1)
2006-11-10 05:18:31 +00:00
import gconf
import pango
2007-02-25 02:37:56 +00:00
import gnome
2007-05-08 23:15:26 +00:00
import time
2007-08-31 19:27:27 +00:00
import getopt
2007-08-31 19:56:56 +00:00
import math
2006-11-10 05:18:31 +00:00
class TerminatorTerm:
2007-05-08 23:15:26 +00:00
2007-02-24 14:53:10 +00:00
# Our settings
2007-05-08 23:15:26 +00:00
# FIXME: Add commandline and/or gconf options to change these
2006-11-10 05:18:31 +00:00
defaults = {
2007-12-16 17:11:22 +00:00
'gt_dir' : '/apps/gnome-terminal',
'_profile_dir' : '%s/profiles',
2006-11-10 05:18:31 +00:00
'allow_bold' : True,
'audible_bell' : False,
'background' : None,
'background_color' : '#000000',
'backspace_binding' : 'ascii-del',
2007-07-28 00:44:32 +00:00
'delete_binding' : 'delete-sequence',
2006-11-10 05:18:31 +00:00
'cursor_blinks' : False,
'emulation' : 'xterm',
'font_name' : 'Serif 10',
'foreground_color' : '#AAAAAA',
2007-02-24 14:53:10 +00:00
'scrollbar' : True,
2006-11-10 05:18:31 +00:00
'scroll_on_keystroke' : False,
'scroll_on_output' : False,
'scrollback_lines' : 100,
2007-05-08 23:15:26 +00:00
'focus' : 'sloppy',
2007-02-24 14:53:10 +00:00
'visible_bell' : False,
'child_restart' : True,
'link_scheme' : '(news|telnet|nttp|file|http|ftp|https)',
'_link_user' : '[%s]+(:[%s]+)?',
'link_hostchars' : '-A-Za-z0-9',
'link_userchars' : '-A-Za-z0-9',
2007-07-27 22:31:58 +00:00
'link_passchars' : '-A-Za-z0-9,?;.:/!%$^*&~"#\'',
2007-12-03 19:38:55 +00:00
'_palette' : '%s/palette',
2007-12-16 17:00:53 +00:00
'word_chars' : '-A-Za-z0-9,./?%&#:_',
'mouse_autohide' : True,
2006-11-10 05:18:31 +00:00
}
2007-11-09 03:43:11 +00:00
matches = {}
2007-12-03 19:38:55 +00:00
def __init__ (self, term, profile):
2007-12-16 17:11:22 +00:00
self.defaults['profile_dir'] = self.defaults['_profile_dir']%(self.defaults['gt_dir'])
2007-02-24 14:53:10 +00:00
self.defaults['link_user'] = self.defaults['_link_user']%(self.defaults['link_userchars'], self.defaults['link_passchars'])
2007-02-25 03:30:29 +00:00
self.term = term
2006-11-10 05:18:31 +00:00
self.gconf_client = gconf.client_get_default ()
2007-08-31 19:33:39 +00:00
2007-11-16 00:19:05 +00:00
self.profile = None
2007-12-16 17:11:22 +00:00
profiles = self.gconf_client.get_list (self.defaults['gt_dir'] + '/global/profile_list', 'string')
for item in profiles:
if item == profile:
self.profile = '%s/%s'%(self.defaults['profile_dir'], item)
break
2007-11-16 00:19:05 +00:00
if self.profile == None:
2007-08-31 19:33:39 +00:00
print "Error, unable to find profile " + profile
2007-09-20 21:42:59 +00:00
# FIXME: This absolutely should not be an exit, the terminal should fail to spawn. If they all fail, it should exit from the mainloop or something.
2007-08-31 19:33:39 +00:00
sys.exit (2)
2007-12-03 19:38:55 +00:00
self.defaults['palette'] = self.defaults['_palette']%(self.profile)
2007-02-24 14:53:10 +00:00
self.gconf_client.add_dir (self.profile, gconf.CLIENT_PRELOAD_RECURSIVE)
2007-05-08 23:15:26 +00:00
self.gconf_client.add_dir ('/apps/metacity/general', gconf.CLIENT_PRELOAD_RECURSIVE)
2006-11-10 05:18:31 +00:00
2007-07-28 18:36:51 +00:00
self.clipboard = gtk.clipboard_get (gtk.gdk.SELECTION_CLIPBOARD)
2007-02-25 02:37:56 +00:00
2006-11-10 05:18:31 +00:00
self._vte = vte.Terminal ()
2007-11-09 04:43:05 +00:00
self._vte.set_size (80, 24)
2006-11-10 05:18:31 +00:00
self.reconfigure_vte ()
2007-02-24 14:53:10 +00:00
self._vte.show ()
2006-11-10 05:18:31 +00:00
self._box = gtk.HBox ()
self._scrollbar = gtk.VScrollbar (self._vte.get_adjustment ())
2007-02-24 14:53:10 +00:00
if self.defaults['scrollbar']:
self._scrollbar.show ()
2006-11-10 05:18:31 +00:00
self._box.pack_start (self._vte)
self._box.pack_start (self._scrollbar, False)
2007-02-24 14:53:10 +00:00
self.gconf_client.notify_add (self.profile, self.on_gconf_notification)
2007-05-08 23:15:26 +00:00
self.gconf_client.notify_add ('/apps/metacity/general/focus_mode', self.on_gconf_notification)
2006-11-10 05:18:31 +00:00
2007-10-13 23:11:29 +00:00
self._vte.connect ("key-press-event", self.on_vte_key_press)
2006-11-10 05:18:31 +00:00
self._vte.connect ("button-press-event", self.on_vte_button_press)
2006-11-17 07:23:04 +00:00
self._vte.connect ("popup-menu", self.on_vte_popup_menu)
2007-07-28 01:17:37 +00:00
2007-11-09 05:58:47 +00:00
exit_action = self.gconf_client.get_string (self.profile + "/exit_action")
if exit_action == "restart":
2007-07-28 01:17:37 +00:00
self._vte.connect ("child-exited", self.spawn_child)
2007-11-09 05:58:47 +00:00
if exit_action == "close":
self._vte.connect ("child-exited", lambda close_term: self.term.closeterm (self))
2006-11-10 05:18:31 +00:00
2007-05-08 23:15:26 +00:00
self._vte.add_events (gtk.gdk.ENTER_NOTIFY_MASK)
self._vte.connect ("enter_notify_event", self.on_vte_notify_enter)
2006-11-14 08:04:06 +00:00
2007-11-09 03:43:11 +00:00
self.matches['domain'] = self._vte.match_add ('((%s://(%s@)?)|(www|ftp)[%s]*\\.)[%s.]+(:[0-9]*)?'%(self.defaults['link_scheme'], self.defaults['link_user'], self.defaults['link_hostchars'], self.defaults['link_hostchars']))
self.matches['path'] = self._vte.match_add ('((%s://(%s@)?)|(www|ftp)[%s]*\\.)[%s.]+(:[0-9]+)?/[-A-Za-z0-9_$.+!*(),;:@&=?/~#%%]*[^]\'.}>) \t\r\n,\\\]'%(self.defaults['link_scheme'], self.defaults['link_userchars'], self.defaults['link_hostchars'], self.defaults['link_hostchars']))
self.matches['email'] = self._vte.match_add ('(mailto:)?[a-z0-9][a-z0-9.-]*@[a-z0-9][a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)+')
2007-02-24 14:53:10 +00:00
2007-07-28 01:17:37 +00:00
self.spawn_child ()
def spawn_child (self, event=None):
2007-08-26 23:47:42 +00:00
update_records = self.gconf_client.get_bool (self.profile + "/update_records") or True
login = self.gconf_client.get_bool (self.profile + "/login_shell") or False
2007-07-28 18:36:51 +00:00
if self.gconf_client.get_bool (self.profile + "/use_custom_command") == True:
2007-08-26 23:47:42 +00:00
args = self.gconf_client.get_string (self.profile + "/custom_command").split ()
2007-08-31 19:27:27 +00:00
shell = args[0]
2007-07-28 01:17:37 +00:00
else:
2007-08-26 23:24:32 +00:00
shell = pwd.getpwuid (os.getuid ())[6]
2007-08-26 23:47:42 +00:00
args = [os.path.basename (shell)]
self._vte.fork_command (command = shell, argv = args, envv = [], loglastlog = login, logwtmp = update_records, logutmp = update_records)
2006-11-10 05:18:31 +00:00
def reconfigure_vte (self):
2006-11-10 20:15:33 +00:00
# Set our emulation
2006-11-10 05:18:31 +00:00
self._vte.set_emulation (self.defaults['emulation'])
2007-07-16 22:59:17 +00:00
# Set our wordchars
2007-12-16 17:00:53 +00:00
word_chars = self.gconf_client.get_string (self.profile + "/word_chars" or self.defaults['word_chars'])
self._vte.set_word_chars (word_chars)
2007-07-16 22:59:17 +00:00
# Set our mouselation
2007-12-16 17:00:53 +00:00
self._vte.set_mouse_autohide (self.defaults['mouse_autohide'])
2007-07-16 22:59:17 +00:00
# Set our compatibility
2007-07-28 00:44:32 +00:00
backspace = self.gconf_client.get_string (self.profile + "/backspace_binding") or self.defaults['backspace_binding']
2007-07-28 18:36:51 +00:00
delete = self.gconf_client.get_string (self.profile + "/delete_binding") or self.defaults['delete_binding']
2007-07-28 00:44:32 +00:00
# Note, each of the 4 following comments should replace the line beneath it, but the python-vte bindings don't appear to support this constant, so the magic values are being assumed from the C enum :/
if backspace == "ascii-del":
# backbind = vte.ERASE_ASCII_BACKSPACE
backbind = 2
else:
# backbind = vte.ERASE_AUTO_BACKSPACE
backbind = 1
if delete == "escape-sequence":
# delbind = vte.ERASE_DELETE_SEQUENCE
delbind = 3
else:
# delbind = vte.ERASE_AUTO
delbind = 0
self._vte.set_backspace_binding (backbind)
self._vte.set_delete_binding (delbind)
2007-07-16 22:59:17 +00:00
2006-11-10 20:15:33 +00:00
# Set our font, preferably from gconf settings
2007-02-24 14:53:10 +00:00
if self.gconf_client.get_bool (self.profile + "/use_system_font"):
2006-11-10 05:18:31 +00:00
font_name = (self.gconf_client.get_string ("/desktop/gnome/interface/monospace_font_name") or self.defaults['font_name'])
else:
2007-02-24 14:53:10 +00:00
font_name = (self.gconf_client.get_string (self.profile + "/font") or self.defaults['font_name'])
2006-11-10 05:18:31 +00:00
try:
self._vte.set_font (pango.FontDescription (font_name))
except:
pass
2006-11-10 20:15:33 +00:00
# Set our boldness
2007-02-24 14:53:10 +00:00
self._vte.set_allow_bold (self.gconf_client.get_bool (self.profile + "/allow_bold") or self.defaults['allow_bold'])
2006-11-10 20:15:33 +00:00
# Set our color scheme, preferably from gconf settings
2007-07-27 22:31:58 +00:00
palette = self.gconf_client.get_string (self.profile + "/palette") or self.defaults['palette']
2007-07-27 23:33:43 +00:00
if self.gconf_client.get_bool (self.profile + "/use_theme_colors") == True:
2007-08-10 21:44:02 +00:00
fg_color = self._vte.get_style ().text[gtk.STATE_NORMAL]
bg_color = self._vte.get_style ().base[gtk.STATE_NORMAL]
2007-07-27 23:33:43 +00:00
else:
fg_color = gtk.gdk.color_parse (self.gconf_client.get_string (self.profile + "/foreground_color") or self.defaults['foreground_color'])
bg_color = gtk.gdk.color_parse (self.gconf_client.get_string (self.profile + "/background_color") or self.defaults['background_color'])
2007-07-27 22:31:58 +00:00
colors = palette.split (':')
palette = []
for color in colors:
palette.append (gtk.gdk.color_parse (color))
2007-07-27 23:33:43 +00:00
self._vte.set_colors (fg_color, bg_color, palette)
2006-11-10 20:15:33 +00:00
# Set our cursor blinkiness
2007-02-24 14:53:10 +00:00
self._vte.set_cursor_blinks = (self.gconf_client.get_bool (self.profile + "/cursor_blinks") or self.defaults['cursor_blinks'])
2006-11-10 20:15:33 +00:00
# Set our audible belliness
2007-02-24 14:53:10 +00:00
self._vte.set_audible_bell = not (self.gconf_client.get_bool (self.profile + "/silent_bell") or self.defaults['audible_bell'])
2006-11-10 20:15:33 +00:00
self._vte.set_visible_bell (self.defaults['visible_bell'])
# Set our scrolliness
2007-02-24 14:53:10 +00:00
self._vte.set_scrollback_lines (self.gconf_client.get_int (self.profile + "/scrollback_lines") or self.defaults['scrollback_lines'])
self._vte.set_scroll_on_keystroke (self.gconf_client.get_bool (self.profile + "/scroll_on_keystroke") or self.defaults['scroll_on_keystroke'])
self._vte.set_scroll_on_output (self.gconf_client.get_bool (self.profile + "/scroll_on_output") or self.defaults['scroll_on_output'])
2006-11-10 20:15:33 +00:00
2007-05-08 23:15:26 +00:00
# Set our sloppiness
self.focus = self.gconf_client.get_string ("/apps/metacity/general/focus_mode") or self.defaults['focus']
2006-11-10 05:18:31 +00:00
def on_gconf_notification (self, client, cnxn_id, entry, what):
self.reconfigure_vte ()
def on_vte_button_press (self, term, event):
2006-11-10 20:15:33 +00:00
# Left mouse button should transfer focus to this vte widget
2006-11-10 05:18:31 +00:00
if event.button == 1:
self._vte.grab_focus ()
2006-11-17 04:34:15 +00:00
return False
2006-11-10 20:15:33 +00:00
2007-02-27 20:47:02 +00:00
# Right mouse button should display a context menu
2006-11-10 05:18:31 +00:00
if event.button == 3:
2006-11-17 07:23:04 +00:00
self.do_popup (event)
2006-11-10 05:18:31 +00:00
return True
2006-11-14 08:04:06 +00:00
def on_vte_notify_enter (self, term, event):
2007-05-08 23:15:26 +00:00
if (self.focus == "sloppy" or self.focus == "mouse"):
term.grab_focus ()
return False
2006-11-14 08:04:06 +00:00
2007-02-24 14:53:10 +00:00
def do_scrollbar_toggle (self):
if self._scrollbar.get_property ('visible'):
self._scrollbar.hide ()
else:
2007-08-31 19:56:56 +00:00
# We need to make the terminal narrower by the width of the scrollbar
self._vte.set_size (self._vte.get_column_count () - int(math.ceil(self._scrollbar.allocation.width / self._vte.get_char_width ())), self._vte.get_row_count ())
2007-02-24 14:53:10 +00:00
self._scrollbar.show ()
2007-10-13 23:11:29 +00:00
def on_vte_key_press (self, term, event):
keyname = gtk.gdk.keyval_name (event.keyval)
2007-11-07 19:18:19 +00:00
mask = gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK
2007-10-13 23:11:29 +00:00
2007-11-07 19:18:19 +00:00
if (event.state & mask) == mask:
2007-10-13 23:11:29 +00:00
if keyname == 'N':
self.term.go_next (self)
return (True)
elif keyname == "P":
self.term.go_prev (self)
return (True)
elif keyname == 'H':
self.term.splitaxis (self, False)
return (True)
elif keyname == 'V':
self.term.splitaxis (self, True)
return (True)
elif keyname == 'Q':
self.term.closeterm (self)
return (True)
2007-11-29 17:16:04 +00:00
if keyname and (keyname == 'Tab' or keyname.endswith('_Tab')):
2007-11-16 00:19:05 +00:00
if event.state == gtk.gdk.CONTROL_MASK:
self.term.go_next (self)
return (True)
if (event.state & mask) == mask:
self.term.go_prev (self)
return (True)
2007-10-13 23:11:29 +00:00
return (False)
2006-11-17 07:23:04 +00:00
def on_vte_popup_menu (self, term):
self.do_popup ()
def do_popup (self, event = None):
2007-02-24 14:53:10 +00:00
menu = self.create_popup_menu (event)
2006-11-17 07:23:04 +00:00
menu.popup (None, None, None, event.button, event.time)
2007-02-24 14:53:10 +00:00
def create_popup_menu (self, event):
2006-11-17 07:23:04 +00:00
menu = gtk.Menu ()
2007-08-10 21:44:02 +00:00
url = self._vte.match_check (int (event.x / self._vte.get_char_width ()), int (event.y / self._vte.get_char_height ()))
2007-02-25 02:37:56 +00:00
if url:
2007-11-09 03:43:11 +00:00
if url[1] != self.matches['email']:
address = url[0]
nameopen = "_Open Link"
namecopy = "_Copy Link Address"
else:
2007-11-09 04:36:01 +00:00
if url[0][0:7] != "mailto:":
2007-11-09 03:43:11 +00:00
address = "mailto:" + url[0]
else:
address = url[0]
nameopen = "_Send Mail To..."
namecopy = "_Copy Email Address"
item = gtk.MenuItem (nameopen)
item.connect ("activate", lambda menu_item: gnome.url_show (address))
2007-02-25 02:37:56 +00:00
menu.append (item)
2007-11-09 03:43:11 +00:00
item = gtk.MenuItem (namecopy)
2007-02-25 03:30:29 +00:00
item.connect ("activate", lambda menu_item: self.clipboard.set_text (url[0]))
menu.append (item)
2007-02-25 02:37:56 +00:00
2007-02-25 03:30:29 +00:00
item = gtk.MenuItem ()
2007-02-25 02:37:56 +00:00
menu.append (item)
2006-11-17 07:23:04 +00:00
2007-02-25 03:30:29 +00:00
item = gtk.ImageMenuItem (gtk.STOCK_COPY)
item.connect ("activate", lambda menu_item: self._vte.copy_clipboard ())
item.set_sensitive (self._vte.get_has_selection ())
menu.append (item)
2006-11-17 07:23:04 +00:00
item = gtk.ImageMenuItem (gtk.STOCK_PASTE)
item.connect ("activate", lambda menu_item: self._vte.paste_clipboard ())
menu.append (item)
2007-02-25 03:30:29 +00:00
item = gtk.MenuItem ()
menu.append (item)
2007-02-24 14:53:10 +00:00
item = gtk.CheckMenuItem ("Show scrollbar")
item.set_active (self._scrollbar.get_property ('visible'))
item.connect ("toggled", lambda menu_item: self.do_scrollbar_toggle ())
menu.append (item)
2007-07-29 02:06:52 +00:00
item = gtk.MenuItem ()
menu.append (item)
item = gtk.MenuItem ("Split _Horizontally")
2007-08-10 21:37:02 +00:00
item.connect ("activate", lambda menu_item: self.term.splitaxis (self, False))
2007-07-29 02:06:52 +00:00
menu.append (item)
item = gtk.MenuItem ("Split _Vertically")
2007-08-10 21:37:02 +00:00
item.connect ("activate", lambda menu_item: self.term.splitaxis (self, True))
2007-07-29 02:06:52 +00:00
menu.append (item)
2007-07-29 15:41:59 +00:00
item = gtk.MenuItem ()
menu.append (item)
item = gtk.ImageMenuItem (gtk.STOCK_CLOSE)
item.connect ("activate", lambda menu_item: self.term.closeterm (self))
menu.append (item)
2006-11-17 07:23:04 +00:00
menu.show_all ()
return menu
2006-11-10 05:18:31 +00:00
def get_box (self):
return self._box
class Terminator:
2007-11-09 03:19:25 +00:00
def __init__ (self, profile, maximise):
2007-08-31 19:27:27 +00:00
self.profile = profile
2006-11-14 08:04:06 +00:00
self.gconf_client = gconf.client_get_default ()
2006-11-10 05:18:31 +00:00
self.window = gtk.Window ()
2006-11-13 06:47:26 +00:00
self.icon = self.window.render_icon (gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON)
self.window.set_icon (self.icon)
2006-11-10 05:18:31 +00:00
self.window.connect ("delete_event", self.on_delete_event)
self.window.connect ("destroy", self.on_destroy_event)
2007-11-09 03:19:25 +00:00
if maximise:
self.window.maximize ()
2007-11-07 19:57:56 +00:00
self.window.set_property ('allow-shrink', True)
2006-11-10 05:18:31 +00:00
2007-07-29 02:06:52 +00:00
# Start out with just one terminal
# FIXME: This should be really be decided from some kind of profile
2007-08-31 19:27:27 +00:00
term = (TerminatorTerm (self, self.profile))
2007-10-13 23:11:29 +00:00
self.term_list = [term]
2007-07-29 02:06:52 +00:00
self.window.add (term.get_box ())
self.window.show_all ()
2006-11-10 05:18:31 +00:00
def on_delete_event (self, widget, event, data=None):
2007-11-07 19:38:26 +00:00
if len (self.term_list) == 1:
return False
2007-02-25 03:30:29 +00:00
dialog = gtk.Dialog ("Quit?", self.window, gtk.DIALOG_MODAL, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_QUIT, gtk.RESPONSE_ACCEPT))
2007-08-10 21:44:02 +00:00
label = gtk.Label ("Do you really want to quit?")
dialog.vbox.pack_start (label, True, True, 0)
2007-02-25 03:30:29 +00:00
label.show ()
2007-08-10 21:44:02 +00:00
res = dialog.run ()
2007-02-25 03:30:29 +00:00
if res == gtk.RESPONSE_ACCEPT:
return False
dialog.destroy ()
return True
2006-11-10 05:18:31 +00:00
def on_destroy_event (self, widget, data=None):
gtk.main_quit ()
2007-08-10 21:37:02 +00:00
def splitaxis (self, widget, vert=True):
2007-08-31 19:27:27 +00:00
term2 = TerminatorTerm (self, self.profile)
2007-08-10 21:35:06 +00:00
parent = widget.get_box ().get_parent ()
2007-08-10 23:33:00 +00:00
2007-08-10 21:35:06 +00:00
if vert:
pane = gtk.VPaned ()
else:
pane = gtk.HPaned ()
# VTE doesn't seem to cope well with being resized by the window manager. I expect I am supposed to send some kind of WINCH, or just generally connect window resizing events to a callback that will often tell vte about the new size. For now, cheat. Badly.
cols = widget._vte.get_column_count ()
rows = widget._vte.get_row_count ()
allowance = widget._scrollbar.allocation.width + pane.style_get_property ('handle-size')
if vert:
width = cols
height = (rows / 2) - (allowance / widget._vte.get_char_height ())
else:
width = (cols / 2) - (allowance / widget._vte.get_char_width ())
height = rows
widget._vte.set_size (width, height)
term2._vte.set_size (width, height)
if isinstance (parent, gtk.Window):
# We have just one term
if vert:
newpos = parent.allocation.height / 2
else:
newpos = parent.allocation.width / 2
widget.get_box ().reparent (pane)
2007-11-07 19:05:15 +00:00
pane.pack1 (widget.get_box (), True, True)
pane.pack2 (term2.get_box (), True, True)
2007-08-10 23:33:00 +00:00
parent.add (pane)
pane.set_position (newpos)
2007-08-10 21:35:06 +00:00
if isinstance (parent, gtk.Paned):
# We are inside a split term
if vert:
term2._vte.set_size (cols, (rows / 2) - 1)
if (widget.get_box () == parent.get_child1 ()):
widget.get_box ().reparent (pane)
2007-11-07 19:05:15 +00:00
parent.pack1 (pane, True, True)
2007-08-10 21:35:06 +00:00
else:
widget.get_box ().reparent (pane)
2007-11-07 19:05:15 +00:00
parent.pack2 (pane, True, True)
2007-08-10 21:35:06 +00:00
2007-11-07 19:05:15 +00:00
pane.pack1 (widget.get_box (), True, True)
pane.pack2 (term2.get_box (), True, True)
2007-08-10 21:35:06 +00:00
2007-12-16 16:49:49 +00:00
pane.show ()
term2.get_box ().show ()
2007-10-13 23:11:29 +00:00
# insert the term reference into the list
index = self.term_list.index (widget)
self.term_list.insert (index + 1, term2)
widget._vte.grab_focus ()
2007-08-10 21:35:06 +00:00
return (term2)
2007-07-29 15:41:59 +00:00
def closeterm (self, widget):
parent = widget.get_box ().get_parent ()
sibling = None
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
2007-12-16 16:49:49 +00:00
2007-07-29 15:41:59 +00:00
if isinstance (parent, gtk.Paned):
grandparent = parent.get_parent ()
# Discover sibling while all objects exist
if widget.get_box () == parent.get_child1 ():
sibling = parent.get_child2 ()
if widget.get_box () == parent.get_child2 ():
sibling = parent.get_child1 ()
if not sibling:
# something is wrong, give up
print "Error: %s is not a child of %s"%(widget, parent)
return
if not self.closetermreq ():
2007-10-13 23:11:29 +00:00
self.term_list.remove (widget)
2007-07-29 15:41:59 +00:00
grandparent.remove (parent)
sibling.reparent (grandparent)
widget.get_box ().destroy ()
parent.destroy ()
2007-10-13 23:11:29 +00:00
for term in self.term_list:
if term.get_box () == sibling:
term._vte.grab_focus ()
break
2007-07-29 15:41:59 +00:00
return
def closetermreq (self):
dialog = gtk.Dialog ("Close?", self.window, gtk.DIALOG_MODAL, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_CLOSE, gtk.RESPONSE_ACCEPT))
2007-08-10 21:44:02 +00:00
label = gtk.Label ("Do you really want to close this terminal?")
dialog.vbox.pack_start (label, True, True, 0)
2007-07-29 15:41:59 +00:00
label.show ()
2007-08-10 21:44:02 +00:00
res = dialog.run ()
2007-07-29 15:41:59 +00:00
dialog.destroy ()
if res == gtk.RESPONSE_ACCEPT:
return False
return True
2007-10-13 23:11:29 +00:00
def go_next (self, term):
current = self.term_list.index (term)
next = current
if current == len (self.term_list) - 1:
next = 0
else:
next += 1
self.term_list[next]._vte.grab_focus ()
def go_prev (self, term):
current = self.term_list.index (term)
previous = current
if current == 0:
previous = len (self.term_list) - 1
else:
previous -= 1
self.term_list[previous]._vte.grab_focus ()
2007-08-31 19:27:27 +00:00
def usage ():
2007-10-13 23:15:51 +00:00
print """Terminator by Chris Jones <cmsj@tenshu.net>
2007-08-31 19:33:39 +00:00
Usage: terminator [OPTION]...
-h, --help Show this usage information
-d, --debug Enable debugging
2007-11-09 03:19:25 +00:00
-m, --maximise Maximise the terminator window when it starts
2007-11-09 05:23:26 +00:00
-p, --profile=PROFILE Take settings from gnome-terminal profile PROFILE
2007-08-31 19:33:39 +00:00
"""
2007-08-31 19:27:27 +00:00
2007-07-29 02:06:52 +00:00
if __name__ == '__main__':
2007-08-31 19:27:27 +00:00
debug = 0
profile = "Default"
2007-11-09 03:19:25 +00:00
maximise = False
2007-08-31 19:27:27 +00:00
try:
2007-11-09 05:23:26 +00:00
opts, args = getopt.getopt (sys.argv[1:], "hdmp:", ["help", "debug", "maximise", "profile="])
2007-08-31 19:27:27 +00:00
except getopt.GetoptError:
usage ()
sys.exit (2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage ()
sys.exit (0)
if opt in ("-d", "--debug"):
debug = 1
2007-11-09 03:19:25 +00:00
if opt in ("-m", "--maximise"):
maximise = True
2007-11-09 05:23:26 +00:00
if opt in ("-p", "--profile"):
profile = arg
2007-08-31 19:27:27 +00:00
2007-11-09 03:19:25 +00:00
term = Terminator (profile, maximise)
2006-11-10 05:18:31 +00:00
gtk.main ()