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)
73
static const char * const menu_names[N_PROFILES] =
80
struct ProfileMenuInfo
82
/* the root level -- the header is the only child of this */
85
/* parent of the sections. This is the header's submenu */
91
struct _IndicatorSessionServicePrivate
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;
109
GDBusConnection * conn;
110
GCancellable * cancellable;
111
GVariant * default_icon_serialized;
114
typedef IndicatorSessionServicePrivate priv_t;
116
static const char * get_current_real_name (IndicatorSessionService * self);
122
static void rebuild_now (IndicatorSessionService * self, int section);
123
static void rebuild_soon (IndicatorSessionService * self, int section);
126
rebuild_header_soon (IndicatorSessionService * self)
128
rebuild_soon (self, SECTION_HEADER);
131
rebuild_switch_section_soon (IndicatorSessionService * self)
133
rebuild_soon (self, SECTION_SWITCH);
136
rebuild_logout_section_soon (IndicatorSessionService * self)
138
rebuild_soon (self, SECTION_LOGOUT);
141
rebuild_session_section_soon (IndicatorSessionService * self)
143
rebuild_soon (self, SECTION_SESSION);
146
rebuild_settings_section_soon (IndicatorSessionService * self)
148
rebuild_soon (self, SECTION_SETTINGS);
156
show_user_list (IndicatorSessionService * self)
158
return g_settings_get_boolean (self->priv->indicator_settings,
164
action_state_for_header (IndicatorSessionService * self)
166
const priv_t * const p = self->priv;
168
const gchar * real_name;
174
show_name = g_settings_get_boolean (p->indicator_settings,
175
"show-real-name-on-panel");
177
real_name = get_current_real_name (self);
178
label = show_name && real_name ? real_name : "";
182
/* Translators: the name of the menu ("System"), then the user's name */
183
a11y = g_strdup_printf (_("System, %s"), label);
187
a11y = g_strdup (_("System"));
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);
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);
206
update_header_action (IndicatorSessionService * self)
208
g_simple_action_set_state (self->priv->header_action, action_state_for_header (self));
215
static GMenuModel * create_switch_section (IndicatorSessionService * self, int profile);
218
add_user (IndicatorSessionService * self, guint uid)
220
IndicatorSessionUser * u;
222
if ((u = indicator_session_users_get_user (self->priv->backend_users, uid)))
224
/* update our user table */
225
g_hash_table_insert (self->priv->users, GUINT_TO_POINTER(uid), u);
227
/* queue rebuilds for the affected sections */
228
rebuild_switch_section_soon (self);
229
if (u->is_current_user)
230
rebuild_header_soon (self);
235
on_user_added (IndicatorSessionUsers * backend_users G_GNUC_UNUSED,
239
add_user (INDICATOR_SESSION_SERVICE(gself), uid);
243
on_user_changed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED,
247
add_user (INDICATOR_SESSION_SERVICE(gself), uid);
251
maybe_add_users (IndicatorSessionService * self)
253
if (!show_user_list (self))
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));
266
user_show_menu_changed (IndicatorSessionService * self)
268
if (show_user_list (self))
269
maybe_add_users (self);
271
g_hash_table_remove_all (self->priv->users);
273
rebuild_switch_section_soon (self);
277
on_user_removed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED,
281
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (gself);
282
g_return_if_fail (self != NULL);
284
/* update our user table */
285
g_hash_table_remove (self->priv->users, GUINT_TO_POINTER(uid));
287
/* enqueue rebuilds for the affected sections */
288
rebuild_switch_section_soon (self);
292
get_user_label (const IndicatorSessionUser * user)
296
/* If blank or whitespace, use username instead */
297
for (c = user->real_name; *c != '\0' && g_ascii_isspace (*c); c++);
299
return user->user_name;
301
return user->real_name;
305
get_current_real_name (IndicatorSessionService * self)
310
/* is it the guest? */
311
if (indicator_session_guest_is_active (self->priv->backend_guest))
315
g_hash_table_iter_init (&iter, self->priv->users);
316
while (g_hash_table_iter_next (&iter, &key, &value))
318
IndicatorSessionUser * user = value;
319
if (user->is_current_user)
320
return get_user_label (user);
331
create_admin_section (void)
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);
342
create_settings_section (IndicatorSessionService * self)
345
priv_t * p = self->priv;
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");
352
return G_MENU_MODEL (menu);
356
* The switch-to-guest action's state is a dictionary with these entries:
357
* - "is-active" (boolean)
358
* - "is-logged-in" (boolean)
361
create_guest_switcher_state (IndicatorSessionService * self)
365
IndicatorSessionGuest * const g = self->priv->backend_guest;
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);
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)
381
create_user_switcher_state (IndicatorSessionService * self)
386
GHashTableIter ht_iter;
388
const char * 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))
395
const IndicatorSessionUser * u = ht_value;
397
if (u->is_current_user)
398
current_user = u->user_name;
401
g_variant_builder_add (&a, "s", u->user_name);
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);
413
update_switch_actions (IndicatorSessionService * self)
415
g_simple_action_set_state (self->priv->guest_switcher_action,
416
create_guest_switcher_state (self));
418
g_simple_action_set_state (self->priv->user_switcher_action,
419
create_user_switcher_state (self));
423
use_ellipsis (IndicatorSessionService * self)
425
/* does the backend support confirmation prompts? */
426
if (!indicator_session_actions_can_prompt (self->priv->backend_actions))
429
/* has the user disabled prompts? */
430
if (g_settings_get_boolean (self->priv->indicator_settings,
431
"suppress-logout-restart-shutdown"))
437
/* lower index == more useful.
438
When there are too many users for the menu,
439
we use this to decide which to cull. */
441
compare_users_by_usefulness (gconstpointer ga, gconstpointer gb)
443
const IndicatorSessionUser * a = *(const IndicatorSessionUser**)ga;
444
const IndicatorSessionUser * b = *(const IndicatorSessionUser**)gb;
446
if (a->is_current_user != b->is_current_user)
447
return a->is_current_user ? -1 : 1;
449
if (a->is_logged_in != b->is_logged_in)
450
return a->is_logged_in ? -1 : 1;
452
if (a->login_frequency != b->login_frequency)
453
return a->login_frequency > b->login_frequency ? -1 : 1;
458
/* sorting them for display in the menu */
460
compare_users_by_label (gconstpointer ga, gconstpointer gb)
463
const IndicatorSessionUser * a = *(const IndicatorSessionUser**)ga;
464
const IndicatorSessionUser * b = *(const IndicatorSessionUser**)gb;
466
if ((i = g_strcmp0 (get_user_label (a), get_user_label (b))))
469
return g_strcmp0 (a->user_name, b->user_name);
473
serialize_icon_file (const gchar * filename)
475
GVariant * serialized_icon = NULL;
477
if (filename != NULL)
479
GFile * file = g_file_new_for_path (filename);
480
GIcon * icon = g_file_icon_new (file);
482
serialized_icon = g_icon_serialize (icon);
484
g_object_unref (icon);
485
g_object_unref (file);
488
return serialized_icon;
492
create_switch_section (IndicatorSessionService * self, int profile)
501
const priv_t * const p = self->priv;
502
const gboolean ellipsis = use_ellipsis (self);
504
menu = g_menu_new ();
507
if (indicator_session_users_is_live_session (p->backend_users))
509
const char * action = "indicator.switch-to-screensaver";
510
item = g_menu_item_new (_("Start Screen Saver"), action);
513
else if (profile == PROFILE_LOCKSCREEN ||
514
indicator_session_guest_is_active (p->backend_guest))
516
const char * action = "indicator.switch-to-greeter";
517
item = g_menu_item_new (ellipsis ? _("Switch Account…")
518
: _("Switch Account"), action);
523
const char * action = "indicator.switch-to-screensaver";
525
if (g_hash_table_size (p->users) == 1)
526
item = g_menu_item_new (_("Lock"), action);
528
item = g_menu_item_new (ellipsis ? _("Lock/Switch Account…")
529
: _("Lock/Switch Account"), action);
536
gchar * str = g_settings_get_string (p->keybinding_settings, "screensaver");
537
g_menu_item_set_attribute (item, "accel", "s", str);
541
g_menu_append_item (menu, item);
542
g_object_unref (item);
544
if (indicator_session_guest_is_allowed (p->backend_guest))
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);
552
g_object_unref (item);
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);
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);
565
/* if there are too many users, cull out the less interesting ones */
566
if (users->len > p->max_users)
568
g_ptr_array_sort (users, compare_users_by_usefulness);
569
g_ptr_array_set_size (users, p->max_users);
572
/* sort the users by name */
573
g_ptr_array_sort (users, compare_users_by_label);
576
for (i=0; i<users->len; ++i)
578
const IndicatorSessionUser * u = g_ptr_array_index (users, i);
579
GVariant * serialized_icon;
581
if (profile == PROFILE_LOCKSCREEN && u->is_current_user)
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");
588
if ((serialized_icon = serialize_icon_file (u->icon_file)))
590
g_menu_item_set_attribute_value (item, G_MENU_ATTRIBUTE_ICON, serialized_icon);
591
g_variant_unref (serialized_icon);
594
g_menu_append_item (menu, item);
595
g_object_unref (item);
599
g_ptr_array_free (users, TRUE);
600
return G_MENU_MODEL (menu);
604
create_logout_section (IndicatorSessionService * self)
607
const priv_t * const p = self->priv;
608
const gboolean ellipsis = use_ellipsis (self);
610
menu = g_menu_new ();
612
if (indicator_session_actions_can_logout (p->backend_actions))
614
const char * label = ellipsis ? _("Log Out…") : _("Log Out");
615
g_menu_append (menu, label, "indicator.logout");
618
return G_MENU_MODEL (menu);
622
create_session_section (IndicatorSessionService * self)
625
const priv_t * const p = self->priv;
626
GSettings * const s = p->indicator_settings;
627
const gboolean ellipsis = use_ellipsis (self);
629
menu = g_menu_new ();
631
if (indicator_session_actions_can_suspend (p->backend_actions))
632
g_menu_append (menu, _("Suspend"), "indicator.suspend");
634
if (indicator_session_actions_can_hibernate (p->backend_actions))
635
g_menu_append (menu, _("Hibernate"), "indicator.hibernate");
637
if (indicator_session_actions_can_reboot (p->backend_actions))
639
const char * label = ellipsis ? _("Restart…") : _("Restart");
640
g_menu_append (menu, label, "indicator.reboot");
643
if (!g_settings_get_boolean (s, "suppress-shutdown-menuitem"))
645
const char * label = ellipsis ? _("Shut Down…") : _("Shut Down");
646
g_menu_append (menu, label, "indicator.power-off");
649
return G_MENU_MODEL (menu);
653
create_menu (IndicatorSessionService * self, int profile)
658
GMenuModel * sections[16];
662
g_assert (0<=profile && profile<N_PROFILES);
663
g_assert (self->priv->menus[profile].menu == NULL);
665
if (profile == PROFILE_DESKTOP)
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);
673
else if (profile == PROFILE_GREETER)
675
sections[n++] = create_session_section (self);
677
else if (profile == PROFILE_LOCKSCREEN)
679
sections[n++] = create_switch_section (self, profile);
680
sections[n++] = create_session_section (self);
683
/* add sections to the submenu */
684
submenu = g_menu_new ();
687
g_menu_append_section (submenu, NULL, sections[i]);
688
g_object_unref (sections[i]);
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);
697
/* add header to the menu */
698
menu = g_menu_new ();
699
g_menu_append_item (menu, header);
700
g_object_unref (header);
702
self->priv->menus[profile].menu = menu;
703
self->priv->menus[profile].submenu = submenu;
710
static IndicatorSessionActions *
711
get_backend_actions (gpointer gself)
713
return INDICATOR_SESSION_SERVICE(gself)->priv->backend_actions;
717
on_about_activated (GSimpleAction * a G_GNUC_UNUSED,
718
GVariant * param G_GNUC_UNUSED,
721
indicator_session_actions_about (get_backend_actions(gself));
725
on_online_accounts_activated (GSimpleAction * a G_GNUC_UNUSED,
726
GVariant * param G_GNUC_UNUSED,
729
indicator_session_actions_online_accounts (get_backend_actions(gself));
733
on_help_activated (GSimpleAction * a G_GNUC_UNUSED,
734
GVariant * param G_GNUC_UNUSED,
737
indicator_session_actions_help (get_backend_actions(gself));
741
on_settings_activated (GSimpleAction * a G_GNUC_UNUSED,
742
GVariant * param G_GNUC_UNUSED,
745
indicator_session_actions_settings (get_backend_actions(gself));
749
on_logout_activated (GSimpleAction * a G_GNUC_UNUSED,
750
GVariant * param G_GNUC_UNUSED,
753
indicator_session_actions_logout (get_backend_actions(gself));
757
on_suspend_activated (GSimpleAction * a G_GNUC_UNUSED,
758
GVariant * param G_GNUC_UNUSED,
761
indicator_session_actions_suspend (get_backend_actions(gself));
765
on_hibernate_activated (GSimpleAction * a G_GNUC_UNUSED,
766
GVariant * param G_GNUC_UNUSED,
769
indicator_session_actions_hibernate (get_backend_actions(gself));
773
on_reboot_activated (GSimpleAction * action G_GNUC_UNUSED,
774
GVariant * param G_GNUC_UNUSED,
777
indicator_session_actions_reboot (get_backend_actions(gself));
781
on_power_off_activated (GSimpleAction * a G_GNUC_UNUSED,
782
GVariant * param G_GNUC_UNUSED,
785
indicator_session_actions_power_off (get_backend_actions(gself));
789
on_guest_activated (GSimpleAction * a G_GNUC_UNUSED,
790
GVariant * param G_GNUC_UNUSED,
793
indicator_session_actions_switch_to_guest (get_backend_actions(gself));
797
on_screensaver_activated (GSimpleAction * a G_GNUC_UNUSED,
798
GVariant * param G_GNUC_UNUSED,
801
indicator_session_actions_switch_to_screensaver (get_backend_actions(gself));
805
on_greeter_activated (GSimpleAction * a G_GNUC_UNUSED,
806
GVariant * param G_GNUC_UNUSED,
809
indicator_session_actions_switch_to_greeter (get_backend_actions(gself));
813
on_user_activated (GSimpleAction * a G_GNUC_UNUSED,
817
const char * username = g_variant_get_string (param, NULL);
818
indicator_session_actions_switch_to_username (get_backend_actions(gself),
823
init_gactions (IndicatorSessionService * self)
827
priv_t * p = self->priv;
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 }
843
p->actions = g_simple_action_group_new ();
845
g_action_map_add_action_entries (G_ACTION_MAP(p->actions),
847
G_N_ELEMENTS(entries),
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;
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;
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;
870
rebuild_now (self, SECTION_HEADER);
878
* A small helper function for rebuild_now().
879
* - removes the previous section
880
* - adds and unrefs the new section
883
rebuild_section (GMenu * parent, int pos, GMenuModel * new_section)
885
g_menu_remove (parent, pos);
886
g_menu_insert_section (parent, pos, NULL, new_section);
887
g_object_unref (new_section);
891
rebuild_now (IndicatorSessionService * self, int sections)
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];
898
if (sections & SECTION_HEADER)
900
update_header_action (self);
903
if (sections & SECTION_ADMIN)
905
rebuild_section (desktop->submenu, 0, create_admin_section());
908
if (sections & SECTION_SETTINGS)
910
rebuild_section (desktop->submenu, 1, create_settings_section(self));
913
if (sections & SECTION_SWITCH)
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);
920
if (sections & SECTION_LOGOUT)
922
rebuild_section (desktop->submenu, 3, create_logout_section(self));
925
if (sections & SECTION_SESSION)
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));
934
rebuild_timeout_func (IndicatorSessionService * self)
936
priv_t * p = self->priv;
937
rebuild_now (self, p->rebuild_flags);
938
p->rebuild_flags = 0;
940
return G_SOURCE_REMOVE;
944
rebuild_soon (IndicatorSessionService * self, int section)
946
priv_t * p = self->priv;
948
p->rebuild_flags |= section;
950
if (p->rebuild_id == 0)
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;
958
p->rebuild_id = g_timeout_add (REBUILD_INTERVAL_MSEC,
959
(GSourceFunc)rebuild_timeout_func,
969
on_bus_acquired (GDBusConnection * connection,
976
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(gself);
977
priv_t * p = self->priv;
979
g_debug ("bus acquired: %s", name);
981
p->conn = g_object_ref (G_OBJECT (connection));
983
/* export the actions */
984
if ((id = g_dbus_connection_export_action_group (connection,
986
G_ACTION_GROUP (p->actions),
989
p->actions_export_id = id;
993
g_warning ("cannot export action group: %s", err->message);
994
g_clear_error (&err);
997
/* export the menus */
998
for (i=0; i<N_PROFILES; ++i)
1000
char * path = g_strdup_printf ("%s/%s", BUS_PATH, menu_names[i]);
1001
struct ProfileMenuInfo * menu = &p->menus[i];
1003
if (menu->menu == NULL)
1004
create_menu (self, i);
1006
if ((id = g_dbus_connection_export_menu_model (connection,
1008
G_MENU_MODEL (menu->menu),
1011
menu->export_id = id;
1015
g_warning ("cannot export %s menu: %s", menu_names[i], err->message);
1016
g_clear_error (&err);
1024
unexport (IndicatorSessionService * self)
1027
priv_t * p = self->priv;
1029
/* unexport the menus */
1030
for (i=0; i<N_PROFILES; ++i)
1032
guint * id = &self->priv->menus[i].export_id;
1036
g_dbus_connection_unexport_menu_model (p->conn, *id);
1041
/* unexport the actions */
1042
if (p->actions_export_id)
1044
g_dbus_connection_unexport_action_group (p->conn, p->actions_export_id);
1045
p->actions_export_id = 0;
1050
on_name_lost (GDBusConnection * connection G_GNUC_UNUSED,
1054
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (gself);
1056
g_debug ("%s %s name lost %s", G_STRLOC, G_STRFUNC, name);
1060
g_signal_emit (self, signals[NAME_LOST], 0, NULL);
1068
/* cppcheck-suppress unusedFunction */
1069
indicator_session_service_init (IndicatorSessionService * self)
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");
1083
/* init the backend objects */
1084
p->cancellable = g_cancellable_new ();
1085
backend_get (p->cancellable, &p->backend_actions,
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);
1093
/* init our key-to-User table */
1094
p->users = g_hash_table_new_full (g_direct_hash,
1097
(GDestroyNotify)indicator_session_user_free);
1098
maybe_add_users (self);
1100
init_gactions (self);
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);
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);
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);
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);
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);
1153
self->priv->own_id = g_bus_own_name (G_BUS_TYPE_SESSION,
1155
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
1164
**** GObject plumbing: properties
1168
my_get_property (GObject * o,
1173
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (o);
1175
switch (property_id)
1177
case PROP_MAX_USERS:
1178
g_value_set_uint (value, self->priv->max_users);
1182
G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
1187
my_set_property (GObject * o,
1189
const GValue * value,
1192
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (o);
1194
switch (property_id)
1196
case PROP_MAX_USERS:
1197
self->priv->max_users = g_value_get_uint (value);
1198
rebuild_switch_section_soon (self);
1202
G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
1207
**** GObject plumbing: life cycle
1211
my_dispose (GObject * o)
1214
IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(o);
1215
priv_t * p = self->priv;
1219
g_bus_unown_name (p->own_id);
1225
if (p->cancellable != NULL)
1227
g_cancellable_cancel (p->cancellable);
1228
g_clear_object (&p->cancellable);
1233
g_source_remove (p->rebuild_id);
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);
1245
for (i=0; i<N_PROFILES; ++i)
1246
g_clear_object (&p->menus[i].menu);
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);
1253
g_clear_pointer (&p->default_icon_serialized, g_variant_unref);
1255
G_OBJECT_CLASS (indicator_session_service_parent_class)->dispose (o);
1259
/* cppcheck-suppress unusedFunction */
1260
indicator_session_service_class_init (IndicatorSessionServiceClass * klass)
1262
GObjectClass * object_class = G_OBJECT_CLASS (klass);
1264
object_class->dispose = my_dispose;
1265
object_class->get_property = my_get_property;
1266
object_class->set_property = my_set_property;
1268
g_type_class_add_private (klass, sizeof (IndicatorSessionServicePrivate));
1270
signals[NAME_LOST] = g_signal_new (INDICATOR_SESSION_SERVICE_SIGNAL_NAME_LOST,
1271
G_TYPE_FROM_CLASS(klass),
1273
G_STRUCT_OFFSET (IndicatorSessionServiceClass, name_lost),
1275
g_cclosure_marshal_VOID__VOID,
1278
properties[PROP_0] = NULL;
1280
properties[PROP_MAX_USERS] = g_param_spec_uint ("max-users",
1282
"Max visible users",
1286
G_PARAM_STATIC_STRINGS);
1288
g_object_class_install_properties (object_class, PROP_LAST, properties);
1291
IndicatorSessionService *
1292
indicator_session_service_new (void)
1294
GObject * o = g_object_new (INDICATOR_TYPE_SESSION_SERVICE, NULL);
1296
return INDICATOR_SESSION_SERVICE (o);