~charlesk/indicator-sync/lp-1051798

« back to all changes in this revision

Viewing changes to indicator-sync/sync-service.c

  • Committer: Charles Kerr
  • Date: 2012-08-22 07:07:49 UTC
  • mfrom: (0.1.21 trunk)
  • Revision ID: charles.kerr@canonical.com-20120822070749-76lc1uqz2muybc16
merge lp:~charlesk/indicator-sync/initial-impl for the initial implementation

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   A service which aggregates all the SyncClients' data together
 
3
   for consumption by the Sync Indicator
 
4
 
 
5
   Copyright 2012 Canonical Ltd.
 
6
 
 
7
   Authors:
 
8
     Charles Kerr <charles.kerr@canonical.com>
 
9
 
 
10
   This program is free software: you can redistribute it and/or modify it 
 
11
   under the terms of the GNU General Public License version 3,
 
12
   as published by the Free Software Foundation.
 
13
 
 
14
   This program is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranties of
 
16
   MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
 
17
   See the GNU General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU General Public License along 
 
20
   with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
*/
 
22
 
 
23
#ifdef HAVE_CONFIG_H
 
24
 #include "config.h"
 
25
#endif
 
26
 
 
27
#include <locale.h>
 
28
#include <libintl.h>
 
29
 
 
30
#include <gio/gio.h>
 
31
#include <glib/gi18n.h>
 
32
 
 
33
#include <libdbusmenu-glib/client.h>
 
34
#include <libdbusmenu-glib/menuitem.h>
 
35
#include <libdbusmenu-glib/server.h>
 
36
 
 
37
#include <libindicator/indicator-service.h>
 
38
 
 
39
#include "app-menu-item.h"
 
40
#include "dbus-shared.h"
 
41
#include "sync-client.h"
 
42
#include "sync-client-dbus.h"
 
43
#include "sync-enum.h"
 
44
#include "sync-service-dbus.h"
 
45
 
 
46
/***
 
47
****
 
48
***/
 
49
 
 
50
/* bookkeeping for each SyncClient */
 
51
typedef struct ClientEntry
 
52
{
 
53
  gint watch_id;
 
54
 
 
55
  AppMenuItem * app_menu_item;
 
56
 
 
57
  DbusmenuClient * menu_client;
 
58
  gulong menu_client_root_handler_id;
 
59
 
 
60
  DbusSyncClient * sync_client;
 
61
  gulong sync_client_menu_handler_id;
 
62
  gulong sync_client_state_handler_id;
 
63
  gulong sync_client_paused_handler_id;
 
64
}
 
65
ClientEntry;
 
66
 
 
67
/* the main service struct */
 
68
typedef struct SyncService
 
69
{
 
70
  GMainLoop * mainloop;
 
71
 
 
72
  IndicatorService * indicator_service;
 
73
  DbusmenuServer * menu_server;
 
74
  DbusSyncService * skeleton;
 
75
  guint signal_subscription;
 
76
 
 
77
  GSList * client_entries;
 
78
}
 
79
SyncService;
 
80
 
 
81
static SyncService sync_service;
 
82
 
 
83
static void entry_clear_menu_client (ClientEntry * entry);
 
84
 
 
85
 
 
86
/****
 
87
*****  Various ways to look up a ClientEntry
 
88
****/
 
89
 
 
90
typedef gint (entry_compare_func)(const ClientEntry * entry, gconstpointer key);
 
91
 
 
92
static gint
 
93
entry_compare_to_object_path (const ClientEntry * entry, gconstpointer path)
 
94
{
 
95
  GDBusProxy * proxy = G_DBUS_PROXY (entry->sync_client);
 
96
 
 
97
  return g_strcmp0 (g_dbus_proxy_get_object_path(proxy), path);
 
98
}
 
99
static gint
 
100
entry_compare_to_dbus_name (const ClientEntry * entry, gconstpointer name)
 
101
{
 
102
  GDBusProxy * proxy = G_DBUS_PROXY (entry->sync_client);
 
103
 
 
104
  return g_strcmp0 (g_dbus_proxy_get_name(proxy), name);
 
105
}
 
106
static gint
 
107
entry_compare_to_menu_client (const ClientEntry * entry, gconstpointer client)
 
108
{
 
109
  const ptrdiff_t diff = (gconstpointer)(entry->menu_client) - client;
 
110
  if (diff < 0) return -1;
 
111
  if (diff > 0) return  1;
 
112
  return 0;
 
113
}
 
114
 
 
115
struct name_and_path
 
116
{
 
117
  const gchar * name;
 
118
  const gchar * path;
 
119
};
 
120
 
 
121
static gint
 
122
entry_compare_to_name_and_path (const ClientEntry * entry, gconstpointer key)
 
123
{
 
124
  int i;
 
125
  const struct name_and_path * nap = key;
 
126
 
 
127
  /* primary key */
 
128
  if (( i = entry_compare_to_dbus_name (entry, nap->name)))
 
129
    return i;
 
130
 
 
131
  /* secondary key */
 
132
  return entry_compare_to_object_path (entry, nap->path);
 
133
}
 
134
 
 
135
static ClientEntry *
 
136
entry_find (SyncService * service, entry_compare_func func, gconstpointer key)
 
137
{
 
138
  GSList * l;
 
139
  ClientEntry * match = NULL;
 
140
 
 
141
  for (l=service->client_entries; l!=NULL; l=l->next)
 
142
    {
 
143
      if (func (l->data, key) == 0)
 
144
        {
 
145
          match = l->data;
 
146
          break;
 
147
        }
 
148
    }
 
149
 
 
150
  return match;
 
151
}
 
152
static ClientEntry *
 
153
entry_find_from_dbus_name (SyncService * service, const gchar * name)
 
154
{
 
155
  return entry_find (service, entry_compare_to_dbus_name, name);
 
156
}
 
157
static ClientEntry *
 
158
entry_find_from_menu_client (SyncService * service, DbusmenuClient * client)
 
159
{
 
160
  return entry_find (service, entry_compare_to_menu_client, client);
 
161
}
 
162
static ClientEntry *
 
163
entry_find_from_name_and_path (SyncService  * service,
 
164
                               const gchar  * name,
 
165
                               const gchar  * path)
 
166
{
 
167
  struct name_and_path nap;
 
168
  nap.name = name;
 
169
  nap.path = path;
 
170
  return entry_find (service, entry_compare_to_name_and_path, &nap);
 
171
}
 
172
 
 
173
static gint
 
174
entry_compare_by_appname (gconstpointer ga, gconstpointer gb)
 
175
{
 
176
  const ClientEntry * const a = ga;
 
177
  const ClientEntry * const b = gb;
 
178
  return g_strcmp0 (app_menu_item_get_name(a->app_menu_item),
 
179
                    app_menu_item_get_name(b->app_menu_item));
 
180
}
 
181
 
 
182
static SyncState
 
183
entry_get_state (ClientEntry * entry)
 
184
{
 
185
  g_return_val_if_fail (entry->sync_client != NULL, SYNC_STATE_IDLE);
 
186
 
 
187
  return dbus_sync_client_get_state (entry->sync_client);
 
188
}
 
189
 
 
190
static gboolean
 
191
entry_get_paused (ClientEntry * entry)
 
192
{
 
193
  g_return_val_if_fail (entry->sync_client != NULL, FALSE);
 
194
 
 
195
  return dbus_sync_client_get_paused (entry->sync_client);
 
196
}
 
197
 
 
198
 
 
199
/****
 
200
*****
 
201
****/
 
202
 
 
203
static inline void
 
204
menuitem_set_visible (DbusmenuMenuitem * mi, gboolean v)
 
205
{
 
206
  dbusmenu_menuitem_property_set_bool (mi, DBUSMENU_MENUITEM_PROP_VISIBLE, v);
 
207
}
 
208
 
 
209
static void
 
210
menuitem_unparent (DbusmenuMenuitem * mi)
 
211
{
 
212
  DbusmenuMenuitem * parent = dbusmenu_menuitem_get_parent (mi);
 
213
  if (parent != NULL)
 
214
    {
 
215
      dbusmenu_menuitem_child_delete (parent, mi);
 
216
    }
 
217
}
 
218
 
 
219
static void
 
220
service_menu_append_client_menu (DbusmenuMenuitem  * root,
 
221
                                 DbusmenuClient    * menu_client)
 
222
{
 
223
  g_return_if_fail (menu_client != NULL);
 
224
 
 
225
  DbusmenuMenuitem * mi = dbusmenu_client_get_root (menu_client);
 
226
  if (mi != NULL)
 
227
    {
 
228
      GList * l;
 
229
      GList * children = dbusmenu_menuitem_get_children (mi);
 
230
      if (children == NULL)
 
231
        {
 
232
          mi = DBUSMENU_MENUITEM(dbusmenu_menuitem_proxy_new (mi));
 
233
          dbusmenu_menuitem_child_append (root, mi);
 
234
        }
 
235
      else for (l=children; l!=NULL; l=l->next)
 
236
        {
 
237
          mi = DBUSMENU_MENUITEM(l->data);
 
238
          mi = DBUSMENU_MENUITEM(dbusmenu_menuitem_proxy_new (mi));
 
239
          dbusmenu_menuitem_child_append (root, mi);
 
240
        }
 
241
    }
 
242
}
 
243
 
 
244
static void
 
245
service_refresh_menu (SyncService * service)
 
246
{
 
247
  GSList * l;
 
248
  GSList * entries;
 
249
  g_debug (G_STRLOC" rebuilding the menu");
 
250
 
 
251
  /* get an alphabetically sorted list of SyncClients */
 
252
  entries = g_slist_copy (service->client_entries);
 
253
  entries = g_slist_sort (entries, entry_compare_by_appname);
 
254
 
 
255
  /* build the new menu */
 
256
  DbusmenuMenuitem * root = dbusmenu_menuitem_new ();
 
257
  for (l=entries; l!=NULL; l=l->next)
 
258
    {
 
259
      ClientEntry * entry = l->data;
 
260
 
 
261
      /* add the client's app menuitem */
 
262
      DbusmenuMenuitem * mi = DBUSMENU_MENUITEM (entry->app_menu_item);
 
263
      menuitem_unparent (mi);
 
264
      menuitem_set_visible (mi, TRUE);
 
265
      dbusmenu_menuitem_child_append (root, mi);
 
266
 
 
267
      /* add the client's custom menuitems */
 
268
      service_menu_append_client_menu (root, entry->menu_client);
 
269
 
 
270
      /* add a separator before the next client */
 
271
      if (l->next != NULL)
 
272
        {
 
273
          DbusmenuMenuitem * sep = dbusmenu_menuitem_new ();
 
274
          menuitem_set_visible (mi, TRUE);
 
275
          dbusmenu_menuitem_property_set (sep,
 
276
                                          DBUSMENU_MENUITEM_PROP_TYPE,
 
277
                                          DBUSMENU_CLIENT_TYPES_SEPARATOR);
 
278
          dbusmenu_menuitem_child_append (root, sep);
 
279
        }
 
280
    }
 
281
 
 
282
  dbusmenu_server_set_root (service->menu_server, root);
 
283
 
 
284
  /* cleanup */
 
285
  g_slist_free (entries);
 
286
  g_object_unref (root);
 
287
}
 
288
 
 
289
static SyncState
 
290
service_calculate_state (SyncService * service)
 
291
{
 
292
  GSList * l;
 
293
 
 
294
  /* if any service is in error state... */
 
295
  for (l=service->client_entries; l!=NULL; l=l->next)
 
296
    if (entry_get_state (l->data) == SYNC_STATE_ERROR)
 
297
      return SYNC_STATE_ERROR;
 
298
 
 
299
  /* otherwise if any service is syncing... */
 
300
  for (l=service->client_entries; l!=NULL; l=l->next)
 
301
    if (entry_get_state (l->data) == SYNC_STATE_SYNCING)
 
302
      return SYNC_STATE_SYNCING;
 
303
 
 
304
  return SYNC_STATE_IDLE;
 
305
}
 
306
 
 
307
static void
 
308
service_refresh_state (SyncService * service)
 
309
{
 
310
  const SyncState new_state = service_calculate_state (service);
 
311
 
 
312
  dbus_sync_service_set_state (service->skeleton, new_state);
 
313
}
 
314
 
 
315
static gboolean
 
316
service_calculate_paused (SyncService * service)
 
317
{
 
318
  GSList * l;
 
319
 
 
320
  for (l=service->client_entries; l!=NULL; l=l->next)
 
321
    if (entry_get_paused (l->data))
 
322
      return TRUE;
 
323
 
 
324
  return FALSE;
 
325
}
 
326
 
 
327
static void
 
328
service_refresh_paused (SyncService * service)
 
329
{
 
330
  const gboolean new_paused = service_calculate_paused (service);
 
331
 
 
332
  dbus_sync_service_set_paused (service->skeleton, new_paused);
 
333
}
 
334
 
 
335
static void
 
336
service_refresh_count (SyncService * service)
 
337
{
 
338
  const guint new_count = g_slist_length (service->client_entries);
 
339
 
 
340
  dbus_sync_service_set_client_count (service->skeleton, new_count);
 
341
}
 
342
 
 
343
static void
 
344
service_refresh (SyncService * service)
 
345
{
 
346
  service_refresh_menu (service);
 
347
  service_refresh_state (service);
 
348
  service_refresh_paused (service);
 
349
  service_refresh_count (service);
 
350
}
 
351
 
 
352
/****
 
353
*****
 
354
****/
 
355
 
 
356
static void
 
357
signal_handler_clear (gpointer instance, gulong * handler_id)
 
358
{
 
359
  g_return_if_fail (handler_id != NULL);
 
360
 
 
361
  if ((instance != NULL) && *handler_id)
 
362
    {
 
363
      g_signal_handler_disconnect (instance, *handler_id);
 
364
    }
 
365
 
 
366
  *handler_id = 0;
 
367
}
 
368
 
 
369
static void
 
370
entry_free (ClientEntry * entry)
 
371
{
 
372
  g_debug (G_STRLOC " freeing entry %p", entry);
 
373
 
 
374
  if (entry->watch_id != 0)
 
375
    {
 
376
      g_bus_unwatch_name (entry->watch_id);
 
377
      entry->watch_id = 0;
 
378
    }
 
379
 
 
380
  signal_handler_clear (entry->sync_client, &entry->sync_client_menu_handler_id);
 
381
  signal_handler_clear (entry->sync_client, &entry->sync_client_state_handler_id);
 
382
  signal_handler_clear (entry->sync_client, &entry->sync_client_paused_handler_id);
 
383
  g_clear_object (&entry->sync_client);
 
384
 
 
385
  entry_clear_menu_client (entry);
 
386
 
 
387
  g_free (entry);
 
388
}
 
389
 
 
390
static void
 
391
service_remove_entry (SyncService * service, ClientEntry * entry)
 
392
{
 
393
  g_return_if_fail (service != NULL);
 
394
  g_return_if_fail (entry != NULL);
 
395
 
 
396
  service->client_entries = g_slist_remove (service->client_entries, entry);
 
397
  service_refresh (service);
 
398
 
 
399
  entry_free (entry);
 
400
}
 
401
 
 
402
static void
 
403
service_add_entry (SyncService * service, ClientEntry * entry)
 
404
{
 
405
  service->client_entries = g_slist_prepend (service->client_entries, entry);
 
406
  service_refresh (service);
 
407
}
 
408
 
 
409
static void
 
410
on_client_menu_root_changed (DbusmenuClient    * client,
 
411
                             DbusmenuMenuitem  * newroot     G_GNUC_UNUSED,
 
412
                             gpointer            user_data)
 
413
{
 
414
  SyncService * service = user_data;
 
415
  ClientEntry * entry = entry_find_from_menu_client (service, client);
 
416
  g_return_if_fail (entry != NULL);
 
417
 
 
418
  g_debug (G_STRLOC " SyncClient %s changed its menu root",
 
419
           app_menu_item_get_name(entry->app_menu_item));
 
420
  service_refresh_menu (service);
 
421
}
 
422
 
 
423
static void
 
424
entry_create_menu_client (SyncService * service,
 
425
                          ClientEntry * entry)
 
426
{
 
427
  g_return_if_fail (entry != NULL);
 
428
  g_return_if_fail (entry->sync_client != NULL);
 
429
 
 
430
  const gchar * name = g_dbus_proxy_get_name (G_DBUS_PROXY(entry->sync_client));
 
431
  const gchar * path = dbus_sync_client_get_menu_path (entry->sync_client);
 
432
  entry->menu_client = dbusmenu_client_new (name, path);
 
433
 
 
434
  entry->menu_client_root_handler_id = g_signal_connect (
 
435
                                        entry->menu_client,
 
436
                                        DBUSMENU_CLIENT_SIGNAL_ROOT_CHANGED,
 
437
                                        G_CALLBACK(on_client_menu_root_changed),
 
438
                                        service);
 
439
}
 
440
 
 
441
static void
 
442
entry_clear_menu_client (ClientEntry * entry)
 
443
{
 
444
  signal_handler_clear (entry->menu_client, &entry->menu_client_root_handler_id);
 
445
  g_clear_object (&entry->menu_client);
 
446
}
 
447
 
 
448
static void
 
449
on_sync_client_state_changed (GObject * o, GParamSpec * ps, gpointer service)
 
450
{
 
451
  service_refresh_state (service);
 
452
}
 
453
 
 
454
static void
 
455
on_sync_client_paused_changed (GObject * o, GParamSpec * ps, gpointer service)
 
456
{
 
457
  service_refresh_paused (service);
 
458
}
 
459
 
 
460
static void
 
461
on_sync_client_menu_path_changed (GObject * o, GParamSpec * ps, gpointer gentry)
 
462
{
 
463
  SyncService * service = &sync_service;
 
464
  DbusSyncClient * sync_client = DBUS_SYNC_CLIENT(o);
 
465
  ClientEntry * entry = gentry;
 
466
  g_return_if_fail (sync_client != NULL);
 
467
 
 
468
  entry_clear_menu_client (entry);
 
469
  entry_create_menu_client (service, entry);
 
470
  service_refresh_menu (service);
 
471
}
 
472
 
 
473
static void
 
474
on_sync_client_vanished (GDBusConnection * connection  G_GNUC_UNUSED,
 
475
                         const gchar     * dbus_name,
 
476
                         gpointer          user_data)
 
477
{
 
478
  ClientEntry * entry;
 
479
  SyncService * self = user_data;
 
480
 
 
481
  while ((entry = entry_find_from_dbus_name (self, dbus_name)))
 
482
   {
 
483
     service_remove_entry (self, entry);
 
484
   }
 
485
}
 
486
 
 
487
static ClientEntry *
 
488
entry_new (SyncService * service, DbusSyncClient * sync_client)
 
489
{
 
490
  GDBusProxy * proxy = G_DBUS_PROXY(sync_client);
 
491
  ClientEntry * entry = g_new0 (ClientEntry, 1);
 
492
 
 
493
  entry->sync_client = sync_client;
 
494
 
 
495
  entry->app_menu_item = app_menu_item_new (proxy);
 
496
 
 
497
  entry->sync_client_menu_handler_id = g_signal_connect (
 
498
    proxy, "notify::menu-path",
 
499
    G_CALLBACK(on_sync_client_menu_path_changed), entry);
 
500
 
 
501
  entry->sync_client_state_handler_id = g_signal_connect (
 
502
    proxy, "notify::state",
 
503
    G_CALLBACK(on_sync_client_state_changed), service);
 
504
 
 
505
  entry->sync_client_paused_handler_id = g_signal_connect (
 
506
    proxy, "notify::paused",
 
507
    G_CALLBACK(on_sync_client_paused_changed), service);
 
508
 
 
509
  entry_create_menu_client (service, entry);
 
510
 
 
511
  entry->watch_id = g_bus_watch_name_on_connection (
 
512
    g_dbus_proxy_get_connection (proxy),
 
513
    g_dbus_proxy_get_name (proxy),
 
514
    G_BUS_NAME_WATCHER_FLAGS_NONE,
 
515
    NULL, on_sync_client_vanished,
 
516
    service, NULL);
 
517
 
 
518
  g_debug (G_STRLOC" created a new proxy for '%s', watch id is %d",
 
519
           g_dbus_proxy_get_name(proxy), entry->watch_id);
 
520
 
 
521
  return entry;
 
522
}
 
523
 
 
524
static void
 
525
on_sync_client_exists (GDBusConnection * connection,
 
526
                       const gchar     * sender,
 
527
                       const gchar     * object,
 
528
                       const gchar     * interface,
 
529
                       const gchar     * signal      G_GNUC_UNUSED,
 
530
                       GVariant        * params      G_GNUC_UNUSED,
 
531
                       gpointer          user_data)
 
532
{
 
533
  g_debug (G_STRLOC" got an Exists signal from"
 
534
                   " sender {%s}"
 
535
                   " object {%s}"
 
536
                   " interface {%s}",
 
537
                   sender, object, interface);
 
538
 
 
539
  SyncService * service = user_data;
 
540
 
 
541
  if (entry_find_from_name_and_path (service, sender, object) != NULL)
 
542
    {
 
543
      g_debug (G_STRLOC" ...which we're already tracking");
 
544
      return;
 
545
    }
 
546
 
 
547
  GError * err = NULL;
 
548
  g_debug (G_STRLOC" ...which is new to us! Let's add it to our list.");
 
549
  DbusSyncClient * proxy = dbus_sync_client_proxy_new_sync (
 
550
                             connection,
 
551
                             G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
 
552
                             sender,
 
553
                             object,
 
554
                             NULL,
 
555
                             &err);
 
556
  if (err == NULL)
 
557
    {
 
558
      service_add_entry (service, entry_new (service, proxy));
 
559
    }
 
560
  else
 
561
    {
 
562
      g_warning ("couldn't create a proxy for '%s': %s", object, err->message);
 
563
      g_clear_error (&err);
 
564
    }
 
565
}
 
566
 
 
567
/****
 
568
*****
 
569
****/
 
570
 
 
571
static void
 
572
on_got_bus (GObject * o, GAsyncResult * res, gpointer user_data)
 
573
{
 
574
  GError * err = NULL;
 
575
  SyncService * service = user_data;
 
576
  GDBusConnection * connection = g_bus_get_finish (res, &err);
 
577
 
 
578
  if (err != NULL)
 
579
    {
 
580
      g_error ("unable to get bus: %s", err->message);
 
581
      g_clear_error (&err);
 
582
    }
 
583
  else
 
584
    {
 
585
      g_dbus_interface_skeleton_export (
 
586
          G_DBUS_INTERFACE_SKELETON(service->skeleton),
 
587
          connection,
 
588
          SYNC_SERVICE_DBUS_OBJECT,
 
589
          &err);
 
590
 
 
591
      if (err != NULL)
 
592
        {
 
593
          g_error ("unable to get bus: %s", err->message);
 
594
          g_clear_error (&err);
 
595
        }
 
596
 
 
597
      /* listen for SyncClients to show up on the bus */
 
598
      g_debug (G_STRLOC" listening to Exists from %s", SYNC_CLIENT_DBUS_IFACE);
 
599
      service->signal_subscription = g_dbus_connection_signal_subscribe (
 
600
                                       connection,
 
601
                                       NULL, /* sender */
 
602
                                       SYNC_CLIENT_DBUS_IFACE,
 
603
                                       "Exists",
 
604
                                       NULL, /* path */
 
605
                                       NULL, /* arg0 */
 
606
                                       G_DBUS_SIGNAL_FLAGS_NONE,
 
607
                                       on_sync_client_exists,
 
608
                                       service,
 
609
                                       NULL); /* destroy notify */
 
610
 
 
611
      /* cleanup */
 
612
      g_object_unref (connection);
 
613
    }
 
614
}
 
615
 
 
616
static void 
 
617
service_shutdown (IndicatorService * service G_GNUC_UNUSED, gpointer user_data)
 
618
{
 
619
  SyncService * sync_service = user_data;
 
620
  g_debug ("sync-service shutting down by request");
 
621
  g_main_loop_quit (sync_service->mainloop);
 
622
}
 
623
 
 
624
int
 
625
main (int argc, char ** argv)
 
626
{
 
627
  memset (&sync_service, 0, sizeof(sync_service));
 
628
 
 
629
  setlocale (LC_ALL, "");
 
630
  bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
 
631
  textdomain (GETTEXT_PACKAGE);
 
632
 
 
633
  g_type_init ();
 
634
 
 
635
  sync_service.indicator_service =
 
636
    indicator_service_new_version (SYNC_SERVICE_DBUS_NAME, 1);
 
637
 
 
638
  g_signal_connect (sync_service.indicator_service,
 
639
                    INDICATOR_SERVICE_SIGNAL_SHUTDOWN,
 
640
                    G_CALLBACK(service_shutdown),
 
641
                    &sync_service);
 
642
 
 
643
  sync_service.skeleton = dbus_sync_service_skeleton_new ();
 
644
 
 
645
  g_bus_get (G_BUS_TYPE_SESSION, NULL, on_got_bus, &sync_service);
 
646
 
 
647
  sync_service.menu_server = dbusmenu_server_new(SYNC_SERVICE_DBUS_MENU_OBJECT);
 
648
 
 
649
  /* the main loop */
 
650
  sync_service.mainloop = g_main_loop_new (NULL, FALSE);
 
651
  g_main_loop_run (sync_service.mainloop);
 
652
 
 
653
  /* cleanup */
 
654
  g_clear_pointer (&sync_service.mainloop, g_main_loop_unref);
 
655
  g_slist_free_full (sync_service.client_entries, (GDestroyNotify)entry_free);
 
656
  g_clear_object (&sync_service.menu_server);
 
657
  g_clear_object (&sync_service.skeleton);
 
658
  g_clear_object (&sync_service.indicator_service);
 
659
  return 0;
 
660
}