From ae39f7001e5603010afc02de29787ade6d48ef14 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 22 Mar 2013 16:34:34 -0500 Subject: port indicator-session to GMenu/cmake. Code coverage increased from 0% to 95.4%. --- src/CMakeLists.txt | 19 + src/Makefile.am | 207 ---- src/actions.c | 383 ++++++ src/actions.h | 129 ++ src/backend-dbus/CMakeLists.txt | 86 ++ src/backend-dbus/actions.c | 730 ++++++++++++ src/backend-dbus/actions.h | 73 ++ src/backend-dbus/backend-dbus.c | 117 ++ src/backend-dbus/backend-dbus.h | 38 + .../com.canonical.indicators.webcredentials.xml | 82 ++ src/backend-dbus/display-manager.xml | 30 + src/backend-dbus/guest.c | 570 +++++++++ src/backend-dbus/guest.h | 72 ++ src/backend-dbus/org.freedesktop.Accounts.User.xml | 744 ++++++++++++ src/backend-dbus/org.freedesktop.Accounts.xml | 194 ++++ .../org.freedesktop.ConsoleKit.Manager.xml | 353 ++++++ .../org.freedesktop.ConsoleKit.Seat.xml | 164 +++ .../org.freedesktop.ConsoleKit.Session.xml | 435 +++++++ src/backend-dbus/org.gnome.ScreenSaver.xml | 16 + .../org.gnome.SessionManager.EndSessionDialog.xml | 53 + src/backend-dbus/org.gnome.SessionManager.xml | 451 +++++++ src/backend-dbus/session-dbus.xml | 20 + src/backend-dbus/upower.xml | 309 +++++ src/backend-dbus/users.c | 810 +++++++++++++ src/backend-dbus/users.h | 71 ++ src/backend-dbus/utils.c | 399 +++++++ src/backend-dbus/utils.h | 53 + src/backend.h | 47 + src/dialog.c | 248 ---- src/dialog.h | 64 - src/display-manager.xml | 30 - src/gtk-logout-helper.c | 266 ----- src/guest.c | 190 +++ src/guest.h | 82 ++ src/indicator-session.c | 495 -------- src/main.c | 87 ++ src/online-accounts-mgr.c | 166 --- src/online-accounts-mgr.h | 50 - src/org.freedesktop.Accounts.User.xml | 744 ------------ src/org.freedesktop.Accounts.xml | 194 ---- src/org.freedesktop.ConsoleKit.Manager.xml | 353 ------ src/org.freedesktop.ConsoleKit.Seat.xml | 164 --- src/org.freedesktop.ConsoleKit.Session.xml | 435 ------- src/service.c | 1192 +++++++++++++++++++ src/service.h | 64 + src/session-dbus.c | 282 ----- src/session-dbus.h | 56 - src/session-dbus.xml | 20 - src/session-menu-mgr.c | 1226 -------------------- src/session-menu-mgr.h | 55 - src/session-service.c | 96 -- src/shared-names.h | 52 - src/upower.xml | 309 ----- src/user-widget.c | 292 ----- src/user-widget.h | 55 - src/users-service-dbus.c | 1044 ----------------- src/users-service-dbus.h | 97 -- src/users.c | 198 ++++ src/users.h | 146 +++ 59 files changed, 8407 insertions(+), 7000 deletions(-) create mode 100644 src/CMakeLists.txt delete mode 100644 src/Makefile.am create mode 100644 src/actions.c create mode 100644 src/actions.h create mode 100644 src/backend-dbus/CMakeLists.txt create mode 100644 src/backend-dbus/actions.c create mode 100644 src/backend-dbus/actions.h create mode 100644 src/backend-dbus/backend-dbus.c create mode 100644 src/backend-dbus/backend-dbus.h create mode 100644 src/backend-dbus/com.canonical.indicators.webcredentials.xml create mode 100644 src/backend-dbus/display-manager.xml create mode 100644 src/backend-dbus/guest.c create mode 100644 src/backend-dbus/guest.h create mode 100644 src/backend-dbus/org.freedesktop.Accounts.User.xml create mode 100644 src/backend-dbus/org.freedesktop.Accounts.xml create mode 100644 src/backend-dbus/org.freedesktop.ConsoleKit.Manager.xml create mode 100644 src/backend-dbus/org.freedesktop.ConsoleKit.Seat.xml create mode 100644 src/backend-dbus/org.freedesktop.ConsoleKit.Session.xml create mode 100644 src/backend-dbus/org.gnome.ScreenSaver.xml create mode 100644 src/backend-dbus/org.gnome.SessionManager.EndSessionDialog.xml create mode 100644 src/backend-dbus/org.gnome.SessionManager.xml create mode 100644 src/backend-dbus/session-dbus.xml create mode 100644 src/backend-dbus/upower.xml create mode 100644 src/backend-dbus/users.c create mode 100644 src/backend-dbus/users.h create mode 100644 src/backend-dbus/utils.c create mode 100644 src/backend-dbus/utils.h create mode 100644 src/backend.h delete mode 100644 src/dialog.c delete mode 100644 src/dialog.h delete mode 100644 src/display-manager.xml delete mode 100644 src/gtk-logout-helper.c create mode 100644 src/guest.c create mode 100644 src/guest.h delete mode 100644 src/indicator-session.c create mode 100644 src/main.c delete mode 100644 src/online-accounts-mgr.c delete mode 100644 src/online-accounts-mgr.h delete mode 100644 src/org.freedesktop.Accounts.User.xml delete mode 100644 src/org.freedesktop.Accounts.xml delete mode 100644 src/org.freedesktop.ConsoleKit.Manager.xml delete mode 100644 src/org.freedesktop.ConsoleKit.Seat.xml delete mode 100644 src/org.freedesktop.ConsoleKit.Session.xml create mode 100644 src/service.c create mode 100644 src/service.h delete mode 100644 src/session-dbus.c delete mode 100644 src/session-dbus.h delete mode 100644 src/session-dbus.xml delete mode 100644 src/session-menu-mgr.c delete mode 100644 src/session-menu-mgr.h delete mode 100644 src/session-service.c delete mode 100644 src/shared-names.h delete mode 100644 src/upower.xml delete mode 100644 src/user-widget.c delete mode 100644 src/user-widget.h delete mode 100644 src/users-service-dbus.c delete mode 100644 src/users-service-dbus.h create mode 100644 src/users.c create mode 100644 src/users.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..efa704c --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,19 @@ +add_subdirectory (backend-dbus) + +add_library (libindicatorsessionservice STATIC + actions.c + actions.h + guest.c + guest.h + service.c + service.h + users.c + users.h) +set_target_properties (libindicatorsessionservice PROPERTIES COMPILE_FLAGS " -g ${CC_WARNING_ARGS} ${GCOV_FLAGS}") + +include_directories(${SERVICE_INCLUDE_DIRS}) +link_directories(${SERVICE_LIBRARY_DIRS}) + +add_executable (indicator-session-service main.c) +target_link_libraries (indicator-session-service libindicatorsessionservice backenddbus ${SERVICE_LIBRARIES} ${GCOV_LIBS}) + diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index bcc8652..0000000 --- a/src/Makefile.am +++ /dev/null @@ -1,207 +0,0 @@ -CLEANFILES = -EXTRA_DIST = - -libexec_PROGRAMS = \ - indicator-session-service - -if BUILD_GTKLOGOUTHELPER -libexec_PROGRAMS += \ - gtk-logout-helper -endif - -################### -# Indicator Stuff -################### - -CLEANFILES += .libs/*.gcda .libs/*.gcno *.gcda *.gcno - -sessionlibdir = $(INDICATORDIR) -sessionlib_LTLIBRARIES = libsession.la -libsession_la_SOURCES = \ - indicator-session.c \ - gen-session-dbus.xml.h \ - shared-names.h \ - user-widget.c \ - user-widget.h -libsession_la_CFLAGS = \ - $(APPLET_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - -Wall -Wunused \ - -DG_LOG_DOMAIN=\"Indicator-Session\" -libsession_la_LIBADD = $(APPLET_LIBS) -libsession_la_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - -module -avoid-version - -dbus_display_manager_sources = \ - dbus-display-manager.c \ - dbus-display-manager.h - -$(dbus_display_manager_sources): display-manager.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-display-manager \ - $^ - -dbus_consolekit_manager_sources = \ - dbus-consolekit-manager.c \ - dbus-consolekit-manager.h - -$(dbus_consolekit_manager_sources): org.freedesktop.ConsoleKit.Manager.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-consolekit-manager \ - $^ - -dbus_consolekit_seat_sources = \ - dbus-consolekit-seat.c \ - dbus-consolekit-seat.h - -$(dbus_consolekit_seat_sources): org.freedesktop.ConsoleKit.Seat.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-consolekit-seat \ - $^ - -dbus_consolekit_session_sources = \ - dbus-consolekit-session.c \ - dbus-consolekit-session.h - -$(dbus_consolekit_session_sources): org.freedesktop.ConsoleKit.Session.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-consolekit-session \ - $^ - -dbus_accounts_sources = \ - dbus-accounts.c \ - dbus-accounts.h - -$(dbus_accounts_sources): org.freedesktop.Accounts.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-accounts \ - $^ - -dbus_user_sources = \ - dbus-user.c \ - dbus-user.h - -$(dbus_user_sources): org.freedesktop.Accounts.User.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-user \ - $^ - -dbus_upower_sources = \ - dbus-upower.c \ - dbus-upower.h - -$(dbus_upower_sources): upower.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-upower \ - --c-namespace DBus \ - $^ - -gen-%.xml.c: %.xml - @echo "Building $@ from $<" - @echo "const char * _$(subst -,_,$(subst .,_,$(basename $(notdir $<)))) = " > $@ - @sed -e "s:\":\\\\\":g" -e s:^:\": -e s:\$$:\\\\n\": $< >> $@ - @echo ";" >> $@ - -gen-%.xml.h: %.xml - @echo "Building $@ from $<" - @echo "extern const char * _$(subst -,_,$(subst .,_,$(basename $(notdir $<))));" > $@ - -################# -# Session Stuff -################# - -indicator_session_service_SOURCES = \ - $(dbus_accounts_sources) \ - $(dbus_consolekit_manager_sources) \ - $(dbus_consolekit_seat_sources) \ - $(dbus_consolekit_session_sources) \ - $(dbus_display_manager_sources) \ - $(dbus_upower_sources) \ - $(dbus_user_sources) \ - session-service.c \ - session-dbus.c \ - session-dbus.h \ - gen-session-dbus.xml.c \ - users-service-dbus.h \ - users-service-dbus.c \ - session-menu-mgr.h \ - session-menu-mgr.c \ - online-accounts-mgr.c \ - online-accounts-mgr.h - -indicator_session_service_CFLAGS = \ - $(SESSIONSERVICE_CFLAGS) \ - $(GCONF_CFLAGS) \ - -DLIBEXECDIR=\"$(libexecdir)\" \ - -Wall \ - -DG_LOG_DOMAIN=\"Indicator-Session\" \ - $(COVERAGE_CFLAGS) -indicator_session_service_LDADD = \ - $(SESSIONSERVICE_LIBS) \ - $(GCONF_LIBS) -indicator_session_service_LDFLAGS = \ - $(COVERAGE_LDFLAGS) - -################# -# GTK Logout Stuff -################# - -if BUILD_GTKLOGOUTHELPER -gtk_logout_helper_SOURCES = \ - $(dbus_consolekit_manager_sources) \ - gtk-logout-helper.c \ - dialog.c \ - dialog.h - -gtk_logout_helper_CFLAGS = \ - $(SESSIONSERVICE_CFLAGS) \ - $(GTKLOGOUTHELPER_CFLAGS) \ - $(GCONF_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - -Wall \ - -DINDICATOR_ICONS_DIR="\"$(INDICATORICONSDIR)\"" - -gtk_logout_helper_LDADD = \ - $(SESSIONSERVICE_LIBS) \ - $(GTKLOGOUTHELPER_LIBS) \ - $(GCONF_LIBS) - -gtk_logout_helper_LDFLAGS = \ - $(COVERAGE_LDFLAGS) -endif - - -############### -# Other Stuff -############### - -BUILT_SOURCES = \ - $(dbus_accounts_sources) \ - $(dbus_consolekit_manager_sources) \ - $(dbus_consolekit_seat_sources) \ - $(dbus_consolekit_session_sources) \ - $(dbus_display_manager_sources) \ - $(dbus_upower_sources) \ - $(dbus_user_sources) \ - gen-session-dbus.xml.c \ - gen-session-dbus.xml.h - -EXTRA_DIST += \ - display-manager.xml \ - org.freedesktop.Accounts.User.xml \ - org.freedesktop.Accounts.xml \ - org.freedesktop.ConsoleKit.Manager.xml \ - org.freedesktop.ConsoleKit.Seat.xml \ - org.freedesktop.ConsoleKit.Session.xml \ - session-dbus.xml \ - upower.xml - -CLEANFILES += $(BUILT_SOURCES) diff --git a/src/actions.c b/src/actions.c new file mode 100644 index 0000000..788f418 --- /dev/null +++ b/src/actions.c @@ -0,0 +1,383 @@ + +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "actions.h" + +/*** +**** GObject Boilerplate +***/ + +G_DEFINE_TYPE (IndicatorSessionActions, indicator_session_actions, G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_CAN_SWITCH, + PROP_CAN_HIBERNATE, + PROP_CAN_SUSPEND, + PROP_CAN_LOCK, + PROP_CAN_LOGOUT, + PROP_CAN_PROMPT, + PROP_HAS_ONLINE_ACCOUNT_ERROR, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorSessionActions * self = INDICATOR_SESSION_ACTIONS (o); + + switch (property_id) + { + case PROP_CAN_SWITCH: + g_value_set_boolean (value, indicator_session_actions_can_switch (self)); + break; + + case PROP_CAN_HIBERNATE: + g_value_set_boolean (value, indicator_session_actions_can_hibernate (self)); + break; + + case PROP_CAN_SUSPEND: + g_value_set_boolean (value, indicator_session_actions_can_suspend (self)); + break; + + case PROP_CAN_LOCK: + g_value_set_boolean (value, indicator_session_actions_can_lock (self)); + break; + + case PROP_CAN_LOGOUT: + g_value_set_boolean (value, indicator_session_actions_can_logout (self)); + break; + + case PROP_CAN_PROMPT: + g_value_set_boolean (value, indicator_session_actions_can_prompt (self)); + break; + + case PROP_HAS_ONLINE_ACCOUNT_ERROR: + g_value_set_boolean (value, indicator_session_actions_has_online_account_error (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_actions_class_init (IndicatorSessionActionsClass * klass) +{ + GObjectClass * object_class; + const GParamFlags flags = G_PARAM_READABLE | G_PARAM_STATIC_STRINGS; + + object_class = G_OBJECT_CLASS (klass); + object_class->get_property = my_get_property; + + klass->can_lock = NULL; + klass->can_logout = NULL; + klass->can_switch = NULL; + klass->can_suspend = NULL; + klass->can_hibernate = NULL; + klass->has_online_account_error = NULL; + klass->logout = NULL; + klass->suspend = NULL; + klass->hibernate = NULL; + klass->restart = NULL; + klass->shutdown = NULL; + klass->switch_to_screensaver = NULL; + klass->switch_to_greeter = NULL; + klass->switch_to_guest = NULL; + klass->switch_to_username = NULL; + + /* properties */ + + properties[PROP_0] = NULL; + + properties[PROP_CAN_SWITCH] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_SWITCH, + "Can Switch Sessions", + "Whether or not the system services allow session switching", + TRUE, flags); + + properties[PROP_CAN_HIBERNATE] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_HIBERNATE, + "Can Hibernate", + "Whether or not the system services allow the user to hibernate", + TRUE, flags); + + properties[PROP_CAN_SUSPEND] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_SUSPEND, + "Can Suspend", + "Whether or not the system services allow the user to suspend", + TRUE, flags); + + properties[PROP_CAN_LOCK] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_LOCK, + "Can Lock", + "Whether or not the system services allow the user to lock the screen", + TRUE, flags); + + properties[PROP_CAN_LOGOUT] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_LOGOUT, + "Can Logout", + "Whether or not the system services allow the user to logout", + TRUE, flags); + + properties[PROP_CAN_PROMPT] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT, + "Can Show End Session Dialog", + "Whether or not we can show an End Session dialog", + TRUE, flags); + + properties[PROP_HAS_ONLINE_ACCOUNT_ERROR] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_HAS_ONLINE_ACCOUNT_ERROR, + "Has Online Account Error", + "Whether or not an online account setting requires attention from the user", + FALSE, flags); + + g_object_class_install_properties (object_class, PROP_LAST, properties); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_actions_init (IndicatorSessionActions * self G_GNUC_UNUSED) +{ +} + +/*** +**** +***/ + +gboolean +indicator_session_actions_can_lock (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_lock (self); +} + +gboolean +indicator_session_actions_can_logout (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_logout (self); +} + +gboolean +indicator_session_actions_can_switch (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_switch (self); +} + +gboolean +indicator_session_actions_can_suspend (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_suspend (self); +} + +gboolean +indicator_session_actions_can_hibernate (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_hibernate (self); +} + +gboolean +indicator_session_actions_can_prompt (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_prompt (self); +} + +gboolean +indicator_session_actions_has_online_account_error (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->has_online_account_error (self); +} + +/*** +**** +***/ + +void +indicator_session_actions_settings (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->settings (self); +} + +void +indicator_session_actions_logout (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->logout (self); +} + +void +indicator_session_actions_shutdown (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->shutdown (self); +} + +void +indicator_session_actions_help (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->help (self); +} + +void +indicator_session_actions_about (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->about (self); +} + +void +indicator_session_actions_restart (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->restart (self); +} + +void +indicator_session_actions_suspend (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->suspend (self); +} + +void +indicator_session_actions_hibernate (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->hibernate (self); +} + +void +indicator_session_actions_switch_to_screensaver (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->switch_to_screensaver (self); +} + +void +indicator_session_actions_switch_to_greeter (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->switch_to_greeter (self); +} + +void +indicator_session_actions_switch_to_guest (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->switch_to_guest (self); +} + +void +indicator_session_actions_switch_to_username (IndicatorSessionActions * self, + const gchar * username) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->switch_to_username (self, username); +} + +/*** +**** +***/ + +static void +notify_func (IndicatorSessionActions * self, int prop) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + g_debug ("%s %s emitting '%s' prop notify", G_STRLOC, G_STRFUNC, properties[prop]->name); + + g_object_notify_by_pspec (G_OBJECT(self), properties[prop]); +} + +void +indicator_session_actions_notify_can_lock (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_LOCK); +} + +void +indicator_session_actions_notify_can_logout (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_LOGOUT); +} + +void +indicator_session_actions_notify_can_switch (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_SWITCH); +} + +void +indicator_session_actions_notify_can_suspend (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_SUSPEND); +} + +void +indicator_session_actions_notify_can_hibernate (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_HIBERNATE); +} + +void +indicator_session_actions_notify_can_prompt (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_PROMPT); +} + +void +indicator_session_actions_notify_has_online_account_error (IndicatorSessionActions * self) +{ + notify_func (self, PROP_HAS_ONLINE_ACCOUNT_ERROR); +} diff --git a/src/actions.h b/src/actions.h new file mode 100644 index 0000000..e0d0ec5 --- /dev/null +++ b/src/actions.h @@ -0,0 +1,129 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __INDICATOR_SESSION_ACTIONS_H__ +#define __INDICATOR_SESSION_ACTIONS_H__ + +#include +#include + +G_BEGIN_DECLS + +/* standard GObject macros */ +#define INDICATOR_TYPE_SESSION_ACTIONS (indicator_session_actions_get_type()) +#define INDICATOR_SESSION_ACTIONS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_ACTIONS, IndicatorSessionActions)) +#define INDICATOR_SESSION_ACTIONS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_ACTIONS, IndicatorSessionActionsClass)) +#define INDICATOR_SESSION_ACTIONS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_SESSION_ACTIONS, IndicatorSessionActionsClass)) +#define INDICATOR_IS_SESSION_ACTIONS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_ACTIONS)) + +typedef struct _IndicatorSessionActions IndicatorSessionActions; +typedef struct _IndicatorSessionActionsClass IndicatorSessionActionsClass; + +/* property keys */ +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_LOCK "can-lock" +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_LOGOUT "can-logout" +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_SWITCH "can-switch" +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_SUSPEND "can-suspend" +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_HIBERNATE "can-hibernate" +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT "can-show-end-session-dialog" +#define INDICATOR_SESSION_ACTIONS_PROP_HAS_ONLINE_ACCOUNT_ERROR "has-online-account-error" + +/** + * A base class for invoking and getting state information on system actions. + * Use backend.h's get_backend() to get an instance. + */ +struct _IndicatorSessionActions +{ + /*< private >*/ + GObject parent; +}; + +struct _IndicatorSessionActionsClass +{ + GObjectClass parent_class; + + /* pure virtual functions */ + + gboolean (*can_lock) (IndicatorSessionActions * self); + gboolean (*can_logout) (IndicatorSessionActions * self); + gboolean (*can_switch) (IndicatorSessionActions * self); + gboolean (*can_suspend) (IndicatorSessionActions * self); + gboolean (*can_hibernate) (IndicatorSessionActions * self); + gboolean (*can_prompt) (IndicatorSessionActions * self); + gboolean (*has_online_account_error) (IndicatorSessionActions * self); + + void (*suspend) (IndicatorSessionActions * self); + void (*hibernate) (IndicatorSessionActions * self); + void (*logout) (IndicatorSessionActions * self); + void (*restart) (IndicatorSessionActions * self); + void (*shutdown) (IndicatorSessionActions * self); + void (*help) (IndicatorSessionActions * self); + void (*about) (IndicatorSessionActions * self); + void (*settings) (IndicatorSessionActions * self); + + void (*switch_to_greeter) (IndicatorSessionActions * self); + void (*switch_to_screensaver) (IndicatorSessionActions * self); + void (*switch_to_guest) (IndicatorSessionActions * self); + void (*switch_to_username) (IndicatorSessionActions * self, + const gchar * username); +}; + +/*** +**** +***/ + +GType indicator_session_actions_get_type (void); + +gboolean indicator_session_actions_can_lock (IndicatorSessionActions * self); +gboolean indicator_session_actions_can_logout (IndicatorSessionActions * self); +gboolean indicator_session_actions_can_switch (IndicatorSessionActions * self); +gboolean indicator_session_actions_can_suspend (IndicatorSessionActions * self); +gboolean indicator_session_actions_can_hibernate (IndicatorSessionActions * self); +gboolean indicator_session_actions_can_prompt (IndicatorSessionActions * self); +gboolean indicator_session_actions_has_online_account_error (IndicatorSessionActions * self); + + +void indicator_session_actions_notify_can_lock (IndicatorSessionActions * self); +void indicator_session_actions_notify_can_logout (IndicatorSessionActions * self); +void indicator_session_actions_notify_can_switch (IndicatorSessionActions * self); +void indicator_session_actions_notify_can_suspend (IndicatorSessionActions * self); +void indicator_session_actions_notify_can_hibernate (IndicatorSessionActions * self); +void indicator_session_actions_notify_can_prompt (IndicatorSessionActions * self); +void indicator_session_actions_notify_has_online_account_error (IndicatorSessionActions * self); + +void indicator_session_actions_lock (IndicatorSessionActions * self); +void indicator_session_actions_suspend (IndicatorSessionActions * self); +void indicator_session_actions_hibernate (IndicatorSessionActions * self); +void indicator_session_actions_logout (IndicatorSessionActions * self); +void indicator_session_actions_restart (IndicatorSessionActions * self); +void indicator_session_actions_shutdown (IndicatorSessionActions * self); + +void indicator_session_actions_help (IndicatorSessionActions * self); +void indicator_session_actions_about (IndicatorSessionActions * self); +void indicator_session_actions_settings (IndicatorSessionActions * self); + +void indicator_session_actions_switch_to_screensaver (IndicatorSessionActions * self); +void indicator_session_actions_switch_to_greeter (IndicatorSessionActions * self); +void indicator_session_actions_switch_to_guest (IndicatorSessionActions * self); +void indicator_session_actions_switch_to_username (IndicatorSessionActions * self, + const gchar * username); + +G_END_DECLS + +#endif /* __INDICATOR_SESSION_ACTIONS_H__ */ diff --git a/src/backend-dbus/CMakeLists.txt b/src/backend-dbus/CMakeLists.txt new file mode 100644 index 0000000..a477cfe --- /dev/null +++ b/src/backend-dbus/CMakeLists.txt @@ -0,0 +1,86 @@ +# autogenerate source code files for our DBus proxies +function(gdbus_codegen XML_FILE INTERFACE_PREFIX SOURCE_PREFIX) + + set (SRC_C, ${SOURCE_PREFIX}.c) + set (SRC_H, ${SOURCE_PREFIX}.h) + + # check for the app + find_program (GDBUS_CODEGEN_EXECUTABLE NAMES gdbus-codegen DOC "gdbus-codegen executable") + if(NOT GDBUS_CODEGEN_EXECUTABLE) + message(FATAL_ERROR "Executable gdbus-codegen not found") + endif() + + # generate the code + add_custom_command ( + OUTPUT ${SOURCE_PREFIX}.c ${SOURCE_PREFIX}.h + COMMAND gdbus-codegen ARGS --interface-prefix ${INTERFACE_PREFIX} --generate-c-code ${SOURCE_PREFIX} ${CMAKE_CURRENT_SOURCE_DIR}/${XML_FILE} + DEPENDS ${XML_FILE}) + + # update our variables + set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${SRC_C}) + set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${SRC_H}) + set_property (SOURCE ${SRC_C} ${SRC_H} PROPERTY GENERATED) + + # cleanup + unset (SRC_C) + unset (SRC_H) + +endfunction(gdbus_codegen) +gdbus_codegen ("display-manager.xml" "org.freedesktop" "dbus-display-manager") +gdbus_codegen ("com.canonical.indicators.webcredentials.xml" "com.canonical.indicators" "dbus-webcredentials") +gdbus_codegen ("org.freedesktop.Accounts.xml" "org.freedesktop" "dbus-accounts") +gdbus_codegen ("org.freedesktop.Accounts.User.xml" "org.freedesktop" "dbus-user") +gdbus_codegen ("org.freedesktop.ConsoleKit.Manager.xml" "org.freedesktop" "dbus-consolekit-manager") +gdbus_codegen ("org.freedesktop.ConsoleKit.Seat.xml" "org.freedesktop" "dbus-consolekit-seat") +gdbus_codegen ("org.freedesktop.ConsoleKit.Session.xml" "org.freedesktop" "dbus-consolekit-session") +gdbus_codegen ("org.gnome.ScreenSaver.xml" "org" "gnome-screen-saver") +gdbus_codegen ("org.gnome.SessionManager.xml" "org" "gnome-session-manager") +gdbus_codegen ("org.gnome.SessionManager.EndSessionDialog.xml" "org.gnome.SessionManager" "dbus-end-session-dialog") +gdbus_codegen ("upower.xml" "org.freedesktop" "dbus-upower") + +# add warnings/coverage info on handwritten files +# but not the autogenerated ones... +set_source_files_properties (actions.c + backend-dbus.c + guest.c + users.c + utils.c + PROPERTIES COMPILE_FLAGS " -g ${CC_WARNING_ARGS} ${GCOV_FLAGS}") + +# add the bin dir to our include path s.t. our code can find the autogenerated header files +include_directories (${CMAKE_CURRENT_BINARY_DIR} ${SERVICE_INCLUDE_DIRS}) + +add_library (backenddbus STATIC + gnome-screen-saver.c + gnome-screen-saver.h + gnome-session-manager.c + gnome-session-manager.h + dbus-display-manager.c + dbus-display-manager.h + dbus-consolekit-manager.c + dbus-consolekit-manager.h + dbus-consolekit-seat.c + dbus-consolekit-seat.h + dbus-consolekit-session.c + dbus-consolekit-session.h + dbus-accounts.c + dbus-accounts.h + dbus-upower.c + dbus-upower.h + dbus-user.c + dbus-user.h + dbus-webcredentials.c + dbus-webcredentials.h + dbus-end-session-dialog.c + dbus-end-session-dialog.h + actions.c + actions.h + backend-dbus.c + backend-dbus.h + guest.c + guest.h + users.c + users.h + utils.c + utils.h) + diff --git a/src/backend-dbus/actions.c b/src/backend-dbus/actions.c new file mode 100644 index 0000000..8994710 --- /dev/null +++ b/src/backend-dbus/actions.c @@ -0,0 +1,730 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include + +#include "dbus-end-session-dialog.h" +#include "dbus-upower.h" +#include "dbus-webcredentials.h" +#include "gnome-screen-saver.h" +#include "gnome-session-manager.h" + +#include "actions.h" + +enum +{ + END_SESSION_TYPE_LOGOUT = 0, + END_SESSION_TYPE_SHUTDOWN, + END_SESSION_TYPE_REBOOT +}; + +struct _IndicatorSessionActionsDbusPriv +{ + GCancellable * cancellable; + + GSettings * lockdown_settings; + UPower * upower; + GnomeScreenSaver * screen_saver; + GnomeSessionManager * session_manager; + ConsoleKitManager * ck_manager; + ConsoleKitSeat * ck_seat; + DisplayManagerSeat * dm_seat; + Webcredentials * webcredentials; + EndSessionDialog * end_session_dialog; + + gboolean suspend_allowed; + gboolean hibernate_allowed; + gboolean seat_allows_activation; +}; + +typedef IndicatorSessionActionsDbusPriv priv_t; + +G_DEFINE_TYPE (IndicatorSessionActionsDbus, + indicator_session_actions_dbus, + INDICATOR_TYPE_SESSION_ACTIONS) + +/*** +**** +***/ + +static void +log_and_clear_error (GError ** err, const char * loc, const char * func) +{ + if (*err) + { + g_warning ("%s %s: %s", loc, func, (*err)->message); + g_clear_error (err); + } +} + +static void +on_can_activate_sessions (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gboolean can_activate_sessions; + + err = NULL; + can_activate_sessions = FALSE; + console_kit_seat_call_can_activate_sessions_finish (CONSOLE_KIT_SEAT(o), + &can_activate_sessions, + res, + &err); + if (err == NULL) + { + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv; + p->seat_allows_activation = can_activate_sessions; + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +set_ck_seat (IndicatorSessionActionsDbus * self, ConsoleKitSeat * seat) +{ + priv_t * p = self->priv; + + g_clear_object (&p->ck_seat); + + if (seat != NULL) + { + p->ck_seat = g_object_ref (seat); + + console_kit_seat_call_can_activate_sessions (seat, + p->cancellable, + on_can_activate_sessions, + self); + } +} + +/*** +**** +***/ + +static void +set_dm_seat (IndicatorSessionActionsDbus * self, DisplayManagerSeat * seat) +{ + priv_t * p = self->priv; + + if (p->dm_seat != NULL) + { + g_signal_handlers_disconnect_by_data (p->dm_seat, self); + g_clear_object (&p->dm_seat); + } + + if (seat != NULL) + { + p->dm_seat = g_object_ref (seat); + /*g_signal_connect (seat, "notify::has-actions-account", G_CALLBACK(on_notify_has_actions_account), self);*/ + } +} + +static void +on_screensaver_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + GnomeScreenSaver * ss; + + err = NULL; + ss = gnome_screen_saver_proxy_new_for_bus_finish (res, &err); + if (err == NULL) + { + INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv->screen_saver = ss; + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_suspend_allowed_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gboolean allowed = FALSE; + + err = NULL; + upower_call_suspend_allowed_finish (UPOWER(o), &allowed, res, &err); + if (err == NULL) + { + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv; + + if (p->suspend_allowed != allowed) + { + p->suspend_allowed = allowed; + indicator_session_actions_notify_can_suspend (gself); + } + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_hibernate_allowed_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gboolean allowed = FALSE; + + err = NULL; + upower_call_hibernate_allowed_finish (UPOWER(o), &allowed, res, &err); + if (err == NULL) + { + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv; + + if (p->hibernate_allowed != allowed) + { + p->hibernate_allowed = allowed; + indicator_session_actions_notify_can_hibernate (gself); + } + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_upower_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + UPower * upower; + + err = NULL; + upower = upower_proxy_new_for_bus_finish (res, &err); + if (err == NULL) + { + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv; + + p->upower = upower; + + g_signal_connect_swapped (upower, "notify::can-suspend", + G_CALLBACK(indicator_session_actions_notify_can_suspend), gself); + + g_signal_connect_swapped (upower, "notify::can-hibernate", + G_CALLBACK(indicator_session_actions_notify_can_hibernate), gself); + + upower_call_suspend_allowed (upower, p->cancellable, on_suspend_allowed_ready, gself); + + upower_call_hibernate_allowed (upower, p->cancellable, on_hibernate_allowed_ready, gself); + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_session_manager_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + GnomeSessionManager * sm; + + err = NULL; + sm = gnome_session_manager_proxy_new_for_bus_finish (res, &err); + if (err == NULL) + { + INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv->session_manager = sm; + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_webcredentials_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + Webcredentials * webcredentials; + + err = NULL; + webcredentials = webcredentials_proxy_new_for_bus_finish (res, &err); + if (err == NULL) + { + INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv->webcredentials = webcredentials; + + g_signal_connect_swapped (webcredentials, "notify::error-status", + G_CALLBACK(indicator_session_actions_notify_has_online_account_error), gself); + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_end_session_dialog_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + EndSessionDialog * end_session_dialog; + + err = NULL; + end_session_dialog = end_session_dialog_proxy_new_for_bus_finish (res, &err); + if (err == NULL) + { + INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv->end_session_dialog = end_session_dialog; + + indicator_session_actions_notify_can_prompt (INDICATOR_SESSION_ACTIONS(gself)); + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +/*** +**** Virtual Functions +***/ + +static gboolean +my_can_lock (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return !g_settings_get_boolean (p->lockdown_settings, "disable-lock-screen"); +} + +static gboolean +my_can_logout (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return !g_settings_get_boolean (p->lockdown_settings, "disable-log-out"); +} + +static gboolean +my_can_switch (IndicatorSessionActions * self) +{ + const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return p->seat_allows_activation + && !g_settings_get_boolean (p->lockdown_settings, "disable-user-switching"); +} + +static gboolean +my_can_suspend (IndicatorSessionActions * self) +{ + const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return p && p->upower && p->suspend_allowed && upower_get_can_suspend (p->upower); +} + +static gboolean +my_can_hibernate (IndicatorSessionActions * self) +{ + const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return p && p->upower && p->hibernate_allowed && upower_get_can_hibernate (p->upower); +} + +static gboolean +my_can_prompt (IndicatorSessionActions * self) +{ + const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return (p != NULL) + && (p->end_session_dialog != NULL) + && (g_dbus_proxy_get_name_owner (G_DBUS_PROXY(p->end_session_dialog)) != NULL); +} + +static gboolean +my_has_online_account_error (IndicatorSessionActions * self) +{ + const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return p && (p->webcredentials) && (webcredentials_get_error_status (p->webcredentials)); +} + +static void +my_suspend (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->upower != NULL); + + upower_call_suspend (p->upower, p->cancellable, NULL, NULL); +} + +static void +my_hibernate (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->upower != NULL); + + upower_call_hibernate (p->upower, p->cancellable, NULL, NULL); +} + +/*** +**** End Session Dialog +***/ + +static void +logout_now (IndicatorSessionActions * self, gboolean try_to_prompt) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + const int type = try_to_prompt ? 0 : 1; + + g_return_if_fail (p->session_manager != NULL); + + gnome_session_manager_call_logout (p->session_manager, + type, + p->cancellable, + NULL, + NULL); +} + +static void +logout_now_with_prompt (IndicatorSessionActions * self) +{ + logout_now (self, TRUE); +} + +static void +logout_now_quietly (IndicatorSessionActions * self) +{ + logout_now (self, FALSE); +} + +static void +restart_now (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->ck_manager != NULL); + + console_kit_manager_call_restart (p->ck_manager, p->cancellable, NULL, NULL); +} + +static void +shutdown_now (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->ck_manager != NULL); + + console_kit_manager_call_stop (p->ck_manager, p->cancellable, NULL, NULL); +} + +static void +stop_listening_to_dialog (IndicatorSessionActionsDbus * self) +{ + g_signal_handlers_disconnect_by_data (self->priv->end_session_dialog, self); +} +static void +on_end_session_dialog_canceled (IndicatorSessionActionsDbus * self) +{ + stop_listening_to_dialog (self); +} +static void +on_end_session_dialog_closed (IndicatorSessionActionsDbus * self) +{ + stop_listening_to_dialog (self); +} + +static void +on_open_end_session_dialog_ready (GObject * o, + GAsyncResult * res, + gpointer gself G_GNUC_UNUSED) +{ + GError * err = NULL; + end_session_dialog_call_open_finish (END_SESSION_DIALOG(o), res, &err); + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +show_end_session_dialog (IndicatorSessionActionsDbus * self, int type) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + gpointer o = p->end_session_dialog; + const char * inhibitor_paths[] = { NULL }; + + g_assert (o != NULL); + + g_signal_connect_swapped (o, "confirmed-logout", G_CALLBACK(logout_now_quietly), self); + g_signal_connect_swapped (o, "confirmed-reboot", G_CALLBACK(restart_now), self); + g_signal_connect_swapped (o, "confirmed-shutdown", G_CALLBACK(shutdown_now), self); + g_signal_connect_swapped (o, "canceled", G_CALLBACK(on_end_session_dialog_canceled), self); + g_signal_connect_swapped (o, "closed", G_CALLBACK(on_end_session_dialog_closed), self); + + end_session_dialog_call_open (p->end_session_dialog, type, 0, 0, inhibitor_paths, + p->cancellable, + on_open_end_session_dialog_ready, + self); +} + +static void +my_logout (IndicatorSessionActions * self) +{ + if (my_can_prompt (self)) + show_end_session_dialog (INDICATOR_SESSION_ACTIONS_DBUS(self), END_SESSION_TYPE_LOGOUT); + else + logout_now_with_prompt (self); +} + + +static void +my_restart (IndicatorSessionActions * self) +{ + if (my_can_prompt (self)) + show_end_session_dialog (INDICATOR_SESSION_ACTIONS_DBUS(self), END_SESSION_TYPE_REBOOT); + else + restart_now (self); +} + +static void +my_shutdown (IndicatorSessionActions * self) +{ + /* NB: TYPE_REBOOT instead of TYPE_SHUTDOWN because + the latter adds lock & logout options in Unity... */ + if (my_can_prompt (self)) + show_end_session_dialog (INDICATOR_SESSION_ACTIONS_DBUS(self), END_SESSION_TYPE_REBOOT); + else + shutdown_now (self); +} + +/*** +**** +***/ + +static void +run_outside_app (const char * cmd) +{ + GError * err = NULL; + g_debug ("%s calling \"%s\"", G_STRFUNC, cmd); + g_spawn_command_line_async (cmd, &err); + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +my_help (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + run_outside_app ("yelp"); +} + +static void +my_settings (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + run_outside_app ("gnome-control-center"); +} + +static void +my_about (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + run_outside_app ("gnome-control-center info"); +} + +/*** +**** +***/ + +static void +my_switch_to_screensaver (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->screen_saver != NULL); + + gnome_screen_saver_call_lock (p->screen_saver, p->cancellable, NULL, NULL); +} + +static void +my_switch_to_greeter (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->dm_seat != NULL); + + display_manager_seat_call_switch_to_greeter (p->dm_seat, p->cancellable, + NULL, NULL); +} + +static void +my_switch_to_guest (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->dm_seat != NULL); + + display_manager_seat_call_switch_to_guest (p->dm_seat, "", + p->cancellable, + NULL, NULL); +} + +static void +my_switch_to_username (IndicatorSessionActions * self, const char * username) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->dm_seat != NULL); + + display_manager_seat_call_switch_to_user (p->dm_seat, username, "", + p->cancellable, + NULL, NULL); +} + +static void +my_dispose (GObject * o) +{ + IndicatorSessionActionsDbus * self = INDICATOR_SESSION_ACTIONS_DBUS (o); + priv_t * p = self->priv; + + if (p->cancellable != NULL) + { + g_cancellable_cancel (p->cancellable); + g_clear_object (&p->cancellable); + } + + g_clear_object (&p->lockdown_settings); + g_clear_object (&p->ck_manager); + g_clear_object (&p->upower); + g_clear_object (&p->screen_saver); + g_clear_object (&p->session_manager); + g_clear_object (&p->webcredentials); + g_clear_object (&p->end_session_dialog); + set_dm_seat (self, NULL); + set_ck_seat (self, NULL); + + G_OBJECT_CLASS (indicator_session_actions_dbus_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + /*IndicatorSessionActionsDbus * u = INDICATOR_SESSION_ACTIONS_DBUS (o);*/ + + G_OBJECT_CLASS (indicator_session_actions_dbus_parent_class)->finalize (o); +} + +/*** +**** GObject Boilerplate +***/ + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_actions_dbus_class_init (IndicatorSessionActionsDbusClass * klass) +{ + GObjectClass * object_class; + IndicatorSessionActionsClass * actions_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + actions_class = INDICATOR_SESSION_ACTIONS_CLASS (klass); + actions_class->can_lock = my_can_lock; + actions_class->can_logout = my_can_logout; + actions_class->can_switch = my_can_switch; + actions_class->can_suspend = my_can_suspend; + actions_class->can_hibernate = my_can_hibernate; + actions_class->can_prompt = my_can_prompt; + actions_class->has_online_account_error = my_has_online_account_error; + actions_class->logout = my_logout; + actions_class->suspend = my_suspend; + actions_class->hibernate = my_hibernate; + actions_class->restart = my_restart; + actions_class->shutdown = my_shutdown; + actions_class->settings = my_settings; + actions_class->help = my_help; + actions_class->about = my_about; + actions_class->switch_to_screensaver = my_switch_to_screensaver; + actions_class->switch_to_greeter = my_switch_to_greeter; + actions_class->switch_to_guest = my_switch_to_guest; + actions_class->switch_to_username = my_switch_to_username; + + g_type_class_add_private (klass, sizeof (IndicatorSessionActionsDbusPriv)); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_actions_dbus_init (IndicatorSessionActionsDbus * self) +{ + priv_t * p; + GSettings * s; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_ACTIONS_DBUS, + IndicatorSessionActionsDbusPriv); + p->cancellable = g_cancellable_new (); + p->seat_allows_activation = TRUE; + self->priv = p; + + s = g_settings_new ("org.gnome.desktop.lockdown"); + g_signal_connect_swapped (s, "changed::disable-lock-screen", + G_CALLBACK(indicator_session_actions_notify_can_lock), self); + g_signal_connect_swapped (s, "changed::disable-log-out", + G_CALLBACK(indicator_session_actions_notify_can_logout), self); + g_signal_connect_swapped (s, "changed::disable-user-switching", + G_CALLBACK(indicator_session_actions_notify_can_switch), self); + p->lockdown_settings = s; + + gnome_screen_saver_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + "org.gnome.ScreenSaver", + "/org/gnome/ScreenSaver", + p->cancellable, + on_screensaver_proxy_ready, + self); + + upower_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.UPower", + "/org/freedesktop/UPower", + p->cancellable, + on_upower_proxy_ready, + self); + + gnome_session_manager_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + p->cancellable, + on_session_manager_proxy_ready, + self); + + webcredentials_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + "com.canonical.indicators.webcredentials", + "/com/canonical/indicators/webcredentials", + p->cancellable, + on_webcredentials_proxy_ready, + self); + + end_session_dialog_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + "com.canonical.Unity", + "/org/gnome/SessionManager/EndSessionDialog", + p->cancellable, + on_end_session_dialog_proxy_ready, + self); +} + +/*** +**** Public +***/ + +IndicatorSessionActions * +indicator_session_actions_dbus_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_SESSION_ACTIONS_DBUS, NULL); + + return INDICATOR_SESSION_ACTIONS (o); +} + +void +indicator_session_actions_dbus_set_proxies (IndicatorSessionActionsDbus * self, + ConsoleKitManager * ck_manager, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * ck_seat) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS_DBUS(self)); + + self->priv->ck_manager = g_object_ref (ck_manager); + + set_dm_seat (self, dm_seat); + + set_ck_seat (self, ck_seat); +} diff --git a/src/backend-dbus/actions.h b/src/backend-dbus/actions.h new file mode 100644 index 0000000..997dd73 --- /dev/null +++ b/src/backend-dbus/actions.h @@ -0,0 +1,73 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __INDICATOR_SESSION_ACTIONS_DBUS_H__ +#define __INDICATOR_SESSION_ACTIONS_DBUS_H__ + +#include +#include + +#include "../actions.h" /* parent class */ +#include "dbus-accounts.h" +#include "dbus-consolekit-manager.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-session.h" +#include "dbus-display-manager.h" + + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_ACTIONS_DBUS (indicator_session_actions_dbus_get_type()) +#define INDICATOR_SESSION_ACTIONS_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_ACTIONS_DBUS, IndicatorSessionActionsDbus)) +#define INDICATOR_SESSION_ACTIONS_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_ACTIONS_DBUS, IndicatorSessionActionsDbusClass)) +#define INDICATOR_IS_SESSION_ACTIONS_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_ACTIONS_DBUS)) + +typedef struct _IndicatorSessionActionsDbus IndicatorSessionActionsDbus; +typedef struct _IndicatorSessionActionsDbusPriv IndicatorSessionActionsDbusPriv; +typedef struct _IndicatorSessionActionsDbusClass IndicatorSessionActionsDbusClass; + +/** + * An implementation of IndicatorSessionActions that gets its user information + * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus. + */ +struct _IndicatorSessionActionsDbus +{ + /*< private >*/ + IndicatorSessionActions parent; + IndicatorSessionActionsDbusPriv * priv; +}; + +struct _IndicatorSessionActionsDbusClass +{ + IndicatorSessionActionsClass parent_class; +}; + +GType indicator_session_actions_dbus_get_type (void); + +IndicatorSessionActions * indicator_session_actions_dbus_new (void); + +void indicator_session_actions_dbus_set_proxies (IndicatorSessionActionsDbus * self, + ConsoleKitManager * ck_manager, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * ck_seat); + + +G_END_DECLS + +#endif /* __INDICATOR_SESSION_ACTIONS_DBUS_H__ */ diff --git a/src/backend-dbus/backend-dbus.c b/src/backend-dbus/backend-dbus.c new file mode 100644 index 0000000..ea8f0ec --- /dev/null +++ b/src/backend-dbus/backend-dbus.c @@ -0,0 +1,117 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "actions.h" +#include "backend-dbus.h" +#include "guest.h" +#include "users.h" +#include "utils.h" + +struct dbus_world_data +{ + GCancellable * cancellable; + IndicatorSessionActionsDbus * actions; + IndicatorSessionUsersDbus * users; + IndicatorSessionGuestDbus * guest; +}; + +static void +on_proxies_ready (ConsoleKitManager * ck_manager, + Accounts * account_manager, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * ck_seat, + ConsoleKitSession * ck_session, + AccountsUser * active_user G_GNUC_UNUSED, + const GError * error, + gpointer gdata) +{ + struct dbus_world_data * data = gdata; + + if (error == NULL) + { + if (data->actions != NULL) + indicator_session_actions_dbus_set_proxies (data->actions, + ck_manager, + dm_seat, + ck_seat); + + if (data->users != NULL) + indicator_session_users_dbus_set_proxies (data->users, + account_manager, + dm_seat, + ck_seat); + + if (data->guest != NULL) + indicator_session_guest_dbus_set_proxies (data->guest, + account_manager, + dm_seat, + ck_seat, + ck_session); + } + + g_free (data); +} + +/*** +**** +***/ + +void +backend_get (GCancellable * cancellable, + IndicatorSessionActions ** setme_actions, + IndicatorSessionUsers ** setme_users, + IndicatorSessionGuest ** setme_guest) +{ + struct dbus_world_data * data; + + data = g_new0 (struct dbus_world_data, 1); + + if (setme_actions != NULL) + { + IndicatorSessionActions * actions; + actions = indicator_session_actions_dbus_new (); + data->actions = INDICATOR_SESSION_ACTIONS_DBUS (actions); + + *setme_actions = actions; + } + + if (setme_users != NULL) + { + IndicatorSessionUsers * users; + users = indicator_session_users_dbus_new (); + data->users = INDICATOR_SESSION_USERS_DBUS (users); + + *setme_users = users; + } + + if (setme_guest != NULL) + { + IndicatorSessionGuest * guest; + guest = indicator_session_guest_dbus_new (); + data->guest = INDICATOR_SESSION_GUEST_DBUS (guest); + + *setme_guest = guest; + } + + data->cancellable = g_object_ref (cancellable); + + indicator_session_util_get_session_proxies (on_proxies_ready, + data->cancellable, + data); +} diff --git a/src/backend-dbus/backend-dbus.h b/src/backend-dbus/backend-dbus.h new file mode 100644 index 0000000..daf6ac3 --- /dev/null +++ b/src/backend-dbus/backend-dbus.h @@ -0,0 +1,38 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __INDICATOR_SESSION_BACKEND_DESKTOP_H__ +#define __INDICATOR_SESSION_BACKEND_DESKTOP_H__ + +#include /* GCancellable */ + +#include "../actions.h" +#include "../guest.h" +#include "../users.h" + +G_BEGIN_DECLS + +void backend_get (GCancellable * cancellable, + IndicatorSessionActions ** setme_actions, + IndicatorSessionUsers ** setme_users, + IndicatorSessionGuest ** setme_guest); + +G_END_DECLS + +#endif diff --git a/src/backend-dbus/com.canonical.indicators.webcredentials.xml b/src/backend-dbus/com.canonical.indicators.webcredentials.xml new file mode 100644 index 0000000..d215081 --- /dev/null +++ b/src/backend-dbus/com.canonical.indicators.webcredentials.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/backend-dbus/display-manager.xml b/src/backend-dbus/display-manager.xml new file mode 100644 index 0000000..07b5f29 --- /dev/null +++ b/src/backend-dbus/display-manager.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/backend-dbus/guest.c b/src/backend-dbus/guest.c new file mode 100644 index 0000000..516ba00 --- /dev/null +++ b/src/backend-dbus/guest.c @@ -0,0 +1,570 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include + +#include "dbus-accounts.h" +#include "dbus-display-manager.h" +#include "dbus-user.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-manager.h" +#include "dbus-consolekit-session.h" + +#include "guest.h" + +struct _IndicatorSessionGuestDbusPriv +{ + GCancellable * cancellable; + + Accounts * accounts; + AccountsUser * guest; + DisplayManagerSeat * display_manager_seat; + + ConsoleKitSeat * seat; + ConsoleKitSession * active_session; + guint active_uid; + + gboolean guest_is_active; + gboolean guest_is_allowed; +}; + +typedef IndicatorSessionGuestDbusPriv priv_t; + +G_DEFINE_TYPE (IndicatorSessionGuestDbus, + indicator_session_guest_dbus, + INDICATOR_TYPE_SESSION_GUEST) + +/*** +**** +***/ + +static void +check_for_active_guest (IndicatorSessionGuestDbus * self) +{ + gboolean guest_is_active; + priv_t * p = self->priv; + + guest_is_active = (p->active_uid) + && (p->guest != NULL) + && (p->active_uid == accounts_user_get_uid (p->guest)); + + if (p->guest_is_active != guest_is_active) + { + p->guest_is_active = guest_is_active; + + indicator_session_guest_notify_active (INDICATOR_SESSION_GUEST(self)); + } +} + +static void +set_active_uid (IndicatorSessionGuestDbus * self, guint uid) +{ + self->priv->active_uid = uid; + + check_for_active_guest (self); +} + +static void +on_active_uid_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + guint uid; + GError * err; + IndicatorSessionGuestDbus * self; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + uid = 0; + err = NULL; + self = INDICATOR_SESSION_GUEST_DBUS (gself); + console_kit_session_call_get_unix_user_finish (self->priv->active_session, &uid, res, &err); + + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + set_active_uid (self, uid); + } +} + + +static void +set_active_session (IndicatorSessionGuestDbus * self, + ConsoleKitSession * session) +{ + priv_t * p = self->priv; + + if (p->active_session != NULL) + { + g_debug ("%s %s active_session refcount is %d before we unref", G_STRLOC, G_STRFUNC, G_OBJECT(self->priv->active_session)->ref_count); + + g_clear_object (&p->active_session); + } + + if (session != NULL) + { + p->active_session = g_object_ref (session); + + console_kit_session_call_get_unix_user (session, + p->cancellable, + on_active_uid_ready, + self); + } +} + +static void +on_active_session_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + ConsoleKitSession * session; + + err = NULL; + session = console_kit_session_proxy_new_finish (res, &err); + + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + } + else + { + set_active_session (gself, session); + } + + g_clear_object (&session); +} + + +static void +on_active_session_changed (ConsoleKitSeat * seat G_GNUC_UNUSED, + const gchar * ssid, + IndicatorSessionGuestDbus * self) +{ + console_kit_session_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + ssid, + self->priv->cancellable, + on_active_session_proxy_ready, + self); +} + +static void +set_seat (IndicatorSessionGuestDbus * self, + ConsoleKitSeat * seat) +{ + priv_t * p = self->priv; + + if (p->seat != NULL) + { +g_debug ("%s %s guest-dbus disconnecting from %p", G_STRLOC, G_STRFUNC, (void*)p->seat); + g_signal_handlers_disconnect_by_data (p->seat, self); +g_debug ("%s %s seat refcount is %d before our unref", G_STRLOC, G_STRFUNC, G_OBJECT(p->seat)->ref_count); + + g_clear_object (&p->seat); + } + + if (seat != NULL) + { + p->seat = g_object_ref (seat); +g_debug ("%s %s guest-dbus connecting to %p", G_STRLOC, G_STRFUNC, (void*)p->seat); + + g_signal_connect (seat, "active-session-changed", + G_CALLBACK(on_active_session_changed), self); + } +} + +/*** +**** +***/ + +static void +set_guest (IndicatorSessionGuestDbus * self, + AccountsUser * guest) +{ + priv_t * p = self->priv; + + if (p->guest != NULL) + { + g_debug ("%s %s guest refcount is %d before we unref", G_STRLOC, G_STRFUNC, G_OBJECT(p->guest)->ref_count); + + g_clear_object (&p->guest); + } + + if (guest != NULL) + { + p->guest = g_object_ref (guest); + } + + g_debug ("%s %s guest proxy is now %p", G_STRLOC, G_STRFUNC, (void*)guest); + indicator_session_guest_notify_logged_in (INDICATOR_SESSION_GUEST(self)); + + check_for_active_guest (self); +} + +static void +on_user_deleted (IndicatorSessionGuestDbus * self, + const gchar * path) +{ + AccountsUser * guest = self->priv->guest; + g_debug ("%s %s %s", G_STRLOC, G_STRFUNC, path); + + if (guest != NULL) + if (!g_strcmp0 (path, g_dbus_proxy_get_object_path (G_DBUS_PROXY(guest)))) + set_guest (self, NULL); +} + +static gboolean +is_guest (AccountsUser * user) +{ + /* a guest will look like this: + username:[guest-jjbEVV] realname:[Guest] system:[1] */ + return IS_ACCOUNTS_USER(user) + && accounts_user_get_system_account (user) + && !g_ascii_strcasecmp (accounts_user_get_real_name(user), "Guest"); +} + +static void +on_user_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer self) +{ + GError * err; + AccountsUser * user; + + err = NULL; + user = accounts_user_proxy_new_for_bus_finish (res, &err); + + if (err != NULL) + { + g_warning ("%s: %s", G_STRFUNC, err->message); + g_error_free (err); + } + else if (is_guest (user)) + { + g_debug ("%s %s got guest", G_STRLOC, G_STRFUNC); + set_guest (INDICATOR_SESSION_GUEST_DBUS(self), user); + } + + g_clear_object (&user); +} + +static void +create_user_proxy_for_path (IndicatorSessionGuestDbus * self, + const char * path) +{ + const char * name = "org.freedesktop.Accounts"; + const GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + g_debug ("%s %s creating proxy for %s", G_STRLOC, G_STRFUNC, path); + + accounts_user_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, path, + self->priv->cancellable, + on_user_proxy_ready, self); +} + +static void +on_user_list_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar ** paths; + + err = NULL; + paths = NULL; + accounts_call_list_cached_users_finish (ACCOUNTS(o), &paths, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + int i; + + for (i=0; paths && paths[i]; ++i) + create_user_proxy_for_path (gself, paths[i]); + + g_strfreev (paths); + } +} + +static void +set_account_manager (IndicatorSessionGuestDbus * self, + Accounts * a) +{ + g_debug ("%s %s setting account manager to %p", G_STRLOC, G_STRFUNC, (void*)a); + + if (self->priv->accounts != NULL) + { +g_debug ("%s %s guest-dbus disconnecting from %p", G_STRLOC, G_STRFUNC, (void*)self->priv->accounts); + g_signal_handlers_disconnect_by_data (self->priv->accounts, self); +g_debug ("%s %s account manager refcount is %d before our unref", G_STRLOC, G_STRFUNC, G_OBJECT(self->priv->accounts)->ref_count); + g_clear_object (&self->priv->accounts); + } + + if (a != NULL) + { + self->priv->accounts = g_object_ref (a); + +g_debug ("%s %s guest-dbus connecting to %p", G_STRLOC, G_STRFUNC, (void*)self->priv->accounts); + g_signal_connect_swapped (a, "user-added", + G_CALLBACK(create_user_proxy_for_path), self); + + g_signal_connect_swapped (a, "user-deleted", + G_CALLBACK(on_user_deleted), self); + + accounts_call_list_cached_users (a, + self->priv->cancellable, + on_user_list_ready, + self); + } +} + +static void +set_guest_is_allowed (IndicatorSessionGuestDbus * self, gboolean guest_is_allowed) +{ + priv_t * p = self->priv; + g_debug ("%s %s guest_is_allowed: %d", G_STRLOC, G_STRFUNC, (int)guest_is_allowed); + + if (p->guest_is_allowed != guest_is_allowed) + { + p->guest_is_allowed = guest_is_allowed; + + indicator_session_guest_notify_allowed (INDICATOR_SESSION_GUEST (self)); + } +} + +static void +on_notify_has_guest_account (GObject * seat, GParamSpec * pspec G_GNUC_UNUSED, gpointer gself) +{ + set_guest_is_allowed (INDICATOR_SESSION_GUEST_DBUS (gself), + display_manager_seat_get_has_guest_account (DISPLAY_MANAGER_SEAT(seat))); +} + +static void +set_display_manager_seat (IndicatorSessionGuestDbus * self, DisplayManagerSeat * seat) +{ + priv_t * p = self->priv; + + if (p->display_manager_seat != NULL) + { + g_signal_handlers_disconnect_by_data (p->display_manager_seat, self); + g_debug ("%s %s before we unref, dm seat's refcount is %d", G_STRLOC, G_STRFUNC, G_OBJECT(p->display_manager_seat)->ref_count); + g_clear_object (&p->display_manager_seat); + } + + if (seat != NULL) + { + p->display_manager_seat = g_object_ref (seat); + + g_signal_connect (seat, "notify::has-guest-account", G_CALLBACK(on_notify_has_guest_account), self); + + on_notify_has_guest_account (G_OBJECT(seat), NULL, self); + } +} + +#if 0 +static void +on_display_manager_seat_proxy_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + DisplayManagerSeat * seat; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + err = NULL; + seat = display_manager_seat_proxy_new_for_bus_finish (res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + set_display_manager_seat (INDICATOR_SESSION_GUEST_DBUS(gself), seat); + } + + g_clear_object (&seat); +} +#endif + +static void +on_switch_to_guest_done (GObject * o, GAsyncResult * res, gpointer unused G_GNUC_UNUSED) +{ + GError * err; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + err = NULL; + display_manager_seat_call_switch_to_guest_finish (DISPLAY_MANAGER_SEAT(o), res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } +} + +/*** +**** Virtual Functions +***/ + +static void +my_dispose (GObject * o) +{ + IndicatorSessionGuestDbus * self = INDICATOR_SESSION_GUEST_DBUS (o); + + if (self->priv->cancellable != NULL) + { + g_cancellable_cancel (self->priv->cancellable); + g_clear_object (&self->priv->cancellable); + } + + set_seat (self, NULL); + set_active_session (self, NULL); + set_account_manager (self, NULL); + set_display_manager_seat (self, NULL); + g_clear_object (&self->priv->guest); + + G_OBJECT_CLASS (indicator_session_guest_dbus_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + /*IndicatorSessionGuestDbus * u = INDICATOR_SESSION_GUEST_DBUS (o);*/ + + G_OBJECT_CLASS (indicator_session_guest_dbus_parent_class)->finalize (o); +} + +static gboolean +my_is_allowed (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST_DBUS(self), FALSE); + + return INDICATOR_SESSION_GUEST_DBUS(self)->priv->guest_is_allowed; +} + +static gboolean +my_is_logged_in (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST_DBUS(self), FALSE); + + return INDICATOR_SESSION_GUEST_DBUS(self)->priv->guest != NULL; +} + +static gboolean +my_is_active (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST_DBUS(self), FALSE); + + return INDICATOR_SESSION_GUEST_DBUS(self)->priv->guest_is_active; +} + +static void +my_switch_to_guest (IndicatorSessionGuest * self) +{ + priv_t * p; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + g_return_if_fail (INDICATOR_IS_SESSION_GUEST_DBUS(self)); + + p = INDICATOR_SESSION_GUEST_DBUS(self)->priv; + + if (p->display_manager_seat != NULL) + { + display_manager_seat_call_switch_to_guest (p->display_manager_seat, + "", + p->cancellable, + on_switch_to_guest_done, + self); + } +} + +/*** +**** GObject Boilerplate +***/ + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_guest_dbus_class_init (IndicatorSessionGuestDbusClass * klass) +{ + GObjectClass * object_class; + IndicatorSessionGuestClass * guest_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + guest_class = INDICATOR_SESSION_GUEST_CLASS (klass); + guest_class->is_allowed = my_is_allowed; + guest_class->is_logged_in = my_is_logged_in; + guest_class->is_active = my_is_active; + guest_class->switch_to_guest = my_switch_to_guest; + + g_type_class_add_private (klass, sizeof (IndicatorSessionGuestDbusPriv)); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_guest_dbus_init (IndicatorSessionGuestDbus * self) +{ + priv_t * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_GUEST_DBUS, + IndicatorSessionGuestDbusPriv); + p->cancellable = g_cancellable_new (); + self->priv = p; + +#if 0 + display_manager_seat_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.DisplayManager", + g_getenv ("XDG_SEAT_PATH"), + self->priv->cancellable, + on_display_manager_seat_proxy_ready, + self); +#endif +} + +/*** +**** Public +***/ + +IndicatorSessionGuest * +indicator_session_guest_dbus_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_SESSION_GUEST_DBUS, NULL); + + return INDICATOR_SESSION_GUEST (o); +} + +void +indicator_session_guest_dbus_set_proxies (IndicatorSessionGuestDbus * self, + Accounts * accounts, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * seat, + ConsoleKitSession * session) +{ + g_return_if_fail (INDICATOR_IS_SESSION_GUEST_DBUS(self)); + g_debug ("%s %s accounts %p seat %p session %p", G_STRLOC, G_STRFUNC, (void*)accounts, (void*)seat, (void*)session); + + set_account_manager (self, accounts); + set_display_manager_seat (self, dm_seat); + set_seat (self, seat); + set_active_session (self, session); +} diff --git a/src/backend-dbus/guest.h b/src/backend-dbus/guest.h new file mode 100644 index 0000000..03b6b28 --- /dev/null +++ b/src/backend-dbus/guest.h @@ -0,0 +1,72 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __GUEST_DBUS_H__ +#define __GUEST_DBUS_H__ + +#include +#include + +#include "../guest.h" /* parent class */ +#include "dbus-accounts.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-session.h" +#include "dbus-display-manager.h" + + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_GUEST_DBUS (indicator_session_guest_dbus_get_type()) +#define INDICATOR_SESSION_GUEST_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_GUEST_DBUS, IndicatorSessionGuestDbus)) +#define INDICATOR_SESSION_GUEST_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_GUEST_DBUS, IndicatorSessionGuestDbusClass)) +#define INDICATOR_IS_SESSION_GUEST_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_GUEST_DBUS)) + +typedef struct _IndicatorSessionGuestDbus IndicatorSessionGuestDbus; +typedef struct _IndicatorSessionGuestDbusPriv IndicatorSessionGuestDbusPriv; +typedef struct _IndicatorSessionGuestDbusClass IndicatorSessionGuestDbusClass; + +/** + * An implementation of IndicatorSessionGuest that gets its user information + * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus. + */ +struct _IndicatorSessionGuestDbus +{ + /*< private >*/ + IndicatorSessionGuest parent; + IndicatorSessionGuestDbusPriv * priv; +}; + +struct _IndicatorSessionGuestDbusClass +{ + IndicatorSessionGuestClass parent_class; +}; + +GType indicator_session_guest_dbus_get_type (void); + +IndicatorSessionGuest * indicator_session_guest_dbus_new (void); + +void indicator_session_guest_dbus_set_proxies (IndicatorSessionGuestDbus *, + Accounts *, + DisplayManagerSeat *, + ConsoleKitSeat *, + ConsoleKitSession *); + +G_END_DECLS + +#endif diff --git a/src/backend-dbus/org.freedesktop.Accounts.User.xml b/src/backend-dbus/org.freedesktop.Accounts.User.xml new file mode 100644 index 0000000..53f54d4 --- /dev/null +++ b/src/backend-dbus/org.freedesktop.Accounts.User.xml @@ -0,0 +1,744 @@ + + + + + + + + + + + The new username. + + + + + + + Sets the users username. Note that it is usually not allowed + to have multiple users with the same username. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the username of any user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new name, typically in the form "Firstname Lastname". + + + + + + + Sets the users real name. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own name + + + org.freedesktop.accounts.user-administration + To change the name of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new email address. + + + + + + + Sets the users email address. + + + Note that setting an email address in the AccountsService is + not the same as configuring a mail client. Mail clients might + default to email address that is configured here, though. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own email address + + + org.freedesktop.accounts.user-administration + To change the email address of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new language, as a locale specification like "de_DE.UTF-8". + + + + + + + Sets the users language. + + + The expectation is that display managers will start the + users session with this locale. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + + The new xsession to start (e.g. "gnome") + + + + + + + Sets the users x session. + + + The expectation is that display managers will log the user in to this + specified session, if available. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new location as a freeform string. + + + + + + + Sets the users location. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own location + + + org.freedesktop.accounts.user-administration + To change the location of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new homedir as an absolute path. + + + + + + + Sets the users home directory. + + + Note that changing the users home directory moves all the content + from the old location to the new one, and is potentially an + expensive operation. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the home directory of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new user shell. + + + + + + + Sets the users shell. + + + Note that setting the shell to a non-allowed program may + prevent the user from logging in. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the shell of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The absolute filename of a png file to use as the users icon. + + + + + + + Sets the users icon. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own icon + + + org.freedesktop.accounts.user-administration + To change the icon of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + Whether to lock or unlock the users account. + + + + + + + Locks or unlocks a users account. + + + Locking an account prevents the user from logging in. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To lock or unlock user accounts + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new account type, encoded as an integer: + + + 0 + Standard user + + + 1 + Administrator + + + + + + + + + Changes the users account type. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change an account type + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new password mode, encoded as an integer: + + + 0 + Regular password + + + 1 + Password must be set at next login + + + 2 + No password + + + + + + + + + Changes the users password mode. + + + Note that changing the password mode has the side-effect of + unlocking the account. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change a users password mode + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The crypted password. + + + + + + + The password hint. + + + + + + + Sets a new password for this user. + + + Note that setting a password has the side-effect of + unlocking the account. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the password of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + Whether to enable automatic login for this user. + + + + + + + Enables or disables automatic login for a user. + + + Note that usually only one user can have automatic login + enabled, so turning it on for a user will disable it for + the previously configured autologin user. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.set-login-option + To change the login screen configuration + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + The uid of the user. + + + + + + + + + + The username of the user. + + + + + + + + + + The users real name. + + + + + + + + + + The users account type, encoded as an integer: + + + 0 + Standard user + + + 1 + Administrator + + + + + + + + + + + + The users home directory. + + + + + + + + + + The users shell. + + + + + + + + + + The email address. + + + + + + + + + + The users language, as a locale specification like "de_DE.UTF-8". + + + + + + + + + + The users x session. + + + + + + + + + + The users location. + + + + + + + + + + How often the user has logged in. + + + + + + + + + + The filename of a png file containing the users icon. + + + + + + + + + + Whether the users account is locked. + + + + + + + + + + The password mode for the user account, encoded as an integer: + + + 0 + Regular password + + + 1 + Password must be set at next login + + + 2 + No password + + + + + + + + + + + + The password hint for the user. + + + + + + + + + + Whether automatic login is enabled for the user. + + + + + + + + + + Whether this is a 'system' account, like 'root' or 'nobody'. + System accounts should normally not appear in lists of + users, and ListCachedUsers will not include such accounts. + + + + + + + + + + Emitted when the user is changed. + + + + + + + diff --git a/src/backend-dbus/org.freedesktop.Accounts.xml b/src/backend-dbus/org.freedesktop.Accounts.xml new file mode 100644 index 0000000..9c19761 --- /dev/null +++ b/src/backend-dbus/org.freedesktop.Accounts.xml @@ -0,0 +1,194 @@ + + + + + + + + + + Object paths of cached users + + + + + + Lists users which have logged into the system locally before. + This is not meant to return an exhaustive list of all users. + It is possible for FindUserByName() + to return a user that's not on the list. + + + + + + + + + The uid to look up + + + Object path of user + + + + + + Finds a user by uid. + + + + if no user with the given uid exists + + + + + + + + The username to look up + + + Object path of user + + + + + + Finds a user by its username. + + + + if no user with the given username exists + + + + + + + + The username for the new user + + + + The real name for the new user + + + Object path of the new user + + + + The account type, encoded as an integer + + + + + + Creates a new user account. + + + The accountType argument can take the following values: + + + + 0 + Standard user + + + 1 + Administrator + + + 2 + Supervised user + + + + + The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + The uid to delete + + + Whether to remove the users files + + + + + + Deletes a user account. + + + + The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + Object path of the user that was added. + + + + + Emitted when a user is added. + + + + + + + + Object path of the user that was deleted. + + + + + Emitted when a user is deleted. + + + + + + + + Object path of the user that was changed. + + + + + Emitted when a user is changed. + + + + + + + + + + The version of the running daemon. + + + + + + + diff --git a/src/backend-dbus/org.freedesktop.ConsoleKit.Manager.xml b/src/backend-dbus/org.freedesktop.ConsoleKit.Manager.xml new file mode 100644 index 0000000..f903b55 --- /dev/null +++ b/src/backend-dbus/org.freedesktop.ConsoleKit.Manager.xml @@ -0,0 +1,353 @@ + + + + + + + + + This method initiates a request to restart (ie. reboot) the computer system. + + + + + + + + + + + + + + This method initiates a request to stop (ie. shutdown) the computer system. + + + + + + + + + + + + + + The secret cookie that is used to identify the new session + + + + + This method requests that a new Session + be created for the calling process. The properties of this new Session are set automatically + from information collected about the calling process. + + This new session exists until the calling process disconnects from the system bus or + calls CloseSession(). + + It is the responsibility of the calling process to set the environment variable + XDG_SESSION_COOKIE to the value of the returned cookie. This cookie should only + be made available to child processes of the caller so that they may be identified + as members of this session. + + See this simple example: + + DBusError error; + DBusMessage *message; + DBusMessage *reply; + + message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "OpenSession"); + if (message == NULL) { + goto out; + } + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connector->connection, + message, + -1, + &error); + if (reply == NULL) { + goto out; + } + + dbus_error_init (&error); + if (! dbus_message_get_args (reply, + &error, + DBUS_TYPE_STRING, &cookie, + DBUS_TYPE_INVALID)) { + goto out; + } + + + + OpenSessionWithParameters() + + + + + + + An array of sets of property names and values + + + + + The secret cookie that is used to identify the new session + + + + + This method requests that a new Session + be created for the calling process. The properties of this new Session are from the + parameters provided. + + This new session exists until the calling process disconnects from the system bus or + calls CloseSession(). + + It is the responsibility of the calling process to set the environment variable + XDG_SESSION_COOKIE to the value of the returned cookie. This cookie should only + be made available to child processes of the caller so that they may be identified + as members of this session. + + See the Session properties for a list of valid parameters. + + org.freedesktop.ConsoleKit.Session + This method is restricted to privileged users by D-Bus policy. + + + + + + + The secret cookie that is used to identify the session + + + + + Whether the session was successfully closed + + + + + This method is used to close the session identified by the supplied cookie. + + The session can only be closed by the same process that opened the session. + + + + + + + + + an array of Seat IDs + + + + + This gets a list of all the Seats + that are currently present on the system. + Each Seat ID is an D-Bus object path for the object that implements the + Seat interface. + + org.freedesktop.ConsoleKit.Seat + + + + + + + an array of Session IDs + + + + + This gets a list of all the Sessions + that are currently present on the system. + Each Session ID is an D-Bus object path for the object that implements the + Session interface. + + org.freedesktop.ConsoleKit.Session + + + + + + + + The secret cookie that is used to identify the session + + + + + The object identifier for the current session + + + + + Returns the session ID that is associated with the specified cookie. + + + + + + + + + The POSIX process ID + + + + + The object identifier for the current session + + + + + Attempts to determine the session ID for the specified + POSIX process ID (pid). + + + + + + + + + The object identifier for the current session + + + + + Attempts to determine the session ID that the caller belongs to. + + See this example of using dbus-send: + + dbus-send --system --dest=org.freedesktop.ConsoleKit \ + --type=method_call --print-reply --reply-timeout=2000 \ + /org/freedesktop/ConsoleKit/Manager \ + org.freedesktop.ConsoleKit.Manager.GetCurrentSession + + + + + + + + + POSIX User identification + + + + + an array of Session IDs + + + + + This gets a list of all the Sessions + that are currently open for the specified user. + Each Session ID is an D-Bus object path for the object that implements the + Session interface. + + + + + + + + User identification + + + + + an array of Session IDs + + + + + This gets a list of all the Sessions + that are currently open for the specified user. + Each Session ID is an D-Bus object path for the object that implements the + Session interface. + + + + + + + + + The value of the system-idle-hint + + + + + Returns TRUE if the idle-hint + property of every open session is TRUE or if there are no open sessions. + + + + + + + + An ISO 8601 format date-type string + + + + + Returns an ISO 8601 date-time string that corresponds to + the time of the last change of the system-idle-hint. + + + + + + + + + The Seat ID for the added seat + + + + + Emitted when a Seat has been added to the system. + + + + + + + + The Seat ID for the removed seat + + + + + Emitted when a Seat has been removed from the system. + + + + + + + + The value of the system-idle-hint + + + + + Emitted when the value of the system-idle-hint has changed. + + + + + + diff --git a/src/backend-dbus/org.freedesktop.ConsoleKit.Seat.xml b/src/backend-dbus/org.freedesktop.ConsoleKit.Seat.xml new file mode 100644 index 0000000..58c2ce7 --- /dev/null +++ b/src/backend-dbus/org.freedesktop.ConsoleKit.Seat.xml @@ -0,0 +1,164 @@ + + + + + + + A seat is a collection of sessions and a set of hardware (usually at +least a keyboard and mouse). Only one session may be active on a +seat at a time. + + + + + + + Seat ID + + + + + Returns the ID for Seat. + + + + + + + + an array of Session IDs + + + + + This gets a list of all the Sessions + that are currently attached to this seat. + Each Session ID is an D-Bus object path for the object that implements the + Session interface. + + + + + + + + an array of devices + + + + + This gets a list of all the devices + that are currently associated with this seat. + Each device is an D-Bus structure that represents + the device type and the device id. + + + + + + + + + Session ID + + + + + Gets the Session ID that is currently active on this Seat. + Returns NULL if there is no active session. + + + + + + + + TRUE if seat supports session activation + + + + Used to determine whether the seat supports session activation. + + + + + + + + + Session ID + + + + + Attempt to activate the specified session. In most + cases, if successful, this will cause the session to + become visible and take control of the hardware that is + associated with this seat. + + Activate() + + + + + + + Session ID + + + + + Emitted when the active session has changed. + + + + + + + Session ID + + + + + Emitted when a session has been added to the seat. + + + + + + + Session ID + + + + + Emitted when a session has been removed from the seat. + + + + + + + Device structure + + + + + Emitted when a device has been associated with the seat. + + + + + + + Device structure + + + + + Emitted when a device has been dissociated from the seat. + + + + + diff --git a/src/backend-dbus/org.freedesktop.ConsoleKit.Session.xml b/src/backend-dbus/org.freedesktop.ConsoleKit.Session.xml new file mode 100644 index 0000000..b6e1cdb --- /dev/null +++ b/src/backend-dbus/org.freedesktop.ConsoleKit.Session.xml @@ -0,0 +1,435 @@ + + + + + + + Session objects represent and store information + related to a user session. + + The properties associated with the Session + specifically refer to the properties of the "session leader". + + + + + + + Session ID + + + + Returns the ID for Session. + + + + + + + Seat ID + + + + Returns the ID for the Seat the Session is + attached to. + + org.freedesktop.ConsoleKit.Seat + + + + + + Session type + + + + + Returns the type of the session. + Warning: we haven't yet defined the allowed values for this property. + It is probably best to avoid this until we do. + + + session-type + + + + + + User ID + + + + Returns the user that the session belongs to. + + + user + + + + + + POSIX User ID + + + + Returns the POSIX user ID that the session belongs to. + + unix-user + + + + + + The value of the X11 display + + + + Returns the value of the X11 DISPLAY for this session + if one is present. + + x11-display + + + + + + The value of the X11 display device + + + + Returns the value of the display device (aka TTY) that the + X11 display for the session is connected to. If there is no x11-display set then this value + is undefined. + + x11-display-device + + + + + + The value of the display device + + + + Returns the value of the display device (aka TTY) that the + session is connected to. + + display-device + + + + + + The remote host name + + + + Returns the value of the remote host name for the session. + + + remote-host-name + + + + + + The value of the native system login session ID + + + + Returns the value of the login session ID that the + underlying system uses to enforce session boundaries. If there is no login session ID + set then this value is an empty string. + + + + + + + TRUE if the session is active, otherwise FALSE + + + + Returns whether the session is active on the Seat that + it is attached to. + If the session is not attached to a seat this value is undefined. + + + active + + + + + + TRUE if the session is local, otherwise FALSE + + + + Returns whether the session is local + FIXME: we need to come up with a concrete definition for this value. + It was originally used as a way to identify XDMCP sessions that originate + from a remote system. + + + is-local + + + + + + An ISO 8601 format date-type string + + + + + Returns an ISO 8601 date-time string that corresponds to + the time that the session was opened. + + + + + + + + + + Attempt to activate the this session. In most + cases, if successful, this will cause the session to + become visible and become active on the seat that it + is attached to. + + Seat.ActivateSession() + + + + + + + This will cause a Lock + signal to be emitted for this session. + + + This method is restricted to privileged users by D-Bus policy. + Lock signal + + + + + + + This will cause an Unlock + signal to be emitted for this session. + + This can be used by login managers to unlock a session before it is + re-activated during fast-user-switching. + + + This method is restricted to privileged users by D-Bus policy. + Unlock signal + + + + + + + The value of the idle-hint + + + + + Gets the value of the idle-hint + property. + + + idle-hint + + + + + + An ISO 8601 format date-type string + + + + + Returns an ISO 8601 date-time string that corresponds to + the time of the last change of the idle-hint. + + + + + + + + + boolean value to set the idle-hint to + + + + + This may be used by the session to indicate that + it is idle. + + Use of this method is restricted to the user + that owns the session. + + + + + + + + TRUE if the session is active, otherwise FALSE + + + + + Emitted when the active property has changed. + + + + + + + the new value of idle-hint + + + + + Emitted when the idle-hint property has changed. + + + + + + + Emitted in response to a call to the Lock() method. + It is intended that the screensaver for the session should lock the screen in response to this signal. + + + + + + + Emitted in response to a call to the Unlock() method. + It is intended that the screensaver for the session should unlock the screen in response to this signal. + + + + + + + + The user assigned to the session. + + + + + + + The user assigned to the session. + + + + + + + + The type of the session. + Warning: we haven't yet defined the allowed values for this property. + It is probably best to avoid this until we do. + + + + + + + + The remote host name for the session. + + This will be set in situations where the session is + opened and controlled from a remote system. + + For example, this value will be set when the + session is created from an SSH or XDMCP connection. + + + + + + + + The display device (aka TTY) that the + session is connected to. + + + + + + + + Value of the X11 DISPLAY for this session + if one is present. + + + + + + + + + The display device (aka TTY) that the X11 display for the + session is connected to. If there is no x11-display set then + this value is undefined. + + + + + + + + + Whether the session is active on the Seat that + it is attached to. + If the session is not attached to a seat this value is undefined. + + + + + + + + + Whether the session is local + FIXME: we need to come up with a concrete definition for this value. + It was originally used as a way to identify XDMCP sessions that originate + from a remote system. + + + + + + + + + This is a hint used to indicate that the session may be idle. + + + For sessions with a x11-display set (ie. graphical + sessions), it is up to each session to delegate the + responsibility for updating this value. Typically, the + screensaver will set this. + + However, for non-graphical sessions with a display-device set + the Session object itself will periodically update this value based + on the activity detected on the display-device itself. + + + This should not be considered authoritative. + + + + + + + diff --git a/src/backend-dbus/org.gnome.ScreenSaver.xml b/src/backend-dbus/org.gnome.ScreenSaver.xml new file mode 100644 index 0000000..c21fdc5 --- /dev/null +++ b/src/backend-dbus/org.gnome.ScreenSaver.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/src/backend-dbus/org.gnome.SessionManager.EndSessionDialog.xml b/src/backend-dbus/org.gnome.SessionManager.EndSessionDialog.xml new file mode 100644 index 0000000..5392de0 --- /dev/null +++ b/src/backend-dbus/org.gnome.SessionManager.EndSessionDialog.xml @@ -0,0 +1,53 @@ + + + + + + + + + The type of dialog to show. + 0 for logout, 1 for shutdown, 2 for restart. + + + + + + + Timestamp of the user-initiated event which triggered + the call, or 0 if the call was not triggered by an event. + + + + + + + The number of seconds which the dialog should stay open + before automatic action is taken. + + + + + + + The object paths of all inhibitors that are registered + for the action. + + + + + + This function opens a dialog which asks the user for confirmation + of a logout, poweroff or reboot action. The dialog has a timeout + after which the action is automatically taken, and it should show + the inhibitors to the user. + + + + + + + + + + diff --git a/src/backend-dbus/org.gnome.SessionManager.xml b/src/backend-dbus/org.gnome.SessionManager.xml new file mode 100644 index 0000000..eb69180 --- /dev/null +++ b/src/backend-dbus/org.gnome.SessionManager.xml @@ -0,0 +1,451 @@ + + + + + + + + + + + The variable name + + + + + The value + + + + + Adds the variable name to the application launch environment with the specified value. May only be used during the Session Manager initialization phase. + + + + + + + + The locale category + + + + + The value + + + + + Reads the current state of the specific locale category. + + + + + + + + The error message + + + + + Whether the error should be treated as fatal + + + + + May be used by applications launched during the Session Manager initialization phase to indicate there was a problem. + + + + + + + + + + + The application identifier + + + + + Client startup identifier + + + + + The object path of the newly registered client + + + + + Register the caller as a Session Management client. + + + + + + + + + The object path of the client + + + + + Unregister the specified client from Session Management. + + + + + + + + + The application identifier + + + + + The toplevel X window identifier + + + + + The reason for the inhibit + + + + + Flags that specify what should be inhibited + + + + + The cookie + + + + + Proactively indicates that the calling application is performing an action that should not be interrupted and sets a reason to be displayed to the user when an interruption is about to take placea. + + + Applications should invoke this method when they begin an operation that + should not be interrupted, such as creating a CD or DVD. The types of actions + that may be blocked are specified by the flags parameter. When the application + completes the operation it should call Uninhibit() + or disconnect from the session bus. + + + Applications should not expect that they will always be able to block the + action. In most cases, users will be given the option to force the action + to take place. + + + Reasons should be short and to the point. + + + The flags parameter must include at least one of the following: + + + 1 + Inhibit logging out + + + 2 + Inhibit user switching + + + 4 + Inhibit suspending the session or computer + + + 8 + Inhibit the session being marked as idle + + + 16 + Inhibit auto-mounting removable media for the session + + + Values for flags may be bitwise or'ed together. + + + The returned cookie is used to uniquely identify this request. It should be used + as an argument to Uninhibit() in + order to remove the request. + + + + + + + + + + The cookie + + + + + Cancel a previous call to Inhibit() identified by the cookie. + + + + + + + + Flags that spefify what should be inhibited + + + + + Returns TRUE if any of the operations in the bitfield flags are inhibited + + + + + Determine if operation(s) specified by the flags + are currently inhibited. Flags are same as those accepted + by the + Inhibit() + method. + + + + + + + + an array of client IDs + + + + + This gets a list of all the Clients + that are currently known to the session manager. + Each Client ID is an D-Bus object path for the object that implements the + Client interface. + + org.gnome.SessionManager.Client + + + + + + + an array of inhibitor IDs + + + + + This gets a list of all the Inhibitors + that are currently known to the session manager. + Each Inhibitor ID is an D-Bus object path for the object that implements the + Inhibitor interface. + + org.gnome.SessionManager.Inhibitor + + + + + + + + The autostart condition string + + + + + True if condition is handled, false otherwise + + + + + Allows the caller to determine whether the session manager is + handling changes to the specified autostart condition. + + + + + + + + Request a shutdown dialog. + + + + + + + + Request a reboot dialog. + + + + + + + + True if shutdown is available to the user, false otherwise + + + + + Allows the caller to determine whether or not it's okay to show + a shutdown option in the UI + + + + + + + + The type of logout that is being requested + + + + + Request a logout dialog + + Allowed values for the mode parameter are: + + + 0 + Normal. + + + 1 + No confirmation inferface should be shown. + + + 2 + Forcefully logout. No confirmation will be shown and any inhibitors will be ignored. + + + Values for flags may be bitwise or'ed together. + + + + + + + + + True if the session has entered the Running phase, false otherwise + + + + + Allows the caller to determine whether the session manager + has entered the Running phase, in case the client missed the + SessionRunning signal. + + + + + + + + + + The object path for the added client + + + + + Emitted when a client has been added to the session manager. + + + + + + + + The object path for the removed client + + + + + Emitted when a client has been removed from the session manager. + + + + + + + + + The object path for the added inhibitor + + + + + Emitted when an inhibitor has been added to the session manager. + + + + + + + + The object path for the removed inhibitor + + + + + Emitted when an inhibitor has been removed from the session manager. + + + + + + + + + Indicates the session has entered the Running phase. + + + + + + + + Indicates the session is about to end. + + + + + + + + + + The name of the session that has been loaded. + + + + + + + + If true, the session is currently in the + foreground and available for user input. + + + + + + + + A bitmask of flags to indicate which actions + are inhibited. See the Inhibit() function's description + for a list of possible values. + + + + + + diff --git a/src/backend-dbus/session-dbus.xml b/src/backend-dbus/session-dbus.xml new file mode 100644 index 0000000..96e9837 --- /dev/null +++ b/src/backend-dbus/session-dbus.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/backend-dbus/upower.xml b/src/backend-dbus/upower.xml new file mode 100644 index 0000000..18d5fbd --- /dev/null +++ b/src/backend-dbus/upower.xml @@ -0,0 +1,309 @@ + + + + + + + + The DeviceKit-power service is available via the system message + bus. To access the service, use + the org.freedesktop.UPower interface on + the /org/freedesktop/UPower object on + the D-Bus system bus service with the well-known + name org.freedesktop.UPower. + + + + +$ dbus-send --print-reply \ + --system \ + --dest=org.freedesktop.UPower \ + /org/freedesktop/UPower \ + org.freedesktop.UPower.EnumerateDevices + +method return sender=:1.386 -> dest=:1.451 reply_serial=2 + array [ + object path "/org/freedesktop/UPower/devices/line_power_AC" + object path "/org/freedesktop/UPower/devices/battery_BAT0" + ] + + + + + + + + + + + + An array of object paths for devices. + + + + + + Enumerate all power objects on the system. + + + + + + + + + + Object path of device that was added. + + + + + + Emitted when a device is added. + + + + + + + + + + Object path of device that was removed. + + + + + + Emitted when a device is removed. + + + + + + + + + + Object path of device that was changed. + + + + + + Emitted when a device changed. + + + + + + + + + + + + Emitted when one or more properties on the object changes. + + + + + + + + + + + + This signal is sent when the session is about to be suspended or + hibernated. + Session and system programs have one second to do anything required + before the sleep action is taken (such as sending out Avahi or + Jabber messages). + + + + + + + + + + + + This signal is sent when the session has just returned from + Suspend() or Hibernate(). + Session and system programs can then do anything required (such as + sending out Avahi or Jabber messages). + + + + + + + + + + + + + This method tells UPower that the Suspend() or Hibernate() method + is about to be called. + This allows UPower to emit the Suspending signal whilst + session activities are happening that have to be done before the + suspend process is started. + + + This method would typically be called by the session power + management daemon, before it locks the screen and waits for the + screen to fade to black. + The session power management component would then call Suspend() or + Hibernate() when these syncronous tasks have completed. + + + If this method is not called than nothing bad will happen and + Suspend() or Hibernate() will block for the required second. + + + + + + + + + + + + + Suspends the computer into a low power state. + System state is not preserved if the power is lost. + + + If AboutToRequestSleep() has not been called then UPower will send + the Sleeping() signal and block for one second. + + + If AboutToRequestSleep() has been called less than one second + before this method is called then UPower will block for the + remaining time to complete one second of delay. + + + + + + + + + + + TRUE if allowed, otherwise FALSE + + + + + Check if the caller has (or can get) the PolicyKit privilege to call + Suspend. + + + + + + + + + + + + + Hibernates the computer into a low power state. + System state is preserved if the power is lost. + + + If AboutToRequestSleep() has not been called then UPower will send + the Sleeping() signal and block for one second. + + + If AboutToRequestSleep() has been called less than one second + before this method is called then UPower will block for the + remaining time to complete one second of delay. + + + + + + + + + + + TRUE if allowed, otherwise FALSE + + + + + Check if the caller has (or can get) the PolicyKit privilege to call + Hibernate. + + + + + + + + + + Version of the running daemon, e.g. 002. + + + + + + Whether the system is able to suspend. + + + + + + Whether the system is able to hibernate. + + + + + + Indicates whether the system is running on battery power. + This property is provided for convenience. + + + + + + Indicates whether the system is running on battery power and if the battery is critically low. + This property is provided for convenience. + + + + + + + + Indicates if the laptop lid is closed where the display cannot be seen. + + + + + + + + + + If the system has a lid device. + + + + + + + + diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c new file mode 100644 index 0000000..4798d33 --- /dev/null +++ b/src/backend-dbus/users.c @@ -0,0 +1,810 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "dbus-accounts.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-session.h" +#include "dbus-consolekit-manager.h" +#include "dbus-user.h" + +#include "users.h" + +struct _IndicatorSessionUsersDbusPriv +{ + char * active_session_id; + + Accounts * accounts; + + DisplayManagerSeat * dm_seat; + + ConsoleKitSeat * seat_proxy; + + /* user's dbus object path -> AccountsUser* */ + GHashTable * path_to_user; + + /* uint32 user-id --> user's dbus object path */ + GHashTable * uid_to_user_path; + + /* uint32 user-id --> hashset of ssid strings */ + GHashTable * uid_to_sessions; + + /* ssid string --> uint32 user-id */ + GHashTable * session_to_uid; + + GCancellable * cancellable; +}; + +typedef IndicatorSessionUsersDbusPriv priv_t; + +G_DEFINE_TYPE (IndicatorSessionUsersDbus, + indicator_session_users_dbus, + INDICATOR_TYPE_SESSION_USERS) + +/*** +**** +***/ + +static void create_user_proxy_for_path (IndicatorSessionUsersDbus * self, + const char * path); + +static void create_session_proxy_for_ssid (IndicatorSessionUsersDbus * self, + const char * ssid); + +static void +emit_user_changed_for_path (IndicatorSessionUsersDbus * self, const char * path) +{ + AccountsUser * user = g_hash_table_lookup (self->priv->path_to_user, path); + + if (user && !accounts_user_get_system_account (user)) + indicator_session_users_changed (INDICATOR_SESSION_USERS(self), path); +} + +static void +emit_user_changed_for_uid (IndicatorSessionUsersDbus * self, guint uid) +{ + const char * path; + + if ((path = g_hash_table_lookup (self->priv->uid_to_user_path, GUINT_TO_POINTER(uid)))) + emit_user_changed_for_path (self, path); +} + +/*** +**** ACCOUNT MANAGER / USER TRACKING +***/ + +/* called when a user proxy gets the 'Changed' signal */ +static void +on_user_changed (AccountsUser * user, gpointer gself) +{ + /* Accounts.User doesn't update properties in the standard way, + * so create a new proxy to pull in the new properties. + * The older proxy is freed when it's removed from our path_to_user hash */ + const char * path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)); + create_user_proxy_for_path (gself, path); +} + +static void +track_user (IndicatorSessionUsersDbus * self, + AccountsUser * user) +{ + priv_t * p; + const char * path; + gboolean already_had_user; + + p = self->priv; + + path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)); + already_had_user = g_hash_table_contains (p->path_to_user, path); + + g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); + g_hash_table_insert (p->path_to_user, g_strdup(path), user); + + if (already_had_user) + { + emit_user_changed_for_path (self, path); + } + else + { + const guint uid = (guint) accounts_user_get_uid (user); + + g_hash_table_insert (p->uid_to_user_path, + GUINT_TO_POINTER(uid), + g_strdup(path)); + + if (!accounts_user_get_system_account (user)) + indicator_session_users_added (INDICATOR_SESSION_USERS(self), path); + } +} + +static void +untrack_user (IndicatorSessionUsersDbus * self, + const gchar * path) +{ + g_hash_table_remove (self->priv->path_to_user, path); + + indicator_session_users_removed (INDICATOR_SESSION_USERS(self), path); +} + + +static void +on_user_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer self) +{ + GError * err; + AccountsUser * user; + + err = NULL; + user = accounts_user_proxy_new_for_bus_finish (res, &err); + if (err != NULL) + { + g_warning ("%s: %s", G_STRFUNC, err->message); + g_error_free (err); + } + else + { + track_user (self, user); + } +} + +static void +create_user_proxy_for_path (IndicatorSessionUsersDbus * self, + const char * path) +{ + const char * name = "org.freedesktop.Accounts"; + const GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + + accounts_user_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, path, + self->priv->cancellable, + on_user_proxy_ready, self); +} + +static void +on_user_list_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar ** paths; + + err = NULL; + paths = NULL; + accounts_call_list_cached_users_finish (ACCOUNTS(o), &paths, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + int i; + + for (i=0; paths && paths[i]; ++i) + create_user_proxy_for_path (gself, paths[i]); + + g_strfreev (paths); + } +} + +static void +set_account_manager (IndicatorSessionUsersDbus * self, Accounts * a) +{ + priv_t * p = self->priv; + + if (p->accounts != NULL) + { + g_signal_handlers_disconnect_by_data (p->accounts, self); + g_clear_object (&p->accounts); + } + + if (a != NULL) + { + p->accounts = g_object_ref (a); + + accounts_call_list_cached_users (a, + self->priv->cancellable, + on_user_list_ready, + self); + + g_signal_connect_swapped (a, "user-added", + G_CALLBACK(create_user_proxy_for_path), self); + + g_signal_connect_swapped (a, "user-deleted", + G_CALLBACK(untrack_user), self); + } +} + +#if 0 +static void +create_accounts_proxy (IndicatorSessionUsersDbus * self) +{ + const char * name = "org.freedesktop.Accounts"; + const char * path = "/org/freedesktop/Accounts"; + GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + + accounts_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, path, + self->priv->cancellable, + on_accounts_proxy_ready, self); +} +#endif + +/** + * SEAT / SESSION TRACKING + * + * There are two simple goals here: + * + * 1. Keep track of how many GUI sessions each user has + * so that we can set the 'is_logged_in' flag correctly + * + * 2. Also track which is the current session, + * so that we can compare it to those GUI sessions to + * set the 'is_current_session' flag correctly. + * + * Now that you know the goals, these steps may make more sense: + * + * 1. create a ConsoleKitManager proxy + * 2. ask it for the current session + * 3. create a corresponding Session proxy + * 4. ask that Session proxy for its seat + * 5. create a corresponding Seat proxy + * 6. connect to that seat's session-added / session-removed signals + * 7. ask the seat for a list of its current sessions + * 8. create corresponding Session proxies + * 9. of them, look for the GUI sessions by checking their X11 properties + * 10. for each GUI session, get the corresponding uid + * 11. use the information to update our uid <--> GUI sessions tables + */ + +static void +track_session (IndicatorSessionUsersDbus * self, + const char * ssid, + guint uid) +{ + gpointer uid_key; + GHashTable * sessions; + + uid_key = GUINT_TO_POINTER (uid); + sessions = g_hash_table_lookup (self->priv->uid_to_sessions, uid_key); + if (sessions == NULL) + { + sessions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_hash_table_insert (self->priv->uid_to_sessions, uid_key, sessions); + } + + g_hash_table_add (sessions, g_strdup (ssid)); + g_hash_table_insert (self->priv->session_to_uid, g_strdup(ssid), uid_key); + + g_debug ("%s %s now tracking ssid:%s uid:%u. uid has %u tracked ssids.", + G_STRLOC, G_STRFUNC, ssid, uid, g_hash_table_size (sessions)); + + emit_user_changed_for_uid (self, uid); +} + +static void +untrack_session (IndicatorSessionUsersDbus * self, + const char * ssid) +{ + gpointer uidptr; + priv_t * p = self->priv; + + if (g_hash_table_lookup_extended (p->session_to_uid, ssid, NULL, &uidptr)) + { + const guint uid = GPOINTER_TO_UINT (uidptr); + GHashTable * sessions = g_hash_table_lookup (p->uid_to_sessions, uidptr); + + g_hash_table_remove (p->session_to_uid, ssid); + g_hash_table_remove (sessions, ssid); + g_debug ("%s %s not tracking ssid:%s uid:%u. uid has %u tracked ssids.", + G_STRLOC, G_STRFUNC, ssid, uid, + sessions ? g_hash_table_size (sessions) : 0); + + emit_user_changed_for_uid (self, uid); + } +} + +static void +on_session_proxy_uid_ready (GObject * o, + GAsyncResult * res, + gpointer gself) +{ + guint uid; + GError * err; + ConsoleKitSession * session = CONSOLE_KIT_SESSION (o); + + uid = 0; + err = NULL; + console_kit_session_call_get_unix_user_finish (session, &uid, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else if (uid) + { + const char * path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(session)); + track_session (gself, path, uid); + } + + g_object_unref (o); +} + +static void +on_session_x11_display_ready (GObject * o, + GAsyncResult * res, + gpointer gself) +{ + priv_t * p; + GError * err; + gchar * gui; + ConsoleKitSession * session; + + p = INDICATOR_SESSION_USERS_DBUS(gself)->priv; + + err = NULL; + gui = NULL; + session = CONSOLE_KIT_SESSION (o); + console_kit_session_call_get_x11_display_finish (session, &gui, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + gboolean is_gui_session; + + is_gui_session = gui && *gui; + + if (!is_gui_session) + g_clear_object (&session); + else + console_kit_session_call_get_unix_user (session, + p->cancellable, + on_session_proxy_uid_ready, + gself); + + g_free (gui); + } +} + +static void +on_session_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + ConsoleKitSession * session; + + err = NULL; + session = console_kit_session_proxy_new_finish (res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else if (session != NULL) + { + priv_t * p = INDICATOR_SESSION_USERS_DBUS(gself)->priv; + + console_kit_session_call_get_x11_display (session, + p->cancellable, + on_session_x11_display_ready, + gself); + } +} + +static void +create_session_proxy_for_ssid (IndicatorSessionUsersDbus * self, + const char * ssid) +{ + const char * name = "org.freedesktop.ConsoleKit"; + GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + + console_kit_session_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, ssid, + self->priv->cancellable, + on_session_proxy_ready, self); +} + +static void +on_session_list_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar ** sessions; + + err = NULL; + sessions = NULL; + console_kit_seat_call_get_sessions_finish (CONSOLE_KIT_SEAT(o), + &sessions, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + int i; + + for (i=0; sessions && sessions[i]; i++) + create_session_proxy_for_ssid (gself, sessions[i]); + + g_strfreev (sessions); + } +} + +static inline guint +get_uid_for_session (IndicatorSessionUsersDbus * self, const char * ssid) +{ + guint uid = 0; + gpointer value; + + if (ssid != NULL) + if ((value = g_hash_table_lookup (self->priv->session_to_uid, ssid))) + uid = GPOINTER_TO_UINT (value); + + return uid; +} + +/* it's a live session if username is 'ubuntu' and uid is 999 */ +static gboolean +is_live_ssid (IndicatorSessionUsersDbus * self, const char * ssid) +{ + priv_t * p; + guint uid; + + p = INDICATOR_SESSION_USERS_DBUS (self)->priv; + uid = get_uid_for_session (self, ssid); + + if (uid == 999) + { + const char * path; + AccountsUser * user = NULL; + + if ((path = g_hash_table_lookup (p->uid_to_user_path, GUINT_TO_POINTER (uid)))) + user = g_hash_table_lookup (p->path_to_user, path); + + return (user != NULL) && !g_strcmp0 (accounts_user_get_user_name(user), "ubuntu"); + } + + return FALSE; +} + + +static void +set_active_session (IndicatorSessionUsersDbus * self, const char * ssid) +{ + priv_t * p = self->priv; + const guint old_uid = get_uid_for_session (self, p->active_session_id); + const guint new_uid = get_uid_for_session (self, ssid); + const gboolean old_live = is_live_ssid (self, p->active_session_id); + const gboolean new_live = is_live_ssid (self, ssid); + + g_debug ("%s %s changing active_session_id from '%s' to '%s'", + G_STRLOC, G_STRFUNC, p->active_session_id, ssid); + g_free (p->active_session_id); + p->active_session_id = g_strdup (ssid); + + if (old_uid != new_uid) + { + emit_user_changed_for_uid (self, old_uid); + emit_user_changed_for_uid (self, new_uid); + } + + if (old_live != new_live) + { + indicator_session_users_notify_is_live_session (INDICATOR_SESSION_USERS(self)); + } +} + +static void +on_seat_active_session_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar * ssid; + ConsoleKitSeat * seat; + + err = NULL; + ssid = NULL; + seat = CONSOLE_KIT_SEAT (o); + console_kit_seat_call_get_active_session_finish (seat, &ssid, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else if (ssid != NULL) + { + set_active_session (INDICATOR_SESSION_USERS_DBUS(gself), ssid); + g_free (ssid); + } +} + +static void +set_seat (IndicatorSessionUsersDbus * self, ConsoleKitSeat * seat) +{ + priv_t * p = self->priv; + + if (p->seat_proxy != NULL) + { + g_signal_handlers_disconnect_by_data (p->seat_proxy, self); + g_clear_object (&p->seat_proxy); + } + + if (seat != NULL) + { + p->seat_proxy = g_object_ref (seat); + + /* ask the seat for a list of all the sessions */ + console_kit_seat_call_get_sessions (seat, + p->cancellable, + on_session_list_ready, + self); + + /* ask the seat for the name of the active session */ + console_kit_seat_call_get_active_session (p->seat_proxy, + p->cancellable, + on_seat_active_session_ready, + self); + + /* listen for session changes in this seat */ + g_signal_connect_swapped (seat, "session-added", + G_CALLBACK(create_session_proxy_for_ssid),self); + g_signal_connect_swapped (seat, "session-removed", + G_CALLBACK(untrack_session), self); + g_signal_connect_swapped (seat, "active-session-changed", + G_CALLBACK(set_active_session), self); + } +} + +/*** +**** +***/ + +static void +set_dm_seat (IndicatorSessionUsersDbus * self, DisplayManagerSeat * dm_seat) +{ + priv_t * p = self->priv; + + g_clear_object (&p->dm_seat); + + if (dm_seat != NULL) + p->dm_seat = g_object_ref (dm_seat); +} + +static void +activate_username (IndicatorSessionUsersDbus * self, const char * username) +{ + priv_t * p = self->priv; + const char * session = ""; + + g_return_if_fail (p->dm_seat != NULL); + + display_manager_seat_call_switch_to_user (p->dm_seat, username, session, + p->cancellable, NULL, NULL); +} + +/*** +**** +***/ + +static void +my_dispose (GObject * o) +{ + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (o); + priv_t * p = self->priv; + + if (p->cancellable) + { + g_cancellable_cancel (p->cancellable); + g_clear_object (&p->cancellable); + } + + set_seat (self, NULL); + set_dm_seat (self, NULL); + set_account_manager (self, NULL); + + g_clear_pointer (&p->path_to_user, g_hash_table_destroy); + g_clear_pointer (&p->session_to_uid, g_hash_table_destroy); + g_clear_pointer (&p->uid_to_sessions, g_hash_table_destroy); + g_clear_pointer (&p->uid_to_user_path, g_hash_table_destroy); + + G_OBJECT_CLASS (indicator_session_users_dbus_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + IndicatorSessionUsersDbus * u = INDICATOR_SESSION_USERS_DBUS (o); + + g_free (u->priv->active_session_id); + + G_OBJECT_CLASS (indicator_session_users_dbus_parent_class)->finalize (o); +} + +static void +my_activate_user (IndicatorSessionUsers * users, const char * key) +{ + priv_t * p; + const char * username = 0; + + p = INDICATOR_SESSION_USERS_DBUS (users)->priv; + if (p != 0) + { + AccountsUser * au = g_hash_table_lookup (p->path_to_user, key); + + if (au != NULL) + username = accounts_user_get_user_name (au); + } + + if (username != 0) + activate_username (INDICATOR_SESSION_USERS_DBUS(users), username); + else + g_warning ("%s %s can't find user for '%s'", G_STRLOC, G_STRFUNC, key); +} + +static gboolean +my_is_live_session (IndicatorSessionUsers * users) +{ + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS(users); + + return is_live_ssid (self, self->priv->active_session_id); +} + +static GStrv +my_get_keys (IndicatorSessionUsers * users) +{ + int i; + priv_t * p; + gchar ** keys; + GHashTableIter iter; + gpointer path; + gpointer user; + + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_DBUS(users), NULL); + p = INDICATOR_SESSION_USERS_DBUS (users)->priv; + + i = 0; + keys = g_new (gchar*, g_hash_table_size(p->path_to_user)+1); + g_hash_table_iter_init (&iter, p->path_to_user); + while (g_hash_table_iter_next (&iter, &path, &user)) + if (!accounts_user_get_system_account (user)) + keys[i++] = g_strdup (path); + keys[i] = NULL; + + return keys; +} + +static IndicatorSessionUser * +my_get_user (IndicatorSessionUsers * users, const gchar * key) +{ + priv_t * p; + AccountsUser * au; + IndicatorSessionUser * ret = NULL; + + p = INDICATOR_SESSION_USERS_DBUS (users)->priv; + + au = g_hash_table_lookup (p->path_to_user, key); + if (au && !accounts_user_get_system_account(au)) + { + const guint uid = (guint) accounts_user_get_uid (au); + GHashTable * s; + + ret = g_new0 (IndicatorSessionUser, 1); + + s = g_hash_table_lookup (p->uid_to_sessions, GUINT_TO_POINTER(uid)); + if (s == NULL) + { + ret->is_logged_in = FALSE; + ret->is_current_user = FALSE; + } + else + { + ret->is_logged_in = g_hash_table_size (s) > 0; + ret->is_current_user = g_hash_table_contains (s, p->active_session_id); + } + + ret->uid = uid; + ret->user_name = g_strdup (accounts_user_get_user_name (au)); + ret->real_name = g_strdup (accounts_user_get_real_name (au)); + ret->icon_file = g_strdup (accounts_user_get_icon_file (au)); + ret->login_frequency = accounts_user_get_login_frequency (au); + } + + return ret; +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_dbus_class_init (IndicatorSessionUsersDbusClass * klass) +{ + GObjectClass * object_class; + IndicatorSessionUsersClass * users_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + users_class = INDICATOR_SESSION_USERS_CLASS (klass); + users_class->is_live_session = my_is_live_session; + users_class->get_keys = my_get_keys; + users_class->get_user = my_get_user; + users_class->activate_user = my_activate_user; + + g_type_class_add_private (klass, sizeof (IndicatorSessionUsersDbusPriv)); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_dbus_init (IndicatorSessionUsersDbus * self) +{ + priv_t * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_USERS_DBUS, + IndicatorSessionUsersDbusPriv); + self->priv = p; + p->cancellable = g_cancellable_new (); + + p->path_to_user = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); + + p->uid_to_user_path = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, g_free); + + p->session_to_uid = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + + p->uid_to_sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify)g_hash_table_destroy); + +#if 0 + console_kit_manager_proxy_new_for_bus ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + p->cancellable, + on_console_kit_manager_proxy_ready, + self); +#endif +} + +/*** +**** Public +***/ + +IndicatorSessionUsers * +indicator_session_users_dbus_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_SESSION_USERS_DBUS, NULL); + + return INDICATOR_SESSION_USERS (o); +} + +void +indicator_session_users_dbus_set_proxies (IndicatorSessionUsersDbus * self, + Accounts * accounts, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * seat) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS_DBUS (self)); + + set_account_manager (self, accounts); + set_seat (self, seat); + set_dm_seat (self, dm_seat); +} diff --git a/src/backend-dbus/users.h b/src/backend-dbus/users.h new file mode 100644 index 0000000..ff1e0ad --- /dev/null +++ b/src/backend-dbus/users.h @@ -0,0 +1,71 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __USERS_DBUS_H__ +#define __USERS_DBUS_H__ + +#include +#include + +#include "../users.h" /* parent class */ +#include "dbus-accounts.h" +#include "dbus-consolekit-seat.h" +#include "dbus-display-manager.h" + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_USERS_DBUS (indicator_session_users_dbus_get_type()) +#define INDICATOR_SESSION_USERS_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_USERS_DBUS, IndicatorSessionUsersDbus)) +#define INDICATOR_SESSION_USERS_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_USERS_DBUS, IndicatorSessionUsersDbusClass)) +#define INDICATOR_IS_SESSION_USERS_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_USERS_DBUS)) + +typedef struct _IndicatorSessionUsersDbus IndicatorSessionUsersDbus; +typedef struct _IndicatorSessionUsersDbusPriv IndicatorSessionUsersDbusPriv; +typedef struct _IndicatorSessionUsersDbusClass IndicatorSessionUsersDbusClass; + +/** + * An implementation of IndicatorSessionUsers that gets its user information + * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus. + */ +struct _IndicatorSessionUsersDbus +{ + /*< private >*/ + IndicatorSessionUsers parent; + IndicatorSessionUsersDbusPriv * priv; +}; + +struct _IndicatorSessionUsersDbusClass +{ + IndicatorSessionUsersClass parent_class; +}; + +GType indicator_session_users_dbus_get_type (void); + +IndicatorSessionUsers * indicator_session_users_dbus_new (void); + +void indicator_session_users_dbus_set_proxies (IndicatorSessionUsersDbus *, + Accounts *, + DisplayManagerSeat *, + ConsoleKitSeat *); + + + +G_END_DECLS + +#endif diff --git a/src/backend-dbus/utils.c b/src/backend-dbus/utils.c new file mode 100644 index 0000000..86a5e5a --- /dev/null +++ b/src/backend-dbus/utils.c @@ -0,0 +1,399 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "utils.h" + +/*** +**** indicator_session_util_get_session_proxies() +***/ + +struct session_proxy_data +{ + ConsoleKitManager * ck_manager; + Accounts * account_manager; + DisplayManagerSeat * dm_seat; + + ConsoleKitSeat * current_seat; + ConsoleKitSession * current_session; + AccountsUser * active_user; + + GCancellable * cancellable; + GError * error; + int pending; + + indicator_session_util_session_proxies_func callback; + gpointer user_data; +}; + +static void +session_proxy_data_free (struct session_proxy_data * data) +{ + g_clear_object (&data->ck_manager); + g_clear_object (&data->account_manager); + g_clear_object (&data->dm_seat); + + g_clear_object (&data->current_seat); + g_clear_object (&data->current_session); + g_clear_object (&data->active_user); + + g_clear_object (&data->cancellable); + g_clear_error (&data->error); + + g_free (data); +} + +static void +finish_callback (struct session_proxy_data * data) +{ + g_assert (data != NULL); + g_debug ("%s %s: pending is %d", G_STRLOC, G_STRFUNC, (data->pending-1)); + + if (!--data->pending) + { + data->callback (data->ck_manager, + data->account_manager, + data->dm_seat, + data->current_seat, + data->current_session, + data->active_user, + data->error, + data->user_data); + + session_proxy_data_free (data); + } +} + +static void +on_user_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer gdata) +{ + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + data->active_user = accounts_user_proxy_new_for_bus_finish (res, &data->error); + + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else + { + g_debug ("%s %s user proxy is %p", G_STRLOC, G_STRFUNC, (void*)data->active_user); + } + + finish_callback (data); +} + +static void +on_user_path_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + char * path = NULL; + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + accounts_call_find_user_by_id_finish (data->account_manager, &path, res, &data->error); + + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else if (path != NULL) + { + g_debug ("%s %s user path is %s", G_STRLOC, G_STRFUNC, path); + ++data->pending; + accounts_user_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.Accounts", + path, + data->cancellable, + on_user_proxy_ready, + data); + } + + finish_callback (data); + g_free (path); +} + +static void +on_uid_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + guint uid = 0; + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + console_kit_session_call_get_unix_user_finish (data->current_session, &uid, res, &data->error); + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else if (uid) + { + g_debug ("%s %s uid is %u", G_STRLOC, G_STRFUNC, uid); + ++data->pending; + accounts_call_find_user_by_id (data->account_manager, + uid, + data->cancellable, + on_user_path_ready, + data); + } + + finish_callback (data); +} + +static void +on_seat_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + data->current_seat = console_kit_seat_proxy_new_for_bus_finish (res, &data->error); + + if (data->error != NULL) + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + + finish_callback (data); +} + +static void +on_sid_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + char * sid = NULL; + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + console_kit_session_call_get_seat_id_finish (data->current_session, &sid, res, &data->error); + + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else if (sid != NULL) + { + g_debug ("%s %s sid is %s", G_STRLOC, G_STRFUNC, sid); + ++data->pending; + console_kit_seat_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + sid, + data->cancellable, + on_seat_proxy_ready, + data); + } + + finish_callback (data); + g_free (sid); +} + +static void +on_session_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + data->current_session = console_kit_session_proxy_new_finish (res, &data->error); + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else + { + ++data->pending; + console_kit_session_call_get_seat_id (data->current_session, + data->cancellable, + on_sid_ready, + data); + + ++data->pending; + console_kit_session_call_get_unix_user (data->current_session, + data->cancellable, + on_uid_ready, + data); + } + + finish_callback (data); +} + +static void +on_current_session_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + char * ssid = NULL; + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + ssid = NULL; + console_kit_manager_call_get_current_session_finish (data->ck_manager, + &ssid, res, + &data->error); + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else if (ssid) + { + g_debug ("%s %s ssid is %s", G_STRLOC, G_STRFUNC, ssid); + data->pending++; + console_kit_session_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + ssid, + data->cancellable, + on_session_proxy_ready, + data); + + } + + finish_callback (data); + g_free (ssid); +} + +static void +on_display_manager_seat_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer gdata) +{ + DisplayManagerSeat * seat; + struct session_proxy_data * data = gdata; + + seat = display_manager_seat_proxy_new_for_bus_finish (res, &data->error); + + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else if (seat != NULL) + { + data->dm_seat = g_object_ref (seat); + } + + finish_callback (data); + g_clear_object (&seat); +} + +static void +on_console_kit_manager_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer gdata) +{ + ConsoleKitManager * mgr; + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + if (data->error == NULL) + { + mgr = console_kit_manager_proxy_new_for_bus_finish (res, &data->error); + g_debug ("%s %s mgr is %p, err is %p", G_STRLOC, G_STRFUNC, (void*)mgr, (void*)data->error); + + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else + { + data->ck_manager = mgr; + + data->pending++; + console_kit_manager_call_get_current_session (mgr, + data->cancellable, + on_current_session_ready, + data); + + } + } + + finish_callback (data); +} + +static void +on_accounts_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + if (data->error == NULL) + { + data->account_manager = accounts_proxy_new_for_bus_finish (res, &data->error); + + if (data->error != NULL) + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + + finish_callback (data); +} + +/** + * Getting all the proxies we want is kind of a pain -- + * especially without blocking (ie, using _sync() funcs) -- + * so it's farmed out to this wrapper utility. + * + * 1. in this func, start getting the ConsoleKit and Accounts proxies + * 2. when the accounts proxy is ready, stash it in data.account_manager + * 3. when the ck manager proxy is ready, stash it in data.ck_manager and + * ask it for the current session's ssid + * 4. when the ssid is ready, start getting a proxy for it + * 5. when the session's proxy is ready, stash it in data.current_session + * and ask it for both the current seat's sid and the active user's uid + * 6. When the current seat's sid is ready, start getting a proxy for it + * 7. When the current seat's proxy is ready, stash it in data.current_seat + * 8. when the active user's uid is ready, ask data.account_manager for the path + * 9. when the user path is ready, start getting an Accounts.User proxy for it + * 10. when the Accounts.User proxy is read, stash it in data.active_user + * + * When everything is done, or if there's an error, invoke the data.callback + */ +void +indicator_session_util_get_session_proxies ( + indicator_session_util_session_proxies_func func, + GCancellable * cancellable, + gpointer user_data) +{ + struct session_proxy_data * data; + + data = g_new0 (struct session_proxy_data, 1); + data->callback = func; + data->user_data = user_data; + data->cancellable = g_object_ref (cancellable); + + data->pending++; + accounts_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.Accounts", + "/org/freedesktop/Accounts", + data->cancellable, + on_accounts_proxy_ready, data); + + data->pending++; + console_kit_manager_proxy_new_for_bus ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + data->cancellable, + on_console_kit_manager_proxy_ready, data); + + data->pending++; + display_manager_seat_proxy_new_for_bus ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.DisplayManager", + g_getenv ("XDG_SEAT_PATH"), + data->cancellable, + on_display_manager_seat_proxy_ready, data); + +} diff --git a/src/backend-dbus/utils.h b/src/backend-dbus/utils.h new file mode 100644 index 0000000..b4f26c3 --- /dev/null +++ b/src/backend-dbus/utils.h @@ -0,0 +1,53 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __DBUS_UTILS_H__ +#define __DBUS_UTILS_H__ + +#include +#include + +#include "dbus-accounts.h" +#include "dbus-display-manager.h" +#include "dbus-user.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-session.h" +#include "dbus-consolekit-manager.h" + +typedef void (*indicator_session_util_session_proxies_func)( + ConsoleKitManager * ck_manager, + Accounts * account_manager, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * current_ck_seat, + ConsoleKitSession * current_ck_session, + AccountsUser * active_user, + const GError * error, + gpointer user_data); + +/** + * Both users-dbus and guest-dbus need some of these proxies. + * Getting them all involves a lot of steps, so instead of repeating + * ourselves, the common dbus steps are extracted to this func. + */ +void indicator_session_util_get_session_proxies ( + indicator_session_util_session_proxies_func func, + GCancellable * cancellable, + gpointer user_data); + +#endif diff --git a/src/backend.h b/src/backend.h new file mode 100644 index 0000000..2df215d --- /dev/null +++ b/src/backend.h @@ -0,0 +1,47 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __INDICATOR_SESSION_BACKEND_H__ +#define __INDICATOR_SESSION_BACKEND_H__ + +#include /* GCancellable */ + +#include "actions.h" +#include "guest.h" +#include "users.h" + +G_BEGIN_DECLS + +/** + * Gets instances of the backend abstract base classes. + * These are how IndicatorSystemService knows what's happening on the system. + * + * This function isn't defined in libindicatorsessionservice. + * Instead, one of two implementations is statically linked at build time: + * one for production in libbackenddbus (in src/backend-dbus/) or + * one for testing in libbackendmock (in tests/). + */ +void backend_get (GCancellable * cancellable, + IndicatorSessionActions ** setme_actions, + IndicatorSessionUsers ** setme_users, + IndicatorSessionGuest ** setme_guest); + +G_END_DECLS + +#endif diff --git a/src/dialog.c b/src/dialog.c deleted file mode 100644 index eb91f57..0000000 --- a/src/dialog.c +++ /dev/null @@ -1,248 +0,0 @@ -/* -A dialog to ask the user about the various logout options that -are available. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "dbus-consolekit-manager.h" -#include "dialog.h" - -/* Strings */ - -static const gchar * title_strings[LOGOUT_DIALOG_TYPE_CNT] = { - /* LOGOUT_DIALOG_LOGOUT, */ NC_("title", "Log Out"), - /* LOGOUT_DIALOG_RESTART, */ NC_("title", "Restart"), - /* LOGOUT_DIALOG_SHUTDOWN, */ NC_("title", "Shut Down") -}; - -static const gchar * body_strings[LOGOUT_DIALOG_TYPE_CNT] = { - /* LOGOUT_DIALOG_LOGOUT, */ N_("Are you sure you want to close all programs and log out of the computer?"), - /* LOGOUT_DIALOG_RESTART, */ N_("Are you sure you want to close all programs and restart the computer?"), - /* LOGOUT_DIALOG_SHUTDOWN, */ N_("Are you sure you want to close all programs and shut down the computer?") -}; - -static const gchar * button_strings[LOGOUT_DIALOG_TYPE_CNT] = { - /* LOGOUT_DIALOG_LOGOUT, */ NC_("button", "Log Out"), - /* LOGOUT_DIALOG_RESTART, */ NC_("button", "Restart"), - /* LOGOUT_DIALOG_SHUTDOWN, */ NC_("button", "Shut Down") -}; - -/* TRANSLATORS: These strings have an ellipsis so that the user knows - they are also going to get a password dialog to do the action. */ -static const gchar * button_auth_strings[LOGOUT_DIALOG_TYPE_CNT] = { - /* LOGOUT_DIALOG_LOGOUT, */ NC_("button auth", "Log Out"), - /* LOGOUT_DIALOG_RESTART, */ NC_("button auth", "Restart…"), - /* LOGOUT_DIALOG_SHUTDOWN, */ NC_("button auth", "Shut Down…") -}; - -/* TRANSLATORS: This button appears on the logout dialog when - there are updates that require restart. It will do a restart - in place of a log out. */ -static const gchar * restart_updates = N_("Restart Instead"); -static const gchar * restart_auth = N_("Restart Instead…"); -static const gchar * body_logout_update = N_("Some software updates won’t apply until the computer next restarts."); - -static const gchar * icon_strings[LOGOUT_DIALOG_TYPE_CNT] = { - /* LOGOUT_DIALOG_LOGOUT, */ "system-log-out", - /* LOGOUT_DIALOG_RESTART, */ "system-restart", - /* LOGOUT_DIALOG_SHUTDOWN, */ "system-shutdown" -}; - - - -typedef struct _LogoutDialogPrivate LogoutDialogPrivate; -struct _LogoutDialogPrivate { - guint type; -}; - -#define LOGOUT_DIALOG_GET_PRIVATE(o) \ -(G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGOUT_DIALOG_TYPE, LogoutDialogPrivate)) - -static void logout_dialog_class_init (LogoutDialogClass *klass); -static void logout_dialog_init (LogoutDialog *self); -static void logout_dialog_dispose (GObject *object); -static void logout_dialog_finalize (GObject *object); - -G_DEFINE_TYPE (LogoutDialog, logout_dialog, GTK_TYPE_MESSAGE_DIALOG); - -static void -logout_dialog_class_init (LogoutDialogClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (LogoutDialogPrivate)); - - object_class->dispose = logout_dialog_dispose; - object_class->finalize = logout_dialog_finalize; - - return; -} - -static void -logout_dialog_init (LogoutDialog *self) -{ - - return; -} - -static void -logout_dialog_dispose (GObject *object) -{ - - - G_OBJECT_CLASS (logout_dialog_parent_class)->dispose (object); - return; -} - -static void -logout_dialog_finalize (GObject *object) -{ - - - G_OBJECT_CLASS (logout_dialog_parent_class)->finalize (object); - return; -} - -/* Checks for updates that would signal that a restart is - required for them to apply */ -static gboolean -check_restart_required (void) -{ - return g_file_test("/var/run/reboot-required", G_FILE_TEST_EXISTS); -} - -/* Checks with console kit to see if we can do what we want */ -static gboolean -ck_check_allowed (LogoutDialogType type) -{ - gboolean allowed = TRUE; - - ConsoleKitManager * ck_proxy = console_kit_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - NULL, - NULL); - if (ck_proxy != NULL) - { - switch (type) { - case LOGOUT_DIALOG_TYPE_RESTART: - console_kit_manager_call_can_restart_sync (ck_proxy, &allowed, NULL, NULL); - break; - case LOGOUT_DIALOG_TYPE_SHUTDOWN: - console_kit_manager_call_can_stop_sync (ck_proxy, &allowed, NULL, NULL); - break; - default: - break; - } - - g_object_unref(ck_proxy); - } - - return allowed; -} - -LogoutDialog * -logout_dialog_new (LogoutDialogType type) -{ - GtkWidget * image = gtk_image_new_from_icon_name(icon_strings[type], GTK_ICON_SIZE_DIALOG); - gtk_widget_show(image); - - LogoutDialog * dialog = LOGOUT_DIALOG(g_object_new(LOGOUT_DIALOG_TYPE, - /* Window */ - "icon-name", icon_strings[type], - "modal", TRUE, - "resizable", FALSE, - "title", g_dpgettext2 (NULL, "title", title_strings[type]), - "window-position", GTK_WIN_POS_CENTER_ALWAYS, - /* Message Dialog */ - "buttons", GTK_BUTTONS_NONE, - "image", image, - "message-type", GTK_MESSAGE_OTHER, - "text", _(body_strings[type]), - NULL)); - - gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); - - gboolean allowed = FALSE; - if (type == LOGOUT_DIALOG_TYPE_LOG_OUT) { - allowed = ck_check_allowed(LOGOUT_DIALOG_TYPE_RESTART); - } else { - allowed = ck_check_allowed(type); - } - - gboolean restart_required = FALSE; - if (type == LOGOUT_DIALOG_TYPE_LOG_OUT) { - restart_required = check_restart_required(); - } - - const gchar * button_text; - if (allowed) { - button_text = g_dpgettext2 (NULL, "button", button_strings[type]); - } else { - button_text = g_dpgettext2 (NULL, "button auth", button_auth_strings[type]); - } - - if (restart_required) { - const gchar * restart_req; - if (allowed) { - restart_req = restart_updates; - } else { - restart_req = restart_auth; - } - - g_object_set(dialog, "secondary-text", _(body_logout_update), NULL); - - gtk_dialog_add_buttons(GTK_DIALOG(dialog), - _(restart_req), GTK_RESPONSE_HELP, - _("Cancel"), GTK_RESPONSE_CANCEL, - button_text, GTK_RESPONSE_OK, - NULL); - } else { - gtk_dialog_add_buttons(GTK_DIALOG(dialog), - _("Cancel"), GTK_RESPONSE_CANCEL, - button_text, GTK_RESPONSE_OK, - NULL); - } - - gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); - - /* The following is a workaround to fix an issue in GtkMessageDialog - in which the user can tab through the text in addition to - the buttons. */ - GtkWidget *message_area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog)); - GList *children = gtk_container_get_children(GTK_CONTAINER(message_area)); - GList *l; - - for (l = children; l != NULL; l = g_list_next (l)) - { - GtkWidget *child = l->data; - gtk_widget_set_can_focus(child, FALSE); - } - - g_list_free (children); - - return dialog; -} diff --git a/src/dialog.h b/src/dialog.h deleted file mode 100644 index 18a55a7..0000000 --- a/src/dialog.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -A dialog to ask the user about the various logout options that -are available. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifndef __LOGOUT_DIALOG_H__ -#define __LOGOUT_DIALOG_H__ - -#include -#include - -#include - -G_BEGIN_DECLS - -#define LOGOUT_DIALOG_TYPE (logout_dialog_get_type ()) -#define LOGOUT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGOUT_DIALOG_TYPE, LogoutDialog)) -#define LOGOUT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LOGOUT_DIALOG_TYPE, LogoutDialogClass)) -#define IS_LOGOUT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGOUT_DIALOG_TYPE)) -#define IS_LOGOUT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGOUT_DIALOG_TYPE)) -#define LOGOUT_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGOUT_DIALOG_TYPE, LogoutDialogClass)) - -typedef enum _LogoutDialogType LogoutDialogType; -enum _LogoutDialogType { - LOGOUT_DIALOG_TYPE_LOG_OUT, - LOGOUT_DIALOG_TYPE_RESTART, - LOGOUT_DIALOG_TYPE_SHUTDOWN, - LOGOUT_DIALOG_TYPE_CNT -}; - -typedef struct _LogoutDialog LogoutDialog; -typedef struct _LogoutDialogClass LogoutDialogClass; - -struct _LogoutDialogClass { - GtkMessageDialogClass parent_class; -}; - -struct _LogoutDialog { - GtkMessageDialog parent; -}; - -GType logout_dialog_get_type (void); -LogoutDialog * logout_dialog_new (LogoutDialogType type); - -G_END_DECLS - -#endif diff --git a/src/display-manager.xml b/src/display-manager.xml deleted file mode 100644 index 07b5f29..0000000 --- a/src/display-manager.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gtk-logout-helper.c b/src/gtk-logout-helper.c deleted file mode 100644 index 55db630..0000000 --- a/src/gtk-logout-helper.c +++ /dev/null @@ -1,266 +0,0 @@ -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using it's applet interface. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - Christoph Korn - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#include "config.h" - -#include -#include -#include /* textdomain(), bindtextdomain() */ -#include -#include "dialog.h" -#include "shared-names.h" - -static GVariant * -call_console_kit (const gchar *method, GVariant *parameters, GError **error) -{ - GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, error); - if (!bus) - { - g_variant_unref (parameters); - return NULL; - } - - GVariant *result = g_dbus_connection_call_sync(bus, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - method, - parameters, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - error); - g_object_unref (bus); - - return result; -} - -static void -consolekit_fallback (LogoutDialogType action) -{ - GError * error = NULL; - GVariant *result = NULL; - - g_debug("Falling back to using ConsoleKit for action"); - - switch (action) { - case LOGOUT_DIALOG_TYPE_LOG_OUT: - g_warning("Unable to fallback to ConsoleKit for logout as it's a session issue. We need some sort of session handler."); - break; - case LOGOUT_DIALOG_TYPE_SHUTDOWN: - g_debug("Telling ConsoleKit to 'Stop'"); - result = call_console_kit ("Stop", g_variant_new ("()"), &error); - break; - case LOGOUT_DIALOG_TYPE_RESTART: - g_debug("Telling ConsoleKit to 'Restart'"); - result = call_console_kit ("Restart", g_variant_new ("()"), &error); - break; - default: - g_warning("Unknown action"); - break; - } - - if (!result) { - if (error != NULL) { - g_warning ("ConsoleKit action failed: %s", error->message); - } else { - g_warning ("ConsoleKit action failed: unknown error"); - } - - consolekit_fallback(action); - } - else - g_variant_unref (result); - g_clear_error (&error); - - return; -} - -static GVariant * -call_gnome_session (const gchar *method, GVariant *parameters, GError **error) -{ - GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, error); - if (!bus) - { - g_variant_unref (parameters); - return NULL; - } - - GVariant *result = g_dbus_connection_call_sync(bus, - "org.gnome.SessionManager", - "/org/gnome/SessionManager", - "org.gnome.SessionManager", - method, - parameters, - NULL, - G_DBUS_CALL_FLAGS_NONE, - G_MAXINT, - NULL, - error); - g_object_unref (bus); - - return result; -} - -static void -session_action (LogoutDialogType action) -{ - GError * error = NULL; - GVariant *result = NULL; - - if (action == LOGOUT_DIALOG_TYPE_LOG_OUT) { - g_debug("Asking Session manager to 'Logout'"); - result = call_gnome_session ("Logout", g_variant_new ("(u)", 1), &error); - } else if (action == LOGOUT_DIALOG_TYPE_SHUTDOWN) { - g_debug("Asking Session manager to 'RequestShutdown'"); - result = call_gnome_session ("RequestShutdown", g_variant_new ("()"), &error); - } else if (action == LOGOUT_DIALOG_TYPE_RESTART) { - g_debug("Asking Session manager to 'RequestReboot'"); - result = call_gnome_session ("RequestReboot", g_variant_new ("()"), &error); - } else { - g_warning ("Unknown session action"); - } - - if (!result) { - if (error != NULL) { - g_warning ("SessionManager action failed: %s", error->message); - } else { - g_warning ("SessionManager action failed: unknown error"); - } - - consolekit_fallback(action); - } - else - g_variant_unref (result); - g_clear_error (&error); - - return; -} - -static LogoutDialogType type = LOGOUT_DIALOG_TYPE_LOG_OUT; - -static gboolean -option_logout (const gchar * arg, const gchar * value, gpointer data, GError * error) -{ - type = LOGOUT_DIALOG_TYPE_LOG_OUT; - g_debug("Dialog type: logout"); - return TRUE; -} - -static gboolean -option_shutdown (const gchar * arg, const gchar * value, gpointer data, GError * error) -{ - type = LOGOUT_DIALOG_TYPE_SHUTDOWN; - g_debug("Dialog type: shutdown"); - return TRUE; -} - -static gboolean -option_restart (const gchar * arg, const gchar * value, gpointer data, GError * error) -{ - type = LOGOUT_DIALOG_TYPE_RESTART; - g_debug("Dialog type: restart"); - return TRUE; -} - -static GOptionEntry options[] = { - {"logout", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, option_logout, "Log out of the current session", NULL}, - {"shutdown", 's', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, option_shutdown, "Switch off the entire system", NULL}, - {"restart", 'r', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, option_restart, "Restart the system", NULL}, - - {NULL} -}; - -static gboolean -suppress_confirmations (void) -{ - GSettings * s = g_settings_new (SESSION_SCHEMA); - const gboolean suppress = g_settings_get_boolean (s, SUPPRESS_KEY); - g_clear_object (&s); - return suppress; -} - - - -int -main (int argc, char * argv[]) -{ - gtk_init(&argc, &argv); - - /* Setting up i18n and gettext. Apparently, we need - all of these. */ - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); - textdomain (GETTEXT_PACKAGE); - - GError * error = NULL; - GOptionContext * context = g_option_context_new(" - logout of the current session"); - g_option_context_add_main_entries(context, options, "gtk-logout-helper"); - g_option_context_add_group(context, gtk_get_option_group(TRUE)); - g_option_context_set_help_enabled(context, TRUE); - - if (!g_option_context_parse(context, &argc, &argv, &error)) { - g_debug("Option parsing failed: %s", error->message); - g_error_free(error); - return 1; - } - - /* Init some theme/icon stuff */ - gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), - INDICATOR_ICONS_DIR); - - GtkWidget * dialog = NULL; - if (!suppress_confirmations()) { - g_debug("Showing dialog to ask for user confirmation"); - dialog = GTK_WIDGET(logout_dialog_new(type)); - } - - if (dialog != NULL) { - GtkResponseType response = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_hide(dialog); - - if (response == GTK_RESPONSE_OK) { - g_debug("Dialog return response: 'okay'"); - } else if (response == GTK_RESPONSE_HELP) { - g_debug("Dialog return response: 'help'"); - } else { - g_debug("Dialog return response: %d", response); - } - - if (response == GTK_RESPONSE_HELP) { - type = LOGOUT_DIALOG_TYPE_RESTART; - response = GTK_RESPONSE_OK; - } - - if (response != GTK_RESPONSE_OK) { - g_debug("Final response was not okay, quiting"); - return 0; - } - } - - session_action(type); - g_debug("Finished action, quiting"); - - return 0; -} diff --git a/src/guest.c b/src/guest.c new file mode 100644 index 0000000..bcbd384 --- /dev/null +++ b/src/guest.c @@ -0,0 +1,190 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "guest.h" + +G_DEFINE_TYPE (IndicatorSessionGuest, + indicator_session_guest, + G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_ALLOWED, + PROP_LOGGED_IN, + PROP_ACTIVE, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorSessionGuest * self = INDICATOR_SESSION_GUEST (o); + + switch (property_id) + { + case PROP_ALLOWED: + g_value_set_boolean (value, indicator_session_guest_is_allowed (self)); + break; + + case PROP_LOGGED_IN: + g_value_set_boolean (value, indicator_session_guest_is_logged_in (self)); + break; + + case PROP_ACTIVE: + g_value_set_boolean (value, indicator_session_guest_is_active (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +my_dispose (GObject *object) +{ + G_OBJECT_CLASS (indicator_session_guest_parent_class)->dispose (object); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_guest_class_init (IndicatorSessionGuestClass * klass) +{ + GObjectClass * object_class; + const GParamFlags flags = G_PARAM_READABLE | G_PARAM_STATIC_STRINGS; + + object_class = G_OBJECT_CLASS (klass); + object_class->get_property = my_get_property; + object_class->dispose = my_dispose; + + klass->is_allowed = NULL; + klass->is_logged_in = NULL; + klass->is_active = NULL; + klass->switch_to_guest = NULL; + + properties[PROP_0] = NULL; + + properties[PROP_ALLOWED] = + g_param_spec_boolean (INDICATOR_SESSION_GUEST_PROPERTY_ALLOWED, + "Is Allowed", + "Whether or not a Guest user is allowed", + FALSE, flags); + + properties[PROP_LOGGED_IN] = + g_param_spec_boolean (INDICATOR_SESSION_GUEST_PROPERTY_LOGGED_IN, + "Is Logged In", + "Whether or not the Guest account is logged in", + FALSE, flags); + + properties[PROP_ACTIVE] = + g_param_spec_boolean (INDICATOR_SESSION_GUEST_PROPERTY_ACTIVE, + "Is Active", + "If the Guest account has the current session", + FALSE, flags); + + g_object_class_install_properties (object_class, PROP_LAST, properties); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_guest_init (IndicatorSessionGuest *self G_GNUC_UNUSED) +{ +} + +/*** +**** +***/ + +gboolean +indicator_session_guest_is_active (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST (self), FALSE); + + return INDICATOR_SESSION_GUEST_GET_CLASS (self)->is_active (self); +} + +gboolean +indicator_session_guest_is_allowed (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST (self), FALSE); + + return INDICATOR_SESSION_GUEST_GET_CLASS (self)->is_allowed (self); +} + +gboolean +indicator_session_guest_is_logged_in (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST (self), FALSE); + + return INDICATOR_SESSION_GUEST_GET_CLASS (self)->is_logged_in (self); +} + +/*** +**** +***/ +static void +notify_func (IndicatorSessionGuest * self, int prop) +{ + g_return_if_fail (INDICATOR_IS_SESSION_GUEST (self)); + + g_debug ("%s %s emitting '%s' prop notify", G_STRLOC, G_STRFUNC, properties[prop]->name); + + g_object_notify_by_pspec (G_OBJECT(self), properties[prop]); +} + +void +indicator_session_guest_notify_active (IndicatorSessionGuest * self) +{ + notify_func (self, PROP_ACTIVE); +} + +void +indicator_session_guest_notify_allowed (IndicatorSessionGuest * self) +{ + notify_func (self, PROP_ALLOWED); +} + +void +indicator_session_guest_notify_logged_in (IndicatorSessionGuest * self) +{ + notify_func (self, PROP_LOGGED_IN); +} + +/*** +**** +***/ + +void +indicator_session_guest_switch_to_guest (IndicatorSessionGuest * self) +{ + gboolean allowed; + + g_return_if_fail (INDICATOR_IS_SESSION_GUEST (self)); + + g_object_get (self, INDICATOR_SESSION_GUEST_PROPERTY_ALLOWED, &allowed, NULL); + g_return_if_fail (allowed); + + INDICATOR_SESSION_GUEST_GET_CLASS (self)->switch_to_guest (self); +} + diff --git a/src/guest.h b/src/guest.h new file mode 100644 index 0000000..30947d5 --- /dev/null +++ b/src/guest.h @@ -0,0 +1,82 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __GUEST_H__ +#define __GUEST_H__ + +#include +#include + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_GUEST (indicator_session_guest_get_type()) +#define INDICATOR_SESSION_GUEST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_GUEST, IndicatorSessionGuest)) +#define INDICATOR_SESSION_GUEST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_GUEST, IndicatorSessionGuestClass)) +#define INDICATOR_SESSION_GUEST_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_SESSION_GUEST, IndicatorSessionGuestClass)) +#define INDICATOR_IS_SESSION_GUEST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_GUEST)) + +typedef struct _IndicatorSessionGuest IndicatorSessionGuest; +typedef struct _IndicatorSessionGuestClass IndicatorSessionGuestClass; + +GType indicator_session_guest_get_type (void); + +/** + * A base class for getting state information about the system's guest user. + * Use backend.h's get_backend() to get an instance. + */ +struct _IndicatorSessionGuest +{ + /*< private >*/ + GObject parent; +}; + +/* properties */ +#define INDICATOR_SESSION_GUEST_PROPERTY_ALLOWED "guest-is-allowed" +#define INDICATOR_SESSION_GUEST_PROPERTY_LOGGED_IN "guest-is-logged-in" +#define INDICATOR_SESSION_GUEST_PROPERTY_ACTIVE "guest-is-active-session" + +struct _IndicatorSessionGuestClass +{ + GObjectClass parent_class; + + /* virtual functions */ + gboolean (* is_allowed) (IndicatorSessionGuest * self); + gboolean (* is_logged_in) (IndicatorSessionGuest * self); + gboolean (* is_active) (IndicatorSessionGuest * self); + void (* switch_to_guest) (IndicatorSessionGuest * self); +}; + +gboolean indicator_session_guest_is_allowed (IndicatorSessionGuest * self); +gboolean indicator_session_guest_is_logged_in (IndicatorSessionGuest * self); +gboolean indicator_session_guest_is_active (IndicatorSessionGuest * self); + +void indicator_session_guest_switch_to_guest (IndicatorSessionGuest * self); + +/** + * Emit 'notify' signals for the corresponding properties. + * These functions should only be called by IndicatorSessionGuest implementations. + */ +void indicator_session_guest_notify_allowed (IndicatorSessionGuest * self); +void indicator_session_guest_notify_logged_in (IndicatorSessionGuest * self); +void indicator_session_guest_notify_active (IndicatorSessionGuest * self); + + +G_END_DECLS + +#endif diff --git a/src/indicator-session.c b/src/indicator-session.c deleted file mode 100644 index 431292e..0000000 --- a/src/indicator-session.c +++ /dev/null @@ -1,495 +0,0 @@ -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using its applet interface. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "shared-names.h" -#include "user-widget.h" - -#define INDICATOR_SESSION_TYPE (indicator_session_get_type ()) -#define INDICATOR_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SESSION_TYPE, IndicatorSession)) -#define INDICATOR_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_SESSION_TYPE, IndicatorSessionClass)) -#define IS_INDICATOR_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_SESSION_TYPE)) -#define IS_INDICATOR_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_SESSION_TYPE)) -#define INDICATOR_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_SESSION_TYPE, IndicatorSessionClass)) - -typedef struct _IndicatorSession IndicatorSession; -typedef struct _IndicatorSessionClass IndicatorSessionClass; - -struct _IndicatorSessionClass -{ - IndicatorObjectClass parent_class; -}; - -struct _IndicatorSession -{ - IndicatorObject parent; - IndicatorServiceManager * service; - IndicatorObjectEntry entry; - GCancellable * service_proxy_cancel; - GDBusProxy * service_proxy; - GSettings * settings; - DbusmenuClient * menu_client; - GtkIconTheme * icon_theme; -}; - -GType indicator_session_get_type (void); - -/* Indicator stuff */ -INDICATOR_SET_VERSION -INDICATOR_SET_TYPE(INDICATOR_SESSION_TYPE) - -/* Prototypes */ -static gboolean new_user_item (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data); -static void on_menu_layout_updated (DbusmenuClient * client, IndicatorSession * session); -static void indicator_session_update_icon_callback (GtkWidget * widget, gpointer callback_data); -static void indicator_session_update_icon_and_a11y (IndicatorSession * self); -static void indicator_session_update_users_label (IndicatorSession* self, - const gchar* name); -static void service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data); -static void receive_signal (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name, GVariant * parameters, gpointer user_data); -static void service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data); -static void user_real_name_get_cb (GObject * obj, GAsyncResult * res, gpointer user_data); - -static void indicator_session_class_init (IndicatorSessionClass *klass); -static void indicator_session_init (IndicatorSession *self); -static void indicator_session_dispose (GObject *object); -static void indicator_session_finalize (GObject *object); -static GList* indicator_session_get_entries (IndicatorObject* obj); -static guint indicator_session_get_location (IndicatorObject * io, - IndicatorObjectEntry * entry); - -G_DEFINE_TYPE (IndicatorSession, indicator_session, INDICATOR_OBJECT_TYPE); - -static void -indicator_session_class_init (IndicatorSessionClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = indicator_session_dispose; - object_class->finalize = indicator_session_finalize; - - IndicatorObjectClass * io_class = INDICATOR_OBJECT_CLASS(klass); - io_class->get_entries = indicator_session_get_entries; - io_class->get_location = indicator_session_get_location; - return; -} - -static void -indicator_session_init (IndicatorSession *self) -{ - self->settings = g_settings_new ("com.canonical.indicator.session"); - - /* Now let's fire these guys up. */ - self->service = indicator_service_manager_new_version(INDICATOR_SESSION_DBUS_NAME, - INDICATOR_SESSION_DBUS_VERSION); - g_signal_connect (G_OBJECT(self->service), - INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, - G_CALLBACK(service_connection_cb), self); - - self->entry.name_hint = PACKAGE; - self->entry.label = GTK_LABEL (gtk_label_new ("User Name")); - self->entry.image = GTK_IMAGE (gtk_image_new()); - self->entry.menu = GTK_MENU (dbusmenu_gtkmenu_new(INDICATOR_SESSION_DBUS_NAME, - INDICATOR_SESSION_DBUS_OBJECT)); - /* We need to check if the current icon theme has the hard coded icons. - * If not, we'll fall back to a standard icon */ - self->icon_theme = gtk_icon_theme_get_default(); - g_signal_connect(G_OBJECT(self->icon_theme), - "changed", - G_CALLBACK(indicator_session_update_icon_callback), self); - - indicator_session_update_icon_and_a11y (self); - g_settings_bind (self->settings, "show-real-name-on-panel", - self->entry.label, "visible", - G_SETTINGS_BIND_GET); - - /* show-real-name-on-panel affects the a11y string */ - g_signal_connect_swapped (self->settings, - "notify::show-real-name-on-panel", - G_CALLBACK(indicator_session_update_icon_and_a11y), - self); - - gtk_widget_show (GTK_WIDGET(self->entry.menu)); - gtk_widget_show (GTK_WIDGET(self->entry.image)); - g_object_ref_sink (self->entry.menu); - g_object_ref_sink (self->entry.image); - - // set up the handlers - self->menu_client = DBUSMENU_CLIENT(dbusmenu_gtkmenu_get_client(DBUSMENU_GTKMENU(self->entry.menu))); - g_signal_connect (self->menu_client, "layout-updated", - G_CALLBACK(on_menu_layout_updated), self); - - dbusmenu_client_add_type_handler (self->menu_client, - USER_ITEM_TYPE, - new_user_item); - dbusmenu_gtkclient_set_accel_group (DBUSMENU_GTKCLIENT(self->menu_client), - gtk_accel_group_new()); -} - -static void -indicator_session_dispose (GObject *object) -{ - IndicatorSession * self = INDICATOR_SESSION(object); - - g_clear_object (&self->settings); - g_clear_object (&self->service); - g_clear_object (&self->service_proxy); - - if (self->service_proxy_cancel != NULL) - { - g_cancellable_cancel(self->service_proxy_cancel); - g_clear_object (&self->service_proxy_cancel); - } - - g_clear_object (&self->entry.menu); - - G_OBJECT_CLASS (indicator_session_parent_class)->dispose (object); -} - -static void -indicator_session_finalize (GObject *object) -{ - - G_OBJECT_CLASS (indicator_session_parent_class)->finalize (object); - return; -} - -static GList* -indicator_session_get_entries (IndicatorObject* obj) -{ - g_return_val_if_fail(IS_INDICATOR_SESSION(obj), NULL); - - IndicatorSession* self = INDICATOR_SESSION (obj); - return g_list_append (NULL, &self->entry); -} - -static guint -indicator_session_get_location (IndicatorObject * io, - IndicatorObjectEntry * entry) -{ - return 0; -} - -/* callback for the service manager state of being */ -static void -service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data) -{ - IndicatorSession * self = INDICATOR_SESSION (user_data); - - if (connected) { - if (self->service_proxy != NULL){ - // Its a reconnect ! - // Fetch synchronisation data and return (proxy is still legit) - g_dbus_proxy_call (self->service_proxy, - "GetUserRealName", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - user_real_name_get_cb, - user_data); - return; - } - - self->service_proxy_cancel = g_cancellable_new(); - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - INDICATOR_SESSION_DBUS_NAME, - INDICATOR_SESSION_SERVICE_DBUS_OBJECT, - INDICATOR_SESSION_SERVICE_DBUS_IFACE, - self->service_proxy_cancel, - service_proxy_cb, - self); - } - return; -} - - -static void -service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data) -{ - GError * error = NULL; - - IndicatorSession * self = INDICATOR_SESSION(user_data); - g_return_if_fail(self != NULL); - - GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error); - - g_clear_object (&self->service_proxy_cancel); - - if (error != NULL) { - g_warning("Could not grab DBus proxy for %s: %s", INDICATOR_SESSION_DBUS_NAME, error->message); - g_error_free(error); - return; - } - - /* Okay, we're good to grab the proxy at this point, we're - sure that it's ours. */ - self->service_proxy = proxy; - - g_signal_connect(proxy, "g-signal", G_CALLBACK(receive_signal), self); - - // Fetch the user's real name for the user entry label - g_dbus_proxy_call (self->service_proxy, - "GetUserRealName", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - user_real_name_get_cb, - user_data); - return; -} - - -static gboolean -new_user_item (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data) -{ - g_return_val_if_fail (DBUSMENU_IS_MENUITEM(newitem), FALSE); - g_return_val_if_fail (DBUSMENU_IS_GTKCLIENT(client), FALSE); - - GtkWidget * user_item = user_widget_new (newitem); - - GtkMenuItem *user_widget = GTK_MENU_ITEM(user_item); - - dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client), - newitem, - user_widget, - parent); - - g_debug ("%s (\"%s\")", __func__, - dbusmenu_menuitem_property_get (newitem, - USER_ITEM_PROP_NAME)); - return TRUE; -} - -static void -user_real_name_get_cb (GObject * obj, GAsyncResult * res, gpointer user_data) -{ - IndicatorSession * self = INDICATOR_SESSION(user_data); - - GError * error = NULL; - GVariant * result = g_dbus_proxy_call_finish(self->service_proxy, res, &error); - - if (error != NULL) - { - g_warning ("Unable to complete real name dbus query: %s", error->message); - g_clear_error (&error); - } - else - { - const gchar * username = NULL; - g_variant_get (result, "(&s)", &username); - indicator_session_update_users_label (self, username); - g_variant_unref (result); - } -} - -/* Receives all signals from the service, routed to the appropriate functions */ -static void -receive_signal (GDBusProxy * proxy, - gchar * sender_name, - gchar * signal_name, - GVariant * parameters, - gpointer user_data) -{ - IndicatorSession * self = INDICATOR_SESSION(user_data); - - if (!g_strcmp0(signal_name, "UserRealNameUpdated")) - { - const gchar * username = NULL; - g_variant_get (parameters, "(&s)", &username); - indicator_session_update_users_label (self, username); - } -} - -static void -indicator_session_update_users_label (IndicatorSession * self, - const gchar * name) -{ - gtk_label_set_text (self->entry.label, name ? name : ""); -} - -/*** -**** Disposition -***/ - -enum -{ - DISPOSITION_NORMAL, - DISPOSITION_INFO, - DISPOSITION_WARNING, - DISPOSITION_ALERT -}; - -static void -indicator_session_update_a11y_from_disposition (IndicatorSession * indicator, - int disposition) -{ - gchar * a11y; - const gchar * username = gtk_label_get_text (indicator->entry.label); - const gboolean need_attn = disposition != DISPOSITION_NORMAL; - const gboolean show_name = g_settings_get_boolean (indicator->settings, - "show-real-name-on-panel"); - - if (show_name && need_attn) - /* Translators: the name of the menu ("System"), followed by the user's name, - followed by a hint that an item in this menu requires an action from the user */ - a11y = g_strdup_printf (_("System %s (Attention Required)"), username); - else if (show_name) - /* Translators: the name of the menu ("System"), followed by the user's name */ - a11y = g_strdup_printf (_("System %s"), username); - else if (need_attn) - a11y = g_strdup (_("System (Attention Required)")); - else - a11y = g_strdup (_("System")); - - g_debug (G_STRLOC" setting a11y to \"%s\"", a11y); - g_clear_pointer (&indicator->entry.accessible_desc, g_free); - indicator->entry.accessible_desc = a11y; - g_signal_emit (indicator, - INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE_ID, - 0, - &indicator->entry); -} - -static void -indicator_session_update_icon_from_disposition (IndicatorSession * indicator, - int disposition) -{ - const gchar * icon; - - if (disposition == DISPOSITION_NORMAL) - icon = ICON_DEFAULT; - else if (disposition == DISPOSITION_INFO) - icon = ICON_INFO; - else - icon = ICON_ALERT; - - if (gtk_icon_theme_has_icon (indicator->icon_theme, icon) == FALSE) - icon = "gtk-missing-image"; - - g_debug (G_STRLOC" setting icon to \"%s\"", icon); - gtk_image_set_from_icon_name (GTK_IMAGE(indicator->entry.image), - icon, - GTK_ICON_SIZE_BUTTON); -} - -static int -calculate_disposition (IndicatorSession * indicator) -{ - GList * l; - DbusmenuMenuitem * root = dbusmenu_client_get_root (indicator->menu_client); - GList * children = dbusmenu_menuitem_get_children (root); - int ret = DISPOSITION_NORMAL; - - for (l=children; l!=NULL; l=l->next) - { - int val; - const gchar * key = DBUSMENU_MENUITEM_PROP_DISPOSITION; - const gchar * val_str = dbusmenu_menuitem_property_get (l->data, key); - - if (!g_strcmp0 (val_str, DBUSMENU_MENUITEM_DISPOSITION_ALERT)) - val = DISPOSITION_ALERT; - else if (!g_strcmp0 (val_str, DBUSMENU_MENUITEM_DISPOSITION_WARNING)) - val = DISPOSITION_WARNING; - else if (!g_strcmp0 (val_str, DBUSMENU_MENUITEM_DISPOSITION_INFORMATIVE)) - val = DISPOSITION_INFO; - else - val = DISPOSITION_NORMAL; - - if (ret < val) - ret = val; - } - - return ret; -} - -static void -indicator_session_update_icon_callback (GtkWidget * widget, gpointer callback_data) -{ - indicator_session_update_icon_and_a11y ((IndicatorSession *)callback_data); -} - -static void -indicator_session_update_icon_and_a11y (IndicatorSession * indicator) -{ - const int disposition = calculate_disposition (indicator); - indicator_session_update_a11y_from_disposition (indicator, disposition); - indicator_session_update_icon_from_disposition (indicator, disposition); -} - -static void -on_menuitem_property_changed (DbusmenuMenuitem * mi, - gchar * property, - GValue * value, - gpointer indicator) -{ - if (!g_strcmp0 (property, DBUSMENU_MENUITEM_PROP_DISPOSITION)) - indicator_session_update_icon_and_a11y (indicator); -} - -static void -on_menu_layout_updated (DbusmenuClient * client, IndicatorSession * session) -{ - GList * l; - DbusmenuMenuitem * root = dbusmenu_client_get_root (client); - GList * children = dbusmenu_menuitem_get_children (root); - static GQuark tag = 0; - - if (G_UNLIKELY (tag == 0)) - { - tag = g_quark_from_static_string ("x-tagged-by-indicator-session"); - } - - for (l=children; l!=NULL; l=l->next) - { - if (g_object_get_qdata (l->data, tag) == NULL) - { - g_object_set_qdata (l->data, tag, GINT_TO_POINTER(1)); - g_signal_connect (l->data, "property-changed", G_CALLBACK(on_menuitem_property_changed), session); - } - } -} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..ff5997b --- /dev/null +++ b/src/main.c @@ -0,0 +1,87 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include +#include /* exit() */ + +#include +#include + +#include "service.h" + +/*** +**** +***/ + +static gboolean replace = FALSE; + +static void +parse_command_line (int * argc, char *** argv) +{ + GError * error; + GOptionContext * option_context; + + static GOptionEntry entries[] = + { + { "replace", 'r', 0, G_OPTION_ARG_NONE, &replace, "Replace the currently-running service", NULL }, + { NULL } + }; + + error = NULL; + option_context = g_option_context_new ("- indicator-session service"); + g_option_context_add_main_entries (option_context, entries, GETTEXT_PACKAGE); + if (!g_option_context_parse (option_context, argc, argv, &error)) + { + g_print ("option parsing failed: %s\n", error->message); + g_error_free (error); + exit (EXIT_FAILURE); + } + + g_option_context_free (option_context); +} + +/*** +**** +***/ + +int +main (int argc, char ** argv) +{ + GMainLoop * loop; + IndicatorSessionService * service; + + signal (SIGPIPE, SIG_IGN); + + /* boilerplate i18n */ + setlocale (LC_ALL, ""); + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + textdomain (GETTEXT_PACKAGE); + + parse_command_line (&argc, &argv); + + /* run */ + service = indicator_session_service_new (replace); + loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (loop); + + /* cleanup */ + g_clear_object (&service); + g_main_loop_unref (loop); + return 0; +} diff --git a/src/online-accounts-mgr.c b/src/online-accounts-mgr.c deleted file mode 100644 index 4abba00..0000000 --- a/src/online-accounts-mgr.c +++ /dev/null @@ -1,166 +0,0 @@ -/* -Copyright 2012 Canonical Ltd. - -Authors: - Alberto Mardegan - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#include -#include - -#include "online-accounts-mgr.h" - -#include - -struct _OnlineAccountsMgr -{ - GObject parent_instance; - GDBusProxy *proxy; - DbusmenuMenuitem *menu_item; -}; - -#define ONLINE_ACCOUNTS_OBJECT_PATH "/com/canonical/indicators/webcredentials" -#define ONLINE_ACCOUNTS_BUS_NAME "com.canonical.indicators.webcredentials" -#define ONLINE_ACCOUNTS_INTERFACE ONLINE_ACCOUNTS_BUS_NAME - -G_DEFINE_TYPE (OnlineAccountsMgr, online_accounts_mgr, G_TYPE_OBJECT); - -static void -update_disposition (OnlineAccountsMgr *self, GVariant *error_status_prop) -{ - gboolean error_status; - - error_status = g_variant_get_boolean (error_status_prop); - dbusmenu_menuitem_property_set (self->menu_item, - DBUSMENU_MENUITEM_PROP_DISPOSITION, - error_status ? - DBUSMENU_MENUITEM_DISPOSITION_ALERT : - DBUSMENU_MENUITEM_DISPOSITION_NORMAL); -} - -static void -on_properties_changed (GDBusProxy *proxy, - GVariant *changed_properties, - GStrv invalidated_properties, - OnlineAccountsMgr *self) -{ - if (g_variant_n_children (changed_properties) > 0) { - GVariantIter *iter; - const gchar *key; - GVariant *value; - - g_variant_get (changed_properties, "a{sv}", &iter); - while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) { - if (g_strcmp0 (key, "ErrorStatus") == 0) { - update_disposition (self, value); - } - } - g_variant_iter_free (iter); - } -} - -static void -on_menu_item_activated (DbusmenuMenuitem *menu_item, - guint timestamp, - OnlineAccountsMgr *self) -{ - GError *error = NULL; - - if (!g_spawn_command_line_async("gnome-control-center credentials", &error)) - { - g_warning("Unable to show control center: %s", error->message); - g_error_free(error); - } -} - -static void -online_accounts_mgr_init (OnlineAccountsMgr *self) -{ - GError *error = NULL; - GVariant *error_status_prop; - - self->menu_item = dbusmenu_menuitem_new (); - dbusmenu_menuitem_property_set (self->menu_item, - DBUSMENU_MENUITEM_PROP_TYPE, - DBUSMENU_CLIENT_TYPES_DEFAULT); - dbusmenu_menuitem_property_set (self->menu_item, - DBUSMENU_MENUITEM_PROP_LABEL, - _("Online Accounts\342\200\246")); - g_signal_connect (self->menu_item, - DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (on_menu_item_activated), - self); - - self->proxy = - g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - ONLINE_ACCOUNTS_BUS_NAME, - ONLINE_ACCOUNTS_OBJECT_PATH, - ONLINE_ACCOUNTS_INTERFACE, - NULL, - &error); - if (G_UNLIKELY (error != NULL)) { - g_warning ("Couldn't create online_accounts proxy: %s", error->message); - g_clear_error (&error); - return; - } - - g_signal_connect (self->proxy, "g-properties-changed", - G_CALLBACK (on_properties_changed), self); - - error_status_prop = - g_dbus_proxy_get_cached_property (self->proxy, "ErrorStatus"); - if (error_status_prop != NULL) { - update_disposition (self, error_status_prop); - g_variant_unref (error_status_prop); - } -} - -static void -online_accounts_mgr_dispose (GObject *object) -{ - OnlineAccountsMgr *self = ONLINE_ACCOUNTS_MGR (object); - - if (self->proxy != NULL) { - g_object_unref (self->proxy); - self->proxy = NULL; - } - - if (self->menu_item != NULL) { - g_object_unref (self->menu_item); - self->menu_item = NULL; - } - - G_OBJECT_CLASS (online_accounts_mgr_parent_class)->dispose (object); -} - -static void -online_accounts_mgr_class_init (OnlineAccountsMgrClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->dispose = online_accounts_mgr_dispose; -} - -OnlineAccountsMgr *online_accounts_mgr_new () -{ - return g_object_new (ONLINE_ACCOUNTS_TYPE_MGR, NULL); -} - -DbusmenuMenuitem *online_accounts_mgr_get_menu_item (OnlineAccountsMgr *self) -{ - g_return_val_if_fail (ONLINE_ACCOUNTS_IS_MGR (self), NULL); - return self->menu_item; -} diff --git a/src/online-accounts-mgr.h b/src/online-accounts-mgr.h deleted file mode 100644 index 16c0461..0000000 --- a/src/online-accounts-mgr.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2012 Canonical Ltd. - -Authors: - Alberto Mardegan - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifndef _ONLINE_ACCOUNTS_MGR_H_ -#define _ONLINE_ACCOUNTS_MGR_H_ - -#include -#include - -G_BEGIN_DECLS - -#define ONLINE_ACCOUNTS_TYPE_MGR (online_accounts_mgr_get_type ()) -#define ONLINE_ACCOUNTS_MGR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ONLINE_ACCOUNTS_TYPE_MGR, OnlineAccountsMgr)) -#define ONLINE_ACCOUNTS_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ONLINE_ACCOUNTS_TYPE_MGR, OnlineAccountsMgrClass)) -#define ONLINE_ACCOUNTS_IS_MGR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ONLINE_ACCOUNTS_TYPE_MGR)) -#define ONLINE_ACCOUNTS_IS_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ONLINE_ACCOUNTS_TYPE_MGR)) -#define ONLINE_ACCOUNTS_MGR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ONLINE_ACCOUNTS_TYPE_MGR, OnlineAccountsMgrClass)) - -typedef struct _OnlineAccountsMgrClass OnlineAccountsMgrClass; -typedef struct _OnlineAccountsMgr OnlineAccountsMgr; - -struct _OnlineAccountsMgrClass -{ - GObjectClass parent_class; -}; - -GType online_accounts_mgr_get_type (void) G_GNUC_CONST; -OnlineAccountsMgr *online_accounts_mgr_new (void); - -DbusmenuMenuitem *online_accounts_mgr_get_menu_item (OnlineAccountsMgr *self); - -G_END_DECLS - -#endif /* _ONLINE_ACCOUNTS_MGR_H_ */ diff --git a/src/org.freedesktop.Accounts.User.xml b/src/org.freedesktop.Accounts.User.xml deleted file mode 100644 index 53f54d4..0000000 --- a/src/org.freedesktop.Accounts.User.xml +++ /dev/null @@ -1,744 +0,0 @@ - - - - - - - - - - - The new username. - - - - - - - Sets the users username. Note that it is usually not allowed - to have multiple users with the same username. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change the username of any user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new name, typically in the form "Firstname Lastname". - - - - - - - Sets the users real name. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own name - - - org.freedesktop.accounts.user-administration - To change the name of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new email address. - - - - - - - Sets the users email address. - - - Note that setting an email address in the AccountsService is - not the same as configuring a mail client. Mail clients might - default to email address that is configured here, though. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own email address - - - org.freedesktop.accounts.user-administration - To change the email address of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new language, as a locale specification like "de_DE.UTF-8". - - - - - - - Sets the users language. - - - The expectation is that display managers will start the - users session with this locale. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own language - - - org.freedesktop.accounts.user-administration - To change the language of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - - The new xsession to start (e.g. "gnome") - - - - - - - Sets the users x session. - - - The expectation is that display managers will log the user in to this - specified session, if available. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own language - - - org.freedesktop.accounts.user-administration - To change the language of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new location as a freeform string. - - - - - - - Sets the users location. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own location - - - org.freedesktop.accounts.user-administration - To change the location of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new homedir as an absolute path. - - - - - - - Sets the users home directory. - - - Note that changing the users home directory moves all the content - from the old location to the new one, and is potentially an - expensive operation. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change the home directory of a user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new user shell. - - - - - - - Sets the users shell. - - - Note that setting the shell to a non-allowed program may - prevent the user from logging in. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change the shell of a user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The absolute filename of a png file to use as the users icon. - - - - - - - Sets the users icon. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own icon - - - org.freedesktop.accounts.user-administration - To change the icon of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - Whether to lock or unlock the users account. - - - - - - - Locks or unlocks a users account. - - - Locking an account prevents the user from logging in. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To lock or unlock user accounts - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new account type, encoded as an integer: - - - 0 - Standard user - - - 1 - Administrator - - - - - - - - - Changes the users account type. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change an account type - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new password mode, encoded as an integer: - - - 0 - Regular password - - - 1 - Password must be set at next login - - - 2 - No password - - - - - - - - - Changes the users password mode. - - - Note that changing the password mode has the side-effect of - unlocking the account. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change a users password mode - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The crypted password. - - - - - - - The password hint. - - - - - - - Sets a new password for this user. - - - Note that setting a password has the side-effect of - unlocking the account. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change the password of a user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - Whether to enable automatic login for this user. - - - - - - - Enables or disables automatic login for a user. - - - Note that usually only one user can have automatic login - enabled, so turning it on for a user will disable it for - the previously configured autologin user. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.set-login-option - To change the login screen configuration - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - The uid of the user. - - - - - - - - - - The username of the user. - - - - - - - - - - The users real name. - - - - - - - - - - The users account type, encoded as an integer: - - - 0 - Standard user - - - 1 - Administrator - - - - - - - - - - - - The users home directory. - - - - - - - - - - The users shell. - - - - - - - - - - The email address. - - - - - - - - - - The users language, as a locale specification like "de_DE.UTF-8". - - - - - - - - - - The users x session. - - - - - - - - - - The users location. - - - - - - - - - - How often the user has logged in. - - - - - - - - - - The filename of a png file containing the users icon. - - - - - - - - - - Whether the users account is locked. - - - - - - - - - - The password mode for the user account, encoded as an integer: - - - 0 - Regular password - - - 1 - Password must be set at next login - - - 2 - No password - - - - - - - - - - - - The password hint for the user. - - - - - - - - - - Whether automatic login is enabled for the user. - - - - - - - - - - Whether this is a 'system' account, like 'root' or 'nobody'. - System accounts should normally not appear in lists of - users, and ListCachedUsers will not include such accounts. - - - - - - - - - - Emitted when the user is changed. - - - - - - - diff --git a/src/org.freedesktop.Accounts.xml b/src/org.freedesktop.Accounts.xml deleted file mode 100644 index 9c19761..0000000 --- a/src/org.freedesktop.Accounts.xml +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - - - Object paths of cached users - - - - - - Lists users which have logged into the system locally before. - This is not meant to return an exhaustive list of all users. - It is possible for FindUserByName() - to return a user that's not on the list. - - - - - - - - - The uid to look up - - - Object path of user - - - - - - Finds a user by uid. - - - - if no user with the given uid exists - - - - - - - - The username to look up - - - Object path of user - - - - - - Finds a user by its username. - - - - if no user with the given username exists - - - - - - - - The username for the new user - - - - The real name for the new user - - - Object path of the new user - - - - The account type, encoded as an integer - - - - - - Creates a new user account. - - - The accountType argument can take the following values: - - - - 0 - Standard user - - - 1 - Administrator - - - 2 - Supervised user - - - - - The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - The uid to delete - - - Whether to remove the users files - - - - - - Deletes a user account. - - - - The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - Object path of the user that was added. - - - - - Emitted when a user is added. - - - - - - - - Object path of the user that was deleted. - - - - - Emitted when a user is deleted. - - - - - - - - Object path of the user that was changed. - - - - - Emitted when a user is changed. - - - - - - - - - - The version of the running daemon. - - - - - - - diff --git a/src/org.freedesktop.ConsoleKit.Manager.xml b/src/org.freedesktop.ConsoleKit.Manager.xml deleted file mode 100644 index f903b55..0000000 --- a/src/org.freedesktop.ConsoleKit.Manager.xml +++ /dev/null @@ -1,353 +0,0 @@ - - - - - - - - - This method initiates a request to restart (ie. reboot) the computer system. - - - - - - - - - - - - - - This method initiates a request to stop (ie. shutdown) the computer system. - - - - - - - - - - - - - - The secret cookie that is used to identify the new session - - - - - This method requests that a new Session - be created for the calling process. The properties of this new Session are set automatically - from information collected about the calling process. - - This new session exists until the calling process disconnects from the system bus or - calls CloseSession(). - - It is the responsibility of the calling process to set the environment variable - XDG_SESSION_COOKIE to the value of the returned cookie. This cookie should only - be made available to child processes of the caller so that they may be identified - as members of this session. - - See this simple example: - - DBusError error; - DBusMessage *message; - DBusMessage *reply; - - message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - "OpenSession"); - if (message == NULL) { - goto out; - } - - dbus_error_init (&error); - reply = dbus_connection_send_with_reply_and_block (connector->connection, - message, - -1, - &error); - if (reply == NULL) { - goto out; - } - - dbus_error_init (&error); - if (! dbus_message_get_args (reply, - &error, - DBUS_TYPE_STRING, &cookie, - DBUS_TYPE_INVALID)) { - goto out; - } - - - - OpenSessionWithParameters() - - - - - - - An array of sets of property names and values - - - - - The secret cookie that is used to identify the new session - - - - - This method requests that a new Session - be created for the calling process. The properties of this new Session are from the - parameters provided. - - This new session exists until the calling process disconnects from the system bus or - calls CloseSession(). - - It is the responsibility of the calling process to set the environment variable - XDG_SESSION_COOKIE to the value of the returned cookie. This cookie should only - be made available to child processes of the caller so that they may be identified - as members of this session. - - See the Session properties for a list of valid parameters. - - org.freedesktop.ConsoleKit.Session - This method is restricted to privileged users by D-Bus policy. - - - - - - - The secret cookie that is used to identify the session - - - - - Whether the session was successfully closed - - - - - This method is used to close the session identified by the supplied cookie. - - The session can only be closed by the same process that opened the session. - - - - - - - - - an array of Seat IDs - - - - - This gets a list of all the Seats - that are currently present on the system. - Each Seat ID is an D-Bus object path for the object that implements the - Seat interface. - - org.freedesktop.ConsoleKit.Seat - - - - - - - an array of Session IDs - - - - - This gets a list of all the Sessions - that are currently present on the system. - Each Session ID is an D-Bus object path for the object that implements the - Session interface. - - org.freedesktop.ConsoleKit.Session - - - - - - - - The secret cookie that is used to identify the session - - - - - The object identifier for the current session - - - - - Returns the session ID that is associated with the specified cookie. - - - - - - - - - The POSIX process ID - - - - - The object identifier for the current session - - - - - Attempts to determine the session ID for the specified - POSIX process ID (pid). - - - - - - - - - The object identifier for the current session - - - - - Attempts to determine the session ID that the caller belongs to. - - See this example of using dbus-send: - - dbus-send --system --dest=org.freedesktop.ConsoleKit \ - --type=method_call --print-reply --reply-timeout=2000 \ - /org/freedesktop/ConsoleKit/Manager \ - org.freedesktop.ConsoleKit.Manager.GetCurrentSession - - - - - - - - - POSIX User identification - - - - - an array of Session IDs - - - - - This gets a list of all the Sessions - that are currently open for the specified user. - Each Session ID is an D-Bus object path for the object that implements the - Session interface. - - - - - - - - User identification - - - - - an array of Session IDs - - - - - This gets a list of all the Sessions - that are currently open for the specified user. - Each Session ID is an D-Bus object path for the object that implements the - Session interface. - - - - - - - - - The value of the system-idle-hint - - - - - Returns TRUE if the idle-hint - property of every open session is TRUE or if there are no open sessions. - - - - - - - - An ISO 8601 format date-type string - - - - - Returns an ISO 8601 date-time string that corresponds to - the time of the last change of the system-idle-hint. - - - - - - - - - The Seat ID for the added seat - - - - - Emitted when a Seat has been added to the system. - - - - - - - - The Seat ID for the removed seat - - - - - Emitted when a Seat has been removed from the system. - - - - - - - - The value of the system-idle-hint - - - - - Emitted when the value of the system-idle-hint has changed. - - - - - - diff --git a/src/org.freedesktop.ConsoleKit.Seat.xml b/src/org.freedesktop.ConsoleKit.Seat.xml deleted file mode 100644 index 58c2ce7..0000000 --- a/src/org.freedesktop.ConsoleKit.Seat.xml +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - A seat is a collection of sessions and a set of hardware (usually at -least a keyboard and mouse). Only one session may be active on a -seat at a time. - - - - - - - Seat ID - - - - - Returns the ID for Seat. - - - - - - - - an array of Session IDs - - - - - This gets a list of all the Sessions - that are currently attached to this seat. - Each Session ID is an D-Bus object path for the object that implements the - Session interface. - - - - - - - - an array of devices - - - - - This gets a list of all the devices - that are currently associated with this seat. - Each device is an D-Bus structure that represents - the device type and the device id. - - - - - - - - - Session ID - - - - - Gets the Session ID that is currently active on this Seat. - Returns NULL if there is no active session. - - - - - - - - TRUE if seat supports session activation - - - - Used to determine whether the seat supports session activation. - - - - - - - - - Session ID - - - - - Attempt to activate the specified session. In most - cases, if successful, this will cause the session to - become visible and take control of the hardware that is - associated with this seat. - - Activate() - - - - - - - Session ID - - - - - Emitted when the active session has changed. - - - - - - - Session ID - - - - - Emitted when a session has been added to the seat. - - - - - - - Session ID - - - - - Emitted when a session has been removed from the seat. - - - - - - - Device structure - - - - - Emitted when a device has been associated with the seat. - - - - - - - Device structure - - - - - Emitted when a device has been dissociated from the seat. - - - - - diff --git a/src/org.freedesktop.ConsoleKit.Session.xml b/src/org.freedesktop.ConsoleKit.Session.xml deleted file mode 100644 index b6e1cdb..0000000 --- a/src/org.freedesktop.ConsoleKit.Session.xml +++ /dev/null @@ -1,435 +0,0 @@ - - - - - - - Session objects represent and store information - related to a user session. - - The properties associated with the Session - specifically refer to the properties of the "session leader". - - - - - - - Session ID - - - - Returns the ID for Session. - - - - - - - Seat ID - - - - Returns the ID for the Seat the Session is - attached to. - - org.freedesktop.ConsoleKit.Seat - - - - - - Session type - - - - - Returns the type of the session. - Warning: we haven't yet defined the allowed values for this property. - It is probably best to avoid this until we do. - - - session-type - - - - - - User ID - - - - Returns the user that the session belongs to. - - - user - - - - - - POSIX User ID - - - - Returns the POSIX user ID that the session belongs to. - - unix-user - - - - - - The value of the X11 display - - - - Returns the value of the X11 DISPLAY for this session - if one is present. - - x11-display - - - - - - The value of the X11 display device - - - - Returns the value of the display device (aka TTY) that the - X11 display for the session is connected to. If there is no x11-display set then this value - is undefined. - - x11-display-device - - - - - - The value of the display device - - - - Returns the value of the display device (aka TTY) that the - session is connected to. - - display-device - - - - - - The remote host name - - - - Returns the value of the remote host name for the session. - - - remote-host-name - - - - - - The value of the native system login session ID - - - - Returns the value of the login session ID that the - underlying system uses to enforce session boundaries. If there is no login session ID - set then this value is an empty string. - - - - - - - TRUE if the session is active, otherwise FALSE - - - - Returns whether the session is active on the Seat that - it is attached to. - If the session is not attached to a seat this value is undefined. - - - active - - - - - - TRUE if the session is local, otherwise FALSE - - - - Returns whether the session is local - FIXME: we need to come up with a concrete definition for this value. - It was originally used as a way to identify XDMCP sessions that originate - from a remote system. - - - is-local - - - - - - An ISO 8601 format date-type string - - - - - Returns an ISO 8601 date-time string that corresponds to - the time that the session was opened. - - - - - - - - - - Attempt to activate the this session. In most - cases, if successful, this will cause the session to - become visible and become active on the seat that it - is attached to. - - Seat.ActivateSession() - - - - - - - This will cause a Lock - signal to be emitted for this session. - - - This method is restricted to privileged users by D-Bus policy. - Lock signal - - - - - - - This will cause an Unlock - signal to be emitted for this session. - - This can be used by login managers to unlock a session before it is - re-activated during fast-user-switching. - - - This method is restricted to privileged users by D-Bus policy. - Unlock signal - - - - - - - The value of the idle-hint - - - - - Gets the value of the idle-hint - property. - - - idle-hint - - - - - - An ISO 8601 format date-type string - - - - - Returns an ISO 8601 date-time string that corresponds to - the time of the last change of the idle-hint. - - - - - - - - - boolean value to set the idle-hint to - - - - - This may be used by the session to indicate that - it is idle. - - Use of this method is restricted to the user - that owns the session. - - - - - - - - TRUE if the session is active, otherwise FALSE - - - - - Emitted when the active property has changed. - - - - - - - the new value of idle-hint - - - - - Emitted when the idle-hint property has changed. - - - - - - - Emitted in response to a call to the Lock() method. - It is intended that the screensaver for the session should lock the screen in response to this signal. - - - - - - - Emitted in response to a call to the Unlock() method. - It is intended that the screensaver for the session should unlock the screen in response to this signal. - - - - - - - - The user assigned to the session. - - - - - - - The user assigned to the session. - - - - - - - - The type of the session. - Warning: we haven't yet defined the allowed values for this property. - It is probably best to avoid this until we do. - - - - - - - - The remote host name for the session. - - This will be set in situations where the session is - opened and controlled from a remote system. - - For example, this value will be set when the - session is created from an SSH or XDMCP connection. - - - - - - - - The display device (aka TTY) that the - session is connected to. - - - - - - - - Value of the X11 DISPLAY for this session - if one is present. - - - - - - - - - The display device (aka TTY) that the X11 display for the - session is connected to. If there is no x11-display set then - this value is undefined. - - - - - - - - - Whether the session is active on the Seat that - it is attached to. - If the session is not attached to a seat this value is undefined. - - - - - - - - - Whether the session is local - FIXME: we need to come up with a concrete definition for this value. - It was originally used as a way to identify XDMCP sessions that originate - from a remote system. - - - - - - - - - This is a hint used to indicate that the session may be idle. - - - For sessions with a x11-display set (ie. graphical - sessions), it is up to each session to delegate the - responsibility for updating this value. Typically, the - screensaver will set this. - - However, for non-graphical sessions with a display-device set - the Session object itself will periodically update this value based - on the activity detected on the display-device itself. - - - This should not be considered authoritative. - - - - - - - diff --git a/src/service.c b/src/service.c new file mode 100644 index 0000000..1345681 --- /dev/null +++ b/src/service.c @@ -0,0 +1,1192 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include + +#include +#include + +#include "backend.h" +#include "service.h" + +/* FIXME: remove -test */ +#define BUS_NAME "com.canonical.indicator.session-test" +#define BUS_PATH "/com/canonical/indicator/session" + +#define ICON_DEFAULT "system-devices-panel" +#define ICON_INFO "system-devices-panel-information" +#define ICON_ALERT "system-devices-panel-alert" + +G_DEFINE_TYPE (IndicatorSessionService, + indicator_session_service, + G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_REPLACE, + PROP_MAX_USERS, + PROP_LAST +}; + +static GParamSpec * properties[PROP_LAST]; + +enum +{ + SECTION_HEADER = (1<<0), + SECTION_ADMIN = (1<<1), + SECTION_SETTINGS = (1<<2), + SECTION_SWITCH = (1<<3), + SECTION_SESSION = (1<<4) +}; + +enum +{ + FORM_DESKTOP, + FORM_GREETER, + N_FORMS +}; + +static const char * const menu_names[N_FORMS] = +{ + "desktop", + "desktop_greeter" +}; + +struct FormMenuInfo +{ + /* the root level -- the header is the only child of this */ + GMenu * menu; + + /* parent of the sections. This is the header's submenu */ + GMenu * submenu; + + guint export_id; +}; + +struct _IndicatorSessionServicePrivate +{ + guint own_id; + guint max_users; + IndicatorSessionUsers * backend_users; + IndicatorSessionGuest * backend_guest; + IndicatorSessionActions * backend_actions; + GSettings * indicator_settings; + GSettings * keybinding_settings; + GSimpleActionGroup * actions; + guint actions_export_id; + struct FormMenuInfo menus[N_FORMS]; + GSimpleAction * header_action; + GSimpleAction * user_switcher_action; + GSimpleAction * guest_switcher_action; + GHashTable * users; + guint rebuild_id; + int rebuild_flags; + GDBusConnection * conn; + + gboolean replace; +}; + +typedef IndicatorSessionServicePrivate priv_t; + +static const char * get_current_real_name (IndicatorSessionService * self); + +/*** +**** +***/ + +static void rebuild_now (IndicatorSessionService * self, int section); +static void rebuild_soon (IndicatorSessionService * self, int section); + +static inline void +rebuild_header_soon (IndicatorSessionService * self) +{ + rebuild_soon (self, SECTION_HEADER); +} +static inline void +rebuild_switch_section_soon (IndicatorSessionService * self) +{ + rebuild_soon (self, SECTION_SWITCH); +} +static inline void +rebuild_session_section_soon (IndicatorSessionService * self) +{ + rebuild_soon (self, SECTION_SESSION); +} +static inline void +rebuild_settings_section_soon (IndicatorSessionService * self) +{ + rebuild_soon (self, SECTION_SETTINGS); +} + +/*** +**** +***/ + +static void +update_header_action (IndicatorSessionService * self) +{ + gchar * a11y; + gboolean need_attn; + gboolean show_name; + GVariant * variant; + const gchar * real_name; + const gchar * label; + const gchar * iconstr; + const priv_t * const p = self->priv; + + g_return_if_fail (p->header_action != NULL); + + if (indicator_session_actions_has_online_account_error (p->backend_actions)) + { + need_attn = TRUE; + iconstr = ICON_ALERT; + } + else + { + need_attn = FALSE; + iconstr = ICON_DEFAULT; + } + + show_name = g_settings_get_boolean (p->indicator_settings, + "show-real-name-on-panel"); + + real_name = get_current_real_name (self); + label = show_name && real_name ? real_name : ""; + + if (*label && need_attn) + { + /* Translators: the name of the menu ("System"), then the user's name, + then a hint that something in this menu requires user attention */ + a11y = g_strdup_printf (_("System, %s (Attention Required)"), real_name); + } + else if (*label) + { + /* Translators: the name of the menu ("System"), then the user's name */ + a11y = g_strdup_printf (_("System, %s"), label); + } + else if (need_attn) + { + a11y = g_strdup (_("System (Attention Required)")); + } + else + { + a11y = g_strdup (_("System")); + } + + variant = g_variant_new ("(sssb)", label, iconstr, a11y, TRUE); + g_simple_action_set_state (p->header_action, variant); + g_free (a11y); +} + +/*** +**** USERS +***/ + +static GMenuModel * create_switch_section (IndicatorSessionService * self); + +static void +add_user (IndicatorSessionService * self, const gchar * key) +{ + IndicatorSessionUser * u; + + /* update our user table */ + u = indicator_session_users_get_user (self->priv->backend_users, key); + g_hash_table_insert (self->priv->users, g_strdup(key), u); + + /* enqueue rebuilds for the affected sections */ + rebuild_switch_section_soon (self); + if (u->is_current_user) + rebuild_header_soon (self); +} + +static void +on_user_added (IndicatorSessionUsers * backend_users G_GNUC_UNUSED, + const char * key, + gpointer gself) +{ + add_user (INDICATOR_SESSION_SERVICE(gself), key); +} + +static void +on_user_changed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED, + const char * key, + gpointer gself) +{ + add_user (INDICATOR_SESSION_SERVICE(gself), key); +} + +static void +on_user_removed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED, + const char * key, + gpointer gself) +{ + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (gself); + g_return_if_fail (self != NULL); + + /* update our user table */ + g_hash_table_remove (self->priv->users, key); + + /* enqueue rebuilds for the affected sections */ + rebuild_switch_section_soon (self); +} + +static const char * +get_current_real_name (IndicatorSessionService * self) +{ + GHashTableIter iter; + gpointer key, value; + + /* is it the guest? */ + if (indicator_session_guest_is_active (self->priv->backend_guest)) + return _("Guest"); + + /* is it a user? */ + g_hash_table_iter_init (&iter, self->priv->users); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + IndicatorSessionUser * user = value; + if (user->is_current_user) + return user->real_name; + } + + return ""; +} + +/*** +**** +***/ + +static GMenuModel * +create_admin_section (void) +{ + GMenu * menu; + GMenuItem * item; + + menu = g_menu_new (); + + item = g_menu_item_new (_("About This Computer"), "indicator.about"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + + item = g_menu_item_new (_("Ubuntu Help"), "indicator.help"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + + return G_MENU_MODEL (menu); +} + +static GMenuModel * +create_settings_section (IndicatorSessionService * self) +{ + GMenu * menu; + GMenuItem * item; + priv_t * p = self->priv; + + menu = g_menu_new (); + + item = g_menu_item_new (_("System Settings\342\200\246"), "indicator.settings"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + + if (indicator_session_actions_has_online_account_error (p->backend_actions)) + { + item = g_menu_item_new (_("Online Accounts\342\200\246"), "indicator.online-accounts"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + return G_MENU_MODEL (menu); +} + +/** + * The switch-to-guest action's state is a dictionary with these entries: + * - "is-active" (boolean) + * - "is-logged-in" (boolean) + */ +static GVariant * +create_guest_switcher_state (IndicatorSessionService * self) +{ + GVariant * val; + GVariantBuilder * b; + IndicatorSessionGuest * const g = self->priv->backend_guest; + + b = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + val = g_variant_new_boolean (indicator_session_guest_is_active (g)); + g_variant_builder_add (b, "{sv}", "is-active", val); + val = g_variant_new_boolean (indicator_session_guest_is_logged_in (g)); + g_variant_builder_add (b, "{sv}", "is-logged-in", val); + return g_variant_builder_end (b); +} + +/** + * The switch-to-user action's state is a dictionary with these entries: + * - "active-user" (username string) + * - "logged-in-users" (array of username strings) + */ +static GVariant * +create_user_switcher_state (IndicatorSessionService * self) +{ + GVariantBuilder * a; + GVariantBuilder * b; + GVariant * val; + GHashTableIter ht_iter; + gpointer ht_key, ht_value; + const char * current_user; + + current_user = ""; + a = g_variant_builder_new (G_VARIANT_TYPE("as")); + g_hash_table_iter_init (&ht_iter, self->priv->users); + while (g_hash_table_iter_next (&ht_iter, &ht_key, &ht_value)) + { + const IndicatorSessionUser * u = ht_value; + + if (u->is_current_user) + current_user = u->user_name; + + if (u->is_logged_in) + g_variant_builder_add (a, "s", u->user_name); + } + + b = g_variant_builder_new (G_VARIANT_TYPE("a{sv}")); + val = g_variant_new_string (current_user); + g_variant_builder_add (b, "{sv}", "active-user", val); + val = g_variant_builder_end (a); + g_variant_builder_add (b, "{sv}", "logged-in-users", val); + return g_variant_builder_end (b); +} + +static void +update_switch_actions (IndicatorSessionService * self) +{ + g_simple_action_set_state (self->priv->guest_switcher_action, + create_guest_switcher_state (self)); + + g_simple_action_set_state (self->priv->user_switcher_action, + create_user_switcher_state (self)); +} + +static gboolean +use_ellipsis (IndicatorSessionService * self) +{ + /* does the backend support confirmation prompts? */ + if (!indicator_session_actions_can_prompt (self->priv->backend_actions)) + return FALSE; + + /* has the user disabled prompts? */ + if (g_settings_get_boolean (self->priv->indicator_settings, + "suppress-logout-restart-shutdown")) + return FALSE; + + return TRUE; +} + +/* lower index == more useful. + When there are too many users for the menu, + we use this to decide which to cull. */ +static int +compare_users_by_usefulness (gconstpointer ga, gconstpointer gb) +{ + const IndicatorSessionUser * a = *(const IndicatorSessionUser**)ga; + const IndicatorSessionUser * b = *(const IndicatorSessionUser**)gb; + + if (a->is_current_user != b->is_current_user) + return a->is_current_user ? -1 : 1; + + if (a->is_logged_in != b->is_logged_in) + return a->is_logged_in ? -1 : 1; + + if (a->login_frequency != b->login_frequency) + return a->login_frequency > b->login_frequency ? -1 : 1; + + return 0; +} + +/* sorting them for display in the menu */ +static int +compare_users_by_label (gconstpointer ga, gconstpointer gb) +{ + int i; + const IndicatorSessionUser * a = *(const IndicatorSessionUser**)ga; + const IndicatorSessionUser * b = *(const IndicatorSessionUser**)gb; + + if ((i = g_strcmp0 (a->real_name, b->real_name))) + return i; + + return g_strcmp0 (a->user_name, b->user_name); +} + +static GMenuModel * +create_switch_section (IndicatorSessionService * self) +{ + gchar * str; + GMenu * menu; + GMenuItem * item; + guint i; + gpointer guser; + GHashTableIter iter; + GPtrArray * users; + const priv_t * const p = self->priv; + const gboolean ellipsis = use_ellipsis (self); + + menu = g_menu_new (); + + /* lockswitch */ + if (indicator_session_users_is_live_session (p->backend_users)) + { + const char * action = "indicator.switch-to-screensaver"; + item = g_menu_item_new (_("Start Screen Saver"), action); + } + else if (indicator_session_guest_is_active (p->backend_guest)) + { + const char * action = "indicator.switch-to-greeter"; + item = g_menu_item_new (ellipsis ? _("Switch Account\342\200\246") + : _("Switch Account"), action); + } + else if (g_hash_table_size (p->users) == 1) + { + const char * action = "indicator.switch-to-greeter"; + item = g_menu_item_new (ellipsis ? _("Lock\342\200\246") + : _("Lock"), action); + } + else + { + const char * action = "indicator.switch-to-greeter"; + item = g_menu_item_new (ellipsis ? _("Lock/Switch Account\342\200\246") + : _("Lock/Switch Account"), action); + } + str = g_settings_get_string (p->keybinding_settings, "screensaver"); + g_menu_item_set_attribute (item, "accel", "s", str); + g_free (str); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + + if (indicator_session_guest_is_allowed (p->backend_guest)) + { + item = g_menu_item_new (_("Guest Session"), "indicator.switch-to-guest"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + /* build an array of all the users we know of */ + users = g_ptr_array_new (); + g_hash_table_iter_init (&iter, p->users); + while (g_hash_table_iter_next (&iter, NULL, &guser)) + g_ptr_array_add (users, guser); + + /* if there are too many users, cull out the less interesting ones */ + if (users->len > p->max_users) + { + g_ptr_array_sort (users, compare_users_by_usefulness); + g_ptr_array_set_size (users, p->max_users); + } + + /* sort the users by name */ + g_ptr_array_sort (users, compare_users_by_label); + + /* add the users */ + for (i=0; ilen; ++i) + { + const IndicatorSessionUser * u = g_ptr_array_index (users, i); + item = g_menu_item_new (u->real_name, NULL); + g_menu_item_set_action_and_target (item, "indicator.switch-to-user", "s", u->user_name); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + /* cleanup */ + g_ptr_array_free (users, TRUE); + return G_MENU_MODEL (menu); +} + +static GMenuModel * +create_session_section (IndicatorSessionService * self) +{ + GMenu * menu; + GMenuItem * item; + const priv_t * const p = self->priv; + GSettings * const s = p->indicator_settings; + const gboolean ellipsis = use_ellipsis (self); + + menu = g_menu_new (); + + if (indicator_session_actions_can_logout (p->backend_actions) && !g_settings_get_boolean (s, "suppress-logout-menuitem")) + { + item = g_menu_item_new (ellipsis ? _("Log Out\342\200\246") + : _("Log Out"), "indicator.logout"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + if (indicator_session_actions_can_suspend (p->backend_actions)) + { + item = g_menu_item_new (_("Suspend"), "indicator.suspend"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + if (indicator_session_actions_can_hibernate (p->backend_actions)) + { + item = g_menu_item_new (_("Hibernate"), "indicator.hibernate"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + if (!g_settings_get_boolean (s, "suppress-restart-menuitem")) + { + item = g_menu_item_new (ellipsis ? _("Restart\342\200\246") + : _("Restart"), "indicator.restart"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + if (!g_settings_get_boolean (s, "suppress-shutdown-menuitem")) + { + item = g_menu_item_new (ellipsis ? _("Shutdown\342\200\246") + : _("Shutdown"), "indicator.shutdown"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + return G_MENU_MODEL (menu); +} + +static void +create_menu (IndicatorSessionService * self, int form_factor) +{ + GMenu * menu; + GMenu * submenu; + GMenuItem * header; + GMenuModel * sections[16]; + int i; + int n = 0; + + g_assert (0<=form_factor && form_factorpriv->menus[form_factor].menu == NULL); + + if (form_factor == FORM_DESKTOP) + { + sections[n++] = create_admin_section (); + sections[n++] = create_settings_section (self); + sections[n++] = create_switch_section (self); + sections[n++] = create_session_section (self); + } + else if (form_factor == FORM_GREETER) + { + sections[n++] = create_session_section (self); + } + + /* add sections to the submenu */ + submenu = g_menu_new (); + for (i=0; ipriv->menus[form_factor].menu = menu; + self->priv->menus[form_factor].submenu = submenu; +} + +/*** +**** GActions +***/ + +static IndicatorSessionActions * +get_backend_actions (gpointer gself) +{ + return INDICATOR_SESSION_SERVICE(gself)->priv->backend_actions; +} + +static void +on_about_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_about (get_backend_actions(gself)); +} + +static void +on_help_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_help (get_backend_actions(gself)); +} + +static void +on_settings_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_settings (get_backend_actions(gself)); +} + +static void +on_logout_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_logout (get_backend_actions(gself)); +} + +static void +on_suspend_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_suspend (get_backend_actions(gself)); +} + +static void +on_hibernate_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_hibernate (get_backend_actions(gself)); +} + +static void +on_restart_activated (GSimpleAction * action G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_restart (get_backend_actions(gself)); +} + +static void +on_shutdown_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_shutdown (get_backend_actions(gself)); +} + +static void +on_guest_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_switch_to_guest (get_backend_actions(gself)); +} + +static void +on_screensaver_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_switch_to_screensaver (get_backend_actions(gself)); +} + +static void +on_greeter_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_switch_to_greeter (get_backend_actions(gself)); +} + +static void +on_user_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param, + gpointer gself) +{ + const char * username = g_variant_get_string (param, NULL); + indicator_session_actions_switch_to_username (get_backend_actions(gself), + username); +} + +static void +init_gactions (IndicatorSessionService * self) +{ + GVariant * v; + GSimpleAction * a; + priv_t * p = self->priv; + + GActionEntry entries[] = { + { "about", on_about_activated }, + { "help", on_help_activated }, + { "settings", on_settings_activated }, + { "logout", on_logout_activated }, + { "suspend", on_suspend_activated }, + { "hibernate", on_hibernate_activated }, + { "restart", on_restart_activated }, + { "shutdown", on_shutdown_activated }, + { "switch-to-screensaver", on_screensaver_activated }, + { "switch-to-greeter", on_greeter_activated } + }; + + p->actions = g_simple_action_group_new (); + + g_action_map_add_action_entries (G_ACTION_MAP(p->actions), + entries, + G_N_ELEMENTS(entries), + self); + + /* add switch-to-guest action */ + v = create_guest_switcher_state (self); + a = g_simple_action_new_stateful ("switch-to-guest", NULL, v); + g_signal_connect (a, "activate", G_CALLBACK(on_guest_activated), self); + g_simple_action_group_insert (p->actions, G_ACTION(a)); + p->guest_switcher_action = a; + + /* add switch-to-user action... parameter is the uesrname */ + v = create_user_switcher_state (self); + a = g_simple_action_new_stateful ("switch-to-user", G_VARIANT_TYPE_STRING, v); + g_signal_connect (a, "activate", G_CALLBACK(on_user_activated), self); + g_simple_action_group_insert (p->actions, G_ACTION(a)); + p->user_switcher_action = a; + + /* add the header action */ + v = g_variant_new ("(sssb)", "label", ICON_DEFAULT, "a11y", TRUE); + a = g_simple_action_new_stateful ("_header", NULL, v); + g_simple_action_group_insert (p->actions, G_ACTION(a)); + p->header_action = a; + + rebuild_now (self, SECTION_HEADER); +} + +/*** +**** +***/ + +static void +replace_section (GMenu * parent, int pos, GMenuModel * new_section) +{ + g_menu_remove (parent, pos); + g_menu_insert_section (parent, pos, NULL, new_section); + g_object_unref (G_OBJECT(new_section)); +} + +static void +rebuild_now (IndicatorSessionService * self, int sections) +{ + priv_t * p = self->priv; + struct FormMenuInfo * desktop = &p->menus[FORM_DESKTOP]; + struct FormMenuInfo * greeter = &p->menus[FORM_GREETER]; + + if (sections & SECTION_HEADER) + { + update_header_action (self); + } + + if (sections & SECTION_ADMIN) + { + replace_section (desktop->submenu, 0, create_admin_section()); + } + + if (sections & SECTION_SETTINGS) + { + replace_section (desktop->submenu, 1, create_settings_section(self)); + } + + if (sections & SECTION_SWITCH) + { + replace_section (desktop->submenu, 2, create_switch_section(self)); + update_switch_actions (self); + } + + if (sections & SECTION_SESSION) + { + replace_section (desktop->submenu, 3, create_session_section(self)); + replace_section (greeter->submenu, 0, create_session_section(self)); + } +} + +static int +rebuild_timeout_func (IndicatorSessionService * self) +{ + priv_t * p = self->priv; + rebuild_now (self, p->rebuild_flags); + p->rebuild_flags = 0; + p->rebuild_id = 0; + return G_SOURCE_REMOVE; +} + +static void +rebuild_soon (IndicatorSessionService * self, int section) +{ + priv_t * p = self->priv; + + p->rebuild_flags |= section; + + if (p->rebuild_id == 0) + { + static const int REBUILD_INTERVAL_MSEC = 500; + + p->rebuild_id = g_timeout_add (REBUILD_INTERVAL_MSEC, + (GSourceFunc)rebuild_timeout_func, + self); + } +} + +/*** +**** GDBus +***/ + +static void +on_bus_acquired (GDBusConnection * connection, + const gchar * name, + gpointer gself) +{ + int i; + guint id; + GError * err = NULL; + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(gself); + priv_t * p = self->priv; + + g_debug ("bus acquired: %s", name); + + p->conn = g_object_ref (G_OBJECT (connection)); + + /* export the actions */ + if ((id = g_dbus_connection_export_action_group (connection, + BUS_PATH, + G_ACTION_GROUP (p->actions), + &err))) + { + p->actions_export_id = id; + } + else + { + g_warning ("cannot export action group: %s", err->message); + g_clear_error (&err); + } + + /* export the menus */ + for (i=0; imenus[i]; + + if (menu->menu == NULL) + create_menu (self, i); + + if ((id = g_dbus_connection_export_menu_model (connection, + path, + G_MENU_MODEL (menu->menu), + &err))) + { + menu->export_id = id; + } + else + { + g_warning ("cannot export %s menu: %s", menu_names[i], err->message); + g_clear_error (&err); + } + + g_free (path); + } +} + +static void +unexport (IndicatorSessionService * self) +{ + int i; + priv_t * p = self->priv; + + /* unexport the menus */ + for (i=0; ipriv->menus[i].export_id; + + if (*id) + { + g_dbus_connection_unexport_menu_model (p->conn, *id); + *id = 0; + } + } + + /* unexport the actions */ + if (p->actions_export_id) + { + g_dbus_connection_unexport_action_group (p->conn, p->actions_export_id); + p->actions_export_id = 0; + } +} + +static void +on_name_lost (GDBusConnection * connection G_GNUC_UNUSED, + const gchar * name, + gpointer gself) +{ + g_debug ("%s %s name lost %s", G_STRLOC, G_STRFUNC, name); + + unexport (INDICATOR_SESSION_SERVICE (gself)); +} + +/*** +**** +***/ + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_service_init (IndicatorSessionService * self) +{ + int i; + GStrv keys; + priv_t * p; + gpointer gp; + + /* init our priv pointer */ + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_SERVICE, + IndicatorSessionServicePrivate); + p->indicator_settings = g_settings_new ("com.canonical.indicator.session"); + p->keybinding_settings = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); + self->priv = p; + + /* init the backend objects */ + backend_get (g_cancellable_new (), &p->backend_actions, + &p->backend_users, + &p->backend_guest); + + /* init our key-to-User table */ + p->users = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify)indicator_session_user_free); + keys = indicator_session_users_get_keys (p->backend_users); + for (i=0; keys && keys[i]; ++i) + add_user (self, keys[i]); + g_strfreev (keys); + + init_gactions (self); + + /* watch for changes in backend_users */ + gp = p->backend_users; + g_signal_connect (gp, INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED, + G_CALLBACK(on_user_added), self); + g_signal_connect (gp, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, + G_CALLBACK(on_user_changed), self); + g_signal_connect (gp, INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED, + G_CALLBACK(on_user_removed), self); + g_signal_connect_swapped (gp, "notify::is-live-session", + G_CALLBACK(rebuild_switch_section_soon), self); + + /* watch for changes in backend_guest */ + gp = p->backend_guest; + g_signal_connect_swapped (gp, "notify::guest-is-active-session", + G_CALLBACK(rebuild_header_soon), self); + g_signal_connect_swapped (gp, "notify", + G_CALLBACK(rebuild_switch_section_soon), self); + + /* watch for updates in backend_actions */ + gp = p->backend_actions; + g_signal_connect_swapped (gp, "notify", + G_CALLBACK(rebuild_switch_section_soon), self); + g_signal_connect_swapped (gp, "notify", + G_CALLBACK(rebuild_session_section_soon), self); + g_signal_connect_swapped (gp, "notify::has-online-account-error", + G_CALLBACK(rebuild_header_soon), self); + g_signal_connect_swapped (gp, "notify::has-online-account-error", + G_CALLBACK(rebuild_settings_section_soon), self); + + /* watch for changes in the indicator's settings */ + gp = p->indicator_settings; + g_signal_connect_swapped (gp, "changed::suppress-logout-restart-shutdown", + G_CALLBACK(rebuild_switch_section_soon), self); + g_signal_connect_swapped (gp, "changed::suppress-logout-restart-shutdown", + G_CALLBACK(rebuild_session_section_soon), self); + g_signal_connect_swapped (gp, "changed::suppress-logout-menuitem", + G_CALLBACK(rebuild_session_section_soon), self); + g_signal_connect_swapped (gp, "changed::suppress-restart-menuitem", + G_CALLBACK(rebuild_session_section_soon), self); + g_signal_connect_swapped (gp, "changed::suppress-shutdown-menuitem", + G_CALLBACK(rebuild_session_section_soon), self); + g_signal_connect_swapped (gp, "changed::show-real-name-on-panel", + G_CALLBACK(rebuild_header_soon), self); + + /* watch for changes to the lock keybinding */ + gp = p->keybinding_settings; + g_signal_connect_swapped (gp, "changed::screensaver", + G_CALLBACK(rebuild_switch_section_soon), self); +} + +static void +my_constructed (GObject * o) +{ + GBusNameOwnerFlags owner_flags; + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(o); + + /* own the name in constructed() instead of init() so that + we'll know the value of the 'replace' property */ + owner_flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT; + if (self->priv->replace) + owner_flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE; + + self->priv->own_id = g_bus_own_name (G_BUS_TYPE_SESSION, + BUS_NAME, + owner_flags, + on_bus_acquired, + NULL, + on_name_lost, + self, + NULL); +} + +/*** +**** GObject plumbing: properties +***/ + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (o); + + switch (property_id) + { + case PROP_REPLACE: + g_value_set_boolean (value, self->priv->replace); + break; + + case PROP_MAX_USERS: + g_value_set_uint (value, self->priv->max_users); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +my_set_property (GObject * o, + guint property_id, + const GValue * value G_GNUC_UNUSED, + GParamSpec * pspec) +{ + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (o); + + switch (property_id) + { + case PROP_REPLACE: + self->priv->replace = g_value_get_boolean (value); + break; + + case PROP_MAX_USERS: + self->priv->max_users = g_value_get_uint (value); + rebuild_switch_section_soon (self); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +/*** +**** GObject plumbing: life cycle +***/ + +static void +my_dispose (GObject * o) +{ + int i; + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(o); + priv_t * p = self->priv; + + unexport (self); + + if (p->rebuild_id) + { + g_source_remove (p->rebuild_id); + p->rebuild_id = 0; + } + + if (p->own_id) + { + g_bus_unown_name (p->own_id); + p->own_id = 0; + } + + g_clear_pointer (&p->users, g_hash_table_destroy); + g_clear_object (&p->backend_users); + g_clear_object (&p->backend_guest); + g_clear_object (&p->backend_actions); + g_clear_object (&p->indicator_settings); + g_clear_object (&p->keybinding_settings); + g_clear_object (&p->actions); + + for (i=0; imenus[i].menu); + + g_clear_object (&p->header_action); + g_clear_object (&p->user_switcher_action); + g_clear_object (&p->guest_switcher_action); + g_clear_object (&p->conn); + + G_OBJECT_CLASS (indicator_session_service_parent_class)->dispose (o); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_service_class_init (IndicatorSessionServiceClass * klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = my_dispose; + object_class->constructed = my_constructed; + object_class->get_property = my_get_property; + object_class->set_property = my_set_property; + + g_type_class_add_private (klass, sizeof (IndicatorSessionServicePrivate)); + + properties[PROP_0] = NULL; + + properties[PROP_REPLACE] = g_param_spec_boolean ("replace", + "Replace Service", + "Replace existing service", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + properties[PROP_MAX_USERS] = g_param_spec_uint ("max-users", + "Max Users", + "Max visible users", + 0, INT_MAX, 12, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST, properties); +} + +IndicatorSessionService * +indicator_session_service_new (gboolean replace) +{ + GObject * o = g_object_new (INDICATOR_TYPE_SESSION_SERVICE, + "replace", replace, + NULL); + + return INDICATOR_SESSION_SERVICE (o); +} diff --git a/src/service.h b/src/service.h new file mode 100644 index 0000000..2a78855 --- /dev/null +++ b/src/service.h @@ -0,0 +1,64 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __INDICATOR_SESSION_SERVICE_H__ +#define __INDICATOR_SESSION_SERVICE_H__ + +#include +#include + +G_BEGIN_DECLS + +/* standard GObject macros */ +#define INDICATOR_TYPE_SESSION_SERVICE (indicator_session_service_get_type()) +#define INDICATOR_SESSION_SERVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_SERVICE, IndicatorSessionService)) +#define INDICATOR_SESSION_SERVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_SERVICE, IndicatorSessionServiceClass)) +#define INDICATOR_SESSION_SERVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_SESSION_SERVICE, IndicatorSessionServiceClass)) +#define INDICATOR_IS_SESSION_SERVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_SERVICE)) + +typedef struct _IndicatorSessionService IndicatorSessionService; +typedef struct _IndicatorSessionServiceClass IndicatorSessionServiceClass; +typedef struct _IndicatorSessionServicePrivate IndicatorSessionServicePrivate; + +/** + * The Indicator Session Service. + */ +struct _IndicatorSessionService +{ + /*< private >*/ + GObject parent; + IndicatorSessionServicePrivate * priv; +}; + +struct _IndicatorSessionServiceClass +{ + GObjectClass parent_class; +}; + +/*** +**** +***/ + +GType indicator_session_service_get_type (void); + +IndicatorSessionService * indicator_session_service_new (gboolean replace); + +G_END_DECLS + +#endif /* __INDICATOR_SESSION_SERVICE_H__ */ diff --git a/src/session-dbus.c b/src/session-dbus.c deleted file mode 100644 index 4ece444..0000000 --- a/src/session-dbus.c +++ /dev/null @@ -1,282 +0,0 @@ -/* -The Dbus object on the bus for the indicator. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "session-dbus.h" -#include "shared-names.h" - -static GVariant * get_users_real_name (SessionDbus * service); -static void bus_get_cb (GObject * object, GAsyncResult * res, gpointer user_data); -static void bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data); - -#include "gen-session-dbus.xml.h" - -typedef struct _SessionDbusPrivate SessionDbusPrivate; -struct _SessionDbusPrivate { - gchar * name; - GDBusConnection * bus; - GCancellable * bus_cancel; - guint dbus_registration; -}; - -/* GDBus Stuff */ -static GDBusNodeInfo * node_info = NULL; -static GDBusInterfaceInfo * interface_info = NULL; -static GDBusInterfaceVTable interface_table = { - method_call: bus_method_call, - get_property: NULL, /* No properties */ - set_property: NULL /* No properties */ -}; - -#define SESSION_DBUS_GET_PRIVATE(o) \ -(G_TYPE_INSTANCE_GET_PRIVATE ((o), SESSION_DBUS_TYPE, SessionDbusPrivate)) - -static void session_dbus_class_init (SessionDbusClass *klass); -static void session_dbus_init (SessionDbus *self); -static void session_dbus_dispose (GObject *object); -static void session_dbus_finalize (GObject *object); - -G_DEFINE_TYPE (SessionDbus, session_dbus, G_TYPE_OBJECT); - -static void -session_dbus_class_init (SessionDbusClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (SessionDbusPrivate)); - - object_class->dispose = session_dbus_dispose; - object_class->finalize = session_dbus_finalize; - - /* Setting up the DBus interfaces */ - if (node_info == NULL) { - GError * error = NULL; - - node_info = g_dbus_node_info_new_for_xml(_session_dbus, &error); - if (error != NULL) { - g_error("Unable to parse Session Service Interface description: %s", error->message); - g_error_free(error); - } - } - - if (interface_info == NULL) { - interface_info = g_dbus_node_info_lookup_interface(node_info, INDICATOR_SESSION_SERVICE_DBUS_IFACE); - - if (interface_info == NULL) { - g_error("Unable to find interface '" INDICATOR_SESSION_SERVICE_DBUS_IFACE "'"); - } - } - - return; -} - -static void -session_dbus_init (SessionDbus *self) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(self); - - priv->name = NULL; - priv->bus = NULL; - priv->bus_cancel = NULL; - priv->dbus_registration = 0; - - priv->bus_cancel = g_cancellable_new(); - g_bus_get(G_BUS_TYPE_SESSION, - priv->bus_cancel, - bus_get_cb, - self); - - return; -} - -static void -bus_get_cb (GObject * object, GAsyncResult * res, gpointer user_data) -{ - GError * error = NULL; - GDBusConnection * connection = g_bus_get_finish(res, &error); - - if (error != NULL) { - g_error("OMG! Unable to get a connection to DBus: %s", error->message); - g_error_free(error); - return; - } - - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(user_data); - - g_warn_if_fail(priv->bus == NULL); - priv->bus = connection; - - if (priv->bus_cancel != NULL) { - g_object_unref(priv->bus_cancel); - priv->bus_cancel = NULL; - } - - /* Now register our object on our new connection */ - priv->dbus_registration = g_dbus_connection_register_object(priv->bus, - INDICATOR_SESSION_SERVICE_DBUS_OBJECT, - interface_info, - &interface_table, - user_data, - NULL, - &error); - - if (error != NULL) { - g_error("Unable to register the object to DBus: %s", error->message); - g_error_free(error); - return; - } - - return; -} - -/* A method has been called from our dbus inteface. Figure out what it - is and dispatch it. */ -static void -bus_method_call (GDBusConnection * connection, const gchar * sender, - const gchar * path, const gchar * interface, - const gchar * method, GVariant * params, - GDBusMethodInvocation * invocation, gpointer user_data) -{ - SessionDbus * service = SESSION_DBUS (user_data); - - GVariant * retval = NULL; - - if (g_strcmp0(method, "GetUserRealName") == 0) { - retval = get_users_real_name (service); - } - else { - g_warning("Calling method '%s' on the indicator service and it's unknown", method); - } - g_dbus_method_invocation_return_value(invocation, retval); - return; -} - -static void -session_dbus_dispose (GObject *object) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(object); - - if (priv->dbus_registration != 0) { - g_dbus_connection_unregister_object(priv->bus, priv->dbus_registration); - /* Don't care if it fails, there's nothing we can do */ - priv->dbus_registration = 0; - } - - if (priv->bus != NULL) { - g_object_unref(priv->bus); - priv->bus = NULL; - } - - if (priv->bus_cancel != NULL) { - g_cancellable_cancel(priv->bus_cancel); - g_object_unref(priv->bus_cancel); - priv->bus_cancel = NULL; - } - - G_OBJECT_CLASS (session_dbus_parent_class)->dispose (object); - return; -} - -static void -session_dbus_finalize (GObject *object) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(object); - - g_clear_pointer (&priv->name, g_free); - - G_OBJECT_CLASS (session_dbus_parent_class)->finalize (object); - return; -} - -static GVariant * -get_users_real_name (SessionDbus * service) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(service); - return g_variant_new ("(s)", priv->name ? priv->name : ""); -} - -SessionDbus * -session_dbus_new (void) -{ - return SESSION_DBUS(g_object_new(SESSION_DBUS_TYPE, NULL)); -} - -void -session_dbus_set_name (SessionDbus * session, const gchar * name) -{ -} - -void -session_dbus_set_users_real_name (SessionDbus * session, const gchar * name) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(session); - GError * error = NULL; - - g_free (priv->name); - priv->name = g_strdup(name); - - if (priv->bus != NULL) { - g_dbus_connection_emit_signal (priv->bus, - NULL, - INDICATOR_SESSION_SERVICE_DBUS_OBJECT, - INDICATOR_SESSION_SERVICE_DBUS_IFACE, - "UserRealNameUpdated", - g_variant_new ("(s)", priv->name, NULL), - &error); - - if (error != NULL) { - g_warning("Unable to send UserRealNameUpdated signal: %s", error->message); - g_error_free(error); - return; - } - } - return; -} - -void session_dbus_restart_required (SessionDbus* session) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(session); - GError * error = NULL; - - if (priv->bus != NULL) { - g_debug("About to send RebootRequired signal"); - - g_dbus_connection_emit_signal (priv->bus, - NULL, - INDICATOR_SESSION_SERVICE_DBUS_OBJECT, - INDICATOR_SESSION_SERVICE_DBUS_IFACE, - "RestartRequired", - NULL, - &error); - - if (error != NULL) { - g_warning("Unable to send reboot-required signal: %s", error->message); - g_error_free(error); - } - } - -} diff --git a/src/session-dbus.h b/src/session-dbus.h deleted file mode 100644 index 7520f06..0000000 --- a/src/session-dbus.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -The Dbus object on the bus for the indicator. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifndef __SESSION_DBUS_H__ -#define __SESSION_DBUS_H__ - -#include -#include - -G_BEGIN_DECLS - -#define SESSION_DBUS_TYPE (session_dbus_get_type ()) -#define SESSION_DBUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SESSION_DBUS_TYPE, SessionDbus)) -#define SESSION_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SESSION_DBUS_TYPE, SessionDbusClass)) -#define IS_SESSION_DBUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SESSION_DBUS_TYPE)) -#define IS_SESSION_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SESSION_DBUS_TYPE)) -#define SESSION_DBUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SESSION_DBUS_TYPE, SessionDbusClass)) - -typedef struct _SessionDbus SessionDbus; -typedef struct _SessionDbusClass SessionDbusClass; - -struct _SessionDbusClass { - GObjectClass parent_class; - void (*icon_updated) (SessionDbus * session, gchar * icon, gpointer user_data); -}; - -struct _SessionDbus { - GObject parent; -}; - -GType session_dbus_get_type (void); -SessionDbus * session_dbus_new (void); -void session_dbus_set_name (SessionDbus * session, const gchar * name); -void session_dbus_set_users_real_name (SessionDbus * session, const gchar * name); -void session_dbus_restart_required (SessionDbus* session); -G_END_DECLS - -#endif diff --git a/src/session-dbus.xml b/src/session-dbus.xml deleted file mode 100644 index 96e9837..0000000 --- a/src/session-dbus.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/src/session-menu-mgr.c b/src/session-menu-mgr.c deleted file mode 100644 index b618135..0000000 --- a/src/session-menu-mgr.c +++ /dev/null @@ -1,1226 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Charles Kerr - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#include "config.h" - -#include -#include /* geteuid(), getpwuid() */ - -#include -#include - -#include -#include - -#include "dbus-upower.h" -#include "session-menu-mgr.h" -#include "shared-names.h" -#include "users-service-dbus.h" -#include "online-accounts-mgr.h" - -#define DEBUG_SHOW_ALL FALSE - -#define UPOWER_ADDRESS "org.freedesktop.UPower" -#define UPOWER_PATH "/org/freedesktop/UPower" - -#define CMD_HELP "yelp" -#define CMD_INFO "gnome-control-center info" -#define CMD_SYSTEM_SETTINGS "gnome-control-center" -#ifdef HAVE_GTKLOGOUTHELPER - #define HAVE_RESTART_CMD TRUE - #define CMD_RESTART LIBEXECDIR"/gtk-logout-helper --restart" - #define CMD_LOGOUT LIBEXECDIR"/gtk-logout-helper --logout" - #define CMD_SHUTDOWN LIBEXECDIR"/gtk-logout-helper --shutdown" -#else - #define HAVE_RESTART_CMD FALSE /* hmm, no gnome-session-quit --restart? */ - #define CMD_RESTART "" - #define CMD_LOGOUT "gnome-session-quit --logout" - #define CMD_SHUTDOWN "gnome-session-quit --power-off" -#endif - -/** - * Which switch menuitem to show -- based on lockdown settings, - * greeter mode, number of users in the system, and so on. - * See get_switcher_mode() - */ -typedef enum -{ - SWITCHER_MODE_SCREENSAVER, - SWITCHER_MODE_LOCK, - SWITCHER_MODE_SWITCH, - SWITCHER_MODE_SWITCH_OR_LOCK, - SWITCHER_MODE_NONE -} -SwitcherMode; - -/** - * Creates and manages the menumodel and associated actions for the - * session menu described at . - * - * This is a pretty straightforward class: it creates the menumodel - * and listens for events that can affect the model's properties. - * - * Simple event sources, such as GSettings and a UPower DBus proxy, - * are handled here. More involved event sources are delegated to the - * UsersServiceDBus facade class. - */ -struct _SessionMenuMgr -{ - GObject parent_instance; - - DbusmenuMenuitem * top_mi; - DbusmenuMenuitem * screensaver_mi; - DbusmenuMenuitem * lock_mi; - DbusmenuMenuitem * lock_switch_mi; - DbusmenuMenuitem * guest_mi; - DbusmenuMenuitem * online_accounts_mi; - DbusmenuMenuitem * logout_mi; - DbusmenuMenuitem * suspend_mi; - DbusmenuMenuitem * hibernate_mi; - DbusmenuMenuitem * restart_mi; - DbusmenuMenuitem * shutdown_mi; - - GSList * user_menuitems; - gint user_menuitem_index; - - GSettings * lockdown_settings; - GSettings * indicator_settings; - GSettings * keybinding_settings; - - /* cached settings taken from the upower proxy */ - gboolean can_hibernate; - gboolean can_suspend; - gboolean allow_hibernate; - gboolean allow_suspend; - - gboolean greeter_mode; - - GCancellable * cancellable; - DBusUPower * upower_proxy; - SessionDbus * session_dbus; - UsersServiceDbus * users_dbus_facade; - OnlineAccountsMgr * online_accounts_mgr; -}; - -static SwitcherMode get_switcher_mode (SessionMenuMgr *); - -static void init_upower_proxy (SessionMenuMgr *); - -static void update_screensaver_shortcut (SessionMenuMgr *); -static void update_user_menuitems (SessionMenuMgr *); -static void update_session_menuitems (SessionMenuMgr *); -static void update_confirmation_labels (SessionMenuMgr *); - -static void action_func_lock (SessionMenuMgr *); -static void action_func_suspend (SessionMenuMgr *); -static void action_func_hibernate (SessionMenuMgr *); -static void action_func_switch_to_lockscreen (SessionMenuMgr *); -static void action_func_switch_to_greeter (SessionMenuMgr *); -static void action_func_switch_to_guest (SessionMenuMgr *); -static void action_func_switch_to_user (AccountsUser *); -static void action_func_spawn_async (const char * cmd); - -static gboolean is_this_guest_session (void); -static gboolean is_this_live_session (void); - -static void on_guest_logged_in_changed (UsersServiceDbus *, - SessionMenuMgr *); - -static void on_user_logged_in_changed (UsersServiceDbus *, - AccountsUser *, - SessionMenuMgr *); - -/** -*** GObject init / dispose -**/ - -G_DEFINE_TYPE (SessionMenuMgr, session_menu_mgr, G_TYPE_OBJECT); - -static void -session_menu_mgr_init (SessionMenuMgr *mgr) -{ - mgr->top_mi = dbusmenu_menuitem_new (); - - /* Lockdown settings */ - GSettings * s = g_settings_new ("org.gnome.desktop.lockdown"); - g_signal_connect_swapped (s, "changed::disable-log-out", - G_CALLBACK(update_session_menuitems), mgr); - g_signal_connect_swapped (s, "changed::disable-lock-screen", - G_CALLBACK(update_user_menuitems), mgr); - g_signal_connect_swapped (s, "changed::disable-user-switching", - G_CALLBACK(update_user_menuitems), mgr); - mgr->lockdown_settings = s; - - /* Indicator settings */ - s = g_settings_new ("com.canonical.indicator.session"); - g_signal_connect_swapped (s, "changed::suppress-logout-restart-shutdown", - G_CALLBACK(update_confirmation_labels), mgr); - g_signal_connect_swapped (s, "changed::suppress-logout-menuitem", - G_CALLBACK(update_session_menuitems), mgr); - g_signal_connect_swapped (s, "changed::suppress-restart-menuitem", - G_CALLBACK(update_session_menuitems), mgr); - g_signal_connect_swapped (s, "changed::suppress-shutdown-menuitem", - G_CALLBACK(update_session_menuitems), mgr); - mgr->indicator_settings = s; - - /* Keybinding settings */ - s = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); - g_signal_connect_swapped (s, "changed::screensaver", - G_CALLBACK(update_screensaver_shortcut), mgr); - mgr->keybinding_settings = s; - - /* listen for user events */ - mgr->users_dbus_facade = g_object_new (USERS_SERVICE_DBUS_TYPE, NULL); - g_signal_connect_swapped (mgr->users_dbus_facade, "user-list-changed", - G_CALLBACK (update_user_menuitems), mgr); - g_signal_connect (mgr->users_dbus_facade, "user-logged-in-changed", - G_CALLBACK(on_user_logged_in_changed), mgr); - g_signal_connect (mgr->users_dbus_facade, "guest-logged-in-changed", - G_CALLBACK(on_guest_logged_in_changed), mgr); - - init_upower_proxy (mgr); - - /* Online accounts menu item */ - mgr->online_accounts_mgr = online_accounts_mgr_new (); -} - -static void -session_menu_mgr_dispose (GObject *object) -{ - SessionMenuMgr * mgr = SESSION_MENU_MGR (object); - - if (mgr->cancellable != NULL) - { - g_cancellable_cancel (mgr->cancellable); - g_clear_object (&mgr->cancellable); - } - - g_clear_object (&mgr->indicator_settings); - g_clear_object (&mgr->lockdown_settings); - g_clear_object (&mgr->keybinding_settings); - g_clear_object (&mgr->upower_proxy); - g_clear_object (&mgr->users_dbus_facade); - g_clear_object (&mgr->top_mi); - g_clear_object (&mgr->session_dbus); - g_clear_object (&mgr->online_accounts_mgr); - - g_slist_free (mgr->user_menuitems); - mgr->user_menuitems = NULL; - - G_OBJECT_CLASS (session_menu_mgr_parent_class)->dispose (object); -} - -static void -session_menu_mgr_class_init (SessionMenuMgrClass * klass) -{ - GObjectClass* object_class = G_OBJECT_CLASS (klass); - object_class->dispose = session_menu_mgr_dispose; -} - -/*** -**** UPower Proxy: -**** -**** 1. While bootstrapping, we invoke the AllowSuspend and AllowHibernate -**** methods to find out whether or not those features are allowed. -**** 2. While bootstrapping, we get the CanSuspend and CanHibernate properties -**** and also listen for property changes. -**** 3. These four values are used to set suspend and hibernate's visibility. -**** -***/ - -static void -on_upower_properties_changed (SessionMenuMgr * mgr) -{ - gboolean need_refresh = FALSE; - - if (mgr->upower_proxy != NULL) - { - gboolean b; - - /* suspend */ - b = dbus_upower_get_can_suspend (mgr->upower_proxy); - if (mgr->can_suspend != b) - { - mgr->can_suspend = b; - need_refresh = TRUE; - } - - /* hibernate */ - b = dbus_upower_get_can_hibernate (mgr->upower_proxy); - if (mgr->can_hibernate != b) - { - mgr->can_hibernate = b; - need_refresh = TRUE; - } - } - - if (need_refresh) - { - update_session_menuitems (mgr); - } -} - -static void -init_upower_proxy (SessionMenuMgr * mgr) -{ - /* default values */ - mgr->can_suspend = TRUE; - mgr->can_hibernate = TRUE; - mgr->allow_suspend = TRUE; - mgr->allow_hibernate = TRUE; - - mgr->cancellable = g_cancellable_new (); - - GError * error = NULL; - mgr->upower_proxy = dbus_upower_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - UPOWER_ADDRESS, - UPOWER_PATH, - NULL, - &error); - if (error != NULL) - { - g_warning ("Error creating upower proxy: %s", error->message); - g_clear_error (&error); - } - else - { - dbus_upower_call_suspend_allowed_sync (mgr->upower_proxy, - &mgr->allow_suspend, - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } - - dbus_upower_call_hibernate_allowed_sync (mgr->upower_proxy, - &mgr->allow_hibernate, - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } - - g_signal_connect_swapped (mgr->upower_proxy, "changed", - G_CALLBACK(on_upower_properties_changed), mgr); - } -} - -/*** -**** Menuitem Helpers -***/ - -static inline void -mi_set_label (DbusmenuMenuitem * mi, const char * str) -{ - dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_LABEL, str); -} - -static inline void -mi_set_type (DbusmenuMenuitem * mi, const char * str) -{ - dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_TYPE, str); -} - -static inline void -mi_set_visible (DbusmenuMenuitem * mi, gboolean b) -{ - dbusmenu_menuitem_property_set_bool (mi, DBUSMENU_MENUITEM_PROP_VISIBLE, - b || DEBUG_SHOW_ALL); -} - -static inline void -mi_set_logged_in (DbusmenuMenuitem * mi, gboolean b) -{ - dbusmenu_menuitem_property_set_bool (mi, USER_ITEM_PROP_LOGGED_IN, b); -} - -static DbusmenuMenuitem* -mi_new_separator (void) -{ - DbusmenuMenuitem * mi = dbusmenu_menuitem_new (); - mi_set_type (mi, DBUSMENU_CLIENT_TYPES_SEPARATOR); - return mi; -} - -static DbusmenuMenuitem* -mi_new (const char * label) -{ - DbusmenuMenuitem * mi = dbusmenu_menuitem_new (); - mi_set_label (mi, label); - return mi; -} - -static void -check_online_accounts_status (SessionMenuMgr * mgr, DbusmenuMenuitem * mi) -{ - const gchar *disposition; - gboolean on_alert; - - disposition = - dbusmenu_menuitem_property_get (mi, DBUSMENU_MENUITEM_PROP_DISPOSITION); - on_alert = g_strcmp0 (disposition, DBUSMENU_MENUITEM_DISPOSITION_ALERT) == 0; - - mi_set_visible (mi, on_alert); -} - -static void -on_online_accounts_changed (SessionMenuMgr * mgr, const gchar * property, - GVariant *value, DbusmenuMenuitem *mi) -{ - if (g_strcmp0 (property, DBUSMENU_MENUITEM_PROP_DISPOSITION) == 0) - { - check_online_accounts_status(mgr, mi); - } -} - -/*** -**** Admin Menuitems -**** -***/ - -static void -build_admin_menuitems (SessionMenuMgr * mgr) -{ - if (!mgr->greeter_mode) - { - DbusmenuMenuitem * mi; - const gboolean show_settings = !mgr->greeter_mode; - - mi = mi_new (_("About This Computer")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), CMD_INFO); - - mi = mi_new (_("Ubuntu Help")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), CMD_HELP); - - mi = mi_new_separator (); - mi_set_visible (mi, show_settings); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - - mi = mi_new (_("System Settings\342\200\246")); - mi_set_visible (mi, show_settings); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), - CMD_SYSTEM_SETTINGS); - - mi = mgr->online_accounts_mi = - online_accounts_mgr_get_menu_item (mgr->online_accounts_mgr); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, - G_CALLBACK(on_online_accounts_changed), - mgr); - check_online_accounts_status (mgr, mi); - - mi = mi_new_separator (); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - } -} - -/*** -**** Session Menuitems -**** -***/ - -static void -update_session_menuitems (SessionMenuMgr * mgr) -{ - gboolean v; - GSettings * s = mgr->indicator_settings; - - v = !mgr->greeter_mode - && !is_this_live_session() - && !g_settings_get_boolean (mgr->lockdown_settings, "disable-log-out") - && !g_settings_get_boolean (s, "suppress-logout-menuitem"); - mi_set_visible (mgr->logout_mi, v); - - v = mgr->can_suspend - && mgr->allow_suspend; - mi_set_visible (mgr->suspend_mi, v); - - v = mgr->can_hibernate - && mgr->allow_hibernate; - mi_set_visible (mgr->hibernate_mi, v); - - v = HAVE_RESTART_CMD - && !g_settings_get_boolean (s, "suppress-restart-menuitem"); - mi_set_visible (mgr->restart_mi, v); - - v = !g_settings_get_boolean (s, "suppress-shutdown-menuitem"); - mi_set_visible (mgr->shutdown_mi, v); -} - -/* Update the ellipses when the confirmation setting changes. - * - * : - * "Label the menu item with a trailing ellipsis ("...") only if the - * command requires further input from the user before it can be performed." - */ -static void -update_confirmation_labels (SessionMenuMgr * mgr) -{ - const gboolean confirm_needed = !g_settings_get_boolean ( - mgr->indicator_settings, - "suppress-logout-restart-shutdown"); - - mi_set_label (mgr->logout_mi, confirm_needed ? _("Log Out\342\200\246") - : _("Log Out")); - - mi_set_label (mgr->shutdown_mi, confirm_needed ? _("Shut Down\342\200\246") - : _("Shut Down")); - - mi_set_label (mgr->restart_mi, confirm_needed ? _("Restart\342\200\246") - : _("Restart")); -} - -static void -build_session_menuitems (SessionMenuMgr* mgr) -{ - DbusmenuMenuitem * mi; - - mi = mgr->logout_mi = mi_new (_("Log Out\342\200\246")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), CMD_LOGOUT); - - mi = mgr->suspend_mi = mi_new (_("Suspend")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_suspend), mgr); - - mi = mgr->hibernate_mi = mi_new (_("Hibernate")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_hibernate), mgr); - - mi = mgr->restart_mi = mi_new (_("Restart\342\200\246")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), CMD_RESTART); - - mi = mgr->shutdown_mi = mi_new (_("Shut Down\342\200\246")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), CMD_SHUTDOWN); - - update_confirmation_labels (mgr); - update_session_menuitems (mgr); -} - -/**** -***** User Menuitems -***** https://wiki.ubuntu.com/SystemMenu#Account-switching_items -****/ - -/* Local extensions to AccountsUser */ - -static GQuark -get_menuitem_quark (void) -{ - static GQuark q = 0; - - if (G_UNLIKELY(!q)) - { - q = g_quark_from_static_string ("menuitem"); - } - - return q; -} - -static DbusmenuMenuitem* -user_get_menuitem (AccountsUser * user) -{ - return g_object_get_qdata (G_OBJECT(user), get_menuitem_quark()); -} - -static void -user_clear_menuitem (AccountsUser * user) -{ - g_object_steal_qdata (G_OBJECT(user), get_menuitem_quark()); -} - -static void -user_set_menuitem (AccountsUser * user, DbusmenuMenuitem * mi) -{ - g_object_set_qdata (G_OBJECT(user), get_menuitem_quark(), mi); - - g_object_weak_ref (G_OBJECT(mi), (GWeakNotify)user_clear_menuitem, user); -} - -/***/ - -static GQuark -get_mgr_quark (void) -{ - static GQuark q = 0; - - if (G_UNLIKELY(!q)) - { - q = g_quark_from_static_string ("session-menu-mgr"); - } - - return q; -} - -static SessionMenuMgr* -user_get_mgr (AccountsUser * user) -{ - return g_object_get_qdata (G_OBJECT(user), get_mgr_quark()); -} - -static void -user_set_mgr (AccountsUser * user, SessionMenuMgr * mgr) -{ - g_object_set_qdata (G_OBJECT(user), get_mgr_quark(), mgr); -} - -/***/ - -static GQuark -get_collision_quark (void) -{ - static GQuark q = 0; - - if (G_UNLIKELY(!q)) - { - q = g_quark_from_static_string ("name-collision"); - } - - return q; -} - -static gboolean -user_has_name_collision (AccountsUser * u) -{ - return g_object_get_qdata (G_OBJECT(u), get_collision_quark()) != NULL; -} - -static void -user_set_name_collision (AccountsUser * u, gboolean b) -{ - g_object_set_qdata (G_OBJECT(u), get_collision_quark(), GINT_TO_POINTER(b)); -} - -/*** -**** -***/ - -static void -on_guest_logged_in_changed (UsersServiceDbus * usd, - SessionMenuMgr * mgr) -{ - if (mgr->guest_mi != NULL) - { - mi_set_logged_in (mgr->guest_mi, - users_service_dbus_is_guest_logged_in (usd)); - } -} - -/* When a user's login state changes, - update the corresponding menuitem's LOGGED_IN property */ -static void -on_user_logged_in_changed (UsersServiceDbus * usd, - AccountsUser * user, - SessionMenuMgr * mgr) -{ - DbusmenuMenuitem * mi = user_get_menuitem (user); - - if (mi != NULL) - { - mi_set_logged_in (mi, users_service_dbus_is_user_logged_in (usd, user)); - } -} - -static void -update_screensaver_shortcut (SessionMenuMgr * mgr) -{ - gchar * s = g_settings_get_string (mgr->keybinding_settings, "screensaver"); - g_debug ("%s Screensaver shortcut changed to: '%s'", G_STRLOC, s); - - if (mgr->lock_mi != NULL) - { - dbusmenu_menuitem_property_set_shortcut_string (mgr->lock_mi, s); - } - - if (mgr->lock_switch_mi != NULL) - { - dbusmenu_menuitem_property_set_shortcut_string (mgr->lock_switch_mi, s); - } - - if (mgr->screensaver_mi != NULL) - { - dbusmenu_menuitem_property_set_shortcut_string (mgr->screensaver_mi, s); - } - - g_free (s); -} - -static void -update_user_menuitem_icon (DbusmenuMenuitem * mi, AccountsUser * user) -{ - const gchar * str = accounts_user_get_icon_file (user); - - if (!str || !*str) - { - str = USER_ITEM_ICON_DEFAULT; - } - - dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_ICON, str); -} - -static void -update_user_menuitem_name (DbusmenuMenuitem * mi, AccountsUser * user) -{ - GString * gstr = g_string_new (accounts_user_get_real_name (user)); - - if (user_has_name_collision (user)) - g_string_append_printf (gstr, " (%s)", accounts_user_get_user_name(user)); - - if (!gstr->len) - g_string_assign (gstr, accounts_user_get_user_name(user)); - - dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_NAME, gstr->str); - g_string_free (gstr, TRUE); -} - -static void -on_user_property_changed (AccountsUser * user, - GParamSpec * pspec, - DbusmenuMenuitem * mi) -{ - static const char * interned_icon_file = NULL; - static const char * interned_real_name = NULL; - static const char * interned_user_name = NULL; - - if (G_UNLIKELY (interned_icon_file == NULL)) - { - interned_icon_file = g_intern_static_string ("icon-file"); - interned_user_name = g_intern_static_string ("user-name"); - interned_real_name = g_intern_static_string ("real-name"); - } - - if (pspec->name == interned_icon_file) - { - update_user_menuitem_icon (mi, user); - } - else if ((pspec->name == interned_real_name) - || (pspec->name == interned_user_name)) - { - /* name changing can affect other menuitems too by invalidating - the sort order or name collision flags... so let's rebuild */ - update_user_menuitems (user_get_mgr (user)); - } -} - -typedef struct -{ - gpointer instance; - gulong handler_id; -} -SignalHandlerData; - -/* when a user menuitem is destroyed, - it should stop listening for its UserAccount's property changes */ -static void -on_user_menuitem_destroyed (SignalHandlerData * data) -{ - g_signal_handler_disconnect (data->instance, data->handler_id); - g_free (data); -} - -static DbusmenuMenuitem* -user_menuitem_new (AccountsUser * user, SessionMenuMgr * mgr) -{ - DbusmenuMenuitem * mi = dbusmenu_menuitem_new (); - mi_set_type (mi, USER_ITEM_TYPE); - - /* set the name & icon and listen for property changes */ - update_user_menuitem_name (mi, user); - update_user_menuitem_icon (mi, user); - SignalHandlerData * hd = g_new0 (SignalHandlerData, 1); - hd->instance = user; - hd->handler_id = g_signal_connect (user, "notify", - G_CALLBACK(on_user_property_changed), mi); - g_object_weak_ref (G_OBJECT(mi), (GWeakNotify)on_user_menuitem_destroyed, hd); - - /* set the logged-in property */ - mi_set_logged_in (mi, - users_service_dbus_is_user_logged_in (mgr->users_dbus_facade, user)); - - /* set the is-current-user property */ - const gboolean is_current_user = - !g_strcmp0 (g_get_user_name(), accounts_user_get_user_name(user)); - - dbusmenu_menuitem_property_set_bool (mi, - USER_ITEM_PROP_IS_CURRENT_USER, - is_current_user); - - /* set the switch-to-user action */ - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_switch_to_user), user); - - /* give this AccountsUser a hook back to this menuitem */ - user_set_menuitem (user, mi); - user_set_mgr (user, mgr); - - return mi; -} - -/* for sorting AccountsUsers from most to least frequently used */ -static gint -compare_users_by_login_frequency (gconstpointer a, gconstpointer b) -{ - const guint64 a_freq = accounts_user_get_login_frequency (ACCOUNTS_USER(a)); - const guint64 b_freq = accounts_user_get_login_frequency (ACCOUNTS_USER(b)); - if (a_freq > b_freq) return -1; - if (a_freq < b_freq) return 1; - return 0; -} - -/* for sorting AccountsUsers alphabetically */ -static gint -compare_users_by_username (gconstpointer ga, gconstpointer gb) -{ - AccountsUser * a = ACCOUNTS_USER(ga); - AccountsUser * b = ACCOUNTS_USER(gb); - - const int ret = g_strcmp0 (accounts_user_get_real_name (a), - accounts_user_get_real_name (b)); - - if (!ret) /* names are the same, so both have a name collision */ - { - user_set_name_collision (a, TRUE); - user_set_name_collision (b, TRUE); - } - - return ret; -} - -static gboolean -is_user_switching_allowed (SessionMenuMgr * mgr) -{ - /* maybe it's locked down */ - if (g_settings_get_boolean (mgr->lockdown_settings, "disable-user-switching")) - { - return FALSE; - } - - /* maybe the seat doesn't support activation */ - if (!users_service_dbus_can_activate_session (mgr->users_dbus_facade)) - { - return FALSE; - } - - return TRUE; -} - -static void -build_user_menuitems (SessionMenuMgr * mgr) -{ - g_return_if_fail (!mgr->greeter_mode); - - DbusmenuMenuitem * mi; - GSList * items = NULL; - gint pos = mgr->user_menuitem_index; - const char * current_real_name = NULL; - - /** - *** Start Screen Saver - *** Switch Account... - *** Lock - *** Lock / Switch Account... - **/ - - const SwitcherMode mode = get_switcher_mode (mgr); - - mi = mgr->screensaver_mi = mi_new (_("Start Screen Saver")); - mi_set_visible (mi, mode == SWITCHER_MODE_SCREENSAVER); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_lock), mgr); - - mi = mi_new (_("Switch User Account\342\200\246")); - mi_set_visible (mi, mode == SWITCHER_MODE_SWITCH); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_switch_to_greeter), mgr); - - mi = mgr->lock_mi = mi_new (_("Lock")); - mi_set_visible (mi, mode == SWITCHER_MODE_LOCK); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_switch_to_lockscreen), mgr); - - mi = mgr->lock_switch_mi = mi_new (_("Lock/Switch Account\342\200\246")); - mi_set_visible (mi, mode == SWITCHER_MODE_SWITCH_OR_LOCK); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_switch_to_lockscreen), mgr); - - const gboolean is_guest = is_this_guest_session (); - const gboolean guest_allowed = - users_service_dbus_guest_session_enabled (mgr->users_dbus_facade); - mi = mgr->guest_mi = dbusmenu_menuitem_new (); - mi_set_type (mi, USER_ITEM_TYPE); - mi_set_visible (mi, !is_guest && guest_allowed); - dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_NAME, _("Guest Session")); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - on_guest_logged_in_changed (mgr->users_dbus_facade, mgr); - items = g_slist_prepend (items, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_switch_to_guest), mgr); - - if (guest_allowed && is_guest) - { - current_real_name = _("Guest"); - } - - /*** - **** Users - ***/ - - /* if we can switch to another user account, show them here */ - const char * const username = g_get_user_name(); - GList * users = users_service_dbus_get_user_list (mgr->users_dbus_facade); - - /* since we're building (or rebuilding) from scratch, - clear the name collision flags */ - GList * u; - for (u=users; u!=NULL; u=u->next) - { - AccountsUser * user = ACCOUNTS_USER(u->data); - - user_set_name_collision (user, FALSE); - - if (!g_strcmp0 (username, accounts_user_get_user_name(user))) - { - current_real_name = accounts_user_get_real_name (user); - } - } - - if (is_user_switching_allowed (mgr)) - { - /* pick the most frequently used accounts */ - const int MAX_USERS = 12; /* this limit comes from the spec */ - if (g_list_length(users) > MAX_USERS) - { - users = g_list_sort (users, compare_users_by_login_frequency); - GList * last = g_list_nth (users, MAX_USERS-1); - GList * remainder = last->next; - last->next = NULL; - remainder->prev = NULL; - g_list_free (remainder); - } - - /* Sort the users by name for display */ - users = g_list_sort (users, compare_users_by_username); - - /* Create menuitems for them */ - int i; - for (i=0, u=users; inext, i++) - { - AccountsUser * user = u->data; - DbusmenuMenuitem * mi = user_menuitem_new (user, mgr); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - } - } - - g_list_free (users); - - /* separator */ - if (mode != SWITCHER_MODE_SCREENSAVER && !is_guest && guest_allowed) - { - mi = mi_new_separator (); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - } - - if (current_real_name != NULL) - { - session_dbus_set_users_real_name (mgr->session_dbus, - current_real_name); - } - - update_screensaver_shortcut (mgr); - mgr->user_menuitems = items; -} - -static void -update_user_menuitems (SessionMenuMgr * mgr) -{ - /* remove any previous user menuitems */ - GSList * l; - for (l=mgr->user_menuitems; l!=NULL; l=l->next) - { - dbusmenu_menuitem_child_delete (mgr->top_mi, l->data); - } - g_slist_free (mgr->user_menuitems); - mgr->user_menuitems = NULL; - - /* add fresh user menuitems */ - if (!mgr->greeter_mode) - { - build_user_menuitems (mgr); - } -} - -/*** -**** Actions! -***/ - -static void -action_func_spawn_async (const char * cmd) -{ - GError * error = NULL; - - g_debug ("%s calling \"%s\"", G_STRFUNC, cmd); - g_spawn_command_line_async (cmd, &error); - - if (error != NULL) - { - g_warning ("Unable to execute \"%s\": %s", cmd, error->message); - g_clear_error (&error); - } -} - -/* Calling "Lock" locks the screen & goes to black. - Calling "SimulateUserActivity" afterwards shows the Lock Screen. */ -static void -lock_helper (SessionMenuMgr * mgr, gboolean show_lock_screen) -{ - if (!g_settings_get_boolean (mgr->lockdown_settings, "disable-lock-screen")) - { - GError * error = NULL; - GDBusProxy * proxy = g_dbus_proxy_new_for_bus_sync ( - G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - "org.gnome.ScreenSaver", - "/org/gnome/ScreenSaver", - "org.gnome.ScreenSaver", - NULL, - &error); - - if (error == NULL) - { - g_dbus_proxy_call_sync (proxy, "Lock", - NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &error); - } - - if ((error == NULL) && show_lock_screen) - { - g_dbus_proxy_call_sync (proxy, "SimulateUserActivity", - NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &error); - } - - if (error != NULL) - { - g_warning ("Error locking screen: %s", error->message); - } - - g_clear_object (&proxy); - g_clear_error (&error); - } -} - -static void -action_func_lock (SessionMenuMgr * mgr) -{ - lock_helper (mgr, FALSE); -} - -static void -action_func_switch_to_lockscreen (SessionMenuMgr * mgr) -{ - lock_helper (mgr, TRUE); -} - -static void -action_func_switch_to_greeter (SessionMenuMgr * mgr) -{ - action_func_lock (mgr); - users_service_dbus_show_greeter (mgr->users_dbus_facade); -} - -static void -action_func_switch_to_user (AccountsUser * user) -{ - SessionMenuMgr * mgr = user_get_mgr (user); - - g_return_if_fail (mgr != NULL); - - if (g_strcmp0 (g_get_user_name(), accounts_user_get_user_name(user)) != 0) - { - action_func_lock (mgr); - users_service_dbus_activate_user_session (mgr->users_dbus_facade, user); - } -} - -static void -action_func_switch_to_guest (SessionMenuMgr * mgr) -{ - action_func_lock (mgr); - users_service_dbus_activate_guest_session (mgr->users_dbus_facade); -} - -static void -action_func_suspend (SessionMenuMgr * mgr) -{ - GError * error = NULL; - - dbus_upower_call_suspend_sync (mgr->upower_proxy, - mgr->cancellable, - &error); - - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } -} - -static void -action_func_hibernate (SessionMenuMgr * mgr) -{ - GError * error = NULL; - - dbus_upower_call_hibernate_sync (mgr->upower_proxy, - mgr->cancellable, - &error); - - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } -} - -/*** -**** -***/ - -static gboolean -is_this_guest_session (void) -{ - /* FIXME: this test has been here awhile and seems to work, - but seems brittle to me */ - return geteuid() < 500; -} - -static gboolean -is_this_live_session (void) -{ - const struct passwd * const pw = getpwuid (geteuid()); - return (pw->pw_uid==999) && !g_strcmp0("ubuntu",pw->pw_name); -} - -static SwitcherMode -get_switcher_mode (SessionMenuMgr * mgr) -{ - SwitcherMode mode; - - const gboolean can_lock = !g_settings_get_boolean (mgr->lockdown_settings, - "disable-lock-screen"); - const gboolean can_switch = is_user_switching_allowed (mgr); - - if (!can_lock && !can_switch) /* hmm, quite an extreme lockdown */ - { - mode = SWITCHER_MODE_NONE; - } - else if (is_this_live_session()) /* live sessions can't lock or switch */ - { - mode = SWITCHER_MODE_SCREENSAVER; - } - else if (!can_switch) /* switching's locked down */ - { - mode = SWITCHER_MODE_LOCK; - } - else if (is_this_guest_session ()) /* guest sessions can't lock */ - { - mode = SWITCHER_MODE_SWITCH; - } - else /* both locking & switching are allowed */ - { - GList * l = users_service_dbus_get_user_list (mgr->users_dbus_facade); - const size_t user_count = g_list_length (l); - g_list_free (l); - - /* only show switch mode if we have users to switch to */ - mode = user_count > (is_this_guest_session() ? 0 : 1) - ? SWITCHER_MODE_SWITCH_OR_LOCK - : SWITCHER_MODE_LOCK; - } - - return mode; -} - - -/*** -**** -***/ - -SessionMenuMgr* -session_menu_mgr_new (SessionDbus * session_dbus, - gboolean greeter_mode) -{ - SessionMenuMgr* mgr = g_object_new (SESSION_TYPE_MENU_MGR, NULL); - mgr->greeter_mode = greeter_mode; - mgr->session_dbus = g_object_ref (session_dbus); - build_admin_menuitems (mgr); - const guint n = g_list_length (dbusmenu_menuitem_get_children (mgr->top_mi)); - mgr->user_menuitem_index = n; - update_user_menuitems (mgr); - build_session_menuitems (mgr); - - /* After we have the session menu items built we can look to - align them with UPower */ - on_upower_properties_changed (mgr); - - return mgr; -} - -/** - * session_menu_mgr_get_menu: - * - * Returns: (transfer none): the manager's menu. - */ -DbusmenuMenuitem * -session_menu_mgr_get_menu (SessionMenuMgr * mgr) -{ - g_return_val_if_fail (IS_SESSION_MENU_MGR(mgr), NULL); - - return mgr->top_mi; -} diff --git a/src/session-menu-mgr.h b/src/session-menu-mgr.h deleted file mode 100644 index 5a173e1..0000000 --- a/src/session-menu-mgr.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - - -#ifndef _SESSION_MENU_MGR_H_ -#define _SESSION_MENU_MGR_H_ - -#include - -#include "session-dbus.h" - -G_BEGIN_DECLS - -#define SESSION_TYPE_MENU_MGR (session_menu_mgr_get_type ()) -#define SESSION_MENU_MGR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SESSION_TYPE_MENU_MGR, SessionMenuMgr)) -#define SESSION_MENU_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SESSION_TYPE_MENU_MGR, SessionMenuMgrClass)) -#define IS_SESSION_MENU_MGR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SESSION_TYPE_MENU_MGR)) -#define IS_SESSION_MENU_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SESSION_TYPE_MENU_MGR)) -#define SESSION_MENU_MGR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SESSION_TYPE_MENU_MGR, SessionMenuMgrClass)) - -typedef struct _SessionMenuMgrClass SessionMenuMgrClass; -typedef struct _SessionMenuMgr SessionMenuMgr; - -struct _SessionMenuMgrClass -{ - GObjectClass parent_class; -}; - -GType session_menu_mgr_get_type (void) G_GNUC_CONST; - -SessionMenuMgr* session_menu_mgr_new (SessionDbus * session_dbus, - gboolean greeter_mode); - -DbusmenuMenuitem* session_menu_mgr_get_menu (SessionMenuMgr * mgr); - - -G_END_DECLS - -#endif /* _SESSION_MENU_MGR_H_ */ diff --git a/src/session-service.c b/src/session-service.c deleted file mode 100644 index 13438d3..0000000 --- a/src/session-service.c +++ /dev/null @@ -1,96 +0,0 @@ -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using it's applet interface. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - Christoph Korn - Cody Russell - Conor Curran - Charles Kerr - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#include "config.h" - -#include -#include - -#include -#include -#include - -#include - -#include - -#include - -#include "session-dbus.h" -#include "session-menu-mgr.h" -#include "shared-names.h" -#include "users-service-dbus.h" - -static SessionDbus * session_dbus = NULL; -static GMainLoop * mainloop = NULL; - - -/* When the service interface starts to shutdown, - we should follow it. */ -void -service_shutdown (IndicatorService * service, gpointer user_data) -{ - if (mainloop != NULL) - { - g_debug ("Service shutdown"); - g_main_loop_quit (mainloop); - } -} - -static inline gboolean -is_greeter_mode (void) -{ - return !g_strcmp0 (g_getenv ("INDICATOR_GREETER_MODE"), "1"); -} - -/* Main, is well, main. It brings everything up and throws - us into the mainloop of no return. */ -int -main (int argc, char ** argv) -{ - /* Setting up i18n and gettext. - Apparently we need all of these. */ - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); - textdomain (GETTEXT_PACKAGE); - - IndicatorService * service = indicator_service_new_version (INDICATOR_SESSION_DBUS_NAME, - INDICATOR_SESSION_DBUS_VERSION); - g_signal_connect (G_OBJECT(service), INDICATOR_SERVICE_SIGNAL_SHUTDOWN, - G_CALLBACK(service_shutdown), NULL); - - session_dbus = session_dbus_new(); - - SessionMenuMgr * menu_mgr = session_menu_mgr_new (session_dbus, is_greeter_mode()); - DbusmenuServer* server = dbusmenu_server_new (INDICATOR_SESSION_DBUS_OBJECT); - dbusmenu_server_set_root (server, session_menu_mgr_get_menu (menu_mgr)); - - mainloop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(mainloop); - - return 0; -} - diff --git a/src/shared-names.h b/src/shared-names.h deleted file mode 100644 index c08f98a..0000000 --- a/src/shared-names.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using it's applet interface. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifndef __DBUS_SHARED_NAMES_H__ -#define __DBUS_SHARED_NAMES_H__ - -#define INDICATOR_SESSION_DBUS_NAME "com.canonical.indicator.session" -#define INDICATOR_SESSION_DBUS_OBJECT "/com/canonical/indicator/session/menu" -#define INDICATOR_SESSION_DBUS_VERSION 0 - -#define INDICATOR_SESSION_SERVICE_DBUS_OBJECT "/com/canonical/indicator/session/service" -#define INDICATOR_SESSION_SERVICE_DBUS_IFACE "com.canonical.indicator.session.service" -#define USER_ITEM_TYPE "x-canonical-user-item" -#define USER_ITEM_PROP_NAME "user-item-name" -#define USER_ITEM_PROP_LOGGED_IN "user-item-logged-in" -#define USER_ITEM_PROP_IS_CURRENT_USER "user-item-is-current-user" -#define USER_ITEM_PROP_ICON "user-item-icon-path" -#define USER_ITEM_ICON_DEFAULT "avatar-default" - -#define ICON_DEFAULT "system-devices-panel" -#define ICON_INFO "system-devices-panel-information" -#define ICON_ALERT "system-devices-panel-alert" - -/* the session indicator's settings */ -#define SESSION_SCHEMA "com.canonical.indicator.session" -#define SUPPRESS_KEY "suppress-logout-restart-shutdown" -#define LOGOUT_KEY "suppress-logout-menuitem" -#define RESTART_KEY "suppress-restart-menuitem" -#define SHUTDOWN_KEY "suppress-shutdown-menuitem" -#define SHOW_USER_MENU "user-show-menu" - - -#endif /* __DBUS_SHARED_NAMES_H__ */ diff --git a/src/upower.xml b/src/upower.xml deleted file mode 100644 index 18d5fbd..0000000 --- a/src/upower.xml +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - The DeviceKit-power service is available via the system message - bus. To access the service, use - the org.freedesktop.UPower interface on - the /org/freedesktop/UPower object on - the D-Bus system bus service with the well-known - name org.freedesktop.UPower. - - - - -$ dbus-send --print-reply \ - --system \ - --dest=org.freedesktop.UPower \ - /org/freedesktop/UPower \ - org.freedesktop.UPower.EnumerateDevices - -method return sender=:1.386 -> dest=:1.451 reply_serial=2 - array [ - object path "/org/freedesktop/UPower/devices/line_power_AC" - object path "/org/freedesktop/UPower/devices/battery_BAT0" - ] - - - - - - - - - - - - An array of object paths for devices. - - - - - - Enumerate all power objects on the system. - - - - - - - - - - Object path of device that was added. - - - - - - Emitted when a device is added. - - - - - - - - - - Object path of device that was removed. - - - - - - Emitted when a device is removed. - - - - - - - - - - Object path of device that was changed. - - - - - - Emitted when a device changed. - - - - - - - - - - - - Emitted when one or more properties on the object changes. - - - - - - - - - - - - This signal is sent when the session is about to be suspended or - hibernated. - Session and system programs have one second to do anything required - before the sleep action is taken (such as sending out Avahi or - Jabber messages). - - - - - - - - - - - - This signal is sent when the session has just returned from - Suspend() or Hibernate(). - Session and system programs can then do anything required (such as - sending out Avahi or Jabber messages). - - - - - - - - - - - - - This method tells UPower that the Suspend() or Hibernate() method - is about to be called. - This allows UPower to emit the Suspending signal whilst - session activities are happening that have to be done before the - suspend process is started. - - - This method would typically be called by the session power - management daemon, before it locks the screen and waits for the - screen to fade to black. - The session power management component would then call Suspend() or - Hibernate() when these syncronous tasks have completed. - - - If this method is not called than nothing bad will happen and - Suspend() or Hibernate() will block for the required second. - - - - - - - - - - - - - Suspends the computer into a low power state. - System state is not preserved if the power is lost. - - - If AboutToRequestSleep() has not been called then UPower will send - the Sleeping() signal and block for one second. - - - If AboutToRequestSleep() has been called less than one second - before this method is called then UPower will block for the - remaining time to complete one second of delay. - - - - - - - - - - - TRUE if allowed, otherwise FALSE - - - - - Check if the caller has (or can get) the PolicyKit privilege to call - Suspend. - - - - - - - - - - - - - Hibernates the computer into a low power state. - System state is preserved if the power is lost. - - - If AboutToRequestSleep() has not been called then UPower will send - the Sleeping() signal and block for one second. - - - If AboutToRequestSleep() has been called less than one second - before this method is called then UPower will block for the - remaining time to complete one second of delay. - - - - - - - - - - - TRUE if allowed, otherwise FALSE - - - - - Check if the caller has (or can get) the PolicyKit privilege to call - Hibernate. - - - - - - - - - - Version of the running daemon, e.g. 002. - - - - - - Whether the system is able to suspend. - - - - - - Whether the system is able to hibernate. - - - - - - Indicates whether the system is running on battery power. - This property is provided for convenience. - - - - - - Indicates whether the system is running on battery power and if the battery is critically low. - This property is provided for convenience. - - - - - - - - Indicates if the laptop lid is closed where the display cannot be seen. - - - - - - - - - - If the system has a lid device. - - - - - - - - diff --git a/src/user-widget.c b/src/user-widget.c deleted file mode 100644 index 79b87b0..0000000 --- a/src/user-widget.c +++ /dev/null @@ -1,292 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran - Mirco Müller - Charles Kerr - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#include - -#include - -#include "shared-names.h" -#include "user-widget.h" - - -typedef struct _UserWidgetPrivate UserWidgetPrivate; - -struct _UserWidgetPrivate -{ - DbusmenuMenuitem* twin_item; - GtkWidget* user_image; - GtkWidget* user_name; - GtkWidget* container; - GtkWidget* tick_icon; - gboolean logged_in; - gboolean sessions_active; -}; - -#define USER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USER_WIDGET_TYPE, UserWidgetPrivate)) - -/* Prototypes */ -static void user_widget_class_init (UserWidgetClass *klass); -static void user_widget_init (UserWidget *self); -static void user_widget_dispose (GObject *object); -static void user_widget_finalize (GObject *object); - -static void user_widget_set_twin_item (UserWidget* self, - DbusmenuMenuitem* twin_item); - -static gboolean user_widget_primitive_draw_cb_gtk_3 (GtkWidget *image, - cairo_t* cr, - gpointer user_data); - -G_DEFINE_TYPE (UserWidget, user_widget, GTK_TYPE_MENU_ITEM); - -static void -user_widget_class_init (UserWidgetClass *klass) -{ - GObjectClass * gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (UserWidgetPrivate)); - - gobject_class->dispose = user_widget_dispose; - gobject_class->finalize = user_widget_finalize; -} - -static void -user_widget_init (UserWidget *self) -{ - self->priv = USER_WIDGET_GET_PRIVATE(self); - - UserWidgetPrivate * priv = self->priv; - - priv->user_image = NULL; - priv->user_name = NULL; - priv->logged_in = FALSE; - priv->sessions_active = FALSE; - priv->container = NULL; - priv->tick_icon = NULL; - - // Create the UI elements. - priv->user_image = gtk_image_new (); - gtk_misc_set_alignment(GTK_MISC(priv->user_image), 0.0, 0.0); - - priv->user_name = gtk_label_new (NULL); - - priv->container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); - - priv->tick_icon = gtk_image_new_from_icon_name ("account-logged-in", - GTK_ICON_SIZE_MENU); - gtk_misc_set_alignment(GTK_MISC(priv->tick_icon), 1.0, 0.5); - - // Pack it together - gtk_box_pack_start (GTK_BOX (priv->container), - priv->user_image, - FALSE, - FALSE, - 0); - gtk_box_pack_start (GTK_BOX (priv->container), - priv->user_name, - FALSE, - FALSE, - 3); - gtk_box_pack_end (GTK_BOX(priv->container), - priv->tick_icon, - FALSE, - FALSE, 5); - - gtk_widget_show_all (priv->container); - gtk_container_add (GTK_CONTAINER (self), priv->container); - gtk_widget_show_all (priv->tick_icon); - gtk_widget_set_no_show_all (priv->tick_icon, TRUE); - gtk_widget_hide (priv->tick_icon); - - - // Fetch the drawing context. - g_signal_connect_after (GTK_WIDGET(self), "draw", - G_CALLBACK(user_widget_primitive_draw_cb_gtk_3), - GTK_WIDGET(self)); -} - -static void -user_widget_dispose (GObject *object) -{ - G_OBJECT_CLASS (user_widget_parent_class)->dispose (object); -} - -// TODO tidy up image and name -static void -user_widget_finalize (GObject *object) -{ - G_OBJECT_CLASS (user_widget_parent_class)->finalize (object); -} - - -/*****************************************************************/ - -// TODO handle drawing of green check mark -static gboolean -user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, - cairo_t* cr, - gpointer user_data) -{ - g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE); - UserWidget* meta = USER_WIDGET(user_data); - UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta); - - // Draw dot only when user is the current user. - if (dbusmenu_menuitem_property_get_bool (priv->twin_item, USER_ITEM_PROP_IS_CURRENT_USER)) - { - gdouble x, y; - GtkStyle * style = gtk_widget_get_style (widget); - - GtkAllocation allocation; - gtk_widget_get_allocation (widget, &allocation); - x = allocation.x + 13; - y = allocation.height / 2; - - cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI); - - cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, - style->fg[gtk_widget_get_state(widget)].green/65535.0, - style->fg[gtk_widget_get_state(widget)].blue/65535.0); - cairo_fill (cr); - } - - return FALSE; -} - -/*** -**** -***/ - -static void -update_icon (UserWidget * self, DbusmenuMenuitem * mi) -{ - gboolean updated = FALSE; - GtkImage * image = GTK_IMAGE(self->priv->user_image); - - /* first try the menuitem's icon property */ - const gchar * icon_name = dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_ICON); - if (icon_name != NULL) - { - int width = 18; /* arbitrary default values */ - int height = 18; - GError * err = NULL; - GdkPixbuf * pixbuf = NULL; - - /* load the image */ - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); - pixbuf = gdk_pixbuf_new_from_file_at_size (icon_name, width, height, &err); - if (err == NULL) - { - gtk_image_set_from_pixbuf (image, pixbuf); - g_object_unref (pixbuf); - updated = TRUE; - } - else - { - g_warning ("Couldn't load the image \"%s\": %s", icon_name, err->message); - g_clear_error (&err); - } - } - - /* as a fallback, use the default user icon */ - if (!updated) - { - gtk_image_set_from_icon_name (image, - USER_ITEM_ICON_DEFAULT, - GTK_ICON_SIZE_MENU); - } -} - -static void -update_logged_in (UserWidget * self, DbusmenuMenuitem * mi) -{ - const gboolean b = dbusmenu_menuitem_property_get_bool (mi, USER_ITEM_PROP_LOGGED_IN); - - g_debug ("User \"%s\" %s active sessions", - dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME), - b ? "has" : "doesn't have"); - - gtk_widget_set_visible (self->priv->tick_icon, b); -} - -static void -update_name (UserWidget * self, DbusmenuMenuitem * mi) -{ - gtk_label_set_label (GTK_LABEL(self->priv->user_name), - dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME)); -} - -static void -user_widget_property_update (DbusmenuMenuitem * mi, - const gchar * property, - GVariant * value, - UserWidget * self) -{ - g_return_if_fail (IS_USER_WIDGET (self)); - - if (!g_strcmp0 (property, USER_ITEM_PROP_LOGGED_IN)) - { - update_logged_in (self, mi); - } - else if (!g_strcmp0 (property, USER_ITEM_PROP_ICON)) - { - update_icon (self, mi); - } - else if (!g_strcmp0 (property, USER_ITEM_PROP_NAME)) - { - update_name (self, mi); - } - else - { - g_debug ("%s FIXME: unhandled property change %s", G_STRFUNC, property); - } -} - -static void -user_widget_set_twin_item (UserWidget * self, DbusmenuMenuitem * mi) -{ - self->priv->twin_item = mi; - - update_icon (self, mi); - update_name (self, mi); - update_logged_in (self, mi); - - g_signal_connect (G_OBJECT(mi), "property-changed", - G_CALLBACK(user_widget_property_update), self); -} - - /** - * user_widget_new: - * @item: the #DbusmenuMenuitem this widget will render. - * - * Returns: (transfer full): a new #UserWidget. - **/ -GtkWidget* -user_widget_new (DbusmenuMenuitem *item) -{ - GtkWidget* widget = g_object_new(USER_WIDGET_TYPE, NULL); - user_widget_set_twin_item ( USER_WIDGET(widget), item ); - return widget; -} diff --git a/src/user-widget.h b/src/user-widget.h deleted file mode 100644 index 0953e6c..0000000 --- a/src/user-widget.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ -#ifndef __USER_WIDGET_H__ -#define __USER_WIDGET_H__ - -#include -#include - -G_BEGIN_DECLS - -#define USER_WIDGET_TYPE (user_widget_get_type ()) -#define USER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), USER_WIDGET_TYPE, UserWidget)) -#define USER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), USER_WIDGET_TYPE, UserWidgetClass)) -#define IS_USER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), USER_WIDGET_TYPE)) -#define IS_USER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), USER_WIDGET_TYPE)) -#define USER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), USER_WIDGET_TYPE, UserWidgetClass)) - -typedef struct _UserWidget UserWidget; -typedef struct _UserWidgetClass UserWidgetClass; -typedef struct _UserWidgetPrivate UserWidgetPrivate; - -struct _UserWidgetClass -{ - GtkMenuItemClass parent_class; -}; - -struct _UserWidget -{ - /*< private >*/ - GtkMenuItem parent; - UserWidgetPrivate * priv; -}; - -GType user_widget_get_type (void) G_GNUC_CONST; -GtkWidget* user_widget_new(DbusmenuMenuitem *twin_item); - -G_END_DECLS - -#endif diff --git a/src/users-service-dbus.c b/src/users-service-dbus.c deleted file mode 100644 index f12f47c..0000000 --- a/src/users-service-dbus.c +++ /dev/null @@ -1,1044 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */ -/* - * Copyright 2009 Canonical Ltd. - * - * Authors: - * Cody Russell - * Charles Kerr - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#include - -#include - -#include /* getpwuid() */ - -#include "dbus-accounts.h" -#include "dbus-consolekit-manager.h" -#include "dbus-consolekit-seat.h" -#include "dbus-consolekit-session.h" -#include "dbus-display-manager.h" -#include "dbus-user.h" -#include "shared-names.h" -#include "users-service-dbus.h" - -#define CK_ADDR "org.freedesktop.ConsoleKit" -#define CK_SESSION_IFACE "org.freedesktop.ConsoleKit.Session" - -/** -*** -**/ - -static void update_user_list (UsersServiceDbus * self); - -static gchar* get_seat (UsersServiceDbus * service); - -static void on_user_added (Accounts * o, - const gchar * user_object_path, - UsersServiceDbus * service); - -static void on_user_deleted (Accounts * o, - const gchar * user_object_path, - UsersServiceDbus * service); - -static void on_session_added (ConsoleKitSeat * seat, - const gchar * ssid, - UsersServiceDbus * service); - -static void on_session_removed (ConsoleKitSeat * seat, - const gchar * ssid, - UsersServiceDbus * service); - -static void on_session_list (ConsoleKitSeat * seat, - GAsyncResult * result, - UsersServiceDbus * service); - -/*** -**** Priv Struct -***/ - -struct _UsersServiceDbusPrivate -{ - gchar * seat; - gchar * guest_ssid; - - /* ssid -> AccountsUser lookup */ - GHashTable * sessions; - - /* user object path -> AccountsUser lookup */ - GHashTable * users; - - GCancellable * cancellable; - ConsoleKitSeat * seat_proxy; - ConsoleKitManager * ck_manager_proxy; - Accounts * accounts_proxy; -}; - -/*** -**** GObject -***/ - -enum -{ - USER_LIST_CHANGED, - USER_LOGGED_IN_CHANGED, - GUEST_LOGGED_IN_CHANGED, - N_SIGNALS -}; - -static guint signals[N_SIGNALS] = { 0 }; - -G_DEFINE_TYPE (UsersServiceDbus, users_service_dbus, G_TYPE_OBJECT); - -static void -users_service_dbus_dispose (GObject *object) -{ - UsersServiceDbusPrivate * priv = USERS_SERVICE_DBUS(object)->priv; - - g_clear_object (&priv->accounts_proxy); - g_clear_object (&priv->seat_proxy); - g_clear_object (&priv->ck_manager_proxy); - - if (priv->cancellable != NULL) - { - g_cancellable_cancel (priv->cancellable); - g_clear_object (&priv->cancellable); - } - - if (priv->users != NULL) - { - g_hash_table_destroy (priv->users); - priv->users = NULL; - } - - if (priv->sessions != NULL) - { - g_hash_table_destroy (priv->sessions); - priv->sessions = NULL; - } - - G_OBJECT_CLASS (users_service_dbus_parent_class)->dispose (object); -} - -static void -users_service_dbus_finalize (GObject *object) -{ - UsersServiceDbusPrivate * priv = USERS_SERVICE_DBUS(object)->priv; - - g_free (priv->guest_ssid); - g_free (priv->seat); - - G_OBJECT_CLASS (users_service_dbus_parent_class)->finalize (object); -} - -static void -users_service_dbus_class_init (UsersServiceDbusClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (UsersServiceDbusPrivate)); - - object_class->dispose = users_service_dbus_dispose; - object_class->finalize = users_service_dbus_finalize; - - signals[USER_LIST_CHANGED] = g_signal_new ( - "user-list-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UsersServiceDbusClass, user_list_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[USER_LOGGED_IN_CHANGED] = g_signal_new ( - "user-logged-in-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UsersServiceDbusClass, user_logged_in_changed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - signals[GUEST_LOGGED_IN_CHANGED] = g_signal_new ( - "guest-logged-in-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UsersServiceDbusClass, guest_logged_in_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -users_service_dbus_init (UsersServiceDbus *self) -{ - GError * error = NULL; - - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - USERS_SERVICE_DBUS_TYPE, - UsersServiceDbusPrivate); - - UsersServiceDbusPrivate * p = self->priv; - - p->cancellable = g_cancellable_new (); - - /* ssid -> AccountsUser */ - p->sessions = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_object_unref); - - /* user object path -> AccountsUser */ - p->users = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_object_unref); - - /** - *** create the consolekit manager proxy... - **/ - - p->ck_manager_proxy = console_kit_manager_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_clear_error (&error); - } - - p->seat = get_seat (self); - - /** - *** create the consolekit seat proxy... - **/ - - if (p->seat != NULL) - { - ConsoleKitSeat * proxy = console_kit_seat_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.ConsoleKit", - p->seat, - NULL, - &error); - - if (error != NULL) - { - g_warning ("Failed to connect to the ConsoleKit seat: %s", error->message); - g_clear_error (&error); - } - else - { - g_signal_connect (proxy, "session-added", - G_CALLBACK (on_session_added), self); - g_signal_connect (proxy, "session-removed", - G_CALLBACK (on_session_removed), self); - console_kit_seat_call_get_sessions (proxy, p->cancellable, - (GAsyncReadyCallback)on_session_list, self); - p->seat_proxy = proxy; - } - } - - /** - *** create the accounts manager proxy... - **/ - - Accounts * proxy = accounts_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.Accounts", - "/org/freedesktop/Accounts", - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } - else - { - g_signal_connect (proxy, "user-added", G_CALLBACK(on_user_added), self); - g_signal_connect (proxy, "user-deleted", G_CALLBACK(on_user_deleted), self); - p->accounts_proxy = proxy; - update_user_list (self); - } -} - -/*** -**** -***/ - -static void -emit_user_list_changed (UsersServiceDbus * self) -{ - g_signal_emit (self, signals[USER_LIST_CHANGED], 0); -} - -static void -emit_user_login_changed (UsersServiceDbus * self, AccountsUser * user) -{ - g_signal_emit (self, signals[USER_LOGGED_IN_CHANGED], 0, user); -} - -static void -emit_guest_login_changed (UsersServiceDbus * self) -{ - g_signal_emit (self, signals[GUEST_LOGGED_IN_CHANGED], 0); -} - -/*** -**** -***/ - -static ConsoleKitSession* -create_consolekit_session_proxy (const char * ssid) -{ - GError * error = NULL; - - ConsoleKitSession * p = console_kit_session_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - CK_ADDR, - ssid, - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - - return p; -} - -static gchar * -get_seat_from_session_proxy (ConsoleKitSession * session_proxy) -{ - gchar * seat = NULL; - - GError * error = NULL; - console_kit_session_call_get_seat_id_sync (session_proxy, - &seat, - NULL, - &error); - if (error != NULL) - { - g_debug ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - - return seat; -} - -static gchar * -get_seat (UsersServiceDbus *service) -{ - gchar * seat = NULL; - gchar * ssid = NULL; - GError * error = NULL; - UsersServiceDbusPrivate * priv = service->priv; - - console_kit_manager_call_get_current_session_sync (priv->ck_manager_proxy, - &ssid, - NULL, - &error); - - if (error != NULL) - { - g_debug ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - else - { - ConsoleKitSession * session = create_consolekit_session_proxy (ssid); - - if (session != NULL) - { - seat = get_seat_from_session_proxy (session); - g_object_unref (session); - } - } - - return seat; -} - -/*** -**** AccountsUser add-ons for tracking sessions -***/ - -static GHashTable* -user_get_sessions_hashset (AccountsUser * user) -{ - static GQuark q = 0; - - if (G_UNLIKELY(!q)) - { - q = g_quark_from_static_string ("sessions"); - } - - GObject * o = G_OBJECT (user); - GHashTable * h = g_object_get_qdata (o, q); - if (h == NULL) - { - h = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - g_object_set_qdata_full (o, q, h, (GDestroyNotify)g_hash_table_destroy); - } - - return h; -} - -static void -user_add_session (AccountsUser * user, const char * ssid) -{ - g_hash_table_add (user_get_sessions_hashset(user), g_strdup(ssid)); -} - -static void -user_remove_session (AccountsUser * user, const char * ssid) -{ - g_hash_table_remove (user_get_sessions_hashset(user), ssid); -} - -static guint -user_count_sessions (AccountsUser * user) -{ - return g_hash_table_size (user_get_sessions_hashset(user)); -} - -/*** -**** Users -***/ - -/* adds this user session to the user's and service's session tables */ -static void -add_user_session (UsersServiceDbus * service, - AccountsUser * user, - const gchar * ssid) -{ - ConsoleKitSession * session_proxy = create_consolekit_session_proxy (ssid); - if (session_proxy != NULL) - { - UsersServiceDbusPrivate * priv = service->priv; - gchar * seat = get_seat_from_session_proxy (session_proxy); - - /* is this session in our seat? */ - if (seat && priv->seat && !g_strcmp0 (seat, priv->seat)) - { - /* does this session have a display? */ - gchar * display = NULL; - console_kit_session_call_get_x11_display_sync (session_proxy, - &display, - NULL, NULL); - const gboolean has_display = display && *display; - g_free (display); - - if (has_display) - { - const gchar * username = accounts_user_get_user_name (user); - g_debug ("%s adding %s's session '%s' to our tables", - G_STRLOC, username, ssid); - - g_hash_table_insert (priv->sessions, - g_strdup (ssid), - g_object_ref (user)); - - user_add_session (user, ssid); - } - } - - g_free (seat); - g_object_unref (session_proxy); - } -} - -/* calls add_user_session() for each of this user's sessions */ -static void -add_user_sessions (UsersServiceDbus *self, AccountsUser * user) -{ - const guint64 uid = accounts_user_get_uid (user); - const char * username = accounts_user_get_user_name (user); - g_debug ("%s adding %s (%i)", G_STRLOC, username, (int)uid); - - GError * error = NULL; - gchar ** sessions = NULL; - console_kit_manager_call_get_sessions_for_unix_user_sync ( - self->priv->ck_manager_proxy, - uid, - &sessions, - NULL, - &error); - - if (error != NULL) - { - g_debug ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - else if (sessions != NULL) - { - int i; - - for (i=0; sessions[i]; i++) - { - const char * const ssid = sessions[i]; - g_debug ("%s adding %s's session %s", G_STRLOC, username, ssid); - add_user_session (self, user, ssid); - } - - g_strfreev (sessions); - } -} - -/* returns true if this property is one we use */ -static gboolean -is_interesting_user_property (const char * key) -{ - return !g_strcmp0 (key, "IconFile") - || !g_strcmp0 (key, "LoginFrequency") - || !g_strcmp0 (key, "RealName") - || !g_strcmp0 (key, "Uid") - || !g_strcmp0 (key, "UserName"); -} - -static void -sync_user_properties (GDBusProxy * source, GDBusProxy * target) -{ - gchar ** keys = g_dbus_proxy_get_cached_property_names (source); - - if (keys != NULL) - { - int i; - GVariantBuilder builder; - gboolean changed = FALSE; - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - - for (i=0; keys[i]; i++) - { - const gchar * const key = keys[i]; - - if (is_interesting_user_property (key)) - { - GVariant * oldval = g_dbus_proxy_get_cached_property (target, key); - GVariant * newval = g_dbus_proxy_get_cached_property (source, key); - - /* all the properties we're interested in are - basic types safe for g_variant_compare()... */ - g_assert (g_variant_type_is_basic(g_variant_get_type(newval))); - - if (g_variant_compare (oldval, newval)) - { - changed = TRUE; - g_dbus_proxy_set_cached_property (target, key, newval); - g_variant_builder_add (&builder, "{sv}", key, newval); - } - - g_variant_unref (newval); - g_variant_unref (oldval); - } - } - - if (changed) - { - g_signal_emit_by_name (target, "g-properties-changed", g_variant_builder_end(&builder), keys); - } - - g_variant_builder_clear (&builder); - g_strfreev (keys); - } -} - -/** - * The AccountsUserProxy's properties aren't being updated automatically - * for some reason... the only update we get is the 'changed' signal. - * This function is a workaround to update our User object's properties. - */ -static void -on_user_changed (AccountsUser * user, UsersServiceDbus * service) -{ - AccountsUser * tmp = accounts_user_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.Accounts", - g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)), - NULL, - NULL); - if (tmp != NULL) - { - sync_user_properties (G_DBUS_PROXY(tmp), G_DBUS_PROXY(user)); - g_object_unref (tmp); - } -} - -static void -add_user_from_object_path (UsersServiceDbus * self, - const char * user_object_path) -{ - GError * error = NULL; - - AccountsUser * user = accounts_user_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.Accounts", - user_object_path, - NULL, - &error); - - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_clear_error (&error); - } - else - { - AccountsUser * prev = g_hash_table_lookup (self->priv->users, user_object_path); - - if (prev != NULL) /* we've already got this user... sync its properties */ - { - sync_user_properties (G_DBUS_PROXY(user), G_DBUS_PROXY(prev)); - g_object_unref (user); - user = prev; - } - else /* ooo, we got a new user */ - { - g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); - g_hash_table_insert (self->priv->users, g_strdup(user_object_path), user); - } - - add_user_sessions (self, user); - } -} - - -/* asks org.freedesktop.Accounts for a list of users and - * calls add_user_from_object_path() on each of those users */ -static void -update_user_list (UsersServiceDbus *self) -{ - g_return_if_fail(IS_USERS_SERVICE_DBUS(self)); - - GError * error = NULL; - char ** object_paths = NULL; - UsersServiceDbusPrivate * priv = self->priv; - - accounts_call_list_cached_users_sync (priv->accounts_proxy, - &object_paths, - NULL, - &error); - - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } - else if (object_paths != NULL) - { - gint i; - - for (i=0; object_paths[i] != NULL; ++i) - { - add_user_from_object_path (self, object_paths[i]); - } - - emit_user_list_changed (self); - - g_strfreev (object_paths); - } - - g_debug ("%s finished updating the user list", G_STRLOC); -} - -static void -on_user_added (Accounts * o G_GNUC_UNUSED, - const gchar * user_path G_GNUC_UNUSED, - UsersServiceDbus * service) -{ - /* We see a new user but we might not want to list it -- - for example, lightdm shows up when we switch to the greeter. - So instead of adding the user directly here, let's ask - org.freedesktop.Accounts for a fresh list of users - because it filters out special cases. */ - update_user_list (service); -} - -static void -on_user_deleted (Accounts * o G_GNUC_UNUSED, - const gchar * user_path, - UsersServiceDbus * service) -{ - AccountsUser * user = g_hash_table_lookup (service->priv->users, user_path); - - if (user != NULL) - { - GObject * o = g_object_ref (G_OBJECT(user)); - g_hash_table_remove (service->priv->users, user_path); - emit_user_list_changed (service); - g_object_unref (o); - } -} - -static AccountsUser * -find_user_from_username (UsersServiceDbus * self, - const gchar * username) -{ - AccountsUser * match = NULL; - - g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), match); - - gpointer user; - GHashTableIter iter; - g_hash_table_iter_init (&iter, self->priv->users); - while (!match && g_hash_table_iter_next (&iter, NULL, &user)) - { - if (!g_strcmp0 (username, accounts_user_get_user_name (user))) - { - match = user; - } - } - - return match; -} - -/*** -**** Sessions -***/ - -static void -on_session_removed (ConsoleKitSeat * seat_proxy, - const gchar * ssid, - UsersServiceDbus * service) -{ - g_return_if_fail (IS_USERS_SERVICE_DBUS (service)); - - UsersServiceDbusPrivate * priv = service->priv; - g_debug ("%s %s() session removed %s", G_STRLOC, G_STRFUNC, ssid); - - if (!g_strcmp0 (ssid, priv->guest_ssid)) - { - g_debug ("%s removing guest session %s", G_STRLOC, ssid); - g_clear_pointer (&priv->guest_ssid, g_free); - emit_guest_login_changed (service); - } - else - { - AccountsUser * user = g_hash_table_lookup (priv->sessions, ssid); - if (user == NULL) - { - g_debug ("%s we're not tracking ssid %s", G_STRLOC, ssid); - } - else - { - GObject * o = g_object_ref (G_OBJECT(user)); - g_hash_table_remove (service->priv->users, ssid); - user_remove_session (user, ssid); - emit_user_login_changed (service, user); - g_object_unref (o); - } - } -} - -static gchar* -get_unix_username_from_ssid (UsersServiceDbus * self, - const gchar * ssid) -{ - gchar * username = NULL; - - ConsoleKitSession * session_proxy = create_consolekit_session_proxy (ssid); - if (session_proxy != NULL) - { - guint uid = 0; - GError * error = NULL; - console_kit_session_call_get_unix_user_sync (session_proxy, - &uid, - NULL, &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_clear_error (&error); - } - else - { - errno = 0; - const struct passwd * pwent = getpwuid (uid); - if (pwent == NULL) - { - g_warning ("Failed to lookup user id %d: %s", (int)uid, g_strerror(errno)); - } - else - { - username = g_strdup (pwent->pw_name); - } - } - - g_object_unref (session_proxy); - } - - return username; -} - -static gboolean -is_guest_username (const char * username) -{ - if (!g_strcmp0 (username, "guest")) - return TRUE; - - if (username && g_str_has_prefix (username, "guest-")) - return TRUE; - - return FALSE; -} - -/* If the new session belongs to 'guest', update our guest_ssid. - Otherwise, call add_user_session() to update our session tables */ -static void -on_session_added (ConsoleKitSeat * seat_proxy G_GNUC_UNUSED, - const gchar * ssid, - UsersServiceDbus * service) -{ - g_return_if_fail (IS_USERS_SERVICE_DBUS(service)); - - gchar * username = get_unix_username_from_ssid (service, ssid); - g_debug ("%s %s() username %s has new session %s", G_STRLOC, G_STRFUNC, username, ssid); - - if (is_guest_username (username)) - { - /* handle guest as a special case -- it's not in the GDM - user tables and there isn't be an AccountsUser for it */ - g_debug("Found guest session: %s", ssid); - g_free (service->priv->guest_ssid); - service->priv->guest_ssid = g_strdup (ssid); - emit_guest_login_changed (service); - } - else - { - AccountsUser * user = find_user_from_username (service, username); - - if (user != NULL) - { - add_user_session (service, user, ssid); - emit_user_login_changed (service, user); - } - } - - g_free (username); -} - -/* Receives a list of sessions and calls on_session_added() for each of them */ -static void -on_session_list (ConsoleKitSeat * seat_proxy, - GAsyncResult * result, - UsersServiceDbus * self) -{ - GError * error = NULL; - gchar ** sessions = NULL; - g_debug ("%s bootstrapping the session list", G_STRLOC); - - console_kit_seat_call_get_sessions_finish (seat_proxy, - &sessions, - result, - &error); - - if (error != NULL) - { - g_debug ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - else if (sessions != NULL) - { - int i; - - for (i=0; sessions[i]; i++) - { - g_debug ("%s adding initial session '%s'", G_STRLOC, sessions[i]); - on_session_added (seat_proxy, sessions[i], self); - } - - g_strfreev (sessions); - } - - g_debug ("%s done bootstrapping the session list", G_STRLOC); -} - -static DisplayManagerSeat * -create_display_proxy (UsersServiceDbus * self) -{ - const gchar * const seat = g_getenv ("XDG_SEAT_PATH"); - g_debug ("%s creating a DisplayManager proxy for seat %s", G_STRLOC, seat); - - GError * error = NULL; - DisplayManagerSeat * p = display_manager_seat_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.DisplayManager", - seat, - NULL, - &error); - - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - - return p; -} - -/*** -**** Public API -***/ - -/** - * users_service_dbus_get_user_list: - * - * Returns: (transfer container): a list of AccountsUser objects - */ -GList * -users_service_dbus_get_user_list (UsersServiceDbus * self) -{ - g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), NULL); - - return g_hash_table_get_values (self->priv->users); -} - -/** - * users_service_dbus_show_greeter: - * - * Ask the Display Mnaager to switch to the greeter screen. - */ -void -users_service_dbus_show_greeter (UsersServiceDbus * self) -{ - DisplayManagerSeat * dp; - - g_return_if_fail (IS_USERS_SERVICE_DBUS(self)); - - dp = create_display_proxy (self); - if (dp != NULL) - { - display_manager_seat_call_switch_to_greeter_sync (dp, NULL, NULL); - g_clear_object (&dp); - } -} - -/** - * users_service_dbus_activate_guest_session: - * - * Activates the guest account. - */ -void -users_service_dbus_activate_guest_session (UsersServiceDbus * self) -{ - DisplayManagerSeat * dp; - - g_return_if_fail (IS_USERS_SERVICE_DBUS(self)); - - dp = create_display_proxy (self); - if (dp != NULL) - { - display_manager_seat_call_switch_to_guest_sync (dp, "", NULL, NULL); - g_clear_object (&dp); - } -} - -/** - * users_service_dbus_activate_user_session: - * - * Activates a specific user. - */ -void -users_service_dbus_activate_user_session (UsersServiceDbus * self, - AccountsUser * user) -{ - DisplayManagerSeat * dp; - - g_return_if_fail (IS_USERS_SERVICE_DBUS(self)); - - dp = create_display_proxy (self); - if (dp != NULL) - { - const char * const username = accounts_user_get_user_name (user); - display_manager_seat_call_switch_to_user_sync (dp, username, "", NULL, NULL); - g_clear_object (&dp); - } -} - -/** - * users_service_dbus_guest_session_enabled: - * - * Tells whether or not guest sessions are allowed. - */ -gboolean -users_service_dbus_guest_session_enabled (UsersServiceDbus * self) -{ - DisplayManagerSeat * dp; - gboolean enabled = FALSE; - - g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), enabled); - - dp = create_display_proxy (self); - if (dp != NULL) - { - enabled = display_manager_seat_get_has_guest_account (dp); - g_clear_object (&dp); - } - - return enabled; -} - -gboolean -users_service_dbus_can_activate_session (UsersServiceDbus * self) -{ - gboolean can_activate = FALSE; - - g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), can_activate); - - GError * error = NULL; - console_kit_seat_call_can_activate_sessions_sync (self->priv->seat_proxy, - &can_activate, - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - - return can_activate; -} - -gboolean -users_service_dbus_is_guest_logged_in (UsersServiceDbus * self) -{ - g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), FALSE); - - return self->priv->guest_ssid != NULL; -} - -gboolean -users_service_dbus_is_user_logged_in (UsersServiceDbus * self, - AccountsUser * user) -{ - g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), FALSE); - g_return_val_if_fail (IS_ACCOUNTS_USER(user), FALSE); - - return user_count_sessions (user) > 0; -} diff --git a/src/users-service-dbus.h b/src/users-service-dbus.h deleted file mode 100644 index 0f082c3..0000000 --- a/src/users-service-dbus.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2009 Canonical Ltd. - * - * Authors: - * Cody Russell - * Charles Kerr - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef __USERS_SERVICE_DBUS_H__ -#define __USERS_SERVICE_DBUS_H__ - -#include -#include - -#include "dbus-user.h" /* for AccountsUser */ - -G_BEGIN_DECLS - -#define USERS_SERVICE_DBUS_TYPE (users_service_dbus_get_type ()) -#define USERS_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), USERS_SERVICE_DBUS_TYPE, UsersServiceDbus)) -#define IS_USERS_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), USERS_SERVICE_DBUS_TYPE)) - -typedef struct _UsersServiceDbus UsersServiceDbus; -typedef struct _UsersServiceDbusClass UsersServiceDbusClass; -typedef struct _UsersServiceDbusPrivate UsersServiceDbusPrivate; - -/** - * A facade class which interacts with multiple DBus services to - * track info which is useful to the interactor's user menu: - * - * 1. A list of users to add to the user menu. - * - * Each user is an AccountsUser object, which is a GDBusProxy - * to an org.freedesktop.Accounts.User object. - * - * We initially build this list by calling org.freedesktop.Accounts' - * GetCachedUsers method. We also monitor o.f.Accounts' UserAdded - * and UserDeleted and update the list accordingly. - * - * 2. Track which users currently have X sessions. - * This is used for the menuitems' USER_ITEM_PROP_LOGGED_IN property. - * - * We initially build this list by calling org.freedesktop.ConsoleKit.Seat's - * GetDevices method. We also monitor the seat for SessionAdded and - * SessionRemoved and update the list accordingly. - * - * 3. Provide an API for user switching and guest sessions. - * These are typically pass-through functions to GDBusProxies. - * - */ -struct _UsersServiceDbus -{ - /*< private >*/ - GObject parent; - UsersServiceDbusPrivate * priv; -}; - -struct _UsersServiceDbusClass -{ - GObjectClass parent_class; - - /* Signals */ - void (* user_list_changed) (UsersServiceDbus*, gpointer); - void (* user_logged_in_changed) (UsersServiceDbus*, AccountsUser*, gpointer); - void (* guest_logged_in_changed) (UsersServiceDbus*, gpointer); -}; - -GType users_service_dbus_get_type (void) G_GNUC_CONST; - -GList * users_service_dbus_get_user_list (UsersServiceDbus * self); - -gboolean users_service_dbus_is_guest_logged_in (UsersServiceDbus * self); -gboolean users_service_dbus_is_user_logged_in (UsersServiceDbus * self, - AccountsUser * user); - -void users_service_dbus_show_greeter (UsersServiceDbus * self); -gboolean users_service_dbus_guest_session_enabled (UsersServiceDbus * self); -gboolean users_service_dbus_can_activate_session (UsersServiceDbus * self); -void users_service_dbus_activate_guest_session (UsersServiceDbus * self); -void users_service_dbus_activate_user_session (UsersServiceDbus * self, - AccountsUser * user); - -G_END_DECLS - -#endif diff --git a/src/users.c b/src/users.c new file mode 100644 index 0000000..4b9c0ad --- /dev/null +++ b/src/users.c @@ -0,0 +1,198 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "users.h" + +/* signals enum */ +enum +{ + USER_ADDED, + USER_REMOVED, + USER_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (IndicatorSessionUsers, indicator_session_users, G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_IS_LIVE_SESSION, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorSessionUsers * self = INDICATOR_SESSION_USERS (o); + + switch (property_id) + { + case PROP_IS_LIVE_SESSION: + g_value_set_boolean (value, indicator_session_users_is_live_session (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_class_init (IndicatorSessionUsersClass * klass) +{ + GObjectClass * object_class; + const GParamFlags flags = G_PARAM_READABLE | G_PARAM_STATIC_STRINGS; + + object_class = G_OBJECT_CLASS (klass); + object_class->get_property = my_get_property; + + signals[USER_ADDED] = g_signal_new (INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED, + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (IndicatorSessionUsersClass, user_added), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[USER_REMOVED] = g_signal_new (INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED, + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (IndicatorSessionUsersClass, user_removed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[USER_CHANGED] = g_signal_new (INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (IndicatorSessionUsersClass, user_changed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + + properties[PROP_IS_LIVE_SESSION] = + g_param_spec_boolean (INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, + "Is Live Session", + "Whether or this is a 'live session', such as booting from a live CD", + FALSE, flags); + + g_object_class_install_properties (object_class, PROP_LAST, properties); + +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_init (IndicatorSessionUsers * self G_GNUC_UNUSED) +{ +} + +/*** +**** Virtual Functions +***/ + +GStrv +indicator_session_users_get_keys (IndicatorSessionUsers * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS (self), NULL); + + return INDICATOR_SESSION_USERS_GET_CLASS (self)->get_keys (self); +} + +IndicatorSessionUser * +indicator_session_users_get_user (IndicatorSessionUsers * self, + const char * key) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS (self), NULL); + + return INDICATOR_SESSION_USERS_GET_CLASS (self)->get_user (self, key); +} + +void +indicator_session_users_activate_user (IndicatorSessionUsers * self, + const char * key) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS (self)); + + INDICATOR_SESSION_USERS_GET_CLASS (self)->activate_user (self, key); +} + +gboolean +indicator_session_users_is_live_session (IndicatorSessionUsers * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS (self), FALSE); + + return INDICATOR_SESSION_USERS_GET_CLASS (self)->is_live_session (self); +} + +void +indicator_session_user_free (IndicatorSessionUser * user) +{ + g_return_if_fail (user != NULL); + + g_free (user->real_name); + g_free (user->user_name); + g_free (user->icon_file); + g_free (user); +} + +/*** +**** Signal Convenience +***/ + +void +indicator_session_users_added (IndicatorSessionUsers * self, const char * key) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS (self)); + + g_signal_emit (self, signals[USER_ADDED], 0, key); +} + +void +indicator_session_users_removed (IndicatorSessionUsers * self, const char * key) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS (self)); + + g_signal_emit (self, signals[USER_REMOVED], 0, key); +} + +void +indicator_session_users_changed (IndicatorSessionUsers * self, const char * key) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS (self)); + + g_signal_emit (self, signals[USER_CHANGED], 0, key); +} + +void +indicator_session_users_notify_is_live_session (IndicatorSessionUsers * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS (self)); + + g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_IS_LIVE_SESSION]); +} + diff --git a/src/users.h b/src/users.h new file mode 100644 index 0000000..31ee39e --- /dev/null +++ b/src/users.h @@ -0,0 +1,146 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __USERS_H__ +#define __USERS_H__ + +#include +#include + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_USERS (indicator_session_users_get_type()) +#define INDICATOR_SESSION_USERS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_USERS, IndicatorSessionUsers)) +#define INDICATOR_SESSION_USERS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_USERS, IndicatorSessionUsersClass)) +#define INDICATOR_SESSION_USERS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_SESSION_USERS, IndicatorSessionUsersClass)) +#define INDICATOR_IS_SESSION_USERS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_USERS)) + + +typedef struct _IndicatorSessionUser IndicatorSessionUser; +typedef struct _IndicatorSessionUsers IndicatorSessionUsers; +typedef struct _IndicatorSessionUsersClass IndicatorSessionUsersClass; + +/** + * A base class for monitoring the system's users and active sessions. + * Use backend.h's get_backend() to get an instance. + */ +struct _IndicatorSessionUsers +{ + /*< private >*/ + GObject parent; +}; + +struct _IndicatorSessionUser +{ + gboolean is_current_user; + gboolean is_logged_in; + guint uid; + guint64 login_frequency; + gchar * user_name; + gchar * real_name; + gchar * icon_file; +}; + +/* signal keys */ +#define INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED "user-added" +#define INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED "user-removed" +#define INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED "user-changed" + +/* property keys */ +#define INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION "is-live-session" + +struct _IndicatorSessionUsersClass +{ + GObjectClass parent_class; + + /* signals */ + + void (* user_added) (IndicatorSessionUsers * self, + const gchar * key); + + void (* user_removed) (IndicatorSessionUsers * self, + const gchar * key); + + void (* user_changed) (IndicatorSessionUsers * self, + const gchar * key); + + + /* pure virtual functions */ + + gboolean (* is_live_session) (IndicatorSessionUsers * self); + + + GStrv (* get_keys) (IndicatorSessionUsers * self); + + IndicatorSessionUser * (* get_user) (IndicatorSessionUsers * self, + const gchar * key); + + void ( * activate_user) (IndicatorSessionUsers * self, + const gchar * key); +}; + +/*** +**** +***/ + +GType indicator_session_users_get_type (void); + +/* emits the "user-added" signal */ +void indicator_session_users_added (IndicatorSessionUsers * self, + const gchar * key); + +/* emits the "user-removed" signal */ +void indicator_session_users_removed (IndicatorSessionUsers * self, + const gchar * key); + +/* emits the "user-changed" signal */ +void indicator_session_users_changed (IndicatorSessionUsers * self, + const gchar * key); + +/* notify listeners of a change to the 'is-live-session' property */ +void indicator_session_users_notify_is_live_session (IndicatorSessionUsers * self); + + + +/*** +**** +***/ + +gboolean indicator_session_users_is_live_session (IndicatorSessionUsers * users); + +/* get a list of user keys */ +GStrv indicator_session_users_get_keys (IndicatorSessionUsers * users); + +/* get information about a particular user. + call indicator_session_user_free() when done with the returned struct. */ +IndicatorSessionUser * +indicator_session_users_get_user (IndicatorSessionUsers * users, + const gchar * key); + +/* frees a IndicatorSessionUser struct */ +void indicator_session_user_free (IndicatorSessionUser * user); + +/* activate to a different session */ +void indicator_session_users_activate_user (IndicatorSessionUsers * self, + const char * key); + + +G_END_DECLS + +#endif -- cgit v1.2.3