2
* This file is a part of the Cairo-Dock project
4
* Copyright : (C) see the 'copyright' file.
5
* E-mail : see the 'copyright' file.
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
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
#include <sys/types.h>
25
#include "applet-struct.h"
26
#include "applet-item.h"
27
#include "applet-draw.h"
28
#include "applet-host.h"
29
#include "applet-host-ias.h" // for fallback
30
#include "applet-host-kde.h"
33
#define CD_STATUS_NOTIFIER_WATCHER_ADDR "org.kde.StatusNotifierWatcher"
34
#define CD_STATUS_NOTIFIER_WATCHER_OBJ "/StatusNotifierWatcher"
35
#define CD_STATUS_NOTIFIER_WATCHER_IFACE "org.kde.StatusNotifierWatcher"
37
static DBusGProxyCall *s_pDetectWatcherCall = NULL;
44
static void on_new_item (DBusGProxy *proxy_watcher, const gchar *cNotifierItemId, CairoDockModuleInstance *myApplet)
47
cd_debug ("=== %s (%s)", __func__, cNotifierItemId);
49
gchar *cService = NULL, *cObjectPath = NULL;
50
gchar *str = strchr (cNotifierItemId, '/');
51
if (str != NULL) // service + path
53
cService = g_strndup (cNotifierItemId, str - cNotifierItemId);
56
else // we handle this case too, by supposing the path is the default /StatusNotifierItem
58
cService = g_strdup (cNotifierItemId);
62
cd_satus_notifier_add_new_item (cService, cObjectPath, -1); // indicator-application's positions start from 0, so it will never be -1.
68
static void on_removed_item (DBusGProxy *proxy_watcher, const gchar *cNotifierItemId, CairoDockModuleInstance *myApplet)
71
cd_debug ("=== %s (%s)", __func__, cNotifierItemId);
73
gchar *str = strchr (cNotifierItemId, '/');
74
if (str != NULL) // service + path, remove the path, we only need the service.
77
cd_satus_notifier_remove_item (cNotifierItemId, -1);
87
static void _on_get_applications_from_watcher (DBusGProxy *proxy, DBusGProxyCall *call_id, CairoDockModuleInstance *myApplet)
89
cd_debug ("=== %s ()", __func__);
92
GError *erreur = NULL;
93
GValue *v = g_new0 (GValue, 1);
94
gboolean bSuccess = dbus_g_proxy_end_call (proxy,
101
cd_debug ("=== couldn't get applications from the watcher (%s)", erreur->message);
102
g_error_free (erreur);
109
if (!G_VALUE_HOLDS_BOXED (v))
111
gchar **pApplications = g_value_get_boxed (v);
112
if (pApplications == NULL)
116
gchar *cService = NULL, *cObjectPath = NULL;
117
CDStatusNotifierItem *pItem;
118
for (i = 0; pApplications[i] != NULL; i ++)
120
g_print (" + '%s'\n", pApplications[i]); // service + path
121
if (*pApplications[i] == '\0')
124
gchar *str = strchr (pApplications[i], '/');
125
if (str != NULL) // service + path
127
cService = g_strndup (pApplications[i], str - pApplications[i]);
130
else // we handle this case too, by supposing the path is the default /StatusNotifierItem
132
cService = g_strdup (pApplications[i]);
135
pItem = cd_satus_notifier_create_item (cService, cObjectPath);
139
cd_debug ("=== => + %s", pItem->cTitle);
140
myData.pItems = g_list_prepend (myData.pItems, pItem);
145
if (myConfig.bCompactMode)
147
cd_satus_notifier_reload_compact_mode ();
151
cd_satus_notifier_load_icons_from_items ();
154
else // un watcher asocial comme celui d'Ubuntu, on essaye avec l'"indicator-application".
156
cd_debug ("=== this watcher is not so friendly, let's try the 'application indicator'");
157
myData.bBrokenWatcher = TRUE;
158
if (myData.bIASWatched)
159
cd_satus_notifier_get_items_from_ias ();
169
static void _on_register_host (DBusGProxy *proxy, DBusGProxyCall *call_id, CairoDockModuleInstance *myApplet)
171
cd_debug ("=== %s ()", __func__);
173
GError *erreur = NULL;
174
gboolean bSuccess = dbus_g_proxy_end_call (proxy,
180
cd_debug ("couldn't register to the Notification Watcher (%s)", erreur->message);
181
g_error_free (erreur);
186
if (bSuccess) // we are friend now, let's ask him the current items.
188
cd_debug ("=== found a friendly watcher, now ask for the items...");
189
// get the current items
190
myData.pProxyWatcherProps = cairo_dock_create_new_session_proxy (
191
CD_STATUS_NOTIFIER_WATCHER_ADDR,
192
CD_STATUS_NOTIFIER_WATCHER_OBJ,
193
DBUS_INTERFACE_PROPERTIES);
194
dbus_g_proxy_begin_call (myData.pProxyWatcherProps,
196
(DBusGProxyCallNotify)_on_get_applications_from_watcher,
198
(GDestroyNotify) NULL,
199
G_TYPE_STRING, CD_STATUS_NOTIFIER_WATCHER_IFACE,
200
G_TYPE_STRING, "RegisteredStatusNotifierItems",
203
// connect to the signals to keep the list of items up-to-date.
204
dbus_g_proxy_add_signal(myData.pProxyWatcher, "StatusNotifierItemRegistered",
205
G_TYPE_STRING, G_TYPE_INVALID); // ServiceRegistered
206
dbus_g_proxy_connect_signal(myData.pProxyWatcher, "StatusNotifierItemRegistered",
207
G_CALLBACK(on_new_item), myApplet, NULL);
209
dbus_g_proxy_add_signal(myData.pProxyWatcher, "StatusNotifierItemUnregistered",
210
G_TYPE_STRING, G_TYPE_INVALID); // ServiceUnregistered
211
dbus_g_proxy_connect_signal(myData.pProxyWatcher, "StatusNotifierItemUnregistered",
212
G_CALLBACK(on_removed_item), myApplet, NULL);
214
else // an asocial watcher like the Ubuntu's one, let's try with the IAS if availeble.
216
cd_debug ("=== no friendy watcher, let's try the 'application indicator'");
217
myData.bBrokenWatcher = TRUE;
218
if (myData.bIASWatched)
219
cd_satus_notifier_get_items_from_ias ();
223
static void _on_watcher_owner_changed (gboolean bOwned, gpointer data)
225
cd_debug ("=== Watcher is on the bus (%d)", bOwned);
230
myData.bNoWatcher = FALSE;
231
// set up a proxy to the Watcher
232
myData.pProxyWatcher = cairo_dock_create_new_session_proxy (
233
CD_STATUS_NOTIFIER_WATCHER_ADDR,
234
CD_STATUS_NOTIFIER_WATCHER_OBJ,
235
CD_STATUS_NOTIFIER_WATCHER_IFACE); // whenever it appears on the bus, we'll get it.
237
// and register to it.
238
cd_debug ("=== register to the it");
239
dbus_g_proxy_begin_call (myData.pProxyWatcher, "RegisterStatusNotifierHost", // RegisterNotificationHost
240
(DBusGProxyCallNotify)_on_register_host,
242
(GDestroyNotify) NULL,
243
G_TYPE_STRING, myData.cHostName,
245
CD_APPLET_SET_IMAGE_ON_MY_ICON (NULL); // remove the broken image if it was set beforehand, to get the default icon in the items GUI.
247
else // no more watcher on the bus.
249
g_object_unref (myData.pProxyWatcher);
250
myData.pProxyWatcher = NULL;
252
g_object_unref (myData.pProxyWatcherProps);
253
myData.pProxyWatcherProps = NULL;
255
g_list_foreach (myData.pItems, (GFunc) cd_free_item, NULL);
256
g_list_free (myData.pItems);
257
myData.pItems = NULL;
259
g_hash_table_remove_all (myData.pThemePaths);
261
// empty the list of items and redraw.
262
if (! myConfig.bCompactMode)
264
CD_APPLET_DELETE_MY_ICONS_LIST;
268
// draw an 'failed' image to not have an empty icon.
269
CD_APPLET_SET_IMAGE_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/icon-broken.svg");
271
myData.bBrokenWatcher = FALSE;
273
myData.bNoWatcher = TRUE;
274
cd_satus_notifier_launch_our_watcher ();
278
static void _on_detect_watcher (gboolean bPresent, gpointer data)
280
cd_debug ("=== Watcher is present: %d", bPresent);
282
s_pDetectWatcherCall = NULL;
283
// if present, set up proxy.
286
_on_watcher_owner_changed (TRUE, NULL);
288
else if (myConfig.bCompactMode) // in compact mode, draw a 'failed' image to not have an empty icon.
290
myData.bNoWatcher = TRUE;
291
cd_satus_notifier_launch_our_watcher ();
292
CD_APPLET_SET_IMAGE_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/icon-broken.svg");
295
// watch whenever the Watcher goes up or down.
296
cairo_dock_watch_dbus_name_owner (CD_STATUS_NOTIFIER_WATCHER_ADDR,
297
(CairoDockDbusNameOwnerChangedFunc) _on_watcher_owner_changed,
302
void cd_satus_notifier_detect_watcher (void)
304
s_pDetectWatcherCall = cairo_dock_dbus_detect_application_async (CD_STATUS_NOTIFIER_WATCHER_ADDR,
305
(CairoDockOnAppliPresentOnDbus) _on_detect_watcher,
309
void cd_satus_notifier_unregister_from_watcher (void)
311
if (myData.pProxyWatcher != NULL)
313
g_object_unref (myData.pProxyWatcher);
314
g_object_unref (myData.pProxyWatcherProps);
317
if (s_pDetectWatcherCall != NULL)
319
DBusGProxy *pProxy = cairo_dock_get_main_proxy ();
320
dbus_g_proxy_cancel_call (pProxy, s_pDetectWatcherCall);
321
s_pDetectWatcherCall = NULL;
323
cairo_dock_stop_watching_dbus_name_owner (CD_STATUS_NOTIFIER_WATCHER_ADDR,
324
(CairoDockOnAppliPresentOnDbus) _on_detect_watcher);