2008-06-26 23:24:52 +00:00
#!/usr/bin/python
# Terminator - multiple gnome terminals in one window
# Copyright (C) 2006-2008 cmsj@tenshu.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 2 only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
""" Terminator by Chris Jones <cmsj@tenshu.net> """
2008-07-02 09:16:52 +00:00
import pygtk
pygtk . require ( " 2.0 " )
2008-06-26 23:24:52 +00:00
import gobject , gtk , pango
2008-12-24 03:31:39 +00:00
import os , signal , sys , subprocess , pwd , re
2008-06-26 23:24:52 +00:00
#import version details
from terminatorlib . version import *
# import our configuration loader
from terminatorlib import config
2008-06-28 20:20:49 +00:00
from terminatorlib . config import dbg , err , debug
2008-06-26 23:24:52 +00:00
#import encoding list
from terminatorlib . encoding import TerminatorEncoding
# import vte-bindings
try :
import vte
2008-07-17 17:44:21 +00:00
except ImportError :
2008-06-26 23:24:52 +00:00
error = gtk . MessageDialog ( None , gtk . DIALOG_MODAL , gtk . MESSAGE_ERROR , gtk . BUTTONS_OK ,
_ ( ' You need to install python bindings for libvte ( " python-vte " in debian/ubuntu) ' ) )
error . run ( )
sys . exit ( 1 )
2009-01-26 00:20:03 +00:00
class TerminatorTermTitle ( gtk . EventBox ) :
2009-01-30 12:04:59 +00:00
wanted = None
2009-01-26 00:20:03 +00:00
_title = None
_group = None
_separator = None
_hbox = None
2009-01-27 00:31:48 +00:00
_icon = None
2009-01-30 12:04:59 +00:00
_parent = None
2009-02-02 17:18:40 +00:00
_unzoomed_title = None
2009-01-26 00:20:03 +00:00
2009-01-30 12:04:59 +00:00
def __init__ ( self , configwanted = False ) :
2009-01-26 00:20:03 +00:00
gtk . EventBox . __init__ ( self )
2009-01-30 12:04:59 +00:00
2009-01-26 00:20:03 +00:00
self . _title = gtk . Label ( )
self . _group = gtk . Label ( )
self . _separator = gtk . VSeparator ( )
2009-01-27 00:31:48 +00:00
self . _icon = gtk . Image ( )
2009-01-26 00:20:03 +00:00
self . _hbox = gtk . HBox ( )
2009-01-27 00:31:48 +00:00
self . _hbox . pack_start ( self . _icon , False , True , 2 )
self . _hbox . pack_start ( self . _group , False , True , 2 )
2009-01-26 00:20:03 +00:00
self . _hbox . pack_start ( self . _separator , False , True , 2 )
self . _hbox . pack_start ( self . _title , True , True )
self . add ( self . _hbox )
self . _title . show ( )
self . _hbox . show ( )
2009-01-30 12:04:59 +00:00
self . wanted = configwanted
2009-01-26 00:20:03 +00:00
def set_group_label ( self , name ) :
""" If ' name ' is None, hide the group name object, otherwise set it as the group label """
if name :
self . _group . set_text ( name )
self . _group . show ( )
self . _separator . show ( )
else :
self . _group . hide ( )
self . _separator . hide ( )
def set_terminal_title ( self , name ) :
""" Set the text shown in the titlebar """
self . _title . set_text ( name )
2009-02-02 17:18:40 +00:00
def get_terminal_title ( self ) :
""" Return the text showin in the titlebar """
return ( self . _title . get_text ( ) )
2009-01-26 00:20:03 +00:00
def set_background_color ( self , color ) :
""" Set the background color of the titlebar """
self . modify_bg ( gtk . STATE_NORMAL , color )
2009-01-26 00:22:11 +00:00
def set_foreground_color ( self , color ) :
""" Set the foreground color of the titlebar """
self . _title . modify_fg ( color )
2009-01-27 00:31:48 +00:00
def set_from_icon_name ( self , name , size = gtk . ICON_SIZE_MENU ) :
""" Set an icon for the group label """
if not name :
self . _icon . hide ( )
return
self . _icon . set_from_icon_name ( APP_NAME + name , size )
self . _icon . show ( )
2009-01-30 11:42:28 +00:00
def update ( self ) :
""" Update our state """
2009-01-30 12:04:59 +00:00
if not self . _parent :
self . _parent = self . get_parent ( )
2009-02-02 17:18:40 +00:00
if self . _parent . terminator . _zoomed and len ( self . _parent . terminator . term_list ) :
self . _unzoomed_title = self . get_terminal_title ( )
2009-02-02 17:20:16 +00:00
self . set_terminal_title ( " Zoomed/Maximised terminal, %d hidden " % ( len ( self . _parent . terminator . term_list ) - 1 ) )
2009-02-02 17:18:40 +00:00
self . show ( )
return
else :
if self . _unzoomed_title :
self . set_terminal_title ( self . _unzoomed_title )
self . _unzoomed_title = None
2009-01-30 15:23:47 +00:00
if isinstance ( self . _parent . get_parent ( ) , gtk . Window ) :
self . hide ( )
return
2009-01-30 12:04:59 +00:00
if ( self . _parent . conf . titlebars and self . wanted ) or self . _parent . _group :
self . show ( )
else :
self . hide ( )
if self . _parent . _group :
self . set_group_label ( self . _parent . _group )
2009-01-30 11:42:28 +00:00
else :
self . set_group_label ( None )
2008-06-26 23:24:52 +00:00
class TerminatorTerm ( gtk . VBox ) :
2009-03-06 11:25:15 +00:00
matches = None
2008-07-03 22:48:29 +00:00
TARGET_TYPE_VTE = 8
2008-08-26 21:24:36 +00:00
_custom_font_size = None
2008-12-10 18:16:55 +00:00
_group = None
2009-01-28 01:18:21 +00:00
focus = None
2009-03-20 10:13:29 +00:00
_urgent_bell_cnid = None
2008-06-26 23:24:52 +00:00
def __init__ ( self , terminator , profile = None , command = None , cwd = None ) :
gtk . VBox . __init__ ( self )
self . terminator = terminator
self . conf = terminator . conf
self . command = command
2008-10-20 08:29:47 +00:00
self . _oldtitle = " "
2009-03-06 11:25:15 +00:00
self . matches = { }
2008-06-26 23:24:52 +00:00
self . cwd = cwd or os . getcwd ( ) ;
if not os . path . exists ( self . cwd ) or not os . path . isdir ( self . cwd ) :
self . cwd = pwd . getpwuid ( os . getuid ( ) ) [ 5 ]
self . clipboard = gtk . clipboard_get ( gtk . gdk . SELECTION_CLIPBOARD )
self . scrollbar_position = self . conf . scrollbar_position
2008-09-04 17:41:02 +00:00
self . _composited_support = True
2008-06-26 23:24:52 +00:00
self . _vte = vte . Terminal ( )
2008-09-04 17:41:02 +00:00
if not hasattr ( self . _vte , " set_opacity " ) or not hasattr ( self . _vte , " is_composited " ) :
self . _composited_support = False
2009-02-13 10:43:11 +00:00
dbg ( ' H9TRANS: composited_support: %s ' % self . _composited_support )
2008-07-16 19:27:16 +00:00
#self._vte.set_double_buffered(True)
2008-06-26 23:24:52 +00:00
self . _vte . set_size ( 80 , 24 )
2008-07-17 21:09:41 +00:00
self . _vte . _expose_data = None
2008-06-26 23:24:52 +00:00
self . _vte . show ( )
self . _termbox = gtk . HBox ( )
self . _termbox . show ( )
2009-01-26 00:20:03 +00:00
2009-01-30 12:04:59 +00:00
self . _titlebox = TerminatorTermTitle ( self . conf . titlebars )
2008-08-12 01:12:30 +00:00
self . _search_string = None
self . _searchbox = gtk . HBox ( )
self . _searchinput = gtk . Entry ( )
self . _searchinput . set_activates_default ( True )
self . _searchinput . show ( )
self . _searchinput . connect ( ' activate ' , self . do_search )
self . _searchinput . connect ( ' key-press-event ' , self . search_keypress )
slabel = gtk . Label ( )
2008-11-28 12:59:48 +00:00
slabel . set_text ( _ ( " Search: " ) )
2008-08-12 01:12:30 +00:00
slabel . show ( )
2008-09-25 21:33:45 +00:00
sclose = gtk . Button ( )
sclose . set_relief ( gtk . RELIEF_NONE )
sclose . set_focus_on_click ( False )
sclose . set_relief ( gtk . RELIEF_NONE )
sclose_icon = gtk . Image ( )
sclose_icon . set_from_stock ( gtk . STOCK_CLOSE , gtk . ICON_SIZE_MENU )
sclose . add ( sclose_icon )
sclose . set_name ( " terminator-search-close-button " )
if hasattr ( sclose , " set_tooltip_text " ) :
sclose . set_tooltip_text ( " Close Search Bar " )
sclose . connect ( ' clicked ' , self . end_search )
sclose . show_all ( )
2008-09-25 21:40:44 +00:00
# Button for the next result. Explicitly not show()n by default.
self . _search_next = gtk . Button ( _ ( " Next " ) )
self . _search_next . connect ( ' clicked ' , self . next_search )
2008-08-12 01:12:30 +00:00
self . _searchbox . pack_start ( slabel , False )
self . _search_result_label = gtk . Label ( )
self . _search_result_label . set_text ( " " )
self . _search_result_label . show ( )
self . _searchbox . pack_start ( self . _searchinput )
2008-09-25 21:33:45 +00:00
self . _searchbox . pack_start ( self . _search_result_label , False )
2008-09-25 21:40:44 +00:00
self . _searchbox . pack_start ( self . _search_next , False , False )
2008-09-25 21:33:45 +00:00
self . _searchbox . pack_end ( sclose , False , False )
2008-08-12 01:12:30 +00:00
2008-06-26 23:24:52 +00:00
self . show ( )
self . pack_start ( self . _titlebox , False )
self . pack_start ( self . _termbox )
2008-08-12 01:12:30 +00:00
self . pack_end ( self . _searchbox )
2008-06-26 23:24:52 +00:00
2009-01-30 12:04:59 +00:00
self . _titlebox . update ( )
2008-06-26 23:24:52 +00:00
self . _scrollbar = gtk . VScrollbar ( self . _vte . get_adjustment ( ) )
if self . scrollbar_position != " hidden " and self . scrollbar_position != " disabled " :
self . _scrollbar . show ( )
if self . scrollbar_position == ' left ' :
packfunc = self . _termbox . pack_end
else :
packfunc = self . _termbox . pack_start
packfunc ( self . _vte )
packfunc ( self . _scrollbar , False )
self . _vte . connect ( " key-press-event " , self . on_vte_key_press )
self . _vte . connect ( " button-press-event " , self . on_vte_button_press )
2008-08-06 22:12:45 +00:00
self . _vte . connect ( " popup-menu " , self . create_popup_menu )
2008-06-26 23:24:52 +00:00
""" drag and drop """
2008-07-03 22:48:29 +00:00
srcvtetargets = [ ( " vte " , gtk . TARGET_SAME_APP , self . TARGET_TYPE_VTE ) ]
dsttargets = [ ( " vte " , gtk . TARGET_SAME_APP , self . TARGET_TYPE_VTE ) , ( ' text/plain ' , 0 , 0 ) , ( " STRING " , 0 , 0 ) , ( " COMPOUND_TEXT " , 0 , 0 ) ]
2008-06-26 23:24:52 +00:00
self . _vte . drag_source_set ( gtk . gdk . CONTROL_MASK | gtk . gdk . BUTTON3_MASK , srcvtetargets , gtk . gdk . ACTION_MOVE )
self . _titlebox . drag_source_set ( gtk . gdk . BUTTON1_MASK , srcvtetargets , gtk . gdk . ACTION_MOVE )
#self._vte.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT |gtk.DEST_DEFAULT_DROP ,dsttargets, gtk.gdk.ACTION_MOVE)
self . _vte . drag_dest_set ( gtk . DEST_DEFAULT_MOTION | gtk . DEST_DEFAULT_HIGHLIGHT | gtk . DEST_DEFAULT_DROP , dsttargets , gtk . gdk . ACTION_MOVE )
self . _vte . connect ( " drag-begin " , self . on_drag_begin , self )
self . _titlebox . connect ( " drag-begin " , self . on_drag_begin , self )
self . _vte . connect ( " drag-data-get " , self . on_drag_data_get , self )
self . _titlebox . connect ( " drag-data-get " , self . on_drag_data_get , self )
#for testing purpose: drag-motion
self . _vte . connect ( " drag-motion " , self . on_drag_motion , self )
self . _vte . connect ( " drag-data-received " , self . on_drag_data_received , self )
if self . conf . copy_on_selection :
self . _vte . connect ( " selection-changed " , lambda widget : self . _vte . copy_clipboard ( ) )
2008-09-04 17:41:02 +00:00
if self . _composited_support :
self . _vte . connect ( " composited-changed " , self . on_composited_changed )
2008-06-26 23:24:52 +00:00
self . _vte . connect ( " window-title-changed " , self . on_vte_title_change )
self . _vte . connect ( " grab-focus " , self . on_vte_focus )
self . _vte . connect ( " focus-out-event " , self . on_vte_focus_out )
self . _vte . connect ( " focus-in-event " , self . on_vte_focus_in )
2008-08-03 02:09:38 +00:00
self . _vte . connect ( " resize-window " , self . on_resize_window )
2008-07-03 22:48:29 +00:00
2008-06-26 23:24:52 +00:00
exit_action = self . conf . exit_action
if exit_action == " restart " :
self . _vte . connect ( " child-exited " , self . spawn_child )
# We need to support "left" because some buggy versions of gnome-terminal
# set it in some situations
elif exit_action in ( " close " , " left " ) :
self . _vte . connect ( " child-exited " , lambda close_term : self . terminator . closeterm ( self ) )
self . _vte . add_events ( gtk . gdk . ENTER_NOTIFY_MASK )
self . _vte . connect ( " enter_notify_event " , self . on_vte_notify_enter )
2009-01-28 01:18:21 +00:00
self . _vte . connect_after ( " realize " , self . reconfigure_vte )
2008-08-03 02:09:38 +00:00
self . add_matches ( posix = self . conf . try_posix_regexp )
2008-06-26 23:24:52 +00:00
dbg ( ' SEGBUG: Setting http_proxy ' )
env_proxy = os . getenv ( ' http_proxy ' )
if not env_proxy and self . conf . http_proxy and self . conf . http_proxy != ' ' :
os . putenv ( ' http_proxy ' , self . conf . http_proxy )
dbg ( ' SEGBUG: Setting COLORTERM ' )
os . putenv ( ' COLORTERM ' , ' gnome-terminal ' )
dbg ( ' SEGBUG: TerminatorTerm __init__ complete ' )
2008-07-03 22:48:29 +00:00
2009-03-19 22:03:44 +00:00
def prepareurl ( self , url , match ) :
dbg ( " prepareurl: Checking ' %s ' with a match of ' %s ' " % ( url , match ) )
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
elif match == self . matches [ ' launchpad ' ] :
url = ' https://bugs.launchpad.net/bugs/ %s ' % re . sub ( r ' [^0-9]+ ' , ' ' , url )
return url
2008-07-04 06:29:32 +00:00
def openurl ( self , url ) :
2008-07-03 22:48:29 +00:00
dbg ( ' openurl: viewing %s ' % url )
try :
2008-09-08 20:13:31 +00:00
dbg ( ' openurl: calling xdg-open ' )
subprocess . Popen ( [ " xdg-open " , url ] )
2008-07-03 22:48:29 +00:00
except :
2008-09-08 20:13:31 +00:00
dbg ( ' openurl: xdg-open failed ' )
2008-07-03 22:48:29 +00:00
try :
dbg ( ' openurl: calling url_show ' )
2008-08-29 18:18:31 +00:00
self . terminator . url_show ( url )
2008-07-03 22:48:29 +00:00
except :
dbg ( ' openurl: url_show failed. No URL for you ' )
pass
2008-08-03 02:09:38 +00:00
def on_resize_window ( self , widget , width , height ) :
dbg ( ' Resize window triggered on %s : %d x %d ' % ( widget , width , height ) )
2008-06-26 23:24:52 +00:00
def on_drag_begin ( self , widget , drag_context , data ) :
dbg ( ' Drag begins ' )
widget . drag_source_set_icon_pixbuf ( self . terminator . icon_theme . load_icon ( APP_NAME , 48 , 0 ) )
2008-08-03 02:09:38 +00:00
2008-06-26 23:24:52 +00:00
def on_drag_data_get ( self , widget , drag_context , selection_data , info , time , data ) :
dbg ( " Drag data get " )
selection_data . set ( " vte " , info , str ( data . terminator . term_list . index ( self ) ) )
2008-07-03 22:48:29 +00:00
2008-07-16 20:00:43 +00:00
def on_expose_event ( self , widget , event ) :
if widget . _expose_data is None :
return False
color = widget . _expose_data [ ' color ' ]
coord = widget . _expose_data [ ' coord ' ]
context = widget . window . cairo_create ( )
#leaving those xxx_group as they could be usefull
##http://macslow.thepimp.net/?p=153
#context.push_group()
context . set_source_rgba ( color . red , color . green , color . blue , 0.5 )
if len ( coord ) > 0 :
context . move_to ( coord [ len ( coord ) - 1 ] [ 0 ] , coord [ len ( coord ) - 1 ] [ 1 ] )
for i in coord :
context . line_to ( i [ 0 ] , i [ 1 ] )
context . fill ( )
#context.pop_group_to_source()
#context.paint()
return False
2008-08-03 02:09:38 +00:00
2008-06-26 23:24:52 +00:00
def on_drag_motion ( self , widget , drag_context , x , y , time , data ) :
dbg ( " Drag Motion on " )
"""
x - special / gnome - icon - list
text / uri - list
UTF8_STRING
COMPOUND_TEXT
TEXT
STRING
text / plain ; charset = utf - 8
text / plain ; charset = UTF - 8
text / plain
"""
if ' text/plain ' in drag_context . targets :
#copy text from another widget
return
srcwidget = drag_context . get_source_widget ( )
if ( isinstance ( srcwidget , gtk . EventBox ) and srcwidget == self . _titlebox ) or widget == srcwidget :
#on self
return
alloc = widget . allocation
rect = gtk . gdk . Rectangle ( 0 , 0 , alloc . width , alloc . height )
2008-07-16 20:00:43 +00:00
2008-06-26 23:24:52 +00:00
if self . conf . use_theme_colors :
color = self . _vte . get_style ( ) . text [ gtk . STATE_NORMAL ]
else :
color = gtk . gdk . color_parse ( self . conf . foreground_color )
pos = self . get_location ( widget , x , y )
topleft = ( 0 , 0 )
topright = ( alloc . width , 0 )
topmiddle = ( alloc . width / 2 , 0 )
bottomleft = ( 0 , alloc . height )
bottomright = ( alloc . width , alloc . height )
bottommiddle = ( alloc . width / 2 , alloc . height )
middle = ( alloc . width / 2 , alloc . height / 2 )
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 )
if pos == " top " :
coord = ( topleft , topright , middleright , middleleft )
if pos == " left " :
coord = ( topleft , topmiddle , bottommiddle , bottomleft )
if pos == " bottom " :
coord = ( bottomleft , bottomright , middleright , middleleft )
2008-07-16 19:17:53 +00:00
2008-07-16 20:00:43 +00:00
#here, we define some widget internal values
widget . _expose_data = { ' color ' : color , ' coord ' : coord }
#redraw by forcing an event
2009-03-21 01:39:49 +00:00
connec = widget . connect_after ( ' expose-event ' , self . on_expose_event )
2008-07-16 20:00:43 +00:00
widget . window . invalidate_rect ( rect , True )
widget . window . process_updates ( True )
#finaly reset the values
2008-07-17 21:09:41 +00:00
widget . disconnect ( connec )
2008-07-16 20:00:43 +00:00
widget . _expose_data = None
2008-07-16 19:17:53 +00:00
2008-06-26 23:24:52 +00:00
def on_drag_drop ( self , widget , drag_context , x , y , time ) :
parent = widget . get_parent ( )
dbg ( ' Drag drop on %s ' % parent )
2008-08-03 02:09:38 +00:00
2008-06-26 23:24:52 +00:00
def on_drag_data_received ( self , widget , drag_context , x , y , selection_data , info , time , data ) :
dbg ( " Drag Data Received " )
if selection_data . type == ' text/plain ' :
#copy text to destination
#print "%s %s" % (selection_data.type, selection_data.target)
txt = selection_data . data . strip ( )
if txt [ 0 : 7 ] == " file:// " :
txt = " ' %s ' " % txt [ 7 : ]
2009-01-07 18:35:44 +00:00
for term in self . terminator . term_list :
2009-01-10 00:45:41 +00:00
if term == self or ( term . _group != None and term . _group == self . _group ) :
2009-01-07 18:35:44 +00:00
term . _vte . feed_child ( txt )
2008-06-26 23:24:52 +00:00
return
widgetsrc = data . terminator . term_list [ int ( selection_data . data ) ]
srcvte = drag_context . get_source_widget ( )
#check if computation requireds
if ( isinstance ( srcvte , gtk . EventBox ) and srcvte == self . _titlebox ) or srcvte == widget :
dbg ( " on itself " )
return
srchbox = widgetsrc
dsthbox = widget . get_parent ( ) . get_parent ( )
dstpaned = dsthbox . get_parent ( )
srcpaned = srchbox . get_parent ( )
if isinstance ( dstpaned , gtk . Window ) and isinstance ( srcpaned , gtk . Window ) :
dbg ( " Only one terminal " )
return
pos = self . get_location ( widget , x , y )
2009-01-04 02:37:42 +00:00
data . terminator . remove ( widgetsrc , True )
2008-06-26 23:24:52 +00:00
data . terminator . add ( self , widgetsrc , pos )
return
def get_location ( self , vte , x , y ) :
pos = " "
#get the diagonales function for the receiving widget
coef1 = float ( vte . allocation . height ) / float ( vte . allocation . width )
coef2 = - float ( vte . allocation . height ) / float ( vte . allocation . width )
b1 = 0
b2 = vte . allocation . height
2008-07-03 22:48:29 +00:00
#determine position in rectangle
2008-06-26 23:24:52 +00:00
"""
- - - - - - - -
| \ / |
| \ / |
| \/ |
| / \ |
| / \ |
| / \|
- - - - - - - -
"""
if ( x * coef1 + b1 > y ) and ( x * coef2 + b2 < y ) :
pos = " right "
if ( x * coef1 + b1 > y ) and ( x * coef2 + b2 > y ) :
pos = " top "
if ( x * coef1 + b1 < y ) and ( x * coef2 + b2 > y ) :
pos = " left "
if ( x * coef1 + b1 < y ) and ( x * coef2 + b2 < y ) :
pos = " bottom "
return pos
2008-08-03 02:09:38 +00:00
def add_matches ( self , posix = True ) :
2008-06-26 23:24:52 +00:00
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 , \\ \" ] "
2008-08-02 22:32:10 +00:00
2008-08-03 02:09:38 +00:00
if posix :
dbg ( ' add_matches: Trying POSIX URL regexps. Set try_posix_regexp = False in config to only try GNU if you get (harmless) VTE warnings. ' )
lboundry = " [[:<:]] "
rboundry = " [[:>:]] "
else : # GNU
dbg ( ' add_matches: Trying GNU URL regexps. Set try_posix_regexp = True in config if URLs are not detected. ' )
lboundry = " \\ < "
rboundry = " \\ > "
2008-07-13 22:16:19 +00:00
self . matches [ ' full_uri ' ] = self . _vte . match_add ( lboundry + schemes + " //( " + user + " @)?[ " + hostchars + " .]+(:[0-9]+)?( " + urlpath + " )? " + rboundry + " /? " )
2008-06-26 23:24:52 +00:00
2008-07-13 22:16:19 +00:00
if self . matches [ ' full_uri ' ] == - 1 :
2008-08-03 02:09:38 +00:00
if posix :
err ( ' add_matches: POSIX match failed, trying GNU ' )
self . add_matches ( posix = False )
else :
err ( ' add_matches: Failed adding URL match patterns ' )
2008-06-26 23:24:52 +00:00
else :
2009-03-25 13:04:49 +00:00
self . matches [ ' voip ' ] = self . _vte . match_add ( lboundry + ' (callto:|h323:|sip:) ' + " [ " + userchars + " +][ " + userchars + " .]*(:[0-9]+)?@?[ " + pathchars + " ]+ " + rboundry )
2008-07-13 22:16:19 +00:00
self . matches [ ' addr_only ' ] = self . _vte . match_add ( lboundry + " (www|ftp)[ " + hostchars + " ]* \ .[ " + hostchars + " .]+(:[0-9]+)?( " + urlpath + " )? " + rboundry + " /? " )
self . matches [ ' email ' ] = self . _vte . match_add ( lboundry + " (mailto:)?[a-zA-Z0-9][a-zA-Z0-9.+-]*@[a-zA-Z0-9][a-zA-Z0-9-]* \ .[a-zA-Z0-9][a-zA-Z0-9-]+[.a-zA-Z0-9-]* " + rboundry )
self . matches [ ' nntp ' ] = self . _vte . match_add ( lboundry + ''' news:[-A-Z \ ^_a-z { |}~! " #$ % & ' ()*+,./0-9;:=?`]+@[-A-Za-z0-9.]+(:[0-9]+)? ''' + rboundry )
2008-12-14 05:13:25 +00:00
# if the url looks like a Launchpad changelog closure entry LP: #92953 - make it a url to http://bugs.launchpad.net
self . matches [ ' launchpad ' ] = self . _vte . match_add ( ' \\ bLP:? #?[0-9]+ \\ b ' )
2008-06-26 23:24:52 +00:00
2008-07-20 21:15:14 +00:00
def _path_lookup ( self , command ) :
if os . path . isabs ( command ) :
if os . path . isfile ( command ) :
return command
else :
return None
elif command [ : 2 ] == ' ./ ' and os . path . isfile ( command ) :
dbg ( ' path_lookup: Relative filename " %s " found in cwd ' % command )
return command
try :
paths = os . environ [ ' PATH ' ] . split ( ' : ' )
if len ( paths [ 0 ] ) == 0 : raise ( ValueError )
except ( ValueError , NameError ) :
dbg ( ' path_lookup: PATH not set in environment, using fallbacks ' )
paths = [ ' /usr/local/bin ' , ' /usr/bin ' , ' /bin ' ]
dbg ( ' path_lookup: Using %d paths: %s ' % ( len ( paths ) , paths ) )
for path in paths :
target = os . path . join ( path , command )
if os . path . isfile ( target ) :
dbg ( ' path_lookup: found " %s " ' % target )
return target
dbg ( ' path_lookup: Unable to locate " %s " ' % command )
def _shell_lookup ( self ) :
shells = [ os . getenv ( ' SHELL ' ) , pwd . getpwuid ( os . getuid ( ) ) [ 6 ] ,
' bash ' , ' zsh ' , ' tcsh ' , ' ksh ' , ' csh ' , ' sh ' ]
for shell in shells :
if shell is None : continue
elif os . path . isfile ( shell ) :
return shell
else :
rshell = self . _path_lookup ( shell )
if rshell is not None :
dbg ( ' shell_lookup: Found " %s " at " %s " ' % ( shell , rshell ) )
return rshell
dbg ( ' shell_lookup: Unable to locate a shell ' )
2008-06-26 23:24:52 +00:00
def spawn_child ( self , event = None ) :
update_records = self . conf . update_records
login = self . conf . login_shell
args = [ ]
2008-07-20 21:15:14 +00:00
shell = None
command = None
2008-06-26 23:24:52 +00:00
if self . command :
2008-07-17 17:32:24 +00:00
dbg ( ' spawn_child: using self.command: %s ' % self . command )
2008-07-20 21:15:14 +00:00
command = self . command
2008-06-26 23:24:52 +00:00
elif self . conf . use_custom_command :
2008-07-17 17:32:24 +00:00
dbg ( ' spawn_child: using custom command: %s ' % self . conf . custom_command )
2008-07-20 21:15:14 +00:00
command = self . conf . custom_command
2008-06-26 23:24:52 +00:00
2008-07-20 21:15:14 +00:00
if type ( command ) is list :
# List of arguments from -x
dbg ( ' spawn_child: Bypassing shell and trying to run " %s " directly ' % command [ 0 ] )
shell = self . _path_lookup ( command [ 0 ] )
args = command
else :
shell = self . _shell_lookup ( )
if self . conf . login_shell :
args . insert ( 0 , " - %s " % shell )
else :
args . insert ( 0 , shell )
if command is not None :
args + = [ ' -c ' , command ]
if shell is None :
2008-06-26 23:24:52 +00:00
# Give up, we're completely stuck
err ( _ ( ' Unable to find a shell ' ) )
gobject . timeout_add ( 100 , self . terminator . closeterm , self )
return ( - 1 )
dbg ( ' SEGBUG: Setting WINDOWID ' )
2008-07-17 17:32:24 +00:00
os . putenv ( ' WINDOWID ' , ' %s ' % self . _vte . get_parent_window ( ) . xid )
2008-06-26 23:24:52 +00:00
2008-07-17 17:32:24 +00:00
dbg ( ' SEGBUG: Forking command: " %s " with args " %s " , loglastlog = " %s " , ' \
' logwtmp = " %s " , logutmp = " %s " and cwd " %s " ' % ( shell , args , login ,
update_records , update_records , self . cwd ) )
self . _pid = self . _vte . fork_command ( command = shell , argv = args ,
envv = [ ] , loglastlog = login , logwtmp = update_records ,
logutmp = update_records , directory = self . cwd )
2008-06-26 23:24:52 +00:00
2008-08-07 20:34:47 +00:00
dbg ( ' SEGBUG: Forked command ' )
self . on_vte_title_change ( self . _vte ) # Force an initial update of our titles
2009-01-30 12:04:59 +00:00
self . _titlebox . update ( )
2008-08-07 20:34:47 +00:00
2008-06-26 23:24:52 +00:00
if self . _pid == - 1 :
err ( _ ( ' Unable to start shell: ' ) + shell )
return ( - 1 )
def get_cwd ( self ) :
""" Return the current working directory of the subprocess.
This function requires OS specific behaviours
"""
2008-10-28 00:29:41 +00:00
try :
cwd = self . terminator . pid_get_cwd ( self . _pid )
except OSError :
err ( ' get_cwd: unable to get cwd of %d ' % self . _pid )
cwd = ' ~ '
pass
2008-12-11 08:13:02 +00:00
dbg ( ' get_cwd found: %s ' % cwd )
2008-06-26 23:24:52 +00:00
return ( cwd )
2009-01-28 01:18:21 +00:00
def reconfigure_vte ( self , widget = None ) :
2008-06-26 23:24:52 +00:00
# Set our emulation
self . _vte . set_emulation ( self . conf . emulation )
# Set our wordchars
self . _vte . set_word_chars ( self . conf . word_chars )
# Set our mouselation
self . _vte . set_mouse_autohide ( self . conf . mouse_autohide )
# Set our compatibility
backspace = self . conf . backspace_binding
delete = self . conf . delete_binding
# 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 )
# Set our font
2008-08-26 21:24:36 +00:00
if not self . _custom_font_size :
try :
self . _vte . set_font ( pango . FontDescription ( self . conf . font ) )
except :
pass
2008-06-26 23:24:52 +00:00
# Set our boldness
self . _vte . set_allow_bold ( self . conf . allow_bold )
# Set our color scheme
palette = self . conf . palette
if self . conf . use_theme_colors :
fg_color = self . _vte . get_style ( ) . text [ gtk . STATE_NORMAL ]
bg_color = self . _vte . get_style ( ) . base [ gtk . STATE_NORMAL ]
else :
fg_color = gtk . gdk . color_parse ( self . conf . foreground_color )
bg_color = gtk . gdk . color_parse ( self . conf . background_color )
colors = palette . split ( ' : ' )
palette = [ ]
for color in colors :
if color :
palette . append ( gtk . gdk . color_parse ( color ) )
self . _vte . set_colors ( fg_color , bg_color , palette )
2009-03-25 12:48:27 +00:00
cursor_color = self . conf . cursor_color
if cursor_color != ' ' :
self . _vte . set_color_cursor ( gtk . gdk . color_parse ( cursor_color ) )
2009-03-25 12:58:55 +00:00
# Set cursor shape
2009-03-26 10:34:02 +00:00
if hasattr ( self . _vte , " set_cursor_shape " ) :
self . _vte . set_cursor_shape ( getattr ( vte , " CURSOR_SHAPE_ " + self . conf . cursor_shape . upper ( ) ) )
2009-03-25 12:58:55 +00:00
2008-06-26 23:24:52 +00:00
# Set our background image, transparency and type
# Many thanks to the authors of gnome-terminal, on which this code is based.
background_type = self . conf . background_type
2009-01-19 14:45:08 +00:00
dbg ( ' H9TRANS: Configuring background type as: %s ' % background_type )
2008-06-26 23:24:52 +00:00
# set background image settings
if background_type == " image " :
2009-01-19 14:45:08 +00:00
dbg ( ' H9TRANS: Setting background image to: %s ' % self . conf . background_image )
2008-06-26 23:24:52 +00:00
self . _vte . set_background_image_file ( self . conf . background_image )
2009-01-19 14:45:08 +00:00
dbg ( ' H9TRANS: Setting background image scroll to: %s ' % self . conf . scroll_background )
2008-06-26 23:24:52 +00:00
self . _vte . set_scroll_background ( self . conf . scroll_background )
else :
2009-01-19 14:45:08 +00:00
dbg ( ' H9TRANS: Unsetting background image ' )
2008-06-26 23:24:52 +00:00
self . _vte . set_background_image_file ( ' ' )
2009-01-19 14:45:08 +00:00
dbg ( ' H9TRANS: Unsetting background image scrolling ' )
2008-06-26 23:24:52 +00:00
self . _vte . set_scroll_background ( False )
# set transparency for the background (image)
2008-09-04 17:41:02 +00:00
opacity = 65535
2008-06-26 23:24:52 +00:00
if background_type in ( " image " , " transparent " ) :
self . _vte . set_background_tint_color ( bg_color )
self . _vte . set_background_saturation ( 1 - ( self . conf . background_darkness ) )
2008-09-04 17:41:02 +00:00
opacity = int ( self . conf . background_darkness * 65535 )
2009-01-19 14:45:08 +00:00
dbg ( ' H9TRANS: Set background tint color to: %s ' % bg_color )
dbg ( ' H9TRANS: Set background saturation to: %s ' % ( 1 - ( self . conf . background_darkness ) ) )
2008-06-26 23:24:52 +00:00
else :
2009-01-19 14:45:08 +00:00
dbg ( ' H9TRANS: Set background saturation to: 1 ' )
2008-06-26 23:24:52 +00:00
self . _vte . set_background_saturation ( 1 )
2008-09-04 17:41:02 +00:00
if self . _composited_support :
2009-01-19 14:45:08 +00:00
dbg ( ' H9TRANS: Set opacity to: %s ' % opacity )
2008-09-04 17:41:02 +00:00
self . _vte . set_opacity ( opacity )
2008-06-26 23:24:52 +00:00
2009-02-13 10:43:11 +00:00
if background_type == " transparent " :
if not self . conf . enable_real_transparency :
self . _vte . set_background_transparent ( True )
2009-03-20 01:24:24 +00:00
else :
self . _vte . set_background_transparent ( False )
2008-06-26 23:24:52 +00:00
# Set our cursor blinkiness
2008-07-12 15:26:33 +00:00
self . _vte . set_cursor_blinks ( self . conf . cursor_blink )
2008-06-26 23:24:52 +00:00
if self . conf . force_no_bell :
self . _vte . set_audible_bell ( False )
2009-03-20 10:13:29 +00:00
self . _vte . set_visible_bell ( False )
if self . _urgent_bell_cnid :
self . _vte . disconnect ( self . _urgent_bell_cnid )
self . _urgent_bell_cnid = None
else :
# Set our audible belliness
self . _vte . set_audible_bell ( self . conf . audible_bell )
# Set our visual flashiness
self . _vte . set_visible_bell ( self . conf . visible_bell )
# Set our urgent belliness
if self . conf . urgent_bell :
2009-03-26 21:09:30 +00:00
try :
self . _urgent_bell_cnid = self . _vte . connect ( " beep " , self . terminator . on_beep )
except TypeError :
err ( " beep signal not supported by your VTE, urgent handler not available " )
2009-03-20 10:13:29 +00:00
elif self . _urgent_bell_cnid :
self . _vte . disconnect ( self . _urgent_bell_cnid )
self . _urgent_bell_cnid = None
2008-06-26 23:24:52 +00:00
# Set our scrolliness
self . _vte . set_scrollback_lines ( self . conf . scrollback_lines )
self . _vte . set_scroll_on_keystroke ( self . conf . scroll_on_keystroke )
self . _vte . set_scroll_on_output ( self . conf . scroll_on_output )
if self . scrollbar_position != self . conf . scrollbar_position :
self . scrollbar_position = self . conf . scrollbar_position
if self . scrollbar_position == ' hidden ' or self . scrollbar_position == ' disabled ' :
self . _scrollbar . hide ( )
else :
self . _scrollbar . show ( )
if self . scrollbar_position == ' right ' :
self . _termbox . reorder_child ( self . _vte , 0 )
elif self . scrollbar_position == ' left ' :
self . _termbox . reorder_child ( self . _scrollbar , 0 )
2009-03-26 10:36:47 +00:00
if hasattr ( self . _vte , " set_alternate_screen_scroll " ) :
self . _vte . set_alternate_screen_scroll ( self . conf . alternate_screen_scroll )
2008-06-26 23:24:52 +00:00
# Set our sloppiness
self . focus = self . conf . focus
self . _vte . queue_draw ( )
def on_composited_changed ( self , widget ) :
self . reconfigure_vte ( )
def on_vte_button_press ( self , term , event ) :
# Left mouse button + Ctrl while over a link should open it
mask = gtk . gdk . CONTROL_MASK
if ( event . state & mask ) == mask :
if event . button == 1 :
url = self . _vte . match_check ( int ( event . x / self . _vte . get_char_width ( ) ) , int ( event . y / self . _vte . get_char_height ( ) ) )
if url :
2009-03-19 22:03:44 +00:00
self . openurl ( self . prepareurl ( url [ 0 ] , url [ 1 ] ) )
2008-06-26 23:24:52 +00:00
return False
# Left mouse button should transfer focus to this vte widget
# we also need to give focus on the widget where the paste occured
if event . button in ( 1 , 2 ) :
2008-12-26 15:43:02 +00:00
if event . button == 2 and self . _group :
self . paste_clipboard ( True )
return True
2008-06-26 23:24:52 +00:00
self . _vte . grab_focus ( )
return False
# Right mouse button should display a context menu if ctrl not pressed
if event . button == 3 and event . state & gtk . gdk . CONTROL_MASK == 0 :
2008-08-06 22:12:45 +00:00
self . create_popup_menu ( self . _vte , event )
2008-06-26 23:24:52 +00:00
return True
def on_vte_notify_enter ( self , term , event ) :
if ( self . focus == " sloppy " or self . focus == " mouse " ) :
term . grab_focus ( )
return False
def do_scrollbar_toggle ( self ) :
self . toggle_widget_visibility ( self . _scrollbar )
def do_title_toggle ( self ) :
2009-01-30 11:42:28 +00:00
self . _titlebox . wanted = not self . _titlebox . get_property ( ' visible ' )
2008-06-26 23:24:52 +00:00
self . toggle_widget_visibility ( self . _titlebox )
def toggle_widget_visibility ( self , widget ) :
if not isinstance ( widget , gtk . Widget ) :
raise TypeError
if widget . get_property ( ' visible ' ) :
widget . hide ( )
else :
widget . show ( )
2008-12-26 15:43:02 +00:00
def paste_clipboard ( self , primary = False ) :
if self . _group :
for term in self . terminator . term_list :
if term . _group == self . _group :
if primary :
term . _vte . paste_primary ( )
else :
term . _vte . paste_clipboard ( )
else :
if primary :
self . _vte . paste_primary ( )
else :
self . _vte . paste_clipboard ( )
2008-06-26 23:24:52 +00:00
self . _vte . grab_focus ( )
#keybindings for the individual splited terminals (affects only the
#the selected terminal)
2008-08-11 18:02:14 +00:00
UnhandledKeybindings = ( ' close_window ' , ' full_screen ' )
2008-06-26 23:24:52 +00:00
def on_vte_key_press ( self , term , event ) :
2008-10-12 22:42:30 +00:00
if not event :
2008-11-04 17:01:00 +00:00
dbg ( ' on_vte_key_press: Called on %s with no event ' % term )
2008-10-12 22:42:30 +00:00
return False
2008-08-11 18:02:14 +00:00
mapping = self . terminator . keybindings . lookup ( event )
2008-06-26 23:24:52 +00:00
2009-01-25 18:33:22 +00:00
if mapping == " hide_window " :
2009-01-25 14:26:20 +00:00
return False
2008-06-26 23:24:52 +00:00
2008-08-11 18:02:14 +00:00
if mapping and mapping not in self . UnhandledKeybindings :
2008-11-04 17:01:00 +00:00
dbg ( " on_vte_key_press: lookup found %r " % mapping )
2008-08-11 18:02:14 +00:00
getattr ( self , " key_ " + mapping ) ( )
return True
2008-12-11 07:08:28 +00:00
if self . _group and self . _vte . is_focus ( ) :
self . terminator . group_emit ( self , self . _group , ' key-press-event ' , event )
2008-08-11 18:02:14 +00:00
return False
# Key events
2008-08-11 18:16:10 +00:00
def key_zoom_in ( self ) :
self . zoom ( True )
2008-08-11 18:02:14 +00:00
2008-08-11 18:16:10 +00:00
def key_zoom_out ( self ) :
self . zoom ( False )
2008-08-11 18:02:14 +00:00
2008-08-11 18:16:10 +00:00
def key_copy ( self ) :
self . _vte . copy_clipboard ( )
2008-08-11 18:02:14 +00:00
2008-08-11 18:16:10 +00:00
def key_paste ( self ) :
self . paste_clipboard ( )
2008-08-11 18:02:14 +00:00
2008-08-11 18:16:10 +00:00
def key_toggle_scrollbar ( self ) :
self . do_scrollbar_toggle ( )
2008-08-11 18:02:14 +00:00
2008-08-11 18:16:10 +00:00
def key_zoom_normal ( self ) :
self . zoom_orig ( )
2008-08-11 18:02:14 +00:00
2008-08-12 01:12:30 +00:00
def key_search ( self ) :
self . start_search ( )
2008-08-11 18:02:14 +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)
def key_new_root_tab ( self ) :
self . terminator . newtab ( self , True )
def key_go_next ( self ) :
self . terminator . go_next ( self )
def key_go_prev ( self ) :
self . terminator . go_prev ( self )
2008-12-19 07:41:55 +00:00
def key_go_up ( self ) :
self . terminator . go_up ( self )
def key_go_down ( self ) :
self . terminator . go_down ( self )
def key_go_left ( self ) :
self . terminator . go_left ( self )
def key_go_right ( self ) :
self . terminator . go_right ( self )
2008-08-11 18:02:14 +00:00
def key_split_horiz ( self ) :
self . terminator . splitaxis ( self , False )
def key_split_vert ( self ) :
self . terminator . splitaxis ( self , True )
def key_close_term ( self ) :
self . terminator . closeterm ( self )
def key_new_tab ( self ) :
self . terminator . newtab ( self )
def key_resize_up ( self ) :
self . terminator . resizeterm ( self , ' Up ' )
def key_resize_down ( self ) :
self . terminator . resizeterm ( self , ' Down ' )
def key_resize_left ( self ) :
self . terminator . resizeterm ( self , ' Left ' )
def key_resize_right ( self ) :
self . terminator . resizeterm ( self , ' Right ' )
def key_move_tab_right ( self ) :
self . terminator . move_tab ( self , ' right ' )
2008-08-11 18:30:04 +00:00
def key_move_tab_left ( self ) :
2008-08-11 18:02:14 +00:00
self . terminator . move_tab ( self , ' left ' )
def key_toggle_zoom ( self ) :
self . terminator . toggle_zoom ( self )
def key_scaled_zoom ( self ) :
self . terminator . toggle_zoom ( self , True )
2008-08-11 18:30:04 +00:00
def key_next_tab ( self ) :
self . terminator . next_tab ( self )
2008-08-11 18:02:14 +00:00
2008-08-11 18:30:04 +00:00
def key_prev_tab ( self ) :
self . terminator . previous_tab ( self )
2008-11-17 10:42:34 +00:00
2009-01-21 08:29:32 +00:00
def key_switch_to_tab_1 ( self ) :
2009-01-21 05:18:59 +00:00
self . terminator . switch_to_tab ( self , 0 )
2009-01-21 08:29:32 +00:00
def key_switch_to_tab_2 ( self ) :
2009-01-21 05:18:59 +00:00
self . terminator . switch_to_tab ( self , 1 )
2009-01-21 08:29:32 +00:00
def key_switch_to_tab_3 ( self ) :
2009-01-21 05:18:59 +00:00
self . terminator . switch_to_tab ( self , 2 )
2009-01-21 08:29:32 +00:00
def key_switch_to_tab_4 ( self ) :
2009-01-21 05:18:59 +00:00
self . terminator . switch_to_tab ( self , 3 )
2009-01-21 08:29:32 +00:00
def key_switch_to_tab_5 ( self ) :
2009-01-21 05:18:59 +00:00
self . terminator . switch_to_tab ( self , 4 )
2009-01-21 08:29:32 +00:00
def key_switch_to_tab_6 ( self ) :
2009-01-21 05:18:59 +00:00
self . terminator . switch_to_tab ( self , 5 )
2009-01-21 08:29:32 +00:00
def key_switch_to_tab_7 ( self ) :
2009-01-21 05:18:59 +00:00
self . terminator . switch_to_tab ( self , 6 )
2009-01-21 08:29:32 +00:00
def key_switch_to_tab_8 ( self ) :
2009-01-21 05:18:59 +00:00
self . terminator . switch_to_tab ( self , 7 )
2009-01-21 08:29:32 +00:00
def key_switch_to_tab_9 ( self ) :
2009-01-21 05:18:59 +00:00
self . terminator . switch_to_tab ( self , 8 )
2009-01-21 08:29:32 +00:00
def key_switch_to_tab_10 ( self ) :
2009-01-21 05:18:59 +00:00
self . terminator . switch_to_tab ( self , 9 )
2008-11-17 10:42:34 +00:00
def key_reset ( self ) :
self . _vte . reset ( True , False )
def key_reset_clear ( self ) :
self . _vte . reset ( True , True )
2008-08-11 18:02:14 +00:00
# End key events
2008-06-26 23:24:52 +00:00
def zoom_orig ( self ) :
2008-08-26 21:24:36 +00:00
self . _custom_font_size = None
2008-06-26 23:24:52 +00:00
self . _vte . set_font ( pango . FontDescription ( self . conf . font ) )
def zoom ( self , zoom_in ) :
pangodesc = self . _vte . get_font ( )
fontsize = pangodesc . get_size ( )
if fontsize > pango . SCALE and not zoom_in :
fontsize - = pango . SCALE
elif zoom_in :
fontsize + = pango . SCALE
pangodesc . set_size ( fontsize )
2008-08-26 21:24:36 +00:00
self . _custom_font_size = fontsize
2008-06-26 23:24:52 +00:00
self . _vte . set_font ( pangodesc )
2008-08-12 01:12:30 +00:00
def start_search ( self ) :
self . _searchbox . show ( )
self . _searchinput . grab_focus ( )
def search_keypress ( self , widget , event ) :
key = gtk . gdk . keyval_name ( event . keyval )
if key == ' Escape ' :
self . end_search ( )
2008-09-25 21:33:45 +00:00
def end_search ( self , widget = None ) :
2008-08-12 01:12:30 +00:00
self . _search_row = 0
self . _search_string = None
self . _search_result_label . set_text ( " " )
self . _searchbox . hide ( )
2008-08-12 23:17:40 +00:00
self . _scrollbar . set_value ( self . _vte . get_cursor_position ( ) [ 1 ] )
2008-08-12 01:12:30 +00:00
self . _vte . grab_focus ( )
def do_search ( self , widget ) :
string = widget . get_text ( )
2008-11-04 17:01:00 +00:00
dbg ( " do_search: Looking for %r " % string )
2008-08-12 01:12:30 +00:00
if string == ' ' :
return
if string != self . _search_string :
2008-08-12 23:17:40 +00:00
self . _search_row = self . _get_vte_buffer_range ( ) [ 0 ]
2008-08-12 01:12:30 +00:00
self . _search_string = string
self . _search_result_label . set_text ( " Searching scrollback " )
self . next_search ( )
# Called by get_text_range, once per character. Argh.
def _search_character ( self , widget , col , row , junk ) :
return True
2008-09-25 21:40:44 +00:00
def next_search ( self , widget = None ) :
2008-08-12 23:17:40 +00:00
startrow , endrow = self . _get_vte_buffer_range ( )
2008-08-12 01:12:30 +00:00
while True :
2008-08-12 23:17:40 +00:00
if self . _search_row == endrow :
self . _search_row = startrow
2008-08-12 01:12:30 +00:00
self . _search_result_label . set_text ( " Finished Search " )
2008-09-25 21:40:44 +00:00
self . _search_next . hide ( )
2008-08-12 01:12:30 +00:00
return
2008-08-12 23:17:40 +00:00
buffer = self . _vte . get_text_range ( self . _search_row , 0 , self . _search_row , - 1 , self . _search_character )
2008-08-12 01:12:30 +00:00
2008-11-04 17:01:00 +00:00
# dbg("Row %d buffer: %r" % (self._search_row, buffer))
2008-08-12 01:12:30 +00:00
index = buffer . find ( self . _search_string )
if index != - 1 :
self . _search_result_label . set_text ( " Found at row %d " % self . _search_row )
2008-08-12 23:17:40 +00:00
self . _scrollbar . set_value ( self . _search_row )
2008-08-12 01:12:30 +00:00
self . _search_row + = 1
2008-09-25 21:40:44 +00:00
self . _search_next . show ( )
2008-08-12 01:12:30 +00:00
return
self . _search_row + = 1
2008-08-12 23:17:40 +00:00
def _get_vte_buffer_range ( self ) :
column , endrow = self . _vte . get_cursor_position ( )
startrow = max ( 0 , endrow - self . conf . scrollback_lines )
return ( startrow , endrow )
2008-08-12 01:12:30 +00:00
2008-12-19 23:17:43 +00:00
def get_geometry ( self ) :
''' Returns Gdk.Window.get_position(), pixel-based cursor position,
and Gdk . Window . get_geometry ( ) '''
reply = dict ( )
x , y = self . _vte . window . get_origin ( )
reply . setdefault ( ' origin_x ' , x )
reply . setdefault ( ' origin_y ' , y )
2008-12-19 07:41:55 +00:00
column , row = self . _vte . get_cursor_position ( )
cursor_x = column * self . _vte . get_char_width ( )
2008-12-19 23:17:43 +00:00
cursor_y = row * self . _vte . get_char_height ( )
reply . setdefault ( ' cursor_x ' , cursor_x )
reply . setdefault ( ' cursor_y ' , cursor_y )
geometry = self . _vte . window . get_geometry ( )
reply . setdefault ( ' offset_x ' , geometry [ 0 ] )
reply . setdefault ( ' offset_y ' , geometry [ 1 ] )
reply . setdefault ( ' span_x ' , geometry [ 2 ] )
reply . setdefault ( ' span_y ' , geometry [ 3 ] )
reply . setdefault ( ' depth ' , geometry [ 4 ] )
return reply
2008-12-19 07:41:55 +00:00
2008-08-06 22:12:45 +00:00
def create_popup_menu ( self , widget , event = None ) :
2008-06-26 23:24:52 +00:00
menu = gtk . Menu ( )
url = None
2009-03-19 22:03:44 +00:00
address = None
2008-06-26 23:24:52 +00:00
if event :
url = self . _vte . match_check ( int ( event . x / self . _vte . get_char_width ( ) ) , int ( event . y / self . _vte . get_char_height ( ) ) )
2008-08-06 22:12:45 +00:00
button = event . button
time = event . time
else :
button = 0
time = 0
2008-06-26 23:24:52 +00:00
if url :
2009-03-19 22:03:44 +00:00
address = self . prepareurl ( url [ 0 ] , url [ 1 ] )
if url [ 1 ] == self . matches [ ' email ' ] :
nameopen = _ ( " _Send Mail To... " )
namecopy = _ ( " _Copy Email Address " )
item = gtk . MenuItem ( nameopen )
2009-03-25 13:04:49 +00:00
elif url [ 1 ] == self . matches [ ' voip ' ] :
nameopen = _ ( " Ca_ll To... " )
namecopy = _ ( " _Copy Call Address " )
item = gtk . MenuItem ( nameopen )
2009-03-19 22:03:44 +00:00
else :
2008-06-26 23:24:52 +00:00
nameopen = _ ( " _Open Link " )
namecopy = _ ( " _Copy Link Address " )
iconopen = gtk . image_new_from_stock ( gtk . STOCK_JUMP_TO , gtk . ICON_SIZE_MENU )
item = gtk . ImageMenuItem ( nameopen )
item . set_property ( ' image ' , iconopen )
2008-07-04 06:29:32 +00:00
item . connect ( " activate " , lambda menu_item : self . openurl ( address ) )
2008-06-26 23:24:52 +00:00
menu . append ( item )
item = gtk . MenuItem ( namecopy )
item . connect ( " activate " , lambda menu_item : self . clipboard . set_text ( url [ 0 ] ) )
menu . append ( item )
item = gtk . MenuItem ( )
menu . append ( item )
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 )
item = gtk . ImageMenuItem ( gtk . STOCK_PASTE )
item . connect ( " activate " , lambda menu_item : self . paste_clipboard ( ) )
menu . append ( item )
item = gtk . MenuItem ( )
menu . append ( item )
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 )
item = gtk . CheckMenuItem ( _ ( " Show _titlebar " ) )
item . set_active ( self . _titlebox . get_property ( ' visible ' ) )
item . connect ( " toggled " , lambda menu_item : self . do_title_toggle ( ) )
2008-12-10 18:16:55 +00:00
if self . _group :
item . set_sensitive ( False )
2008-06-26 23:24:52 +00:00
menu . append ( item )
self . _do_encoding_items ( menu )
item = gtk . MenuItem ( )
menu . append ( item )
if not self . terminator . _zoomed :
str_horiz = _ ( " Split H_orizontally " )
str_vert = _ ( " Split V_ertically " )
item = gtk . ImageMenuItem ( str_horiz )
item_image = gtk . Image ( )
item_image . set_from_icon_name ( APP_NAME + ' _horiz ' , gtk . ICON_SIZE_MENU )
item . set_image ( item_image )
item . connect ( " activate " , lambda menu_item : self . terminator . splitaxis ( self , False ) )
menu . append ( item )
item = gtk . ImageMenuItem ( str_vert )
item_image = gtk . Image ( )
item_image . set_from_icon_name ( APP_NAME + ' _vert ' , gtk . ICON_SIZE_MENU )
item . set_image ( item_image )
item . connect ( " activate " , lambda menu_item : self . terminator . splitaxis ( self , True ) )
menu . append ( item )
2008-08-07 20:34:47 +00:00
2008-06-26 23:24:52 +00:00
item = gtk . MenuItem ( _ ( " Open _Tab " ) )
item . connect ( " activate " , lambda menu_item : self . terminator . newtab ( self ) )
menu . append ( item )
2008-08-07 20:34:47 +00:00
if self . terminator . debugaddress :
item = gtk . MenuItem ( _ ( " Open _Debug Tab " ) )
item . connect ( " activate " , lambda menu_item : self . terminator . newtab ( self , command = " telnet %s " % ' ' . join ( [ str ( x ) for x in self . terminator . debugaddress ] ) ) )
menu . append ( item )
2008-06-26 23:24:52 +00:00
if self . conf . extreme_tabs :
item = gtk . MenuItem ( _ ( " Open Top Level Tab " ) )
item . connect ( " activate " , lambda menu_item : self . terminator . newtab ( self , True ) )
menu . append ( item )
item = gtk . MenuItem ( )
menu . append ( item )
if len ( self . terminator . term_list ) > 1 :
if not self . terminator . _zoomed :
item = gtk . MenuItem ( _ ( " _Zoom terminal " ) )
item . connect ( " activate " , lambda menu_item : self . terminator . toggle_zoom ( self , True ) )
menu . append ( item )
2008-07-11 23:56:44 +00:00
item = gtk . MenuItem ( _ ( " Ma_ximise terminal " ) )
2008-06-26 23:24:52 +00:00
item . connect ( " activate " , lambda menu_item : self . terminator . toggle_zoom ( self ) )
menu . append ( item )
else :
if self . terminator . _zoomed and not self . terminator . _maximised :
item = gtk . MenuItem ( _ ( " _Unzoom terminal " ) )
item . connect ( " activate " , lambda menu_item : self . terminator . toggle_zoom ( self , True ) )
menu . append ( item )
if self . terminator . _zoomed and self . terminator . _maximised :
2008-07-11 23:56:44 +00:00
item = gtk . MenuItem ( _ ( " Unma_ximise terminal " ) )
2008-06-26 23:24:52 +00:00
item . connect ( " activate " , lambda menu_item : self . terminator . toggle_zoom ( self ) )
menu . append ( item )
item = gtk . MenuItem ( )
menu . append ( item )
2008-11-01 00:50:34 +00:00
item = gtk . MenuItem ( _ ( " Ed_it profile " ) )
item . connect ( " activate " , lambda menu_item : self . terminator . edit_profile ( self ) )
menu . append ( item )
item = gtk . MenuItem ( )
menu . append ( item )
2008-12-10 18:16:55 +00:00
item = gtk . MenuItem ( _ ( " _Group " ) )
menu . append ( item )
submenu = gtk . Menu ( )
item . set_submenu ( submenu )
self . populate_grouping_menu ( submenu )
2008-12-11 08:07:28 +00:00
if len ( self . terminator . term_list ) == 1 :
item . set_sensitive ( False )
2008-12-10 18:16:55 +00:00
item = gtk . MenuItem ( )
menu . append ( item )
2008-06-26 23:24:52 +00:00
item = gtk . ImageMenuItem ( gtk . STOCK_CLOSE )
item . connect ( " activate " , lambda menu_item : self . terminator . closeterm ( self ) )
menu . append ( item )
menu . show_all ( )
2008-08-06 22:12:45 +00:00
menu . popup ( None , None , None , button , time )
return True
2008-06-26 23:24:52 +00:00
2008-12-10 18:16:55 +00:00
def populate_grouping_menu ( self , widget ) :
groupitem = None
if len ( self . terminator . groupings ) > 0 :
groupitem = gtk . RadioMenuItem ( groupitem , _ ( " None " ) )
groupitem . set_active ( self . _group == None )
groupitem . connect ( " activate " , self . set_group , None )
widget . append ( groupitem )
for group in self . terminator . groupings :
item = gtk . RadioMenuItem ( groupitem , group )
item . set_active ( self . _group == group )
item . connect ( " toggled " , self . set_group , group )
widget . append ( item )
groupitem = item
item = gtk . MenuItem ( )
widget . append ( item )
2008-12-11 07:08:28 +00:00
item = gtk . MenuItem ( _ ( " _New group " ) )
2008-12-10 18:16:55 +00:00
item . connect ( " activate " , self . create_group )
widget . append ( item )
2008-12-11 08:07:28 +00:00
item = gtk . MenuItem ( )
widget . append ( item )
item = gtk . MenuItem ( _ ( " _Group all " ) )
item . connect ( " activate " , self . group_all )
widget . append ( item )
2009-01-06 09:44:38 +00:00
if len ( self . terminator . groupings ) > 0 :
item = gtk . MenuItem ( _ ( " _Ungroup all " ) )
item . connect ( " activate " , self . ungroup_all )
widget . append ( item )
2008-12-10 18:16:55 +00:00
def create_group ( self , item ) :
2008-12-11 07:08:28 +00:00
win = gtk . Window ( )
vbox = gtk . VBox ( )
hbox = gtk . HBox ( )
entrybox = gtk . HBox ( )
win . add ( vbox )
label = gtk . Label ( _ ( " Group name: " ) )
entry = gtk . Entry ( )
okbut = gtk . Button ( stock = gtk . STOCK_OK )
canbut = gtk . Button ( stock = gtk . STOCK_CANCEL )
entrybox . pack_start ( label , False , True )
entrybox . pack_start ( entry , True , True )
hbox . pack_end ( okbut , False , False )
hbox . pack_end ( canbut , False , False )
vbox . pack_start ( entrybox , False , True )
vbox . pack_start ( hbox , False , True )
canbut . connect ( " clicked " , lambda kill : win . destroy ( ) )
okbut . connect ( " clicked " , self . do_create_group , win , entry )
entry . connect ( " activate " , self . do_create_group , win , entry )
win . show_all ( )
def do_create_group ( self , widget , window , entry ) :
name = entry . get_text ( )
self . terminator . groupings . append ( name )
self . set_group ( None , name )
window . destroy ( )
2008-12-10 18:16:55 +00:00
def set_group ( self , item , data ) :
if self . _group == data :
# No action needed
return
2009-01-30 12:04:59 +00:00
else :
self . _group = data
2009-01-26 00:20:03 +00:00
self . _titlebox . set_group_label ( data )
2009-01-30 12:04:59 +00:00
self . _titlebox . update ( )
2008-12-10 18:16:55 +00:00
2009-01-30 12:04:59 +00:00
self . terminator . group_hoover ( )
2008-12-10 18:16:55 +00:00
2008-12-11 08:07:28 +00:00
def group_all ( self , widget ) :
allname = _ ( " All " )
if not allname in self . terminator . groupings :
self . terminator . groupings . append ( allname )
for term in self . terminator . term_list :
term . set_group ( None , allname )
self . terminator . group_hoover ( )
2009-01-06 09:44:38 +00:00
def ungroup_all ( self , widget ) :
for term in self . terminator . term_list :
term . set_group ( None , None )
self . terminator . group_hoover ( )
2008-06-26 23:24:52 +00:00
def on_encoding_change ( self , widget , encoding ) :
current = self . _vte . get_encoding ( )
if current != encoding :
dbg ( ' Setting Encoding to: %s ' % encoding )
self . _vte . set_encoding ( encoding )
def _do_encoding_items ( self , menu ) :
active_encodings = self . conf . active_encodings
item = gtk . MenuItem ( _ ( " Encodings " ) )
menu . append ( item )
submenu = gtk . Menu ( )
item . set_submenu ( submenu )
current_encoding = self . _vte . get_encoding ( )
group = None
for encoding in active_encodings :
radioitem = gtk . RadioMenuItem ( group , _ ( encoding ) )
if group is None :
group = radioitem
if encoding == current_encoding :
radioitem . set_active ( True )
radioitem . connect ( ' activate ' , self . on_encoding_change , encoding )
submenu . append ( radioitem )
item = gtk . MenuItem ( _ ( " Other Encodings " ) )
submenu . append ( item )
#second level
submenu = gtk . Menu ( )
item . set_submenu ( submenu )
encodings = TerminatorEncoding ( ) . get_list ( )
encodings . sort ( lambda x , y : cmp ( x [ 2 ] . lower ( ) , y [ 2 ] . lower ( ) ) )
group = None
for encoding in encodings :
if encoding [ 1 ] in active_encodings :
continue
if encoding [ 1 ] is None :
label = " %s %s " % ( encoding [ 2 ] , self . _vte . get_encoding ( ) )
else :
label = " %s %s " % ( encoding [ 2 ] , encoding [ 1 ] )
radioitem = gtk . RadioMenuItem ( group , label )
if group is None :
group = radioitem
if encoding [ 1 ] == current_encoding :
radioitem . set_active ( True )
radioitem . connect ( ' activate ' , self . on_encoding_change , encoding [ 1 ] )
submenu . append ( radioitem )
2008-08-05 10:28:46 +00:00
2008-08-07 22:07:21 +00:00
def get_window_title ( self , vte = None ) :
if vte is None :
vte = self . _vte
2008-08-07 20:34:47 +00:00
title = vte . get_window_title ( )
if title is None :
title = str ( self . command )
return title
2008-06-26 23:24:52 +00:00
def on_vte_title_change ( self , vte ) :
2008-08-07 22:07:21 +00:00
title = self . get_window_title ( vte )
2008-10-20 08:29:47 +00:00
if title == self . _oldtitle :
# Title hasn't changed, don't bother doing anything
return
self . _oldtitle = title
2008-06-26 23:24:52 +00:00
if self . conf . titletips :
vte . set_property ( " has-tooltip " , True )
2008-08-07 20:34:47 +00:00
vte . set_property ( " tooltip-text " , title )
2008-06-26 23:24:52 +00:00
#set the title anyhow, titlebars setting only show/hide the label
2009-01-26 00:20:03 +00:00
self . _titlebox . set_terminal_title ( title )
2008-11-17 11:19:12 +00:00
self . terminator . set_window_title ( " %s - %s " % ( re . sub ( ' - %s ' % APP_NAME . capitalize ( ) , ' ' , title ) , APP_NAME . capitalize ( ) ) )
2008-06-26 23:24:52 +00:00
notebookpage = self . terminator . get_first_notebook_page ( vte )
while notebookpage != None :
2008-06-27 17:11:24 +00:00
if notebookpage [ 0 ] . get_tab_label ( notebookpage [ 1 ] ) :
label = notebookpage [ 0 ] . get_tab_label ( notebookpage [ 1 ] )
2008-08-07 20:34:47 +00:00
label . set_title ( title )
2008-06-27 17:11:24 +00:00
notebookpage [ 0 ] . set_tab_label ( notebookpage [ 1 ] , label )
2008-06-26 23:24:52 +00:00
notebookpage = self . terminator . get_first_notebook_page ( notebookpage [ 0 ] )
def on_vte_focus_in ( self , vte , event ) :
2009-01-30 12:04:59 +00:00
self . _titlebox . set_background_color ( self . terminator . window . get_style ( ) . bg [ gtk . STATE_SELECTED ] )
2008-06-26 23:24:52 +00:00
return
2008-08-05 10:28:46 +00:00
2008-06-26 23:24:52 +00:00
def on_vte_focus_out ( self , vte , event ) :
2009-01-30 12:04:59 +00:00
self . _titlebox . set_background_color ( self . terminator . window . get_style ( ) . bg [ gtk . STATE_NORMAL ] )
2008-06-26 23:24:52 +00:00
return
def on_vte_focus ( self , vte ) :
2008-08-07 22:07:21 +00:00
title = self . get_window_title ( vte )
2008-08-07 20:34:47 +00:00
self . terminator . set_window_title ( " %s - %s " % ( title , APP_NAME . capitalize ( ) ) )
notebookpage = self . terminator . get_first_notebook_page ( vte )
while notebookpage != None :
if notebookpage [ 0 ] . get_tab_label ( notebookpage [ 1 ] ) :
label = notebookpage [ 0 ] . get_tab_label ( notebookpage [ 1 ] )
label . set_title ( title )
notebookpage [ 0 ] . set_tab_label ( notebookpage [ 1 ] , label )
notebookpage = self . terminator . get_first_notebook_page ( notebookpage [ 0 ] )
2009-02-16 14:03:42 +00:00
def is_scrollbar_present ( self ) :
return self . _scrollbar . get_property ( ' visible ' )
2008-06-26 23:24:52 +00:00