Fix syntax error in getting the widget set (Stephen Watson).
[rox-lib.git] / ROX-Lib2 / python / rox / settings.py
blobc2420795eb025b8a2c8ed77faa04ec6110df9ec4
1 """ROX-Session settings with D-Bus and optional Gnome (gconf) setting
3 Setting and Settings are derived from ROX-Lib's Option and OptionGroup
4 respectively. A Setting sends a dbus message to ROX-Session when changed.
6 Use get_xsettings to get the dbus interface, then create a Settings object
7 with it to pass to each Setting.
8 """
9 import os
10 import rox
11 from rox.options import OptionGroup, Option
12 import rox.session
13 import gobject
15 gconf = None
17 _warned_import = False
18 _warned_connect = False
19 _warned_norox = False
21 def get_xsettings():
22 """Returns ROX-Session's Settings dbus/xxmlrpc interface.
24 Called automatically if and when necessary
25 """
26 return rox.session.get_settings()
28 def get_gconf():
29 """Get GConf connection.
31 Some of the options have corresponding gconf entries; this gets
32 the gconf client connection. It will be called automatically if
33 and when necessary.
34 """
35 global gconf
36 try:
37 import gconf
38 client = gconf.client_get_default ()
39 client.add_dir ("/desktop/gnome/interface",
40 gconf.CLIENT_PRELOAD_NONE)
41 except:
42 client = None
43 return client
45 class Settings(OptionGroup):
46 """A group of options associated with the dbus interface. """
48 program = os.path.basename(rox.app_dir) # For dialog box title
50 def __init__(self, bus = None, client = None):
51 """Constructor
53 bus: ROX-Session's dbus interface. Omit to use default
54 client: gconf client connection. Omit to use default
55 """
56 self.options = {}
57 self.callbacks = []
58 self.bus = bus or get_xsettings()
59 self.client = client
61 def notify(self):
62 map(apply, self.callbacks)
63 for option in self:
64 option.has_changed = False
66 def save(self):
67 pass
69 class Setting(Option):
70 def __init__(self, name, default, settings, garbage = False,
71 gconf_key = None):
72 """Constructor
74 name: Option name as sent in dbus message.
75 default: Default value.
76 settings: The group of Settings this one belongs to.
77 garbage: Font and theme changes cause (some versions of?) GTK to
78 update all windows even if they're supposed to have been
79 destroyed. If we've just closed a dialog eg font selection (or
80 menu?), this can cause a crash, so this option forces a garbage
81 collection to make sure there is no stale reference.
82 gconf_key: Optional gconf setting key. If it begins with / it
83 will be treated as the absolute path, otherwise it will
84 have /desktop/gnome/interface/ prepended.
85 """
86 self.name = name
87 self.default = default
88 self.settings = settings
89 settings.options[name] = self
90 self.garbage = garbage
91 self.value = None
92 if gconf_key and gconf_key[0] != '/':
93 gconf_key = "/desktop/gnome/interface/" + gconf_key
94 self.gconf_key = gconf_key
95 try:
96 type, value = settings.bus.GetSetting(name)
97 except: #XXX: dbus.DBusException:
98 self._set(default)
99 else:
100 self._set(value, notify = False)
102 def make_gconf_value(self):
103 """Returns value ready to be converted to a GConfValue.
105 Override if necessary. Return a bool, int or string
106 (so the name is slightly misleading).
108 if type(self.default) is str:
109 return str(self.value)
110 else:
111 return self.int_value
113 def pre_notify_hook(self):
114 """Called just before notifying dbus the standard way.
116 Override to perform additional operations and return True
117 if you want to prevent normal notification.
118 Won't be called if there's no bus.
120 return False
122 def post_notify_hook(self):
123 """Called just after notifying dbus the standard way.
125 Override to perform additional operations.
126 Won't be called if there's no bus, but otherwise will be called
127 even if pre_notif_hook() returns True.
129 pass
131 def _set(self, value, notify = True):
132 Option._set(self, value)
133 if not notify: return
135 # This is a separate function because it used to be called via a
136 # GObject idle timeout instead of immediately. But that seems to be
137 # more of a hinrance than a help.
138 def set():
139 if self.garbage:
140 import gc
141 gc.collect()
143 if not self.settings.bus is None:
144 if not self.pre_notify_hook():
145 if type(self.default) is str:
146 self.settings.bus.SetString(self.name, self.value)
147 else:
148 self.settings.bus.SetInt(self.name, self.int_value)
149 self.post_notify_hook()
151 if self.gconf_key:
152 if not self.settings.client:
153 self.settings.client = get_gconf()
154 if self.settings.client:
155 val = self.make_gconf_value()
156 # Unfortunately GConfClient.set can't coerce builtin
157 # types to GConfValues
158 if type(val) is bool:
159 self.settings.client.set_bool(self.gconf_key, val)
160 elif type(val) is int:
161 self.settings.client.set_int(self.gconf_key, val)
162 else:
163 self.settings.client.set_string(self.gconf_key, val)
165 return False
167 if self.garbage:
168 gobject.idle_add(set)
169 else:
170 set()
172 class BoolSetting(Setting):
173 """Bool setting for GConf/D-Bus
175 Option doesn't distinguish between int and bool, but gconf does,
176 so use this for bool options.
178 def __init__(self, name, default, settings, theme, gconf_key = None):
179 Setting.__init__(self, name, default, settings, theme, gconf_key)
180 def make_gconf_value(self):
181 return self.int_value != 0
183 # Test routine
184 if __name__=='__main__':
185 setobj=get_xsettings()
186 print 'object=', setobj
187 v='Gtk/KeyThemeName'
188 print '%s = %s' % (v, setobj.GetSetting(v))
189 v='Net/ThemeName'
190 print '%s = %s' % (v, setobj.GetSetting(v))
192 print 'All: ', setobj.Enumerate()
193 print 'ROX: ', setobj.Enumerate('ROX/*')