6
# Developped as a part of Cairo-Dock, but usable as a stand-alone systray daemon.
7
# The code follows the same logic as the KDE watcher, to ensure a complete compatibility.
12
import dbus, dbus.service
13
from dbus.mainloop.glib import DBusGMainLoop
15
class SNWatcher(dbus.service.Object):
16
bus_name_str = 'org.kde.StatusNotifierWatcher'
17
bus_obj_str = '/StatusNotifierWatcher'
18
bus_iface_str = 'org.kde.StatusNotifierWatcher'
19
items_list = [] # array of service+path
20
hosts_list = [] # array of services
23
DBusGMainLoop(set_as_default=True)
25
self.bus = dbus.SessionBus()
26
bus_name = dbus.service.BusName (self.bus_name_str, self.bus)
27
print "registered a watcher:",bus_name
28
dbus.service.Object.__init__(self, bus_name, self.bus_obj_str)
29
except Exception, exception:
30
print 'Could not open dbus. Uncaught exception.'
33
bus_object = self.bus.get_object(dbus.BUS_DAEMON_NAME, dbus.BUS_DAEMON_PATH)
34
self.main = dbus.Interface(bus_object, dbus.BUS_DAEMON_IFACE)
35
self.main.connect_to_signal("NameOwnerChanged", self.on_name_owner_changed)
37
self.loop = gobject.MainLoop()
40
def on_name_owner_changed(self, service, prev_owner, new_owner):
41
print "name_owner_changed: %s; %s; %s" % (service, prev_owner, new_owner)
42
if (new_owner == '' and not service.startswith(':')): # a service has disappear from the bus, check if it was an item or a host.
43
# search amongst the items.
45
print " search for ",match
47
for it in self.items_list:
48
print " check for ",it
49
if (it.startswith(match)): # it[0:len(match)] == match
51
to_be_removed.append(it)
52
for it in to_be_removed:
53
self.items_list.remove (it)
54
self.StatusNotifierItemUnregistered(it)
56
# search amongst the hosts.
58
for it in self.hosts_list:
60
to_be_removed.append(it)
61
for it in to_be_removed:
62
self.hosts_list.remove (it)
63
self.StatusNotifierHostUnregistered()
67
@dbus.service.method(dbus_interface = bus_iface_str, in_signature = 's', out_signature = None)
68
def RegisterStatusNotifierHost(self, service):
69
if (self.hosts_list.count (service) == 0): # if not already listed
70
self.hosts_list.append (service)
71
self.StatusNotifierHostRegistered()
72
print 'hosts:',self.hosts_list
75
@dbus.service.method(dbus_interface = bus_iface_str, in_signature = 's', out_signature = None, sender_keyword='sender')
76
def RegisterStatusNotifierItem(self, serviceOrPath, sender=None):
77
# build the item id: service + path
78
if (serviceOrPath[0] == '/'):
82
service = serviceOrPath
83
path = "/StatusNotifierItem"
85
itemId = service + path
86
# keep track of this new item, and emit the 'new' signal.
87
if (self.items_list.count (itemId) == 0): # if not already listed
88
self.items_list.append (itemId)
89
self.StatusNotifierItemRegistered (itemId)
93
@dbus.service.method(dbus_interface = dbus.PROPERTIES_IFACE, in_signature = 'ss', out_signature = 'v')
94
def Get(self, interface, property):
95
if interface == 'org.kde.StatusNotifierWatcher':
96
if property == 'RegisteredStatusNotifierItems':
97
print "items: ",self.items_list
98
if (len (self.items_list) != 0):
99
return self.items_list
100
else: # too bad! dbus-python can't encode the GValue if 'items_list' is None or [].
101
return [''] # so we return a empty string; hopefuly the host will skip this invalid value.
102
elif property == 'HasStatusNotifierHostRegistered':
103
return (len (self.hosts_list) != 0)
104
elif property == 'ProtocolVersion':
109
@dbus.service.signal(dbus_interface=bus_name_str, signature='s')
110
def StatusNotifierItemRegistered(self, service):
111
print "%s registered" % (service)
114
@dbus.service.signal(dbus_interface=bus_name_str, signature='s')
115
def StatusNotifierItemUnregistered(self, service):
116
print "%s unregistered" % (service)
119
@dbus.service.signal(dbus_interface=bus_name_str, signature=None)
120
def StatusNotifierHostRegistered(self):
121
print "a host has been registered"
124
@dbus.service.signal(dbus_interface=bus_name_str, signature=None)
125
def StatusNotifierHostUnregistered(self):
126
print "a host has been unregistered"
130
if __name__ == '__main__':