diff --git a/ChangeLog b/ChangeLog index 7e180444..6ae60bf5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/terminator b/terminator index eab7487b..fec4324e 100755 --- a/terminator +++ b/terminator @@ -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,11 +99,11 @@ 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() - + self._scrollbar = gtk.VScrollbar (self._vte.get_adjustment ()) if self.scrollbar_position != "hidden" and self.scrollbar_position != "disabled": self._scrollbar.show () @@ -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()) @@ -874,9 +755,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 @@ -893,23 +771,21 @@ class Terminator: #We have a corresponding parent pane # #allocation = parent.get_allocation() - + if keyname in ('Up', 'Down'): maxi = parent.get_child1().get_allocation().height + parent.get_child2().get_allocation().height - 1 - + else: maxi = parent.get_child1().get_allocation().width + parent.get_child2().get_allocation().width - 1 move = 10 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 @@ -925,14 +801,12 @@ class Terminator: elif isinstance (parent, gtk.HPaned) and not vertical: 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) diff --git a/terminatorconfig.py b/terminatorconfig.py index 0b880fb0..80c863bb 100755 --- a/terminatorconfig.py +++ b/terminatorconfig.py @@ -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