3
# This is a part of the Cairo-Dock plug-ins.
4
# Copyright : (C) 2011 by Fabrice Rey
5
# E-mail : fabounet@glx-dock.org
7
# This program is free software; you can redistribute it and/or
8
# modify it under the terms of the GNU General Public License
9
# as published by the Free Software Foundation; either version 3
10
# of the License, or (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
# http://www.gnu.org/licenses/licenses.html#GPL
18
# Developped as a part of Cairo-Dock, but usable as a stand-alone systray daemon.
19
# The code follows the same logic as the KDE watcher, to ensure a complete compatibility.
21
from __future__ import print_function
27
g_bMainLoopInGObject = True
29
from gi.repository import GLib as glib
30
from gi.repository import GObject as gobject
31
g_bMainLoopInGObject = False
33
import dbus, dbus.service
34
from dbus.mainloop.glib import DBusGMainLoop
36
class SNWatcher(dbus.service.Object):
37
bus_name_str = 'org.kde.StatusNotifierWatcher'
38
bus_obj_str = '/StatusNotifierWatcher'
39
bus_iface_str = 'org.kde.StatusNotifierWatcher'
40
items_list = [] # array of service+path
41
hosts_list = [] # array of services
43
def _emit_host_registered (self):
44
self.StatusNotifierHostRegistered()
48
DBusGMainLoop(set_as_default=True)
50
self.bus = dbus.SessionBus()
51
bus_name = dbus.service.BusName (self.bus_name_str, self.bus)
52
print("[Cairo-Dock] Status-Notifier: registered a watcher:",bus_name)
53
dbus.service.Object.__init__(self, bus_name, self.bus_obj_str)
54
except dbus.DBusException:
55
print('Could not open dbus. Uncaught exception.')
58
bus_object = self.bus.get_object(dbus.BUS_DAEMON_NAME, dbus.BUS_DAEMON_PATH)
59
self.main = dbus.Interface(bus_object, dbus.BUS_DAEMON_IFACE)
60
self.main.connect_to_signal("NameOwnerChanged", self.on_name_owner_changed)
62
if g_bMainLoopInGObject:
63
self.loop = gobject.MainLoop()
65
self.loop = glib.MainLoop()
68
def on_name_owner_changed(self, service, prev_owner, new_owner):
69
# print("name_owner_changed: %s; %s; %s" % (service, prev_owner, new_owner))
70
if (new_owner == '' and not service.startswith(':')): # a service has disappear from the bus, check if it was an item or a host.
71
# search amongst the items.
73
# print(" search for ",match)
75
for it in self.items_list:
76
# print(" check for ",it)
77
if (it.startswith(match)): # it[0:len(match)] == match
79
to_be_removed.append(it)
80
for it in to_be_removed:
81
self.items_list.remove (it)
82
self.StatusNotifierItemUnregistered(it)
84
# search amongst the hosts.
86
for it in self.hosts_list:
88
to_be_removed.append(it)
89
for it in to_be_removed:
90
self.hosts_list.remove (it)
91
self.StatusNotifierHostUnregistered()
92
elif (service == 'com.Skype.API'): # this stupid proprietary software only creates its item when the host appears !
93
glib.timeout_add_seconds(2, self._emit_host_registered)
97
@dbus.service.method(dbus_interface = bus_iface_str, in_signature = 's', out_signature = None)
98
def RegisterStatusNotifierHost(self, service):
99
if (self.hosts_list.count (service) == 0): # if not already listed
100
self.hosts_list.append (service)
101
self.StatusNotifierHostRegistered()
102
# print('hosts:',self.hosts_list)
105
@dbus.service.method(dbus_interface = bus_iface_str, in_signature = 's', out_signature = None, sender_keyword='sender')
106
def RegisterStatusNotifierItem(self, serviceOrPath, sender=None):
107
# build the item id: service + path
108
if (serviceOrPath[0] == '/'):
112
service = serviceOrPath
113
path = "/StatusNotifierItem"
115
itemId = service + path
116
# keep track of this new item, and emit the 'new' signal.
117
if (self.items_list.count (itemId) == 0): # if not already listed
118
self.items_list.append (itemId)
119
self.StatusNotifierItemRegistered (itemId)
123
@dbus.service.method(dbus_interface = dbus.PROPERTIES_IFACE, in_signature = 'ss', out_signature = 'v')
124
def Get(self, interface, property):
125
if interface == 'org.kde.StatusNotifierWatcher':
126
if property == 'RegisteredStatusNotifierItems':
127
# print("items: ",self.items_list)
128
if (len (self.items_list) != 0):
129
return self.items_list
130
else: # too bad! dbus-python can't encode the GValue if 'items_list' is None or [].
131
return [''] # so we return a empty string; hopefuly the host will skip this invalid value.
132
elif property == 'IsStatusNotifierHostRegistered':
133
return (len (self.hosts_list) != 0)
134
elif property == 'HasStatusNotifierHostRegistered': # deprecated
135
return (len (self.hosts_list) != 0)
136
elif property == 'ProtocolVersion':
141
@dbus.service.signal(dbus_interface=bus_name_str, signature='s')
142
def StatusNotifierItemRegistered(self, service):
143
# print("%s registered" % (service))
146
@dbus.service.signal(dbus_interface=bus_name_str, signature='s')
147
def StatusNotifierItemUnregistered(self, service):
148
# print("%s unregistered" % (service))
151
@dbus.service.signal(dbus_interface=bus_name_str, signature=None)
152
def StatusNotifierHostRegistered(self):
153
# print("a host has been registered")
156
@dbus.service.signal(dbus_interface=bus_name_str, signature=None)
157
def StatusNotifierHostUnregistered(self):
158
# print("a host has been unregistered")
162
if __name__ == '__main__':