2009-08-10 23:42:39 +00:00
|
|
|
#!/usr/bin/python
|
|
|
|
# Terminator by Chris Jones <cmsj@tenshu.net>
|
|
|
|
# GPL v2 only
|
|
|
|
"""terminal.py - classes necessary to provide Terminal widgets"""
|
|
|
|
|
2010-02-01 20:15:53 +00:00
|
|
|
from __future__ import division
|
2009-08-10 23:42:39 +00:00
|
|
|
import sys
|
2009-08-19 00:06:38 +00:00
|
|
|
import os
|
2010-01-25 12:35:34 +00:00
|
|
|
import signal
|
2014-09-19 14:08:08 +00:00
|
|
|
import gi
|
2014-09-19 14:10:43 +00:00
|
|
|
from gi.repository import GLib, GObject, Pango, Gtk, Gdk
|
|
|
|
gi.require_version('Vte', '2.91') # vte-0.38 (gnome-3.14)
|
|
|
|
from gi.repository import Vte
|
2009-10-28 23:07:42 +00:00
|
|
|
import subprocess
|
2010-01-11 20:03:54 +00:00
|
|
|
import urllib
|
2009-08-10 23:42:39 +00:00
|
|
|
|
2013-10-31 16:39:16 +00:00
|
|
|
from util import dbg, err, gerr, spawn_new_terminator, make_uuid
|
2009-09-06 21:55:37 +00:00
|
|
|
import util
|
2009-08-18 11:55:37 +00:00
|
|
|
from config import Config
|
2009-08-19 00:06:38 +00:00
|
|
|
from cwd import get_default_cwd
|
2010-02-20 23:05:51 +00:00
|
|
|
from factory import Factory
|
2010-01-11 20:06:53 +00:00
|
|
|
from terminator import Terminator
|
2009-08-18 12:44:41 +00:00
|
|
|
from titlebar import Titlebar
|
2009-10-08 19:27:49 +00:00
|
|
|
from terminal_popup_menu import TerminalPopupMenu
|
2009-08-18 12:47:46 +00:00
|
|
|
from searchbar import Searchbar
|
2009-09-02 23:52:36 +00:00
|
|
|
from translation import _
|
2010-01-18 19:48:24 +00:00
|
|
|
from signalman import Signalman
|
2009-12-17 23:17:32 +00:00
|
|
|
import plugin
|
2013-08-28 21:09:17 +00:00
|
|
|
from terminatorlib.layoutlauncher import LayoutLauncher
|
2009-08-18 11:55:37 +00:00
|
|
|
|
2009-08-18 12:54:46 +00:00
|
|
|
# pylint: disable-msg=R0904
|
2014-09-19 14:08:08 +00:00
|
|
|
class Terminal(Gtk.VBox):
|
2009-08-10 23:42:39 +00:00
|
|
|
"""Class implementing the VTE widget and its wrappings"""
|
|
|
|
|
2009-08-19 00:06:38 +00:00
|
|
|
__gsignals__ = {
|
2014-09-19 14:08:08 +00:00
|
|
|
'close-term': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'title-change': (GObject.SignalFlags.RUN_LAST, None,
|
|
|
|
(GObject.TYPE_STRING,)),
|
|
|
|
'enumerate': (GObject.SignalFlags.RUN_LAST, None,
|
|
|
|
(GObject.TYPE_INT,)),
|
|
|
|
'group-tab': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'group-tab-toggle': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'ungroup-tab': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'ungroup-all': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'split-horiz': (GObject.SignalFlags.RUN_LAST, None,
|
|
|
|
(GObject.TYPE_STRING,)),
|
|
|
|
'split-vert': (GObject.SignalFlags.RUN_LAST, None,
|
|
|
|
(GObject.TYPE_STRING,)),
|
|
|
|
'rotate-cw': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'rotate-ccw': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'tab-new': (GObject.SignalFlags.RUN_LAST, None,
|
|
|
|
(GObject.TYPE_BOOLEAN, GObject.TYPE_OBJECT)),
|
|
|
|
'tab-top-new': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'focus-in': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'focus-out': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'zoom': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'maximise': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'unzoom': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'resize-term': (GObject.SignalFlags.RUN_LAST, None,
|
|
|
|
(GObject.TYPE_STRING,)),
|
|
|
|
'navigate': (GObject.SignalFlags.RUN_LAST, None,
|
|
|
|
(GObject.TYPE_STRING,)),
|
|
|
|
'tab-change': (GObject.SignalFlags.RUN_LAST, None,
|
|
|
|
(GObject.TYPE_INT,)),
|
|
|
|
'group-all': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'group-all-toggle': (GObject.SignalFlags.RUN_LAST, None, ()),
|
|
|
|
'move-tab': (GObject.SignalFlags.RUN_LAST, None,
|
|
|
|
(GObject.TYPE_STRING,)),
|
2009-08-19 00:06:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TARGET_TYPE_VTE = 8
|
|
|
|
|
2009-09-04 21:12:13 +00:00
|
|
|
terminator = None
|
2009-08-11 22:27:56 +00:00
|
|
|
vte = None
|
2009-08-19 00:06:38 +00:00
|
|
|
terminalbox = None
|
2009-10-06 23:08:13 +00:00
|
|
|
scrollbar = None
|
2010-01-12 00:33:55 +00:00
|
|
|
scrollbar_position = None
|
2009-08-18 12:44:41 +00:00
|
|
|
titlebar = None
|
|
|
|
searchbar = None
|
|
|
|
|
2009-09-04 21:12:13 +00:00
|
|
|
group = None
|
2009-08-19 00:06:38 +00:00
|
|
|
cwd = None
|
2010-01-29 23:52:21 +00:00
|
|
|
origcwd = None
|
2009-09-02 20:10:28 +00:00
|
|
|
command = None
|
2009-08-19 00:06:38 +00:00
|
|
|
clipboard = None
|
2009-09-06 21:55:37 +00:00
|
|
|
pid = None
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-08-18 11:55:37 +00:00
|
|
|
matches = None
|
|
|
|
config = None
|
2009-08-18 12:44:41 +00:00
|
|
|
default_encoding = None
|
2010-01-10 23:47:55 +00:00
|
|
|
custom_encoding = None
|
|
|
|
custom_font_size = None
|
2010-02-27 14:02:16 +00:00
|
|
|
layout_command = None
|
2013-08-27 17:22:00 +00:00
|
|
|
directory = None
|
2009-08-11 22:27:56 +00:00
|
|
|
|
2011-10-07 00:20:54 +00:00
|
|
|
fgcolor_active = None
|
|
|
|
fgcolor_inactive = None
|
|
|
|
bgcolor = None
|
|
|
|
palette_active = None
|
|
|
|
palette_inactive = None
|
|
|
|
|
2009-08-19 00:06:38 +00:00
|
|
|
composite_support = None
|
|
|
|
|
2010-01-10 17:15:14 +00:00
|
|
|
cnxids = None
|
2012-06-24 18:36:39 +00:00
|
|
|
targets_for_new_group = None
|
2009-11-08 01:06:31 +00:00
|
|
|
|
2009-08-10 23:42:39 +00:00
|
|
|
def __init__(self):
|
|
|
|
"""Class initialiser"""
|
2014-09-19 14:08:08 +00:00
|
|
|
GObject.GObject.__init__(self)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-09-04 21:12:13 +00:00
|
|
|
self.terminator = Terminator()
|
2010-01-04 13:11:16 +00:00
|
|
|
self.terminator.register_terminal(self)
|
|
|
|
|
2010-05-15 12:18:22 +00:00
|
|
|
# FIXME: Surely these should happen in Terminator::register_terminal()?
|
2009-09-04 21:48:35 +00:00
|
|
|
self.connect('enumerate', self.terminator.do_enumerate)
|
2009-10-08 23:22:01 +00:00
|
|
|
self.connect('focus-in', self.terminator.focus_changed)
|
2012-06-24 18:36:39 +00:00
|
|
|
self.connect('focus-out', self.terminator.focus_left)
|
2009-09-04 21:48:35 +00:00
|
|
|
|
2009-08-18 11:55:37 +00:00
|
|
|
self.matches = {}
|
2010-01-18 19:48:24 +00:00
|
|
|
self.cnxids = Signalman()
|
2009-08-18 11:55:37 +00:00
|
|
|
|
|
|
|
self.config = Config()
|
2009-08-11 22:27:56 +00:00
|
|
|
|
2009-08-19 00:06:38 +00:00
|
|
|
self.cwd = get_default_cwd()
|
2010-01-29 23:52:21 +00:00
|
|
|
self.origcwd = self.terminator.origcwd
|
2014-09-19 14:10:43 +00:00
|
|
|
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2011-02-23 21:46:55 +00:00
|
|
|
self.pending_on_vte_size_allocate = False
|
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
self.vte = Vte.Terminal()
|
2009-08-11 22:48:19 +00:00
|
|
|
self.vte._expose_data = None
|
2009-10-01 21:15:50 +00:00
|
|
|
if not hasattr(self.vte, "set_opacity") or \
|
|
|
|
not hasattr(self.vte, "is_composited"):
|
2009-08-19 00:06:38 +00:00
|
|
|
self.composite_support = False
|
2010-01-21 20:36:18 +00:00
|
|
|
else:
|
|
|
|
self.composite_support = True
|
2010-01-21 20:58:07 +00:00
|
|
|
dbg('composite_support: %s' % self.composite_support)
|
|
|
|
|
2009-08-11 22:48:19 +00:00
|
|
|
self.vte.show()
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-08-18 12:44:41 +00:00
|
|
|
self.default_encoding = self.vte.get_encoding()
|
2009-08-18 11:55:37 +00:00
|
|
|
self.update_url_matches(self.config['try_posix_regexp'])
|
|
|
|
|
2009-08-19 00:06:38 +00:00
|
|
|
self.terminalbox = self.create_terminalbox()
|
|
|
|
|
2010-01-18 23:27:22 +00:00
|
|
|
self.titlebar = Titlebar(self)
|
2009-08-19 00:06:38 +00:00
|
|
|
self.titlebar.connect_icon(self.on_group_button_press)
|
2009-09-02 23:52:36 +00:00
|
|
|
self.titlebar.connect('edit-done', self.on_edit_done)
|
2009-09-02 20:18:36 +00:00
|
|
|
self.connect('title-change', self.titlebar.set_terminal_title)
|
2009-10-15 13:17:37 +00:00
|
|
|
self.titlebar.connect('create-group', self.really_create_group)
|
2010-03-23 20:48:04 +00:00
|
|
|
self.titlebar.show_all()
|
2009-09-02 20:18:36 +00:00
|
|
|
|
2009-08-18 12:44:41 +00:00
|
|
|
self.searchbar = Searchbar()
|
2009-11-04 18:06:34 +00:00
|
|
|
self.searchbar.connect('end-search', self.on_search_done)
|
2009-08-18 12:44:41 +00:00
|
|
|
|
|
|
|
self.show()
|
2014-09-19 14:10:43 +00:00
|
|
|
self.pack_start(self.titlebar, False, True, 0)
|
2014-09-19 14:08:08 +00:00
|
|
|
self.pack_start(self.terminalbox, True, True, 0)
|
|
|
|
self.pack_end(self.searchbar, True, True, 0)
|
2009-08-18 12:44:41 +00:00
|
|
|
|
2009-08-19 00:06:38 +00:00
|
|
|
self.connect_signals()
|
|
|
|
|
2012-10-19 03:51:39 +00:00
|
|
|
os.putenv('TERM', self.config['term'])
|
|
|
|
os.putenv('COLORTERM', self.config['colorterm'])
|
2009-08-19 00:06:38 +00:00
|
|
|
|
|
|
|
env_proxy = os.getenv('http_proxy')
|
|
|
|
if not env_proxy:
|
|
|
|
if self.config['http_proxy'] and self.config['http_proxy'] != '':
|
|
|
|
os.putenv('http_proxy', self.config['http_proxy'])
|
2012-04-14 11:15:50 +00:00
|
|
|
self.reconfigure()
|
|
|
|
self.vte.set_size(80, 24)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2010-06-15 13:54:43 +00:00
|
|
|
def get_vte(self):
|
|
|
|
"""This simply returns the vte widget we are using"""
|
|
|
|
return(self.vte)
|
|
|
|
|
2010-05-15 13:51:20 +00:00
|
|
|
def force_set_profile(self, widget, profile):
|
|
|
|
"""Forcibly set our profile"""
|
|
|
|
self.set_profile(widget, profile, True)
|
|
|
|
|
|
|
|
def set_profile(self, _widget, profile, force=False):
|
2009-12-26 20:09:16 +00:00
|
|
|
"""Set our profile"""
|
2010-01-13 23:02:17 +00:00
|
|
|
if profile != self.config.get_profile():
|
2010-05-15 13:51:20 +00:00
|
|
|
self.config.set_profile(profile, force)
|
2010-01-13 23:02:17 +00:00
|
|
|
self.reconfigure()
|
2009-12-26 20:09:16 +00:00
|
|
|
|
|
|
|
def get_profile(self):
|
|
|
|
"""Return our profile name"""
|
|
|
|
return(self.config.profile)
|
|
|
|
|
2010-04-02 15:45:32 +00:00
|
|
|
def get_cwd(self):
|
|
|
|
"""Return our cwd"""
|
2015-06-19 01:58:41 +00:00
|
|
|
# Disabled and reverted to revert to old style cwd detection as only returns None.
|
|
|
|
# return(GLib.filename_from_uri(self.vte.get_current_directory_uri())[0])
|
|
|
|
return(self.terminator.pid_cwd(self.pid))
|
2010-04-02 15:45:32 +00:00
|
|
|
|
2009-11-04 23:42:54 +00:00
|
|
|
def close(self):
|
|
|
|
"""Close ourselves"""
|
2012-04-19 08:18:05 +00:00
|
|
|
dbg('close: called')
|
|
|
|
self.cnxids.remove_signal(self.vte, 'child-exited')
|
2009-11-04 23:42:54 +00:00
|
|
|
self.emit('close-term')
|
2010-01-25 13:00:29 +00:00
|
|
|
try:
|
2012-04-19 08:18:05 +00:00
|
|
|
dbg('close: killing %d' % self.pid)
|
2010-01-25 13:00:29 +00:00
|
|
|
os.kill(self.pid, signal.SIGHUP)
|
2012-04-19 08:18:05 +00:00
|
|
|
except Exception, ex:
|
2010-01-25 13:00:29 +00:00
|
|
|
# We really don't want to care if this failed. Deep OS voodoo is
|
|
|
|
# not what we should be doing.
|
2012-04-19 08:18:05 +00:00
|
|
|
dbg('os.kill failed: %s' % ex)
|
2010-01-25 13:00:29 +00:00
|
|
|
pass
|
2009-11-04 23:42:54 +00:00
|
|
|
|
2009-08-19 00:06:38 +00:00
|
|
|
def create_terminalbox(self):
|
|
|
|
"""Create a GtkHBox containing the terminal and a scrollbar"""
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
terminalbox = Gtk.HBox()
|
2014-09-19 14:10:43 +00:00
|
|
|
self.scrollbar = Gtk.VScrollbar(self.vte.get_vadjustment())
|
2010-01-12 00:33:55 +00:00
|
|
|
self.scrollbar.set_no_show_all(True)
|
|
|
|
self.scrollbar_position = self.config['scrollbar_position']
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2010-01-12 00:33:55 +00:00
|
|
|
if self.scrollbar_position not in ('hidden', 'disabled'):
|
2009-10-06 23:08:13 +00:00
|
|
|
self.scrollbar.show()
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2010-01-12 00:33:55 +00:00
|
|
|
if self.scrollbar_position == 'left':
|
2009-08-19 00:06:38 +00:00
|
|
|
func = terminalbox.pack_end
|
|
|
|
else:
|
|
|
|
func = terminalbox.pack_start
|
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
func(self.vte, True, True, 0)
|
|
|
|
func(self.scrollbar, False, True, 0)
|
2010-03-23 20:48:04 +00:00
|
|
|
terminalbox.show_all()
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2010-03-23 20:48:04 +00:00
|
|
|
return(terminalbox)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-08-18 11:55:37 +00:00
|
|
|
def update_url_matches(self, posix = True):
|
|
|
|
"""Update the regexps used to match URLs"""
|
|
|
|
userchars = "-A-Za-z0-9"
|
|
|
|
passchars = "-A-Za-z0-9,?;.:/!%$^*&~\"#'"
|
|
|
|
hostchars = "-A-Za-z0-9"
|
|
|
|
pathchars = "-A-Za-z0-9_$.+!*(),;:@&=?/~#%'\""
|
|
|
|
schemes = "(news:|telnet:|nntp:|file:/|https?:|ftps?:|webcal:)"
|
|
|
|
user = "[" + userchars + "]+(:[" + passchars + "]+)?"
|
|
|
|
urlpath = "/[" + pathchars + "]*[^]'.}>) \t\r\n,\\\"]"
|
|
|
|
|
|
|
|
if posix:
|
2009-11-14 23:12:58 +00:00
|
|
|
dbg ('Terminal::update_url_matches: Trying POSIX URL regexps')
|
2009-08-18 11:55:37 +00:00
|
|
|
lboundry = "[[:<:]]"
|
|
|
|
rboundry = "[[:>:]]"
|
|
|
|
else: # GNU
|
2009-11-14 23:12:58 +00:00
|
|
|
dbg ('Terminal::update_url_matches: Trying GNU URL regexps')
|
2009-08-18 11:55:37 +00:00
|
|
|
lboundry = "\\<"
|
|
|
|
rboundry = "\\>"
|
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
# VERIFY/FIXME FOR GTK3: What's this with the POSIX and GNU mode l/r boundry[sic] values?
|
|
|
|
# Neither of the two works for me since the Vte 0.38 update.
|
|
|
|
# Should we get rid of them and the try_posix_regexp option totally?
|
|
|
|
# They don't seem to be necessary, and there really shouldn't be any difference
|
|
|
|
# between Linux and non-Linux systems, GLib should hide this (does it?).
|
|
|
|
lboundry = ''
|
|
|
|
rboundry = ''
|
|
|
|
|
|
|
|
re = (lboundry + schemes +
|
2009-08-18 11:55:37 +00:00
|
|
|
"//(" + user + "@)?[" + hostchars +".]+(:[0-9]+)?(" +
|
|
|
|
urlpath + ")?" + rboundry + "/?")
|
2014-09-19 14:10:43 +00:00
|
|
|
reg = GLib.Regex.new(re, GLib.RegexCompileFlags.OPTIMIZE, 0)
|
|
|
|
self.matches['full_uri'] = self.vte.match_add_gregex(reg, 0)
|
2009-08-18 11:55:37 +00:00
|
|
|
|
|
|
|
if self.matches['full_uri'] == -1:
|
|
|
|
if posix:
|
2009-12-10 11:52:26 +00:00
|
|
|
err ('Terminal::update_url_matches: POSIX failed, trying GNU')
|
2009-08-18 11:55:37 +00:00
|
|
|
self.update_url_matches(posix = False)
|
|
|
|
else:
|
2009-12-10 11:52:26 +00:00
|
|
|
err ('Terminal::update_url_matches: Failed adding URL matches')
|
2009-08-18 11:55:37 +00:00
|
|
|
else:
|
2014-09-19 14:10:43 +00:00
|
|
|
re = (lboundry +
|
2009-08-18 11:55:37 +00:00
|
|
|
'(callto:|h323:|sip:)' + "[" + userchars + "+][" +
|
|
|
|
userchars + ".]*(:[0-9]+)?@?[" + pathchars + "]+" +
|
|
|
|
rboundry)
|
2014-09-19 14:10:43 +00:00
|
|
|
reg = GLib.Regex.new(re, GLib.RegexCompileFlags.OPTIMIZE, 0)
|
|
|
|
self.matches['voip'] = self.vte.match_add_gregex(reg, 0)
|
|
|
|
re = (lboundry +
|
2009-08-18 11:55:37 +00:00
|
|
|
"(www|ftp)[" + hostchars + "]*\.[" + hostchars +
|
|
|
|
".]+(:[0-9]+)?(" + urlpath + ")?" + rboundry + "/?")
|
2014-09-19 14:10:43 +00:00
|
|
|
reg = GLib.Regex.new(re, GLib.RegexCompileFlags.OPTIMIZE, 0)
|
|
|
|
self.matches['addr_only'] = self.vte.match_add_gregex(reg, 0)
|
|
|
|
re = (lboundry +
|
2010-01-14 13:52:48 +00:00
|
|
|
"(mailto:)?[a-zA-Z0-9][a-zA-Z0-9.+-]*@[a-zA-Z0-9]" +
|
2010-01-19 19:44:23 +00:00
|
|
|
"[a-zA-Z0-9-]*\.[a-zA-Z0-9][a-zA-Z0-9-]+" +
|
2010-01-14 13:52:48 +00:00
|
|
|
"[.a-zA-Z0-9-]*" + rboundry)
|
2014-09-19 14:10:43 +00:00
|
|
|
reg = GLib.Regex.new(re, GLib.RegexCompileFlags.OPTIMIZE, 0)
|
|
|
|
self.matches['email'] = self.vte.match_add_gregex(reg, 0)
|
|
|
|
re = (lboundry +
|
2010-01-19 19:44:23 +00:00
|
|
|
"""news:[-A-Z\^_a-z{|}~!"#$%&'()*+,./0-9;:=?`]+@""" +
|
2010-01-14 13:52:48 +00:00
|
|
|
"[-A-Za-z0-9.]+(:[0-9]+)?" + rboundry)
|
2014-09-19 14:10:43 +00:00
|
|
|
reg = GLib.Regex.new(re, GLib.RegexCompileFlags.OPTIMIZE, 0)
|
|
|
|
self.matches['nntp'] = self.vte.match_add_gregex(reg, 0)
|
2009-08-18 11:55:37 +00:00
|
|
|
|
2009-12-17 23:17:32 +00:00
|
|
|
# Now add any matches from plugins
|
|
|
|
try:
|
|
|
|
registry = plugin.PluginRegistry()
|
|
|
|
registry.load_plugins()
|
|
|
|
plugins = registry.get_plugins_by_capability('url_handler')
|
|
|
|
|
|
|
|
for urlplugin in plugins:
|
|
|
|
name = urlplugin.handler_name
|
|
|
|
match = urlplugin.match
|
2010-06-22 23:48:06 +00:00
|
|
|
if name in self.matches:
|
2012-01-14 20:09:25 +00:00
|
|
|
dbg('refusing to add duplicate match %s' % name)
|
2010-06-22 23:48:06 +00:00
|
|
|
continue
|
2014-09-19 14:10:43 +00:00
|
|
|
reg = GLib.Regex.new(match, GLib.RegexCompileFlags.OPTIMIZE, 0)
|
|
|
|
self.matches[name] = self.vte.match_add_gregex(reg, 0)
|
2012-01-14 20:09:25 +00:00
|
|
|
dbg('added plugin URL handler for %s (%s) as %d' %
|
|
|
|
(name, urlplugin.__class__.__name__,
|
|
|
|
self.matches[name]))
|
2009-12-30 01:50:47 +00:00
|
|
|
except Exception, ex:
|
2012-01-14 20:09:25 +00:00
|
|
|
err('Exception occurred adding plugin URL match: %s' % ex)
|
2010-06-22 23:48:06 +00:00
|
|
|
|
|
|
|
def match_add(self, name, match):
|
|
|
|
"""Register a URL match"""
|
|
|
|
if name in self.matches:
|
|
|
|
err('Terminal::match_add: Refusing to create duplicate match %s' % name)
|
|
|
|
return
|
2014-09-19 14:10:43 +00:00
|
|
|
reg = GLib.Regex.new(match, GLib.RegexCompileFlags.OPTIMIZE, 0)
|
|
|
|
self.matches[name] = self.vte.match_add_gregex(reg, 0)
|
2010-06-22 23:48:06 +00:00
|
|
|
|
|
|
|
def match_remove(self, name):
|
|
|
|
"""Remove a previously registered URL match"""
|
|
|
|
if name not in self.matches:
|
|
|
|
err('Terminal::match_remove: Unable to remove non-existent match %s' % name)
|
|
|
|
return
|
|
|
|
self.vte.match_remove(self.matches[name])
|
|
|
|
del(self.matches[name])
|
|
|
|
|
2009-08-19 00:06:38 +00:00
|
|
|
def connect_signals(self):
|
|
|
|
"""Connect all the gtk signals and drag-n-drop mechanics"""
|
|
|
|
|
2015-06-19 01:32:24 +00:00
|
|
|
self.scrollbar.connect('button-press-event', self.on_buttonpress)
|
|
|
|
|
2009-08-19 00:06:38 +00:00
|
|
|
self.vte.connect('key-press-event', self.on_keypress)
|
|
|
|
self.vte.connect('button-press-event', self.on_buttonpress)
|
2015-03-02 21:03:08 +00:00
|
|
|
self.vte.connect('scroll-event', self.on_mousewheel)
|
2009-08-19 00:06:38 +00:00
|
|
|
self.vte.connect('popup-menu', self.popup_menu)
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
srcvtetargets = [("vte", Gtk.TargetFlags.SAME_APP, self.TARGET_TYPE_VTE)]
|
|
|
|
dsttargets = [("vte", Gtk.TargetFlags.SAME_APP, self.TARGET_TYPE_VTE),
|
2011-08-20 22:18:56 +00:00
|
|
|
('text/x-moz-url', 0, 0),
|
|
|
|
('_NETSCAPE_URL', 0, 0)]
|
2014-09-19 14:10:43 +00:00
|
|
|
# dsttargets = Gtk.target_list_add_text_targets(dsttargets) # FIXME FOR GTK3
|
|
|
|
# dsttargets = Gtk.target_list_add_uri_targets(dsttargets)
|
2011-08-20 22:18:56 +00:00
|
|
|
dbg('Finalised drag targets: %s' % dsttargets)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
# for (widget, mask) in [
|
|
|
|
# (self.vte, Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.BUTTON3_MASK),
|
|
|
|
# (self.titlebar, Gdk.ModifierType.BUTTON1_MASK)]:
|
|
|
|
# widget.drag_source_set(mask, srcvtetargets, Gdk.DragAction.MOVE) # FIXME FOR GTK3
|
|
|
|
#
|
|
|
|
# self.vte.drag_dest_set(Gtk.DestDefaults.MOTION |
|
|
|
|
# Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP,
|
|
|
|
# dsttargets, Gdk.DragAction.COPY | Gdk.DragAction.MOVE) # FIXME FOR GTK3
|
2009-08-19 00:06:38 +00:00
|
|
|
|
|
|
|
for widget in [self.vte, self.titlebar]:
|
|
|
|
widget.connect('drag-begin', self.on_drag_begin, self)
|
|
|
|
widget.connect('drag-data-get', self.on_drag_data_get,
|
|
|
|
self)
|
|
|
|
|
|
|
|
self.vte.connect('drag-motion', self.on_drag_motion, self)
|
|
|
|
self.vte.connect('drag-data-received',
|
|
|
|
self.on_drag_data_received, self)
|
|
|
|
|
2010-01-18 19:48:24 +00:00
|
|
|
# FIXME: Shouldn't this be in configure()?
|
2009-08-19 00:06:38 +00:00
|
|
|
if self.config['copy_on_selection']:
|
2010-01-18 19:48:24 +00:00
|
|
|
self.cnxids.new(self.vte, 'selection-changed',
|
2010-01-10 17:15:14 +00:00
|
|
|
lambda widget: self.vte.copy_clipboard())
|
2009-08-19 00:06:38 +00:00
|
|
|
|
|
|
|
if self.composite_support:
|
2010-01-21 20:36:18 +00:00
|
|
|
self.vte.connect('composited-changed', self.reconfigure)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-09-06 22:53:48 +00:00
|
|
|
self.vte.connect('window-title-changed', lambda x:
|
|
|
|
self.emit('title-change', self.get_window_title()))
|
2009-08-19 00:06:38 +00:00
|
|
|
self.vte.connect('grab-focus', self.on_vte_focus)
|
|
|
|
self.vte.connect('focus-in-event', self.on_vte_focus_in)
|
2011-10-07 00:20:54 +00:00
|
|
|
self.vte.connect('focus-out-event', self.on_vte_focus_out)
|
2011-02-23 21:46:55 +00:00
|
|
|
self.vte.connect('size-allocate', self.deferred_on_vte_size_allocate)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
self.vte.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK)
|
2009-08-19 00:06:38 +00:00
|
|
|
self.vte.connect('enter_notify_event',
|
|
|
|
self.on_vte_notify_enter)
|
|
|
|
|
2010-01-18 19:48:24 +00:00
|
|
|
self.cnxids.new(self.vte, 'realize', self.reconfigure)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-09-02 23:52:36 +00:00
|
|
|
def create_popup_group_menu(self, widget, event = None):
|
|
|
|
"""Pop up a menu for the group widget"""
|
|
|
|
if event:
|
|
|
|
button = event.button
|
|
|
|
time = event.time
|
|
|
|
else:
|
|
|
|
button = 0
|
|
|
|
time = 0
|
|
|
|
|
|
|
|
menu = self.populate_group_menu()
|
|
|
|
menu.show_all()
|
2014-09-19 14:10:43 +00:00
|
|
|
menu.popup(None, None, self.position_popup_group_menu, widget, button, time)
|
2009-09-02 23:52:36 +00:00
|
|
|
return(True)
|
|
|
|
|
|
|
|
def populate_group_menu(self):
|
|
|
|
"""Fill out a group menu"""
|
2014-09-19 14:08:08 +00:00
|
|
|
menu = Gtk.Menu()
|
2014-09-19 14:10:43 +00:00
|
|
|
self.group_menu = menu # from http://stackoverflow.com/questions/21960298/python-gtk3-right-click-menu -- is this the right way?
|
2009-09-02 23:52:36 +00:00
|
|
|
groupitem = None
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
item = Gtk.MenuItem(_('New group...'))
|
2009-09-02 23:52:36 +00:00
|
|
|
item.connect('activate', self.create_group)
|
|
|
|
menu.append(item)
|
2009-11-20 05:40:31 +00:00
|
|
|
|
2009-09-04 21:12:13 +00:00
|
|
|
if len(self.terminator.groups) > 0:
|
2014-09-19 14:10:43 +00:00
|
|
|
groupitem = Gtk.RadioMenuItem(_('None'), groupitem)
|
2009-09-04 21:12:13 +00:00
|
|
|
groupitem.set_active(self.group == None)
|
|
|
|
groupitem.connect('activate', self.set_group, None)
|
|
|
|
menu.append(groupitem)
|
|
|
|
|
|
|
|
for group in self.terminator.groups:
|
2014-09-19 14:10:43 +00:00
|
|
|
item = Gtk.RadioMenuItem(group, groupitem, False) # VERIFY FOR GTK3 what is the last arg?
|
2009-09-04 21:12:13 +00:00
|
|
|
item.set_active(self.group == group)
|
|
|
|
item.connect('toggled', self.set_group, group)
|
|
|
|
menu.append(item)
|
|
|
|
groupitem = item
|
|
|
|
|
|
|
|
if self.group != None or len(self.terminator.groups) > 0:
|
2014-09-19 14:08:08 +00:00
|
|
|
menu.append(Gtk.MenuItem())
|
2009-09-04 21:12:13 +00:00
|
|
|
|
|
|
|
if self.group != None:
|
2014-09-19 14:08:08 +00:00
|
|
|
item = Gtk.MenuItem(_('Remove group %s') % self.group)
|
2009-09-04 21:12:13 +00:00
|
|
|
item.connect('activate', self.ungroup, self.group)
|
|
|
|
menu.append(item)
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
if util.has_ancestor(self, Gtk.Notebook):
|
2014-09-19 14:10:43 +00:00
|
|
|
item = Gtk.MenuItem.new_with_mnemonic(_('G_roup all in tab'))
|
2009-09-06 20:54:33 +00:00
|
|
|
item.connect('activate', lambda x: self.emit('group_tab'))
|
2009-09-04 23:34:09 +00:00
|
|
|
menu.append(item)
|
|
|
|
|
|
|
|
if len(self.terminator.groups) > 0:
|
2014-09-19 14:10:43 +00:00
|
|
|
item = Gtk.MenuItem.new_with_mnemonic(_('Ungr_oup all in tab'))
|
2009-09-06 20:54:33 +00:00
|
|
|
item.connect('activate', lambda x: self.emit('ungroup_tab'))
|
2009-09-04 23:34:09 +00:00
|
|
|
menu.append(item)
|
2009-09-04 21:12:13 +00:00
|
|
|
|
|
|
|
if len(self.terminator.groups) > 0:
|
2014-09-19 14:08:08 +00:00
|
|
|
item = Gtk.MenuItem(_('Remove all groups'))
|
2009-09-06 20:54:33 +00:00
|
|
|
item.connect('activate', lambda x: self.emit('ungroup-all'))
|
2009-09-04 21:12:13 +00:00
|
|
|
menu.append(item)
|
|
|
|
|
|
|
|
if self.group != None:
|
2014-09-19 14:08:08 +00:00
|
|
|
menu.append(Gtk.MenuItem())
|
2009-09-04 21:12:13 +00:00
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
item = Gtk.MenuItem(_('Close group %s') % self.group)
|
2009-09-06 20:54:33 +00:00
|
|
|
item.connect('activate', lambda x:
|
2009-11-04 23:42:54 +00:00
|
|
|
self.terminator.closegroupedterms(self.group))
|
2009-09-04 21:12:13 +00:00
|
|
|
menu.append(item)
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
menu.append(Gtk.MenuItem())
|
2009-09-04 21:12:13 +00:00
|
|
|
|
|
|
|
groupitem = None
|
|
|
|
|
2009-11-20 06:11:12 +00:00
|
|
|
for key, value in {_('Broadcast all'):'all',
|
2009-09-04 21:12:13 +00:00
|
|
|
_('Broadcast group'):'group',
|
2009-11-20 06:11:12 +00:00
|
|
|
_('Broadcast off'):'off'}.items():
|
2014-09-19 14:10:43 +00:00
|
|
|
groupitem = Gtk.RadioMenuItem(key, groupitem)
|
2009-11-20 06:11:12 +00:00
|
|
|
dbg('Terminal::populate_group_menu: %s active: %s' %
|
|
|
|
(key, self.terminator.groupsend ==
|
|
|
|
self.terminator.groupsend_type[value]))
|
2009-09-04 21:12:13 +00:00
|
|
|
groupitem.set_active(self.terminator.groupsend ==
|
|
|
|
self.terminator.groupsend_type[value])
|
|
|
|
groupitem.connect('activate', self.set_groupsend,
|
|
|
|
self.terminator.groupsend_type[value])
|
|
|
|
menu.append(groupitem)
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
menu.append(Gtk.MenuItem())
|
2009-09-04 21:12:13 +00:00
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
item = Gtk.CheckMenuItem(_('Split to this group'))
|
2009-11-09 22:33:17 +00:00
|
|
|
item.set_active(self.config['split_to_group'])
|
2009-09-06 20:54:33 +00:00
|
|
|
item.connect('toggled', lambda x: self.do_splittogroup_toggle())
|
2009-09-04 21:12:13 +00:00
|
|
|
menu.append(item)
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
item = Gtk.CheckMenuItem(_('Autoclean groups'))
|
2009-11-09 22:33:17 +00:00
|
|
|
item.set_active(self.config['autoclean_groups'])
|
2009-09-06 20:54:33 +00:00
|
|
|
item.connect('toggled', lambda x: self.do_autocleangroups_toggle())
|
2009-09-04 21:12:13 +00:00
|
|
|
menu.append(item)
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
menu.append(Gtk.MenuItem())
|
2009-09-04 21:12:13 +00:00
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
item = Gtk.MenuItem(_('Insert terminal number'))
|
2009-09-06 20:54:33 +00:00
|
|
|
item.connect('activate', lambda x: self.emit('enumerate', False))
|
2009-09-04 21:12:13 +00:00
|
|
|
menu.append(item)
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
item = Gtk.MenuItem(_('Insert padded terminal number'))
|
2009-09-06 20:54:33 +00:00
|
|
|
item.connect('activate', lambda x: self.emit('enumerate', True))
|
2009-09-04 21:12:13 +00:00
|
|
|
menu.append(item)
|
2009-09-02 23:52:36 +00:00
|
|
|
|
|
|
|
return(menu)
|
|
|
|
|
|
|
|
def position_popup_group_menu(self, menu, widget):
|
|
|
|
"""Calculate the position of the group popup menu"""
|
2014-09-19 14:08:08 +00:00
|
|
|
_screen_w = Gdk.Screen.width()
|
|
|
|
screen_h = Gdk.Screen.height()
|
2009-09-02 23:52:36 +00:00
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
widget_win = widget.get_window()
|
|
|
|
_something, widget_x, widget_y = widget_win.get_origin() # VERIFY FOR GTK3: what's the first return value?
|
|
|
|
_widget_w = widget_win.get_width()
|
|
|
|
widget_h = widget_win.get_height()
|
2009-09-02 23:52:36 +00:00
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
_menu_w = menu.size_request().width
|
|
|
|
menu_h = menu.size_request().height
|
2009-09-02 23:52:36 +00:00
|
|
|
|
|
|
|
if widget_y + widget_h + menu_h > screen_h:
|
|
|
|
menu_y = max(widget_y - menu_h, 0)
|
|
|
|
else:
|
|
|
|
menu_y = widget_y + widget_h
|
|
|
|
|
|
|
|
return(widget_x, menu_y, 1)
|
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def set_group(self, _item, name):
|
2009-11-04 23:28:09 +00:00
|
|
|
"""Set a particular group"""
|
|
|
|
if self.group == name:
|
|
|
|
# already in this group, no action needed
|
|
|
|
return
|
2009-11-20 06:18:21 +00:00
|
|
|
dbg('Terminal::set_group: Setting group to %s' % name)
|
2009-11-04 23:28:09 +00:00
|
|
|
self.group = name
|
|
|
|
self.titlebar.set_group_label(name)
|
|
|
|
self.terminator.group_hoover()
|
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def create_group(self, _item):
|
2009-10-15 13:17:37 +00:00
|
|
|
"""Trigger the creation of a group via the titlebar (because popup
|
|
|
|
windows are really lame)"""
|
|
|
|
self.titlebar.create_group()
|
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def really_create_group(self, _widget, groupname):
|
2009-10-15 13:17:37 +00:00
|
|
|
"""The titlebar has spoken, let a group be created"""
|
2009-10-27 23:05:12 +00:00
|
|
|
self.terminator.create_group(groupname)
|
2009-11-04 23:28:09 +00:00
|
|
|
self.set_group(None, groupname)
|
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def ungroup(self, _widget, data):
|
2009-11-04 23:28:09 +00:00
|
|
|
"""Remove a group"""
|
|
|
|
# FIXME: Could we emit and have Terminator do this?
|
|
|
|
for term in self.terminator.terminals:
|
|
|
|
if term.group == data:
|
|
|
|
term.set_group(None, None)
|
|
|
|
self.terminator.group_hoover()
|
2009-09-02 23:52:36 +00:00
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def set_groupsend(self, _widget, value):
|
2009-09-04 21:12:13 +00:00
|
|
|
"""Set the groupsend mode"""
|
|
|
|
# FIXME: Can we think of a smarter way of doing this than poking?
|
2009-11-20 06:11:12 +00:00
|
|
|
if value in self.terminator.groupsend_type.values():
|
|
|
|
dbg('Terminal::set_groupsend: setting groupsend to %s' % value)
|
2009-10-27 23:05:12 +00:00
|
|
|
self.terminator.groupsend = value
|
2009-09-04 21:12:13 +00:00
|
|
|
|
|
|
|
def do_splittogroup_toggle(self):
|
|
|
|
"""Toggle the splittogroup mode"""
|
2009-11-09 22:33:17 +00:00
|
|
|
self.config['split_to_group'] = not self.config['split_to_group']
|
2009-09-04 21:12:13 +00:00
|
|
|
|
|
|
|
def do_autocleangroups_toggle(self):
|
|
|
|
"""Toggle the autocleangroups mode"""
|
2009-11-09 22:33:17 +00:00
|
|
|
self.config['autoclean_groups'] = not self.config['autoclean_groups']
|
2009-09-04 21:12:13 +00:00
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def reconfigure(self, _widget=None):
|
2009-08-19 00:06:38 +00:00
|
|
|
"""Reconfigure our settings"""
|
2009-11-08 01:06:31 +00:00
|
|
|
dbg('Terminal::reconfigure')
|
2010-01-18 19:48:24 +00:00
|
|
|
self.cnxids.remove_signal(self.vte, 'realize')
|
2010-01-10 17:35:03 +00:00
|
|
|
|
|
|
|
# Handle child command exiting
|
2010-01-18 19:48:24 +00:00
|
|
|
self.cnxids.remove_signal(self.vte, 'child-exited')
|
2010-01-10 17:35:03 +00:00
|
|
|
|
|
|
|
if self.config['exit_action'] == 'restart':
|
2010-03-05 19:54:39 +00:00
|
|
|
self.cnxids.new(self.vte, 'child-exited', self.spawn_child, True)
|
2010-01-10 17:35:03 +00:00
|
|
|
elif self.config['exit_action'] in ('close', 'left'):
|
2010-01-18 19:48:24 +00:00
|
|
|
self.cnxids.new(self.vte, 'child-exited',
|
2014-09-19 14:10:43 +00:00
|
|
|
lambda x, y: self.emit('close-term'))
|
2009-11-08 01:06:31 +00:00
|
|
|
|
2010-01-10 23:47:55 +00:00
|
|
|
if self.custom_encoding != True:
|
|
|
|
self.vte.set_encoding(self.config['encoding'])
|
|
|
|
self.vte.set_mouse_autohide(self.config['mouse_autohide'])
|
|
|
|
|
|
|
|
backspace = self.config['backspace_binding']
|
|
|
|
delete = self.config['delete_binding']
|
|
|
|
|
|
|
|
try:
|
|
|
|
if backspace == 'ascii-del':
|
2014-09-19 14:10:43 +00:00
|
|
|
backbind = Vte.ERASE_ASCII_DELETE
|
2010-01-24 15:45:47 +00:00
|
|
|
elif backspace == 'control-h':
|
2014-09-19 14:10:43 +00:00
|
|
|
backbind = Vte.ERASE_ASCII_BACKSPACE
|
2010-01-24 15:45:47 +00:00
|
|
|
elif backspace == 'escape-sequence':
|
2014-09-19 14:10:43 +00:00
|
|
|
backbind = Vte.ERASE_DELETE_SEQUENCE
|
2010-01-10 23:47:55 +00:00
|
|
|
else:
|
2014-09-19 14:10:43 +00:00
|
|
|
backbind = Vte.ERASE_AUTO
|
2010-01-10 23:47:55 +00:00
|
|
|
except AttributeError:
|
|
|
|
if backspace == 'ascii-del':
|
|
|
|
backbind = 2
|
2010-01-24 15:45:47 +00:00
|
|
|
elif backspace == 'control-h':
|
2010-01-10 23:47:55 +00:00
|
|
|
backbind = 1
|
2010-01-24 15:45:47 +00:00
|
|
|
elif backspace == 'escape-sequence':
|
|
|
|
backbind = 3
|
|
|
|
else:
|
|
|
|
backbind = 0
|
2010-01-10 23:47:55 +00:00
|
|
|
|
|
|
|
try:
|
2010-01-24 15:45:47 +00:00
|
|
|
if delete == 'ascii-del':
|
2014-09-19 14:10:43 +00:00
|
|
|
delbind = Vte.ERASE_ASCII_DELETE
|
2010-01-24 15:45:47 +00:00
|
|
|
elif delete == 'control-h':
|
2014-09-19 14:10:43 +00:00
|
|
|
delbind = Vte.ERASE_ASCII_BACKSPACE
|
2010-01-24 15:45:47 +00:00
|
|
|
elif delete == 'escape-sequence':
|
2014-09-19 14:10:43 +00:00
|
|
|
delbind = Vte.ERASE_DELETE_SEQUENCE
|
2010-01-10 23:47:55 +00:00
|
|
|
else:
|
2014-09-19 14:10:43 +00:00
|
|
|
delbind = Vte.ERASE_AUTO
|
2010-01-10 23:47:55 +00:00
|
|
|
except AttributeError:
|
2010-01-24 15:45:47 +00:00
|
|
|
if delete == 'ascii-del':
|
|
|
|
delbind = 2
|
|
|
|
elif delete == 'control-h':
|
|
|
|
delbind = 1
|
|
|
|
elif delete == 'escape-sequence':
|
2010-01-10 23:47:55 +00:00
|
|
|
delbind = 3
|
|
|
|
else:
|
|
|
|
delbind = 0
|
|
|
|
|
|
|
|
self.vte.set_backspace_binding(backbind)
|
|
|
|
self.vte.set_delete_binding(delbind)
|
|
|
|
|
|
|
|
if not self.custom_font_size:
|
|
|
|
try:
|
2010-01-21 21:39:05 +00:00
|
|
|
if self.config['use_system_font'] == True:
|
|
|
|
font = self.config.get_system_font()
|
|
|
|
else:
|
|
|
|
font = self.config['font']
|
2014-09-19 14:08:08 +00:00
|
|
|
self.set_font(Pango.FontDescription(font))
|
2010-01-10 23:47:55 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
self.vte.set_allow_bold(self.config['allow_bold'])
|
|
|
|
if self.config['use_theme_colors']:
|
2014-09-19 14:10:43 +00:00
|
|
|
self.fgcolor_active = self.vte.get_style_context().get_color(Gtk.StateType.NORMAL) # VERIFY FOR GTK3: do these really take the theme colors?
|
|
|
|
self.bgcolor = self.vte.get_style_context().get_background_color(Gtk.StateType.NORMAL)
|
2010-01-10 23:47:55 +00:00
|
|
|
else:
|
2014-09-19 14:10:43 +00:00
|
|
|
self.fgcolor_active = Gdk.RGBA()
|
|
|
|
self.fgcolor_active.parse(self.config['foreground_color'])
|
|
|
|
self.bgcolor = Gdk.RGBA()
|
|
|
|
self.bgcolor.parse(self.config['background_color'])
|
|
|
|
|
|
|
|
if self.config['background_type'] == 'transparent':
|
|
|
|
self.bgcolor.alpha = self.config['background_darkness']
|
|
|
|
else:
|
|
|
|
self.bgcolor.alpha = 1
|
2011-10-07 00:20:54 +00:00
|
|
|
|
|
|
|
factor = self.config['inactive_color_offset']
|
2013-05-11 22:09:12 +00:00
|
|
|
if factor > 1.0:
|
|
|
|
factor = 1.0
|
2011-10-07 00:20:54 +00:00
|
|
|
self.fgcolor_inactive = self.fgcolor_active.copy()
|
2013-05-11 22:03:46 +00:00
|
|
|
dbg(("fgcolor_inactive set to: RGB(%s,%s,%s)", getattr(self.fgcolor_inactive, "red"),
|
|
|
|
getattr(self.fgcolor_inactive, "green"),
|
|
|
|
getattr(self.fgcolor_inactive, "blue")))
|
2011-10-07 00:20:54 +00:00
|
|
|
|
|
|
|
for bit in ['red', 'green', 'blue']:
|
|
|
|
setattr(self.fgcolor_inactive, bit,
|
|
|
|
getattr(self.fgcolor_inactive, bit) * factor)
|
2010-01-10 23:47:55 +00:00
|
|
|
|
2013-05-11 22:03:46 +00:00
|
|
|
dbg(("fgcolor_inactive set to: RGB(%s,%s,%s)", getattr(self.fgcolor_inactive, "red"),
|
|
|
|
getattr(self.fgcolor_inactive, "green"),
|
|
|
|
getattr(self.fgcolor_inactive, "blue")))
|
2010-01-10 23:47:55 +00:00
|
|
|
colors = self.config['palette'].split(':')
|
2011-10-07 00:20:54 +00:00
|
|
|
self.palette_active = []
|
|
|
|
self.palette_inactive = []
|
2010-01-10 23:47:55 +00:00
|
|
|
for color in colors:
|
|
|
|
if color:
|
2014-09-19 14:10:43 +00:00
|
|
|
newcolor = Gdk.RGBA()
|
|
|
|
newcolor.parse(color)
|
2011-10-07 00:20:54 +00:00
|
|
|
newcolor_inactive = newcolor.copy()
|
|
|
|
for bit in ['red', 'green', 'blue']:
|
|
|
|
setattr(newcolor_inactive, bit,
|
|
|
|
getattr(newcolor_inactive, bit) * factor)
|
|
|
|
self.palette_active.append(newcolor)
|
|
|
|
self.palette_inactive.append(newcolor_inactive)
|
|
|
|
self.vte.set_colors(self.fgcolor_active, self.bgcolor,
|
|
|
|
self.palette_active)
|
|
|
|
self.set_cursor_color()
|
2014-09-19 14:10:43 +00:00
|
|
|
self.vte.set_cursor_shape(getattr(Vte.CursorShape,
|
|
|
|
self.config['cursor_shape'].upper()));
|
2010-01-10 23:47:55 +00:00
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
if self.config['cursor_blink'] == True:
|
|
|
|
self.vte.set_cursor_blink_mode(Vte.CursorBlinkMode.ON)
|
2010-04-06 20:11:11 +00:00
|
|
|
else:
|
2014-09-19 14:10:43 +00:00
|
|
|
self.vte.set_cursor_blink_mode(Vte.CursorBlinkMode.OFF)
|
2010-01-10 23:47:55 +00:00
|
|
|
|
|
|
|
if self.config['force_no_bell'] == True:
|
|
|
|
self.vte.set_audible_bell(False)
|
2014-09-19 14:10:43 +00:00
|
|
|
self.cnxids.remove_signal(self.vte, 'bell')
|
2010-01-10 23:47:55 +00:00
|
|
|
else:
|
|
|
|
self.vte.set_audible_bell(self.config['audible_bell'])
|
2014-09-19 14:10:43 +00:00
|
|
|
self.cnxids.remove_signal(self.vte, 'bell')
|
2010-02-11 13:05:12 +00:00
|
|
|
if self.config['urgent_bell'] == True or \
|
|
|
|
self.config['icon_bell'] == True:
|
2010-01-21 00:13:56 +00:00
|
|
|
try:
|
2014-09-19 14:10:43 +00:00
|
|
|
self.cnxids.new(self.vte, 'bell', self.on_bell)
|
2010-01-21 00:13:56 +00:00
|
|
|
except TypeError:
|
2014-09-19 14:10:43 +00:00
|
|
|
err('bell signal unavailable with this version of VTE')
|
2010-01-10 23:47:55 +00:00
|
|
|
|
2010-03-24 13:22:37 +00:00
|
|
|
if self.config['scrollback_infinite'] == True:
|
|
|
|
scrollback_lines = -1
|
|
|
|
else:
|
|
|
|
scrollback_lines = self.config['scrollback_lines']
|
|
|
|
self.vte.set_scrollback_lines(scrollback_lines)
|
2010-01-10 23:47:55 +00:00
|
|
|
self.vte.set_scroll_on_keystroke(self.config['scroll_on_keystroke'])
|
|
|
|
self.vte.set_scroll_on_output(self.config['scroll_on_output'])
|
|
|
|
|
2010-01-12 00:33:55 +00:00
|
|
|
if self.scrollbar_position != self.config['scrollbar_position']:
|
|
|
|
self.scrollbar_position = self.config['scrollbar_position']
|
2010-01-21 22:38:52 +00:00
|
|
|
if self.config['scrollbar_position'] in ['disabled', 'hidden']:
|
2010-01-12 00:33:55 +00:00
|
|
|
self.scrollbar.hide()
|
|
|
|
else:
|
|
|
|
self.scrollbar.show()
|
2014-09-19 14:10:43 +00:00
|
|
|
if self.config['scrollbar_position'] == 'left': # FIXME FOR GTK3: moving the scrollbar to the other side (by changing prefs) doesn't work
|
2010-01-12 00:33:55 +00:00
|
|
|
self.reorder_child(self.scrollbar, 0)
|
|
|
|
elif self.config['scrollbar_position'] == 'right':
|
|
|
|
self.reorder_child(self.vte, 0)
|
2010-01-10 23:47:55 +00:00
|
|
|
|
|
|
|
self.titlebar.update()
|
|
|
|
self.vte.queue_draw()
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2011-10-07 00:20:54 +00:00
|
|
|
def set_cursor_color(self):
|
|
|
|
"""Set the cursor color appropriately"""
|
|
|
|
if self.config['cursor_color'] == self.config['foreground_color']:
|
|
|
|
try:
|
|
|
|
self.vte.set_color_cursor(None)
|
|
|
|
except TypeError:
|
|
|
|
# FIXME: I think this is only necessary because of
|
|
|
|
# https://bugzilla.gnome.org/show_bug.cgi?id=614910
|
|
|
|
pass
|
|
|
|
elif self.config['cursor_color'] != '':
|
2014-09-19 14:10:43 +00:00
|
|
|
cursor_color = Gdk.RGBA()
|
|
|
|
cursor_color.parse(self.config['cursor_color'])
|
|
|
|
self.vte.set_color_cursor(cursor_color)
|
2011-10-07 00:20:54 +00:00
|
|
|
|
2009-09-02 20:10:28 +00:00
|
|
|
def get_window_title(self):
|
|
|
|
"""Return the window title"""
|
|
|
|
return(self.vte.get_window_title() or str(self.command))
|
|
|
|
|
2009-09-02 23:52:36 +00:00
|
|
|
def on_group_button_press(self, widget, event):
|
2009-08-19 00:06:38 +00:00
|
|
|
"""Handler for the group button"""
|
2009-09-02 23:52:36 +00:00
|
|
|
if event.button == 1:
|
2014-09-19 14:10:43 +00:00
|
|
|
if event.type == Gdk.EventType._2BUTTON_PRESS or \
|
|
|
|
event.type == Gdk.EventType._3BUTTON_PRESS:
|
2012-06-24 18:42:12 +00:00
|
|
|
# Ignore these, or they make the interaction bad
|
2013-09-03 12:20:22 +00:00
|
|
|
return True
|
2012-06-24 18:42:12 +00:00
|
|
|
# Super key applies interaction to all terms in group
|
2014-09-19 14:08:08 +00:00
|
|
|
include_siblings=event.get_state() & Gdk.ModifierType.MOD4_MASK == Gdk.ModifierType.MOD4_MASK
|
2012-06-24 18:42:12 +00:00
|
|
|
if include_siblings:
|
|
|
|
targets=self.terminator.get_sibling_terms(self)
|
|
|
|
else:
|
|
|
|
targets=[self]
|
2014-09-19 14:08:08 +00:00
|
|
|
if event.get_state() & Gdk.ModifierType.CONTROL_MASK == Gdk.ModifierType.CONTROL_MASK:
|
2012-06-24 18:42:12 +00:00
|
|
|
dbg('on_group_button_press: toggle terminal to focused terminals group')
|
|
|
|
focused=self.get_toplevel().get_focussed_terminal()
|
|
|
|
if focused in targets: targets.remove(focused)
|
|
|
|
if self != focused:
|
|
|
|
if self.group==focused.group:
|
|
|
|
new_group=None
|
|
|
|
else:
|
|
|
|
new_group=focused.group
|
|
|
|
[term.set_group(None, new_group) for term in targets]
|
|
|
|
[term.titlebar.update(focused) for term in targets]
|
|
|
|
return True
|
2014-09-19 14:08:08 +00:00
|
|
|
elif event.get_state() & Gdk.ModifierType.SHIFT_MASK == Gdk.ModifierType.SHIFT_MASK:
|
2012-06-24 18:42:12 +00:00
|
|
|
dbg('on_group_button_press: rename of terminals group')
|
|
|
|
self.targets_for_new_group = targets
|
|
|
|
self.titlebar.create_group()
|
|
|
|
return True
|
2014-09-19 14:08:08 +00:00
|
|
|
elif event.type == Gdk.EventType.BUTTON_PRESS:
|
2012-06-24 18:42:12 +00:00
|
|
|
# Single Click gives popup
|
|
|
|
dbg('on_group_button_press: group menu popup')
|
|
|
|
self.create_popup_group_menu(widget, event)
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
dbg('on_group_button_press: unknown group button interaction')
|
2009-09-02 23:52:36 +00:00
|
|
|
return(False)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-09-06 21:55:37 +00:00
|
|
|
def on_keypress(self, widget, event):
|
2009-08-19 00:06:38 +00:00
|
|
|
"""Handler for keyboard events"""
|
2009-10-14 12:05:07 +00:00
|
|
|
if not event:
|
|
|
|
dbg('Terminal::on_keypress: Called on %s with no event' % widget)
|
|
|
|
return(False)
|
|
|
|
|
|
|
|
# FIXME: Does keybindings really want to live in Terminator()?
|
|
|
|
mapping = self.terminator.keybindings.lookup(event)
|
|
|
|
|
|
|
|
if mapping == "hide_window":
|
|
|
|
return(False)
|
|
|
|
|
2009-12-10 11:52:26 +00:00
|
|
|
if mapping and mapping not in ['close_window',
|
|
|
|
'full_screen',
|
|
|
|
'new_tab']:
|
2009-10-14 12:05:07 +00:00
|
|
|
dbg('Terminal::on_keypress: lookup found: %r' % mapping)
|
|
|
|
# handle the case where user has re-bound copy to ctrl+<key>
|
|
|
|
# we only copy if there is a selection otherwise let it fall through
|
|
|
|
# to ^<key>
|
2014-09-19 14:08:08 +00:00
|
|
|
if (mapping == "copy" and event.get_state() & Gdk.ModifierType.CONTROL_MASK):
|
2009-10-28 12:53:18 +00:00
|
|
|
if self.vte.get_has_selection ():
|
2009-10-14 12:05:07 +00:00
|
|
|
getattr(self, "key_" + mapping)()
|
|
|
|
return(True)
|
2009-10-28 12:53:18 +00:00
|
|
|
else:
|
|
|
|
getattr(self, "key_" + mapping)()
|
|
|
|
return(True)
|
2009-10-14 12:05:07 +00:00
|
|
|
|
|
|
|
# FIXME: This is all clearly wrong. We should be doing this better
|
2010-01-20 23:46:13 +00:00
|
|
|
# maybe we can emit the key event and let Terminator() care?
|
|
|
|
groupsend = self.terminator.groupsend
|
|
|
|
groupsend_type = self.terminator.groupsend_type
|
2011-08-20 13:53:23 +00:00
|
|
|
window_focussed = self.vte.get_toplevel().get_property('has-toplevel-focus')
|
2011-05-11 12:36:47 +00:00
|
|
|
if groupsend != groupsend_type['off'] and window_focussed and self.vte.is_focus():
|
2010-01-20 23:46:13 +00:00
|
|
|
if self.group and groupsend == groupsend_type['group']:
|
2009-10-14 12:05:07 +00:00
|
|
|
self.terminator.group_emit(self, self.group, 'key-press-event',
|
|
|
|
event)
|
2010-01-20 23:46:13 +00:00
|
|
|
if groupsend == groupsend_type['all']:
|
2009-10-14 12:05:07 +00:00
|
|
|
self.terminator.all_emit(self, 'key-press-event', event)
|
|
|
|
|
|
|
|
return(False)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-09-06 21:55:37 +00:00
|
|
|
def on_buttonpress(self, widget, event):
|
2009-08-19 00:06:38 +00:00
|
|
|
"""Handler for mouse events"""
|
2009-09-03 13:47:14 +00:00
|
|
|
# Any button event should grab focus
|
2009-09-06 21:55:37 +00:00
|
|
|
widget.grab_focus()
|
2009-09-03 13:47:14 +00:00
|
|
|
|
2015-06-19 01:32:24 +00:00
|
|
|
if type(widget) == Gtk.VScrollbar and event.type == Gdk.EventType._2BUTTON_PRESS:
|
|
|
|
# Suppress double-click behavior
|
|
|
|
return True
|
|
|
|
|
2009-09-03 13:47:14 +00:00
|
|
|
if event.button == 1:
|
|
|
|
# Ctrl+leftclick on a URL should open it
|
2014-09-19 14:08:08 +00:00
|
|
|
if event.get_state() & Gdk.ModifierType.CONTROL_MASK == Gdk.ModifierType.CONTROL_MASK:
|
2009-09-03 13:47:14 +00:00
|
|
|
url = self.check_for_url(event)
|
|
|
|
if url:
|
|
|
|
self.open_url(url, prepare=True)
|
|
|
|
elif event.button == 2:
|
|
|
|
# middleclick should paste the clipboard
|
|
|
|
self.paste_clipboard(True)
|
|
|
|
return(True)
|
|
|
|
elif event.button == 3:
|
|
|
|
# rightclick should display a context menu if Ctrl is not pressed
|
2014-09-19 14:08:08 +00:00
|
|
|
if event.get_state() & Gdk.ModifierType.CONTROL_MASK == 0:
|
2009-09-06 21:55:37 +00:00
|
|
|
self.popup_menu(widget, event)
|
2009-09-03 13:47:14 +00:00
|
|
|
return(True)
|
|
|
|
|
|
|
|
return(False)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2015-03-02 21:03:08 +00:00
|
|
|
def on_mousewheel(self, widget, event):
|
|
|
|
"""Handler for modifier + mouse wheel scroll events"""
|
|
|
|
SMOOTH_SCROLL_UP = event.direction == Gdk.ScrollDirection.SMOOTH and event.delta_y <= 0.
|
|
|
|
SMOOTH_SCROLL_DOWN = event.direction == Gdk.ScrollDirection.SMOOTH and event.delta_y > 0.
|
|
|
|
if event.state & Gdk.ModifierType.CONTROL_MASK == Gdk.ModifierType.CONTROL_MASK:
|
|
|
|
# Ctrl + mouse wheel up/down
|
|
|
|
if event.direction == Gdk.ScrollDirection.UP or SMOOTH_SCROLL_UP:
|
|
|
|
self.zoom_in()
|
|
|
|
return (True)
|
|
|
|
elif event.direction == Gdk.ScrollDirection.DOWN or SMOOTH_SCROLL_DOWN:
|
|
|
|
self.zoom_out()
|
|
|
|
return (True)
|
|
|
|
if event.state & Gdk.ModifierType.SHIFT_MASK == Gdk.ModifierType.SHIFT_MASK:
|
|
|
|
# Shift + mouse wheel up/down
|
|
|
|
if event.direction == Gdk.ScrollDirection.UP or SMOOTH_SCROLL_UP:
|
|
|
|
self.scroll_by_page(-1)
|
|
|
|
return (True)
|
|
|
|
elif event.direction == Gdk.ScrollDirection.DOWN or SMOOTH_SCROLL_DOWN:
|
|
|
|
self.scroll_by_page(1)
|
|
|
|
return (True)
|
|
|
|
return(False)
|
|
|
|
|
2009-09-03 13:47:14 +00:00
|
|
|
def popup_menu(self, widget, event=None):
|
2009-08-19 00:06:38 +00:00
|
|
|
"""Display the context menu"""
|
2009-10-08 19:27:49 +00:00
|
|
|
menu = TerminalPopupMenu(self)
|
|
|
|
menu.show(widget, event)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-10-06 23:08:13 +00:00
|
|
|
def do_scrollbar_toggle(self):
|
2010-01-23 00:50:28 +00:00
|
|
|
"""Show or hide the terminal scrollbar"""
|
2009-10-06 23:08:13 +00:00
|
|
|
self.toggle_widget_visibility(self.scrollbar)
|
|
|
|
|
|
|
|
def toggle_widget_visibility(self, widget):
|
2010-01-23 00:50:28 +00:00
|
|
|
"""Show or hide a widget"""
|
2009-10-06 23:08:13 +00:00
|
|
|
if widget.get_property('visible'):
|
|
|
|
widget.hide()
|
|
|
|
else:
|
|
|
|
widget.show()
|
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def on_encoding_change(self, _widget, encoding):
|
2009-10-08 20:27:00 +00:00
|
|
|
"""Handle the encoding changing"""
|
|
|
|
current = self.vte.get_encoding()
|
|
|
|
if current != encoding:
|
|
|
|
dbg('on_encoding_change: setting encoding to: %s' % encoding)
|
|
|
|
self.custom_encoding = not (encoding == self.config['encoding'])
|
|
|
|
self.vte.set_encoding(encoding)
|
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def on_drag_begin(self, widget, drag_context, _data):
|
2009-10-27 23:05:12 +00:00
|
|
|
"""Handle the start of a drag event"""
|
|
|
|
widget.drag_source_set_icon_pixbuf(util.widget_pixbuf(self, 512))
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def on_drag_data_get(self, _widget, _drag_context, selection_data, info,
|
|
|
|
_time, data):
|
2009-10-27 23:05:12 +00:00
|
|
|
"""I have no idea what this does, drag and drop is a mystery. sorry."""
|
|
|
|
selection_data.set('vte', info,
|
|
|
|
str(data.terminator.terminals.index(self)))
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def on_drag_motion(self, widget, drag_context, x, y, _time, _data):
|
2009-10-27 23:05:12 +00:00
|
|
|
"""*shrug*"""
|
2013-01-30 10:53:53 +00:00
|
|
|
if not drag_context.targets == ['vte'] and \
|
2014-09-19 14:08:08 +00:00
|
|
|
(Gtk.targets_include_text(drag_context.targets) or \
|
|
|
|
Gtk.targets_include_uri(drag_context.targets)):
|
2009-10-27 23:05:12 +00:00
|
|
|
# copy text from another widget
|
|
|
|
return
|
|
|
|
srcwidget = drag_context.get_source_widget()
|
2014-09-19 14:08:08 +00:00
|
|
|
if(isinstance(srcwidget, Gtk.EventBox) and
|
2009-10-27 23:05:12 +00:00
|
|
|
srcwidget == self.titlebar) or widget == srcwidget:
|
|
|
|
# on self
|
|
|
|
return
|
|
|
|
|
2015-06-19 01:34:30 +00:00
|
|
|
alloc = widget.get_allocation()
|
2014-09-19 14:08:08 +00:00
|
|
|
rect = (0, 0, alloc.width, alloc.height)
|
2009-10-27 23:05:12 +00:00
|
|
|
|
|
|
|
if self.config['use_theme_colors']:
|
2014-09-19 14:10:43 +00:00
|
|
|
color = self.vte.get_style_context().get_color(Gtk.StateType.NORMAL) # VERIFY FOR GTK3 as above
|
2009-10-27 23:05:12 +00:00
|
|
|
else:
|
2014-09-19 14:10:43 +00:00
|
|
|
color = Gdk.RGBA()
|
|
|
|
color.parse(self.config['foreground_color']) # VERIFY FOR GTK3
|
2009-10-27 23:05:12 +00:00
|
|
|
|
|
|
|
pos = self.get_location(widget, x, y)
|
2010-01-23 00:50:28 +00:00
|
|
|
topleft = (0, 0)
|
|
|
|
topright = (alloc.width, 0)
|
|
|
|
topmiddle = (alloc.width/2, 0)
|
2009-10-27 23:05:12 +00:00
|
|
|
bottomleft = (0, alloc.height)
|
2010-01-23 00:50:28 +00:00
|
|
|
bottomright = (alloc.width, alloc.height)
|
2009-10-27 23:05:12 +00:00
|
|
|
bottommiddle = (alloc.width/2, alloc.height)
|
|
|
|
middleleft = (0, alloc.height/2)
|
|
|
|
middleright = (alloc.width, alloc.height/2)
|
|
|
|
#print "%f %f %d %d" %(coef1, coef2, b1,b2)
|
|
|
|
coord = ()
|
|
|
|
if pos == "right":
|
|
|
|
coord = (topright, topmiddle, bottommiddle, bottomright)
|
|
|
|
elif pos == "top":
|
|
|
|
coord = (topleft, topright, middleright , middleleft)
|
|
|
|
elif pos == "left":
|
|
|
|
coord = (topleft, topmiddle, bottommiddle, bottomleft)
|
|
|
|
elif pos == "bottom":
|
|
|
|
coord = (bottomleft, bottomright, middleright , middleleft)
|
|
|
|
|
|
|
|
#here, we define some widget internal values
|
|
|
|
widget._expose_data = { 'color': color, 'coord' : coord }
|
|
|
|
#redraw by forcing an event
|
|
|
|
connec = widget.connect_after('expose-event', self.on_expose_event)
|
|
|
|
widget.window.invalidate_rect(rect, True)
|
|
|
|
widget.window.process_updates(True)
|
|
|
|
#finaly reset the values
|
|
|
|
widget.disconnect(connec)
|
|
|
|
widget._expose_data = None
|
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def on_expose_event(self, widget, _event):
|
2009-10-27 23:05:12 +00:00
|
|
|
"""Handle an expose event while dragging"""
|
|
|
|
if not widget._expose_data:
|
|
|
|
return(False)
|
|
|
|
|
|
|
|
color = widget._expose_data['color']
|
|
|
|
coord = widget._expose_data['coord']
|
|
|
|
|
|
|
|
context = widget.window.cairo_create()
|
|
|
|
context.set_source_rgba(color.red, color.green, color.blue, 0.5)
|
|
|
|
if len(coord) > 0 :
|
2010-01-23 00:50:28 +00:00
|
|
|
context.move_to(coord[len(coord)-1][0], coord[len(coord)-1][1])
|
2009-10-27 23:05:12 +00:00
|
|
|
for i in coord:
|
2010-01-23 00:50:28 +00:00
|
|
|
context.line_to(i[0], i[1])
|
2009-10-27 23:05:12 +00:00
|
|
|
|
|
|
|
context.fill()
|
|
|
|
return(False)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-08-19 18:02:33 +00:00
|
|
|
def on_drag_data_received(self, widget, drag_context, x, y, selection_data,
|
2010-01-23 00:50:28 +00:00
|
|
|
_info, _time, data):
|
|
|
|
"""Something has been dragged into the terminal. Handle it as either a
|
|
|
|
URL or another terminal."""
|
2011-08-20 22:18:56 +00:00
|
|
|
dbg('drag data received of type: %s' % selection_data.type)
|
2014-09-19 14:08:08 +00:00
|
|
|
if Gtk.targets_include_text(drag_context.targets) or \
|
|
|
|
Gtk.targets_include_uri(drag_context.targets):
|
2009-10-27 23:05:12 +00:00
|
|
|
# copy text to destination
|
2012-10-18 21:12:44 +00:00
|
|
|
txt = selection_data.data.strip(' ')
|
2009-10-27 23:05:12 +00:00
|
|
|
if txt[0:7] == 'file://':
|
2010-01-23 00:50:28 +00:00
|
|
|
txt = "'%s'" % urllib.unquote(txt[7:])
|
2013-02-15 15:10:55 +00:00
|
|
|
else:
|
|
|
|
txt = txt.split('\n')[0]
|
2010-01-20 12:11:02 +00:00
|
|
|
for term in self.terminator.get_target_terms(self):
|
2009-10-27 23:05:12 +00:00
|
|
|
term.feed(txt)
|
|
|
|
return
|
|
|
|
|
|
|
|
widgetsrc = data.terminator.terminals[int(selection_data.data)]
|
|
|
|
srcvte = drag_context.get_source_widget()
|
|
|
|
#check if computation requireds
|
2014-09-19 14:08:08 +00:00
|
|
|
if (isinstance(srcvte, Gtk.EventBox) and
|
2009-10-27 23:05:12 +00:00
|
|
|
srcvte == self.titlebar) or srcvte == widget:
|
|
|
|
return
|
|
|
|
|
|
|
|
srchbox = widgetsrc
|
2010-02-20 23:05:51 +00:00
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
# The widget argument is actually a Vte.Terminal(). Turn that into a
|
2010-02-20 23:05:51 +00:00
|
|
|
# terminatorlib Terminal()
|
|
|
|
maker = Factory()
|
|
|
|
while True:
|
|
|
|
widget = widget.get_parent()
|
|
|
|
if not widget:
|
|
|
|
# We've run out of widgets. Something is wrong.
|
2010-03-02 12:39:47 +00:00
|
|
|
err('Failed to find Terminal from vte')
|
2010-02-20 23:05:51 +00:00
|
|
|
return
|
|
|
|
if maker.isinstance(widget, 'Terminal'):
|
|
|
|
break
|
|
|
|
|
|
|
|
dsthbox = widget
|
2009-10-27 23:05:12 +00:00
|
|
|
|
|
|
|
dstpaned = dsthbox.get_parent()
|
|
|
|
srcpaned = srchbox.get_parent()
|
|
|
|
|
|
|
|
pos = self.get_location(widget, x, y)
|
|
|
|
|
2009-11-17 04:56:55 +00:00
|
|
|
srcpaned.remove(widgetsrc)
|
2010-03-08 21:46:45 +00:00
|
|
|
dstpaned.split_axis(dsthbox, pos in ['top', 'bottom'], None, widgetsrc, pos in ['bottom', 'right'])
|
2009-11-20 15:31:07 +00:00
|
|
|
srcpaned.hoover()
|
2010-04-12 20:35:24 +00:00
|
|
|
widgetsrc.ensure_visible_and_focussed()
|
2009-10-27 23:05:12 +00:00
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def get_location(self, term, x, y):
|
2009-10-27 23:05:12 +00:00
|
|
|
"""Get our location within the terminal"""
|
|
|
|
pos = ''
|
|
|
|
#get the diagonales function for the receiving widget
|
2015-06-19 01:34:30 +00:00
|
|
|
term_alloc = term.get_allocation()
|
|
|
|
coef1 = float(term_alloc.height)/float(term_alloc.width)
|
|
|
|
coef2 = -float(term_alloc.height)/float(term_alloc.width)
|
2009-10-27 23:05:12 +00:00
|
|
|
b1 = 0
|
2015-06-19 01:34:30 +00:00
|
|
|
b2 = term_alloc.height
|
2009-10-27 23:05:12 +00:00
|
|
|
#determine position in rectangle
|
2010-01-23 00:50:28 +00:00
|
|
|
#--------
|
|
|
|
#|\ /|
|
|
|
|
#| \ / |
|
|
|
|
#| \/ |
|
|
|
|
#| /\ |
|
|
|
|
#| / \ |
|
|
|
|
#|/ \|
|
|
|
|
#--------
|
2009-10-27 23:05:12 +00:00
|
|
|
if (x*coef1 + b1 > y ) and (x*coef2 + b2 < y ):
|
2009-12-10 11:52:26 +00:00
|
|
|
pos = "right"
|
2009-10-27 23:05:12 +00:00
|
|
|
if (x*coef1 + b1 > y ) and (x*coef2 + b2 > y ):
|
2009-12-10 11:52:26 +00:00
|
|
|
pos = "top"
|
2009-10-27 23:05:12 +00:00
|
|
|
if (x*coef1 + b1 < y ) and (x*coef2 + b2 > y ):
|
2009-12-10 11:52:26 +00:00
|
|
|
pos = "left"
|
2009-10-27 23:05:12 +00:00
|
|
|
if (x*coef1 + b1 < y ) and (x*coef2 + b2 < y ):
|
2009-12-10 11:52:26 +00:00
|
|
|
pos = "bottom"
|
2009-10-27 23:05:12 +00:00
|
|
|
return pos
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-11-09 22:35:55 +00:00
|
|
|
def grab_focus(self):
|
2010-01-23 00:50:28 +00:00
|
|
|
"""Steal focus for this terminal"""
|
2015-02-25 23:07:14 +00:00
|
|
|
if not self.vte.has_focus():
|
|
|
|
self.vte.grab_focus()
|
2009-11-09 22:35:55 +00:00
|
|
|
|
2010-04-12 20:35:24 +00:00
|
|
|
def ensure_visible_and_focussed(self):
|
|
|
|
"""Make sure that we're visible and focussed"""
|
2011-02-23 21:35:10 +00:00
|
|
|
window = self.get_toplevel()
|
2010-04-12 20:35:24 +00:00
|
|
|
topchild = window.get_child()
|
|
|
|
maker = Factory()
|
|
|
|
|
|
|
|
if maker.isinstance(topchild, 'Notebook'):
|
2013-12-18 17:06:59 +00:00
|
|
|
# Find which page number this term is on
|
|
|
|
tabnum = topchild.page_num_descendant(self)
|
|
|
|
# If terms page number is not the current one, switch to it
|
|
|
|
current_page = topchild.get_current_page()
|
|
|
|
if tabnum != current_page:
|
|
|
|
topchild.set_current_page(tabnum)
|
2010-04-12 20:35:24 +00:00
|
|
|
|
|
|
|
self.grab_focus()
|
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def on_vte_focus(self, _widget):
|
|
|
|
"""Update our UI when we get focus"""
|
2009-10-27 23:05:12 +00:00
|
|
|
self.emit('title-change', self.get_window_title())
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def on_vte_focus_in(self, _widget, _event):
|
|
|
|
"""Inform other parts of the application when focus is received"""
|
2011-10-07 00:20:54 +00:00
|
|
|
self.vte.set_colors(self.fgcolor_active, self.bgcolor,
|
|
|
|
self.palette_active)
|
|
|
|
self.set_cursor_color()
|
2013-11-19 11:46:11 +00:00
|
|
|
if not self.terminator.doing_layout:
|
|
|
|
self.terminator.last_focused_term = self
|
|
|
|
if self.get_toplevel().is_child_notebook():
|
2013-12-18 17:06:59 +00:00
|
|
|
notebook = self.get_toplevel().get_children()[0]
|
|
|
|
notebook.set_last_active_term(self.uuid)
|
|
|
|
notebook.clean_last_active_term()
|
2013-11-19 11:46:11 +00:00
|
|
|
self.get_toplevel().last_active_term = None
|
|
|
|
else:
|
|
|
|
self.get_toplevel().last_active_term = self.uuid
|
2009-10-08 23:22:01 +00:00
|
|
|
self.emit('focus-in')
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2011-10-07 00:20:54 +00:00
|
|
|
def on_vte_focus_out(self, _widget, _event):
|
|
|
|
"""Inform other parts of the application when focus is lost"""
|
|
|
|
self.vte.set_colors(self.fgcolor_inactive, self.bgcolor,
|
|
|
|
self.palette_inactive)
|
|
|
|
self.set_cursor_color()
|
|
|
|
self.emit('focus-out')
|
|
|
|
|
2010-07-03 19:00:04 +00:00
|
|
|
def on_window_focus_out(self):
|
|
|
|
"""Update our UI when the window loses focus"""
|
|
|
|
self.titlebar.update('window-focus-out')
|
|
|
|
|
2009-11-04 18:06:34 +00:00
|
|
|
def scrollbar_jump(self, position):
|
|
|
|
"""Move the scrollbar to a particular row"""
|
|
|
|
self.scrollbar.set_value(position)
|
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def on_search_done(self, _widget):
|
2009-11-04 18:06:34 +00:00
|
|
|
"""We've finished searching, so clean up"""
|
|
|
|
self.searchbar.hide()
|
|
|
|
self.scrollbar.set_value(self.vte.get_cursor_position()[1])
|
|
|
|
self.vte.grab_focus()
|
|
|
|
|
2010-01-23 00:50:28 +00:00
|
|
|
def on_edit_done(self, _widget):
|
2009-09-02 23:52:36 +00:00
|
|
|
"""A child widget is done editing a label, return focus to VTE"""
|
|
|
|
self.vte.grab_focus()
|
|
|
|
|
2011-02-23 21:46:55 +00:00
|
|
|
def deferred_on_vte_size_allocate(self, widget, allocation):
|
|
|
|
# widget & allocation are not used in on_vte_size_allocate, so we
|
|
|
|
# can use the on_vte_size_allocate instead of duplicating the code
|
|
|
|
if self.pending_on_vte_size_allocate == True:
|
|
|
|
return
|
|
|
|
self.pending_on_vte_size_allocate = True
|
2014-09-19 14:08:08 +00:00
|
|
|
GObject.idle_add(self.do_deferred_on_vte_size_allocate, widget, allocation)
|
2011-02-23 21:46:55 +00:00
|
|
|
|
|
|
|
def do_deferred_on_vte_size_allocate(self, widget, allocation):
|
|
|
|
self.pending_on_vte_size_allocate = False
|
|
|
|
self.on_vte_size_allocate(widget, allocation)
|
|
|
|
|
2009-08-19 18:02:33 +00:00
|
|
|
def on_vte_size_allocate(self, widget, allocation):
|
|
|
|
self.titlebar.update_terminal_size(self.vte.get_column_count(),
|
|
|
|
self.vte.get_row_count())
|
2014-09-19 14:10:43 +00:00
|
|
|
if self.config['geometry_hinting']:
|
2011-02-23 21:35:10 +00:00
|
|
|
window = self.get_toplevel()
|
2011-02-23 21:46:55 +00:00
|
|
|
window.deferred_set_rough_geometry_hints()
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-08-19 18:02:33 +00:00
|
|
|
def on_vte_notify_enter(self, term, event):
|
2009-10-27 23:05:12 +00:00
|
|
|
"""Handle the mouse entering this terminal"""
|
2010-02-07 11:59:57 +00:00
|
|
|
# FIXME: This shouldn't be looking up all these values every time
|
2010-01-21 21:39:05 +00:00
|
|
|
sloppy = False
|
|
|
|
if self.config['focus'] == 'system':
|
2010-02-07 11:59:57 +00:00
|
|
|
sloppy = self.config.get_system_focus() in ['sloppy', 'mouse']
|
2010-01-21 21:39:05 +00:00
|
|
|
elif self.config['focus'] in ['sloppy', 'mouse']:
|
|
|
|
sloppy = True
|
|
|
|
if sloppy == True and self.titlebar.editing() == False:
|
|
|
|
term.grab_focus()
|
|
|
|
return(False)
|
2009-08-19 00:06:38 +00:00
|
|
|
|
2009-11-14 18:55:51 +00:00
|
|
|
def get_zoom_data(self):
|
|
|
|
"""Return a dict of information for Window"""
|
|
|
|
data = {}
|
|
|
|
data['old_font'] = self.vte.get_font()
|
|
|
|
data['old_char_height'] = self.vte.get_char_height()
|
|
|
|
data['old_char_width'] = self.vte.get_char_width()
|
|
|
|
data['old_allocation'] = self.vte.get_allocation()
|
|
|
|
data['old_padding'] = self.vte.get_padding()
|
|
|
|
data['old_columns'] = self.vte.get_column_count()
|
|
|
|
data['old_rows'] = self.vte.get_row_count()
|
|
|
|
data['old_parent'] = self.get_parent()
|
|
|
|
|
|
|
|
return(data)
|
|
|
|
|
|
|
|
def zoom_scale(self, widget, allocation, old_data):
|
|
|
|
"""Scale our font correctly based on how big we are not vs before"""
|
2010-02-27 14:38:01 +00:00
|
|
|
self.cnxids.remove_signal(self, 'size-allocate')
|
|
|
|
# FIXME: Is a zoom signal actualy used anywhere?
|
2010-01-18 19:48:24 +00:00
|
|
|
self.cnxids.remove_signal(self, 'zoom')
|
2009-11-14 18:55:51 +00:00
|
|
|
|
|
|
|
new_columns = self.vte.get_column_count()
|
|
|
|
new_rows = self.vte.get_row_count()
|
|
|
|
new_font = self.vte.get_font()
|
|
|
|
new_allocation = self.vte.get_allocation()
|
|
|
|
|
|
|
|
old_alloc = {'x': old_data['old_allocation'].width - \
|
|
|
|
old_data['old_padding'][0],
|
|
|
|
'y': old_data['old_allocation'].height - \
|
|
|
|
old_data['old_padding'][1]
|
|
|
|
}
|
|
|
|
|
|
|
|
dbg('Terminal::zoom_scale: Resized from %dx%d to %dx%d' % (
|
|
|
|
old_data['old_columns'],
|
|
|
|
old_data['old_rows'],
|
|
|
|
new_columns,
|
|
|
|
new_rows))
|
|
|
|
|
2009-12-10 11:52:26 +00:00
|
|
|
if new_rows == old_data['old_rows'] or \
|
|
|
|
new_columns == old_data['old_columns']:
|
2009-11-14 18:55:51 +00:00
|
|
|
dbg('Terminal::zoom_scale: One axis unchanged, not scaling')
|
|
|
|
return
|
|
|
|
|
|
|
|
old_area = old_data['old_columns'] * old_data['old_rows']
|
|
|
|
new_area = new_columns * new_rows
|
|
|
|
area_factor = (new_area / old_area) / 2
|
|
|
|
|
2010-02-01 20:15:53 +00:00
|
|
|
new_size = int(old_data['old_font'].get_size() * area_factor)
|
|
|
|
if new_size == 0:
|
2010-02-27 14:38:01 +00:00
|
|
|
err('refusing to set a zero sized font')
|
2010-02-01 20:15:53 +00:00
|
|
|
return
|
|
|
|
new_font.set_size(new_size)
|
|
|
|
dbg('setting new font: %s' % new_font)
|
2010-07-13 12:50:33 +00:00
|
|
|
self.set_font(new_font)
|
2009-11-14 18:55:51 +00:00
|
|
|
|
2009-10-06 23:08:13 +00:00
|
|
|
def is_zoomed(self):
|
|
|
|
"""Determine if we are a zoomed terminal"""
|
2009-11-14 18:55:51 +00:00
|
|
|
prop = None
|
|
|
|
parent = self.get_parent()
|
2011-02-23 21:35:10 +00:00
|
|
|
window = self.get_toplevel()
|
2009-10-06 23:08:13 +00:00
|
|
|
|
|
|
|
try:
|
2009-11-14 18:55:51 +00:00
|
|
|
prop = window.get_property('term-zoomed')
|
2009-10-06 23:08:13 +00:00
|
|
|
except TypeError:
|
|
|
|
prop = False
|
|
|
|
|
|
|
|
return(prop)
|
|
|
|
|
2009-11-14 18:55:51 +00:00
|
|
|
def zoom(self, widget=None):
|
2009-10-06 23:08:13 +00:00
|
|
|
"""Zoom ourself to fill the window"""
|
2009-10-12 21:05:19 +00:00
|
|
|
self.emit('zoom')
|
2009-10-06 23:08:13 +00:00
|
|
|
|
2009-11-14 18:55:51 +00:00
|
|
|
def maximise(self, widget=None):
|
2009-10-06 23:08:13 +00:00
|
|
|
"""Maximise ourself to fill the window"""
|
2009-10-12 21:05:19 +00:00
|
|
|
self.emit('maximise')
|
2009-10-06 23:08:13 +00:00
|
|
|
|
2009-11-14 18:55:51 +00:00
|
|
|
def unzoom(self, widget=None):
|
|
|
|
"""Restore normal layout"""
|
|
|
|
self.emit('unzoom')
|
|
|
|
|
2010-03-05 22:44:38 +00:00
|
|
|
def set_cwd(self, cwd=None):
|
|
|
|
"""Set our cwd"""
|
|
|
|
if cwd is not None:
|
|
|
|
self.cwd = cwd
|
|
|
|
|
2010-03-19 22:16:08 +00:00
|
|
|
def spawn_child(self, widget=None, respawn=False, debugserver=False):
|
2009-08-19 18:02:33 +00:00
|
|
|
update_records = self.config['update_records']
|
|
|
|
login = self.config['login_shell']
|
|
|
|
args = []
|
|
|
|
shell = None
|
|
|
|
command = None
|
|
|
|
|
2010-02-17 19:57:05 +00:00
|
|
|
if self.terminator.doing_layout == True:
|
|
|
|
dbg('still laying out, refusing to spawn a child')
|
|
|
|
return
|
|
|
|
|
2010-03-05 19:54:39 +00:00
|
|
|
if respawn == False:
|
|
|
|
self.vte.grab_focus()
|
2009-11-08 23:06:26 +00:00
|
|
|
|
2010-01-18 22:56:43 +00:00
|
|
|
options = self.config.options_get()
|
2010-02-21 11:58:17 +00:00
|
|
|
if options and options.command:
|
2010-01-18 22:56:43 +00:00
|
|
|
command = options.command
|
|
|
|
options.command = None
|
2010-02-21 11:58:17 +00:00
|
|
|
elif options and options.execute:
|
2010-01-18 22:56:43 +00:00
|
|
|
command = options.execute
|
|
|
|
options.execute = None
|
|
|
|
elif self.config['use_custom_command']:
|
2009-08-19 18:02:33 +00:00
|
|
|
command = self.config['custom_command']
|
2010-02-27 14:02:16 +00:00
|
|
|
elif self.layout_command:
|
|
|
|
command = self.layout_command
|
2010-03-19 22:16:08 +00:00
|
|
|
elif debugserver is True:
|
|
|
|
details = self.terminator.debug_address
|
|
|
|
dbg('spawning debug session with: %s:%s' % (details[0],
|
|
|
|
details[1]))
|
|
|
|
command = 'telnet %s %s' % (details[0], details[1])
|
2009-08-19 18:02:33 +00:00
|
|
|
|
2013-08-27 17:22:00 +00:00
|
|
|
# working directory set in layout config
|
|
|
|
if self.directory:
|
|
|
|
self.set_cwd(self.directory)
|
|
|
|
# working directory given as argument
|
|
|
|
elif options and options.working_directory and \
|
2010-03-31 13:02:55 +00:00
|
|
|
options.working_directory != '':
|
|
|
|
self.set_cwd(options.working_directory)
|
|
|
|
options.working_directory = ''
|
|
|
|
|
2010-01-18 22:56:43 +00:00
|
|
|
if type(command) is list:
|
|
|
|
shell = util.path_lookup(command[0])
|
|
|
|
args = command
|
2009-08-19 18:02:33 +00:00
|
|
|
else:
|
2010-01-18 22:56:43 +00:00
|
|
|
shell = util.shell_lookup()
|
|
|
|
|
|
|
|
if self.config['login_shell']:
|
|
|
|
args.insert(0, "-%s" % shell)
|
|
|
|
else:
|
|
|
|
args.insert(0, shell)
|
2009-08-19 18:02:33 +00:00
|
|
|
|
2010-01-18 22:56:43 +00:00
|
|
|
if command is not None:
|
|
|
|
args += ['-c', command]
|
2009-08-19 18:02:33 +00:00
|
|
|
|
|
|
|
if shell is None:
|
|
|
|
self.vte.feed(_('Unable to find a shell'))
|
|
|
|
return(-1)
|
|
|
|
|
2009-11-07 01:40:43 +00:00
|
|
|
try:
|
|
|
|
os.putenv('WINDOWID', '%s' % self.vte.get_parent_window().xid)
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
2009-08-19 18:02:33 +00:00
|
|
|
|
2011-08-25 21:10:04 +00:00
|
|
|
envv = []
|
2012-10-19 03:51:39 +00:00
|
|
|
envv.append('TERM=%s' % self.config['term'])
|
|
|
|
envv.append('COLORTERM=%s' % self.config['colorterm'])
|
2011-08-25 21:10:04 +00:00
|
|
|
envv.append('TERMINATOR_UUID=%s' % self.uuid.urn)
|
|
|
|
if self.terminator.dbus_name:
|
|
|
|
envv.append('TERMINATOR_DBUS_NAME=%s' % self.terminator.dbus_name)
|
|
|
|
if self.terminator.dbus_path:
|
|
|
|
envv.append('TERMINATOR_DBUS_PATH=%s' % self.terminator.dbus_path)
|
|
|
|
|
2010-01-18 22:56:43 +00:00
|
|
|
dbg('Forking shell: "%s" with args: %s' % (shell, args))
|
2015-06-19 01:38:17 +00:00
|
|
|
result, self.pid = self.vte.spawn_sync(Vte.PtyFlags.DEFAULT,
|
2014-09-19 14:10:43 +00:00
|
|
|
self.cwd,
|
|
|
|
args,
|
|
|
|
envv,
|
|
|
|
GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
None)
|
2009-09-02 20:10:28 +00:00
|
|
|
self.command = shell
|
2009-08-19 18:02:33 +00:00
|
|
|
|
|
|
|
self.titlebar.update()
|
|
|
|
|
|
|
|
if self.pid == -1:
|
|
|
|
self.vte.feed(_('Unable to start shell:') + shell)
|
|
|
|
return(-1)
|
|
|
|
|
2009-09-03 13:47:14 +00:00
|
|
|
def check_for_url(self, event):
|
|
|
|
"""Check if the mouse is over a URL"""
|
|
|
|
return (self.vte.match_check(int(event.x / self.vte.get_char_width()),
|
|
|
|
int(event.y / self.vte.get_char_height())))
|
|
|
|
|
2009-09-04 19:12:35 +00:00
|
|
|
def prepare_url(self, urlmatch):
|
|
|
|
"""Prepare a URL from a VTE match"""
|
|
|
|
url = urlmatch[0]
|
|
|
|
match = urlmatch[1]
|
|
|
|
|
|
|
|
if match == self.matches['email'] and url[0:7] != 'mailto:':
|
|
|
|
url = 'mailto:' + url
|
|
|
|
elif match == self.matches['addr_only'] and url[0:3] == 'ftp':
|
|
|
|
url = 'ftp://' + url
|
|
|
|
elif match == self.matches['addr_only']:
|
|
|
|
url = 'http://' + url
|
2009-12-17 23:17:32 +00:00
|
|
|
elif match in self.matches.values():
|
|
|
|
# We have a match, but it's not a hard coded one, so it's a plugin
|
|
|
|
try:
|
|
|
|
registry = plugin.PluginRegistry()
|
|
|
|
registry.load_plugins()
|
|
|
|
plugins = registry.get_plugins_by_capability('url_handler')
|
|
|
|
|
|
|
|
for urlplugin in plugins:
|
|
|
|
if match == self.matches[urlplugin.handler_name]:
|
|
|
|
newurl = urlplugin.callback(url)
|
|
|
|
if newurl is not None:
|
2009-12-30 01:05:51 +00:00
|
|
|
dbg('Terminal::prepare_url: URL prepared by \
|
|
|
|
%s plugin' % urlplugin.handler_name)
|
2009-12-17 23:17:32 +00:00
|
|
|
url = newurl
|
2010-01-23 00:50:28 +00:00
|
|
|
break
|
2009-12-30 01:50:47 +00:00
|
|
|
except Exception, ex:
|
2012-01-14 20:09:25 +00:00
|
|
|
err('Exception occurred preparing URL: %s' % ex)
|
2009-12-17 23:17:32 +00:00
|
|
|
|
|
|
|
return(url)
|
2009-09-04 19:12:35 +00:00
|
|
|
|
2009-09-03 13:47:14 +00:00
|
|
|
def open_url(self, url, prepare=False):
|
2009-09-04 19:12:35 +00:00
|
|
|
"""Open a given URL, conditionally unpacking it from a VTE match"""
|
|
|
|
if prepare == True:
|
|
|
|
url = self.prepare_url(url)
|
|
|
|
dbg('open_url: URL: %s (prepared: %s)' % (url, prepare))
|
2010-04-12 21:45:45 +00:00
|
|
|
|
2012-01-14 20:39:00 +00:00
|
|
|
if self.config['use_custom_url_handler']:
|
|
|
|
dbg("Using custom URL handler: %s" %
|
|
|
|
self.config['custom_url_handler'])
|
|
|
|
try:
|
|
|
|
subprocess.Popen([self.config['custom_url_handler'], url])
|
|
|
|
return
|
|
|
|
except:
|
|
|
|
dbg('custom url handler did not work, falling back to defaults')
|
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
Gtk.show_uri(None, url, Gdk.CURRENT_TIME)
|
2010-04-12 21:45:45 +00:00
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
try:
|
|
|
|
subprocess.Popen(["xdg-open", url])
|
|
|
|
except:
|
|
|
|
dbg('xdg-open did not work, falling back to webbrowser.open')
|
|
|
|
import webbrowser
|
|
|
|
webbrowser.open(url)
|
2009-09-03 13:47:14 +00:00
|
|
|
|
|
|
|
def paste_clipboard(self, primary=False):
|
|
|
|
"""Paste one of the two clipboards"""
|
2009-11-04 18:06:34 +00:00
|
|
|
for term in self.terminator.get_target_terms(self):
|
2009-09-04 21:48:35 +00:00
|
|
|
if primary:
|
|
|
|
term.vte.paste_primary()
|
|
|
|
else:
|
|
|
|
term.vte.paste_clipboard()
|
2009-09-03 13:47:14 +00:00
|
|
|
self.vte.grab_focus()
|
2009-09-04 19:12:35 +00:00
|
|
|
|
2009-09-04 21:48:35 +00:00
|
|
|
def feed(self, text):
|
|
|
|
"""Feed the supplied text to VTE"""
|
2014-09-19 14:10:43 +00:00
|
|
|
self.vte.feed_child(text, len(text))
|
2009-09-04 21:48:35 +00:00
|
|
|
|
2009-10-28 23:07:42 +00:00
|
|
|
def zoom_in(self):
|
|
|
|
"""Increase the font size"""
|
|
|
|
self.zoom_font(True)
|
|
|
|
|
|
|
|
def zoom_out(self):
|
|
|
|
"""Decrease the font size"""
|
|
|
|
self.zoom_font(False)
|
|
|
|
|
|
|
|
def zoom_font(self, zoom_in):
|
|
|
|
"""Change the font size"""
|
|
|
|
pangodesc = self.vte.get_font()
|
|
|
|
fontsize = pangodesc.get_size()
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
if fontsize > Pango.SCALE and not zoom_in:
|
|
|
|
fontsize -= Pango.SCALE
|
2009-10-28 23:07:42 +00:00
|
|
|
elif zoom_in:
|
2014-09-19 14:08:08 +00:00
|
|
|
fontsize += Pango.SCALE
|
2009-10-28 23:07:42 +00:00
|
|
|
|
|
|
|
pangodesc.set_size(fontsize)
|
2010-07-13 12:50:33 +00:00
|
|
|
self.set_font(pangodesc)
|
2010-01-10 23:47:55 +00:00
|
|
|
self.custom_font_size = fontsize
|
2009-10-28 23:07:42 +00:00
|
|
|
|
|
|
|
def zoom_orig(self):
|
|
|
|
"""Restore original font size"""
|
2010-01-21 21:39:05 +00:00
|
|
|
if self.config['use_system_font'] == True:
|
|
|
|
font = self.config.get_system_font()
|
|
|
|
else:
|
|
|
|
font = self.config['font']
|
|
|
|
dbg("Terminal::zoom_orig: restoring font to: %s" % font)
|
2014-09-19 14:08:08 +00:00
|
|
|
self.set_font(Pango.FontDescription(font))
|
2010-01-10 23:47:55 +00:00
|
|
|
self.custom_font_size = None
|
2009-10-28 23:07:42 +00:00
|
|
|
|
2010-07-13 12:50:33 +00:00
|
|
|
def set_font(self, fontdesc):
|
|
|
|
"""Set the font we want in VTE"""
|
2014-09-19 14:10:43 +00:00
|
|
|
self.vte.set_font(fontdesc)
|
2010-07-13 12:50:33 +00:00
|
|
|
|
2010-01-20 00:54:35 +00:00
|
|
|
def get_cursor_position(self):
|
|
|
|
"""Return the co-ordinates of our cursor"""
|
2010-05-05 08:46:09 +00:00
|
|
|
# FIXME: THIS METHOD IS DEPRECATED AND UNUSED
|
2010-01-20 00:54:35 +00:00
|
|
|
col, row = self.vte.get_cursor_position()
|
|
|
|
width = self.vte.get_char_width()
|
|
|
|
height = self.vte.get_char_height()
|
|
|
|
return((col * width, row * height))
|
|
|
|
|
2010-01-20 23:36:11 +00:00
|
|
|
def get_font_size(self):
|
|
|
|
"""Return the width/height of our font"""
|
|
|
|
return((self.vte.get_char_width(), self.vte.get_char_height()))
|
|
|
|
|
|
|
|
def get_size(self):
|
|
|
|
"""Return the column/rows of the terminal"""
|
|
|
|
return((self.vte.get_column_count(), self.vte.get_row_count()))
|
|
|
|
|
2014-09-19 14:10:43 +00:00
|
|
|
def on_bell(self, widget):
|
2010-01-21 00:13:56 +00:00
|
|
|
"""Set the urgency hint for our window"""
|
2010-02-11 13:05:12 +00:00
|
|
|
if self.config['urgent_bell'] == True:
|
2011-02-23 21:35:10 +00:00
|
|
|
window = self.get_toplevel()
|
2014-09-19 14:08:08 +00:00
|
|
|
if window.flags() & Gtk.TOPLEVEL:
|
2013-01-30 10:26:56 +00:00
|
|
|
window.set_urgency_hint(True)
|
2010-02-11 13:05:12 +00:00
|
|
|
if self.config['icon_bell'] == True:
|
|
|
|
self.titlebar.icon_bell()
|
2010-01-21 00:13:56 +00:00
|
|
|
|
2010-03-11 13:04:01 +00:00
|
|
|
def describe_layout(self, count, parent, global_layout, child_order):
|
2010-02-01 12:11:44 +00:00
|
|
|
"""Describe our layout"""
|
|
|
|
layout = {}
|
|
|
|
layout['type'] = 'Terminal'
|
2010-02-02 00:39:41 +00:00
|
|
|
layout['parent'] = parent
|
2010-03-11 13:04:01 +00:00
|
|
|
layout['order'] = child_order
|
2010-04-19 22:41:54 +00:00
|
|
|
if self.group:
|
|
|
|
layout['group'] = self.group
|
2010-03-18 23:11:07 +00:00
|
|
|
profile = self.get_profile()
|
|
|
|
if layout != "default":
|
|
|
|
# There's no point explicitly noting default profiles
|
|
|
|
layout['profile'] = profile
|
2010-04-22 22:14:03 +00:00
|
|
|
title = self.titlebar.get_custom_string()
|
|
|
|
if title:
|
|
|
|
layout['title'] = title
|
2013-10-30 16:12:00 +00:00
|
|
|
layout['uuid'] = self.uuid
|
2010-02-02 00:39:41 +00:00
|
|
|
name = 'terminal%d' % count
|
|
|
|
count = count + 1
|
|
|
|
global_layout[name] = layout
|
|
|
|
return(count)
|
2010-02-01 12:11:44 +00:00
|
|
|
|
|
|
|
def create_layout(self, layout):
|
|
|
|
"""Apply our layout"""
|
2010-06-15 14:19:05 +00:00
|
|
|
dbg('Setting layout')
|
2010-02-17 19:57:05 +00:00
|
|
|
if layout.has_key('command') and layout['command'] != '':
|
2010-02-27 14:02:16 +00:00
|
|
|
self.layout_command = layout['command']
|
2010-04-20 11:30:43 +00:00
|
|
|
if layout.has_key('profile') and layout['profile'] != '':
|
|
|
|
if layout['profile'] in self.config.list_profiles():
|
|
|
|
self.set_profile(self, layout['profile'])
|
2010-04-19 22:41:54 +00:00
|
|
|
if layout.has_key('group') and layout['group'] != '':
|
|
|
|
# This doesn't need/use self.titlebar, but it's safer than sending
|
|
|
|
# None
|
|
|
|
self.really_create_group(self.titlebar, layout['group'])
|
2010-04-22 22:14:03 +00:00
|
|
|
if layout.has_key('title') and layout['title'] != '':
|
|
|
|
self.titlebar.set_custom_string(layout['title'])
|
2013-08-27 17:22:00 +00:00
|
|
|
if layout.has_key('directory') and layout['directory'] != '':
|
|
|
|
self.directory = layout['directory']
|
2013-10-30 16:12:00 +00:00
|
|
|
if layout.has_key('uuid') and layout['uuid'] != '':
|
|
|
|
self.uuid = make_uuid(layout['uuid'])
|
2010-02-01 12:11:44 +00:00
|
|
|
|
2013-07-14 19:01:58 +00:00
|
|
|
def scroll_by_page(self, pages):
|
|
|
|
"""Scroll up or down in pages"""
|
2015-03-02 20:50:29 +00:00
|
|
|
amount = pages * self.vte.get_vadjustment().get_page_increment()
|
2013-07-14 19:01:58 +00:00
|
|
|
self.scroll_by(int(amount))
|
|
|
|
|
|
|
|
def scroll_by_line(self, lines):
|
|
|
|
"""Scroll up or down in lines"""
|
2015-03-02 20:50:29 +00:00
|
|
|
amount = lines * self.vte.get_vadjustment().get_step_increment()
|
2013-07-14 19:01:58 +00:00
|
|
|
self.scroll_by(int(amount))
|
|
|
|
|
|
|
|
def scroll_by(self, amount):
|
|
|
|
"""Scroll up or down by an amount of lines"""
|
2015-03-02 20:50:29 +00:00
|
|
|
adjustment = self.vte.get_vadjustment()
|
|
|
|
bottom = adjustment.get_upper() - adjustment.get_page_size()
|
2013-07-14 19:01:58 +00:00
|
|
|
value = adjustment.get_value() + amount
|
|
|
|
adjustment.set_value(min(value, bottom))
|
|
|
|
|
2015-06-19 01:36:41 +00:00
|
|
|
def get_allocation(self):
|
|
|
|
"""Get a real allocation which includes the bloody x and y coordinates (grumble, grumble)"""
|
|
|
|
alloc = super(Terminal, self).get_allocation()
|
|
|
|
alloc.x, alloc.y = self.translate_coordinates(self.get_toplevel(), 0, 0)
|
|
|
|
return alloc
|
|
|
|
|
2009-10-28 12:53:18 +00:00
|
|
|
# There now begins a great list of keyboard event handlers
|
|
|
|
def key_zoom_in(self):
|
2009-10-28 23:07:42 +00:00
|
|
|
self.zoom_in()
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_zoom_out(self):
|
2009-10-28 23:07:42 +00:00
|
|
|
self.zoom_out()
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_copy(self):
|
|
|
|
self.vte.copy_clipboard()
|
|
|
|
|
|
|
|
def key_paste(self):
|
2010-06-17 13:08:54 +00:00
|
|
|
self.paste_clipboard()
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_toggle_scrollbar(self):
|
|
|
|
self.do_scrollbar_toggle()
|
|
|
|
|
|
|
|
def key_zoom_normal(self):
|
|
|
|
self.zoom_orig ()
|
|
|
|
|
|
|
|
def key_search(self):
|
2009-11-04 18:06:34 +00:00
|
|
|
self.searchbar.start_search()
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
# bindings that should be moved to Terminator as they all just call
|
|
|
|
# a function of Terminator. It would be cleaner if TerminatorTerm
|
|
|
|
# has absolutely no reference to Terminator.
|
|
|
|
# N (next) - P (previous) - O (horizontal) - E (vertical) - W (close)
|
2010-01-18 20:39:46 +00:00
|
|
|
def key_cycle_next(self):
|
|
|
|
self.key_go_next()
|
|
|
|
|
|
|
|
def key_cycle_prev(self):
|
|
|
|
self.key_go_prev()
|
|
|
|
|
2009-10-28 12:53:18 +00:00
|
|
|
def key_go_next(self):
|
2009-11-09 22:33:17 +00:00
|
|
|
self.emit('navigate', 'next')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_go_prev(self):
|
2009-11-09 22:33:17 +00:00
|
|
|
self.emit('navigate', 'prev')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_go_up(self):
|
2009-11-09 22:33:17 +00:00
|
|
|
self.emit('navigate', 'up')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_go_down(self):
|
2009-11-09 22:33:17 +00:00
|
|
|
self.emit('navigate', 'down')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_go_left(self):
|
2009-11-09 22:33:17 +00:00
|
|
|
self.emit('navigate', 'left')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_go_right(self):
|
2009-11-09 22:33:17 +00:00
|
|
|
self.emit('navigate', 'right')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_split_horiz(self):
|
2015-06-19 01:58:41 +00:00
|
|
|
self.emit('split-horiz', self.get_cwd())
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_split_vert(self):
|
2015-06-19 01:58:41 +00:00
|
|
|
self.emit('split-vert', self.get_cwd())
|
2009-10-28 12:53:18 +00:00
|
|
|
|
2012-04-04 15:48:29 +00:00
|
|
|
def key_rotate_cw(self):
|
|
|
|
self.emit('rotate-cw')
|
|
|
|
|
|
|
|
def key_rotate_ccw(self):
|
|
|
|
self.emit('rotate-ccw')
|
|
|
|
|
2009-10-28 12:53:18 +00:00
|
|
|
def key_close_term(self):
|
2009-11-21 18:11:50 +00:00
|
|
|
self.close()
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_resize_up(self):
|
2009-11-08 23:06:26 +00:00
|
|
|
self.emit('resize-term', 'up')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_resize_down(self):
|
2009-11-08 23:06:26 +00:00
|
|
|
self.emit('resize-term', 'down')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_resize_left(self):
|
2009-11-08 23:06:26 +00:00
|
|
|
self.emit('resize-term', 'left')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_resize_right(self):
|
2009-11-08 23:06:26 +00:00
|
|
|
self.emit('resize-term', 'right')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_move_tab_right(self):
|
2010-01-21 13:02:37 +00:00
|
|
|
self.emit('move-tab', 'right')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_move_tab_left(self):
|
2010-01-21 13:02:37 +00:00
|
|
|
self.emit('move-tab', 'left')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_toggle_zoom(self):
|
2009-11-14 18:55:51 +00:00
|
|
|
if self.is_zoomed():
|
|
|
|
self.unzoom()
|
|
|
|
else:
|
|
|
|
self.maximise()
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_scaled_zoom(self):
|
2009-11-14 18:55:51 +00:00
|
|
|
if self.is_zoomed():
|
|
|
|
self.unzoom()
|
|
|
|
else:
|
|
|
|
self.zoom()
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_next_tab(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', -1)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_prev_tab(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', -2)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_switch_to_tab_1(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', 0)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_switch_to_tab_2(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', 1)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_switch_to_tab_3(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', 2)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_switch_to_tab_4(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', 3)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_switch_to_tab_5(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', 4)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_switch_to_tab_6(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', 5)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_switch_to_tab_7(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', 6)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_switch_to_tab_8(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', 7)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_switch_to_tab_9(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', 8)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_switch_to_tab_10(self):
|
2010-01-21 12:33:42 +00:00
|
|
|
self.emit('tab-change', 9)
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_reset(self):
|
|
|
|
self.vte.reset (True, False)
|
|
|
|
|
|
|
|
def key_reset_clear(self):
|
|
|
|
self.vte.reset (True, True)
|
|
|
|
|
|
|
|
def key_group_all(self):
|
2010-01-21 12:55:57 +00:00
|
|
|
self.emit('group-all')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
2014-01-24 22:29:07 +00:00
|
|
|
def key_group_all_toggle(self):
|
|
|
|
self.emit('group-all-toggle')
|
|
|
|
|
2009-10-28 12:53:18 +00:00
|
|
|
def key_ungroup_all(self):
|
2010-01-21 12:55:57 +00:00
|
|
|
self.emit('ungroup-all')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_group_tab(self):
|
2010-01-21 12:55:57 +00:00
|
|
|
self.emit('group-tab')
|
2014-01-24 22:29:07 +00:00
|
|
|
|
|
|
|
def key_group_tab_toggle(self):
|
|
|
|
self.emit('group-tab-toggle')
|
|
|
|
|
2009-10-28 12:53:18 +00:00
|
|
|
def key_ungroup_tab(self):
|
2010-01-21 12:55:57 +00:00
|
|
|
self.emit('ungroup-tab')
|
2009-10-28 12:53:18 +00:00
|
|
|
|
|
|
|
def key_new_window(self):
|
2015-06-19 01:58:41 +00:00
|
|
|
self.terminator.new_window(self.get_cwd())
|
2010-01-29 23:52:21 +00:00
|
|
|
|
|
|
|
def key_new_terminator(self):
|
2013-08-28 21:09:17 +00:00
|
|
|
spawn_new_terminator(self.origcwd, ['-u'])
|
2010-07-03 17:54:53 +00:00
|
|
|
|
|
|
|
def key_broadcast_off(self):
|
|
|
|
self.set_groupsend(None, self.terminator.groupsend_type['off'])
|
2012-06-23 22:48:23 +00:00
|
|
|
self.terminator.focus_changed(self)
|
2010-07-03 17:54:53 +00:00
|
|
|
|
|
|
|
def key_broadcast_group(self):
|
|
|
|
self.set_groupsend(None, self.terminator.groupsend_type['group'])
|
2012-06-23 22:48:23 +00:00
|
|
|
self.terminator.focus_changed(self)
|
2010-07-03 17:54:53 +00:00
|
|
|
|
|
|
|
def key_broadcast_all(self):
|
|
|
|
self.set_groupsend(None, self.terminator.groupsend_type['all'])
|
2012-06-23 22:48:23 +00:00
|
|
|
self.terminator.focus_changed(self)
|
2010-07-03 17:54:53 +00:00
|
|
|
|
2012-06-26 18:23:39 +00:00
|
|
|
def key_insert_number(self):
|
|
|
|
self.emit('enumerate', False)
|
|
|
|
|
|
|
|
def key_insert_padded(self):
|
|
|
|
self.emit('enumerate', True)
|
|
|
|
|
2012-06-26 18:29:54 +00:00
|
|
|
def key_edit_window_title(self):
|
|
|
|
window = self.get_toplevel()
|
2014-09-19 14:08:08 +00:00
|
|
|
dialog = Gtk.Dialog(_('Rename Window'), window,
|
|
|
|
Gtk.DialogFlags.MODAL,
|
|
|
|
( Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
|
|
|
|
Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT ))
|
|
|
|
dialog.set_default_response(Gtk.ResponseType.ACCEPT)
|
2012-06-26 18:29:54 +00:00
|
|
|
dialog.set_has_separator(False)
|
|
|
|
dialog.set_resizable(False)
|
|
|
|
dialog.set_border_width(8)
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
label = Gtk.Label(label=_('Enter a new title for the Terminator window...'))
|
|
|
|
name = Gtk.Entry()
|
2012-06-26 18:29:54 +00:00
|
|
|
name.set_activates_default(True)
|
|
|
|
if window.title.text != self.vte.get_window_title():
|
|
|
|
name.set_text(self.get_toplevel().title.text)
|
|
|
|
|
|
|
|
dialog.vbox.pack_start(label, False, False, 6)
|
|
|
|
dialog.vbox.pack_start(name, False, False, 6)
|
|
|
|
|
|
|
|
dialog.show_all()
|
|
|
|
res = dialog.run()
|
2014-09-19 14:08:08 +00:00
|
|
|
if res == Gtk.ResponseType.ACCEPT:
|
2012-06-26 18:29:54 +00:00
|
|
|
if name.get_text():
|
|
|
|
window.title.force_title(None)
|
|
|
|
window.title.force_title(name.get_text())
|
|
|
|
else:
|
|
|
|
window.title.force_title(None)
|
|
|
|
dialog.destroy()
|
|
|
|
return
|
2010-07-03 17:54:53 +00:00
|
|
|
|
2013-08-28 21:09:17 +00:00
|
|
|
def key_layout_launcher(self):
|
|
|
|
LAYOUTLAUNCHER=LayoutLauncher()
|
|
|
|
|
2013-07-14 19:01:58 +00:00
|
|
|
def key_page_up(self):
|
|
|
|
self.scroll_by_page(-1)
|
|
|
|
|
|
|
|
def key_page_down(self):
|
|
|
|
self.scroll_by_page(1)
|
|
|
|
|
|
|
|
def key_page_up_half(self):
|
|
|
|
self.scroll_by_page(-0.5)
|
|
|
|
|
|
|
|
def key_page_down_half(self):
|
|
|
|
self.scroll_by_page(0.5)
|
|
|
|
|
|
|
|
def key_line_up(self):
|
|
|
|
self.scroll_by_line(-1)
|
|
|
|
|
|
|
|
def key_line_down(self):
|
|
|
|
self.scroll_by_line(1)
|
|
|
|
|
2009-10-28 12:53:18 +00:00
|
|
|
# End key events
|
|
|
|
|
2014-09-19 14:08:08 +00:00
|
|
|
GObject.type_register(Terminal)
|
2009-08-10 23:42:39 +00:00
|
|
|
# vim: set expandtab ts=4 sw=4:
|