~ubuntu-branches/ubuntu/oneiric/cairo-dock-plug-ins/oneiric-updates

« back to all changes in this revision

Viewing changes to Status-Notifier/src/applet-host-kde.c

  • Committer: Kees Cook
  • Date: 2011-08-11 23:17:39 UTC
  • mfrom: (20.1.1 cairo-dock-plug-ins)
  • Revision ID: kees@outflux.net-20110811231739-cteedan51tmdg77v
Tags: 2.4.0~0beta2-0ubuntu1
releasing version 2.4.0~0beta2-0ubuntu1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
* This file is a part of the Cairo-Dock project
 
3
*
 
4
* Copyright : (C) see the 'copyright' file.
 
5
* E-mail    : see the 'copyright' file.
 
6
*
 
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.
 
11
*
 
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/>.
 
18
*/
 
19
 
 
20
#include <stdlib.h>
 
21
#include <string.h>
 
22
#include <sys/types.h>
 
23
#include <unistd.h>
 
24
 
 
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"
 
31
 
 
32
// KDE watcher
 
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"
 
36
 
 
37
static DBusGProxyCall *s_pDetectWatcherCall = NULL;
 
38
 
 
39
 
 
40
  ///////////////
 
41
 /// Signals ///
 
42
///////////////
 
43
 
 
44
static void on_new_item (DBusGProxy *proxy_watcher, const gchar *cNotifierItemId, CairoDockModuleInstance *myApplet)
 
45
{
 
46
        CD_APPLET_ENTER;
 
47
        cd_debug ("=== %s (%s)", __func__, cNotifierItemId);
 
48
        
 
49
        gchar *cService = NULL, *cObjectPath = NULL;
 
50
        gchar *str = strchr (cNotifierItemId, '/');
 
51
        if (str != NULL)  // service + path
 
52
        {
 
53
                cService = g_strndup (cNotifierItemId, str - cNotifierItemId);
 
54
                cObjectPath = str;
 
55
        }
 
56
        else  // we handle this case too, by supposing the path is the default /StatusNotifierItem
 
57
        {
 
58
                cService = g_strdup (cNotifierItemId);
 
59
                cObjectPath = NULL;
 
60
        }
 
61
        
 
62
        cd_satus_notifier_add_new_item (cService, cObjectPath, -1);  // indicator-application's positions start from 0, so it will never be -1.
 
63
        
 
64
        g_free (cService);
 
65
        CD_APPLET_LEAVE ();
 
66
}
 
67
 
 
68
static void on_removed_item (DBusGProxy *proxy_watcher, const gchar *cNotifierItemId, CairoDockModuleInstance *myApplet)
 
69
{
 
70
        CD_APPLET_ENTER;
 
71
        cd_debug ("=== %s (%s)", __func__, cNotifierItemId);
 
72
        
 
73
        gchar *str = strchr (cNotifierItemId, '/');
 
74
        if (str != NULL)  // service + path, remove the path, we only need the service.
 
75
                *str = '\0';
 
76
        
 
77
        cd_satus_notifier_remove_item (cNotifierItemId, -1);
 
78
        
 
79
        CD_APPLET_LEAVE ();
 
80
}
 
81
 
 
82
 
 
83
  /////////////////
 
84
 /// Get Items ///
 
85
/////////////////
 
86
 
 
87
static void _on_get_applications_from_watcher (DBusGProxy *proxy, DBusGProxyCall *call_id, CairoDockModuleInstance *myApplet)
 
88
{
 
89
        cd_debug ("=== %s ()", __func__);
 
90
        CD_APPLET_ENTER;
 
91
        
 
92
        GError *erreur = NULL;
 
93
        GValue *v = g_new0 (GValue, 1);
 
94
        gboolean bSuccess = dbus_g_proxy_end_call (proxy,
 
95
                call_id,
 
96
                &erreur,
 
97
                G_TYPE_VALUE, v,
 
98
                G_TYPE_INVALID);
 
99
        if (erreur != NULL)
 
100
        {
 
101
                cd_debug ("=== couldn't get applications from the watcher (%s)", erreur->message);
 
102
                g_error_free (erreur);
 
103
                erreur = NULL;
 
104
                bSuccess = FALSE;
 
105
        }
 
106
        
 
107
        if (bSuccess)
 
108
        {
 
109
                if (!G_VALUE_HOLDS_BOXED (v))
 
110
                        CD_APPLET_LEAVE ();
 
111
                gchar **pApplications = g_value_get_boxed (v);
 
112
                if (pApplications == NULL)
 
113
                        CD_APPLET_LEAVE ();
 
114
                
 
115
                guint i;
 
116
                gchar *cService = NULL, *cObjectPath = NULL;
 
117
                CDStatusNotifierItem *pItem;
 
118
                for (i = 0; pApplications[i] != NULL; i ++)
 
119
                {
 
120
                        g_print (" + '%s'\n", pApplications[i]);  // service + path
 
121
                        if (*pApplications[i] == '\0')
 
122
                                continue;
 
123
                        
 
124
                        gchar *str = strchr (pApplications[i], '/');
 
125
                        if (str != NULL)  // service + path
 
126
                        {
 
127
                                cService = g_strndup (pApplications[i], str - pApplications[i]);
 
128
                                cObjectPath = str;
 
129
                        }
 
130
                        else  // we handle this case too, by supposing the path is the default /StatusNotifierItem
 
131
                        {
 
132
                                cService = g_strdup (pApplications[i]);
 
133
                                cObjectPath = NULL;
 
134
                        }
 
135
                        pItem = cd_satus_notifier_create_item (cService, cObjectPath);
 
136
                        g_free (cService);
 
137
                        if (! pItem)
 
138
                                continue;
 
139
                        cd_debug ("===  => + %s", pItem->cTitle);
 
140
                        myData.pItems = g_list_prepend (myData.pItems, pItem);
 
141
                }
 
142
                
 
143
                g_free (v);
 
144
                
 
145
                if (myConfig.bCompactMode)
 
146
                {
 
147
                        cd_satus_notifier_reload_compact_mode ();
 
148
                }
 
149
                else
 
150
                {
 
151
                        cd_satus_notifier_load_icons_from_items ();
 
152
                }
 
153
        }
 
154
        else   // un watcher asocial comme celui d'Ubuntu, on essaye avec l'"indicator-application".
 
155
        {
 
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 ();
 
160
        }
 
161
        CD_APPLET_LEAVE ();
 
162
}
 
163
 
 
164
 
 
165
  //////////////////
 
166
 /// Connection ///
 
167
//////////////////
 
168
 
 
169
static void _on_register_host (DBusGProxy *proxy, DBusGProxyCall *call_id, CairoDockModuleInstance *myApplet)
 
170
{
 
171
        cd_debug ("=== %s ()", __func__);
 
172
        CD_APPLET_ENTER;
 
173
        GError *erreur = NULL;
 
174
        gboolean bSuccess = dbus_g_proxy_end_call (proxy,
 
175
                call_id,
 
176
                &erreur,
 
177
                G_TYPE_INVALID);
 
178
        if (erreur != NULL)
 
179
        {
 
180
                cd_debug ("couldn't register to the Notification Watcher (%s)", erreur->message);
 
181
                g_error_free (erreur);
 
182
                erreur = NULL;
 
183
                bSuccess = FALSE;
 
184
        }
 
185
        
 
186
        if (bSuccess)  // we are friend now, let's ask him the current items.
 
187
        {
 
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,
 
195
                        "Get",
 
196
                        (DBusGProxyCallNotify)_on_get_applications_from_watcher,
 
197
                        myApplet,
 
198
                        (GDestroyNotify) NULL,
 
199
                        G_TYPE_STRING, CD_STATUS_NOTIFIER_WATCHER_IFACE,
 
200
                        G_TYPE_STRING, "RegisteredStatusNotifierItems",
 
201
                        G_TYPE_INVALID);
 
202
                
 
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);
 
208
                
 
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);
 
213
        }
 
214
        else  // an asocial watcher like the Ubuntu's one, let's try with the IAS if availeble.
 
215
        {
 
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 ();
 
220
        }
 
221
        CD_APPLET_LEAVE ();
 
222
}
 
223
static void _on_watcher_owner_changed (gboolean bOwned, gpointer data)
 
224
{
 
225
        cd_debug ("=== Watcher is on the bus (%d)", bOwned);
 
226
        CD_APPLET_ENTER;
 
227
        
 
228
        if (bOwned)
 
229
        {
 
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.
 
236
                
 
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,
 
241
                        myApplet,
 
242
                        (GDestroyNotify) NULL,
 
243
                        G_TYPE_STRING, myData.cHostName,
 
244
                        G_TYPE_INVALID);
 
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.
 
246
        }
 
247
        else  // no more watcher on the bus.
 
248
        {
 
249
                g_object_unref (myData.pProxyWatcher);
 
250
                myData.pProxyWatcher = NULL;
 
251
                
 
252
                g_object_unref (myData.pProxyWatcherProps);
 
253
                myData.pProxyWatcherProps = NULL;
 
254
                
 
255
                g_list_foreach (myData.pItems, (GFunc) cd_free_item, NULL);
 
256
                g_list_free (myData.pItems);
 
257
                myData.pItems = NULL;
 
258
                
 
259
                g_hash_table_remove_all (myData.pThemePaths);
 
260
                
 
261
                // empty the list of items and redraw.
 
262
                if (! myConfig.bCompactMode)
 
263
                {
 
264
                        CD_APPLET_DELETE_MY_ICONS_LIST;
 
265
                }
 
266
                else
 
267
                {
 
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");
 
270
                }
 
271
                myData.bBrokenWatcher = FALSE;
 
272
                
 
273
                myData.bNoWatcher = TRUE;
 
274
                cd_satus_notifier_launch_our_watcher ();
 
275
        }
 
276
        CD_APPLET_LEAVE ();
 
277
}
 
278
static void _on_detect_watcher (gboolean bPresent, gpointer data)
 
279
{
 
280
        cd_debug ("=== Watcher is present: %d", bPresent);
 
281
        CD_APPLET_ENTER;
 
282
        s_pDetectWatcherCall = NULL;
 
283
        // if present, set up proxy.
 
284
        if (bPresent)
 
285
        {
 
286
                _on_watcher_owner_changed (TRUE, NULL);
 
287
        }
 
288
        else if (myConfig.bCompactMode)  // in compact mode, draw a 'failed' image to not have an empty icon.
 
289
        {
 
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");
 
293
        }
 
294
        
 
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,
 
298
                NULL);
 
299
        CD_APPLET_LEAVE ();
 
300
}
 
301
 
 
302
void cd_satus_notifier_detect_watcher (void)
 
303
{
 
304
        s_pDetectWatcherCall = cairo_dock_dbus_detect_application_async (CD_STATUS_NOTIFIER_WATCHER_ADDR,
 
305
                (CairoDockOnAppliPresentOnDbus) _on_detect_watcher,
 
306
                NULL);
 
307
}
 
308
 
 
309
void cd_satus_notifier_unregister_from_watcher (void)
 
310
{
 
311
        if (myData.pProxyWatcher != NULL)
 
312
        {
 
313
                g_object_unref (myData.pProxyWatcher);
 
314
                g_object_unref (myData.pProxyWatcherProps);
 
315
        }
 
316
        
 
317
        if (s_pDetectWatcherCall != NULL)
 
318
        {
 
319
                DBusGProxy *pProxy = cairo_dock_get_main_proxy ();
 
320
                dbus_g_proxy_cancel_call (pProxy, s_pDetectWatcherCall);
 
321
                s_pDetectWatcherCall = NULL;
 
322
        }
 
323
        cairo_dock_stop_watching_dbus_name_owner (CD_STATUS_NOTIFIER_WATCHER_ADDR,
 
324
                (CairoDockOnAppliPresentOnDbus) _on_detect_watcher);
 
325
}