merge in configclass branch

This commit is contained in:
Chris Jones 2008-04-07 23:01:00 +01:00
commit 65e9fe41fa
3 changed files with 102 additions and 210 deletions

View File

@ -2,7 +2,9 @@ terminator 0.9:
* Added support for ~/.terminatorrc
* Added kwybindings for terms size and scrollbar manipulation. Thanks
Emmanuel Bretelle.
* Completely revamped config system which now transparently makes use
of gconf settings if they are available, falls back to sensible
defaults if not, and can be overridden entirely by ~/.terminatorrc
terminator 0.8.1:
* Fixed ChangeLog

View File

@ -31,34 +31,8 @@ gettext.install (APP_NAME)
# import unix-lib
import pwd
# import gconf if possible, if not construct a fake replacement
class fakegconfclient:
def get_string (self, key):
return ("")
def get_list (self, key, type):
return ([])
def add_dir (self, profile, path):
return (True)
def notify_add (self, profile, callback):
return (True)
def get_bool (self, key):
return (False)
def get (self, key):
return (0)
class fakegconf:
CLIENT_PRELOAD_RECURSIVE = False
VALUE_STRING = ""
VALUE_INT = 0
VALUE_FLOAT = 0.0
VALUE_BOOL = False
def client_get_default (self):
foo = fakegconfclient ()
return (foo)
try:
import gconf
except:
pass
# import our configuration loader
import terminatorconfig
# import gtk libs
# check just in case anyone runs it on a non-gnome system.
@ -96,92 +70,19 @@ def openurl (url):
class TerminatorTerm:
# Our settings
defaults = {
'gt_dir' : '/apps/gnome-terminal',
'_profile_dir' : '%s/profiles',
'titlebars' : True,
'titletips' : False,
'allow_bold' : True,
'silent_bell' : True,
'background_color' : '#000000',
'background_darkness' : 0.5,
'background_type' : 'solid',
'backspace_binding' : 'ascii-del',
'delete_binding' : 'delete-sequence',
'cursor_blink' : False,
'emulation' : 'xterm',
'font' : 'Serif 10',
'foreground_color' : '#AAAAAA',
'scrollbar_position' : "right",
'scroll_background' : True,
'scroll_on_keystroke' : False,
'scroll_on_output' : False,
'scrollback_lines' : 100,
'focus' : 'sloppy',
'exit_action' : 'close',
'palette' : '#000000000000:#CDCD00000000:#0000CDCD0000:#CDCDCDCD0000:#30BF30BFA38E:#A53C212FA53C:#0000CDCDCDCD:#FAFAEBEBD7D7:#404040404040:#FFFF00000000:#0000FFFF0000:#FFFFFFFF0000:#00000000FFFF:#FFFF0000FFFF:#0000FFFFFFFF:#FFFFFFFFFFFF',
'word_chars' : '-A-Za-z0-9,./?%&#:_',
'mouse_autohide' : True,
}
matches = {}
def __init__ (self, terminator, profile = None, command = None, cwd = None):
self.defaults['profile_dir'] = self.defaults['_profile_dir']%(self.defaults['gt_dir'])
self.terminator = terminator
self.gconf_client = gconf.client_get_default ()
self.conf = terminator.conf
self.command = command
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]
if profile == None:
profile = self.gconf_client.get_string (self.defaults['gt_dir'] + '/global/default_profile')
self.profile = ""
profiles = self.gconf_client.get_list (self.defaults['gt_dir'] + '/global/profile_list', 'string')
if profile in profiles:
self.profile = '%s/%s'%(self.defaults['profile_dir'], profile)
else:
if profile != "Default" and "Default" in profiles:
self.profile = '%s/Default'%(self.defaults['profile_dir'])
if self.profile:
self.gconf_client.add_dir (self.profile, gconf.CLIENT_PRELOAD_RECURSIVE)
self.gconf_client.notify_add (self.profile, self.on_gconf_notification)
if os.path.exists (pwd.getpwuid(os.getuid ())[5] + "/." + APP_NAME + "rc"):
f = open (pwd.getpwuid (os.getuid ())[5] + "/." + APP_NAME + "rc")
config = f.readlines ()
f.close ()
for line in config:
try:
line = line.strip ()
if line[0] == '#':
pass
elif line:
(key,value) = line.split ("=")
print >> sys.stderr, _('''Overriding setting '%s' from value '%s' to: '%s' ''')%(key.strip (), self.defaults[key.strip ()], value.strip ())
if value.strip() == "True":
self.defaults[key.strip ()] = True
elif value.strip() == "False":
self.defaults[key.strip ()] = False
else:
self.defaults[key.strip ()] = value.strip ()
except:
pass
self.gconf_client.add_dir ('/apps/metacity/general', gconf.CLIENT_PRELOAD_RECURSIVE)
self.gconf_client.notify_add ('/apps/metacity/general/focus_mode', self.on_gconf_notification)
self.clipboard = gtk.clipboard_get (gtk.gdk.SELECTION_CLIPBOARD)
self.scrollbar_position = self.reconf ('scrollbar_position')
self.scrollbar_position = self.conf.scrollbar_position
self._vte = vte.Terminal ()
self._vte.set_size (80, 24)
@ -198,7 +99,7 @@ class TerminatorTerm:
self._box.show()
self._box.pack_start(self._titlebox, False)
self._box.pack_start(self._termbox)
if self.reconf('titlebars'):
if self.conf.titlebars:
self._titlebox.show()
else:
self._titlebox.hide()
@ -224,8 +125,7 @@ class TerminatorTerm:
self._vte.connect ("focus-out-event", self.on_vte_focus_out)
self._vte.connect ("focus-in-event", self.on_vte_focus_in)
exit_action = self.gconf_client.get_string (self.profile + "/exit_action")
exit_action = self.reconf ("exit_action")
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
@ -246,14 +146,14 @@ class TerminatorTerm:
self.spawn_child ()
def spawn_child (self, event=None):
update_records = self.gconf_client.get_bool (self.profile + "/update_records") or True
login = self.gconf_client.get_bool (self.profile + "/login_shell") or False
update_records = self.conf.update_records
login = self.conf.login_shell
if self.command:
args = self.command
shell = self.command[0]
elif self.gconf_client.get_bool (self.profile + "/use_custom_command") == True:
args = self.gconf_client.get_string (self.profile + "/custom_command").split ()
elif self.conf.use_custom_command:
args = self.conf.custom_command.split ()
shell = args[0]
else:
shell = pwd.getpwuid (os.getuid ())[6]
@ -275,42 +175,19 @@ class TerminatorTerm:
cwd = None
return (cwd)
def reconf (self, property):
value = self.gconf_client.get ('%s/%s'%(self.profile, property))
ret = None
if not value:
try:
ret = self.defaults[property]
except:
pass
else:
if value.type == gconf.VALUE_STRING:
ret = value.get_string ()
elif value.type == gconf.VALUE_INT:
ret = value.get_int ()
elif value.type == gconf.VALUE_FLOAT:
ret = value.get_float ()
elif value.type == gconf.VALUE_BOOL:
ret = value.get_bool ()
if ret == None:
print >> sys.stderr, _('Unknown value requested. Unable to find in gconf profile or default settings: ') + property
return (ret)
def reconfigure_vte (self):
# Set our emulation
self._vte.set_emulation (self.defaults['emulation'])
self._vte.set_emulation (self.conf.emulation)
# Set our wordchars
self._vte.set_word_chars (self.reconf ('word_chars'))
self._vte.set_word_chars (self.conf.word_chars)
# Set our mouselation
self._vte.set_mouse_autohide (self.defaults['mouse_autohide'])
self._vte.set_mouse_autohide (self.conf.mouse_autohide)
# Set our compatibility
backspace = self.reconf ('backspace_binding')
delete = self.reconf ('delete_binding')
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":
@ -330,28 +207,23 @@ class TerminatorTerm:
self._vte.set_backspace_binding (backbind)
self._vte.set_delete_binding (delbind)
# Set our font, preferably from gconf settings
if self.gconf_client.get_bool (self.profile + "/use_system_font"):
font_name = (self.gconf_client.get_string ("/desktop/gnome/interface/monospace_font_name") or self.defaults['font'])
else:
font_name = self.reconf ('font')
# Set our font
try:
self._vte.set_font (pango.FontDescription (font_name))
self._vte.set_font (pango.FontDescription (self.conf.font))
except:
pass
# Set our boldness
self._vte.set_allow_bold (self.reconf ('allow_bold'))
self._vte.set_allow_bold (self.conf.allow_bold)
# Set our color scheme, preferably from gconf settings
palette = self.reconf ('palette')
if self.gconf_client.get_bool (self.profile + "/use_theme_colors"):
# 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.reconf ('foreground_color'))
bg_color = gtk.gdk.color_parse (self.reconf ('background_color'))
fg_color = gtk.gdk.color_parse (self.conf.foreground_color)
bg_color = gtk.gdk.color_parse (self.conf.background_color)
colors = palette.split (':')
palette = []
@ -362,12 +234,12 @@ class TerminatorTerm:
# Set our background image, transparency and type
# Many thanks to the authors of gnome-terminal, on which this code is based.
background_type = self.reconf ('background_type')
background_type = self.conf.background_type
# set background image settings
if background_type == "image":
self._vte.set_background_image_file (self.reconf ('background_image'))
self._vte.set_scroll_background (self.reconf('scroll_background'))
self._vte.set_background_image_file (self.conf.background_image)
self._vte.set_scroll_background (self.conf.scroll_background)
else:
self._vte.set_background_image_file('')
self._vte.set_scroll_background(False)
@ -375,8 +247,8 @@ class TerminatorTerm:
# set transparency for the background (image)
if background_type in ("image", "transparent"):
self._vte.set_background_tint_color (bg_color)
self._vte.set_background_saturation(1 - (self.reconf ('background_darkness')))
self._vte.set_opacity(int(self.reconf('background_darkness') * 65535))
self._vte.set_background_saturation(1 - (self.conf.background_darkness))
self._vte.set_opacity(int(self.conf.background_darkness * 65535))
else:
self._vte.set_background_saturation(1)
self._vte.set_opacity(65535)
@ -387,43 +259,39 @@ class TerminatorTerm:
self._vte.set_background_transparent (False)
# Set our cursor blinkiness
self._vte.set_cursor_blinks = (self.reconf ('cursor_blink'))
self._vte.set_cursor_blinks = (self.conf.cursor_blink)
# Set our audible belliness
silent_bell = self.reconf ('silent_bell')
silent_bell = self.conf.silent_bell
self._vte.set_audible_bell = not silent_bell
self._vte.set_visible_bell = silent_bell
# Set our scrolliness
self._vte.set_scrollback_lines (self.reconf ('scrollback_lines'))
self._vte.set_scroll_on_keystroke (self.reconf ('scroll_on_keystroke'))
self._vte.set_scroll_on_output (self.reconf ('scroll_on_output'))
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)
scrollbar_position = self.reconf ('scrollbar_position')
if self.scrollbar_position != self.conf.scrollbar_position:
self.scrollbar_position = self.conf.scrollbar_position
if scrollbar_position != self.scrollbar_position:
if scrollbar_position == 'hidden' or scrollbar_position == 'disabled':
if self.scrollbar_position == 'hidden' or self.scrollbar_position == 'disabled':
self._scrollbar.hide ()
else:
self._scrollbar.show ()
if scrollbar_position == 'right':
if self.scrollbar_position == 'right':
self._box.remove (self._scrollbar)
self._box.remove (self._vte)
self._box.pack_start (self._vte)
self._box.pack_start (self._scrollbar)
elif scrollbar_position == 'left':
elif self.scrollbar_position == 'left':
self._box.remove (self._vte)
self._box.remove (self._scrollbar)
self._box.pack_start(self._scrollbar)
self._box.pack_start(self._vte)
self.scrollbar_position = scrollbar_position
# Set our sloppiness
self.focus = self.gconf_client.get_string ("/apps/metacity/general/focus_mode") or self.defaults['focus']
def on_gconf_notification (self, client, cnxn_id, entry, what):
self.reconfigure_vte ()
self.focus = self.conf.focus
def on_composited_changed (self, widget):
self.reconfigure_vte ()
@ -612,7 +480,7 @@ class TerminatorTerm:
return menu
def on_vte_title_change(self, vte):
if self.reconf ('titletips'):
if self.conf.titletips:
vte.set_property ("has-tooltip", True)
vte.set_property ("tooltip-text", vte.get_window_title ())
#set the title anyhow, titlebars setting only show/hide the label
@ -639,11 +507,24 @@ class TerminatorTerm:
class Terminator:
def __init__ (self, profile, command = None, fullscreen = False, maximise = False, borderless = False):
self.profile = profile
self.gconf_client = gconf.client_get_default ()
self.command = command
self._fullscreen = False
stores = []
stores.append (terminatorconfig.TerminatorConfValuestoreRC ())
# FIXME: enable this again, we should trap and discard broken gconf stuff
# try:
import gconf
store = terminatorconfig.TerminatorConfValuestoreGConf ()
store.set_reconfigure_callback (self.reconfigure_vtes)
stores.append (store)
# except:
# pass
self.conf = terminatorconfig.TerminatorConfig (stores)
self.window = gtk.Window ()
self.window.set_title (APP_NAME.capitalize())
@ -875,9 +756,6 @@ class Terminator:
#self.window.set_title(self.term_list[previous]._vte.get_window_title())
self.term_list[previous]._vte.grab_focus ()
def resizeterm (self, widget, keyname):
vertical = False
if keyname in ('Up', 'Down'):
@ -903,13 +781,11 @@ class Terminator:
if keyname in ('Up', 'Left'):
move = -10
move = max(2, parent.get_position() + move)
move = min(maxi, move)
parent.set_position(move)
def get_first_parent_paned (self, widget, vertical = None):
"""This method returns the first parent pane of a widget.
if vertical is True returns the first VPaned
@ -926,13 +802,11 @@ class Terminator:
return parent
return self.get_first_parent_paned(parent, vertical)
def reconfigure_vtes (self):
for term in self.term_list:
term.reconfigure_vte ()
if __name__ == '__main__':
try:
if (gconf):
pass
except:
# Install a fake gconf setup
gconf = fakegconf ()
def execute_cb (option, opt, value, parser):
assert value is None
@ -953,7 +827,6 @@ if __name__ == '__main__':
parser.add_option ("-p", "--profile", dest="profile", help="Specify a GNOME Terminal profile to emulate")
parser.add_option ("-e", "--command", dest="command", help="Execute the argument to this option inside the terminal")
parser.add_option ("-x", "--execute", dest="execute", action="callback", callback=execute_cb, help="Execute the remainder of the command line inside the terminal")
parser.add_option ("-g", "--no-gconf", dest="nogconf", action="store_true", help="Disable gconf usage, falling back on ~/." + APP_NAME.capitalize() + "rc and defaults")
(options, args) = parser.parse_args ()
if len (args) != 0:
@ -968,9 +841,6 @@ if __name__ == '__main__':
command.append (options.command)
if (options.execute):
command = options.execute
if (options.nogconf):
del (gconf)
gconf = fakegconf ()
term = Terminator (options.profile, command, options.fullscreen, options.maximise, options.borderless)

View File

@ -58,21 +58,17 @@ class TerminatorConfig:
self.sources.append (source)
def __getattr__ (self, keyname):
dbg ("Config: Looking for: %s"%keyname)
dbg ("TConfig: Looking for: '%s'"%keyname)
for source in self.sources:
try:
val = getattr (source, keyname)
dbg ("Config: got: %s from a %s"%(val, source.type))
dbg (" TConfig: got: '%s' from a '%s'"%(val, source.type))
return (val)
except:
dbg ("Config: no value found in %s."%source.type)
pass
dbg ("Config: Out of sources")
raise (AttributeError)
def set_reconfigure_callback (self, function):
self.reconfigure_callback = function
return (True)
dbg (" TConfig: Out of sources")
raise (AttributeError)
class TerminatorConfValuestore:
type = "Base"
@ -108,6 +104,12 @@ class TerminatorConfValuestore:
'palette' : [str, '#000000000000:#CDCD00000000:#0000CDCD0000:#CDCDCDCD0000:#30BF30BFA38E:#A53C212FA53C:#0000CDCDCDCD:#FAFAEBEBD7D7:#404040404040:#FFFF00000000:#0000FFFF0000:#FFFFFFFF0000:#00000000FFFF:#FFFF0000FFFF:#0000FFFFFFFF:#FFFFFFFFFFFF'],
'word_chars' : [str, '-A-Za-z0-9,./?%&#:_'],
'mouse_autohide' : [bool, True],
'update_records' : [bool, True],
'login_shell' : [bool, False],
'use_custom_command' : [bool, False],
'custom_command' : [str, ''],
'use_system_font' : [bool, True],
'use_theme_colors' : [bool, True],
}
def __getattr__ (self, keyname):
@ -138,7 +140,7 @@ class TerminatorConfValuestoreRC (TerminatorConfValuestore):
item = item.strip ()
if item and item[0] != '#':
(key, value) = item.split ("=")
dbg ("VS_RCFile: Setting value %s to %s"%(key, value))
dbg (" VS_RCFile: Setting value %s to %s"%(key, value))
self.values[key] = [self.defaults[key][0], self.defaults[key][0](value)]
except:
pass
@ -150,6 +152,8 @@ class TerminatorConfValuestoreGConf (TerminatorConfValuestore):
def __init__ (self, profile = None):
self.type = "GConf"
import gconf
self.client = gconf.client_get_default ()
# Grab a couple of values from base class to avoid recursing with our __getattr__
@ -161,10 +165,10 @@ class TerminatorConfValuestoreGConf (TerminatorConfValuestore):
profiles = self.client.get_list (self._gt_dir + '/global/profile_list','string')
if profile in profiles:
dbg ("VSGConf: Found profile '%s' in profile_list"%profile)
dbg (" VSGConf: Found profile '%s' in profile_list"%profile)
self.profile = '%s/%s'%(self._profile_dir, profile)
elif "Default" in profiles:
dbg ("VSGConf: profile '%s' not found, but 'Default' exists"%profile)
dbg (" VSGConf: profile '%s' not found, but 'Default' exists"%profile)
self.profile = '%s/%s'%(self._profile_dir, "Default")
else:
# We're a bit stuck, there is no profile in the list
@ -178,17 +182,33 @@ class TerminatorConfValuestoreGConf (TerminatorConfValuestore):
self.client.add_dir ('/apps/metacity/general', gconf.CLIENT_PRELOAD_RECURSIVE)
self.client.notify_add ('/apps/metacity/general/focus_mode', self.on_gconf_notify)
# FIXME: Do we need to watch more non-profile stuff here?
def set_reconfigure_callback (self, function):
dbg (" VSConf: setting callback to: %s"%function)
self.reconfigure_callback = function
return (True)
def on_gconf_notify (self, client, cnxn_id, entry, what):
dbg (" VSGConf: gconf changed, callback is: %s"%self.reconfigure_callback)
if self.reconfigure_callback:
self.reconfigure_callback ()
def __getattr__ (self, key = ""):
ret = None
value = None
dbg (' VSGConf: preparing: %s/%s'%(self.profile, key))
if key == 'font':
if self.use_system_font:
value = self.client.get ('/desktop/gnome/interface/monospace_font_name')
else:
value = self.client.get ('%s/%s'%(self.profile, key))
if key == 'focus':
value = self.client.get ('/apps/metacity/general/focus_mode')
dbg ('VSGConf: preparing: %s/%s'%(self.profile, key))
value = self.client.get ('%s/%s'%(self.profile, key))
dbg ('VSGConf: getting: %s'%value)
if value:
funcname = "get_" + self.defaults[key][0].__name__
# Special case for str