gnome-session r5377 - in trunk: . gnome-session



Author: vuntz
Date: Wed Apr  8 13:42:27 2009
New Revision: 5377
URL: http://svn.gnome.org/viewvc/gnome-session?rev=5377&view=rev

Log:
2009-04-08  Vincent Untz  <vuntz gnome org>

	Make reboot and shutdown leave the session properly, by letting apps
	exit before doing the real reboot/shutdown.

	Note that because of the ConsoleKit policies, the ways it's handled
	when there are more than one user logged in or when the policy always
	require a password might be a bit different:
	 - in the usual case (single user, no password required), everything
	   works as expected.
	 - in the multiple users case (password generally required once), we
	   ask for the password before trying to exit the session.
	 - if the password is required each time the ConsoleKit action is
	   called, then we'll ask for the password only once, after having made
	   all apps exit. If this doesn't work (wrong password), since the
	   session is killed anyway, we log out and ask gdm to do the action.

	* gnome-session/gsm-marshal.list: add new signature that we need
	* gnome-session/gsm-consolekit.[ch]: add new privileges-completed
	signal
	(gsm_consolekit_class_init): add new signal
	(gsm_consolekit_get_result_for_action): new, split from
	gsm_consolekit_can_do_action()
	(gsm_consolekit_can_do_action): ensure that the CK connection works
	here (instead of requiring callers to do it), and use
	gsm_consolekit_get_result_for_action()
	(gsm_consolekit_is_session_for_other_user): new, ask ConsoleKit if a
	session object is for a different user than the current user (ignoring
	the login sessions)
	(gsm_consolekit_is_single_user): new, determine if there's only a
	single user logged in on this machine
	(obtain_privileges_cb): new, PolicyKit callback when the privileges
	were obtained/denied, to send the privileges-completed signal
	(gsm_consolekit_obtain_privileges_for_action): new, obtain the
	PolicyKit privileges for a specific action
	(gsm_consolekit_get_privileges_for_actions): new, to know if we have
	privileges for a set of actions, and request the privileges if needed
	(gsm_consolekit_get_restart_privileges): new, trivial
	(gsm_consolekit_get_stop_privileges): new, trivial
	(gsm_consolekit_can_restart): do not ensure that the CK connection
	works here, it will be done in gsm_consolekit_can_do_action()
	(gsm_consolekit_can_stop): ditto

	* gnome-session/gsm-manager.c: we add a logout type variable that lets
	us remember what should be done when gnome-session exits.
	(quit_request_completed): new, callback that will make gnome-session
	exit after the ConsoleKit call to Stop/Restart has been done. If the
	ConsoleKit call wasn't successful, we fallback on gdm (since we're in
	the EXIT phase, and all apps have quitted, there's no point in not
	asking gdm to do that).
	(gsm_manager_quit): new, to do the right thing to log out depending on
	what the user wanted to achieve when logging out.
	(end_phase): use gsm_manager_quit() instead of directly calling
	gtk_main_quit()
	(cancel_end_session): reset the logout type to none
	(do_attempt_reboot), (do_attempt_shutdown), (manager_attempt_reboot),
	(manager_attempt_shutdown): killed/merged in
	request_reboot/request_shutdown
	(do_inhibit_dialog_action): renamed from do_dialog_action(); for
	shutdown and reboot, we just do like logout and end the phase.
	(inhibit_dialog_response): s/do_dialog_action/do_inhibit_dialog_action
	(query_end_session_complete): add a comment about
	gsm_inhibit_dialog_new to make it clear that the
	GSM_LOGOUT_ACTION_LOGOUT parameter is fine for shutdown and reboot too
	(request_reboot_privileges_completed): new, handle the fact that we got
	the privileges from ConsoleKit to do the reboot.
	(request_reboot): ask ConsoleKit for the privileges to reboot, and if
	it doesn't work (no ConsoleKit), just end the phase
	(request_shutdown_privileges_completed), (request_shutdown): see above
	changes for reboot functions
	(request_logout): set the logout type


Modified:
   trunk/ChangeLog
   trunk/gnome-session/gsm-consolekit.c
   trunk/gnome-session/gsm-consolekit.h
   trunk/gnome-session/gsm-manager.c
   trunk/gnome-session/gsm-marshal.list

Modified: trunk/gnome-session/gsm-consolekit.c
==============================================================================
--- trunk/gnome-session/gsm-consolekit.c	(original)
+++ trunk/gnome-session/gsm-consolekit.c	Wed Apr  8 13:42:27 2009
@@ -35,6 +35,7 @@
 #include <polkit-gnome/polkit-gnome.h>
 #endif
 
+#include "gsm-marshal.h"
 #include "gsm-consolekit.h"
 
 #define CK_NAME      "org.freedesktop.ConsoleKit"
@@ -64,6 +65,7 @@
 
 enum {
         REQUEST_COMPLETED = 0,
+        PRIVILEGES_COMPLETED,
         LAST_SIGNAL
 };
 
@@ -133,6 +135,17 @@
                               G_TYPE_NONE,
                               1, G_TYPE_POINTER);
 
+        signals [PRIVILEGES_COMPLETED] =
+                g_signal_new ("privileges-completed",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GsmConsolekitClass, privileges_completed),
+                              NULL,
+                              NULL,
+                              gsm_marshal_VOID__BOOLEAN_BOOLEAN_POINTER,
+                              G_TYPE_NONE,
+                              3, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_POINTER);
+
         g_type_class_add_private (manager_class, sizeof (GsmConsolekitPrivate));
 }
 
@@ -889,9 +902,9 @@
 }
 
 #ifdef HAVE_POLKIT_GNOME
-static gboolean
-gsm_consolekit_can_do_action (GsmConsolekit *manager,
-                              const char    *action_id)
+static PolKitResult
+gsm_consolekit_get_result_for_action (GsmConsolekit *manager,
+                                      const char    *action_id)
 {
         PolKitGnomeContext *gnome_context;
         PolKitAction *action;
@@ -903,11 +916,11 @@
         gnome_context = polkit_gnome_context_get (NULL);
 
         if (gnome_context == NULL) {
-                return FALSE;
+                return POLKIT_RESULT_UNKNOWN;
         }
 
         if (gnome_context->pk_tracker == NULL) {
-                return FALSE;
+                return POLKIT_RESULT_UNKNOWN;
         }
 
         dbus_error_init (&dbus_error);
@@ -917,17 +930,16 @@
         dbus_error_free (&dbus_error);
 
         if (caller == NULL) {
-                return FALSE;
+                return POLKIT_RESULT_UNKNOWN;
         }
 
         action = polkit_action_new ();
         if (!polkit_action_set_action_id (action, action_id)) {
                 polkit_action_unref (action);
                 polkit_caller_unref (caller);
-                return FALSE;
+                return POLKIT_RESULT_UNKNOWN;
         }
 
-        result = POLKIT_RESULT_UNKNOWN;
         error = NULL;
         result = polkit_context_is_caller_authorized (gnome_context->pk_context,
                                                       action, caller, FALSE,
@@ -936,18 +948,196 @@
                 polkit_error_free (error);
         }
         polkit_action_unref (action);
-                polkit_caller_unref (caller);
+        polkit_caller_unref (caller);
+
+        return result;
+}
+
+static gboolean
+gsm_consolekit_can_do_action (GsmConsolekit *manager,
+                              const char    *action_id)
+{
+        PolKitResult  result;
+        gboolean      res;
+        GError       *error;
+
+        error = NULL;
+        res = gsm_consolekit_ensure_ck_connection (manager, &error);
+        if (!res) {
+                g_warning ("Could not connect to ConsoleKit: %s",
+                           error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        result = gsm_consolekit_get_result_for_action (manager, action_id);
 
         return result != POLKIT_RESULT_NO && result != POLKIT_RESULT_UNKNOWN;
 }
-#endif
 
-gboolean
-gsm_consolekit_can_restart (GsmConsolekit *manager)
+static gboolean
+gsm_consolekit_is_session_for_other_user (GsmConsolekit *manager,
+                                          const char    *object_path,
+                                          unsigned int   current_uid)
+{
+        DBusGProxy    *proxy;
+        gboolean       res;
+        char          *type;
+        unsigned int   uid;
+
+        proxy = dbus_g_proxy_new_for_name (manager->priv->dbus_connection,
+                                           CK_NAME,
+                                           object_path,
+                                           CK_SESSION_INTERFACE);
+
+        res = dbus_g_proxy_call_with_timeout (proxy,
+                                              "GetUnixUser",
+                                              INT_MAX,
+                                              NULL,
+                                              /* parameters: */
+                                              G_TYPE_INVALID,
+                                              /* return values: */
+                                              G_TYPE_UINT, &uid,
+                                              G_TYPE_INVALID);
+
+        /* error is bad: we consider there's another user */
+        if (!res)
+                return TRUE;
+
+        if (uid == current_uid)
+                return FALSE;
+
+        /* filter out login sessions */
+        res = dbus_g_proxy_call_with_timeout (proxy,
+                                              "GetSessionType",
+                                              INT_MAX,
+                                              NULL,
+                                              /* parameters: */
+                                              G_TYPE_INVALID,
+                                              /* return values: */
+                                              G_TYPE_STRING, &type,
+                                              G_TYPE_INVALID);
+
+        /* error is bad: we consider there's another user */
+        if (!res)
+                return TRUE;
+
+        if (g_strcmp0 (type, GSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW) == 0) {
+                g_free (type);
+                return FALSE;
+        }
+
+        g_free (type);
+
+        return TRUE;
+}
+
+static gboolean
+gsm_consolekit_is_single_user (GsmConsolekit *manager)
 {
-#ifdef HAVE_POLKIT_GNOME
-        gboolean res;
-        GError  *error;
+        DBusGProxy   *proxy;
+        GError       *error;
+        gboolean      res;
+        gboolean      single;
+        GPtrArray    *array;
+        unsigned int  current_uid;
+        int           i;
+
+        /* We use the same logic than the one used by ConsoleKit here -- it'd
+         * be nice to have a ConsoleKit API to help us, but well...
+         * If there's any error, we just assume it's multiple users. */
+
+        proxy = dbus_g_proxy_new_for_name (manager->priv->dbus_connection,
+                                           CK_NAME,
+                                           CK_MANAGER_PATH,
+                                           CK_MANAGER_INTERFACE);
+
+        error = NULL;
+        res = dbus_g_proxy_call_with_timeout (proxy,
+                                              "GetSessions",
+                                              INT_MAX,
+                                              &error,
+                                              /* parameters: */
+                                              G_TYPE_INVALID,
+                                              /* return values: */
+                                              dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &array,
+                                              G_TYPE_INVALID);
+
+        if (!res) {
+                g_warning ("Unable to list sessions: %s", error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        single = TRUE;
+        current_uid = getuid ();
+
+        for (i = 0; i < array->len; i++) {
+                char *object_path;
+
+                object_path = g_ptr_array_index (array, i);
+
+                if (gsm_consolekit_is_session_for_other_user (manager,
+                                                              object_path,
+                                                              current_uid)) {
+                        single = FALSE;
+                        break;
+                }
+        }
+
+        g_ptr_array_foreach (array, (GFunc) g_free, NULL);
+        g_ptr_array_free (array, TRUE);
+
+        return single;
+}
+
+static void
+obtain_privileges_cb (PolKitAction  *action,
+                      gboolean       gained_privilege,
+                      GError        *error,
+                      GsmConsolekit *manager)
+{
+        g_signal_emit (G_OBJECT (manager),
+                       signals [PRIVILEGES_COMPLETED],
+                       0, gained_privilege, FALSE, error);
+}
+
+static gboolean
+gsm_consolekit_obtain_privileges_for_action (GsmConsolekit *manager,
+                                             const char    *action_id)
+{
+        PolKitAction *action;
+        pid_t         pid;
+        guint         xid;
+        gboolean      res;
+
+        action = polkit_action_new ();
+        polkit_action_set_action_id (action, action_id);
+
+        xid = 0;
+        pid = getpid ();
+
+        res = polkit_gnome_auth_obtain (action,
+                                        xid,
+                                        pid,
+                                        (PolKitGnomeAuthCB) obtain_privileges_cb,
+                                        manager,
+                                        NULL);
+
+        polkit_action_unref (action);
+
+        return res;
+}
+
+static gboolean
+gsm_consolekit_get_privileges_for_actions (GsmConsolekit *manager,
+                                           const char    *single_action_id,
+                                           const char    *multiple_action_id)
+{
+        PolKitResult  result;
+        gboolean      res;
+        GError       *error;
+        const char   *action_id;
 
         error = NULL;
         res = gsm_consolekit_ensure_ck_connection (manager, &error);
@@ -958,6 +1148,82 @@
                 return FALSE;
         }
 
+        if (gsm_consolekit_is_single_user (manager)) {
+                action_id = single_action_id;
+        } else {
+                action_id = multiple_action_id;
+        }
+
+        result = gsm_consolekit_get_result_for_action (manager, action_id);
+
+        switch (result) {
+        case POLKIT_RESULT_UNKNOWN:
+        case POLKIT_RESULT_NO:
+                return FALSE;
+        case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH:
+        case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_SESSION:
+        case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_ALWAYS:
+        case POLKIT_RESULT_ONLY_VIA_SELF_AUTH:
+        case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_SESSION:
+        case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_ALWAYS:
+                if (!gsm_consolekit_obtain_privileges_for_action (manager,
+                                                                  action_id)) {
+                        /* if the call doesn't work, then we were not even able
+                         * to do the call requesting the privileges: the setup
+                         * is likely broken */
+                        return FALSE;
+                }
+                break;
+        case POLKIT_RESULT_YES:
+                g_signal_emit (G_OBJECT (manager),
+                               signals [PRIVILEGES_COMPLETED],
+                               0, TRUE, FALSE, NULL);
+                break;
+        case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_ONE_SHOT:
+        case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_ONE_SHOT:
+                g_signal_emit (G_OBJECT (manager),
+                               signals [PRIVILEGES_COMPLETED],
+                               0, TRUE, TRUE, NULL);
+                break;
+        default:
+                g_assert_not_reached ();
+                break;
+        }
+
+        return TRUE;
+}
+#endif
+
+gboolean
+gsm_consolekit_get_restart_privileges (GsmConsolekit *manager)
+{
+#ifdef HAVE_POLKIT_GNOME
+        return gsm_consolekit_get_privileges_for_actions (manager,
+                                                          "org.freedesktop.consolekit.system.restart",
+                                                          "org.freedesktop.consolekit.system.restart-multiple-users");
+#else
+        g_debug ("GsmConsolekit: built without PolicyKit-gnome support");
+        return FALSE;
+#endif
+}
+
+gboolean
+gsm_consolekit_get_stop_privileges (GsmConsolekit *manager)
+{
+#ifdef HAVE_POLKIT_GNOME
+        return gsm_consolekit_get_privileges_for_actions (manager,
+                                                          "org.freedesktop.consolekit.system.stop",
+                                                          "org.freedesktop.consolekit.system.stop-multiple-users");
+#else
+        g_debug ("GsmConsolekit: built without PolicyKit-gnome support");
+        return FALSE;
+#endif
+}
+
+gboolean
+gsm_consolekit_can_restart (GsmConsolekit *manager)
+{
+#ifdef HAVE_POLKIT_GNOME
         return gsm_consolekit_can_do_action (manager, "org.freedesktop.consolekit.system.restart") ||
                gsm_consolekit_can_do_action (manager, "org.freedesktop.consolekit.system.restart-multiple-users");
 #else
@@ -970,17 +1236,6 @@
 gsm_consolekit_can_stop (GsmConsolekit *manager)
 {
 #ifdef HAVE_POLKIT_GNOME
-        gboolean res;
-        GError  *error;
-        error = NULL;
-        res = gsm_consolekit_ensure_ck_connection (manager, &error);
-        if (!res) {
-                g_warning ("Could not connect to ConsoleKit: %s",
-                           error->message);
-                g_error_free (error);
-                return FALSE;
-        }
-
         return gsm_consolekit_can_do_action (manager, "org.freedesktop.consolekit.system.stop") ||
                gsm_consolekit_can_do_action (manager, "org.freedesktop.consolekit.system.stop-multiple-users");
 #else

Modified: trunk/gnome-session/gsm-consolekit.h
==============================================================================
--- trunk/gnome-session/gsm-consolekit.h	(original)
+++ trunk/gnome-session/gsm-consolekit.h	Wed Apr  8 13:42:27 2009
@@ -55,6 +55,11 @@
 
         void (* request_completed) (GsmConsolekit *manager,
                                     GError        *error);
+
+        void (* privileges_completed) (GsmConsolekit *manager,
+                                       gboolean       success,
+                                       gboolean       ask_later,
+                                       GError        *error);
 };
 
 enum _GsmConsolekitError {
@@ -72,6 +77,10 @@
 
 gboolean         gsm_consolekit_can_switch_user (GsmConsolekit *manager);
 
+gboolean         gsm_consolekit_get_restart_privileges (GsmConsolekit *manager);
+
+gboolean         gsm_consolekit_get_stop_privileges    (GsmConsolekit *manager);
+
 gboolean         gsm_consolekit_can_stop        (GsmConsolekit *manager);
 
 gboolean         gsm_consolekit_can_restart     (GsmConsolekit *manager);

Modified: trunk/gnome-session/gsm-manager.c
==============================================================================
--- trunk/gnome-session/gsm-manager.c	(original)
+++ trunk/gnome-session/gsm-manager.c	Wed Apr  8 13:42:27 2009
@@ -84,6 +84,18 @@
 
 #define IS_STRING_EMPTY(x) ((x)==NULL||(x)[0]=='\0')
 
+typedef enum
+{
+        GSM_MANAGER_LOGOUT_NONE,
+        GSM_MANAGER_LOGOUT_LOGOUT,
+        GSM_MANAGER_LOGOUT_REBOOT,
+        GSM_MANAGER_LOGOUT_REBOOT_INTERACT,
+        GSM_MANAGER_LOGOUT_REBOOT_GDM,
+        GSM_MANAGER_LOGOUT_SHUTDOWN,
+        GSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT,
+        GSM_MANAGER_LOGOUT_SHUTDOWN_GDM
+} GsmManagerLogoutType;
+
 struct GsmManagerPrivate
 {
         gboolean                failsafe;
@@ -103,6 +115,8 @@
          * since it uses a sublist of all running client that replied in a
          * specific way */
         GSList                 *next_query_clients;
+        /* This is the action that will be done just before we exit */
+        GsmManagerLogoutType    logout_type;
 
         GtkWidget              *inhibit_dialog;
 
@@ -364,6 +378,70 @@
 static void start_phase (GsmManager *manager);
 
 static void
+quit_request_completed (GsmConsolekit *consolekit,
+                        GError        *error,
+                        gpointer       user_data)
+{
+        GdmLogoutAction fallback_action = GPOINTER_TO_INT (user_data);
+
+        if (error != NULL) {
+                gdm_set_logout_action (fallback_action);
+        }
+
+        g_object_unref (consolekit);
+
+        gtk_main_quit ();
+}
+
+static void
+gsm_manager_quit (GsmManager *manager)
+{
+        GsmConsolekit *consolekit;
+
+        /* See the comment in request_reboot() for some more details about how
+         * this works. */
+
+        switch (manager->priv->logout_type) {
+        case GSM_MANAGER_LOGOUT_LOGOUT:
+                gtk_main_quit ();
+                break;
+        case GSM_MANAGER_LOGOUT_REBOOT:
+        case GSM_MANAGER_LOGOUT_REBOOT_INTERACT:
+                gdm_set_logout_action (GDM_LOGOUT_ACTION_NONE);
+
+                consolekit = gsm_get_consolekit ();
+                g_signal_connect (consolekit,
+                                  "request-completed",
+                                  G_CALLBACK (quit_request_completed),
+                                  GINT_TO_POINTER (GDM_LOGOUT_ACTION_REBOOT));
+                gsm_consolekit_attempt_restart (consolekit);
+                break;
+        case GSM_MANAGER_LOGOUT_REBOOT_GDM:
+                gdm_set_logout_action (GDM_LOGOUT_ACTION_REBOOT);
+                gtk_main_quit ();
+                break;
+        case GSM_MANAGER_LOGOUT_SHUTDOWN:
+        case GSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT:
+                gdm_set_logout_action (GDM_LOGOUT_ACTION_NONE);
+
+                consolekit = gsm_get_consolekit ();
+                g_signal_connect (consolekit,
+                                  "request-completed",
+                                  G_CALLBACK (quit_request_completed),
+                                  GINT_TO_POINTER (GDM_LOGOUT_ACTION_SHUTDOWN));
+                gsm_consolekit_attempt_stop (consolekit);
+                break;
+        case GSM_MANAGER_LOGOUT_SHUTDOWN_GDM:
+                gdm_set_logout_action (GDM_LOGOUT_ACTION_SHUTDOWN);
+                gtk_main_quit ();
+                break;
+        default:
+                g_assert_not_reached ();
+                break;
+        }
+}
+
+static void
 end_phase (GsmManager *manager)
 {
         g_debug ("GsmManager: ending phase %s\n",
@@ -403,7 +481,7 @@
                 start_phase (manager);
                 break;
         case GSM_MANAGER_PHASE_EXIT:
-                gtk_main_quit ();
+                gsm_manager_quit (manager);
                 break;
         default:
                 g_assert_not_reached ();
@@ -811,6 +889,9 @@
         gsm_manager_set_phase (manager, GSM_MANAGER_PHASE_RUNNING);
         manager->priv->forceful_logout = FALSE;
 
+        manager->priv->logout_type = GSM_MANAGER_LOGOUT_NONE;
+        gdm_set_logout_action (GDM_LOGOUT_ACTION_NONE);
+
         start_phase (manager);
 }
 
@@ -839,49 +920,6 @@
         }
 }
 
-
-static void
-do_attempt_reboot (GsmConsolekit *consolekit)
-{
-        if (gsm_consolekit_can_restart (consolekit)) {
-                gdm_set_logout_action (GDM_LOGOUT_ACTION_NONE);
-                gsm_consolekit_attempt_restart (consolekit);
-        } else {
-                gdm_set_logout_action (GDM_LOGOUT_ACTION_REBOOT);
-        }
-}
-
-static void
-do_attempt_shutdown (GsmConsolekit *consolekit)
-{
-        if (gsm_consolekit_can_stop (consolekit)) {
-                gdm_set_logout_action (GDM_LOGOUT_ACTION_NONE);
-                gsm_consolekit_attempt_stop (consolekit);
-        } else {
-                gdm_set_logout_action (GDM_LOGOUT_ACTION_SHUTDOWN);
-        }
-}
-
-static void
-manager_attempt_reboot (GsmManager *manager)
-{
-        GsmConsolekit *consolekit;
-
-        consolekit = gsm_get_consolekit ();
-        do_attempt_reboot (consolekit);
-        g_object_unref (consolekit);
-}
-
-static void
-manager_attempt_shutdown (GsmManager *manager)
-{
-        GsmConsolekit *consolekit;
-
-        consolekit = gsm_get_consolekit ();
-        do_attempt_shutdown (consolekit);
-        g_object_unref (consolekit);
-}
-
 static void
 manager_attempt_hibernate (GsmManager *manager)
 {
@@ -911,8 +949,8 @@
 }
 
 static void
-do_dialog_action (GsmManager *manager,
-                  int         action)
+do_inhibit_dialog_action (GsmManager *manager,
+                          int         action)
 {
         switch (action) {
         case GSM_LOGOUT_ACTION_SWITCH_USER:
@@ -924,12 +962,12 @@
         case GSM_LOGOUT_ACTION_SLEEP:
                 manager_attempt_suspend (manager);
                 break;
+        /* If changing the code to make SHUTDOWN/REBOOT/LOGOUT cases different,
+         * then the call to gsm_inhibit_dialog_new() in
+         * query_end_session_complete() should be updated to pass the right
+         * action */
         case GSM_LOGOUT_ACTION_SHUTDOWN:
-                manager_attempt_shutdown (manager);
-                break;
         case GSM_LOGOUT_ACTION_REBOOT:
-                manager_attempt_reboot (manager);
-                break;
         case GSM_LOGOUT_ACTION_LOGOUT:
                 manager->priv->forceful_logout = TRUE;
                 end_phase (manager);
@@ -971,7 +1009,7 @@
                 break;
         case GTK_RESPONSE_ACCEPT:
                 g_debug ("GsmManager: doing action %d", action);
-                do_dialog_action (manager, action);
+                do_inhibit_dialog_action (manager, action);
                 break;
         default:
                 g_assert_not_reached ();
@@ -1002,6 +1040,10 @@
                 return;
         }
 
+        /* Note: GSM_LOGOUT_ACTION_SHUTDOWN and GSM_LOGOUT_ACTION_REBOOT are
+         * actually handled the same way as GSM_LOGOUT_ACTION_LOGOUT in the
+         * inhibit dialog; the action, if the button is clicked, will be to
+         * simply go to the next phase. */
         manager->priv->inhibit_dialog = gsm_inhibit_dialog_new (manager->priv->inhibitors,
                                                                 manager->priv->clients,
                                                                 GSM_LOGOUT_ACTION_LOGOUT);
@@ -2427,59 +2469,133 @@
 }
 
 static void
+request_reboot_privileges_completed (GsmConsolekit *consolekit,
+                                     gboolean       success,
+                                     gboolean       ask_later,
+                                     GError        *error,
+                                     GsmManager    *manager)
+{
+        /* make sure we disconnect the signal handler so that it's not called
+         * again next time the event is fired -- this can happen if the reboot
+         * is cancelled. */
+        g_signal_handlers_disconnect_by_func (consolekit,
+                                              request_reboot_privileges_completed,
+                                              manager);
+
+        g_object_unref (consolekit);
+
+        if (success) {
+                if (ask_later) {
+                        manager->priv->logout_type = GSM_MANAGER_LOGOUT_REBOOT_INTERACT;
+                } else {
+                        manager->priv->logout_type = GSM_MANAGER_LOGOUT_REBOOT;
+                }
+
+                end_phase (manager);
+        }
+}
+
+static void
 request_reboot (GsmManager *manager)
 {
+        GsmConsolekit *consolekit;
+        gboolean       success;
+
         g_debug ("GsmManager: requesting reboot");
 
-        /* shutdown uses logout inhibit */
-        if (! gsm_manager_is_logout_inhibited (manager)) {
-                manager_attempt_reboot (manager);
-                return;
-        }
+        /* We request the privileges before doing anything. There are a few
+         * different cases here:
+         *
+         *   - no ConsoleKit: we fallback on GDM
+         *   - no password required: everything is fine
+         *   - password asked once: we ask for it now. If the user enters it
+         *     fine, then all is great. If the user doesn't enter it fine, we
+         *     don't do anything (so no logout).
+         *   - password asked each time: we don't ask it for now since we don't
+         *     want to ask for it twice. Instead we'll ask for it at the very
+         *     end. If the user will enter it fine, then all is great again. If
+         *     the user doesn't enter it fine, then we'll just fallback to GDM.
+         *
+         * The last case (password asked each time) is a bit broken, but
+         * there's really nothing we can do about it. Generally speaking,
+         * though, the password will only be asked once (unless the system is
+         * configured in paranoid mode), and most probably only if there are
+         * more than one user connected. So the general case is that it will
+         * just work fine.
+         */
 
-        if (manager->priv->inhibit_dialog != NULL) {
-                g_debug ("GsmManager: inhibit dialog already up");
-                gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog));
-                return;
+        consolekit = gsm_get_consolekit ();
+        g_signal_connect (consolekit,
+                          "privileges-completed",
+                          G_CALLBACK (request_reboot_privileges_completed),
+                          manager);
+        success = gsm_consolekit_get_restart_privileges (consolekit);
+
+        if (!success) {
+                g_signal_handlers_disconnect_by_func (consolekit,
+                                                      request_reboot_privileges_completed,
+                                                      manager);
+                g_object_unref (consolekit);
+
+                manager->priv->logout_type = GSM_MANAGER_LOGOUT_REBOOT_GDM;
+                end_phase (manager);
         }
+}
 
-        manager->priv->inhibit_dialog = gsm_inhibit_dialog_new (manager->priv->inhibitors,
-                                                                manager->priv->clients,
-                                                                GSM_LOGOUT_ACTION_REBOOT);
+static void
+request_shutdown_privileges_completed (GsmConsolekit *consolekit,
+                                       gboolean       success,
+                                       gboolean       ask_later,
+                                       GError        *error,
+                                       GsmManager    *manager)
+{
+        /* make sure we disconnect the signal handler so that it's not called
+         * again next time the event is fired -- this can happen if the reboot
+         * is cancelled. */
+        g_signal_handlers_disconnect_by_func (consolekit,
+                                              request_shutdown_privileges_completed,
+                                              manager);
 
-        g_signal_connect (manager->priv->inhibit_dialog,
-                          "response",
-                          G_CALLBACK (inhibit_dialog_response),
-                          manager);
-        gtk_widget_show (manager->priv->inhibit_dialog);
+        g_object_unref (consolekit);
+
+        if (success) {
+                if (ask_later) {
+                        manager->priv->logout_type = GSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT;
+                } else {
+                        manager->priv->logout_type = GSM_MANAGER_LOGOUT_SHUTDOWN;
+                }
+
+                end_phase (manager);
+        }
 }
 
 static void
 request_shutdown (GsmManager *manager)
 {
+        GsmConsolekit *consolekit;
+        gboolean       success;
+
         g_debug ("GsmManager: requesting shutdown");
 
-        /* shutdown uses logout inhibit */
-        if (! gsm_manager_is_logout_inhibited (manager)) {
-                manager_attempt_shutdown (manager);
-                return;
-        }
+        /* See the comment in request_reboot() for some more details about how
+         * this works. */
 
-        if (manager->priv->inhibit_dialog != NULL) {
-                g_debug ("GsmManager: inhibit dialog already up");
-                gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog));
-                return;
-        }
+        consolekit = gsm_get_consolekit ();
+        g_signal_connect (consolekit,
+                          "privileges-completed",
+                          G_CALLBACK (request_shutdown_privileges_completed),
+                          manager);
+        success = gsm_consolekit_get_stop_privileges (consolekit);
 
-        manager->priv->inhibit_dialog = gsm_inhibit_dialog_new (manager->priv->inhibitors,
-                                                                manager->priv->clients,
-                                                                GSM_LOGOUT_ACTION_SHUTDOWN);
+        if (!success) {
+                g_signal_handlers_disconnect_by_func (consolekit,
+                                                      request_shutdown_privileges_completed,
+                                                      manager);
+                g_object_unref (consolekit);
 
-        g_signal_connect (manager->priv->inhibit_dialog,
-                          "response",
-                          G_CALLBACK (inhibit_dialog_response),
-                          manager);
-        gtk_widget_show (manager->priv->inhibit_dialog);
+                manager->priv->logout_type = GSM_MANAGER_LOGOUT_SHUTDOWN_GDM;
+                end_phase (manager);
+        }
 }
 
 static void
@@ -2543,7 +2659,10 @@
                 gboolean    forceful_logout)
 {
         g_debug ("GsmManager: requesting logout");
+
         manager->priv->forceful_logout = forceful_logout;
+        manager->priv->logout_type = GSM_MANAGER_LOGOUT_LOGOUT;
+
         end_phase (manager);
 }
 

Modified: trunk/gnome-session/gsm-marshal.list
==============================================================================
--- trunk/gnome-session/gsm-marshal.list	(original)
+++ trunk/gnome-session/gsm-marshal.list	Wed Apr  8 13:42:27 2009
@@ -1,2 +1,3 @@
 BOOLEAN:POINTER
 VOID:BOOLEAN,BOOLEAN,BOOLEAN,STRING
+VOID:BOOLEAN,BOOLEAN,POINTER



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]