~codygarver/+junk/ind-sess

« back to all changes in this revision

Viewing changes to src/service.c

  • Committer: Cody Garver
  • Date: 2014-04-03 17:08:08 UTC
  • Revision ID: cody@elementaryos.org-20140403170808-z56s93rorb1dzvmk
Initial import, version 12.10.5+14.04.20140324-0ubuntu1

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