Commit 6286db88 authored by Vincent Untz's avatar Vincent Untz Committed by Vincent Untz

Make reboot and shutdown leave the session properly, by letting apps exit

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

svn path=/trunk/; revision=5377
parent aa2f3743
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
2009-04-08 Vincent Untz <vuntz@gnome.org>
Remove the 1-second delay to display the inhibit dialog when an
......
......@@ -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 {
enum {
REQUEST_COMPLETED = 0,
PRIVILEGES_COMPLETED,
LAST_SIGNAL
};
......@@ -133,6 +135,17 @@ gsm_consolekit_class_init (GsmConsolekitClass *manager_class)
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 @@ gsm_consolekit_can_switch_user (GsmConsolekit *manager)
}
#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 @@ gsm_consolekit_can_do_action (GsmConsolekit *manager,
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 @@ gsm_consolekit_can_do_action (GsmConsolekit *manager,
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 @@ gsm_consolekit_can_do_action (GsmConsolekit *manager,
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)
{
#ifdef HAVE_POLKIT_GNOME
gboolean res;
GError *error;
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)
{
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 @@ gsm_consolekit_can_restart (GsmConsolekit *manager)
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 @@ gboolean
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
......
......@@ -55,6 +55,11 @@ struct _GsmConsolekitClass
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 @@ GsmConsolekit *gsm_consolekit_new (void) G_GNUC_MALLOC;
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);
......
......@@ -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 @@ struct GsmManagerPrivate
* 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;
......@@ -363,6 +377,70 @@ phase_num_to_name (guint phase)
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)
{
......@@ -403,7 +481,7 @@ end_phase (GsmManager *manager)
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 @@ cancel_end_session (GsmManager *manager)
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 @@ manager_switch_user (GsmManager *manager)
}
}
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 @@ manager_attempt_suspend (GsmManager *manager)
}
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 @@ do_dialog_action (GsmManager *manager,
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 @@ inhibit_dialog_response (GsmInhibitDialog *dialog,
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 @@ query_end_session_complete (GsmManager *manager)
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);
......@@ -2426,60 +2468,134 @@ gsm_manager_is_suspend_inhibited (GsmManager *manager)
return TRUE;
}
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.
*