2
* Copyright 2013 Canonical Ltd.
5
* Charles Kerr <charles.kerr@canonical.com>
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.
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.
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/>.
20
#include <glib/gi18n.h>
26
#define BUS_NAME "com.canonical.indicator.session"
27
#define BUS_PATH "/com/canonical/indicator/session"
29
#define ICON_DEFAULT "system-devices-panel"
30
#define ICON_INFO "system-devices-panel-information"
31
#define ICON_ALERT "system-devices-panel-alert"
33
G_DEFINE_TYPE (IndicatorSessionService,
34
indicator_session_service,
44
static guint signals[LAST_SIGNAL] = { 0 };
53
static GParamSpec * properties[PROP_LAST];
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)
72
static const char * const menu_names[N_PROFILES] =
78
struct ProfileMenuInfo
80
/* the root level -- the header is the only child of this */
83
/* parent of the sections. This is the header's submenu */
89
struct _IndicatorSessionServicePrivate
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;
107
GDBusConnection * conn;
108
GCancellable * cancellable;
110
/* serialized icon cache */
111
GVariant * alert_icon_serialized;
112
GVariant * default_icon_serialized;
115
typedef IndicatorSessionServicePrivate priv_t;
117
static const char * get_current_real_name (IndicatorSessionService * self);
123
static void rebuild_now (IndicatorSessionService * self, int section);
124
static void rebuild_soon (IndicatorSessionService * self, int section);
127
rebuild_header_soon (IndicatorSessionService * self)
129
rebuild_soon (self, SECTION_HEADER);
132
rebuild_switch_section_soon (IndicatorSessionService * self)
134
rebuild_soon (self, SECTION_SWITCH);
137
rebuild_logout_section_soon (IndicatorSessionService * self)
139
rebuild_soon (self, SECTION_LOGOUT);
142
rebuild_session_section_soon (IndicatorSessionService * self)
144
rebuild_soon (self, SECTION_SESSION);
147
rebuild_settings_section_soon (IndicatorSessionService * self)
149
rebuild_soon (self, SECTION_SETTINGS);
157
action_state_for_header (IndicatorSessionService * self)
159
const priv_t * const p = self->priv;
161
GVariant * serialized_icon;
163
const gchar * real_name;
169
if (indicator_session_actions_has_online_account_error (p->backend_actions))
172
serialized_icon = p->alert_icon_serialized;
177
serialized_icon = p->default_icon_serialized;
180
show_name = g_settings_get_boolean (p->indicator_settings,
181
"show-real-name-on-panel");
183
real_name = get_current_real_name (self);
184
label = show_name && real_name ? real_name : "";
186
if (*label && need_attn)
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);
194
/* Translators: the name of the menu ("System"), then the user's name */
195
a11y = g_strdup_printf (_("System, %s"), label);
199
a11y = g_strdup (_("System (Attention Required)"));
203
a11y = g_strdup (_("System"));
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);
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);
223
update_header_action (IndicatorSessionService * self)
225
g_simple_action_set_state (self->priv->header_action, action_state_for_header (self));
232
static GMenuModel * create_switch_section (IndicatorSessionService * self);
235
add_user (IndicatorSessionService * self, guint uid)
237
IndicatorSessionUser * u;
239
if ((u = indicator_session_users_get_user (self->priv->backend_users, uid)))
241
/* update our user table */
242
g_hash_table_insert (self->priv->users, GUINT_TO_POINTER(uid), u);
244
/* queue rebuilds for the affected sections */
245
rebuild_switch_section_soon (self);
246
if (u->is_current_user)
247
rebuild_header_soon (self);
252
on_user_added (IndicatorSessionUsers * backend_users G_GNUC_UNUSED,
256
add_user (INDICATOR_SESSION_SERVICE(gself), uid);
260
on_user_changed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED,
264
add_user (INDICATOR_SESSION_SERVICE(gself), uid);
268
on_user_removed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED,
272
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (gself);
273
g_return_if_fail (self != NULL);
275
/* update our user table */
276
g_hash_table_remove (self->priv->users, GUINT_TO_POINTER(uid));
278
/* enqueue rebuilds for the affected sections */
279
rebuild_switch_section_soon (self);
283
get_user_label (const IndicatorSessionUser * user)
287
/* If blank or whitespace, use username instead */
288
for (c = user->real_name; *c != '\0' && g_ascii_isspace (*c); c++);
290
return user->user_name;
292
return user->real_name;
296
get_current_real_name (IndicatorSessionService * self)
301
/* is it the guest? */
302
if (indicator_session_guest_is_active (self->priv->backend_guest))
306
g_hash_table_iter_init (&iter, self->priv->users);
307
while (g_hash_table_iter_next (&iter, &key, &value))
309
IndicatorSessionUser * user = value;
310
if (user->is_current_user)
311
return get_user_label (user);
322
create_admin_section (void)
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);
333
create_settings_section (IndicatorSessionService * self)
336
priv_t * p = self->priv;
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");
343
return G_MENU_MODEL (menu);
347
* The switch-to-guest action's state is a dictionary with these entries:
348
* - "is-active" (boolean)
349
* - "is-logged-in" (boolean)
352
create_guest_switcher_state (IndicatorSessionService * self)
356
IndicatorSessionGuest * const g = self->priv->backend_guest;
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);
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)
372
create_user_switcher_state (IndicatorSessionService * self)
377
GHashTableIter ht_iter;
379
const char * 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))
386
const IndicatorSessionUser * u = ht_value;
388
if (u->is_current_user)
389
current_user = u->user_name;
392
g_variant_builder_add (&a, "s", u->user_name);
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);
404
update_switch_actions (IndicatorSessionService * self)
406
g_simple_action_set_state (self->priv->guest_switcher_action,
407
create_guest_switcher_state (self));
409
g_simple_action_set_state (self->priv->user_switcher_action,
410
create_user_switcher_state (self));
414
use_ellipsis (IndicatorSessionService * self)
416
/* does the backend support confirmation prompts? */
417
if (!indicator_session_actions_can_prompt (self->priv->backend_actions))
420
/* has the user disabled prompts? */
421
if (g_settings_get_boolean (self->priv->indicator_settings,
422
"suppress-logout-restart-shutdown"))
428
/* lower index == more useful.
429
When there are too many users for the menu,
430
we use this to decide which to cull. */
432
compare_users_by_usefulness (gconstpointer ga, gconstpointer gb)
434
const IndicatorSessionUser * a = *(const IndicatorSessionUser**)ga;
435
const IndicatorSessionUser * b = *(const IndicatorSessionUser**)gb;
437
if (a->is_current_user != b->is_current_user)
438
return a->is_current_user ? -1 : 1;
440
if (a->is_logged_in != b->is_logged_in)
441
return a->is_logged_in ? -1 : 1;
443
if (a->login_frequency != b->login_frequency)
444
return a->login_frequency > b->login_frequency ? -1 : 1;
449
/* sorting them for display in the menu */
451
compare_users_by_label (gconstpointer ga, gconstpointer gb)
454
const IndicatorSessionUser * a = *(const IndicatorSessionUser**)ga;
455
const IndicatorSessionUser * b = *(const IndicatorSessionUser**)gb;
457
if ((i = g_strcmp0 (get_user_label (a), get_user_label (b))))
460
return g_strcmp0 (a->user_name, b->user_name);
464
serialize_icon_file (const gchar * filename)
466
GVariant * serialized_icon = NULL;
468
if (filename != NULL)
470
GFile * file = g_file_new_for_path (filename);
471
GIcon * icon = g_file_icon_new (file);
473
serialized_icon = g_icon_serialize (icon);
475
g_object_unref (icon);
476
g_object_unref (file);
479
return serialized_icon;
483
create_switch_section (IndicatorSessionService * self)
492
const priv_t * const p = self->priv;
493
const gboolean ellipsis = use_ellipsis (self);
495
menu = g_menu_new ();
498
if (indicator_session_users_is_live_session (p->backend_users))
500
const char * action = "indicator.switch-to-screensaver";
501
item = g_menu_item_new (_("Start Screen Saver"), action);
503
else if (indicator_session_guest_is_active (p->backend_guest))
505
const char * action = "indicator.switch-to-greeter";
506
item = g_menu_item_new (ellipsis ? _("Switch Account…")
507
: _("Switch Account"), action);
511
const char * action = "indicator.switch-to-screensaver";
513
if (g_hash_table_size (p->users) == 1)
514
item = g_menu_item_new (_("Lock"), action);
516
item = g_menu_item_new (ellipsis ? _("Lock/Switch Account…")
517
: _("Lock/Switch Account"), action);
519
str = g_settings_get_string (p->keybinding_settings, "screensaver");
520
g_menu_item_set_attribute (item, "accel", "s", str);
522
g_menu_append_item (menu, item);
523
g_object_unref (item);
525
if (indicator_session_guest_is_allowed (p->backend_guest))
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);
533
g_object_unref (item);
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);
542
/* if there are too many users, cull out the less interesting ones */
543
if (users->len > p->max_users)
545
g_ptr_array_sort (users, compare_users_by_usefulness);
546
g_ptr_array_set_size (users, p->max_users);
549
/* sort the users by name */
550
g_ptr_array_sort (users, compare_users_by_label);
553
for (i=0; i<users->len; ++i)
555
const IndicatorSessionUser * u = g_ptr_array_index (users, i);
556
GVariant * serialized_icon;
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");
562
if ((serialized_icon = serialize_icon_file (u->icon_file)))
564
g_menu_item_set_attribute_value (item, G_MENU_ATTRIBUTE_ICON, serialized_icon);
565
g_variant_unref (serialized_icon);
568
g_menu_append_item (menu, item);
569
g_object_unref (item);
573
g_ptr_array_free (users, TRUE);
574
return G_MENU_MODEL (menu);
578
create_logout_section (IndicatorSessionService * self)
581
const priv_t * const p = self->priv;
582
const gboolean ellipsis = use_ellipsis (self);
584
menu = g_menu_new ();
586
if (indicator_session_actions_can_logout (p->backend_actions))
588
const char * label = ellipsis ? _("Log Out…") : _("Log Out");
589
g_menu_append (menu, label, "indicator.logout");
592
return G_MENU_MODEL (menu);
596
create_session_section (IndicatorSessionService * self)
599
const priv_t * const p = self->priv;
600
GSettings * const s = p->indicator_settings;
601
const gboolean ellipsis = use_ellipsis (self);
603
menu = g_menu_new ();
605
if (indicator_session_actions_can_suspend (p->backend_actions))
606
g_menu_append (menu, _("Suspend"), "indicator.suspend");
608
if (indicator_session_actions_can_hibernate (p->backend_actions))
609
g_menu_append (menu, _("Hibernate"), "indicator.hibernate");
611
if (indicator_session_actions_can_reboot (p->backend_actions))
613
const char * label = ellipsis ? _("Restart…") : _("Restart");
614
g_menu_append (menu, label, "indicator.reboot");
617
if (!g_settings_get_boolean (s, "suppress-shutdown-menuitem"))
619
const char * label = ellipsis ? _("Shut Down…") : _("Shut Down");
620
g_menu_append (menu, label, "indicator.power-off");
623
return G_MENU_MODEL (menu);
627
create_menu (IndicatorSessionService * self, int profile)
632
GMenuModel * sections[16];
636
g_assert (0<=profile && profile<N_PROFILES);
637
g_assert (self->priv->menus[profile].menu == NULL);
639
if (profile == PROFILE_DESKTOP)
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);
647
else if (profile == PROFILE_GREETER)
649
sections[n++] = create_session_section (self);
652
/* add sections to the submenu */
653
submenu = g_menu_new ();
656
g_menu_append_section (submenu, NULL, sections[i]);
657
g_object_unref (sections[i]);
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);
666
/* add header to the menu */
667
menu = g_menu_new ();
668
g_menu_append_item (menu, header);
669
g_object_unref (header);
671
self->priv->menus[profile].menu = menu;
672
self->priv->menus[profile].submenu = submenu;
679
static IndicatorSessionActions *
680
get_backend_actions (gpointer gself)
682
return INDICATOR_SESSION_SERVICE(gself)->priv->backend_actions;
686
on_about_activated (GSimpleAction * a G_GNUC_UNUSED,
687
GVariant * param G_GNUC_UNUSED,
690
indicator_session_actions_about (get_backend_actions(gself));
694
on_online_accounts_activated (GSimpleAction * a G_GNUC_UNUSED,
695
GVariant * param G_GNUC_UNUSED,
698
indicator_session_actions_online_accounts (get_backend_actions(gself));
702
on_help_activated (GSimpleAction * a G_GNUC_UNUSED,
703
GVariant * param G_GNUC_UNUSED,
706
indicator_session_actions_help (get_backend_actions(gself));
710
on_settings_activated (GSimpleAction * a G_GNUC_UNUSED,
711
GVariant * param G_GNUC_UNUSED,
714
indicator_session_actions_settings (get_backend_actions(gself));
718
on_logout_activated (GSimpleAction * a G_GNUC_UNUSED,
719
GVariant * param G_GNUC_UNUSED,
722
indicator_session_actions_logout (get_backend_actions(gself));
726
on_suspend_activated (GSimpleAction * a G_GNUC_UNUSED,
727
GVariant * param G_GNUC_UNUSED,
730
indicator_session_actions_suspend (get_backend_actions(gself));
734
on_hibernate_activated (GSimpleAction * a G_GNUC_UNUSED,
735
GVariant * param G_GNUC_UNUSED,
738
indicator_session_actions_hibernate (get_backend_actions(gself));
742
on_reboot_activated (GSimpleAction * action G_GNUC_UNUSED,
743
GVariant * param G_GNUC_UNUSED,
746
indicator_session_actions_reboot (get_backend_actions(gself));
750
on_power_off_activated (GSimpleAction * a G_GNUC_UNUSED,
751
GVariant * param G_GNUC_UNUSED,
754
indicator_session_actions_power_off (get_backend_actions(gself));
758
on_guest_activated (GSimpleAction * a G_GNUC_UNUSED,
759
GVariant * param G_GNUC_UNUSED,
762
indicator_session_actions_switch_to_guest (get_backend_actions(gself));
766
on_screensaver_activated (GSimpleAction * a G_GNUC_UNUSED,
767
GVariant * param G_GNUC_UNUSED,
770
indicator_session_actions_switch_to_screensaver (get_backend_actions(gself));
774
on_greeter_activated (GSimpleAction * a G_GNUC_UNUSED,
775
GVariant * param G_GNUC_UNUSED,
778
indicator_session_actions_switch_to_greeter (get_backend_actions(gself));
782
on_user_activated (GSimpleAction * a G_GNUC_UNUSED,
786
const char * username = g_variant_get_string (param, NULL);
787
indicator_session_actions_switch_to_username (get_backend_actions(gself),
792
init_gactions (IndicatorSessionService * self)
796
priv_t * p = self->priv;
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 }
812
p->actions = g_simple_action_group_new ();
814
g_action_map_add_action_entries (G_ACTION_MAP(p->actions),
816
G_N_ELEMENTS(entries),
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;
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;
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;
839
rebuild_now (self, SECTION_HEADER);
847
* A small helper function for rebuild_now().
848
* - removes the previous section
849
* - adds and unrefs the new section
852
rebuild_section (GMenu * parent, int pos, GMenuModel * new_section)
854
g_menu_remove (parent, pos);
855
g_menu_insert_section (parent, pos, NULL, new_section);
856
g_object_unref (new_section);
860
rebuild_now (IndicatorSessionService * self, int sections)
862
priv_t * p = self->priv;
863
struct ProfileMenuInfo * desktop = &p->menus[PROFILE_DESKTOP];
864
struct ProfileMenuInfo * greeter = &p->menus[PROFILE_GREETER];
866
if (sections & SECTION_HEADER)
868
update_header_action (self);
871
if (sections & SECTION_ADMIN)
873
rebuild_section (desktop->submenu, 0, create_admin_section());
876
if (sections & SECTION_SETTINGS)
878
rebuild_section (desktop->submenu, 1, create_settings_section(self));
881
if (sections & SECTION_SWITCH)
883
rebuild_section (desktop->submenu, 2, create_switch_section(self));
884
update_switch_actions (self);
887
if (sections & SECTION_LOGOUT)
889
rebuild_section (desktop->submenu, 3, create_logout_section(self));
892
if (sections & SECTION_SESSION)
894
rebuild_section (desktop->submenu, 4, create_session_section(self));
895
rebuild_section (greeter->submenu, 0, create_session_section(self));
900
rebuild_timeout_func (IndicatorSessionService * self)
902
priv_t * p = self->priv;
903
rebuild_now (self, p->rebuild_flags);
904
p->rebuild_flags = 0;
906
return G_SOURCE_REMOVE;
910
rebuild_soon (IndicatorSessionService * self, int section)
912
priv_t * p = self->priv;
914
p->rebuild_flags |= section;
916
if (p->rebuild_id == 0)
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;
924
p->rebuild_id = g_timeout_add (REBUILD_INTERVAL_MSEC,
925
(GSourceFunc)rebuild_timeout_func,
935
on_bus_acquired (GDBusConnection * connection,
942
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(gself);
943
priv_t * p = self->priv;
945
g_debug ("bus acquired: %s", name);
947
p->conn = g_object_ref (G_OBJECT (connection));
949
/* export the actions */
950
if ((id = g_dbus_connection_export_action_group (connection,
952
G_ACTION_GROUP (p->actions),
955
p->actions_export_id = id;
959
g_warning ("cannot export action group: %s", err->message);
960
g_clear_error (&err);
963
/* export the menus */
964
for (i=0; i<N_PROFILES; ++i)
966
char * path = g_strdup_printf ("%s/%s", BUS_PATH, menu_names[i]);
967
struct ProfileMenuInfo * menu = &p->menus[i];
969
if (menu->menu == NULL)
970
create_menu (self, i);
972
if ((id = g_dbus_connection_export_menu_model (connection,
974
G_MENU_MODEL (menu->menu),
977
menu->export_id = id;
981
g_warning ("cannot export %s menu: %s", menu_names[i], err->message);
982
g_clear_error (&err);
990
unexport (IndicatorSessionService * self)
993
priv_t * p = self->priv;
995
/* unexport the menus */
996
for (i=0; i<N_PROFILES; ++i)
998
guint * id = &self->priv->menus[i].export_id;
1002
g_dbus_connection_unexport_menu_model (p->conn, *id);
1007
/* unexport the actions */
1008
if (p->actions_export_id)
1010
g_dbus_connection_unexport_action_group (p->conn, p->actions_export_id);
1011
p->actions_export_id = 0;
1016
on_name_lost (GDBusConnection * connection G_GNUC_UNUSED,
1020
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (gself);
1022
g_debug ("%s %s name lost %s", G_STRLOC, G_STRFUNC, name);
1026
g_signal_emit (self, signals[NAME_LOST], 0, NULL);
1034
/* cppcheck-suppress unusedFunction */
1035
indicator_session_service_init (IndicatorSessionService * self)
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");
1051
/* init the backend objects */
1052
p->cancellable = g_cancellable_new ();
1053
backend_get (p->cancellable, &p->backend_actions,
1057
/* build the serialized icon cache */
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);
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);
1067
/* init our key-to-User table */
1068
p->users = g_hash_table_new_full (g_direct_hash,
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));
1077
init_gactions (self);
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);
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);
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);
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);
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);
1128
self->priv->own_id = g_bus_own_name (G_BUS_TYPE_SESSION,
1130
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
1139
**** GObject plumbing: properties
1143
my_get_property (GObject * o,
1148
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (o);
1150
switch (property_id)
1152
case PROP_MAX_USERS:
1153
g_value_set_uint (value, self->priv->max_users);
1157
G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
1162
my_set_property (GObject * o,
1164
const GValue * value,
1167
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (o);
1169
switch (property_id)
1171
case PROP_MAX_USERS:
1172
self->priv->max_users = g_value_get_uint (value);
1173
rebuild_switch_section_soon (self);
1177
G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
1182
**** GObject plumbing: life cycle
1186
my_dispose (GObject * o)
1189
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(o);
1190
priv_t * p = self->priv;
1194
g_bus_unown_name (p->own_id);
1200
if (p->cancellable != NULL)
1202
g_cancellable_cancel (p->cancellable);
1203
g_clear_object (&p->cancellable);
1208
g_source_remove (p->rebuild_id);
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);
1220
for (i=0; i<N_PROFILES; ++i)
1221
g_clear_object (&p->menus[i].menu);
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);
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);
1232
G_OBJECT_CLASS (indicator_session_service_parent_class)->dispose (o);
1236
/* cppcheck-suppress unusedFunction */
1237
indicator_session_service_class_init (IndicatorSessionServiceClass * klass)
1239
GObjectClass * object_class = G_OBJECT_CLASS (klass);
1241
object_class->dispose = my_dispose;
1242
object_class->get_property = my_get_property;
1243
object_class->set_property = my_set_property;
1245
g_type_class_add_private (klass, sizeof (IndicatorSessionServicePrivate));
1247
signals[NAME_LOST] = g_signal_new (INDICATOR_SESSION_SERVICE_SIGNAL_NAME_LOST,
1248
G_TYPE_FROM_CLASS(klass),
1250
G_STRUCT_OFFSET (IndicatorSessionServiceClass, name_lost),
1252
g_cclosure_marshal_VOID__VOID,
1255
properties[PROP_0] = NULL;
1257
properties[PROP_MAX_USERS] = g_param_spec_uint ("max-users",
1259
"Max visible users",
1263
G_PARAM_STATIC_STRINGS);
1265
g_object_class_install_properties (object_class, PROP_LAST, properties);
1268
IndicatorSessionService *
1269
indicator_session_service_new (void)
1271
GObject * o = g_object_new (INDICATOR_TYPE_SESSION_SERVICE, NULL);
1273
return INDICATOR_SESSION_SERVICE (o);