~cairo-dock-team/cairo-dock-plug-ins/plug-ins

« back to all changes in this revision

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

  • Committer: Matthieu Baerts
  • Date: 2014-10-19 00:26:10 UTC
  • Revision ID: matttbe@gmail.com-20141019002610-ulf26s9b4c4rw10r
We just switched from BZR to Git.
Follow us on Github: https://github.com/Cairo-Dock

Note: we will only use Github to manage our source code and all pull requests.
Please continue to report your bugs/ideas/messages on our forum or Launchpad! 

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"
30
 
 
31
 
// Ubuntu sort-of-high-level-Watcher (new or old address)
32
 
#if (INDICATOR_OLD_NAMES == 0)  // Natty
33
 
#define CD_INDICATOR_APPLICATION_ADDR "com.canonical.indicator.application"
34
 
#define CD_INDICATOR_APPLICATION_OBJ "/com/canonical/indicator/application/service"
35
 
#define CD_INDICATOR_APPLICATION_IFACE "com.canonical.indicator.application.service"
36
 
#else
37
 
#define CD_INDICATOR_APPLICATION_ADDR "org.ayatana.indicator.application"
38
 
#define CD_INDICATOR_APPLICATION_OBJ "/org/ayatana/indicator/application/service"
39
 
#define CD_INDICATOR_APPLICATION_IFACE "org.ayatana.indicator.application.service"
40
 
#endif
41
 
 
42
 
// Ubuntu Indicator Service
43
 
#define  CD_INDICATOR_SERVICE_INTERFACE "org.ayatana.indicator.service"
44
 
#define  CD_INDICATOR_SERVICE_OBJECT "/org/ayatana/indicator/service"
45
 
 
46
 
 
47
 
static DBusGProxyCall *s_pDetectIASCall = NULL;
48
 
 
49
 
#if (INDICATOR_OLD_NAMES != 0)  // Maverick
50
 
static void _cd_cclosure_marshal_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING (GClosure *closure,
51
 
        GValue *return_value G_GNUC_UNUSED,
52
 
        guint n_param_values,
53
 
        const GValue *param_values,
54
 
        gpointer invocation_hint G_GNUC_UNUSED,
55
 
        gpointer marshal_data)
56
 
{
57
 
        //cd_debug ("=== %s ()", __func__);
58
 
        typedef void (*GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING) (
59
 
                gpointer     data1,
60
 
                gchar      *arg_1,
61
 
                gint        arg_2,
62
 
                gchar      *arg_3,
63
 
                gchar      *arg_4,
64
 
                gchar      *arg_5,
65
 
                gchar      *arg_6,
66
 
                gchar      *arg_7,
67
 
                gpointer     data2);
68
 
        register GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING callback;
69
 
        register GCClosure *cc = (GCClosure*) closure;
70
 
        register gpointer data1, data2;
71
 
        g_return_if_fail (n_param_values == 8);  // return_value est NULL ici, car la callback ne renvoit rien.
72
 
 
73
 
        if (G_CCLOSURE_SWAP_DATA (closure))
74
 
        {
75
 
                data1 = closure->data;
76
 
                data2 = g_value_peek_pointer (param_values + 0);
77
 
        }
78
 
        else
79
 
        {
80
 
                data1 = g_value_peek_pointer (param_values + 0);
81
 
                data2 = closure->data;
82
 
        }
83
 
        callback = (GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING) (marshal_data ? marshal_data : cc->callback);
84
 
 
85
 
        callback (data1,
86
 
                (char*) g_value_get_string (param_values + 1),
87
 
                g_value_get_int (param_values + 2),
88
 
                (char*) g_value_get_string (param_values + 3),
89
 
                (char*) g_value_get_string (param_values + 4),
90
 
                (char*) g_value_get_string (param_values + 5),
91
 
                (char*) g_value_get_string (param_values + 6),
92
 
                (char*) g_value_get_string (param_values + 7),
93
 
                data2);
94
 
}
95
 
#else  // Natty
96
 
#if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
97
 
static void _cd_cclosure_marshal_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING_STRING_STRING (
98
 
#elif (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
99
 
static void _cd_cclosure_marshal_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING_STRING (
100
 
#else
101
 
static void _cd_cclosure_marshal_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING (
102
 
#endif
103
 
        GClosure *closure,
104
 
        GValue *return_value G_GNUC_UNUSED,
105
 
        guint n_param_values,
106
 
        const GValue *param_values,
107
 
        gpointer invocation_hint G_GNUC_UNUSED,
108
 
        gpointer marshal_data)
109
 
{
110
 
        //cd_debug ("=== %s ()", __func__);
111
 
        #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
112
 
        typedef void (*GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING_STRING_STRING) (
113
 
        #elif (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
114
 
        typedef void (*GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING_STRING) (
115
 
        #else
116
 
        typedef void (*GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING) (
117
 
        #endif
118
 
                gpointer     data1,
119
 
                gchar      *arg_1,
120
 
                gint        arg_2,
121
 
                gchar      *arg_3,
122
 
                gchar      *arg_4,
123
 
                gchar      *arg_5,
124
 
                gchar      *arg_6,
125
 
                gchar      *arg_7,
126
 
                gchar      *arg_8,
127
 
                #if (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
128
 
                gchar      *arg_9,
129
 
                #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
130
 
                gchar      *arg_10,
131
 
                #endif
132
 
                #endif
133
 
                gpointer     data2);
134
 
        #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
135
 
        register GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING_STRING_STRING callback;
136
 
        #elif (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
137
 
        register GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING_STRING callback;
138
 
        #else
139
 
        register GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING callback;
140
 
        #endif
141
 
        register GCClosure *cc = (GCClosure*) closure;
142
 
        register gpointer data1, data2;
143
 
        // return_value est NULL ici, car la callback ne renvoit rien.
144
 
        #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
145
 
        g_return_if_fail (n_param_values == 11);
146
 
        #elif (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
147
 
        g_return_if_fail (n_param_values == 10);
148
 
        #else
149
 
        g_return_if_fail (n_param_values == 9);
150
 
        #endif
151
 
 
152
 
        if (G_CCLOSURE_SWAP_DATA (closure))
153
 
        {
154
 
                data1 = closure->data;
155
 
                data2 = g_value_peek_pointer (param_values + 0);
156
 
        }
157
 
        else
158
 
        {
159
 
                data1 = g_value_peek_pointer (param_values + 0);
160
 
                data2 = closure->data;
161
 
        }
162
 
        #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
163
 
        callback = (GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING_STRING_STRING)
164
 
        #elif (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
165
 
        callback = (GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING_STRING)
166
 
        #else
167
 
        callback = (GMarshalFunc_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING)
168
 
        #endif
169
 
                (marshal_data ? marshal_data : cc->callback);
170
 
 
171
 
        callback (data1,
172
 
                (char*) g_value_get_string (param_values + 1),
173
 
                g_value_get_int (param_values + 2),
174
 
                (char*) g_value_get_string (param_values + 3),
175
 
                (char*) g_value_get_boxed (param_values + 4),
176
 
                (char*) g_value_get_string (param_values + 5),
177
 
                (char*) g_value_get_string (param_values + 6),
178
 
                (char*) g_value_get_string (param_values + 7),
179
 
                (char*) g_value_get_string (param_values + 8),
180
 
                #if (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
181
 
                (char*) g_value_get_string (param_values + 9),
182
 
                #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
183
 
                (char*) g_value_get_string (param_values + 10),
184
 
                #endif
185
 
                #endif
186
 
                data2);
187
 
}
188
 
#endif
189
 
 
190
 
static void _cd_cclosure_marshal_VOID__INT_STRING_STRING (GClosure *closure,
191
 
        GValue *return_value G_GNUC_UNUSED,
192
 
        guint n_param_values,
193
 
        const GValue *param_values,
194
 
        gpointer invocation_hint G_GNUC_UNUSED,
195
 
        gpointer marshal_data)
196
 
{
197
 
        //cd_debug ("=== %s ()", __func__);
198
 
        typedef void (*GMarshalFunc_VOID__INT_STRING_STRING) (
199
 
                gpointer     data1,
200
 
                gint         arg_1,
201
 
                gchar       *arg_2,
202
 
                gchar       *arg_3,
203
 
                gpointer     data2);
204
 
        register GMarshalFunc_VOID__INT_STRING_STRING callback;
205
 
        register GCClosure *cc = (GCClosure*) closure;
206
 
        register gpointer data1, data2;
207
 
        g_return_if_fail (n_param_values == 4);  // return_value est NULL ici, car la callback ne renvoit rien.
208
 
 
209
 
        if (G_CCLOSURE_SWAP_DATA (closure))
210
 
        {
211
 
                data1 = closure->data;
212
 
                data2 = g_value_peek_pointer (param_values + 0);
213
 
        }
214
 
        else
215
 
        {
216
 
                data1 = g_value_peek_pointer (param_values + 0);
217
 
                data2 = closure->data;
218
 
        }
219
 
        callback = (GMarshalFunc_VOID__INT_STRING_STRING) (marshal_data ? marshal_data : cc->callback);
220
 
 
221
 
        callback (data1,
222
 
                g_value_get_int (param_values + 1),
223
 
                (char*) g_value_get_string (param_values + 2),
224
 
                (char*) g_value_get_string (param_values + 3),
225
 
                data2);
226
 
}
227
 
 
228
 
static void _cd_cclosure_marshal_VOID__INT_STRING (GClosure *closure,
229
 
        GValue *return_value G_GNUC_UNUSED,
230
 
        guint n_param_values,
231
 
        const GValue *param_values,
232
 
        gpointer invocation_hint G_GNUC_UNUSED,
233
 
        gpointer marshal_data)
234
 
{
235
 
        //cd_debug ("=== %s ()", __func__);
236
 
        typedef void (*GMarshalFunc_VOID__INT_STRING) (
237
 
                gpointer     data1,
238
 
                gint         arg_1,
239
 
                gchar       *arg_2,
240
 
                gpointer     data2);
241
 
        register GMarshalFunc_VOID__INT_STRING callback;
242
 
        register GCClosure *cc = (GCClosure*) closure;
243
 
        register gpointer data1, data2;
244
 
        g_return_if_fail (n_param_values == 3);  // return_value est NULL ici, car la callback ne renvoit rien.
245
 
 
246
 
        if (G_CCLOSURE_SWAP_DATA (closure))
247
 
        {
248
 
                data1 = closure->data;
249
 
                data2 = g_value_peek_pointer (param_values + 0);
250
 
        }
251
 
        else
252
 
        {
253
 
                data1 = g_value_peek_pointer (param_values + 0);
254
 
                data2 = closure->data;
255
 
        }
256
 
        callback = (GMarshalFunc_VOID__INT_STRING) (marshal_data ? marshal_data : cc->callback);
257
 
 
258
 
        callback (data1,
259
 
                g_value_get_int (param_values + 1),
260
 
                (char*) g_value_get_string (param_values + 2),
261
 
                data2);
262
 
}
263
 
 
264
 
  ///////////////
265
 
 /// Signals ///
266
 
///////////////
267
 
 
268
 
static void on_new_application (DBusGProxy *proxy_watcher, const gchar *cIconName, gint iPosition, const gchar *cAddress, const gchar *cObjectPath, const gchar *cIconThemePath, const gchar *cLabel, const gchar *cLabelGuide,
269
 
#if (INDICATOR_OLD_NAMES == 0)  // Natty
270
 
const gchar *cAccessbleDesc,  // WTF is this new param ??
271
 
#if (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
272
 
const gchar *cHint,  // <irony> is this a hint to work around a clumsy API ? </irony>
273
 
#if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
274
 
const gchar *cTitle,
275
 
#endif
276
 
#endif
277
 
#endif
278
 
GldiModuleInstance *myApplet)
279
 
{
280
 
        CD_APPLET_ENTER;
281
 
        cd_debug ("=== %s (%s, %s, %s, %s, %d)", __func__, cAddress, cObjectPath, cIconName, cIconThemePath, iPosition);
282
 
        #if (INDICATOR_OLD_NAMES == 0)  // Natty
283
 
        cd_debug ("    %s", cAccessbleDesc);
284
 
        #if (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
285
 
        cd_debug ("    %s", cHint);
286
 
        #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
287
 
        cd_debug ("    %s", cTitle);
288
 
        #endif
289
 
        #endif
290
 
        #endif
291
 
        
292
 
        // position +1 for items placed after this one.
293
 
        CDStatusNotifierItem *pItem;
294
 
        GList *it;
295
 
        for (it = myData.pItems; it != NULL; it = it->next)
296
 
        {
297
 
                pItem = it->data;
298
 
                if (pItem->iPosition >= iPosition)
299
 
                {
300
 
                        pItem->iPosition ++;
301
 
                        cd_debug ("===  %s -> %d -> %d", pItem->cId, pItem->iPosition-1, pItem->iPosition);
302
 
                }
303
 
        }
304
 
        
305
 
        cd_satus_notifier_add_new_item_with_default (cAddress, cObjectPath, iPosition,
306
 
                #if (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
307
 
                cIconName ? cIconName : cHint,
308
 
                #else
309
 
                cIconName,
310
 
                #endif
311
 
                cIconThemePath,
312
 
                #if (INDICATOR_OLD_NAMES == 0)
313
 
                cAccessbleDesc && *cAccessbleDesc != '\0' ? cAccessbleDesc :
314
 
                #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
315
 
                cTitle && *cTitle != '\0' ? cTitle :
316
 
                #endif
317
 
                #endif
318
 
                cLabel
319
 
                );
320
 
        
321
 
        CD_APPLET_LEAVE ();
322
 
}
323
 
 
324
 
static void on_removed_application (DBusGProxy *proxy_watcher, gint iPosition, GldiModuleInstance *myApplet)
325
 
{
326
 
        CD_APPLET_ENTER;
327
 
        cd_debug ("=== %s (%d)", __func__, iPosition);
328
 
        
329
 
        cd_satus_notifier_remove_item (NULL, iPosition);
330
 
        
331
 
        // position -1 for items placed after this one.
332
 
        CDStatusNotifierItem *pItem;
333
 
        GList *it;
334
 
        for (it = myData.pItems; it != NULL; it = it->next)
335
 
        {
336
 
                pItem = it->data;
337
 
                if (pItem->iPosition >= iPosition)
338
 
                {
339
 
                        pItem->iPosition --;
340
 
                        cd_debug ("===  %s -> %d -> %d", pItem->cId, pItem->iPosition+1, pItem->iPosition);
341
 
                }
342
 
        }
343
 
        
344
 
        CD_APPLET_LEAVE ();
345
 
}
346
 
 
347
 
static void on_application_icon_changed (DBusGProxy *proxy_watcher, gint iPosition, const gchar *cIconName, const gchar *cIconDesc, GldiModuleInstance *myApplet)
348
 
{
349
 
        CD_APPLET_ENTER;
350
 
        cd_debug ("=== %s (%d, %s, %s)", __func__, iPosition, cIconName, cIconDesc);
351
 
        
352
 
        CDStatusNotifierItem *pItem = cd_satus_notifier_find_item_from_position (iPosition);
353
 
        g_return_if_fail (pItem != NULL);
354
 
        
355
 
        if (g_strcmp0 (pItem->cIconName, cIconName) == 0)  // discard useless updates (skype...)
356
 
                return;
357
 
        g_free (pItem->cIconName);
358
 
        pItem->cIconName = g_strdup (cIconName);
359
 
        g_free (pItem->cAccessibleDesc);
360
 
        pItem->cAccessibleDesc = g_strdup (cIconDesc);
361
 
        
362
 
        if (pItem->iStatus != CD_STATUS_NEEDS_ATTENTION)
363
 
        {
364
 
                cd_satus_notifier_update_item_image (pItem);
365
 
        }
366
 
        
367
 
        CD_APPLET_LEAVE ();
368
 
}
369
 
 
370
 
static void on_application_icon_theme_path_changed (DBusGProxy *proxy_watcher, gint iPosition, const gchar *cIconThemePath, GldiModuleInstance *myApplet)
371
 
{
372
 
        CD_APPLET_ENTER;
373
 
        cd_debug ("=== %s (%d, %s)", __func__, iPosition, cIconThemePath);
374
 
        
375
 
        CDStatusNotifierItem *pItem = cd_satus_notifier_find_item_from_position (iPosition);
376
 
        g_return_if_fail (pItem != NULL);
377
 
        
378
 
        if (g_strcmp0 (cIconThemePath, pItem->cIconThemePath) != 0)
379
 
        {
380
 
                if (pItem->cIconThemePath != NULL)  // if the item previously provided a theme, remove it first.
381
 
                        cd_satus_notifier_remove_theme_path (pItem->cIconThemePath);
382
 
                g_free (pItem->cIconThemePath);
383
 
                pItem->cIconThemePath = g_strdup (cIconThemePath);
384
 
                
385
 
                cd_satus_notifier_add_theme_path (cIconThemePath);  // and add the new one.
386
 
                
387
 
                if (pItem->cIconName != NULL)
388
 
                {
389
 
                        cd_satus_notifier_update_item_image (pItem);
390
 
                }
391
 
        }
392
 
        CD_APPLET_LEAVE ();
393
 
}
394
 
 
395
 
static void on_application_label_changed (DBusGProxy *proxy_watcher, gint iPosition, const gchar *cLabel, const gchar *cLabelGuide, GldiModuleInstance *myApplet)
396
 
{
397
 
        CD_APPLET_ENTER;
398
 
        cd_debug ("=== %s (%d, %s, %s)", __func__, iPosition, cLabel, cLabelGuide);
399
 
        
400
 
        CDStatusNotifierItem *pItem = cd_satus_notifier_find_item_from_position (iPosition);
401
 
        g_return_if_fail (pItem != NULL);
402
 
        
403
 
        g_free (pItem->cLabel);
404
 
        pItem->cLabel = g_strdup (cLabel);
405
 
        g_free (pItem->cLabelGuide);
406
 
        pItem->cLabelGuide = g_strdup (cLabelGuide);
407
 
        
408
 
        CD_APPLET_LEAVE ();
409
 
}
410
 
 
411
 
static void on_application_title_changed (DBusGProxy *proxy_watcher, gint iPosition, const gchar *cTitle, GldiModuleInstance *myApplet)
412
 
{
413
 
        CD_APPLET_ENTER;
414
 
        cd_debug ("=== %s (%d, %s)", __func__, iPosition, cTitle);
415
 
        
416
 
        CDStatusNotifierItem *pItem = cd_satus_notifier_find_item_from_position (iPosition);
417
 
        g_return_if_fail (pItem != NULL);
418
 
        
419
 
        if (cTitle != NULL)
420
 
        {
421
 
                g_free (pItem->cTitle);
422
 
                pItem->cTitle = g_strdup (cTitle);
423
 
        }
424
 
        
425
 
        CD_APPLET_LEAVE ();
426
 
}
427
 
 
428
 
  /////////////////
429
 
 /// Get Items ///
430
 
/////////////////
431
 
 
432
 
static void _on_get_applications_from_service (DBusGProxy *proxy, DBusGProxyCall *call_id, GldiModuleInstance *myApplet)
433
 
{
434
 
        cd_debug ("=== %s ()", __func__);
435
 
        CD_APPLET_ENTER;
436
 
        
437
 
        //\______________________ get the applications list from the service.
438
 
        GPtrArray *pApplications = NULL;
439
 
        GError *erreur = NULL;
440
 
        GType g_type_ptrarray = dbus_g_type_get_collection ("GPtrArray",
441
 
                dbus_g_type_get_struct("GValueArray",
442
 
                        G_TYPE_STRING,  // iconname
443
 
                        G_TYPE_INT,  // position
444
 
                        G_TYPE_STRING,  // dbusaddress
445
 
                        DBUS_TYPE_G_OBJECT_PATH,  // dbusobject
446
 
                        G_TYPE_STRING,  // iconpath
447
 
                        G_TYPE_STRING,  // label
448
 
                        G_TYPE_STRING,  // labelguide
449
 
                        #if (INDICATOR_OLD_NAMES == 0)  // Natty
450
 
                        G_TYPE_STRING,  // accessibledesc
451
 
                        #if (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
452
 
                        G_TYPE_STRING,  // hint
453
 
                        #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
454
 
                        G_TYPE_STRING,  // title
455
 
                        #endif
456
 
                        #endif
457
 
                        #endif
458
 
                        G_TYPE_INVALID));
459
 
        dbus_g_proxy_end_call (proxy,
460
 
                call_id,
461
 
                &erreur,
462
 
                g_type_ptrarray, &pApplications,
463
 
                G_TYPE_INVALID);
464
 
        if (erreur != NULL)
465
 
        {
466
 
                cd_debug ("=== couldn't get applications in the systray (%s)", erreur->message);
467
 
                g_error_free (erreur);
468
 
                erreur = NULL;
469
 
        }
470
 
        if (pApplications == NULL)
471
 
                CD_APPLET_LEAVE ();
472
 
        
473
 
        //\______________________ build each items.
474
 
        cd_debug ("=== got %d applications", pApplications->len);
475
 
        guint i;
476
 
        GValueArray *va;
477
 
        GValue *v;
478
 
        CDStatusNotifierItem *pItem = NULL;
479
 
        //cd_debug ("=== %d apps in the systray", pApplications->len);
480
 
        for (i = 0; i < pApplications->len; i ++)
481
 
        {
482
 
                // get the properties of the item
483
 
                cd_debug ("=== %d) %p", i, pApplications->pdata[i]);
484
 
                va = pApplications->pdata[i];
485
 
                if (! va)
486
 
                        continue;
487
 
                
488
 
                const gchar *cIconName = NULL;
489
 
                gint iPosition = -1;
490
 
                const gchar *cAddress = NULL;
491
 
                const gchar *cObjectPath = NULL;
492
 
                const gchar *cIconThemePath = NULL;
493
 
                const gchar *cLabel = NULL;
494
 
                const gchar *cLabelGuide = NULL;
495
 
                const gchar *cAccessibleDesc = NULL; // natty
496
 
                // const gchar *cHint = NULL; // oneiric
497
 
                const gchar *cTitle = NULL;  // precise
498
 
                
499
 
                v = g_value_array_get_nth (va, 0);  // GValueArray is deprecated from 2.32, yet it's so convenient to map the g_type_ptrarray type ...
500
 
                if (v && G_VALUE_HOLDS_STRING (v))
501
 
                        cIconName = g_value_get_string (v);
502
 
                
503
 
                v = g_value_array_get_nth (va, 1);
504
 
                if (v && G_VALUE_HOLDS_INT (v))
505
 
                        iPosition = g_value_get_int (v);
506
 
                
507
 
                v = g_value_array_get_nth (va, 2);
508
 
                if (v && G_VALUE_HOLDS_STRING (v))
509
 
                        cAddress = g_value_get_string (v);
510
 
                
511
 
                v = g_value_array_get_nth (va, 3);
512
 
                if (v && G_VALUE_HOLDS (v, DBUS_TYPE_G_OBJECT_PATH))
513
 
                        cObjectPath = (gchar*)g_value_get_boxed (v);
514
 
 
515
 
                v = g_value_array_get_nth (va, 4);
516
 
                if (v && G_VALUE_HOLDS_STRING (v))
517
 
                        cIconThemePath = g_value_get_string (v);
518
 
                
519
 
                v = g_value_array_get_nth (va, 5);
520
 
                if (v && G_VALUE_HOLDS_STRING (v))
521
 
                        cLabel = g_value_get_string (v);
522
 
                
523
 
                v = g_value_array_get_nth (va, 6);
524
 
                if (v && G_VALUE_HOLDS_STRING (v))
525
 
                        cLabelGuide = g_value_get_string (v);
526
 
                
527
 
                #if (INDICATOR_OLD_NAMES == 0)
528
 
                v = g_value_array_get_nth (va, 7);
529
 
                if (v && G_VALUE_HOLDS_STRING (v))
530
 
                        cAccessibleDesc = g_value_get_string (v);
531
 
                
532
 
                #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
533
 
                v = g_value_array_get_nth (va, 9);
534
 
                if (v && G_VALUE_HOLDS_STRING (v))
535
 
                        cTitle = g_value_get_string (v);
536
 
                #endif
537
 
                #endif
538
 
                
539
 
                cd_debug ("===  + item {%s ; %d ; %s ; %s ; %s ; %s ; %s ; %s ; %s}",
540
 
                        cIconName,
541
 
                        iPosition,
542
 
                        cAddress,
543
 
                        cObjectPath,
544
 
                        cIconThemePath,
545
 
                        cLabel,
546
 
                        cLabelGuide,
547
 
                        cAccessibleDesc,
548
 
                        cTitle);
549
 
                
550
 
                if (!cAddress)
551
 
                        continue;
552
 
                
553
 
                // ensure we're not duplicating an existing item (this should never happen if the service is ok, but since it doesn't depend on us, let's be careful).
554
 
                GList *it;
555
 
                for (it = myData.pItems; it != NULL; it = it->next)
556
 
                {
557
 
                        pItem = it->data;
558
 
                        if (strcmp (cAddress, pItem->cService) == 0)  // pItem->cService is never NULL
559
 
                        {
560
 
                                cd_warning ("Duplicated item: %s (%s)", cIconName, cAddress);
561
 
                                return;
562
 
                        }
563
 
                        if (iPosition != -1 && pItem->iPosition == iPosition)
564
 
                        {
565
 
                                cd_warning ("Possible duplicated item: %s/%s/%d , %s/%s/%d)", cIconName, cAddress, iPosition, pItem->cIconName, pItem->cService, pItem->iPosition);
566
 
                        }
567
 
                }
568
 
                
569
 
                // make a new item based on these properties.
570
 
                pItem = cd_satus_notifier_create_item (cAddress, cObjectPath);
571
 
                if (! pItem)
572
 
                        continue;
573
 
                if (pItem->iPosition == -1)
574
 
                        pItem->iPosition = iPosition;
575
 
                if (pItem->cTitle == NULL && pItem->cLabel == NULL && pItem->cAccessibleDesc == NULL)
576
 
                        pItem->cLabel = g_strdup (cAccessibleDesc && *cAccessibleDesc != '\0' ? cAccessibleDesc :
577
 
                                                  cLabel && *cLabel != '\0' ? cLabel :
578
 
                                                  cTitle && *cTitle != '\0' ? cTitle :
579
 
                                                  NULL);  // don't use cId as a fallback, because it often has cryptic names (nm-applet ; dropbox-xxxx). If the appli doesn't provide a title, it's its fault.
580
 
        }
581
 
        
582
 
        if (myConfig.bCompactMode)
583
 
        {
584
 
                cd_satus_notifier_reload_compact_mode ();
585
 
        }
586
 
        else
587
 
        {
588
 
                cd_satus_notifier_load_icons_from_items ();
589
 
        }
590
 
        
591
 
        g_ptr_array_free (pApplications, TRUE);
592
 
        CD_APPLET_LEAVE ();
593
 
}
594
 
 
595
 
void cd_satus_notifier_get_items_from_ias (void)
596
 
{
597
 
        if (! myData.bIASWatched)
598
 
                return;
599
 
        cd_debug ("=== %s ()", __func__);
600
 
        
601
 
        g_return_if_fail (myData.pProxyIndicatorApplicationService == NULL);
602
 
        
603
 
        myData.pProxyIndicatorApplicationService = cairo_dock_create_new_session_proxy (
604
 
                CD_INDICATOR_APPLICATION_ADDR,
605
 
                CD_INDICATOR_APPLICATION_OBJ,
606
 
                CD_INDICATOR_APPLICATION_IFACE);
607
 
        
608
 
        // get the current items
609
 
        dbus_g_proxy_begin_call (myData.pProxyIndicatorApplicationService,
610
 
                "GetApplications",
611
 
                (DBusGProxyCallNotify)_on_get_applications_from_service,
612
 
                myApplet,
613
 
                (GDestroyNotify) NULL,
614
 
                G_TYPE_INVALID);
615
 
        
616
 
        // connect to the signals to keep the list of items up-to-date.
617
 
        #if (INDICATOR_OLD_NAMES != 0)  // Maverick
618
 
        dbus_g_object_register_marshaller(_cd_cclosure_marshal_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING,
619
 
                        G_TYPE_NONE, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
620
 
        #else  // Natty
621
 
        dbus_g_object_register_marshaller(
622
 
        #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
623
 
        _cd_cclosure_marshal_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING_STRING_STRING,
624
 
        #elif (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
625
 
        _cd_cclosure_marshal_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING_STRING,
626
 
        #else
627
 
        _cd_cclosure_marshal_VOID__STRING_INT_STRING_STRING_STRING_STRING_STRING_STRING,
628
 
        #endif
629
 
                        G_TYPE_NONE, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING,
630
 
                        DBUS_TYPE_G_OBJECT_PATH,  // dbusobject
631
 
                        G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
632
 
                        #if (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
633
 
                        G_TYPE_STRING,
634
 
                        #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
635
 
                        G_TYPE_STRING,
636
 
                        #endif
637
 
                        #endif
638
 
                        G_TYPE_INVALID);
639
 
        #endif
640
 
        dbus_g_proxy_add_signal(myData.pProxyIndicatorApplicationService, "ApplicationAdded",
641
 
                G_TYPE_STRING,  // iconname
642
 
                G_TYPE_INT,  // position
643
 
                G_TYPE_STRING,  // dbusaddress
644
 
                #if (INDICATOR_OLD_NAMES != 0)  // Maverick
645
 
                G_TYPE_STRING,  // dbusobject
646
 
                #else  // Natty
647
 
                DBUS_TYPE_G_OBJECT_PATH,  // dbusobject
648
 
                #endif
649
 
                G_TYPE_STRING,  // iconpath
650
 
                G_TYPE_STRING,  // label
651
 
                G_TYPE_STRING,  // labelguide
652
 
                #if (INDICATOR_OLD_NAMES == 0)  // Natty
653
 
                G_TYPE_STRING,  // accessibledesc
654
 
                #if (INDICATOR_APPLICATIONADDED_HAS_HINT == 1)
655
 
                G_TYPE_STRING, // hint => only with indicator-0.4 (Oneiric)
656
 
                #if (INDICATOR_APPLICATIONADDED_HAS_TITLE == 1)
657
 
                G_TYPE_STRING, // title => only with indicator-0.4.90 (Precise)
658
 
                #endif
659
 
                #endif
660
 
                #endif
661
 
                G_TYPE_INVALID);
662
 
        dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationAdded",
663
 
                G_CALLBACK(on_new_application), myApplet, NULL);
664
 
        
665
 
        dbus_g_proxy_add_signal(myData.pProxyIndicatorApplicationService, "ApplicationRemoved",
666
 
                G_TYPE_INT,  // position
667
 
                G_TYPE_INVALID);
668
 
        dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationRemoved",
669
 
                G_CALLBACK(on_removed_application), myApplet, NULL);
670
 
        
671
 
        // we add the following signals because some program don't support the StatusNotifier API (skype, once again...) but only the IAS one.
672
 
        dbus_g_object_register_marshaller(_cd_cclosure_marshal_VOID__INT_STRING_STRING,
673
 
                        G_TYPE_NONE, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
674
 
        dbus_g_proxy_add_signal(myData.pProxyIndicatorApplicationService, "ApplicationIconChanged",
675
 
                G_TYPE_INT,  // position
676
 
                G_TYPE_STRING,  // icon name
677
 
                G_TYPE_STRING,  // icon desc (?)
678
 
                G_TYPE_INVALID);
679
 
        dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationIconChanged",
680
 
                G_CALLBACK(on_application_icon_changed), myApplet, NULL);
681
 
        
682
 
        dbus_g_object_register_marshaller(_cd_cclosure_marshal_VOID__INT_STRING,
683
 
                        G_TYPE_NONE, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID);
684
 
        dbus_g_proxy_add_signal(myData.pProxyIndicatorApplicationService, "ApplicationIconThemePathChanged",
685
 
                G_TYPE_INT,  // position
686
 
                G_TYPE_STRING,  // icon name
687
 
                G_TYPE_STRING,  // icon desc (Note: I'm quite sure they will eventually remove it ...)
688
 
                G_TYPE_INVALID);
689
 
        dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationIconThemePathChanged",
690
 
                G_CALLBACK(on_application_icon_theme_path_changed), myApplet, NULL);
691
 
        
692
 
        dbus_g_proxy_add_signal(myData.pProxyIndicatorApplicationService, "ApplicationLabelChanged",
693
 
                G_TYPE_INT,  // position
694
 
                G_TYPE_STRING,  // label
695
 
                G_TYPE_STRING,  // guide
696
 
                G_TYPE_INVALID);
697
 
        dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationLabelChanged",
698
 
                G_CALLBACK(on_application_label_changed), myApplet, NULL);
699
 
        
700
 
        dbus_g_proxy_add_signal(myData.pProxyIndicatorApplicationService, "ApplicationTitleChanged",
701
 
                G_TYPE_INT,  // position
702
 
                G_TYPE_STRING,  // title
703
 
                G_TYPE_INVALID);
704
 
        dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationTitleChanged",
705
 
                G_CALLBACK(on_application_title_changed), myApplet, NULL);
706
 
}
707
 
 
708
 
  //////////////////
709
 
 /// Connection ///
710
 
//////////////////
711
 
 
712
 
static void _on_start_service (DBusGProxy *proxy, guint status, GError *error, gpointer data)
713
 
{
714
 
        // if service has not started, then we'll assume we don't need it (eg.: KDE)
715
 
        if (status != DBUS_START_REPLY_SUCCESS && status != DBUS_START_REPLY_ALREADY_RUNNING)  // service is not started.
716
 
        {
717
 
                if (error != NULL)  // couldn't start the service
718
 
                        cd_debug ("=== Unable to start the indicator service (%s), assuming we don't need it", error->message);
719
 
                else
720
 
                        cd_debug ("=== Unable to start the indicator service (got status %d), assuming we don't need it", status);
721
 
                myData.bNoIAS = TRUE;
722
 
                cd_satus_notifier_launch_our_watcher ();
723
 
                return;
724
 
        }
725
 
        cd_debug ("=== Indicator Service has started");
726
 
}
727
 
static void _on_watch_service (DBusGProxy *proxy, DBusGProxyCall *call, gpointer data)
728
 
{
729
 
        CD_APPLET_ENTER;
730
 
        GError *error = NULL;
731
 
        guint service_api_version=0, this_service_version=0;
732
 
        dbus_g_proxy_end_call (proxy, call, &error,
733
 
                G_TYPE_UINT, &service_api_version,
734
 
                G_TYPE_UINT, &this_service_version,
735
 
                G_TYPE_INVALID);
736
 
        if (error != NULL)
737
 
        {
738
 
                cd_debug ("Unable to watch the service: %s", error->message);
739
 
                g_error_free (error);
740
 
                /* Note: Not a big deal, let start getting items: it seems that the
741
 
                 * service is no longer available and *no longer needed* on Ubuntu 14.04
742
 
                 *  https://bazaar.launchpad.net/~indicator-applet-developers/indicator-application/trunk.14.04/revision/246
743
 
                 *  https://bugs.launchpad.net/bugs/1303731
744
 
                 * TODO: remove this ugly hack...
745
 
                 */
746
 
                #if (INDICATOR_OLD_NAMES == 0)
747
 
                service_api_version = 1;
748
 
                #endif
749
 
        }
750
 
        cd_debug ("=== got indicator service (API: %d, service: %d, broken watcher: %d)", service_api_version, this_service_version, myData.bBrokenWatcher);
751
 
        
752
 
        if (service_api_version > 0)  /// shouldn't the 2 versions be equal ?...
753
 
        {
754
 
                myData.bIASWatched = TRUE;  // now we're friend with the IAS
755
 
                
756
 
                if (myData.bBrokenWatcher)  // if the watcher is not our friend, let's ask the IAS the current items.
757
 
                {
758
 
                        cd_satus_notifier_get_items_from_ias ();
759
 
                }
760
 
        }
761
 
        CD_APPLET_LEAVE ();
762
 
}
763
 
static void _on_ias_owner_changed (const gchar *cName, gboolean bOwned, gpointer data)
764
 
{
765
 
        CD_APPLET_ENTER;
766
 
        cd_debug ("=== Indicator Applications Service is on the bus (%d)", bOwned);
767
 
        
768
 
        if (bOwned)
769
 
        {
770
 
                myData.bNoIAS = FALSE;
771
 
                // set up a proxy to the Service
772
 
                myData.pProxyIndicatorService = cairo_dock_create_new_session_proxy (
773
 
                        CD_INDICATOR_APPLICATION_ADDR,
774
 
                        CD_INDICATOR_SERVICE_OBJECT,
775
 
                        CD_INDICATOR_SERVICE_INTERFACE);
776
 
                
777
 
                // and watch it.
778
 
                cd_debug ("=== watch it");
779
 
                dbus_g_proxy_begin_call (myData.pProxyIndicatorService,
780
 
                        "Watch",
781
 
                        (DBusGProxyCallNotify)_on_watch_service,
782
 
                        myApplet,
783
 
                        (GDestroyNotify) NULL,
784
 
                        G_TYPE_INVALID);
785
 
        }
786
 
        else  // no more IAS on the bus.
787
 
        {
788
 
                g_object_unref (myData.pProxyIndicatorService);
789
 
                myData.pProxyIndicatorService = NULL;
790
 
                
791
 
                g_object_unref (myData.pProxyIndicatorApplicationService);
792
 
                myData.pProxyIndicatorApplicationService = NULL;
793
 
                
794
 
                myData.bIASWatched = FALSE;
795
 
                
796
 
                myData.bNoIAS = TRUE;
797
 
                cd_satus_notifier_launch_our_watcher ();
798
 
        }
799
 
        CD_APPLET_LEAVE ();
800
 
}
801
 
static void _on_detect_ias (gboolean bPresent, gpointer data)
802
 
{
803
 
        CD_APPLET_ENTER;
804
 
        cd_debug ("=== Indicator Applications Service is present: %d", bPresent);
805
 
        s_pDetectIASCall = NULL;
806
 
        // if present, set up proxy, else try to start the service.
807
 
        if (bPresent)
808
 
        {
809
 
                _on_ias_owner_changed (CD_INDICATOR_APPLICATION_ADDR, TRUE, NULL);
810
 
        }
811
 
        else  // not present, maybe the service is not started => try starting it.
812
 
        {
813
 
                cd_debug ("=== try to start the Indicator Service...");
814
 
                DBusGProxy *dbus_proxy = cairo_dock_get_main_proxy ();
815
 
                org_freedesktop_DBus_start_service_by_name_async (dbus_proxy,
816
 
                        CD_INDICATOR_APPLICATION_ADDR,
817
 
                        0,
818
 
                        _on_start_service,
819
 
                        myApplet);
820
 
        }
821
 
        // watch whenever the Service goes up or down.
822
 
        cairo_dock_watch_dbus_name_owner (CD_INDICATOR_APPLICATION_ADDR,
823
 
                (CairoDockDbusNameOwnerChangedFunc) _on_ias_owner_changed,
824
 
                NULL);
825
 
        CD_APPLET_LEAVE ();
826
 
}
827
 
 
828
 
 
829
 
void cd_satus_notifier_detect_ias (void)
830
 
{
831
 
        s_pDetectIASCall = cairo_dock_dbus_detect_application_async (CD_INDICATOR_APPLICATION_ADDR,
832
 
                (CairoDockOnAppliPresentOnDbus) _on_detect_ias,
833
 
                NULL);
834
 
}
835
 
 
836
 
 
837
 
void cd_satus_notifier_unregister_from_ias (void)
838
 
{
839
 
        if (myData.pProxyIndicatorApplicationService != NULL)
840
 
        {
841
 
                g_object_unref (myData.pProxyIndicatorApplicationService);
842
 
                g_object_unref (myData.pProxyIndicatorService);
843
 
        }
844
 
        
845
 
        if (s_pDetectIASCall != NULL)
846
 
        {
847
 
                DBusGProxy *pProxy = cairo_dock_get_main_proxy ();
848
 
                dbus_g_proxy_cancel_call (pProxy, s_pDetectIASCall);
849
 
                s_pDetectIASCall = NULL;
850
 
        }
851
 
        
852
 
        cairo_dock_stop_watching_dbus_name_owner (CD_INDICATOR_APPLICATION_ADDR,
853
 
                (CairoDockDbusNameOwnerChangedFunc) _on_ias_owner_changed);
854
 
}