merging terminatorconfig.py
This commit is contained in:
commit
2e0440ea60
|
@ -0,0 +1,233 @@
|
|||
#!/usr/bin/python
|
||||
# TerminatorConfig - layered config classes
|
||||
# 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
|
||||
|
||||
"""TerminatorConfig by Chris Jones <cmsj@tenshu.net>
|
||||
|
||||
The config scheme works in layers, with defaults at the base,
|
||||
and a simple/flexible class which can be placed over the top
|
||||
in multiple layers. This was written for Terminator, but
|
||||
could be used generically. Its original use is to guarantee
|
||||
default values for any config item, while allowing them to be
|
||||
overridden by at least two other stores of configuration values.
|
||||
Those being gconf and a plain config file.
|
||||
In addition to the value, the default layer must also provide
|
||||
the datatype (str, int, float and bool are currently supported).
|
||||
values are found as attributes of the TerminatorConfig object.
|
||||
Trying to read a value that doesn't exist will raise an
|
||||
AttributeError. This is by design. If you want to look something
|
||||
up, set a default for it first."""
|
||||
|
||||
# import standard python libs
|
||||
import os, sys
|
||||
|
||||
# import unix-lib
|
||||
import pwd
|
||||
|
||||
# set this to true to enable debugging output
|
||||
debug = True
|
||||
|
||||
def dbg (log = ""):
|
||||
if debug:
|
||||
print >> sys.stderr, log
|
||||
|
||||
class TerminatorConfig:
|
||||
callback = None
|
||||
sources = []
|
||||
|
||||
def __init__ (self, sources = []):
|
||||
for source in sources:
|
||||
if isinstance(source, TerminatorConfValuestore):
|
||||
self.sources.append (source)
|
||||
|
||||
# We always add a default valuestore last so no valid config item ever goes unset
|
||||
source = TerminatorConfValuestoreDefault ()
|
||||
self.sources.append (source)
|
||||
|
||||
def __getattr__ (self, keyname):
|
||||
dbg ("Config: Looking for: %s"%keyname)
|
||||
for source in self.sources:
|
||||
try:
|
||||
val = getattr (source, keyname)
|
||||
dbg ("Config: 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)
|
||||
|
||||
class TerminatorConfValuestore:
|
||||
type = "Base"
|
||||
values = {}
|
||||
reconfigure_callback = None
|
||||
|
||||
# Our settings
|
||||
# FIXME: Is it acceptable to not explicitly store the type, but
|
||||
# instead infer it from defaults[key].__class__.__name__
|
||||
defaults = {
|
||||
'gt_dir' : [str, '/apps/gnome-terminal'],
|
||||
'profile_dir' : [str, '/apps/gnome-terminal/profiles'],
|
||||
'titlebars' : [bool, True],
|
||||
'titletips' : [bool, False],
|
||||
'allow_bold' : [bool, False],
|
||||
'silent_bell' : [bool, True],
|
||||
'background_color' : [str, '#000000'],
|
||||
'background_darkness' : [float, 0.5],
|
||||
'background_type' : [str, 'solid'],
|
||||
'backspace_binding' : [str, 'ascii-del'],
|
||||
'delete_binding' : [str, 'delete-sequence'],
|
||||
'cursor_blink' : [bool, False],
|
||||
'emulation' : [str, 'xterm'],
|
||||
'font' : [str, 'Serif 10'],
|
||||
'foreground_color' : [str, '#AAAAAA'],
|
||||
'scrollbar_position' : [str, "right"],
|
||||
'scroll_background' : [bool, True],
|
||||
'scroll_on_keystroke' : [bool, False],
|
||||
'scroll_on_output' : [bool, False],
|
||||
'scrollback_lines' : [int, 100],
|
||||
'focus' : [str, 'sloppy'],
|
||||
'exit_action' : [str, 'close'],
|
||||
'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],
|
||||
}
|
||||
|
||||
def __getattr__ (self, keyname):
|
||||
if self.values.has_key (keyname):
|
||||
return self.values[keyname][1]
|
||||
else:
|
||||
raise (AttributeError)
|
||||
|
||||
class TerminatorConfValuestoreDefault (TerminatorConfValuestore):
|
||||
def __init__ (self):
|
||||
self.type = "Default"
|
||||
self.values = self.defaults
|
||||
|
||||
class TerminatorConfValuestoreRC (TerminatorConfValuestore):
|
||||
rcfilename = ""
|
||||
#FIXME: use inotify to watch the rc, split __init__ into a parsing function
|
||||
# that can be re-used when rc changes.
|
||||
def __init__ (self):
|
||||
self.type = "RCFile"
|
||||
self.rcfilename = pwd.getpwuid (os.getuid ())[5] + "/.terminatorrc"
|
||||
if os.path.exists (self.rcfilename):
|
||||
rcfile = open (self.rcfilename)
|
||||
rc = rcfile.readlines ()
|
||||
rcfile.close ()
|
||||
|
||||
for item in rc:
|
||||
try:
|
||||
item = item.strip ()
|
||||
if item and item[0] != '#':
|
||||
(key, value) = item.split ("=")
|
||||
dbg ("VS_RCFile: Setting value %s to %s"%(key, value))
|
||||
self.values[key] = [self.defaults[key][0], self.defaults[key][0](value)]
|
||||
except:
|
||||
pass
|
||||
|
||||
class TerminatorConfValuestoreGConf (TerminatorConfValuestore):
|
||||
profile = ""
|
||||
client = None
|
||||
|
||||
def __init__ (self, profile = None):
|
||||
self.type = "GConf"
|
||||
|
||||
self.client = gconf.client_get_default ()
|
||||
|
||||
# Grab a couple of values from base class to avoid recursing with our __getattr__
|
||||
self._gt_dir = self.defaults['gt_dir'][1]
|
||||
self._profile_dir = self.defaults['profile_dir'][1]
|
||||
|
||||
if not profile:
|
||||
profile = self.client.get_string (self._gt_dir + '/global/default_profile')
|
||||
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)
|
||||
self.profile = '%s/%s'%(self._profile_dir, profile)
|
||||
elif "Default" in profiles:
|
||||
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
|
||||
# FIXME: Find a better way to handle this than setting a non-profile
|
||||
dbg ("No profile found, deleting __getattr__")
|
||||
del (self.__getattr__)
|
||||
|
||||
self.client.add_dir (self.profile, gconf.CLIENT_PRELOAD_RECURSIVE)
|
||||
if self.on_gconf_notify:
|
||||
self.client.notify_add (self.profile, self.on_gconf_notify)
|
||||
|
||||
self.client.add_dir ('/apps/metacity/general', gconf.CLIENT_PRELOAD_RECURSIVE)
|
||||
self.client.notify_add ('/apps/metacity/general/focus_mode', self.on_gconf_notify)
|
||||
|
||||
def on_gconf_notify (self, client, cnxn_id, entry, what):
|
||||
if self.reconfigure_callback:
|
||||
self.reconfigure_callback ()
|
||||
|
||||
def __getattr__ (self, key = ""):
|
||||
ret = None
|
||||
|
||||
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
|
||||
if funcname == "get_str":
|
||||
funcname = "get_string"
|
||||
typefunc = getattr (value, funcname)
|
||||
ret = typefunc ()
|
||||
|
||||
return (ret)
|
||||
else:
|
||||
raise (AttributeError)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
stores = []
|
||||
stores.append (TerminatorConfValuestoreRC ())
|
||||
|
||||
try:
|
||||
import gconf
|
||||
stores.append (TerminatorConfValuestoreGConf ())
|
||||
except:
|
||||
pass
|
||||
|
||||
foo = TerminatorConfig (stores)
|
||||
|
||||
## cmsj: this is my testing ground
|
||||
## ensure that font is set in the Default gconf profile
|
||||
## set titlebars in the RC file
|
||||
## remove titletips from gconf/RC
|
||||
## do not define blimnle in any way
|
||||
|
||||
# This should come from gconf (it's set by gnome-terminal)
|
||||
print foo.font
|
||||
|
||||
# This should come from RC
|
||||
print foo.titlebars
|
||||
|
||||
# This should come from defaults
|
||||
print foo.titletips
|
||||
|
||||
# This should raise AttributeError
|
||||
print foo.blimnle
|
Loading…
Reference in New Issue