~unity8-desktop-session-team/indicator-session/indicator-session-using-upstart

« back to all changes in this revision

Viewing changes to src/service.c

  • Committer: Charles Kerr
  • Date: 2012-07-05 15:45:10 UTC
  • Revision ID: charles.kerr@canonical.com-20120705154510-q6dhcpn2lrosssv7
copyediting

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright 2013 Canonical Ltd.
3
 
 *
4
 
 * Authors:
5
 
 *   Charles Kerr <charles.kerr@canonical.com>
6
 
 *
7
 
 * This program is free software: you can redistribute it and/or modify it
8
 
 * under the terms of the GNU General Public License version 3, as published
9
 
 * by the Free Software Foundation.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful, but
12
 
 * WITHOUT ANY WARRANTY; without even the implied warranties of
13
 
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14
 
 * PURPOSE.  See the GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License along
17
 
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
 */
19
 
 
20
 
#include <glib/gi18n.h>
21
 
#include <gio/gio.h>
22
 
 
23
 
#include "backend.h"
24
 
#include "service.h"
25
 
 
26
 
#define BUS_NAME "com.canonical.indicator.session"
27
 
#define BUS_PATH "/com/canonical/indicator/session"
28
 
 
29
 
#define ICON_DEFAULT "system-devices-panel"
30
 
#define ICON_INFO    "system-devices-panel-information"
31
 
#define ICON_ALERT   "system-devices-panel-alert"
32
 
 
33
 
G_DEFINE_TYPE (IndicatorSessionService,
34
 
               indicator_session_service,
35
 
               G_TYPE_OBJECT)
36
 
 
37
 
/* signals enum */
38
 
enum
39
 
{
40
 
  NAME_LOST,
41
 
  LAST_SIGNAL
42
 
};
43
 
 
44
 
static guint signals[LAST_SIGNAL] = { 0 };
45
 
 
46
 
enum
47
 
{
48
 
  PROP_0,
49
 
  PROP_MAX_USERS,
50
 
  PROP_LAST
51
 
};
52
 
 
53
 
static GParamSpec * properties[PROP_LAST];
54
 
 
55
 
enum
56
 
{
57
 
  SECTION_HEADER    = (1<<0),
58
 
  SECTION_ADMIN     = (1<<1),
59
 
  SECTION_SETTINGS  = (1<<2),
60
 
  SECTION_SWITCH    = (1<<3),
61
 
  SECTION_LOGOUT    = (1<<4),
62
 
  SECTION_SESSION   = (1<<5)
63
 
};
64
 
 
65
 
enum
66
 
{
67
 
  PROFILE_DESKTOP,
68
 
  PROFILE_GREETER,
69
 
  N_PROFILES
70
 
};
71
 
 
72
 
static const char * const menu_names[N_PROFILES] =
73
 
{
74
 
  "desktop",
75
 
  "desktop_greeter"
76
 
};
77
 
 
78
 
struct ProfileMenuInfo
79
 
{
80
 
  /* the root level -- the header is the only child of this */
81
 
  GMenu * menu;
82
 
 
83
 
  /* parent of the sections. This is the header's submenu */
84
 
  GMenu * submenu;
85
 
 
86
 
  guint export_id;
87
 
};
88
 
 
89
 
struct _IndicatorSessionServicePrivate
90
 
{
91
 
  guint own_id;
92
 
  guint max_users;
93
 
  IndicatorSessionUsers * backend_users;
94
 
  IndicatorSessionGuest * backend_guest;
95
 
  IndicatorSessionActions * backend_actions;
96
 
  GSettings * indicator_settings;
97
 
  GSettings * keybinding_settings;
98
 
  GSimpleActionGroup * actions;
99
 
  guint actions_export_id;
100
 
  struct ProfileMenuInfo menus[N_PROFILES];
101
 
  GSimpleAction * header_action;
102
 
  GSimpleAction * user_switcher_action;
103
 
  GSimpleAction * guest_switcher_action;
104
 
  GHashTable * users;
105
 
  guint rebuild_id;
106
 
  int rebuild_flags;
107
 
  GDBusConnection * conn;
108
 
  GCancellable * cancellable;
109
 
 
110
 
  /* serialized icon cache */
111
 
  GVariant * alert_icon_serialized;
112
 
  GVariant * default_icon_serialized;
113
 
};
114
 
 
115
 
typedef IndicatorSessionServicePrivate priv_t;
116
 
 
117
 
static const char * get_current_real_name (IndicatorSessionService * self);
118
 
 
119
 
/***
120
 
****
121
 
***/
122
 
 
123
 
static void rebuild_now (IndicatorSessionService * self, int section);
124
 
static void rebuild_soon (IndicatorSessionService * self, int section);
125
 
 
126
 
static inline void
127
 
rebuild_header_soon (IndicatorSessionService * self)
128
 
{
129
 
  rebuild_soon (self, SECTION_HEADER);
130
 
}
131
 
static inline void
132
 
rebuild_switch_section_soon (IndicatorSessionService * self)
133
 
{
134
 
  rebuild_soon (self, SECTION_SWITCH);
135
 
}
136
 
static inline void
137
 
rebuild_logout_section_soon (IndicatorSessionService * self)
138
 
{
139
 
  rebuild_soon (self, SECTION_LOGOUT);
140
 
}
141
 
static inline void
142
 
rebuild_session_section_soon (IndicatorSessionService * self)
143
 
{
144
 
  rebuild_soon (self, SECTION_SESSION);
145
 
}
146
 
static inline void
147
 
rebuild_settings_section_soon (IndicatorSessionService * self)
148
 
{
149
 
  rebuild_soon (self, SECTION_SETTINGS);
150
 
}
151
 
 
152
 
/***
153
 
****
154
 
***/
155
 
 
156
 
static GVariant *
157
 
action_state_for_header (IndicatorSessionService * self)
158
 
{
159
 
  const priv_t * const p = self->priv;
160
 
  gboolean need_attn;
161
 
  GVariant * serialized_icon;
162
 
  gboolean show_name;
163
 
  const gchar * real_name;
164
 
  const gchar * label;
165
 
  gchar * a11y;
166
 
  GVariantBuilder b;
167
 
  GVariant * state;
168
 
 
169
 
  if (indicator_session_actions_has_online_account_error (p->backend_actions))
170
 
    {
171
 
      need_attn = TRUE;
172
 
      serialized_icon = p->alert_icon_serialized;
173
 
    }
174
 
  else
175
 
    {
176
 
      need_attn = FALSE;
177
 
      serialized_icon = p->default_icon_serialized;
178
 
    }
179
 
 
180
 
  show_name = g_settings_get_boolean (p->indicator_settings,
181
 
                                      "show-real-name-on-panel");
182
 
 
183
 
  real_name = get_current_real_name (self);
184
 
  label = show_name && real_name ? real_name : "";
185
 
 
186
 
  if (*label && need_attn)
187
 
    {
188
 
      /* Translators: the name of the menu ("System"), then the user's name,
189
 
         then a hint that something in this menu requires user attention */
190
 
      a11y = g_strdup_printf (_("System, %s (Attention Required)"), real_name);
191
 
    }
192
 
  else if (*label)
193
 
    {
194
 
      /* Translators: the name of the menu ("System"), then the user's name */
195
 
      a11y = g_strdup_printf (_("System, %s"), label);
196
 
    }
197
 
  else if (need_attn)
198
 
    {
199
 
      a11y = g_strdup  (_("System (Attention Required)"));
200
 
    }
201
 
  else
202
 
    {
203
 
      a11y = g_strdup (_("System"));
204
 
    }
205
 
 
206
 
  /* build the state */
207
 
  g_variant_builder_init (&b, G_VARIANT_TYPE("a{sv}"));
208
 
  g_variant_builder_add (&b, "{sv}", "accessible-desc", g_variant_new_string (a11y));
209
 
  if (serialized_icon != NULL)
210
 
    g_variant_builder_add (&b, "{sv}", "icon", serialized_icon);
211
 
  if (label && *label)
212
 
    g_variant_builder_add (&b, "{sv}", "label", g_variant_new_string (label));
213
 
  g_variant_builder_add (&b, "{sv}", "visible", g_variant_new_boolean (TRUE));
214
 
  state = g_variant_builder_end (&b);
215
 
 
216
 
  /* cleanup */
217
 
  g_free (a11y);
218
 
 
219
 
  return state;
220
 
}
221
 
 
222
 
static void
223
 
update_header_action (IndicatorSessionService * self)
224
 
{
225
 
  g_simple_action_set_state (self->priv->header_action, action_state_for_header (self));
226
 
}
227
 
 
228
 
/***
229
 
****  USERS
230
 
***/
231
 
 
232
 
static GMenuModel * create_switch_section (IndicatorSessionService * self);
233
 
 
234
 
static void
235
 
add_user (IndicatorSessionService * self, guint uid)
236
 
{
237
 
  IndicatorSessionUser * u;
238
 
 
239
 
  if ((u = indicator_session_users_get_user (self->priv->backend_users, uid)))
240
 
    {
241
 
      /* update our user table */
242
 
      g_hash_table_insert (self->priv->users, GUINT_TO_POINTER(uid), u);
243
 
 
244
 
      /* queue rebuilds for the affected sections */
245
 
      rebuild_switch_section_soon (self);
246
 
      if (u->is_current_user)
247
 
        rebuild_header_soon (self);
248
 
    }
249
 
}
250
 
 
251
 
static void
252
 
on_user_added (IndicatorSessionUsers * backend_users G_GNUC_UNUSED,
253
 
               guint                   uid,
254
 
               gpointer                gself)
255
 
{
256
 
  add_user (INDICATOR_SESSION_SERVICE(gself), uid);
257
 
}
258
 
 
259
 
static void
260
 
on_user_changed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED,
261
 
                 guint                   uid,
262
 
                 gpointer                gself)
263
 
{
264
 
  add_user (INDICATOR_SESSION_SERVICE(gself), uid);
265
 
}
266
 
 
267
 
static void
268
 
on_user_removed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED,
269
 
                 guint                   uid,
270
 
                 gpointer                gself)
271
 
{
272
 
  IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (gself);
273
 
  g_return_if_fail (self != NULL);
274
 
 
275
 
  /* update our user table */
276
 
  g_hash_table_remove (self->priv->users, GUINT_TO_POINTER(uid));
277
 
 
278
 
  /* enqueue rebuilds for the affected sections */
279
 
  rebuild_switch_section_soon (self);
280
 
}
281
 
 
282
 
static const char *
283
 
get_user_label (const IndicatorSessionUser * user)
284
 
{
285
 
  const char * c;
286
 
 
287
 
  /* If blank or whitespace, use username instead */
288
 
  for (c = user->real_name; *c != '\0' && g_ascii_isspace (*c); c++);
289
 
  if (*c == '\0')
290
 
    return user->user_name;
291
 
 
292
 
  return user->real_name;
293
 
}
294
 
 
295
 
static const char *
296
 
get_current_real_name (IndicatorSessionService * self)
297
 
{
298
 
  GHashTableIter iter;
299
 
  gpointer key, value;
300
 
 
301
 
  /* is it the guest? */
302
 
  if (indicator_session_guest_is_active (self->priv->backend_guest))
303
 
    return _("Guest");
304
 
 
305
 
  /* is it a user? */
306
 
  g_hash_table_iter_init (&iter, self->priv->users);
307
 
  while (g_hash_table_iter_next (&iter, &key, &value))
308
 
    {
309
 
      IndicatorSessionUser * user = value;
310
 
      if (user->is_current_user)
311
 
        return get_user_label (user);
312
 
    }
313
 
 
314
 
  return "";
315
 
}
316
 
 
317
 
/***
318
 
****
319
 
***/
320
 
 
321
 
static GMenuModel *
322
 
create_admin_section (void)
323
 
{
324
 
  GMenu * menu;
325
 
 
326
 
  menu = g_menu_new ();
327
 
  g_menu_append (menu, _("About This Computer"), "indicator.about");
328
 
  g_menu_append (menu, _("Ubuntu Help"), "indicator.help");
329
 
  return G_MENU_MODEL (menu);
330
 
}
331
 
 
332
 
static GMenuModel *
333
 
create_settings_section (IndicatorSessionService * self)
334
 
{
335
 
  GMenu * menu;
336
 
  priv_t * p = self->priv;
337
 
 
338
 
  menu = g_menu_new ();
339
 
  g_menu_append (menu, _("System Settings…"), "indicator.settings");
340
 
  if (indicator_session_actions_has_online_account_error (p->backend_actions))
341
 
      g_menu_append (menu, _("Online Accounts…"), "indicator.online-accounts");
342
 
 
343
 
  return G_MENU_MODEL (menu);
344
 
}
345
 
 
346
 
/**
347
 
 * The switch-to-guest action's state is a dictionary with these entries:
348
 
 *   - "is-active" (boolean)
349
 
 *   - "is-logged-in" (boolean)
350
 
 */
351
 
static GVariant *
352
 
create_guest_switcher_state (IndicatorSessionService * self)
353
 
{
354
 
  GVariant * val;
355
 
  GVariantBuilder b;
356
 
  IndicatorSessionGuest * const g = self->priv->backend_guest;
357
 
 
358
 
  g_variant_builder_init (&b, G_VARIANT_TYPE ("a{sv}"));
359
 
  val = g_variant_new_boolean (indicator_session_guest_is_active (g));
360
 
  g_variant_builder_add (&b, "{sv}", "is-active", val);
361
 
  val = g_variant_new_boolean (indicator_session_guest_is_logged_in (g));
362
 
  g_variant_builder_add (&b, "{sv}", "is-logged-in", val);
363
 
  return g_variant_builder_end (&b);
364
 
}
365
 
 
366
 
/**
367
 
 * The switch-to-user action's state is a dictionary with these entries: 
368
 
 *  - "active-user" (username string)
369
 
 *  - "logged-in-users" (array of username strings)
370
 
 */
371
 
static GVariant *
372
 
create_user_switcher_state (IndicatorSessionService * self)
373
 
{
374
 
  GVariantBuilder a;
375
 
  GVariantBuilder b;
376
 
  GVariant * val;
377
 
  GHashTableIter ht_iter;
378
 
  gpointer ht_value;
379
 
  const char * current_user;
380
 
 
381
 
  current_user = "";
382
 
  g_variant_builder_init (&a, G_VARIANT_TYPE("as"));
383
 
  g_hash_table_iter_init (&ht_iter, self->priv->users);
384
 
  while (g_hash_table_iter_next (&ht_iter, NULL, &ht_value))
385
 
    {
386
 
      const IndicatorSessionUser * u = ht_value;
387
 
 
388
 
      if (u->is_current_user)
389
 
        current_user = u->user_name;
390
 
 
391
 
      if (u->is_logged_in)
392
 
        g_variant_builder_add (&a, "s", u->user_name);
393
 
    }
394
 
 
395
 
  g_variant_builder_init (&b, G_VARIANT_TYPE("a{sv}"));
396
 
  val = g_variant_new_string (current_user);
397
 
  g_variant_builder_add (&b, "{sv}", "active-user", val);
398
 
  val = g_variant_builder_end (&a);
399
 
  g_variant_builder_add (&b, "{sv}", "logged-in-users", val);
400
 
  return g_variant_builder_end (&b);
401
 
}
402
 
 
403
 
static void
404
 
update_switch_actions (IndicatorSessionService * self)
405
 
{
406
 
  g_simple_action_set_state (self->priv->guest_switcher_action,
407
 
                             create_guest_switcher_state (self));
408
 
 
409
 
  g_simple_action_set_state (self->priv->user_switcher_action,
410
 
                             create_user_switcher_state (self));
411
 
}
412
 
 
413
 
static gboolean
414
 
use_ellipsis (IndicatorSessionService * self)
415
 
{
416
 
  /* does the backend support confirmation prompts? */
417
 
  if (!indicator_session_actions_can_prompt (self->priv->backend_actions))
418
 
    return FALSE;
419
 
 
420
 
  /* has the user disabled prompts? */
421
 
  if (g_settings_get_boolean (self->priv->indicator_settings,
422
 
                              "suppress-logout-restart-shutdown"))
423
 
    return FALSE;
424
 
 
425
 
  return TRUE;
426
 
}
427
 
 
428
 
/* lower index == more useful.
429
 
   When there are too many users for the menu,
430
 
   we use this to decide which to cull. */
431
 
static int
432
 
compare_users_by_usefulness (gconstpointer ga, gconstpointer gb)
433
 
{
434
 
  const IndicatorSessionUser * a = *(const IndicatorSessionUser**)ga;
435
 
  const IndicatorSessionUser * b = *(const IndicatorSessionUser**)gb;
436
 
 
437
 
  if (a->is_current_user != b->is_current_user)
438
 
    return a->is_current_user ? -1 : 1;
439
 
 
440
 
  if (a->is_logged_in != b->is_logged_in)
441
 
    return a->is_logged_in ? -1 : 1;
442
 
 
443
 
  if (a->login_frequency != b->login_frequency)
444
 
    return a->login_frequency > b->login_frequency ? -1 : 1;
445
 
 
446
 
  return 0;
447
 
}
448
 
 
449
 
/* sorting them for display in the menu */
450
 
static int
451
 
compare_users_by_label (gconstpointer ga, gconstpointer gb)
452
 
{
453
 
  int i;
454
 
  const IndicatorSessionUser * a = *(const IndicatorSessionUser**)ga;
455
 
  const IndicatorSessionUser * b = *(const IndicatorSessionUser**)gb;
456
 
 
457
 
  if ((i = g_strcmp0 (get_user_label (a), get_user_label (b))))
458
 
    return i;
459
 
 
460
 
  return g_strcmp0 (a->user_name, b->user_name);
461
 
}
462
 
 
463
 
static GVariant *
464
 
serialize_icon_file (const gchar * filename)
465
 
{
466
 
  GVariant * serialized_icon = NULL;
467
 
 
468
 
  if (filename != NULL)
469
 
    {
470
 
      GFile * file = g_file_new_for_path (filename);
471
 
      GIcon * icon = g_file_icon_new (file);
472
 
 
473
 
      serialized_icon = g_icon_serialize (icon);
474
 
 
475
 
      g_object_unref (icon);
476
 
      g_object_unref (file);
477
 
    }
478
 
 
479
 
  return serialized_icon;
480
 
}
481
 
 
482
 
static GMenuModel *
483
 
create_switch_section (IndicatorSessionService * self)
484
 
{
485
 
  gchar * str;
486
 
  GMenu * menu;
487
 
  GMenuItem * item;
488
 
  guint i;
489
 
  gpointer guser;
490
 
  GHashTableIter iter;
491
 
  GPtrArray * users;
492
 
  const priv_t * const p = self->priv;
493
 
  const gboolean ellipsis = use_ellipsis (self);
494
 
 
495
 
  menu = g_menu_new ();
496
 
 
497
 
  /* lockswitch */
498
 
  if (indicator_session_users_is_live_session (p->backend_users))
499
 
    {
500
 
      const char * action = "indicator.switch-to-screensaver";
501
 
      item = g_menu_item_new (_("Start Screen Saver"), action);
502
 
    }
503
 
  else if (indicator_session_guest_is_active (p->backend_guest))
504
 
    {
505
 
      const char * action = "indicator.switch-to-greeter";
506
 
      item = g_menu_item_new (ellipsis ? _("Switch Account…")
507
 
                                       : _("Switch Account"), action);
508
 
    }
509
 
  else
510
 
    {
511
 
      const char * action = "indicator.switch-to-screensaver";
512
 
 
513
 
      if (g_hash_table_size (p->users) == 1)
514
 
        item = g_menu_item_new (_("Lock"), action);
515
 
      else
516
 
        item = g_menu_item_new (ellipsis ? _("Lock/Switch Account…")
517
 
                                         : _("Lock/Switch Account"), action);
518
 
    }
519
 
  str = g_settings_get_string (p->keybinding_settings, "screensaver");
520
 
  g_menu_item_set_attribute (item, "accel", "s", str);
521
 
  g_free (str);
522
 
  g_menu_append_item (menu, item);
523
 
  g_object_unref (item);
524
 
 
525
 
  if (indicator_session_guest_is_allowed (p->backend_guest))
526
 
    {
527
 
      GMenuItem *item;
528
 
 
529
 
      item = g_menu_item_new (_("Guest Session"), "indicator.switch-to-guest");
530
 
      g_menu_item_set_attribute (item, "x-canonical-type", "s", "indicator.guest-menu-item");
531
 
      g_menu_append_item (menu, item);
532
 
 
533
 
      g_object_unref (item);
534
 
    }
535
 
 
536
 
  /* build an array of all the users we know of */
537
 
  users = g_ptr_array_new ();
538
 
  g_hash_table_iter_init (&iter, p->users);
539
 
  while (g_hash_table_iter_next (&iter, NULL, &guser))
540
 
    g_ptr_array_add (users, guser);
541
 
 
542
 
  /* if there are too many users, cull out the less interesting ones */
543
 
  if (users->len > p->max_users)
544
 
    {
545
 
      g_ptr_array_sort (users, compare_users_by_usefulness);
546
 
      g_ptr_array_set_size (users, p->max_users);
547
 
    }
548
 
 
549
 
  /* sort the users by name */
550
 
  g_ptr_array_sort (users, compare_users_by_label);
551
 
 
552
 
  /* add the users */
553
 
  for (i=0; i<users->len; ++i)
554
 
    {
555
 
      const IndicatorSessionUser * u = g_ptr_array_index (users, i);
556
 
      GVariant * serialized_icon;
557
 
 
558
 
      item = g_menu_item_new (get_user_label (u), NULL);
559
 
      g_menu_item_set_action_and_target (item, "indicator.switch-to-user", "s", u->user_name);
560
 
      g_menu_item_set_attribute (item, "x-canonical-type", "s", "indicator.user-menu-item");
561
 
 
562
 
      if ((serialized_icon = serialize_icon_file (u->icon_file)))
563
 
        {
564
 
          g_menu_item_set_attribute_value (item, G_MENU_ATTRIBUTE_ICON, serialized_icon);
565
 
          g_variant_unref (serialized_icon);
566
 
        }
567
 
 
568
 
      g_menu_append_item (menu, item);
569
 
      g_object_unref (item);
570
 
    }
571
 
 
572
 
  /* cleanup */
573
 
  g_ptr_array_free (users, TRUE);
574
 
  return G_MENU_MODEL (menu);
575
 
}
576
 
 
577
 
static GMenuModel *
578
 
create_logout_section (IndicatorSessionService * self)
579
 
{
580
 
  GMenu * menu;
581
 
  const priv_t * const p = self->priv;
582
 
  const gboolean ellipsis = use_ellipsis (self);
583
 
 
584
 
  menu = g_menu_new ();
585
 
 
586
 
  if (indicator_session_actions_can_logout (p->backend_actions))
587
 
    {
588
 
      const char * label = ellipsis ? _("Log Out…") : _("Log Out");
589
 
      g_menu_append (menu, label, "indicator.logout");
590
 
    }
591
 
 
592
 
  return G_MENU_MODEL (menu);
593
 
}
594
 
 
595
 
static GMenuModel *
596
 
create_session_section (IndicatorSessionService * self)
597
 
{
598
 
  GMenu * menu;
599
 
  const priv_t * const p = self->priv;
600
 
  GSettings * const s = p->indicator_settings;
601
 
  const gboolean ellipsis = use_ellipsis (self);
602
 
 
603
 
  menu = g_menu_new ();
604
 
 
605
 
  if (indicator_session_actions_can_suspend (p->backend_actions))
606
 
    g_menu_append (menu, _("Suspend"), "indicator.suspend");
607
 
 
608
 
  if (indicator_session_actions_can_hibernate (p->backend_actions))
609
 
    g_menu_append (menu, _("Hibernate"), "indicator.hibernate");
610
 
 
611
 
  if (indicator_session_actions_can_reboot (p->backend_actions))
612
 
    {
613
 
      const char * label = ellipsis ? _("Restart…") : _("Restart");
614
 
      g_menu_append (menu, label, "indicator.reboot");
615
 
    }
616
 
 
617
 
  if (!g_settings_get_boolean (s, "suppress-shutdown-menuitem"))
618
 
    {
619
 
      const char * label = ellipsis ? _("Shut Down…") : _("Shut Down");
620
 
      g_menu_append (menu, label, "indicator.power-off");
621
 
    }
622
 
 
623
 
  return G_MENU_MODEL (menu);
624
 
}
625
 
 
626
 
static void
627
 
create_menu (IndicatorSessionService * self, int profile)
628
 
{
629
 
  GMenu * menu;
630
 
  GMenu * submenu;
631
 
  GMenuItem * header;
632
 
  GMenuModel * sections[16];
633
 
  int i;
634
 
  int n = 0;
635
 
 
636
 
  g_assert (0<=profile && profile<N_PROFILES);
637
 
  g_assert (self->priv->menus[profile].menu == NULL);
638
 
 
639
 
  if (profile == PROFILE_DESKTOP)
640
 
    {
641
 
      sections[n++] = create_admin_section ();
642
 
      sections[n++] = create_settings_section (self);
643
 
      sections[n++] = create_switch_section (self);
644
 
      sections[n++] = create_logout_section (self);
645
 
      sections[n++] = create_session_section (self);
646
 
    }
647
 
  else if (profile == PROFILE_GREETER)
648
 
    {
649
 
      sections[n++] = create_session_section (self);
650
 
    }
651
 
 
652
 
  /* add sections to the submenu */
653
 
  submenu = g_menu_new ();
654
 
  for (i=0; i<n; ++i)
655
 
    {
656
 
      g_menu_append_section (submenu, NULL, sections[i]);
657
 
      g_object_unref (sections[i]);
658
 
    }
659
 
 
660
 
  /* add submenu to the header */
661
 
  header = g_menu_item_new (NULL, "indicator._header");
662
 
  g_menu_item_set_attribute (header, "x-canonical-type", "s", "com.canonical.indicator.root");
663
 
  g_menu_item_set_submenu (header, G_MENU_MODEL (submenu));
664
 
  g_object_unref (submenu);
665
 
 
666
 
  /* add header to the menu */
667
 
  menu = g_menu_new ();
668
 
  g_menu_append_item (menu, header);
669
 
  g_object_unref (header);
670
 
 
671
 
  self->priv->menus[profile].menu = menu;
672
 
  self->priv->menus[profile].submenu = submenu;
673
 
}
674
 
 
675
 
/***
676
 
****  GActions
677
 
***/
678
 
 
679
 
static IndicatorSessionActions *
680
 
get_backend_actions (gpointer gself)
681
 
{
682
 
  return INDICATOR_SESSION_SERVICE(gself)->priv->backend_actions;
683
 
}
684
 
 
685
 
static void
686
 
on_about_activated (GSimpleAction * a      G_GNUC_UNUSED,
687
 
                    GVariant      * param  G_GNUC_UNUSED,
688
 
                    gpointer        gself)
689
 
{
690
 
  indicator_session_actions_about (get_backend_actions(gself));
691
 
}
692
 
 
693
 
static void
694
 
on_online_accounts_activated (GSimpleAction * a      G_GNUC_UNUSED,
695
 
                              GVariant      * param  G_GNUC_UNUSED,
696
 
                              gpointer        gself)
697
 
{
698
 
  indicator_session_actions_online_accounts (get_backend_actions(gself));
699
 
}
700
 
 
701
 
static void
702
 
on_help_activated (GSimpleAction  * a      G_GNUC_UNUSED,
703
 
                   GVariant       * param  G_GNUC_UNUSED,
704
 
                   gpointer         gself)
705
 
{
706
 
  indicator_session_actions_help (get_backend_actions(gself));
707
 
}
708
 
 
709
 
static void
710
 
on_settings_activated (GSimpleAction * a      G_GNUC_UNUSED,
711
 
                       GVariant      * param  G_GNUC_UNUSED,
712
 
                       gpointer        gself)
713
 
{
714
 
  indicator_session_actions_settings (get_backend_actions(gself));
715
 
}
716
 
 
717
 
static void
718
 
on_logout_activated (GSimpleAction * a      G_GNUC_UNUSED,
719
 
                     GVariant      * param  G_GNUC_UNUSED,
720
 
                     gpointer        gself)
721
 
{
722
 
  indicator_session_actions_logout (get_backend_actions(gself));
723
 
}
724
 
 
725
 
static void
726
 
on_suspend_activated (GSimpleAction * a      G_GNUC_UNUSED,
727
 
                      GVariant      * param  G_GNUC_UNUSED,
728
 
                      gpointer        gself)
729
 
{
730
 
  indicator_session_actions_suspend (get_backend_actions(gself));
731
 
}
732
 
 
733
 
static void
734
 
on_hibernate_activated (GSimpleAction * a      G_GNUC_UNUSED,
735
 
                        GVariant      * param  G_GNUC_UNUSED,
736
 
                        gpointer        gself)
737
 
{
738
 
  indicator_session_actions_hibernate (get_backend_actions(gself));
739
 
}
740
 
 
741
 
static void
742
 
on_reboot_activated (GSimpleAction * action G_GNUC_UNUSED,
743
 
                     GVariant      * param  G_GNUC_UNUSED,
744
 
                     gpointer        gself)
745
 
{
746
 
  indicator_session_actions_reboot (get_backend_actions(gself));
747
 
}
748
 
 
749
 
static void
750
 
on_power_off_activated (GSimpleAction * a     G_GNUC_UNUSED,
751
 
                        GVariant      * param G_GNUC_UNUSED,
752
 
                        gpointer        gself)
753
 
{
754
 
  indicator_session_actions_power_off (get_backend_actions(gself));
755
 
}
756
 
 
757
 
static void
758
 
on_guest_activated (GSimpleAction * a     G_GNUC_UNUSED,
759
 
                    GVariant      * param G_GNUC_UNUSED,
760
 
                    gpointer        gself)
761
 
{
762
 
  indicator_session_actions_switch_to_guest (get_backend_actions(gself));
763
 
}
764
 
 
765
 
static void
766
 
on_screensaver_activated (GSimpleAction * a      G_GNUC_UNUSED,
767
 
                          GVariant      * param  G_GNUC_UNUSED,
768
 
                          gpointer        gself)
769
 
{
770
 
  indicator_session_actions_switch_to_screensaver (get_backend_actions(gself));
771
 
}
772
 
 
773
 
static void
774
 
on_greeter_activated (GSimpleAction * a      G_GNUC_UNUSED,
775
 
                      GVariant      * param  G_GNUC_UNUSED,
776
 
                      gpointer        gself)
777
 
{
778
 
  indicator_session_actions_switch_to_greeter (get_backend_actions(gself));
779
 
}
780
 
 
781
 
static void
782
 
on_user_activated (GSimpleAction * a         G_GNUC_UNUSED,
783
 
                   GVariant      * param,
784
 
                   gpointer        gself)
785
 
{
786
 
  const char * username = g_variant_get_string (param, NULL);
787
 
  indicator_session_actions_switch_to_username (get_backend_actions(gself),
788
 
                                                username);
789
 
}
790
 
 
791
 
static void
792
 
init_gactions (IndicatorSessionService * self)
793
 
{
794
 
  GVariant * v;
795
 
  GSimpleAction * a;
796
 
  priv_t * p = self->priv;
797
 
 
798
 
  GActionEntry entries[] = {
799
 
    { "about",                  on_about_activated           },
800
 
    { "help",                   on_help_activated            },
801
 
    { "hibernate",              on_hibernate_activated       },
802
 
    { "logout",                 on_logout_activated          },
803
 
    { "online-accounts",        on_online_accounts_activated },
804
 
    { "reboot",                 on_reboot_activated          },
805
 
    { "settings",               on_settings_activated        },
806
 
    { "switch-to-screensaver",  on_screensaver_activated     },
807
 
    { "switch-to-greeter",      on_greeter_activated         },
808
 
    { "suspend",                on_suspend_activated         },
809
 
    { "power-off",              on_power_off_activated       }
810
 
  };
811
 
 
812
 
  p->actions = g_simple_action_group_new ();
813
 
 
814
 
  g_action_map_add_action_entries (G_ACTION_MAP(p->actions),
815
 
                                   entries,
816
 
                                   G_N_ELEMENTS(entries),
817
 
                                   self);
818
 
 
819
 
  /* add switch-to-guest action */
820
 
  v = create_guest_switcher_state (self);
821
 
  a = g_simple_action_new_stateful ("switch-to-guest", NULL, v);
822
 
  g_signal_connect (a, "activate", G_CALLBACK(on_guest_activated), self);
823
 
  g_action_map_add_action (G_ACTION_MAP (p->actions), G_ACTION(a));
824
 
  p->guest_switcher_action = a;
825
 
 
826
 
  /* add switch-to-user action... parameter is the uesrname */
827
 
  v = create_user_switcher_state (self);
828
 
  a = g_simple_action_new_stateful ("switch-to-user", G_VARIANT_TYPE_STRING, v);
829
 
  g_signal_connect (a, "activate", G_CALLBACK(on_user_activated), self);
830
 
  g_action_map_add_action (G_ACTION_MAP (p->actions), G_ACTION(a));
831
 
  p->user_switcher_action = a;
832
 
 
833
 
  /* add the header action */
834
 
  a = g_simple_action_new_stateful ("_header", NULL,
835
 
                                    action_state_for_header (self));
836
 
  g_action_map_add_action (G_ACTION_MAP (p->actions), G_ACTION(a));
837
 
  p->header_action = a;
838
 
 
839
 
  rebuild_now (self, SECTION_HEADER);
840
 
}
841
 
 
842
 
/***
843
 
****
844
 
***/
845
 
 
846
 
/**
847
 
 * A small helper function for rebuild_now().
848
 
 * - removes the previous section
849
 
 * - adds and unrefs the new section
850
 
 */
851
 
static void
852
 
rebuild_section (GMenu * parent, int pos, GMenuModel * new_section)
853
 
{
854
 
  g_menu_remove (parent, pos);
855
 
  g_menu_insert_section (parent, pos, NULL, new_section);
856
 
  g_object_unref (new_section);
857
 
}
858
 
 
859
 
static void
860
 
rebuild_now (IndicatorSessionService * self, int sections)
861
 
{
862
 
  priv_t * p = self->priv;
863
 
  struct ProfileMenuInfo * desktop = &p->menus[PROFILE_DESKTOP];
864
 
  struct ProfileMenuInfo * greeter = &p->menus[PROFILE_GREETER];
865
 
 
866
 
  if (sections & SECTION_HEADER)
867
 
    {
868
 
      update_header_action (self);
869
 
    }
870
 
 
871
 
  if (sections & SECTION_ADMIN)
872
 
    {
873
 
      rebuild_section (desktop->submenu, 0, create_admin_section());
874
 
    }
875
 
 
876
 
  if (sections & SECTION_SETTINGS)
877
 
    {
878
 
      rebuild_section (desktop->submenu, 1, create_settings_section(self));
879
 
    }
880
 
 
881
 
  if (sections & SECTION_SWITCH)
882
 
    {
883
 
      rebuild_section (desktop->submenu, 2, create_switch_section(self));
884
 
      update_switch_actions (self);
885
 
    }
886
 
 
887
 
  if (sections & SECTION_LOGOUT)
888
 
    {
889
 
      rebuild_section (desktop->submenu, 3, create_logout_section(self));
890
 
    }
891
 
 
892
 
  if (sections & SECTION_SESSION)
893
 
    {
894
 
      rebuild_section (desktop->submenu, 4, create_session_section(self));
895
 
      rebuild_section (greeter->submenu, 0, create_session_section(self));
896
 
    }
897
 
}
898
 
 
899
 
static int
900
 
rebuild_timeout_func (IndicatorSessionService * self)
901
 
{
902
 
  priv_t * p = self->priv;
903
 
  rebuild_now (self, p->rebuild_flags);
904
 
  p->rebuild_flags = 0;
905
 
  p->rebuild_id = 0;
906
 
  return G_SOURCE_REMOVE;
907
 
}
908
 
 
909
 
static void
910
 
rebuild_soon (IndicatorSessionService * self, int section)
911
 
{
912
 
  priv_t * p = self->priv;
913
 
 
914
 
  p->rebuild_flags |= section;
915
 
 
916
 
  if (p->rebuild_id == 0)
917
 
    {
918
 
      /* Change events seem to come over the bus in small bursts. This msec
919
 
         value is an arbitrary number that tries to be large enough to fold
920
 
         multiple events into a single rebuild, but small enough that the
921
 
         user won't notice any lag. */
922
 
      static const int REBUILD_INTERVAL_MSEC = 500;
923
 
 
924
 
      p->rebuild_id = g_timeout_add (REBUILD_INTERVAL_MSEC,
925
 
                                     (GSourceFunc)rebuild_timeout_func,
926
 
                                     self);
927
 
    }
928
 
}
929
 
 
930
 
/***
931
 
**** GDBus
932
 
***/
933
 
 
934
 
static void
935
 
on_bus_acquired (GDBusConnection * connection,
936
 
                 const gchar     * name,
937
 
                 gpointer          gself)
938
 
{
939
 
  int i;
940
 
  guint id;
941
 
  GError * err = NULL;
942
 
  IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(gself);
943
 
  priv_t * p = self->priv;
944
 
 
945
 
  g_debug ("bus acquired: %s", name);
946
 
 
947
 
  p->conn = g_object_ref (G_OBJECT (connection));
948
 
 
949
 
  /* export the actions */
950
 
  if ((id = g_dbus_connection_export_action_group (connection,
951
 
                                                   BUS_PATH,
952
 
                                                   G_ACTION_GROUP (p->actions),
953
 
                                                   &err)))
954
 
    {
955
 
      p->actions_export_id = id;
956
 
    }
957
 
  else
958
 
    {
959
 
      g_warning ("cannot export action group: %s", err->message);
960
 
      g_clear_error (&err);
961
 
    }
962
 
 
963
 
  /* export the menus */
964
 
  for (i=0; i<N_PROFILES; ++i)
965
 
    {
966
 
      char * path = g_strdup_printf ("%s/%s", BUS_PATH, menu_names[i]);
967
 
      struct ProfileMenuInfo * menu = &p->menus[i];
968
 
 
969
 
      if (menu->menu == NULL)
970
 
        create_menu (self, i);
971
 
 
972
 
      if ((id = g_dbus_connection_export_menu_model (connection,
973
 
                                                     path,
974
 
                                                     G_MENU_MODEL (menu->menu),
975
 
                                                     &err)))
976
 
        {
977
 
          menu->export_id = id;
978
 
        }
979
 
      else
980
 
        {
981
 
          g_warning ("cannot export %s menu: %s", menu_names[i], err->message);
982
 
          g_clear_error (&err);
983
 
        }
984
 
 
985
 
      g_free (path);
986
 
    }
987
 
}
988
 
 
989
 
static void
990
 
unexport (IndicatorSessionService * self)
991
 
{
992
 
  int i;
993
 
  priv_t * p = self->priv;
994
 
 
995
 
  /* unexport the menus */
996
 
  for (i=0; i<N_PROFILES; ++i)
997
 
    {
998
 
      guint * id = &self->priv->menus[i].export_id;
999
 
 
1000
 
      if (*id)
1001
 
        {
1002
 
          g_dbus_connection_unexport_menu_model (p->conn, *id);
1003
 
          *id = 0;
1004
 
        }
1005
 
    }
1006
 
 
1007
 
  /* unexport the actions */
1008
 
  if (p->actions_export_id)
1009
 
    {
1010
 
      g_dbus_connection_unexport_action_group (p->conn, p->actions_export_id);
1011
 
      p->actions_export_id = 0;
1012
 
    }
1013
 
}
1014
 
 
1015
 
static void
1016
 
on_name_lost (GDBusConnection * connection G_GNUC_UNUSED,
1017
 
              const gchar     * name,
1018
 
              gpointer          gself)
1019
 
{
1020
 
  IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (gself);
1021
 
 
1022
 
  g_debug ("%s %s name lost %s", G_STRLOC, G_STRFUNC, name);
1023
 
 
1024
 
  unexport (self);
1025
 
 
1026
 
  g_signal_emit (self, signals[NAME_LOST], 0, NULL);
1027
 
}
1028
 
 
1029
 
/***
1030
 
****
1031
 
***/
1032
 
 
1033
 
static void
1034
 
/* cppcheck-suppress unusedFunction */
1035
 
indicator_session_service_init (IndicatorSessionService * self)
1036
 
{
1037
 
  GList * l;
1038
 
  GList * uids;
1039
 
  priv_t * p;
1040
 
  gpointer gp;
1041
 
  GIcon * icon;
1042
 
 
1043
 
  /* init our priv pointer */
1044
 
  p = G_TYPE_INSTANCE_GET_PRIVATE (self,
1045
 
                                   INDICATOR_TYPE_SESSION_SERVICE,
1046
 
                                   IndicatorSessionServicePrivate);
1047
 
  p->indicator_settings = g_settings_new ("com.canonical.indicator.session");
1048
 
  p->keybinding_settings = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys");
1049
 
  self->priv = p;
1050
 
 
1051
 
  /* init the backend objects */
1052
 
  p->cancellable = g_cancellable_new ();
1053
 
  backend_get (p->cancellable, &p->backend_actions,
1054
 
                               &p->backend_users,
1055
 
                               &p->backend_guest);
1056
 
 
1057
 
  /* build the serialized icon cache */
1058
 
 
1059
 
  icon = g_themed_icon_new_with_default_fallbacks (ICON_ALERT);
1060
 
  p->alert_icon_serialized = g_icon_serialize (icon);
1061
 
  g_object_unref (icon);
1062
 
 
1063
 
  icon = g_themed_icon_new_with_default_fallbacks (ICON_DEFAULT);
1064
 
  p->default_icon_serialized = g_icon_serialize (icon);
1065
 
  g_object_unref (icon);
1066
 
 
1067
 
  /* init our key-to-User table */
1068
 
  p->users = g_hash_table_new_full (g_direct_hash,
1069
 
                                    g_direct_equal,
1070
 
                                    NULL,
1071
 
                                    (GDestroyNotify)indicator_session_user_free);
1072
 
  uids = indicator_session_users_get_uids (p->backend_users);
1073
 
  for (l=uids; l!=NULL; l=l->next)
1074
 
    add_user (self, GPOINTER_TO_UINT(l->data));
1075
 
  g_list_free (uids);
1076
 
 
1077
 
  init_gactions (self);
1078
 
 
1079
 
  /* watch for changes in backend_users */
1080
 
  gp = p->backend_users;
1081
 
  g_signal_connect (gp, INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED,
1082
 
                    G_CALLBACK(on_user_added), self);
1083
 
  g_signal_connect (gp, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED,
1084
 
                    G_CALLBACK(on_user_changed), self);
1085
 
  g_signal_connect (gp, INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED,
1086
 
                    G_CALLBACK(on_user_removed), self);
1087
 
  g_signal_connect_swapped (gp, "notify::is-live-session",
1088
 
                            G_CALLBACK(rebuild_switch_section_soon), self);
1089
 
 
1090
 
  /* watch for changes in backend_guest */
1091
 
  gp = p->backend_guest;
1092
 
  g_signal_connect_swapped (gp, "notify::guest-is-active-session",
1093
 
                            G_CALLBACK(rebuild_header_soon), self);
1094
 
  g_signal_connect_swapped (gp, "notify",
1095
 
                            G_CALLBACK(rebuild_switch_section_soon), self);
1096
 
 
1097
 
  /* watch for updates in backend_actions */
1098
 
  gp = p->backend_actions;
1099
 
  g_signal_connect_swapped (gp, "notify",
1100
 
                            G_CALLBACK(rebuild_switch_section_soon), self);
1101
 
  g_signal_connect_swapped (gp, "notify",
1102
 
                            G_CALLBACK(rebuild_logout_section_soon), self);
1103
 
  g_signal_connect_swapped (gp, "notify",
1104
 
                            G_CALLBACK(rebuild_session_section_soon), self);
1105
 
  g_signal_connect_swapped (gp, "notify::has-online-account-error",
1106
 
                            G_CALLBACK(rebuild_header_soon), self);
1107
 
  g_signal_connect_swapped (gp, "notify::has-online-account-error",
1108
 
                            G_CALLBACK(rebuild_settings_section_soon), self);
1109
 
 
1110
 
  /* watch for changes in the indicator's settings */
1111
 
  gp = p->indicator_settings;
1112
 
  g_signal_connect_swapped (gp, "changed::suppress-logout-restart-shutdown",
1113
 
                            G_CALLBACK(rebuild_switch_section_soon), self);
1114
 
  g_signal_connect_swapped (gp, "changed::suppress-logout-restart-shutdown",
1115
 
                            G_CALLBACK(rebuild_logout_section_soon), self);
1116
 
  g_signal_connect_swapped (gp, "changed::suppress-logout-restart-shutdown",
1117
 
                            G_CALLBACK(rebuild_session_section_soon), self);
1118
 
  g_signal_connect_swapped (gp, "changed::suppress-shutdown-menuitem",
1119
 
                            G_CALLBACK(rebuild_session_section_soon), self);
1120
 
  g_signal_connect_swapped (gp, "changed::show-real-name-on-panel",
1121
 
                            G_CALLBACK(rebuild_header_soon), self);
1122
 
 
1123
 
  /* watch for changes to the lock keybinding */
1124
 
  gp = p->keybinding_settings;
1125
 
  g_signal_connect_swapped (gp, "changed::screensaver",
1126
 
                            G_CALLBACK(rebuild_switch_section_soon), self);
1127
 
 
1128
 
  self->priv->own_id = g_bus_own_name (G_BUS_TYPE_SESSION,
1129
 
                                       BUS_NAME,
1130
 
                                       G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
1131
 
                                       on_bus_acquired,
1132
 
                                       NULL,
1133
 
                                       on_name_lost,
1134
 
                                       self,
1135
 
                                       NULL);
1136
 
}
1137
 
 
1138
 
/***
1139
 
****  GObject plumbing: properties
1140
 
***/
1141
 
 
1142
 
static void
1143
 
my_get_property (GObject     * o,
1144
 
                  guint         property_id,
1145
 
                  GValue      * value,
1146
 
                  GParamSpec  * pspec)
1147
 
{
1148
 
  IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (o);
1149
 
 
1150
 
  switch (property_id)
1151
 
    {
1152
 
      case PROP_MAX_USERS:
1153
 
        g_value_set_uint (value, self->priv->max_users);
1154
 
        break;
1155
 
 
1156
 
      default:
1157
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
1158
 
    }
1159
 
}
1160
 
 
1161
 
static void
1162
 
my_set_property (GObject       * o,
1163
 
                 guint           property_id,
1164
 
                 const GValue  * value,
1165
 
                 GParamSpec    * pspec)
1166
 
{
1167
 
  IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (o);
1168
 
 
1169
 
  switch (property_id)
1170
 
    {
1171
 
      case PROP_MAX_USERS:
1172
 
        self->priv->max_users = g_value_get_uint (value);
1173
 
        rebuild_switch_section_soon (self);
1174
 
        break;
1175
 
 
1176
 
      default:
1177
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
1178
 
    }
1179
 
}
1180
 
 
1181
 
/***
1182
 
****  GObject plumbing: life cycle
1183
 
***/
1184
 
 
1185
 
static void
1186
 
my_dispose (GObject * o)
1187
 
{
1188
 
  int i;
1189
 
  IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(o);
1190
 
  priv_t * p = self->priv;
1191
 
 
1192
 
  if (p->own_id)
1193
 
    {
1194
 
      g_bus_unown_name (p->own_id);
1195
 
      p->own_id = 0;
1196
 
    }
1197
 
 
1198
 
  unexport (self);
1199
 
 
1200
 
  if (p->cancellable != NULL)
1201
 
    {
1202
 
      g_cancellable_cancel (p->cancellable);
1203
 
      g_clear_object (&p->cancellable);
1204
 
    }
1205
 
 
1206
 
  if (p->rebuild_id)
1207
 
    {
1208
 
      g_source_remove (p->rebuild_id);
1209
 
      p->rebuild_id = 0;
1210
 
    }
1211
 
 
1212
 
  g_clear_pointer (&p->users, g_hash_table_destroy);
1213
 
  g_clear_object (&p->backend_users);
1214
 
  g_clear_object (&p->backend_guest);
1215
 
  g_clear_object (&p->backend_actions);
1216
 
  g_clear_object (&p->indicator_settings);
1217
 
  g_clear_object (&p->keybinding_settings);
1218
 
  g_clear_object (&p->actions);
1219
 
 
1220
 
  for (i=0; i<N_PROFILES; ++i)
1221
 
    g_clear_object (&p->menus[i].menu);
1222
 
 
1223
 
  g_clear_object (&p->header_action);
1224
 
  g_clear_object (&p->user_switcher_action);
1225
 
  g_clear_object (&p->guest_switcher_action);
1226
 
  g_clear_object (&p->conn);
1227
 
 
1228
 
  /* clear the serialized icon cache */
1229
 
  g_clear_pointer (&p->alert_icon_serialized, g_variant_unref);
1230
 
  g_clear_pointer (&p->default_icon_serialized, g_variant_unref);
1231
 
 
1232
 
  G_OBJECT_CLASS (indicator_session_service_parent_class)->dispose (o);
1233
 
}
1234
 
 
1235
 
static void
1236
 
/* cppcheck-suppress unusedFunction */
1237
 
indicator_session_service_class_init (IndicatorSessionServiceClass * klass)
1238
 
{
1239
 
  GObjectClass * object_class = G_OBJECT_CLASS (klass);
1240
 
 
1241
 
  object_class->dispose = my_dispose;
1242
 
  object_class->get_property = my_get_property;
1243
 
  object_class->set_property = my_set_property;
1244
 
 
1245
 
  g_type_class_add_private (klass, sizeof (IndicatorSessionServicePrivate));
1246
 
 
1247
 
  signals[NAME_LOST] = g_signal_new (INDICATOR_SESSION_SERVICE_SIGNAL_NAME_LOST,
1248
 
                                     G_TYPE_FROM_CLASS(klass),
1249
 
                                     G_SIGNAL_RUN_LAST,
1250
 
                                     G_STRUCT_OFFSET (IndicatorSessionServiceClass, name_lost),
1251
 
                                     NULL, NULL,
1252
 
                                     g_cclosure_marshal_VOID__VOID,
1253
 
                                     G_TYPE_NONE, 0);
1254
 
 
1255
 
  properties[PROP_0] = NULL;
1256
 
 
1257
 
  properties[PROP_MAX_USERS] = g_param_spec_uint ("max-users",
1258
 
                                                  "Max Users",
1259
 
                                                  "Max visible users",
1260
 
                                                  0, INT_MAX, 12,
1261
 
                                                  G_PARAM_READWRITE |
1262
 
                                                  G_PARAM_CONSTRUCT |
1263
 
                                                  G_PARAM_STATIC_STRINGS);
1264
 
 
1265
 
  g_object_class_install_properties (object_class, PROP_LAST, properties);
1266
 
}
1267
 
 
1268
 
IndicatorSessionService *
1269
 
indicator_session_service_new (void)
1270
 
{
1271
 
  GObject * o = g_object_new (INDICATOR_TYPE_SESSION_SERVICE, NULL);
1272
 
 
1273
 
  return INDICATOR_SESSION_SERVICE (o);
1274
 
}