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
2009-12-01 22:57:54 +00:00
import os , signal , sys , subprocess , pwd , re , urllib2
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
2009-08-14 18:15:32 +00:00
from terminatorlib . terminatoreditablelabel import TerminatorEditableLabel
2009-05-07 00:44:42 +00:00
# import translation support
from terminatorlib import translation
2008-06-26 23:24:52 +00:00
# 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
2009-04-30 20:55:30 +00:00
_termtext = " "
_sizetext = " "
2009-01-26 00:20:03 +00:00
_group = None
_separator = None
_hbox = None
2009-07-13 22:53:57 +00:00
_ebox = None
_grouphbox = 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-08-02 22:44:51 +00:00
_terminal = None
2009-07-13 22:36:45 +00:00
terminator = None
2009-01-26 00:20:03 +00:00
2009-08-02 22:44:51 +00:00
def __init__ ( self , terminal , terminator , configwanted = False ) :
2009-01-26 00:20:03 +00:00
gtk . EventBox . __init__ ( self )
2009-01-30 12:04:59 +00:00
2009-08-14 18:15:32 +00:00
self . _title = TerminatorEditableLabel ( )
2009-01-26 00:20:03 +00:00
self . _group = gtk . Label ( )
self . _separator = gtk . VSeparator ( )
2009-07-13 22:53:57 +00:00
self . _ebox = gtk . EventBox ( )
self . _grouphbox = gtk . HBox ( )
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-08-02 22:44:51 +00:00
self . _terminal = terminal
2009-01-26 00:20:03 +00:00
2009-07-13 22:36:45 +00:00
self . terminator = terminator
if self . terminator . groupsend == 2 :
self . set_from_icon_name ( APP_NAME + \
' _active_broadcast_all ' , gtk . ICON_SIZE_MENU )
elif self . terminator . groupsend == 1 :
self . set_from_icon_name ( APP_NAME + \
' _active_broadcast_group ' , gtk . ICON_SIZE_MENU )
else :
self . set_from_icon_name ( APP_NAME + \
' _active_broadcast_off ' , gtk . ICON_SIZE_MENU )
2009-07-13 22:53:57 +00:00
self . _grouphbox . pack_start ( self . _icon , False , True , 2 )
self . _grouphbox . pack_start ( self . _group , False , True , 2 )
self . _ebox . add ( self . _grouphbox )
self . _ebox . show_all ( )
2009-08-02 22:44:51 +00:00
self . _hbox . pack_start ( self . _ebox , False , True , 0 )
self . _hbox . pack_start ( self . _separator , False , True , 0 )
2009-01-26 00:20:03 +00:00
self . _hbox . pack_start ( self . _title , True , True )
self . add ( self . _hbox )
2009-08-14 18:15:32 +00:00
self . _title . show_all ( )
2009-01-26 00:20:03 +00:00
self . _hbox . show ( )
2009-01-30 12:04:59 +00:00
self . wanted = configwanted
2009-08-14 18:15:32 +00:00
self . connect ( " button-press-event " , self . on_clicked )
2009-06-09 22:47:59 +00:00
2009-07-13 22:53:57 +00:00
def connect_icon ( self , func ) :
self . _ebox . connect ( " button-release-event " , func )
2009-06-09 22:47:59 +00:00
def on_clicked ( self , widget , event ) :
if self . _parent is not None :
self . _parent . _vte . grab_focus ( )
2009-08-14 18:15:32 +00:00
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 ( )
else :
self . _group . hide ( )
2009-08-02 22:44:51 +00:00
self . _separator . show ( )
2009-01-26 00:20:03 +00:00
def set_terminal_title ( self , name ) :
2009-04-30 20:55:30 +00:00
""" Set the title text shown in the titlebar """
self . _termtext = name
self . update_label ( )
def set_terminal_size ( self , width , height ) :
""" Set the terminal size shown in the titlebar """
self . _sizetext = " %s x %s " % ( width , height )
self . update_label ( )
def update_label ( self ) :
""" Update the gtk label with values previously set """
self . _title . set_text ( " %s %s " % ( self . _termtext , self . _sizetext ) )
2009-01-26 00:20:03 +00:00
2009-02-02 17:18:40 +00:00
def get_terminal_title ( self ) :
""" Return the text showin in the titlebar """
2009-04-30 20:55:30 +00:00
return ( self . _termtext )
2009-02-02 17:18:40 +00:00
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-08-02 22:44:51 +00:00
def update_colors ( self , source ) :
""" Update terminals titlebar colours based on grouping """
term = self . _terminal
if term != source and term . _group != None and term . _group == source . _group :
# Not active, group is not none, and in active's group
if self . terminator . groupsend == 0 :
title_fg = term . conf . title_ia_txt_color
title_bg = term . conf . title_ia_bg_color
icon = ' _receive_off '
else :
title_fg = term . conf . title_rx_txt_color
title_bg = term . conf . title_rx_bg_color
icon = ' _receive_on '
group_fg = term . conf . title_rx_txt_color
group_bg = term . conf . title_rx_bg_color
elif term != source and term . _group == None or term . _group != source . _group :
# Not active, group is not none, not in active's group
if self . terminator . groupsend == 2 :
title_fg = term . conf . title_rx_txt_color
title_bg = term . conf . title_rx_bg_color
icon = ' _receive_on '
else :
title_fg = term . conf . title_ia_txt_color
title_bg = term . conf . title_ia_bg_color
icon = ' _receive_off '
group_fg = term . conf . title_ia_txt_color
group_bg = term . conf . title_ia_bg_color
else :
title_fg = term . conf . title_tx_txt_color
title_bg = term . conf . title_tx_bg_color
if self . terminator . groupsend == 2 :
icon = ' _active_broadcast_all '
elif self . terminator . groupsend == 1 :
icon = ' _active_broadcast_group '
else :
icon = ' _active_broadcast_off '
group_fg = term . conf . title_tx_txt_color
group_bg = term . conf . title_tx_bg_color
self . _title . modify_fg ( gtk . STATE_NORMAL , gtk . gdk . color_parse ( title_fg ) )
self . _group . modify_fg ( gtk . STATE_NORMAL , gtk . gdk . color_parse ( group_fg ) )
self . modify_bg ( gtk . STATE_NORMAL , gtk . gdk . color_parse ( title_bg ) )
self . _ebox . modify_bg ( gtk . STATE_NORMAL , gtk . gdk . color_parse ( group_bg ) )
self . set_from_icon_name ( icon , gtk . ICON_SIZE_MENU )
return
2009-01-27 00:31:48 +00:00
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 ) :
2009-04-09 10:23:33 +00:00
if not self . _unzoomed_title :
self . _unzoomed_title = self . get_terminal_title ( )
if self . _parent . conf . zoomedtitlebar :
self . set_terminal_title ( " Zoomed/Maximised terminal, %d hidden " % ( len ( self . _parent . terminator . term_list ) - 1 ) )
self . show ( )
else :
self . hide ( )
2009-02-02 17:18:40 +00:00
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
2009-08-04 01:56:02 +00:00
_custom_encoding = None
_default_encoding = 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 ( )
2009-08-04 01:56:02 +00:00
self . _default_encoding = self . _vte . get_encoding ( )
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-08-02 22:44:51 +00:00
self . _titlebox = TerminatorTermTitle ( self , self . terminator , 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 )
2009-04-30 20:55:30 +00:00
self . _vte . connect ( " size-allocate " , self . on_vte_size_allocate )
2008-07-03 22:48:29 +00:00
2009-07-13 22:53:57 +00:00
self . _titlebox . connect_icon ( self . on_group_button_press )
2009-01-12 11:13:22 +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
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 )
os . putenv ( ' COLORTERM ' , ' gnome-terminal ' )
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
2009-12-29 21:52:13 +00:00
elif match == self . matches [ ' launchpad-bug ' ] :
2009-08-18 17:59:06 +00:00
for item in re . findall ( r ' [0-9]+ ' , url ) :
url = ' https://bugs.launchpad.net/bugs/ %s ' % item
return url
2009-12-29 21:52:13 +00:00
elif match == self . matches [ ' launchpad-branch ' ] :
url = url [ 3 : ] if url . startswith ( ' lp: ' ) else url
url = ' https://code.launchpad.net/+branch/ %s ' % url
2009-12-24 11:59:41 +00:00
elif match == self . matches [ ' apturl ' ] :
# xdg-open will work as-is with apt: URLs
pass
2009-03-19 22:03:44 +00:00
return url
2008-07-03 22:48:29 +00:00
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 ) )
2009-04-30 20:55:30 +00:00
def on_vte_size_allocate ( self , widget , allocation ) :
2009-10-22 19:47:51 +00:00
dbg ( ' Terminal resized to %d x %d ' % ( self . _vte . get_column_count ( ) , self . _vte . get_row_count ( ) ) )
2009-04-30 20:55:30 +00:00
self . _titlebox . set_terminal_size ( self . _vte . get_column_count ( ) , self . _vte . get_row_count ( ) )
2009-12-02 00:19:26 +00:00
if self . _vte . window != None and ( self . conf . geometry_hinting ) :
2009-10-22 19:47:51 +00:00
self . terminator . on_term_resized ( )
2009-04-30 20:55:30 +00:00
2009-05-17 11:45:38 +00:00
def get_pixbuf ( self , maxsize = None ) :
pixmap = self . get_snapshot ( )
2009-05-16 21:17:04 +00:00
( width , height ) = pixmap . get_size ( )
pixbuf = gtk . gdk . Pixbuf ( gtk . gdk . COLORSPACE_RGB , False , 8 , width , height )
pixbuf . get_from_drawable ( pixmap , pixmap . get_colormap ( ) , 0 , 0 , 0 , 0 , width , height )
longest = max ( width , height )
2009-05-17 11:45:38 +00:00
if maxsize is not None :
factor = float ( maxsize ) / float ( longest )
if not maxsize or ( width * factor ) > width or ( height * factor ) > height :
2009-05-16 21:17:04 +00:00
factor = 1
scaledpixbuf = pixbuf . scale_simple ( int ( width * factor ) , int ( height * factor ) , gtk . gdk . INTERP_BILINEAR )
2009-05-17 11:45:38 +00:00
return ( scaledpixbuf )
2008-06-26 23:24:52 +00:00
def on_drag_begin ( self , widget , drag_context , data ) :
dbg ( ' Drag begins ' )
2009-05-17 11:45:38 +00:00
widget . drag_source_set_icon_pixbuf ( self . get_pixbuf ( 512 ) )
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
2009-01-10 16:13:49 +00:00
def get_target_terms ( self ) :
if self . terminator . groupsend == 2 :
return self . terminator . term_list
2009-01-14 12:36:32 +00:00
elif self . terminator . groupsend == 1 :
2009-01-10 16:13:49 +00:00
term_subset = [ ]
for term in self . terminator . term_list :
if term == self or ( term . _group != None and term . _group == self . _group ) :
term_subset . append ( term )
return term_subset
2009-01-14 12:36:32 +00:00
else :
return [ self ]
2009-01-10 16:13:49 +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:// " :
2009-12-01 22:57:54 +00:00
txt = " ' %s ' " % urllib2 . unquote ( txt [ 7 : ] )
2009-01-10 16:13:49 +00:00
for term in self . get_target_terms ( ) :
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 "
2009-07-10 15:46:52 +00:00
pathchars = " -A-Za-z0-9_$.+!*(),;:@&=?/~# % ' \" "
2008-06-26 23:24:52 +00:00
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 )
2009-12-24 11:59:41 +00:00
self . matches [ ' apturl ' ] = self . _vte . match_add ( ' \\ bapt.* \\ b ' )
2009-12-30 00:50:47 +00:00
# if the url looks like a Launchpad changelog closure entry LP: #92953 - make it a url to http://bugs.launchpad.net
# the regular expression is similar to the perl one specified in the Ubuntu Policy Manual - /lp:\s+\#\d+(?:,\s*\#\d+)*/i
self . matches [ ' launchpad-bug ' ] = self . _vte . match_add ( ' \\ b(lp|LP):? \ s?#?[0-9]+(, \ s*#?[0-9]+)* \\ b ' )
# same for Bazaar branches hosted on Launchpad
lpfilters = { }
lpfilters [ ' project ' ] = ' [a-z0-9] {1} [a-z0-9 \ . \ - \ +]+ '
lpfilters [ ' group ' ] = ' ~ %s ' % lpfilters [ ' project ' ]
lpfilters [ ' series ' ] = lpfilters [ ' project ' ]
lpfilters [ ' branch ' ] = ' [a-zA-Z0-9] {1} [a-zA-Z0-9_+@.-]+ '
2009-12-30 01:02:42 +00:00
self . matches [ ' launchpad-branch ' ] = self . _vte . match_add ( ' \\ b((lp|LP): %(project)s (/ %(series)s )?|(lp|LP): %(group)s /( %(project)s | \ +junk)/ %(branch)s ) \\ b ' % lpfilters )
2009-12-24 11:59:41 +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 )
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
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
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 )
2009-08-04 01:56:02 +00:00
# Set our charset
if self . _custom_encoding == False or self . _custom_encoding == None :
self . _vte . set_encoding ( self . conf . encoding )
2008-06-26 23:24:52 +00:00
# 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
2009-09-02 10:01:30 +00:00
if background_type == " image " and self . conf . background_image is not None and self . conf . background_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 " ) :
2009-07-02 20:35:18 +00:00
self . _vte . set_background_tint_color ( gtk . gdk . color_parse ( self . conf . background_color ) )
2008-06-26 23:24:52 +00:00
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-07-02 20:30:53 +00:00
dbg ( ' H9TRANS: Set background tint color to: %s ' % self . conf . background_color )
2009-01-19 14:45:08 +00:00
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
2009-04-09 10:23:33 +00:00
# Sync our titlebar state
self . _titlebox . update ( )
2008-06-26 23:24:52 +00:00
self . _vte . queue_draw ( )
2009-10-22 19:47:51 +00:00
def get_size_details ( self ) :
font_width = self . _vte . get_char_width ( )
font_height = self . _vte . get_char_height ( )
columns = self . _vte . get_column_count ( )
rows = self . _vte . get_row_count ( )
return ( font_width , font_height , columns , rows )
2008-06-26 23:24:52 +00:00
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 ) :
2009-01-14 12:36:32 +00:00
if event . button == 2 :
2008-12-26 15:43:02 +00:00
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
2009-01-10 16:13:49 +00:00
def do_autocleangroups_toggle ( self ) :
self . terminator . autocleangroups = not self . terminator . autocleangroups
2009-01-13 21:10:28 +00:00
if self . terminator . autocleangroups :
self . terminator . group_hoover ( )
2009-01-10 16:13:49 +00:00
2008-06-26 23:24:52 +00:00
def do_scrollbar_toggle ( self ) :
self . toggle_widget_visibility ( self . _scrollbar )
2009-01-10 16:13:49 +00:00
def do_splittogroup_toggle ( self ) :
self . terminator . splittogroup = not self . terminator . splittogroup
2008-06-26 23:24:52 +00:00
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 ) :
2009-01-10 16:13:49 +00:00
for term in self . get_target_terms ( ) :
2008-12-26 15:43:02 +00:00
if primary :
2009-01-10 16:13:49 +00:00
term . _vte . paste_primary ( )
2008-12-26 15:43:02 +00:00
else :
2009-01-10 16:13:49 +00:00
term . _vte . paste_clipboard ( )
2008-06-26 23:24:52 +00:00
self . _vte . grab_focus ( )
2009-01-07 18:39:12 +00:00
def do_enumerate ( self , pad = False ) :
2009-01-10 16:13:49 +00:00
if pad :
numstr = ' % 0 ' + str ( len ( str ( len ( self . terminator . term_list ) ) ) ) + ' d '
else :
numstr = ' %d '
for term in self . get_target_terms ( ) :
idx = self . terminator . term_list . index ( term )
term . _vte . feed_child ( numstr % ( idx + 1 ) )
2009-01-07 18:39:12 +00:00
2008-06-26 23:24:52 +00:00
#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 :
2009-03-27 12:20:12 +00:00
dbg ( " on_vte_key_press: 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>
if ( mapping == " copy " and event . state & gtk . gdk . CONTROL_MASK ) :
if self . _vte . get_has_selection ( ) :
getattr ( self , " key_ " + mapping ) ( )
return True
else :
getattr ( self , " key_ " + mapping ) ( )
return True
2008-08-11 18:02:14 +00:00
2009-01-10 16:13:49 +00:00
if self . terminator . groupsend != 0 and self . _vte . is_focus ( ) :
if self . _group and self . terminator . groupsend == 1 :
self . terminator . group_emit ( self , self . _group , ' key-press-event ' , event )
if self . terminator . groupsend == 2 :
self . terminator . all_emit ( self , ' 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 )
2009-05-23 16:05:50 +00:00
def key_group_all ( self ) :
self . group_all ( self )
def key_ungroup_all ( self ) :
self . ungroup_all ( self )
def key_group_tab ( self ) :
self . group_tab ( self )
def key_ungroup_tab ( self ) :
self . ungroup_tab ( self )
2009-05-28 08:29:56 +00:00
def key_new_window ( self ) :
cmd = sys . argv [ 0 ]
if not os . path . isabs ( cmd ) :
# Command is not an absolute path. Figure out where we are
cmd = os . path . join ( self . terminator . origcwd , sys . argv [ 0 ] )
if not os . path . isfile ( cmd ) :
# we weren't started as ./terminator in a path. Give up
err ( ' Unable to locate Terminator ' )
return False
dbg ( " Spawning: %s " % cmd )
subprocess . Popen ( [ cmd , ] )
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 ( )
2009-12-02 22:48:12 +00:00
if not self . _vte . window :
return reply
2008-12-19 23:17:43 +00:00
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 )
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 )
2009-08-04 11:58:05 +00:00
if hasattr ( item , " set_always_show_image " ) :
item . set_always_show_image ( True )
2008-06-26 23:24:52 +00:00
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 )
2009-08-04 11:58:05 +00:00
if hasattr ( item , " set_always_show_image " ) :
item . set_always_show_image ( True )
2008-06-26 23:24:52 +00:00
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 )
2009-05-11 20:36:40 +00:00
item = gtk . ImageMenuItem ( gtk . STOCK_CLOSE )
item . connect ( " activate " , lambda menu_item : self . terminator . closeterm ( self ) )
menu . append ( item )
item = gtk . MenuItem ( )
menu . append ( item )
2008-06-26 23:24:52 +00:00
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 )
2009-05-11 20:36:40 +00:00
item = gtk . CheckMenuItem ( _ ( " Show _scrollbar " ) )
item . set_active ( self . _scrollbar . get_property ( ' visible ' ) )
item . connect ( " toggled " , lambda menu_item : self . do_scrollbar_toggle ( ) )
menu . append ( item )
item = gtk . CheckMenuItem ( _ ( " Show _titlebar " ) )
item . set_active ( self . _titlebox . get_property ( ' visible ' ) )
item . connect ( " toggled " , lambda menu_item : self . do_title_toggle ( ) )
if self . _group :
item . set_sensitive ( False )
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 )
2009-05-11 20:36:40 +00:00
self . _do_encoding_items ( menu )
2008-06-26 23:24:52 +00:00
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
2009-01-12 11:13:22 +00:00
def create_popup_group_menu ( self , widget , event = None ) :
menu = gtk . Menu ( )
url = None
if event :
url = self . _vte . match_check ( int ( event . x / self . _vte . get_char_width ( ) ) , int ( event . y / self . _vte . get_char_height ( ) ) )
button = event . button
time = event . time
else :
button = 0
time = 0
self . populate_grouping_menu ( menu )
menu . show_all ( )
2009-10-02 08:43:33 +00:00
if gtk . gtk_version > ( 2 , 14 , 0 ) :
menu . popup ( None , None , self . position_popup_group_menu , button , time , widget )
else :
menu . popup ( None , None , None , button , time , widget )
2009-01-12 11:13:22 +00:00
return True
2008-12-10 18:16:55 +00:00
def populate_grouping_menu ( self , widget ) :
groupitem = None
2009-07-13 23:04:30 +00:00
item = gtk . MenuItem ( _ ( " Assign to group... " ) )
2009-01-10 16:13:49 +00:00
item . connect ( " activate " , self . create_group )
widget . append ( item )
2008-12-10 18:16:55 +00:00
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 :
2009-07-21 19:50:06 +00:00
item = gtk . RadioMenuItem ( groupitem , group , False )
2008-12-10 18:16:55 +00:00
item . set_active ( self . _group == group )
item . connect ( " toggled " , self . set_group , group )
widget . append ( item )
groupitem = item
2009-01-10 16:13:49 +00:00
if self . _group != None or len ( self . terminator . groupings ) > 0 :
2008-12-10 18:16:55 +00:00
item = gtk . MenuItem ( )
widget . append ( item )
2009-01-10 16:13:49 +00:00
if self . _group != None :
2009-07-13 23:14:21 +00:00
item = gtk . MenuItem ( _ ( " Remove group %s " ) % ( self . _group ) )
2009-01-10 16:13:49 +00:00
item . connect ( " activate " , self . ungroup , self . _group )
widget . append ( item )
2008-12-11 08:07:28 +00:00
2009-05-23 15:34:23 +00:00
if self . terminator . get_first_parent_widget ( self , gtk . Notebook ) is not None and \
not isinstance ( self . get_parent ( ) , gtk . Notebook ) :
item = gtk . MenuItem ( _ ( " G_roup all in tab " ) )
item . connect ( " activate " , self . group_tab )
widget . append ( item )
if self . terminator . get_first_parent_widget ( self , gtk . Notebook ) is not None and \
not isinstance ( self . get_parent ( ) , gtk . Notebook ) and \
len ( self . terminator . groupings ) > 0 :
item = gtk . MenuItem ( _ ( " Ungr_oup all in tab " ) )
item . connect ( " activate " , self . ungroup_tab )
widget . append ( item )
2009-01-06 09:44:38 +00:00
if len ( self . terminator . groupings ) > 0 :
2009-01-12 16:08:12 +00:00
item = gtk . MenuItem ( _ ( " Remove all groups " ) )
2009-01-06 09:44:38 +00:00
item . connect ( " activate " , self . ungroup_all )
widget . append ( item )
2009-01-10 16:13:49 +00:00
if self . _group != None :
item = gtk . MenuItem ( )
widget . append ( item )
2009-07-13 23:14:21 +00:00
item = gtk . ImageMenuItem ( _ ( " Close group %s " ) % ( self . _group ) )
2009-01-10 16:13:49 +00:00
grp_close_img = gtk . Image ( )
grp_close_img . set_from_stock ( gtk . STOCK_CLOSE , 1 )
item . set_image ( grp_close_img )
item . connect ( " activate " , lambda menu_item : self . terminator . closegroupedterms ( self ) )
widget . append ( item )
item = gtk . MenuItem ( )
widget . append ( item )
groupitem = None
groupitem = gtk . RadioMenuItem ( groupitem , _ ( " Broadcast off " ) )
groupitem . set_active ( self . terminator . groupsend == 0 )
groupitem . connect ( " activate " , self . set_groupsend , 0 )
widget . append ( groupitem )
groupitem = gtk . RadioMenuItem ( groupitem , _ ( " Broadcast to group " ) )
groupitem . set_active ( self . terminator . groupsend == 1 )
groupitem . connect ( " activate " , self . set_groupsend , 1 )
widget . append ( groupitem )
groupitem = gtk . RadioMenuItem ( groupitem , _ ( " Broadcast to all " ) )
groupitem . set_active ( self . terminator . groupsend == 2 )
groupitem . connect ( " activate " , self . set_groupsend , 2 )
widget . append ( groupitem )
item = gtk . MenuItem ( )
widget . append ( item )
item = gtk . CheckMenuItem ( _ ( " Split to this group " ) )
item . set_active ( self . terminator . splittogroup )
item . connect ( " toggled " , lambda menu_item : self . do_splittogroup_toggle ( ) )
2009-01-12 16:08:12 +00:00
if self . _group == None :
item . set_sensitive ( False )
2009-01-10 16:13:49 +00:00
widget . append ( item )
item = gtk . CheckMenuItem ( _ ( " Autoclean groups " ) )
item . set_active ( self . terminator . autocleangroups )
item . connect ( " toggled " , lambda menu_item : self . do_autocleangroups_toggle ( ) )
widget . append ( item )
2009-01-06 09:44:38 +00:00
2009-07-14 11:53:42 +00:00
item = gtk . MenuItem ( )
widget . append ( item )
item = gtk . MenuItem ( _ ( " Insert terminal number " ) )
item . connect ( " activate " , lambda menu_item : self . do_enumerate ( ) )
widget . append ( item )
item = gtk . MenuItem ( _ ( " Insert padded terminal number " ) )
item . connect ( " activate " , lambda menu_item : self . do_enumerate ( pad = True ) )
widget . append ( item )
2009-01-12 11:13:22 +00:00
def position_popup_group_menu ( self , menu , widget ) :
screen_w = gtk . gdk . screen_width ( )
screen_h = gtk . gdk . screen_height ( )
widget_win = widget . get_window ( )
widget_x , widget_y = widget_win . get_origin ( )
widget_w , widget_h = widget_win . get_size ( )
menu_w , menu_h = menu . size_request ( )
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 )
2009-07-13 22:36:45 +00:00
2008-12-10 18:16:55 +00:00
def create_group ( self , item ) :
2009-01-13 21:05:04 +00:00
self . groupingscope = 0
grplist = self . terminator . groupings [ : ]
grplist . sort ( )
2008-12-11 07:08:28 +00:00
win = gtk . Window ( )
2009-01-13 21:05:04 +00:00
vbox = gtk . VBox ( False , 6 )
vbox . set_border_width ( 5 )
2008-12-11 07:08:28 +00:00
win . add ( vbox )
2009-01-13 21:05:04 +00:00
# Populate the "Assign..." Section
contentvbox = gtk . VBox ( False , 6 )
selframe = gtk . Frame ( )
selframe_label = gtk . Label ( )
selframe_label . set_markup ( _ ( " <b>Assign...</b> " ) )
selframe . set_shadow_type ( gtk . SHADOW_NONE )
selframe . set_label_widget ( selframe_label )
selframe_align = gtk . Alignment ( 0 , 0 , 1 , 1 )
selframe_align . set_padding ( 0 , 0 , 12 , 0 )
selframevbox = gtk . VBox ( )
selframehbox = gtk . HBox ( )
# Populate the Combo with existing group names (None at the top)
sel_combo = gtk . combo_box_new_text ( )
2009-07-13 22:54:18 +00:00
sel_combo . append_text ( _ ( " Terminals with no group " ) )
2009-01-13 21:05:04 +00:00
for grp in grplist :
sel_combo . append_text ( grp )
sel_combo . set_sensitive ( False )
# Here are the radio buttons
groupitem = None
groupitem = gtk . RadioButton ( groupitem , _ ( " Terminal " ) )
groupitem . set_active ( True )
groupitem . connect ( " toggled " , self . set_groupingscope , 0 , sel_combo )
2009-01-14 00:59:09 +00:00
selframehbox . pack_start ( groupitem , False )
2009-01-13 21:05:04 +00:00
groupitem = gtk . RadioButton ( groupitem , _ ( " Group " ) )
groupitem . connect ( " toggled " , self . set_groupingscope , 1 , sel_combo )
2009-01-14 00:59:09 +00:00
selframehbox . pack_start ( groupitem , False )
2009-01-13 21:05:04 +00:00
groupitem = gtk . RadioButton ( groupitem , _ ( " All " ) )
groupitem . connect ( " toggled " , self . set_groupingscope , 2 , sel_combo )
2009-01-14 00:59:09 +00:00
selframehbox . pack_start ( groupitem , False )
2009-01-13 21:05:04 +00:00
selframevbox . pack_start ( selframehbox , True , True )
selframevbox . pack_start ( sel_combo , True , True )
selframe_align . add ( selframevbox )
selframe . add ( selframe_align )
contentvbox . pack_start ( selframe )
# Populate the "To..." Section
tgtframe = gtk . Frame ( )
tgtframe_label = gtk . Label ( )
tgtframe_label . set_markup ( _ ( " <b>To...</b> " ) )
tgtframe . set_shadow_type ( gtk . SHADOW_NONE )
tgtframe . set_label_widget ( tgtframe_label )
tgtframe_align = gtk . Alignment ( 0 , 0 , 1 , 1 )
tgtframe_align . set_padding ( 0 , 0 , 12 , 0 )
tgtframevbox = gtk . VBox ( )
# Populate the Combo with existing group names (None not needed)
tgt_comboentry = gtk . combo_box_entry_new_text ( )
for grp in grplist :
tgt_comboentry . append_text ( grp )
tgtframevbox . pack_start ( tgt_comboentry , True , True )
tgtframe_align . add ( tgtframevbox )
tgtframe . add ( tgtframe_align )
contentvbox . pack_start ( tgtframe )
2008-12-11 07:08:28 +00:00
okbut = gtk . Button ( stock = gtk . STOCK_OK )
canbut = gtk . Button ( stock = gtk . STOCK_CANCEL )
2009-01-13 21:05:04 +00:00
hbuttonbox = gtk . HButtonBox ( )
hbuttonbox . set_layout ( gtk . BUTTONBOX_END )
hbuttonbox . pack_start ( canbut , True , True )
hbuttonbox . pack_start ( okbut , True , True )
vbox . pack_start ( contentvbox , False , True )
vbox . pack_end ( hbuttonbox , False , True )
2008-12-11 07:08:28 +00:00
canbut . connect ( " clicked " , lambda kill : win . destroy ( ) )
2009-01-13 21:05:04 +00:00
okbut . connect ( " clicked " , self . do_create_group , win , sel_combo , tgt_comboentry )
tgt_comboentry . child . connect ( " activate " , self . do_create_group , win , sel_combo , tgt_comboentry )
tgt_comboentry . grab_focus ( )
2009-01-14 00:55:46 +00:00
# Center it over the current terminal (not perfect?!?)
# This could be replaced by a less bothersome dialog, but then that would
# center over the window, not the terminal
screen_w = gtk . gdk . screen_width ( )
screen_h = gtk . gdk . screen_height ( )
local_x , local_y = self . allocation . x , self . allocation . y
local_w , local_h = self . allocation . width , self . allocation . height
window_x , window_y = self . get_window ( ) . get_origin ( )
x = window_x + local_x
y = window_y + local_y
win . realize ( )
new_x = min ( max ( 0 , x + ( local_w / 2 ) - ( win . allocation . width / 2 ) ) , screen_w - win . allocation . width )
new_y = min ( max ( 0 , y + ( local_h / 2 ) - ( win . allocation . height / 2 ) ) , screen_h - win . allocation . height )
win . move ( new_x , new_y )
2008-12-11 07:08:28 +00:00
win . show_all ( )
2009-01-13 21:05:04 +00:00
def set_groupingscope ( self , widget , scope = None , sel_combo = None ) :
if widget . get_active ( ) :
self . groupingscope = scope
if self . groupingscope == 1 :
sel_combo . set_sensitive ( True )
else :
sel_combo . set_sensitive ( False )
2008-12-11 07:08:28 +00:00
2009-01-13 21:05:04 +00:00
def do_create_group ( self , widget , window , src , tgt ) :
tgt_name = tgt . child . get_text ( )
try :
src_name = src . get_active_text ( )
2009-07-13 23:04:30 +00:00
src_id = src . get_active ( )
2009-01-13 21:05:04 +00:00
except :
src_name = None
if tgt_name == " " or ( self . groupingscope == 1 and src_name == None ) :
return False
if tgt_name not in self . terminator . groupings :
self . terminator . groupings . append ( tgt_name )
if self . groupingscope == 2 :
for term in self . terminator . term_list :
term . set_group ( None , tgt_name )
elif self . groupingscope == 1 :
for term in self . terminator . term_list :
2009-07-13 23:04:30 +00:00
if term . _group == src_name or ( src_id == 0 and term . _group == None ) :
2009-01-13 21:05:04 +00:00
term . set_group ( None , tgt_name )
else :
self . set_group ( None , tgt_name )
2008-12-11 07:08:28 +00:00
window . destroy ( )
2008-12-10 18:16:55 +00:00
2009-05-23 15:34:23 +00:00
def add_group ( self , groupname ) :
if not groupname in self . terminator . groupings :
self . terminator . groupings . append ( groupname )
2008-12-10 18:16:55 +00:00
def set_group ( self , item , data ) :
if self . _group == data :
# No action needed
return
else :
2009-01-30 12:04:59 +00:00
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
if not self . _group :
# We were not previously in a group
self . _titlebox . show ( )
2008-12-11 07:08:28 +00:00
self . _group = data
2008-12-10 18:16:55 +00:00
else :
# We were previously in a group
2008-12-11 08:07:28 +00:00
self . _group = data
2009-07-13 23:14:21 +00:00
if data is None :
2008-12-10 18:16:55 +00:00
# We have been removed from a group
if not self . conf . titlebars and not self . _want_titlebar :
self . _titlebox . hide ( )
2009-01-10 16:00:05 +00:00
self . terminator . group_hoover ( )
2008-12-10 18:16:55 +00:00
2009-01-10 16:13:49 +00:00
def set_groupsend ( self , item , data ) :
self . terminator . groupsend = data
def ungroup ( self , widget , data ) :
2009-07-13 23:14:21 +00:00
for term in self . terminator . term_list :
if term . _group == data :
term . set_group ( None , None )
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 " )
2009-05-23 15:34:23 +00:00
self . add_group ( allname )
2008-12-11 08:07:28 +00:00
for term in self . terminator . term_list :
2009-07-13 23:15:34 +00:00
term . set_group ( None , allname )
2009-07-29 23:44:36 +00:00
self . on_vte_focus_in ( self . _vte , None )
2008-12-11 08:07:28 +00:00
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 )
2009-07-29 23:44:36 +00:00
self . on_vte_focus_in ( self . _vte , None )
2009-01-06 09:44:38 +00:00
self . terminator . group_hoover ( )
2009-05-23 15:34:23 +00:00
def find_all_terms_in_tab ( self , notebook , pagenum = - 1 ) :
if pagenum == - 1 :
pagenum = notebook . get_current_page ( )
notebookchild = notebook . get_nth_page ( pagenum )
terms = [ ]
for term in self . terminator . term_list :
termparent = term . get_parent ( )
while not isinstance ( termparent , gtk . Window ) :
if termparent == notebookchild :
terms . append ( term )
termparent = termparent . get_parent ( )
return terms
def group_tab ( self , widget ) :
groupname = " "
notebook = self . terminator . get_first_parent_widget ( self , gtk . Notebook )
pagenum = notebook . get_current_page ( )
notebookchild = notebook . get_nth_page ( pagenum )
terms = self . find_all_terms_in_tab ( notebook )
notebooktablabel = notebook . get_tab_label ( notebookchild )
2009-12-01 23:07:10 +00:00
if notebooktablabel . _label . _custom is True :
2009-05-23 15:34:23 +00:00
groupname = notebooktablabel . get_title ( )
if groupname == " " :
2009-12-01 23:14:42 +00:00
tmppagenum = pagenum
while True :
groupname = " Tab %d " % ( tmppagenum + 1 )
if groupname not in self . terminator . groupings :
break
tmppagenum + = 1
2009-05-23 15:34:23 +00:00
self . add_group ( groupname )
for term in terms :
term . set_group ( None , groupname )
2009-07-29 23:44:36 +00:00
self . on_vte_focus_in ( self . _vte , None )
2009-05-23 15:34:23 +00:00
self . terminator . group_hoover ( )
def ungroup_tab ( self , widget ) :
notebook = self . terminator . get_first_parent_widget ( self , gtk . Notebook )
terms = self . find_all_terms_in_tab ( notebook )
for term in terms :
term . set_group ( None , None )
2009-07-29 23:44:36 +00:00
self . on_vte_focus_in ( self . _vte , None )
2009-05-23 15:34:23 +00:00
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 :
2009-08-04 01:56:02 +00:00
dbg ( ' Setting Encoding to: %s ' % encoding )
if encoding == self . conf . encoding :
self . _custom_encoding = False
else :
self . _custom_encoding = True
2008-06-26 23:24:52 +00:00
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 )
2009-08-04 01:56:02 +00:00
encodings = TerminatorEncoding ( ) . get_list ( )
encodings . sort ( lambda x , y : cmp ( x [ 2 ] . lower ( ) , y [ 2 ] . lower ( ) ) )
2008-06-26 23:24:52 +00:00
current_encoding = self . _vte . get_encoding ( )
group = None
2009-08-04 01:56:02 +00:00
if current_encoding not in active_encodings :
active_encodings . insert ( 0 , _ ( current_encoding ) )
2008-06-26 23:24:52 +00:00
for encoding in active_encodings :
2009-08-04 01:56:02 +00:00
if encoding == self . _default_encoding :
extratext = " ( %s ) " % _ ( " Default " )
elif encoding == current_encoding and self . _custom_encoding == True :
extratext = " ( %s ) " % _ ( " User defined " )
else :
extratext = " "
radioitem = gtk . RadioMenuItem ( group , _ ( encoding ) + extratext )
2008-06-26 23:24:52 +00:00
if encoding == current_encoding :
radioitem . set_active ( True )
2009-08-04 01:56:02 +00:00
if group is None :
group = radioitem
2008-06-26 23:24:52 +00:00
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 )
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 )
2009-05-04 00:51:01 +00:00
self . terminator . set_window_title ( title )
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 )
2009-05-11 20:54:23 +00:00
# FIXME: Is this necessary? The above line should update the label. LP #369370 might be related
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-07 18:37:59 +00:00
for term in self . terminator . term_list :
2009-08-02 22:44:51 +00:00
term . _titlebox . update_colors ( self )
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 ) :
return
def on_vte_focus ( self , vte ) :
2008-08-07 22:07:21 +00:00
title = self . get_window_title ( vte )
2009-05-04 00:51:01 +00:00
self . terminator . set_window_title ( title )
2008-08-07 20:34:47 +00:00
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 ) :
2009-07-13 22:36:45 +00:00
return self . _scrollbar . get_property ( ' visible ' )
2008-06-26 23:24:52 +00:00
2009-01-12 11:13:22 +00:00
def on_group_button_press ( self , term , event ) :
if event . button == 1 :
self . create_popup_group_menu ( term , event )
return False