Use XMLRPC if the DBUS version is too old.
[rox-lib/lack.git] / python / rox / session.py
blob5b1316b0357c8a4a15a609bdb7bd70ad61662084
1 """Contact ROX-Session via the DBus or XMLRPC interface. Using get_session()
2 will return a proxy object on which you can make remote calls to control
3 the session. Similarly get_settings() will return an object to control
4 session settings, e.g.
6 try:
7 settings = session.get_settings()
8 type, value = settings.GetSetting('Gtk/KeyThemeName')
9 except:
10 # No ROX-Session available, do something else
12 In addition the Setting class is provided which derives from rox.options.Option
13 but has two important differences: it is not saved to the options file and
14 it is synchronized with a value of the same name in the ROX-Session settings.
15 """
17 import os
18 import rox
19 from rox.options import OptionGroup, Option
20 from rox import OptionsBox, g
21 import rox.xxmlrpc
22 import gobject
24 try:
25 import dbus
26 dbus_ok=(dbus.version>=(0, 42, 0))
27 except:
28 dbus_ok=False
30 if dbus_ok:
31 bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
32 else:
33 bus = None
35 session_service = "net.sf.rox.Session"
36 control_object = '/Session'
37 control_interface = 'net.sf.rox.Session.Control'
38 settings_interface = 'net.sf.rox.Session.Settings'
39 settings_object = '/Settings'
41 def _dbus_get_proxy(bus, service_name, object_name, interface_name):
42 """For internal use. Do not call this, call get_proxy() instead."""
43 try:
44 service = bus.get_service(service_name)
45 obj = service.get_object(object_name, interface_name)
46 proxy = obj
47 except AttributeError:
48 obj = bus.get_object(service_name, object_name)
49 iface = dbus.Interface(obj, interface_name)
50 proxy = iface
51 return proxy
53 class _caller:
54 """For internal use."""
55 def __init__(self, method):
56 self.method=method
58 def __call__(self, *params):
59 client=self.method(*params)
60 return client.get_response()
62 class _RPCProxy:
63 """For internal use."""
64 def __init__(self, obj):
65 self.obj=obj
67 def __getattr__(self, method):
68 invoke=self.obj.__getattr__(method)
69 return _caller(invoke)
71 def _xxmlrpc_get_proxy(service_name, object_name, interface_name):
72 """For internal use. Do not call this, call get_proxy() instead."""
73 proxy=rox.xxmlrpc.XXMLProxy(service_name)
74 return _RPCProxy(proxy.get_object(object_name))
76 def get_proxy(service_name, object_name, interface_name):
77 """Get a proxy object for the required service, object path and interface.
78 This selects an appropriate transport for you, either DBus or XMLRPC."""
79 if dbus_ok:
80 return _dbus_get_proxy(bus, service_name, object_name, interface_name)
81 return _xxmlrpc_get_proxy(service_name, object_name, interface_name)
83 def get_session():
84 """Return a proxy object for the ROX-Session settings interface"""
85 return get_proxy(session_service, control_object,
86 control_interface)
88 def get_settings():
89 """Return a proxy object for the ROX-Session control interface"""
90 return get_proxy(session_service, settings_object,
91 settings_interface)
93 def running():
94 """Return True if ROX-Session is detected as running"""
95 if not dbus_ok:
96 proxy=_xxmlrpc_get_proxy(session_service, control_object,
97 control_interface)
98 return proxy is not None
99 try:
100 proxy = get_proxy('org.freedesktop.DBus', '/org/freedesktop/DBus',
101 'org.freedesktop.DBus')
102 except:
103 return False
105 try:
106 services = proxy.ListServices()
107 except:
108 services = proxy.ListNames()
110 return session_service in services
112 class Setting(Option):
113 """A Setting is an Option whose value is communicated with ROX-Session
114 instead of being stored in the program's options."""
116 def __init__(self, name, default, group=None):
117 """Initialize the option. Unlike the normal Option the value
118 is available immediatley (provided ROX-Session is running)."""
119 Option.__init__(self, name, default, group)
120 self.store = False # Do not let OptionGroup this write to file
122 self.is_string = isinstance(default, basestring)
123 self.proxy = get_settings()
124 try:
125 type, value = self.proxy.GetSetting(name)
126 except:
127 self._set(default)
128 else:
129 self._set(value, notify = False)
131 def _set(self, value, notify = True):
132 Option._set(self, value)
133 if not notify: return
135 def set(obj, value):
136 # Changing the theme will make GTK try to rebuild all
137 # its top-levels. Included destroyed ones that Python's
138 # GC holds a reference to still. Drop them now...
139 import gc; gc.collect()
140 if obj.is_string:
141 obj.proxy.SetString(obj.name, value)
142 else:
143 obj.proxy.SetInt(obj.name, obj.int_value)
145 gobject.idle_add(set, self, value)
148 # Test routine
149 if __name__=='__main__':
150 print 'Session running? %s' % running()
151 settings=get_settings()
152 #print 'settings=', settings
153 v='Gtk/KeyThemeName'
154 print '%s = %s' % (v, settings.GetSetting(v))
155 #x=settings.GetSetting(v)
156 #print str(x), `x`
157 #y=x.get_response()
158 #print y
159 v='Net/ThemeName'
160 print '%s = %s' % (v, settings.GetSetting(v))
161 control=get_session()
162 control.ShowMessages()