~ubuntu-branches/ubuntu/utopic/cairo-dock-plug-ins/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/bzr3070_Status-Notifier_workaround_was_broken_due_to_DBus_API_change.patch/Status-Notifier/src/applet-host-ias.c

  • Committer: Matthieu Baerts
  • Date: 2014-04-08 22:00:47 UTC
  • Revision ID: matttbe@gmail.com-20140408220047-aj0h18w8tk9tcq9t
Tags: 3.3.99.beta1.2.really.3.3.2-0ubuntu2
* debian/patches/bzr3070_Status-Notifier_workaround_was_broken_due_to_
  DBus_API_change.patch:
  - Status-Notifier was broken on Ubuntu 14.04 due to a DBus API change
    in Indicator-Application (LP: #1303731)

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