diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 48 | ||||
-rw-r--r-- | src/consolekit-session.xml | 435 | ||||
-rw-r--r-- | src/dbus-shared-names.h | 12 | ||||
-rw-r--r-- | src/gconf-helper.c | 57 | ||||
-rw-r--r-- | src/gconf-helper.h | 8 | ||||
-rw-r--r-- | src/gdm-local-display-factory.xml | 20 | ||||
-rw-r--r-- | src/indicator-session.c | 164 | ||||
-rw-r--r-- | src/lock-helper.c | 100 | ||||
-rw-r--r-- | src/lock-helper.h | 2 | ||||
-rw-r--r-- | src/session-dbus.c | 139 | ||||
-rw-r--r-- | src/session-dbus.h | 55 | ||||
-rw-r--r-- | src/session-dbus.xml | 15 | ||||
-rw-r--r-- | src/session-service.c | 305 | ||||
-rw-r--r-- | src/upower.xml | 309 | ||||
-rw-r--r-- | src/users-service-dbus.c | 211 | ||||
-rw-r--r-- | src/users-service-dbus.h | 7 |
16 files changed, 1684 insertions, 203 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index cd525bd..24e00e4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,6 +11,7 @@ sessionlibdir = $(INDICATORDIR) sessionlib_LTLIBRARIES = libsession.la libsession_la_SOURCES = \ indicator-session.c \ + session-dbus-client.h \ dbus-shared-names.h \ dbusmenu-shared.h \ users-service-client.h @@ -25,6 +26,20 @@ consolekit-manager-client.h: $(srcdir)/consolekit-manager.xml --output=consolekit-manager-client.h \ $(srcdir)/consolekit-manager.xml +consolekit-session-client.h: $(srcdir)/consolekit-session.xml + dbus-binding-tool \ + --prefix=_consolekit_session_client \ + --mode=glib-client \ + --output=consolekit-session-client.h \ + $(srcdir)/consolekit-session.xml + +gdm-local-display-factory-client.h: $(srcdir)/gdm-local-display-factory.xml + dbus-binding-tool \ + --prefix=_gdm_local_display_factory_client \ + --mode=glib-client \ + --output=gdm-local-display-factory-client.h \ + $(srcdir)/gdm-local-display-factory.xml + users-service-client.h: $(srcdir)/users-service.xml dbus-binding-tool \ --prefix=_users_service_client \ @@ -32,6 +47,27 @@ users-service-client.h: $(srcdir)/users-service.xml --output=users-service-client.h \ $(srcdir)/users-service.xml +upower-client.h: $(srcdir)/upower.xml + dbus-binding-tool \ + --prefix=_upower_client \ + --mode=glib-client \ + --output=upower-client.h \ + $(srcdir)/upower.xml + +session-dbus-client.h: $(srcdir)/session-dbus.xml + dbus-binding-tool \ + --prefix=_session_dbus_client \ + --mode=glib-client \ + --output=session-dbus-client.h \ + $(srcdir)/session-dbus.xml + +session-dbus-server.h: $(srcdir)/session-dbus.xml + dbus-binding-tool \ + --prefix=_session_dbus_server \ + --mode=glib-server \ + --output=session-dbus-server.h \ + $(srcdir)/session-dbus.xml + users-service-marshal.h: $(srcdir)/users-service.list glib-genmarshal --header \ --prefix=_users_service_marshal $(srcdir)/users-service.list \ @@ -50,6 +86,9 @@ indicator_session_service_SOURCES = \ lock-helper.c \ lock-helper.h \ session-service.c \ + session-dbus.c \ + session-dbus.h \ + session-dbus-server.h \ dbusmenu-shared.h \ gconf-helper.c \ users-service-dbus.h \ @@ -88,12 +127,21 @@ gtk_logout_helper_LDADD = \ BUILT_SOURCES = \ consolekit-manager-client.h \ + consolekit-session-client.h \ + gdm-local-display-factory-client.h \ + session-dbus-client.h \ + session-dbus-server.h \ + upower-client.h \ users-service-client.h \ users-service-marshal.h \ users-service-marshal.c EXTRA_DIST = \ consolekit-manager.xml \ + consolekit-session.xml \ + gdm-local-display-factory.xml \ + session-dbus.xml \ + upower.xml \ users-service.xml \ users-service.list diff --git a/src/consolekit-session.xml b/src/consolekit-session.xml new file mode 100644 index 0000000..b6e1cdb --- /dev/null +++ b/src/consolekit-session.xml @@ -0,0 +1,435 @@ +<?xml version="1.0" encoding="UTF-8"?> +<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> + + <interface name="org.freedesktop.ConsoleKit.Session"> + <doc:doc> + <doc:description> + <doc:para>Session objects represent and store information + related to a user session. + </doc:para> + <doc:para>The properties associated with the Session + specifically refer to the properties of the "session leader". + </doc:para> + </doc:description> + </doc:doc> + <method name="GetId"> + <arg name="ssid" direction="out" type="o"> + <doc:doc> + <doc:summary>Session ID</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>Returns the ID for Session.</doc:para> + </doc:description> + </doc:doc> + </method> + <method name="GetSeatId"> + <arg name="sid" direction="out" type="o"> + <doc:doc> + <doc:summary>Seat ID</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>Returns the ID for the Seat the Session is + attached to.</doc:para> + </doc:description> + <doc:seealso><doc:ref type="interface" to="Seat">org.freedesktop.ConsoleKit.Seat</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="GetSessionType"> + <arg name="type" direction="out" type="s"> + <doc:doc> + <doc:summary>Session type</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description> + <doc:para>Returns the type of the session.</doc:para> + <doc:para>Warning: we haven't yet defined the allowed values for this property. + It is probably best to avoid this until we do. + </doc:para> + </doc:description> + <doc:seealso><doc:ref type="property" to="Session:session-type">session-type</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="GetUser"> + <arg name="uid" direction="out" type="u"> + <doc:doc> + <doc:summary>User ID</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>Returns the user that the session belongs to.</doc:para> + </doc:description> + <doc:deprecated version="0.1.3" instead="GetUnixUser"/> + <doc:seealso><doc:ref type="property" to="Session:user">user</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="GetUnixUser"> + <arg name="uid" direction="out" type="u"> + <doc:doc> + <doc:summary>POSIX User ID</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>Returns the POSIX user ID that the session belongs to.</doc:para> + </doc:description> + <doc:seealso><doc:ref type="property" to="Session:unix-user">unix-user</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="GetX11Display"> + <arg name="display" direction="out" type="s"> + <doc:doc> + <doc:summary>The value of the X11 display</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>Returns the value of the X11 DISPLAY for this session + if one is present.</doc:para> + </doc:description> + <doc:seealso><doc:ref type="property" to="Session:x11-display">x11-display</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="GetX11DisplayDevice"> + <arg name="x11_display_device" direction="out" type="s"> + <doc:doc> + <doc:summary>The value of the X11 display device</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>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.</doc:para> + </doc:description> + <doc:seealso><doc:ref type="property" to="Session:x11-display-device">x11-display-device</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="GetDisplayDevice"> + <arg name="display_device" direction="out" type="s"> + <doc:doc> + <doc:summary>The value of the display device</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>Returns the value of the display device (aka TTY) that the + session is connected to.</doc:para> + </doc:description> + <doc:seealso><doc:ref type="property" to="Session:display-device">display-device</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="GetRemoteHostName"> + <arg name="remote_host_name" direction="out" type="s"> + <doc:doc> + <doc:summary>The remote host name</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>Returns the value of the remote host name for the session. + </doc:para> + </doc:description> + <doc:seealso><doc:ref type="property" to="Session:remote-host-name">remote-host-name</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="GetLoginSessionId"> + <arg name="login_session_id" direction="out" type="s"> + <doc:doc> + <doc:summary>The value of the native system login session ID</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>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.</doc:para> + </doc:description> + </doc:doc> + </method> + <method name="IsActive"> + <arg name="active" direction="out" type="b"> + <doc:doc> + <doc:summary>TRUE if the session is active, otherwise FALSE</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>Returns whether the session is active on the Seat that + it is attached to.</doc:para> + <doc:para>If the session is not attached to a seat this value is undefined. + </doc:para> + </doc:description> + <doc:seealso><doc:ref type="property" to="Session:active">active</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="IsLocal"> + <arg name="local" direction="out" type="b"> + <doc:doc> + <doc:summary>TRUE if the session is local, otherwise FALSE</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description><doc:para>Returns whether the session is local</doc:para> + <doc:para>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. + </doc:para> + </doc:description> + <doc:seealso><doc:ref type="property" to="Session:is-local">is-local</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="GetCreationTime"> + <arg name="iso8601_datetime" type="s" direction="out"> + <doc:doc> + <doc:summary>An ISO 8601 format date-type string</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description> + <doc:para>Returns an ISO 8601 date-time string that corresponds to + the time that the session was opened. + </doc:para> + </doc:description> + </doc:doc> + </method> + + <method name="Activate"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para>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.</doc:para> + </doc:description> + <doc:seealso><doc:ref type="method" to="Seat.ActivateSession">Seat.ActivateSession()</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="Lock"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para>This will cause a <doc:ref type="signal" to="Session::Lock">Lock</doc:ref> + signal to be emitted for this session. + </doc:para> + </doc:description> + <doc:permission>This method is restricted to privileged users by D-Bus policy.</doc:permission> + <doc:seealso><doc:ref type="signal" to="Session::Lock">Lock signal</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="Unlock"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para>This will cause an <doc:ref type="signal" to="Session::Unlock">Unlock</doc:ref> + signal to be emitted for this session. + </doc:para> + <doc:para>This can be used by login managers to unlock a session before it is + re-activated during fast-user-switching. + </doc:para> + </doc:description> + <doc:permission>This method is restricted to privileged users by D-Bus policy.</doc:permission> + <doc:seealso><doc:ref type="signal" to="Session::Unlock">Unlock signal</doc:ref></doc:seealso> + </doc:doc> + </method> + + <method name="GetIdleHint"> + <arg name="idle_hint" type="b" direction="out"> + <doc:doc> + <doc:summary>The value of the idle-hint</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description> + <doc:para>Gets the value of the <doc:ref type="property" to="Session:idle-hint">idle-hint</doc:ref> + property. + </doc:para> + </doc:description> + <doc:seealso><doc:ref type="property" to="Session:idle-hint">idle-hint</doc:ref></doc:seealso> + </doc:doc> + </method> + <method name="GetIdleSinceHint"> + <arg name="iso8601_datetime" type="s" direction="out"> + <doc:doc> + <doc:summary>An ISO 8601 format date-type string</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description> + <doc:para>Returns an ISO 8601 date-time string that corresponds to + the time of the last change of the idle-hint. + </doc:para> + </doc:description> + </doc:doc> + </method> + <method name="SetIdleHint"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="idle_hint" type="b" direction="in"> + <doc:doc> + <doc:summary>boolean value to set the idle-hint to</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description> + <doc:para>This may be used by the session to indicate that + it is idle. + </doc:para> + <doc:para>Use of this method is restricted to the user + that owns the session.</doc:para> + </doc:description> + </doc:doc> + </method> + + <signal name="ActiveChanged"> + <arg name="is_active" type="b"> + <doc:doc> + <doc:summary>TRUE if the session is active, otherwise FALSE</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description> + <doc:para>Emitted when the active property has changed.</doc:para> + </doc:description> + </doc:doc> + </signal> + <signal name="IdleHintChanged"> + <arg name="hint" type="b"> + <doc:doc> + <doc:summary>the new value of idle-hint</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description> + <doc:para>Emitted when the idle-hint property has changed.</doc:para> + </doc:description> + </doc:doc> + </signal> + <signal name="Lock"> + <doc:doc> + <doc:description> + <doc:para>Emitted in response to a call to the <doc:ref type="method" to="Session.Lock">Lock()</doc:ref> method.</doc:para> + <doc:para>It is intended that the screensaver for the session should lock the screen in response to this signal.</doc:para> + </doc:description> + </doc:doc> + </signal> + <signal name="Unlock"> + <doc:doc> + <doc:description> + <doc:para>Emitted in response to a call to the <doc:ref type="method" to="Session.Unlock">Unlock()</doc:ref> method.</doc:para> + <doc:para>It is intended that the screensaver for the session should unlock the screen in response to this signal.</doc:para> + </doc:description> + </doc:doc> + </signal> + + <property name="unix-user" type="u" access="readwrite"> + <doc:doc> + <doc:description> + <doc:para>The user assigned to the session.</doc:para> + </doc:description> + </doc:doc> + </property> + <property name="user" type="u" access="readwrite"> + <doc:doc> + <doc:description> + <doc:para>The user assigned to the session.</doc:para> + </doc:description> + <doc:deprecated version="0.1.3" instead="unix-user"/> + </doc:doc> + </property> + <property name="session-type" type="s" access="readwrite"> + <doc:doc> + <doc:description> + <doc:para>The type of the session.</doc:para> + <doc:para>Warning: we haven't yet defined the allowed values for this property. + It is probably best to avoid this until we do. + </doc:para> + </doc:description> + </doc:doc> + </property> + <property name="remote-host-name" type="s" access="readwrite"> + <doc:doc> + <doc:description> + <doc:para>The remote host name for the session. + </doc:para> + <doc:para>This will be set in situations where the session is + opened and controlled from a remote system. + </doc:para> + <doc:para>For example, this value will be set when the + session is created from an SSH or XDMCP connection. + </doc:para> + </doc:description> + </doc:doc> + </property> + <property name="display-device" type="s" access="readwrite"> + <doc:doc> + <doc:description> + <doc:para>The display device (aka TTY) that the + session is connected to. + </doc:para> + </doc:description> + </doc:doc> + </property> + <property name="x11-display" type="s" access="readwrite"> + <doc:doc> + <doc:description> + <doc:para>Value of the X11 DISPLAY for this session + if one is present. + </doc:para> + </doc:description> + </doc:doc> + </property> + <property name="x11-display-device" type="s" access="readwrite"> + <doc:doc> + <doc:description> + <doc:para> + 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. + </doc:para> + </doc:description> + </doc:doc> + </property> + <property name="active" type="b" access="readwrite"> + <doc:doc> + <doc:description> + <doc:para> + Whether the session is active on the Seat that + it is attached to.</doc:para> + <doc:para>If the session is not attached to a seat this value is undefined. + </doc:para> + </doc:description> + </doc:doc> + </property> + <property name="is-local" type="b" access="readwrite"> + <doc:doc> + <doc:description> + <doc:para> + Whether the session is local</doc:para> + <doc:para>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. + </doc:para> + </doc:description> + </doc:doc> + </property> + <property name="idle-hint" type="b" access="readwrite"> + <doc:doc> + <doc:description> + <doc:para> + This is a hint used to indicate that the session may be idle. + </doc:para> + <doc:para> + For sessions with a <doc:ref type="property" to="Session:x11-display">x11-display</doc:ref> set (ie. graphical + sessions), it is up to each session to delegate the + responsibility for updating this value. Typically, the + screensaver will set this. + </doc:para> + <doc:para>However, for non-graphical sessions with a <doc:ref type="property" to="Session:display-device">display-device</doc:ref> set + the Session object itself will periodically update this value based + on the activity detected on the display-device itself. + </doc:para> + <doc:para> + This should not be considered authoritative. + </doc:para> + </doc:description> + </doc:doc> + </property> + + </interface> +</node> diff --git a/src/dbus-shared-names.h b/src/dbus-shared-names.h index 253cba8..3ac14b3 100644 --- a/src/dbus-shared-names.h +++ b/src/dbus-shared-names.h @@ -38,8 +38,20 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define INDICATOR_SESSION_DBUS_OBJECT "/org/ayatana/indicator/session/menu" #define INDICATOR_SESSION_DBUS_VERSION 0 +#define INDICATOR_SESSION_SERVICE_DBUS_OBJECT "/org/ayatana/indicator/session/service" +#define INDICATOR_SESSION_SERVICE_DBUS_IFACE "org.ayatana.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_ICON "user-item-icon-path" +#define USER_ITEM_ICON_DEFAULT "default-icon" + +#define RESTART_ITEM_TYPE "x-canonical-restart-item" +#define RESTART_ITEM_LABEL "restart-label" +#define RESTART_ITEM_ICON "restart-icon" + +#define ICON_DEFAULT "system-shutdown-panel" +#define ICON_RESTART "system-shutdown-panel-restart" #endif /* __DBUS_SHARED_NAMES_H__ */ diff --git a/src/gconf-helper.c b/src/gconf-helper.c index 9262b19..29d8526 100644 --- a/src/gconf-helper.c +++ b/src/gconf-helper.c @@ -30,9 +30,12 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <libdbusmenu-glib/server.h> #include <libdbusmenu-glib/menuitem.h> +#include "dbus-shared-names.h" #include "gconf-helper.h" static GConfClient * gconf_client = NULL; +static guint confirmation_notify = 0; +static guint logout_notify = 0; gboolean supress_confirmations (void) { @@ -42,6 +45,14 @@ supress_confirmations (void) { return gconf_client_get_bool (gconf_client, SUPPRESS_KEY, NULL) ; } +gboolean +show_logout (void) { + if(!gconf_client) { + gconf_client = gconf_client_get_default (); + } + return !gconf_client_get_bool (gconf_client, LOGOUT_KEY, NULL) ; +} + static void update_menu_entries_callback (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer data) { RestartShutdownLogoutMenuItems * restart_shutdown_logout_mi = (RestartShutdownLogoutMenuItems*) data; GConfValue * value = gconf_entry_get_value (entry); @@ -50,24 +61,54 @@ static void update_menu_entries_callback (GConfClient *client, guint cnxn_id, GC if(g_strcmp0 (key, SUPPRESS_KEY) == 0) { if (gconf_value_get_bool (value)) { dbusmenu_menuitem_property_set(restart_shutdown_logout_mi->logout_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Log Out")); - dbusmenu_menuitem_property_set(restart_shutdown_logout_mi->restart_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Restart")); - dbusmenu_menuitem_property_set(restart_shutdown_logout_mi->shutdown_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Switch Off")); + dbusmenu_menuitem_property_set(restart_shutdown_logout_mi->restart_mi, RESTART_ITEM_LABEL, _("Restart")); + dbusmenu_menuitem_property_set(restart_shutdown_logout_mi->shutdown_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Shut Down")); } else { dbusmenu_menuitem_property_set(restart_shutdown_logout_mi->logout_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Log Out...")); - dbusmenu_menuitem_property_set(restart_shutdown_logout_mi->restart_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Restart...")); - dbusmenu_menuitem_property_set(restart_shutdown_logout_mi->shutdown_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Switch Off...")); + dbusmenu_menuitem_property_set(restart_shutdown_logout_mi->restart_mi, RESTART_ITEM_LABEL, _("Restart...")); + dbusmenu_menuitem_property_set(restart_shutdown_logout_mi->shutdown_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Shut Down...")); } } } +static void +update_logout_callback (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer data) { + DbusmenuMenuitem * mi = (DbusmenuMenuitem*) data; + GConfValue * value = gconf_entry_get_value (entry); + const gchar * key = gconf_entry_get_key (entry); + + if(g_strcmp0 (key, LOGOUT_KEY) == 0) { + dbusmenu_menuitem_property_set_bool(mi, DBUSMENU_MENUITEM_PROP_VISIBLE, !gconf_value_get_bool(value)); + } +} + void -update_menu_entries(RestartShutdownLogoutMenuItems * restart_shutdown_logout_mi) { +update_menu_entries(RestartShutdownLogoutMenuItems * restart_shutdown_logout_mi, DbusmenuMenuitem * logoutitem) { + /* If we don't have a client, build one. */ if(!gconf_client) { gconf_client = gconf_client_get_default (); } - gconf_client_add_dir (gconf_client, GLOBAL_DIR, - GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); - gconf_client_notify_add (gconf_client, SUPPRESS_KEY, + + /* If we've not gotten any notifications, then we need + to add the directory for notifications to come from. */ + if (confirmation_notify == 0 || logout_notify == 0) { + gconf_client_add_dir (gconf_client, GLOBAL_DIR, + GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); + } + + if (confirmation_notify != 0) { + gconf_client_notify_remove (gconf_client, confirmation_notify); + confirmation_notify = 0; + } + + if (logout_notify != 0) { + gconf_client_notify_remove (gconf_client, logout_notify); + logout_notify = 0; + } + + confirmation_notify = gconf_client_notify_add (gconf_client, SUPPRESS_KEY, update_menu_entries_callback, restart_shutdown_logout_mi, NULL, NULL); + logout_notify = gconf_client_notify_add (gconf_client, LOGOUT_KEY, + update_logout_callback, logoutitem, NULL, NULL); } diff --git a/src/gconf-helper.h b/src/gconf-helper.h index 951bb0f..6f9bcb7 100644 --- a/src/gconf-helper.h +++ b/src/gconf-helper.h @@ -33,8 +33,9 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <libdbusmenu-glib/server.h> #include <libdbusmenu-glib/menuitem.h> -#define SUPPRESS_KEY "/apps/indicator-session/suppress_logout_restart_shutdown" -#define GLOBAL_DIR "/apps/indicator-session" +#define GLOBAL_DIR "/apps/indicator-session" +#define SUPPRESS_KEY GLOBAL_DIR "/suppress_logout_restart_shutdown" +#define LOGOUT_KEY GLOBAL_DIR "/suppress_logout_menuitem" typedef struct _RestartShutdownLogoutMenuItems { @@ -44,7 +45,8 @@ typedef struct _RestartShutdownLogoutMenuItems } RestartShutdownLogoutMenuItems; -void update_menu_entries(RestartShutdownLogoutMenuItems*); +void update_menu_entries(RestartShutdownLogoutMenuItems*, DbusmenuMenuitem * logoutitem); gboolean supress_confirmations (void); +gboolean show_logout (void); #endif /* __GCONF_HELPER__ */ diff --git a/src/gdm-local-display-factory.xml b/src/gdm-local-display-factory.xml new file mode 100644 index 0000000..66fb77c --- /dev/null +++ b/src/gdm-local-display-factory.xml @@ -0,0 +1,20 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/org/gnome/DisplayManager/LocalDisplayFactory"> + <interface name="org.gnome.DisplayManager.LocalDisplayFactory"> + <method name="CreateProductDisplay"> + <arg name="parent_display_id" direction="in" type="o"/> + <arg name="relay_address" direction="in" type="s"/> + <arg name="id" direction="out" type="o"/> + </method> + <method name="CreateTransientDisplay"> + <arg name="id" direction="out" type="o"/> + </method> + <method name="StartGuestSession"> + <arg name="id" direction="out" type="o"/> + </method> + <method name="SwitchToUser"> + <arg name="username" direction="in" type="s"/> + <arg name="id" direction="out" type="o"/> + </method> + </interface> +</node> diff --git a/src/indicator-session.c b/src/indicator-session.c index 54431ee..b54a5d9 100644 --- a/src/indicator-session.c +++ b/src/indicator-session.c @@ -28,6 +28,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib-object.h> #include <glib/gi18n-lib.h> #include <gtk/gtk.h> +#include <gio/gio.h> #include <libdbusmenu-gtk/menu.h> #include <dbus/dbus-glib.h> @@ -36,9 +37,11 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <libindicator/indicator.h> #include <libindicator/indicator-object.h> #include <libindicator/indicator-service-manager.h> +#include <libindicator/indicator-image-helper.h> #include "dbus-shared-names.h" #include "dbusmenu-shared.h" +#include "session-dbus-client.h" #define INDICATOR_SESSION_TYPE (indicator_session_get_type ()) #define INDICATOR_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SESSION_TYPE, IndicatorSession)) @@ -59,6 +62,7 @@ struct _IndicatorSession { IndicatorServiceManager * service; GtkImage * status_image; DbusmenuGtkMenu * menu; + DBusGProxy * service_proxy; }; GType indicator_session_get_type (void); @@ -73,6 +77,9 @@ static GtkImage * get_icon (IndicatorObject * io); static GtkMenu * get_menu (IndicatorObject * io); static gboolean build_menu_switch (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client); static gboolean new_user_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client); +static void icon_changed (DBusGProxy * proxy, gchar * icon_name, gpointer user_data); +static void service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data); +static gboolean build_restart_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client); static void indicator_session_class_init (IndicatorSessionClass *klass); static void indicator_session_init (IndicatorSession *self); @@ -105,13 +112,29 @@ indicator_session_init (IndicatorSession *self) /* 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->status_image = GTK_IMAGE(gtk_image_new_from_icon_name("system-shutdown-panel", GTK_ICON_SIZE_MENU)); + self->status_image = indicator_image_helper(ICON_DEFAULT); self->menu = dbusmenu_gtkmenu_new(INDICATOR_SESSION_DBUS_NAME, INDICATOR_SESSION_DBUS_OBJECT); DbusmenuClient * client = DBUSMENU_CLIENT(dbusmenu_gtkmenu_get_client(self->menu)); dbusmenu_client_add_type_handler(client, MENU_SWITCH_TYPE, build_menu_switch); dbusmenu_client_add_type_handler(client, USER_ITEM_TYPE, new_user_item); + dbusmenu_client_add_type_handler(client, RESTART_ITEM_TYPE, build_restart_item); + + DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL); + self->service_proxy = dbus_g_proxy_new_for_name(session_bus, + INDICATOR_SESSION_DBUS_NAME, + INDICATOR_SESSION_SERVICE_DBUS_OBJECT, + INDICATOR_SESSION_SERVICE_DBUS_IFACE); + + dbus_g_proxy_add_signal(self->service_proxy, "IconUpdated", + G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->service_proxy, + "IconUpdated", + G_CALLBACK(icon_changed), + self, + NULL); return; } @@ -126,6 +149,11 @@ indicator_session_dispose (GObject *object) self->service = NULL; } + if (self->service_proxy != NULL) { + g_object_unref(self->service_proxy); + self->service_proxy = NULL; + } + G_OBJECT_CLASS (indicator_session_parent_class)->dispose (object); return; } @@ -138,12 +166,50 @@ indicator_session_finalize (GObject *object) return; } +static void +icon_name_get_cb (DBusGProxy *proxy, char * OUT_name, GError *error, gpointer userdata) +{ + if (error != NULL) { + return; + } + + if (OUT_name == NULL || OUT_name[0] == '\0') { + return; + } + + IndicatorSession * self = INDICATOR_SESSION(userdata); + indicator_image_helper_update(self->status_image, OUT_name); + return; +} + +static void +service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data) +{ + IndicatorSession * self = INDICATOR_SESSION(user_data); + + if (connected) { + org_ayatana_indicator_session_service_get_icon_async(self->service_proxy, icon_name_get_cb, user_data); + } else { + indicator_image_helper_update(self->status_image, ICON_DEFAULT); + } + + return; +} + static GtkLabel * get_label (IndicatorObject * io) { return NULL; } +static void +icon_changed (DBusGProxy * proxy, gchar * icon_name, gpointer user_data) +{ + IndicatorSession * session = INDICATOR_SESSION(user_data); + indicator_image_helper_update(session->status_image, icon_name); + return; +} + static GtkImage * get_icon (IndicatorObject * io) { @@ -151,12 +217,45 @@ get_icon (IndicatorObject * io) return INDICATOR_SESSION(io)->status_image; } +static void +user_property_change (DbusmenuMenuitem * item, const gchar * property, const GValue * value, gpointer user_data) +{ + if (g_strcmp0(property, USER_ITEM_PROP_LOGGED_IN) == 0) { + if (g_value_get_boolean(value)) { + gtk_widget_show(GTK_WIDGET(user_data)); + } else { + gtk_widget_hide(GTK_WIDGET(user_data)); + } + } + return; +} + /* Builds an item with a hip little logged in icon. */ static gboolean new_user_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client) { GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new()); - GtkWidget * hbox = gtk_hbox_new(FALSE, 0); + gint padding = 0; + gtk_widget_style_get(GTK_WIDGET(gmi), "horizontal-padding", &padding, NULL); + GtkWidget * hbox = gtk_hbox_new(FALSE, padding); + + GtkWidget * usericon = NULL; + const gchar * icon_name = dbusmenu_menuitem_property_get(newitem, USER_ITEM_PROP_ICON); + g_debug("Using user icon for '%s' from file: %s", dbusmenu_menuitem_property_get(newitem, USER_ITEM_PROP_NAME), icon_name); + if (icon_name != NULL && icon_name[0] != '\0') { + if (g_strcmp0(icon_name, USER_ITEM_ICON_DEFAULT) == 0 || !g_file_test(icon_name, G_FILE_TEST_EXISTS)) { + GIcon * gicon = g_themed_icon_new_with_default_fallbacks("stock_person-panel"); + usericon = gtk_image_new_from_gicon(gicon, GTK_ICON_SIZE_MENU); + g_object_unref(gicon); + } else { + usericon = gtk_image_new_from_file(icon_name); + } + } + if (usericon != NULL) { + gtk_misc_set_alignment(GTK_MISC(usericon), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(hbox), usericon, FALSE, FALSE, 0); + gtk_widget_show(usericon); + } GtkWidget * label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, USER_ITEM_PROP_NAME)); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); @@ -177,6 +276,8 @@ new_user_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuCl dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent); + g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(user_property_change), icon); + return TRUE; } @@ -233,7 +334,7 @@ switch_property_change (DbusmenuMenuitem * item, const gchar * property, const G /* TODO: We need some way to remove the elipsis from appearing twice in the label. Not sure how to do that yet. */ - finalstring = g_strdup_printf(_("Switch from %s..."), username); + finalstring = g_strdup_printf(_("Switch From %s..."), username); if (ems >= 20.0f) { set_ellipsize = TRUE; } else { @@ -257,6 +358,62 @@ switch_property_change (DbusmenuMenuitem * item, const gchar * property, const G static const gchar * dbusmenu_item_data = "dbusmenu-item"; +/* IF the label or icon changes we need to grab that and update + the menu item */ +static void +restart_property_change (DbusmenuMenuitem * item, const gchar * property, const GValue * value, gpointer user_data) +{ + DbusmenuGtkClient * client = DBUSMENU_GTKCLIENT(user_data); + GtkMenuItem * gmi = dbusmenu_gtkclient_menuitem_get(client, item); + + if (g_strcmp0(property, RESTART_ITEM_LABEL) == 0) { + gtk_menu_item_set_label(gmi, g_value_get_string(value)); + } else if (g_strcmp0(property, RESTART_ITEM_ICON) == 0) { + GtkWidget * image = gtk_image_menu_item_get_image(GTK_IMAGE_MENU_ITEM(gmi)); + + GIcon * gicon = g_themed_icon_new_with_default_fallbacks(g_value_get_string(value)); + if (image == NULL) { + image = gtk_image_new_from_gicon(gicon, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(gmi), image); + } else { + gtk_image_set_from_gicon(GTK_IMAGE(image), gicon, GTK_ICON_SIZE_MENU); + } + g_object_unref(G_OBJECT(gicon)); + } + + return; +} + +/* Builds the restart item which is a more traditional GTK image + menu item that puts the graphic into the gutter. */ +static gboolean +build_restart_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client) +{ + GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_image_menu_item_new()); + if (gmi == NULL) { + return FALSE; + } + + dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent); + + g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(restart_property_change), client); + + /* Grab the inital values and put them into the item */ + const GValue * value; + value = dbusmenu_menuitem_property_get_value(newitem, RESTART_ITEM_LABEL); + if (value != NULL) { + restart_property_change(newitem, RESTART_ITEM_LABEL, value, client); + } + + value = dbusmenu_menuitem_property_get_value(newitem, RESTART_ITEM_ICON); + if (value != NULL) { + restart_property_change(newitem, RESTART_ITEM_ICON, value, client); + } + + return TRUE; +} + + /* Callback for when the style changes so we can reevaluate the size of the user name with the potentially new font. */ static void @@ -269,7 +426,6 @@ switch_style_set (GtkWidget * widget, GtkStyle * prev_style, gpointer user_data) return; } - /* This function checks to see if the user name is short enough to not need ellipsing itself, or if, it will get ellipsed by the standard label processor. */ diff --git a/src/lock-helper.c b/src/lock-helper.c index b38be65..ba6b182 100644 --- a/src/lock-helper.c +++ b/src/lock-helper.c @@ -19,9 +19,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <glib/gi18n.h> +#include <gconf/gconf-client.h> #include <dbus/dbus-glib.h> #include "lock-helper.h" +#define GCONF_DIR "/apps/gnome-screensaver" +#define GCONF_KEY GCONF_DIR "/lock_enabled" + static DBusGProxy * gss_proxy = NULL; static GMainLoop * gss_mainloop = NULL; static guint cookie = 0; @@ -29,6 +34,8 @@ static DBusGProxyCall * cookie_call = NULL; static gboolean is_guest = FALSE; +static GConfClient * gconf_client = NULL; + void build_gss_proxy (void); /* Checks to see if there is an error and reports @@ -124,7 +131,11 @@ will_lock_screen (void) return FALSE; } - return TRUE; + if (gconf_client == NULL) { + gconf_client = gconf_client_get_default(); + } + + return gconf_client_get_bool (gconf_client, GCONF_KEY, NULL); } /* When the screensave go active, if we've got a mainloop @@ -175,24 +186,45 @@ activate_timeout (gpointer data) return FALSE; } +/* Handle errors from activating the screensaver */ +static void +active_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer user_data) +{ + GError * error = NULL; + + dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_INVALID); + + if (error != NULL) { + g_warning("Unable to activate screensaver: %s", error->message); + g_error_free(error); + } + + return; +} + /* A fun little function to actually lock the screen. If, that's what you want, let's do it! */ void lock_screen (DbusmenuMenuitem * mi, guint timestamp, gpointer data) { g_debug("Lock Screen"); - if (!will_lock_screen()) { - g_debug("\tGDM set to autologin, blocking lock"); - return; - } build_gss_proxy(); g_return_if_fail(gss_proxy != NULL); - dbus_g_proxy_call_no_reply(gss_proxy, - "Lock", - G_TYPE_INVALID, - G_TYPE_INVALID); + if (will_lock_screen()) { + dbus_g_proxy_call_no_reply(gss_proxy, + "Lock", + G_TYPE_INVALID, + G_TYPE_INVALID); + } else { + dbus_g_proxy_begin_call(gss_proxy, + "SetActive", + active_cb, NULL, + NULL, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INVALID); + } if (gss_mainloop == NULL) { gss_mainloop = g_main_loop_new(NULL, FALSE); @@ -221,3 +253,53 @@ lock_screen_setup (gpointer data) return FALSE; } +/* When the GConf key changes we need to adjust the text on + what we're going to do with the menu item */ +static void +lockscreen_update (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer data) { + DbusmenuMenuitem * mi = (DbusmenuMenuitem*) data; + const gchar * key = gconf_entry_get_key (entry); + + if(g_strcmp0 (key, GCONF_KEY) == 0) { + if (will_lock_screen()) { + dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Lock Screen")); + } else { + dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Start Screensaver")); + } + } +} + +/* Notification handler for lock menuitems. */ +static guint lock_notify = 0; + +/* Sets the menu item to be updating. There can + only be one. So we clear and reset if we get + another. */ +void +lock_screen_update_item (DbusmenuMenuitem * mi) +{ + if (gconf_client == NULL) { + gconf_client = gconf_client_get_default(); + } + + if (lock_notify == 0) { + gconf_client_add_dir (gconf_client, + GCONF_DIR, + GCONF_CLIENT_PRELOAD_ONELEVEL, + NULL); + } + + if (lock_notify != 0) { + gconf_client_notify_remove(gconf_client, lock_notify); + lock_notify = 0; + } + + lock_notify = gconf_client_notify_add(gconf_client, + GCONF_KEY, + lockscreen_update, + mi, + NULL, + NULL); + + return; +} diff --git a/src/lock-helper.h b/src/lock-helper.h index 37f1448..1d707d8 100644 --- a/src/lock-helper.h +++ b/src/lock-helper.h @@ -31,4 +31,6 @@ gboolean will_lock_screen (void); void lock_screen (DbusmenuMenuitem * mi, guint timestamp, gpointer data); gboolean lock_screen_setup (gpointer data); +void lock_screen_update_item (DbusmenuMenuitem * mi); + #endif /* LOCK_HELPER_H__ */ diff --git a/src/session-dbus.c b/src/session-dbus.c new file mode 100644 index 0000000..20a0fa0 --- /dev/null +++ b/src/session-dbus.c @@ -0,0 +1,139 @@ +/* +The Dbus object on the bus for the indicator. + +Copyright 2010 Canonical Ltd. + +Authors: + Ted Gould <ted@canonical.com> + +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 <http://www.gnu.org/licenses/>. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "session-dbus.h" +#include "dbus-shared-names.h" + +static gboolean _session_dbus_server_get_icon (SessionDbus * service, gchar ** icon, GError ** error); + +#include "session-dbus-server.h" + +typedef struct _SessionDbusPrivate SessionDbusPrivate; +struct _SessionDbusPrivate { + gchar * name; +}; + +/* Signals */ +enum { + ICON_UPDATED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +#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; + + signals[ICON_UPDATED] = g_signal_new ("icon-updated", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SessionDbusClass, icon_updated), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + dbus_g_object_type_install_info(SESSION_DBUS_TYPE, &dbus_glib__session_dbus_server_object_info); + + return; +} + +static void +session_dbus_init (SessionDbus *self) +{ + DBusGConnection * session = dbus_g_bus_get(DBUS_BUS_SESSION, NULL); + dbus_g_connection_register_g_object(session, INDICATOR_SESSION_SERVICE_DBUS_OBJECT, G_OBJECT(self)); + + SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(self); + + priv->name = g_strdup(ICON_DEFAULT); + + return; +} + +static void +session_dbus_dispose (GObject *object) +{ + + G_OBJECT_CLASS (session_dbus_parent_class)->dispose (object); + return; +} + +static void +session_dbus_finalize (GObject *object) +{ + SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(object); + + if (priv->name != NULL) { + g_free(priv->name); + priv->name = NULL; + } + + G_OBJECT_CLASS (session_dbus_parent_class)->finalize (object); + return; +} + +static gboolean +_session_dbus_server_get_icon (SessionDbus * service, gchar ** icon, GError ** error) +{ + SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(service); + *icon = g_strdup(priv->name); + return TRUE; +} + +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) +{ + SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(session); + if (priv->name != NULL) { + g_free(priv->name); + priv->name = NULL; + } + priv->name = g_strdup(name); + g_signal_emit(G_OBJECT(session), signals[ICON_UPDATED], 0, priv->name, TRUE); + return; +} diff --git a/src/session-dbus.h b/src/session-dbus.h new file mode 100644 index 0000000..792917b --- /dev/null +++ b/src/session-dbus.h @@ -0,0 +1,55 @@ +/* +The Dbus object on the bus for the indicator. + +Copyright 2010 Canonical Ltd. + +Authors: + Ted Gould <ted@canonical.com> + +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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef __SESSION_DBUS_H__ +#define __SESSION_DBUS_H__ + +#include <glib.h> +#include <glib-object.h> + +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); + +G_END_DECLS + +#endif diff --git a/src/session-dbus.xml b/src/session-dbus.xml new file mode 100644 index 0000000..3ce1693 --- /dev/null +++ b/src/session-dbus.xml @@ -0,0 +1,15 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/org/ayatana/indicator/session/service"> + <interface name="org.ayatana.indicator.session.service"> + + <!-- Icon --> + <method name="GetIcon"> + <arg name="name" direction="out" type="s"/> + </method> + + <signal name="IconUpdated"> + <arg name="name" type="s"/> + </signal> + + </interface> +</node> diff --git a/src/session-service.c b/src/session-service.c index febf007..c1c2e57 100644 --- a/src/session-service.c +++ b/src/session-service.c @@ -28,6 +28,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib/gi18n.h> #include <gio/gio.h> +#include <gio/gdesktopappinfo.h> #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-bindings.h> @@ -43,17 +44,22 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include "gconf-helper.h" +#include "session-dbus.h" #include "users-service-dbus.h" #include "lock-helper.h" +#include "upower-client.h" #define UP_ADDRESS "org.freedesktop.UPower" #define UP_OBJECT "/org/freedesktop/UPower" #define UP_INTERFACE "org.freedesktop.UPower" +#define DESKTOP_FILE "/usr/share/applications/indicator-session-extra.desktop" + #define GUEST_SESSION_LAUNCHER "/usr/share/gdm/guest-session/guest-session-launch" -#define LOCKDOWN_DIR "/desktop/gnome/lockdown" -#define LOCKDOWN_KEY LOCKDOWN_DIR "/disable_user_switching" +#define LOCKDOWN_DIR "/desktop/gnome/lockdown" +#define LOCKDOWN_KEY_USER LOCKDOWN_DIR "/disable_user_switching" +#define LOCKDOWN_KEY_SCREENSAVER LOCKDOWN_DIR "/disable_lock_screen" typedef struct _ActivateData ActivateData; struct _ActivateData @@ -65,6 +71,7 @@ struct _ActivateData static DBusGConnection *system_bus = NULL; static DBusGProxy *gdm_proxy = NULL; static UsersServiceDbus *dbus_interface = NULL; +static SessionDbus *session_dbus = NULL; static DbusmenuMenuitem *lock_menuitem = NULL; static DbusmenuMenuitem *switch_menuitem = NULL; @@ -83,8 +90,14 @@ static DbusmenuMenuitem * logout_mi = NULL; static DbusmenuMenuitem * restart_mi = NULL; static DbusmenuMenuitem * shutdown_mi = NULL; +static gboolean can_hibernate = TRUE; +static gboolean can_suspend = TRUE; +static gboolean allow_hibernate = TRUE; +static gboolean allow_suspend = TRUE; + static GConfClient * gconf_client = NULL; -static guint notify_lockdown_id = 0; + +static void rebuild_items (DbusmenuMenuitem *root, UsersServiceDbus *service); static void lockdown_changed (GConfClient *client, @@ -92,42 +105,44 @@ lockdown_changed (GConfClient *client, GConfEntry *entry, gpointer user_data) { - GConfValue *value = gconf_entry_get_value (entry); - const gchar *key = gconf_entry_get_key (entry); + GConfValue *value = gconf_entry_get_value (entry); + const gchar *key = gconf_entry_get_key (entry); - if (!value || !key) - return; + if (value == NULL || key == NULL) { + return; + } - if (g_strcmp0 (key, LOCKDOWN_KEY) == 0) - { - if (switch_menuitem) - { - if (gconf_value_get_bool (value)) - { - dbusmenu_menuitem_property_set_bool (switch_menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - } - else - { - dbusmenu_menuitem_property_set_bool (switch_menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - } - } - } + if (g_strcmp0 (key, LOCKDOWN_KEY_USER) == 0 || g_strcmp0 (key, LOCKDOWN_KEY_SCREENSAVER) == 0) { + rebuild_items(root_menuitem, dbus_interface); + } + + return; } +/* Ensures that we have a GConf client and if we build one + set up the signal handler. */ static void ensure_gconf_client (void) { - if (!gconf_client) - { - gconf_client = gconf_client_get_default (); - - notify_lockdown_id = gconf_client_notify_add (gconf_client, - LOCKDOWN_KEY, - lockdown_changed, - NULL, - NULL, - NULL); - } + if (!gconf_client) { + gconf_client = gconf_client_get_default (); + gconf_client_add_dir(gconf_client, LOCKDOWN_DIR, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); + gconf_client_notify_add(gconf_client, LOCKDOWN_DIR, lockdown_changed, NULL, NULL, NULL); + } + return; +} + +/* Check to see if the lockdown key is protecting from + locking the screen. If not, lock it. */ +static void +lock_if_possible (void) { + ensure_gconf_client (); + + if (!gconf_client_get_bool (gconf_client, LOCKDOWN_KEY_SCREENSAVER, NULL)) { + lock_screen(NULL, 0, NULL); + } + + return; } /* A return from the command to sleep the system. Make sure @@ -151,7 +166,7 @@ machine_sleep (DbusmenuMenuitem * mi, guint timestamp, gpointer userdata) } screensaver_throttle(type); - lock_screen(NULL, 0, NULL); + lock_if_possible(); dbus_g_proxy_begin_call(up_main_proxy, type, @@ -179,8 +194,10 @@ suspend_prop_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata) } g_debug("Got Suspend: %s", g_value_get_boolean(&candoit) ? "true" : "false"); - if (suspend_mi != NULL) { - dbusmenu_menuitem_property_set_value(suspend_mi, DBUSMENU_MENUITEM_PROP_VISIBLE, &candoit); + gboolean local_can_suspend = g_value_get_boolean(&candoit); + if (local_can_suspend != can_suspend) { + can_suspend = local_can_suspend; + rebuild_items(root_menuitem, dbus_interface); } return; @@ -202,8 +219,10 @@ hibernate_prop_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata) } g_debug("Got Hibernate: %s", g_value_get_boolean(&candoit) ? "true" : "false"); - if (suspend_mi != NULL) { - dbusmenu_menuitem_property_set_value(hibernate_mi, DBUSMENU_MENUITEM_PROP_VISIBLE, &candoit); + gboolean local_can_hibernate = g_value_get_boolean(&candoit); + if (local_can_hibernate != can_hibernate) { + can_hibernate = local_can_hibernate; + rebuild_items(root_menuitem, dbus_interface); } return; @@ -249,6 +268,25 @@ up_changed_cb (DBusGProxy * proxy, gpointer user_data) return; } +/* Handle the callback from the allow functions to check and + see if we're changing the value, and if so, rebuilding the + menus based on that info. */ +static void +allowed_cb (DBusGProxy *proxy, gboolean OUT_allowed, GError *error, gpointer userdata) +{ + if (error != NULL) { + g_warning("Unable to get information on what is allowed from UPower: %s", error->message); + return; + } + + gboolean * can_do = (gboolean *)userdata; + + if (OUT_allowed != *can_do) { + *can_do = OUT_allowed; + rebuild_items (root_menuitem, dbus_interface); + } +} + /* This function goes through and sets up what we need for DKp checking. We're even setting up the calls for the props we need */ @@ -270,23 +308,31 @@ setup_up (void) { UP_ADDRESS, UP_OBJECT, DBUS_INTERFACE_PROPERTIES); + /* Connect to changed signal */ + dbus_g_proxy_add_signal(up_main_proxy, + "Changed", + G_TYPE_INVALID); + + dbus_g_proxy_connect_signal(up_main_proxy, + "Changed", + G_CALLBACK(up_changed_cb), + NULL, + NULL); } g_return_if_fail(up_prop_proxy != NULL); - /* Connect to changed signal */ - dbus_g_proxy_add_signal(up_main_proxy, - "Changed", - G_TYPE_INVALID); - - dbus_g_proxy_connect_signal(up_main_proxy, - "Changed", - G_CALLBACK(up_changed_cb), - NULL, - NULL); /* Force an original "changed" event */ up_changed_cb(up_main_proxy, NULL); + /* Check to see if these are getting blocked by PolicyKit */ + org_freedesktop_UPower_suspend_allowed_async(up_main_proxy, + allowed_cb, + &allow_suspend); + org_freedesktop_UPower_hibernate_allowed_async(up_main_proxy, + allowed_cb, + &allow_hibernate); + return; } @@ -337,6 +383,16 @@ static void activate_guest_session (DbusmenuMenuitem * mi, guint timestamp, gpointer user_data) { GError * error = NULL; + + lock_if_possible(); + + if (dbusmenu_menuitem_property_get_bool(mi, USER_ITEM_PROP_LOGGED_IN)) { + if (users_service_dbus_activate_guest_session(USERS_SERVICE_DBUS(user_data))) { + return; + } + g_warning("Unable to activate guest session, falling back to command line activation."); + } + if (!g_spawn_command_line_async(GUEST_SESSION_LAUNCHER, &error)) { g_warning("Unable to start guest session: %s", error->message); g_error_free(error); @@ -377,6 +433,9 @@ static void activate_new_session (DbusmenuMenuitem * mi, guint timestamp, gpointer user_data) { GError * error = NULL; + + lock_if_possible(); + if (!g_spawn_command_line_async("gdmflexiserver --startnew", &error)) { g_warning("Unable to start new session: %s", error->message); g_error_free(error); @@ -392,6 +451,8 @@ activate_user_session (DbusmenuMenuitem *mi, guint timestamp, gpointer user_data UserData *user = (UserData *)user_data; UsersServiceDbus *service = user->service; + lock_if_possible(); + users_service_dbus_activate_user_session (service, user); } @@ -415,6 +476,16 @@ compare_users_by_username (const gchar *a, return retval; } +/* Take a desktop file and execute it */ +static void +desktop_activate_cb (DbusmenuMenuitem * mi, guint timestamp, gpointer data) +{ + GAppInfo * appinfo = G_APP_INFO(data); + g_return_if_fail(appinfo != NULL); + g_app_info_launch(appinfo, NULL, NULL, NULL); + return; +} + /* Builds up the menu for us */ static void rebuild_items (DbusmenuMenuitem *root, @@ -425,29 +496,47 @@ rebuild_items (DbusmenuMenuitem *root, GList *u; UserData *user; gboolean can_activate; + gboolean can_lockscreen; GList *children; - can_activate = users_service_dbus_can_activate_session (service); + /* Make sure we have a valid GConf client, and build one + if needed */ + ensure_gconf_client (); + /* Check to see which menu items we're allowed to have */ + can_activate = users_service_dbus_can_activate_session (service) && + !gconf_client_get_bool (gconf_client, LOCKDOWN_KEY_USER, NULL); + can_lockscreen = !gconf_client_get_bool (gconf_client, LOCKDOWN_KEY_SCREENSAVER, NULL); + + /* Remove the old menu items if that makes sense */ children = dbusmenu_menuitem_take_children (root); g_list_foreach (children, (GFunc)g_object_unref, NULL); g_list_free (children); - lock_menuitem = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(lock_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _("Lock Screen")); - g_signal_connect(G_OBJECT(lock_menuitem), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(lock_screen), NULL); - dbusmenu_menuitem_child_append(root, lock_menuitem); - if (!will_lock_screen()) { - dbusmenu_menuitem_property_set_bool(lock_menuitem, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE); - } else { - dbusmenu_menuitem_property_set_bool(lock_menuitem, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE); + /* Lock screen item */ + if (can_lockscreen) { + lock_menuitem = dbusmenu_menuitem_new(); + if (will_lock_screen()) { + dbusmenu_menuitem_property_set(lock_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _("Lock Screen")); + } else { + dbusmenu_menuitem_property_set(lock_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _("Start Screensaver")); + } + g_signal_connect(G_OBJECT(lock_menuitem), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(lock_screen), NULL); + dbusmenu_menuitem_child_append(root, lock_menuitem); + lock_screen_update_item(lock_menuitem); } + /* Set to NULL just incase we don't end up building one */ + users_service_dbus_set_guest_item(service, NULL); + + /* Build all of the user switching items */ if (can_activate == TRUE) { - DbusmenuMenuitem * separator1 = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(separator1, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - dbusmenu_menuitem_child_append(root, separator1); + if (can_lockscreen) { + DbusmenuMenuitem * separator1 = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(separator1, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + dbusmenu_menuitem_child_append(root, separator1); + } if (check_guest_session ()) { @@ -457,26 +546,17 @@ rebuild_items (DbusmenuMenuitem *root, dbusmenu_menuitem_property_set_bool (guest_mi, USER_ITEM_PROP_LOGGED_IN, FALSE); dbusmenu_menuitem_child_append (root, guest_mi); g_signal_connect (G_OBJECT (guest_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_guest_session), NULL); + users_service_dbus_set_guest_item(service, guest_mi); } if (check_new_session ()) { - ensure_gconf_client (); switch_menuitem = dbusmenu_menuitem_new (); dbusmenu_menuitem_property_set (switch_menuitem, DBUSMENU_MENUITEM_PROP_TYPE, MENU_SWITCH_TYPE); dbusmenu_menuitem_property_set (switch_menuitem, MENU_SWITCH_USER, g_get_user_name()); dbusmenu_menuitem_child_append (root, switch_menuitem); g_signal_connect (G_OBJECT (switch_menuitem), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_new_session), NULL); - - if (gconf_client_get_bool (gconf_client, LOCKDOWN_KEY, NULL)) - { - dbusmenu_menuitem_property_set_bool (switch_menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - } - else - { - dbusmenu_menuitem_property_set_bool (switch_menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - } } GList * users = NULL; @@ -521,17 +601,29 @@ rebuild_items (DbusmenuMenuitem *root, dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_NAME, user->real_name); } dbusmenu_menuitem_property_set_bool (mi, USER_ITEM_PROP_LOGGED_IN, user->sessions != NULL); + if (user->icon_url != NULL && user->icon_url[0] != '\0' && g_str_has_prefix(user->icon_url, "file://")) { + dbusmenu_menuitem_property_set(mi, USER_ITEM_PROP_ICON, user->icon_url + strlen("file://")); + } else { + dbusmenu_menuitem_property_set(mi, USER_ITEM_PROP_ICON, USER_ITEM_ICON_DEFAULT); + } dbusmenu_menuitem_child_append (root, mi); g_signal_connect (G_OBJECT (mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_user_session), user); + user->menuitem = mi; } } g_list_free(users); } - DbusmenuMenuitem * separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - dbusmenu_menuitem_child_append(root, separator); + /* If there were a bunch of items before us, we need a + separator. */ + if (can_lockscreen || can_activate) { + DbusmenuMenuitem * separator = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + dbusmenu_menuitem_child_append(root, separator); + } + + /* Start going through the session based items. */ logout_mi = dbusmenu_menuitem_new(); if (supress_confirmations()) { @@ -539,35 +631,39 @@ rebuild_items (DbusmenuMenuitem *root, } else { dbusmenu_menuitem_property_set(logout_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Log Out...")); } + dbusmenu_menuitem_property_set_bool(logout_mi, DBUSMENU_MENUITEM_PROP_VISIBLE, show_logout()); dbusmenu_menuitem_child_append(root, logout_mi); g_signal_connect(G_OBJECT(logout_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(show_dialog), "logout"); - suspend_mi = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set_bool(suspend_mi, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_property_set(suspend_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Sleep")); - dbusmenu_menuitem_child_append(root, suspend_mi); - g_signal_connect(G_OBJECT(suspend_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(machine_sleep), "Suspend"); + if (can_suspend && allow_suspend) { + suspend_mi = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(suspend_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Sleep")); + dbusmenu_menuitem_child_append(root, suspend_mi); + g_signal_connect(G_OBJECT(suspend_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(machine_sleep), "Suspend"); + } - hibernate_mi = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set_bool(hibernate_mi, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_property_set(hibernate_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Hibernate")); - dbusmenu_menuitem_child_append(root, hibernate_mi); - g_signal_connect(G_OBJECT(hibernate_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(machine_sleep), "Hibernate"); + if (can_hibernate && allow_hibernate) { + hibernate_mi = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(hibernate_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Hibernate")); + dbusmenu_menuitem_child_append(root, hibernate_mi); + g_signal_connect(G_OBJECT(hibernate_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(machine_sleep), "Hibernate"); + } restart_mi = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(restart_mi, DBUSMENU_MENUITEM_PROP_TYPE, RESTART_ITEM_TYPE); if (supress_confirmations()) { - dbusmenu_menuitem_property_set(restart_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Restart")); + dbusmenu_menuitem_property_set(restart_mi, RESTART_ITEM_LABEL, _("Restart")); } else { - dbusmenu_menuitem_property_set(restart_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Restart...")); + dbusmenu_menuitem_property_set(restart_mi, RESTART_ITEM_LABEL, _("Restart...")); } dbusmenu_menuitem_child_append(root, restart_mi); g_signal_connect(G_OBJECT(restart_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(show_dialog), "restart"); shutdown_mi = dbusmenu_menuitem_new(); if (supress_confirmations()) { - dbusmenu_menuitem_property_set(shutdown_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Switch Off")); + dbusmenu_menuitem_property_set(shutdown_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Shut Down")); } else { - dbusmenu_menuitem_property_set(shutdown_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Switch Off...")); + dbusmenu_menuitem_property_set(shutdown_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Shut Down...")); } dbusmenu_menuitem_child_append(root, shutdown_mi); g_signal_connect(G_OBJECT(shutdown_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(show_dialog), "shutdown"); @@ -577,7 +673,22 @@ rebuild_items (DbusmenuMenuitem *root, restart_shutdown_logout_mi->restart_mi = restart_mi; restart_shutdown_logout_mi->shutdown_mi = shutdown_mi; - update_menu_entries(restart_shutdown_logout_mi); + update_menu_entries(restart_shutdown_logout_mi, logout_mi); + + if (g_file_test(DESKTOP_FILE, G_FILE_TEST_EXISTS)) { + GAppInfo * appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(DESKTOP_FILE)); + + if (appinfo != NULL) { + DbusmenuMenuitem * separator = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + dbusmenu_menuitem_child_append(root, separator); + + DbusmenuMenuitem * desktop_mi = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(desktop_mi, DBUSMENU_MENUITEM_PROP_LABEL, g_app_info_get_name(appinfo)); + g_signal_connect(G_OBJECT(desktop_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(desktop_activate_cb), appinfo); + dbusmenu_menuitem_child_append(root, desktop_mi); + } + } return; } @@ -615,18 +726,24 @@ restart_dir_changed (void) if (restart_required) { if (supress_confirmations()) { - dbusmenu_menuitem_property_set(restart_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Restart Required")); + dbusmenu_menuitem_property_set(restart_mi, RESTART_ITEM_LABEL, _("Restart Required")); } else { - dbusmenu_menuitem_property_set(restart_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Restart Required...")); + dbusmenu_menuitem_property_set(restart_mi, RESTART_ITEM_LABEL, _("Restart Required...")); + } + dbusmenu_menuitem_property_set(restart_mi, RESTART_ITEM_ICON, "system-restart-panel"); + if (session_dbus != NULL) { + session_dbus_set_name(session_dbus, ICON_RESTART); } - dbusmenu_menuitem_property_set(restart_mi, DBUSMENU_MENUITEM_PROP_ICON_NAME, "emblem-important"); } else { if (supress_confirmations()) { - dbusmenu_menuitem_property_set(restart_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Restart")); + dbusmenu_menuitem_property_set(restart_mi, RESTART_ITEM_LABEL, _("Restart")); } else { - dbusmenu_menuitem_property_set(restart_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Restart...")); + dbusmenu_menuitem_property_set(restart_mi, RESTART_ITEM_LABEL, _("Restart...")); + } + dbusmenu_menuitem_property_remove(restart_mi, RESTART_ITEM_ICON); + if (session_dbus != NULL) { + session_dbus_set_name(session_dbus, ICON_DEFAULT); } - dbusmenu_menuitem_property_remove(restart_mi, DBUSMENU_MENUITEM_PROP_ICON_NAME); } return; @@ -666,6 +783,8 @@ main (int argc, char ** argv) INDICATOR_SERVICE_SIGNAL_SHUTDOWN, G_CALLBACK(service_shutdown), NULL); + session_dbus = session_dbus_new(); + g_idle_add(lock_screen_setup, NULL); root_menuitem = dbusmenu_menuitem_new(); diff --git a/src/upower.xml b/src/upower.xml new file mode 100644 index 0000000..a4066ff --- /dev/null +++ b/src/upower.xml @@ -0,0 +1,309 @@ +<!DOCTYPE node PUBLIC +"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> + + <interface name="org.freedesktop.UPower"> + <doc:doc> + <doc:description> + <doc:para> + The DeviceKit-power service is available via the system message + bus. To access the service, use + the <doc:tt>org.freedesktop.UPower</doc:tt> interface on + the <doc:tt>/org/freedesktop/UPower</doc:tt> object on + the D-Bus system bus service with the well-known + name <doc:tt>org.freedesktop.UPower</doc:tt>. + </doc:para> + <doc:para> + <doc:example language="shell" title="simple example"> + <doc:code> +$ 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" + ] + </doc:code> + </doc:example> + </doc:para> + </doc:description> + </doc:doc> + + <!-- ************************************************************ --> + + <method name="EnumerateDevices"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="devices" direction="out" type="ao"> + <doc:doc><doc:summary>An array of object paths for devices.</doc:summary></doc:doc> + </arg> + + <doc:doc> + <doc:description> + <doc:para> + Enumerate all power objects on the system. + </doc:para> + </doc:description> + </doc:doc> + </method> + + <!-- ************************************************************ --> + + <signal name="DeviceAdded"> + <arg name="device" type="o"> + <doc:doc><doc:summary>Object path of device that was added.</doc:summary></doc:doc> + </arg> + + <doc:doc> + <doc:description> + <doc:para> + Emitted when a device is added. + </doc:para> + </doc:description> + </doc:doc> + </signal> + + <!-- ************************************************************ --> + + <signal name="DeviceRemoved"> + <arg name="device" type="o"> + <doc:doc><doc:summary>Object path of device that was removed.</doc:summary></doc:doc> + </arg> + + <doc:doc> + <doc:description> + <doc:para> + Emitted when a device is removed. + </doc:para> + </doc:description> + </doc:doc> + </signal> + + <!-- ************************************************************ --> + + <signal name="DeviceChanged"> + <arg name="device" type="o"> + <doc:doc><doc:summary>Object path of device that was changed.</doc:summary></doc:doc> + </arg> + + <doc:doc> + <doc:description> + <doc:para> + Emitted when a device changed. + </doc:para> + </doc:description> + </doc:doc> + </signal> + + <!-- ************************************************************ --> + + <signal name="Changed"> + <doc:doc> + <doc:description> + <doc:para> + Emitted when one or more properties on the object changes. + </doc:para> + </doc:description> + </doc:doc> + </signal> + + <!-- ************************************************************ --> + + <signal name="Sleeping"> + <doc:doc> + <doc:description> + <doc:para> + 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). + </doc:para> + </doc:description> + </doc:doc> + </signal> + + <!-- ************************************************************ --> + + <signal name="Resuming"> + <doc:doc> + <doc:description> + <doc:para> + 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). + </doc:para> + </doc:description> + </doc:doc> + </signal> + + <!-- ************************************************************ --> + + <method name="AboutToSleep"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + 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. + </doc:para> + <doc:para> + 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. + </doc:para> + <doc:para> + If this method is not called than nothing bad will happen and + Suspend() or Hibernate() will block for the required second. + </doc:para> + </doc:description> + </doc:doc> + </method> + + <!-- ************************************************************ --> + + <method name="Suspend"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Suspends the computer into a low power state. + System state is not preserved if the power is lost. + </doc:para> + <doc:para> + If AboutToRequestSleep() has not been called then UPower will send + the Sleeping() signal and block for one second. + </doc:para> + <doc:para> + 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. + </doc:para> + </doc:description> + </doc:doc> + </method> + + <!-- ************************************************************ --> + + <method name="SuspendAllowed"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="allowed" direction="out" type="b"> + <doc:doc><doc:summary>TRUE if allowed, otherwise FALSE</doc:summary></doc:doc> + </arg> + <doc:doc> + <doc:description> + <doc:para> + Check if the caller has (or can get) the PolicyKit privilege to call + <doc:ref type="method" to="Power.Suspend">Suspend</doc:ref>. + </doc:para> + </doc:description> + </doc:doc> + </method> + + <!-- ************************************************************ --> + + <method name="Hibernate"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Hibernates the computer into a low power state. + System state is preserved if the power is lost. + </doc:para> + <doc:para> + If AboutToRequestSleep() has not been called then UPower will send + the Sleeping() signal and block for one second. + </doc:para> + <doc:para> + 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. + </doc:para> + </doc:description> + </doc:doc> + </method> + + <!-- ************************************************************ --> + + <method name="HibernateAllowed"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="allowed" direction="out" type="b"> + <doc:doc><doc:summary>TRUE if allowed, otherwise FALSE</doc:summary></doc:doc> + </arg> + <doc:doc> + <doc:description> + <doc:para> + Check if the caller has (or can get) the PolicyKit privilege to call + <doc:ref type="method" to="Power.Hibernate">Hibernate</doc:ref>. + </doc:para> + </doc:description> + </doc:doc> + </method> + + <!-- ************************************************************ --> + + <property name="DaemonVersion" type="s" access="read"> + <doc:doc><doc:description><doc:para> + Version of the running daemon, e.g. <doc:tt>002</doc:tt>. + </doc:para></doc:description></doc:doc> + </property> + + <property name="CanSuspend" type="b" access="read"> + <doc:doc><doc:description><doc:para> + Whether the system is able to suspend. + </doc:para></doc:description></doc:doc> + </property> + + <property name="CanHibernate" type="b" access="read"> + <doc:doc><doc:description><doc:para> + Whether the system is able to hibernate. + </doc:para></doc:description></doc:doc> + </property> + + <property name="OnBattery" type="b" access="read"> + <doc:doc><doc:description><doc:para> + Indicates whether the system is running on battery power. + This property is provided for convenience. + </doc:para></doc:description></doc:doc> + </property> + + <property name="OnLowBattery" type="b" access="read"> + <doc:doc><doc:description><doc:para> + Indicates whether the system is running on battery power and if the battery is critically low. + This property is provided for convenience. + </doc:para></doc:description></doc:doc> + </property> + + <property name="LidIsClosed" type="b" access="read"> + <doc:doc> + <doc:description> + <doc:para> + Indicates if the laptop lid is closed where the display cannot be seen. + </doc:para> + </doc:description> + </doc:doc> + </property> + + <property name="LidIsPresent" type="b" access="read"> + <doc:doc> + <doc:description> + <doc:para> + If the system has a lid device. + </doc:para> + </doc:description> + </doc:doc> + </property> + + </interface> + +</node> diff --git a/src/users-service-dbus.c b/src/users-service-dbus.c index 4aefdff..86007c3 100644 --- a/src/users-service-dbus.c +++ b/src/users-service-dbus.c @@ -31,10 +31,16 @@ #include <dbus/dbus-glib-lowlevel.h> #include "dbus-shared-names.h" +#include "gdm-local-display-factory-client.h" #include "users-service-dbus.h" #include "users-service-client.h" #include "users-service-marshal.h" #include "consolekit-manager-client.h" +#include "consolekit-session-client.h" + +#define CK_ADDR "org.freedesktop.ConsoleKit" +#define CK_SESSION_IFACE "org.freedesktop.ConsoleKit.Session" + static void users_service_dbus_class_init (UsersServiceDbusClass *klass); static void users_service_dbus_init (UsersServiceDbus *self); @@ -65,7 +71,7 @@ static void seat_proxy_session_removed (DBusGProxy *seat_ static gboolean do_add_session (UsersServiceDbus *service, UserData *user, const gchar *ssid); -static gchar * get_seat_internal (UsersServiceDbus *self); +static gchar * get_seat_internal (DBusGProxy *proxy); /* Private */ typedef struct _UsersServiceDbusPrivate UsersServiceDbusPrivate; @@ -80,12 +86,16 @@ struct _UsersServiceDbusPrivate DBusGConnection *system_bus; DBusGProxy *gdm_proxy; + DBusGProxy *gdm_local_proxy; DBusGProxy *ck_proxy; DBusGProxy *seat_proxy; DBusGProxy *session_proxy; GHashTable *exclusions; GHashTable *sessions; + + DbusmenuMenuitem * guest_item; + gchar * guest_session_id; }; #define USERS_SERVICE_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USERS_SERVICE_DBUS_TYPE, UsersServiceDbusPrivate)) @@ -155,6 +165,8 @@ users_service_dbus_init (UsersServiceDbus *self) priv->users = NULL; priv->count = 0; + priv->guest_item = NULL; + priv->guest_session_id = NULL; /* Get the system bus */ priv->system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); @@ -198,6 +210,13 @@ users_service_dbus_dispose (GObject *object) static void users_service_dbus_finalize (GObject *object) { + UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (object); + + if (priv->guest_session_id != NULL) { + g_free(priv->guest_session_id); + priv->guest_session_id = NULL; + } + G_OBJECT_CLASS (users_service_dbus_parent_class)->finalize (object); } @@ -266,6 +285,11 @@ create_gdm_proxy (UsersServiceDbus *self) G_CALLBACK (user_updated), self, NULL); + + priv->gdm_local_proxy = dbus_g_proxy_new_for_name (priv->system_bus, + "org.gnome.DisplayManager", + "/org/gnome/DisplayManager/LocalDisplayFactory", + "org.gnome.DisplayManager.LocalDisplayFactory"); } static void @@ -341,9 +365,9 @@ create_cksession_proxy (UsersServiceDbus *service) UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service); priv->session_proxy = dbus_g_proxy_new_for_name (priv->system_bus, - "org.freedesktop.ConsoleKit", + CK_ADDR, priv->ssid, - "org.freedesktop.ConsoleKit.Session"); + CK_SESSION_IFACE); if (!priv->session_proxy) { @@ -383,24 +407,18 @@ get_seat (UsersServiceDbus *service) priv->ssid = ssid; create_cksession_proxy (service); - seat = get_seat_internal (service); + seat = get_seat_internal (priv->session_proxy); return seat; } static gchar * -get_seat_internal (UsersServiceDbus *self) +get_seat_internal (DBusGProxy *proxy) { - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); GError *error = NULL; gchar *seat = NULL; - if (!dbus_g_proxy_call (priv->session_proxy, - "GetSeatId", - &error, - G_TYPE_INVALID, - DBUS_TYPE_G_OBJECT_PATH, &seat, - G_TYPE_INVALID)) + if (!org_freedesktop_ConsoleKit_Session_get_seat_id (proxy, &seat, &error)) { if (error) { @@ -421,13 +439,22 @@ get_unix_user (UsersServiceDbus *service, UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service); GError *error = NULL; guint uid; + DBusGProxy *session_proxy; + + g_debug("Building session proxy for: %s", session_id); + session_proxy = dbus_g_proxy_new_for_name_owner(priv->system_bus, + CK_ADDR, + session_id, + CK_SESSION_IFACE, + &error); + + if (error != NULL) { + g_warning("Unable to get CK Session proxy: %s", error->message); + g_error_free(error); + return FALSE; + } - if (dbus_g_proxy_call (priv->session_proxy, - "GetUnixUser", - &error, - G_TYPE_INVALID, - G_TYPE_UINT, &uid, - G_TYPE_INVALID)) + if (!org_freedesktop_ConsoleKit_Session_get_unix_user(session_proxy, &uid, &error)) { if (error) { @@ -435,6 +462,7 @@ get_unix_user (UsersServiceDbus *service, g_error_free (error); } + g_object_unref(session_proxy); return FALSE; } @@ -443,6 +471,7 @@ get_unix_user (UsersServiceDbus *service, *uidp = (uid_t)uid; } + g_object_unref(session_proxy); return TRUE; } @@ -455,19 +484,29 @@ do_add_session (UsersServiceDbus *service, GError *error = NULL; gchar *seat = NULL; gchar *xdisplay = NULL; + DBusGProxy * session_proxy; GList *l; - seat = get_seat_internal (service); + session_proxy = dbus_g_proxy_new_for_name_owner(priv->system_bus, + CK_ADDR, + ssid, + CK_SESSION_IFACE, + &error); - if (!seat || !priv->seat || strcmp (seat, priv->seat) != 0) + if (error != NULL) { + g_warning("Unable to get CK Session proxy: %s", error->message); + g_error_free(error); return FALSE; + } - if (!dbus_g_proxy_call (priv->session_proxy, - "GetX11Display", - &error, - G_TYPE_INVALID, - G_TYPE_STRING, &xdisplay, - G_TYPE_INVALID)) + seat = get_seat_internal (session_proxy); + + if (!seat || !priv->seat || strcmp (seat, priv->seat) != 0) { + g_object_unref(session_proxy); + return FALSE; + } + + if (!org_freedesktop_ConsoleKit_Session_get_x11_display (session_proxy, &xdisplay, &error)) { if (error) { @@ -475,9 +514,12 @@ do_add_session (UsersServiceDbus *service, g_error_free (error); } + g_object_unref(session_proxy); return FALSE; } + g_object_unref(session_proxy); + if (!xdisplay || xdisplay[0] == '\0') return FALSE; @@ -491,6 +533,10 @@ do_add_session (UsersServiceDbus *service, g_debug ("Adding session %s", ssid); user->sessions = g_list_prepend (user->sessions, g_strdup (ssid)); + + if (user->menuitem != NULL) { + dbusmenu_menuitem_property_set_bool(user->menuitem, USER_ITEM_PROP_LOGGED_IN, TRUE); + } } else { @@ -556,6 +602,17 @@ seat_proxy_session_added (DBusGProxy *seat_proxy, return; } + /* We need to special case guest here because it doesn't + show up in the GDM user tables. */ + if (g_strcmp0("guest", pwent->pw_name) == 0) { + if (priv->guest_item != NULL) { + dbusmenu_menuitem_property_set_bool(priv->guest_item, USER_ITEM_PROP_LOGGED_IN, TRUE); + } + priv->guest_session_id = g_strdup(session_id); + g_debug("Found guest session: %s", priv->guest_session_id); + return; + } + user = g_hash_table_lookup (priv->users, pwent->pw_name); if (!user) { @@ -576,8 +633,17 @@ seat_proxy_session_removed (DBusGProxy *seat_proxy, GList *l; username = g_hash_table_lookup (priv->sessions, session_id); - if (!username) + if (!username) { + if (g_strcmp0(session_id, priv->guest_session_id) == 0) { + g_debug("Removing guest session: %s", priv->guest_session_id); + if (priv->guest_item != NULL) { + dbusmenu_menuitem_property_set_bool(priv->guest_item, USER_ITEM_PROP_LOGGED_IN, FALSE); + } + g_free(priv->guest_session_id); + priv->guest_session_id = NULL; + } return; + } user = g_hash_table_lookup (priv->users, username); if (!user) @@ -592,6 +658,9 @@ seat_proxy_session_removed (DBusGProxy *seat_proxy, g_free (l->data); user->sessions = g_list_delete_link (user->sessions, l); + if (user->menuitem != NULL && user->sessions == NULL) { + dbusmenu_menuitem_property_set_bool(user->menuitem, USER_ITEM_PROP_LOGGED_IN, FALSE); + } } else { @@ -657,6 +726,7 @@ sync_users (UsersServiceDbus *self) user->login_count = g_value_get_int (g_value_array_get_nth (values, 4)); user->icon_url = g_strdup (g_value_get_string (g_value_array_get_nth (values, 5))); user->real_name_conflict = FALSE; + user->menuitem = NULL; g_hash_table_insert (priv->users, g_strdup (user->user_name), @@ -706,21 +776,16 @@ session_is_login_window (UsersServiceDbus *self, char *type = NULL; if (!(proxy = dbus_g_proxy_new_for_name (priv->system_bus, - "org.freedesktop.ConsoleKit", + CK_ADDR, ssid, - "org.freedesktop.ConsoleKit.Session"))) + CK_SESSION_IFACE))) { g_warning ("Failed to get ConsoleKit proxy"); return FALSE; } - if (!dbus_g_proxy_call (proxy, - "GetSessionType", - &error, - G_TYPE_INVALID, - G_TYPE_STRING, &type, - G_TYPE_INVALID)) + if (!org_freedesktop_ConsoleKit_Session_get_session_type (proxy, &type, &error)) { g_warning ("Can't call GetSessionType: %s", error->message); g_error_free (error); @@ -1005,61 +1070,21 @@ users_service_dbus_get_user_list (UsersServiceDbus *self) return g_hash_table_get_values (priv->users); } +/* Activates the guest account if it can. */ +gboolean +users_service_dbus_activate_guest_session (UsersServiceDbus *self) +{ + UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); + return org_gnome_DisplayManager_LocalDisplayFactory_switch_to_user(priv->gdm_local_proxy, "guest", NULL, NULL); +} + +/* Activates a specific user */ gboolean users_service_dbus_activate_user_session (UsersServiceDbus *self, UserData *user) { - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - DBusMessage *message = NULL; - DBusMessage *reply = NULL; - DBusError error; - - dbus_error_init (&error); - - if (!(message = dbus_message_new_method_call ("org.gnome.DisplayManager", - "/org/gnome/DisplayManager/LocalDisplayFactory", - "org.gnome.DisplayManager.LocalDisplayFactory", - "SwitchToUser"))) - { - g_warning ("failed to create new message"); - return FALSE; - } - - if (!dbus_message_append_args (message, - DBUS_TYPE_STRING, &user->user_name, - DBUS_TYPE_INVALID)) - { - g_warning ("failed to append args"); - return FALSE; - } - - if (!(reply = dbus_connection_send_with_reply_and_block (dbus_g_connection_get_connection (priv->system_bus), - message, - -1, - &error))) - { - if (dbus_error_is_set (&error)) - { - g_warning ("Failed to send message: %s", error.message); - dbus_error_free (&error); - - return FALSE; - } - } - - if (message) - { - dbus_message_unref (message); - } - - if (reply) - { - dbus_message_unref (reply); - } - - dbus_error_free (&error); - - return TRUE; + UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); + return org_gnome_DisplayManager_LocalDisplayFactory_switch_to_user(priv->gdm_local_proxy, user->user_name, NULL, NULL); } gboolean @@ -1094,3 +1119,17 @@ users_service_dbus_can_activate_session (UsersServiceDbus *self) return can_activate; } + +/* Sets the menu item that represents the guest account */ +void +users_service_dbus_set_guest_item (UsersServiceDbus * self, DbusmenuMenuitem * mi) +{ + UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); + priv->guest_item = mi; + + if (priv->guest_session_id != NULL) { + dbusmenu_menuitem_property_set_bool(priv->guest_item, USER_ITEM_PROP_LOGGED_IN, TRUE); + } + + return; +} diff --git a/src/users-service-dbus.h b/src/users-service-dbus.h index bba88a7..4798d64 100644 --- a/src/users-service-dbus.h +++ b/src/users-service-dbus.h @@ -22,6 +22,7 @@ #include <glib.h> #include <glib-object.h> +#include <libdbusmenu-glib/menuitem.h> G_BEGIN_DECLS @@ -47,7 +48,10 @@ struct _UserData GList *sessions; + /* Whether the real name here conflicts with another in the system */ gboolean real_name_conflict; + /* The menuitem representing this user if there is one. */ + DbusmenuMenuitem * menuitem; UsersServiceDbus *service; }; @@ -80,6 +84,9 @@ GList *users_service_dbus_get_user_list (UsersServiceDbus *self); gboolean users_service_dbus_can_activate_session (UsersServiceDbus *self); gboolean users_service_dbus_activate_user_session (UsersServiceDbus *self, UserData *user); +gboolean users_service_dbus_activate_guest_session (UsersServiceDbus *self); +void users_service_dbus_set_guest_item (UsersServiceDbus * self, + DbusmenuMenuitem * mi); G_END_DECLS |