diff --git a/gnome-session/gsm-consolekit.c b/gnome-session/gsm-consolekit.c
index e8dd726..583940d 100644
--- a/gnome-session/gsm-consolekit.c
+++ b/gnome-session/gsm-consolekit.c
@@ -23,6 +23,8 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
 
 #include <glib.h>
 #include <glib-object.h>
@@ -34,6 +36,8 @@
 #include "gsm-marshal.h"
 #include "gsm-consolekit.h"
 
+#define MINIMAL_UID 500
+
 #define CK_NAME      "org.freedesktop.ConsoleKit"
 #define CK_PATH      "/org/freedesktop/ConsoleKit"
 #define CK_INTERFACE "org.freedesktop.ConsoleKit"
@@ -51,7 +55,11 @@ struct _GsmConsolekitPrivate
         DBusGConnection *dbus_connection;
         DBusGProxy      *bus_proxy;
         DBusGProxy      *ck_proxy;
+        DBusGProxy      *session_proxy;
+        gchar           *session_id;
         guint32          is_connected : 1;
+        GHashTable      *inhibitors;
+        GHashTable      *sessions;
 };
 
 enum {
@@ -61,7 +69,10 @@ enum {
 
 enum {
         REQUEST_COMPLETED = 0,
-        PRIVILEGES_COMPLETED,
+        QUERY_STOP_COMPLETED,
+        QUERY_STOP,
+        STOP,
+        CANCEL_STOP,
         LAST_SIGNAL
 };
 
@@ -81,7 +92,20 @@ static void     gsm_consolekit_on_name_owner_changed (DBusGProxy        *bus_pro
                                                       const char        *name,
                                                       const char        *prev_owner,
                                                       const char        *new_owner,
-                                                      GsmConsolekit   *manager);
+                                                      GsmConsolekit     *manager);
+
+static void     gsm_consolekit_on_query_stop  (DBusGProxy    *bus_proxy,
+                                               GsmConsolekit *manager);
+static void     gsm_consolekit_on_stop        (DBusGProxy    *bus_proxy,
+                                               GsmConsolekit *manager);
+static void     gsm_consolekit_on_cancel_stop (DBusGProxy    *bus_proxy,
+                                               GsmConsolekit *manager);
+static void     on_inhibitor_added            (DBusGProxy    *object,
+                                               const char    *path,
+                                               GsmConsolekit *manager);
+static void     on_inhibitor_removed          (DBusGProxy    *object,
+                                               const char    *path,
+                                               GsmConsolekit *manager);
 
 G_DEFINE_TYPE (GsmConsolekit, gsm_consolekit, G_TYPE_OBJECT);
 
@@ -137,16 +161,46 @@ gsm_consolekit_class_init (GsmConsolekitClass *manager_class)
                               G_TYPE_NONE,
                               1, G_TYPE_POINTER);
 
-        signals [PRIVILEGES_COMPLETED] =
-                g_signal_new ("privileges-completed",
+        signals [QUERY_STOP_COMPLETED] =
+                g_signal_new ("query-stop-completed",
                               G_OBJECT_CLASS_TYPE (object_class),
                               G_SIGNAL_RUN_LAST,
-                              G_STRUCT_OFFSET (GsmConsolekitClass, privileges_completed),
+                              G_STRUCT_OFFSET (GsmConsolekitClass, query_stop_completed),
                               NULL,
                               NULL,
-                              gsm_marshal_VOID__BOOLEAN_BOOLEAN_POINTER,
+                              gsm_marshal_VOID__UINT_UINT_UINT_POINTER,
                               G_TYPE_NONE,
-                              3, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_POINTER);
+                              4, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER);
+
+        signals [QUERY_STOP] =
+                g_signal_new ("query-stop",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GsmConsolekitClass, query_stop),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+
+        signals [STOP] =
+                g_signal_new ("stop",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GsmConsolekitClass, stop),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+
+        signals [CANCEL_STOP] =
+                g_signal_new ("cancel-stop",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GsmConsolekitClass, cancel_stop),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
 
         g_type_class_add_private (manager_class, sizeof (GsmConsolekitPrivate));
 }
@@ -176,6 +230,8 @@ gsm_consolekit_ensure_ck_connection (GsmConsolekit  *manager,
 {
         GError  *connection_error;
         gboolean is_connected;
+        const gchar *cookie;
+        gchar *path;
 
         connection_error = NULL;
 
@@ -238,6 +294,61 @@ gsm_consolekit_ensure_ck_connection (GsmConsolekit  *manager,
                         is_connected = FALSE;
                         goto out;
                 }
+
+                dbus_g_proxy_add_signal (manager->priv->ck_proxy, "InhibitorAdded",
+                                         DBUS_TYPE_G_OBJECT_PATH,
+                                         G_TYPE_INVALID);
+                dbus_g_proxy_connect_signal (manager->priv->ck_proxy, "InhibitorAdded",
+                                             G_CALLBACK (on_inhibitor_added),
+                                             manager, NULL);
+
+                dbus_g_proxy_add_signal (manager->priv->ck_proxy, "InhibitorRemoved",
+                                         DBUS_TYPE_G_OBJECT_PATH,
+                                         G_TYPE_INVALID);
+                dbus_g_proxy_connect_signal (manager->priv->ck_proxy, "InhibitorRemoved",
+                                             G_CALLBACK (on_inhibitor_removed),
+                                             manager, NULL);
+
+        }
+
+        if (manager->priv->session_proxy == NULL) {
+                cookie = g_getenv ("XDG_SESSION_COOKIE");
+                if (!dbus_g_proxy_call (manager->priv->ck_proxy,
+                                        "GetSessionForCookie",
+                                        &connection_error,
+                                        G_TYPE_STRING, cookie,
+                                        G_TYPE_INVALID,
+                                        DBUS_TYPE_G_OBJECT_PATH, &path,
+                                        G_TYPE_INVALID)) {
+                        g_propagate_error (error, connection_error);
+                        is_connected = FALSE;
+                        goto out;
+                }
+
+                manager->priv->session_id = g_strdup (path);
+                manager->priv->session_proxy =
+                        dbus_g_proxy_new_for_name (manager->priv->dbus_connection,
+                                                   "org.freedesktop.ConsoleKit",
+                                                   path,
+                                                   "org.freedesktop.ConsoleKit.Session");
+                dbus_g_proxy_add_signal (manager->priv->session_proxy, "QueryStop",
+                                         G_TYPE_INVALID);
+                dbus_g_proxy_connect_signal (manager->priv->session_proxy, "QueryStop",
+                                             G_CALLBACK (gsm_consolekit_on_query_stop),
+                                             manager, NULL);
+
+                dbus_g_proxy_add_signal (manager->priv->session_proxy, "Stop",
+                                         G_TYPE_INVALID);
+                dbus_g_proxy_connect_signal (manager->priv->session_proxy, "Stop",
+                                             G_CALLBACK (gsm_consolekit_on_stop),
+                                             manager, NULL);
+
+                dbus_g_proxy_add_signal (manager->priv->session_proxy, "CancelStop",
+                                         G_TYPE_INVALID);
+                dbus_g_proxy_connect_signal (manager->priv->session_proxy, "CancelStop",
+                                             G_CALLBACK (gsm_consolekit_on_cancel_stop),
+                                             manager, NULL);
+                g_free (path);
         }
 
         is_connected = TRUE;
@@ -259,11 +370,25 @@ gsm_consolekit_ensure_ck_connection (GsmConsolekit  *manager,
                                 g_object_unref (manager->priv->ck_proxy);
                                 manager->priv->ck_proxy = NULL;
                         }
+
+                        if (manager->priv->session_proxy != NULL) {
+                                g_object_unref (manager->priv->session_proxy);
+                                manager->priv->session_proxy = NULL;
+                                g_free (manager->priv->session_id);
+                                manager->priv->session_id = NULL;
+                        }
                 } else if (manager->priv->bus_proxy == NULL) {
                         if (manager->priv->ck_proxy != NULL) {
                                 g_object_unref (manager->priv->ck_proxy);
                                 manager->priv->ck_proxy = NULL;
                         }
+
+                        if (manager->priv->session_proxy != NULL) {
+                                g_object_unref (manager->priv->session_proxy);
+                                manager->priv->session_proxy = NULL;
+                                g_free (manager->priv->session_id);
+                                manager->priv->session_id = NULL;
+                        }
                 }
         }
 
@@ -286,16 +411,57 @@ gsm_consolekit_on_name_owner_changed (DBusGProxy    *bus_proxy,
                 manager->priv->ck_proxy = NULL;
         }
 
+        if (manager->priv->session_proxy != NULL) {
+                g_object_unref (manager->priv->session_proxy);
+                manager->priv->session_proxy = NULL;
+                g_free (manager->priv->session_id);
+                manager->priv->session_id = NULL;
+        }
+
         gsm_consolekit_ensure_ck_connection (manager, NULL);
 }
 
 static void
+gsm_consolekit_on_query_stop (DBusGProxy    *bus_proxy,
+                              GsmConsolekit *manager)
+{
+        g_debug ("received Session.QueryStop signal from ConsoleKit");
+
+        g_signal_emit (G_OBJECT (manager), signals [QUERY_STOP], 0);
+}
+
+static void
+gsm_consolekit_on_stop (DBusGProxy    *bus_proxy,
+                        GsmConsolekit *manager)
+{
+        g_debug ("received Session.Stop signal from ConsoleKit");
+
+        g_signal_emit (G_OBJECT (manager), signals [STOP], 0);
+}
+
+static void
+gsm_consolekit_on_cancel_stop (DBusGProxy    *bus_proxy,
+                               GsmConsolekit *manager)
+{
+        g_debug ("received Session.CancelStop signal from ConsoleKit");
+
+        g_signal_emit (G_OBJECT (manager), signals [CANCEL_STOP], 0);
+}
+
+static void inhibitor_data_free (gpointer data);
+
+static void
 gsm_consolekit_init (GsmConsolekit *manager)
 {
         GError *error;
 
         manager->priv = GSM_CONSOLEKIT_GET_PRIVATE (manager);
 
+        manager->priv->inhibitors = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                           g_free, inhibitor_data_free);
+        manager->priv->sessions = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                         g_free, g_free);
+
         error = NULL;
 
         if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
@@ -318,6 +484,13 @@ gsm_consolekit_free_dbus (GsmConsolekit *manager)
                 manager->priv->ck_proxy = NULL;
         }
 
+        if (manager->priv->session_proxy != NULL) {
+                g_object_unref (manager->priv->session_proxy);
+                manager->priv->session_proxy = NULL;
+                g_free (manager->priv->session_id);
+                manager->priv->session_id = NULL;
+        }
+
         if (manager->priv->dbus_connection != NULL) {
                 DBusConnection *connection;
                 connection = dbus_g_connection_get_connection (manager->priv->dbus_connection);
@@ -338,10 +511,12 @@ gsm_consolekit_finalize (GObject *object)
 
         manager = GSM_CONSOLEKIT (object);
 
-        parent_class = G_OBJECT_CLASS (gsm_consolekit_parent_class);
-
         gsm_consolekit_free_dbus (manager);
 
+        g_hash_table_destroy (manager->priv->inhibitors);
+        g_hash_table_destroy (manager->priv->sessions);
+
+        parent_class = G_OBJECT_CLASS (gsm_consolekit_parent_class);
         if (parent_class->finalize != NULL) {
                 parent_class->finalize (object);
         }
@@ -370,6 +545,157 @@ gsm_consolekit_new (void)
 }
 
 static void
+emit_query_stop_complete (GsmConsolekit               *manager,
+                          GsmConsoleKitStopCanProceed  can_proceed,
+                          unsigned int                 inhibitors_nb,
+                          unsigned int                 session_nb,
+                          GError                       *error)
+{
+        GError *call_error;
+
+        g_debug ("QueryStop returned ok=%d, inhibitors=%d, sessions=%d",
+                 can_proceed, inhibitors_nb, session_nb);
+
+        call_error = NULL;
+        if (error != NULL) {
+                call_error = g_error_new_literal (GSM_CONSOLEKIT_ERROR,
+                                                  GSM_CONSOLEKIT_ERROR_QUERYING_STOP,
+                                                  error->message);
+        }
+
+        g_signal_emit (G_OBJECT (manager),
+                       signals [QUERY_STOP_COMPLETED],
+                       0, can_proceed, inhibitors_nb, session_nb, call_error);
+
+        if (call_error != NULL) {
+                g_error_free (call_error);
+        }
+}
+
+static void
+gsm_consolekit_on_query_stop_complete (DBusGProxy     *proxy,
+                                       DBusGProxyCall *call,
+                                       gpointer        user_data)
+{
+        GsmConsolekit *manager = user_data;
+        GError        *error = NULL;
+        GsmConsoleKitStopCanProceed can_proceed = GSM_CONSOLEKIT_STOP_NOT_ALLOWED;
+        unsigned int                inhibitors_nb = 0;
+        unsigned int                session_nb = 0;
+
+        if (dbus_g_proxy_end_call (proxy, call, &error,
+                                   G_TYPE_UINT, &can_proceed,
+                                   G_TYPE_UINT, &inhibitors_nb,
+                                   G_TYPE_UINT, &session_nb,
+                                   G_TYPE_INVALID)) {
+                emit_query_stop_complete (manager,
+                                          can_proceed,
+                                          inhibitors_nb, session_nb,
+                                          NULL);
+        } else {
+                emit_query_stop_complete (manager,
+                                          GSM_CONSOLEKIT_STOP_NOT_ALLOWED,
+                                          0, 0,
+                                          error);
+                g_error_free (error);
+        }
+}
+
+void
+gsm_consolekit_stop_response (GsmConsolekit *manager,
+                              gboolean       ok_to_proceed,
+                              const char    *reason)
+{
+        gboolean res;
+        GError  *error;
+
+        error = NULL;
+
+        g_warning ("sending StopResponse (%d,'%s') to ConsoleKit", ok_to_proceed, reason);
+
+        if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
+                g_warning ("Could not connect to ConsoleKit: %s",
+                           error->message);
+                g_error_free (error);
+                return;
+        }
+
+        res = dbus_g_proxy_call_with_timeout (manager->priv->session_proxy,
+                                              "StopResponse",
+                                              INT_MAX,
+                                              &error,
+                                              G_TYPE_BOOLEAN, ok_to_proceed,
+                                              G_TYPE_STRING, reason ? reason : "",
+                                              G_TYPE_INVALID,
+                                              G_TYPE_INVALID);
+
+        if (!res) {
+                g_warning ("Unable to send StopResponse to ConsoleKit: %s", error->message);
+                g_error_free (error);
+        }
+}
+
+void
+gsm_consolekit_query_stop (GsmConsolekit *manager)
+{
+        GError  *error;
+
+        error = NULL;
+
+        g_debug ("calling QueryStop on ConsoleKit");
+
+        if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
+                g_warning ("Could not connect to ConsoleKit: %s",
+                           error->message);
+                emit_query_stop_complete (manager,
+                                          GSM_CONSOLEKIT_STOP_NOT_ALLOWED,
+                                          0, 0,
+                                          error);
+                g_error_free (error);
+                return;
+        }
+
+        dbus_g_proxy_begin_call_with_timeout (manager->priv->ck_proxy,
+                                              "QueryStop",
+                                              gsm_consolekit_on_query_stop_complete,
+                                              /* user data (and destroy): */
+                                              g_object_ref (manager), g_object_unref,
+                                              INT_MAX,
+                                              /* parameters: */
+                                              G_TYPE_INVALID);
+}
+
+void
+gsm_consolekit_cancel_stop (GsmConsolekit *manager)
+{
+        gboolean res;
+        GError  *error;
+
+        error = NULL;
+
+        g_debug ("calling CancelStop on ConsoleKit");
+
+        if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
+                g_warning ("Could not connect to ConsoleKit: %s",
+                           error->message);
+                g_error_free (error);
+                return;
+        }
+
+        res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy,
+                                              "CancelStop",
+                                              INT_MAX,
+                                              &error,
+                                              G_TYPE_INVALID,
+                                              G_TYPE_INVALID);
+
+        if (!res) {
+                g_warning ("Unable to cancel ConsoleKit stop process: %s", error->message);
+                g_error_free (error);
+        }
+}
+
+static void
 emit_restart_complete (GsmConsolekit *manager,
                        GError        *error)
 {
@@ -749,26 +1075,6 @@ gsm_consolekit_can_switch_user (GsmConsolekit *manager)
 }
 
 gboolean
-gsm_consolekit_get_restart_privileges (GsmConsolekit *manager)
-{
-	g_signal_emit (G_OBJECT (manager),
-		       signals [PRIVILEGES_COMPLETED],
-		       0, TRUE, TRUE, NULL);
-
-	return TRUE;
-}
-
-gboolean
-gsm_consolekit_get_stop_privileges (GsmConsolekit *manager)
-{
-	g_signal_emit (G_OBJECT (manager),
-		       signals [PRIVILEGES_COMPLETED],
-		       0, TRUE, TRUE, NULL);
-
-	return TRUE;
-}
-
-gboolean
 gsm_consolekit_can_restart (GsmConsolekit *manager)
 {
         gboolean res;
@@ -889,6 +1195,222 @@ out:
 	return ret;
 }
 
+GSList *
+gsm_consolekit_get_sessions (GsmConsolekit *manager)
+{
+        GPtrArray *paths;
+        GError *error;
+        guint32 user;
+        struct passwd *pwent;
+        const gchar *name;
+        gchar *key;
+        GSList *sessions;
+        gint i;
+        GHashTableIter iter;
+
+        /* FIXME: track sessions */
+        g_hash_table_remove_all (manager->priv->sessions);
+
+        paths = NULL;
+        error = NULL;
+        if (!dbus_g_proxy_call (manager->priv->ck_proxy,
+                                "GetSessions",
+                                &error,
+                                G_TYPE_INVALID,
+                                dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &paths,
+                                G_TYPE_INVALID)) {
+                g_warning ("Failed to get sessions: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        for (i = 0; i < paths->len; i++) {
+                const gchar *path;
+                DBusGProxy *proxy;
+                GValue value = { 0, };
+
+                path = g_ptr_array_index (paths, i);
+
+                proxy = dbus_g_proxy_new_for_name (manager->priv->dbus_connection,
+                                                   "org.freedesktop.ConsoleKit",
+                                                   path,
+                                                   "org.freedesktop.DBus.Properties");
+                error = NULL;
+                if (!dbus_g_proxy_call (proxy,
+                                        "Get",
+                                        &error,
+                                        G_TYPE_STRING, "org.freedesktop.ConsoleKit.Session",
+                                        G_TYPE_STRING, "user",
+                                        G_TYPE_INVALID,
+                                        G_TYPE_VALUE, &value,
+                                        G_TYPE_INVALID)) {
+                        g_warning ("Failed to get user for session: %s", error->message);
+                        g_error_free (error);
+                        g_object_unref (proxy);
+                        continue;
+                }
+                g_object_unref (proxy);
+
+                user = g_value_get_uint (&value);
+
+                if (user < MINIMAL_UID) {
+                        continue;
+                }
+
+                pwent = getpwuid (user);
+                name = pwent->pw_gecos;
+
+                g_debug ("session %s: uid %d user %s", path, user, name);
+
+                g_hash_table_insert (manager->priv->sessions, g_strdup (path), g_strdup (name));
+        }
+
+ out:
+        if (paths) {
+                g_ptr_array_foreach (paths, (GFunc)g_free, NULL);
+                g_ptr_array_free (paths, TRUE);
+        }
+
+        sessions = NULL;
+        g_hash_table_iter_init (&iter, manager->priv->sessions);
+        while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL)) {
+                sessions = g_slist_prepend (sessions, g_strdup (key));
+        }
+
+        return sessions;
+}
+
+const char *
+gsm_consolekit_get_session_user (GsmConsolekit *manager,
+                                 const char    *session_id)
+{
+        return g_hash_table_lookup (manager->priv->sessions, session_id);
+}
+
+const char *
+gsm_consolekit_get_current_session_id (GsmConsolekit *manager)
+{
+        return manager->priv->session_id;
+}
+
+typedef struct {
+        char *reason;
+        char *session_id;
+} InhibitorData;
+
+static void
+inhibitor_data_free (gpointer data)
+{
+        InhibitorData *inhibitor_data = data;
+
+        g_free (inhibitor_data->reason);
+        g_free (inhibitor_data->session_id);
+        g_free (inhibitor_data);
+}
+
+GSList *
+gsm_consolekit_get_inhibitors (GsmConsolekit *manager)
+{
+        GHashTableIter iter;
+        char *key;
+        GSList *list;
+
+        list = NULL;
+        g_hash_table_iter_init (&iter, manager->priv->inhibitors);
+        while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL)) {
+                list = g_slist_prepend (list, g_strdup (key));
+        }
+
+        return list;
+}
+
+char *
+gsm_consolekit_get_inhibitor_reason (GsmConsolekit *manager,
+                                     const char    *inhibitor_id)
+{
+        InhibitorData *data;
+
+        data = (InhibitorData *)g_hash_table_lookup (manager->priv->inhibitors, inhibitor_id);
+
+        if (data) {
+                return data->reason;
+        }
+
+        return NULL;
+}
+
+char *
+gsm_consolekit_get_inhibitor_session (GsmConsolekit *manager,
+                                      const char    *inhibitor_id)
+{
+        InhibitorData *data;
+
+        data = (InhibitorData *)g_hash_table_lookup (manager->priv->inhibitors, inhibitor_id);
+
+        if (data) {
+                return data->session_id;
+        }
+
+        return NULL;
+}
+
+static void
+on_inhibitor_added (DBusGProxy    *object,
+                    const gchar   *path,
+                    GsmConsolekit *manager)
+{
+        DBusGProxy *proxy;
+        GError *error;
+        InhibitorData *data;
+        GHashTable *values;
+        GValue *value;
+
+        proxy = dbus_g_proxy_new_for_name (manager->priv->dbus_connection,
+                                           "org.freedesktop.ConsoleKit",
+                                           path,
+                                           "org.freedesktop.DBus.Properties");
+
+        error = NULL;
+        if (!dbus_g_proxy_call (proxy,
+                                "GetAll",
+                                &error,
+                                G_TYPE_STRING, "org.freedesktop.ConsoleKit.Inhibitor",
+                                G_TYPE_INVALID,
+                                dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &values,
+                                G_TYPE_INVALID)) {
+                g_warning ("Failed to get properties for inhibitor %s: %s", path, error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        data = g_new0 (InhibitorData, 1);
+        value = g_hash_table_lookup (values, "Reason");
+        if (value) {
+                data->reason = g_value_dup_string (value);
+        }
+        value = g_hash_table_lookup (values, "SessionId");
+        if (value) {
+                data->session_id = g_value_dup_string (value);
+        }
+        g_hash_table_destroy (values);
+
+        g_debug ("got inhibitor %s reason: %s session: %s\n",
+                 path, data->reason, data->session_id);
+
+        g_hash_table_insert (manager->priv->inhibitors, g_strdup (path), data);
+
+ out:
+        g_object_unref (proxy);
+        return;
+}
+
+static void
+on_inhibitor_removed (DBusGProxy    *object,
+                      const char    *path,
+                      GsmConsolekit *manager)
+{
+        g_hash_table_remove (manager->priv->inhibitors, path);
+}
 
 GsmConsolekit *
 gsm_get_consolekit (void)
diff --git a/gnome-session/gsm-consolekit.h b/gnome-session/gsm-consolekit.h
index f80c130..74f23fe 100644
--- a/gnome-session/gsm-consolekit.h
+++ b/gnome-session/gsm-consolekit.h
@@ -37,10 +37,11 @@ G_BEGIN_DECLS
 #define GSM_CONSOLEKIT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), GSM_TYPE_CONSOLEKIT, GsmConsolekitClass))
 #define GSM_CONSOLEKIT_ERROR            (gsm_consolekit_error_quark ())
 
-typedef struct _GsmConsolekit        GsmConsolekit;
-typedef struct _GsmConsolekitClass   GsmConsolekitClass;
-typedef struct _GsmConsolekitPrivate GsmConsolekitPrivate;
-typedef enum   _GsmConsolekitError   GsmConsolekitError;
+typedef struct _GsmConsolekit               GsmConsolekit;
+typedef struct _GsmConsolekitClass          GsmConsolekitClass;
+typedef struct _GsmConsolekitPrivate        GsmConsolekitPrivate;
+typedef enum   _GsmConsolekitError          GsmConsolekitError;
+typedef enum   _GsmConsoleKitStopCanProceed GsmConsoleKitStopCanProceed;
 
 struct _GsmConsolekit
 {
@@ -56,17 +57,32 @@ struct _GsmConsolekitClass
         void (* request_completed) (GsmConsolekit *manager,
                                     GError        *error);
 
-        void (* privileges_completed) (GsmConsolekit *manager,
-                                       gboolean       success,
-                                       gboolean       ask_later,
-                                       GError        *error);
+        void (* query_stop_completed) (GsmConsolekit               *manager,
+                                       GsmConsoleKitStopCanProceed  can_proceed,
+                                       unsigned int                 inhibitors_nb,
+                                       unsigned int                 session_nb,
+                                       GError                      *error);
+
+        void (* query_stop)  (GsmConsolekit *manager);
+
+        void (* stop)        (GsmConsolekit *manager);
+
+        void (* cancel_stop) (GsmConsolekit *manager);
 };
 
 enum _GsmConsolekitError {
-        GSM_CONSOLEKIT_ERROR_RESTARTING = 0,
+        GSM_CONSOLEKIT_ERROR_QUERYING_STOP = 0,
+        GSM_CONSOLEKIT_ERROR_RESTARTING,
         GSM_CONSOLEKIT_ERROR_STOPPING
 };
 
+/* Keep in sync with the ConsoleKit specification */
+enum _GsmConsoleKitStopCanProceed {
+        GSM_CONSOLEKIT_STOP_NOT_ALLOWED = 0,
+        GSM_CONSOLEKIT_STOP_PRIVILEGES_REQUIRED,
+        GSM_CONSOLEKIT_STOP_ALLOWED
+};
+
 #define GSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW "LoginWindow"
 
 GType            gsm_consolekit_get_type        (void);
@@ -77,14 +93,20 @@ 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);
 
+void             gsm_consolekit_stop_response   (GsmConsolekit *manager,
+                                                 gboolean       ok_to_proceed,
+                                                 const char    *reason);
+
+void             gsm_consolekit_query_stop      (GsmConsolekit *manager);
+#define          gsm_consolekit_query_restart gsm_consolekit_query_stop
+
+void             gsm_consolekit_cancel_stop     (GsmConsolekit *manager);
+#define          gsm_consolekit_cancel_restart gsm_consolekit_cancel_stop
+
 void             gsm_consolekit_attempt_stop    (GsmConsolekit *manager);
 
 void             gsm_consolekit_attempt_restart (GsmConsolekit *manager);
@@ -94,6 +116,16 @@ void             gsm_consolekit_set_session_idle (GsmConsolekit *manager,
 
 gchar           *gsm_consolekit_get_current_session_type (GsmConsolekit *manager);
 
+const char      *gsm_consolekit_get_current_session_id (GsmConsolekit *manager);
+GSList          *gsm_consolekit_get_sessions           (GsmConsolekit *manager);
+const char      *gsm_consolekit_get_session_user       (GsmConsolekit *manager,
+                                                        const char    *session_id);
+GSList          *gsm_consolekit_get_inhibitors         (GsmConsolekit *manager);
+char            *gsm_consolekit_get_inhibitor_reason   (GsmConsolekit *manager,
+                                                        const char    *inhibitor_id);
+char            *gsm_consolekit_get_inhibitor_session  (GsmConsolekit *manager,
+                                                        const char    *inhibitor_id);
+
 GsmConsolekit   *gsm_get_consolekit             (void);
 
 G_END_DECLS
diff --git a/gnome-session/gsm-inhibit-dialog.c b/gnome-session/gsm-inhibit-dialog.c
index da59ab0..7614b93 100644
--- a/gnome-session/gsm-inhibit-dialog.c
+++ b/gnome-session/gsm-inhibit-dialog.c
@@ -71,6 +71,7 @@ struct GsmInhibitDialogPrivate
         gboolean           have_xrender;
         int                xrender_event_base;
         int                xrender_error_base;
+        gchar             *extra_text;
 };
 
 enum {
@@ -1157,3 +1158,17 @@ gsm_inhibit_dialog_new (GsmStore *inhibitors,
 
         return GTK_WIDGET (object);
 }
+
+void
+gsm_inhibit_dialog_add_item (GsmInhibitDialog *dialog,
+                             const gchar      *name,
+                             const gchar      *reason,
+                             GdkPixbuf        *image)
+{
+        gtk_list_store_insert_with_values (dialog->priv->list_store,
+                                           NULL, 0,
+                                           INHIBIT_IMAGE_COLUMN, image,
+                                           INHIBIT_NAME_COLUMN, name,
+                                           INHIBIT_REASON_COLUMN, reason,
+                                           -1);
+}
diff --git a/gnome-session/gsm-inhibit-dialog.h b/gnome-session/gsm-inhibit-dialog.h
index f4d31a5..772f2d3 100644
--- a/gnome-session/gsm-inhibit-dialog.h
+++ b/gnome-session/gsm-inhibit-dialog.h
@@ -65,6 +65,11 @@ GtkWidget            * gsm_inhibit_dialog_new                (GsmStore         *
                                                               int               action);
 GtkTreeModel         * gsm_inhibit_dialog_get_model          (GsmInhibitDialog *dialog);
 
+void                   gsm_inhibit_dialog_add_item           (GsmInhibitDialog *dialog,
+                                                              const gchar      *name,
+                                                              const gchar      *reason,
+                                                              GdkPixbuf        *image);
+
 G_END_DECLS
 
 #endif /* __GSM_INHIBIT_DIALOG_H */
diff --git a/gnome-session/gsm-inhibitor.c b/gnome-session/gsm-inhibitor.c
index 4b7178c..58748c4 100644
--- a/gnome-session/gsm-inhibitor.c
+++ b/gnome-session/gsm-inhibitor.c
@@ -480,6 +480,7 @@ gsm_inhibitor_finalize (GObject *object)
 {
         GsmInhibitor *inhibitor = (GsmInhibitor *) object;
 
+        g_print ("finalizing inhibitor %s\n", inhibitor->priv->id);
         g_free (inhibitor->priv->id);
         g_free (inhibitor->priv->bus_name);
         g_free (inhibitor->priv->app_id);
diff --git a/gnome-session/gsm-logout-dialog.c b/gnome-session/gsm-logout-dialog.c
index 760d0ce..42cd8c5 100644
--- a/gnome-session/gsm-logout-dialog.c
+++ b/gnome-session/gsm-logout-dialog.c
@@ -291,11 +291,7 @@ gsm_logout_dialog_timeout (gpointer data)
         }
 
         if (session_type == NULL) {
-		GsmConsolekit *consolekit;
-
-                consolekit = gsm_get_consolekit ();
-                session_type = gsm_consolekit_get_current_session_type (consolekit);
-                g_object_unref (consolekit);
+                session_type = gsm_consolekit_get_current_session_type (logout_dialog->priv->consolekit);
         }
 
         if (g_strcmp0 (session_type, GSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW) != 0) {
diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c
index 49fefe6..c5d3571 100644
--- a/gnome-session/gsm-manager.c
+++ b/gnome-session/gsm-manager.c
@@ -92,10 +92,8 @@ 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;
 
@@ -111,6 +109,8 @@ struct GsmManagerPrivate
         GsmManagerPhase         phase;
         guint                   phase_timeout_id;
         GSList                 *pending_apps;
+        gboolean                initiated_ck_stop;
+        gboolean                received_query_stop;
         gboolean                forceful_logout;
         GSList                 *query_clients;
         guint                   query_timeout_id;
@@ -384,59 +384,30 @@ 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. */
+        /* Reply to the Stop ConsoleKit signal */
+        consolekit = gsm_get_consolekit ();
+        gsm_consolekit_stop_response (consolekit, TRUE, NULL);
+        g_object_unref (consolekit);
 
         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);
+        case GSM_MANAGER_LOGOUT_SHUTDOWN:
+                /* nothing to do: we already asked ConsoleKit to do the
+                 * stop/restart */
+                gtk_main_quit ();
+                break;
                 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 ();
@@ -447,6 +418,8 @@ gsm_manager_quit (GsmManager *manager)
         }
 }
 
+//FIXME: check that we do end_phase only when we're sure of the phase we're in (eg: someone might open the logout dialog (still RUNNING), and then with CK, we might enter the QUERY_END; if the user presses logout, the code will assume RUNNING->QUERY_END while it will do QUERY_END->END)
+//FIXME: if we enter QUERY_END because of CK, destroy logout dialog?
 static void
 end_phase (GsmManager *manager)
 {
@@ -765,6 +738,9 @@ do_phase_exit (GsmManager *manager)
                 gsm_store_foreach (manager->priv->clients,
                                    (GsmStoreFunc)_client_stop,
                                    NULL);
+                /* each time a client exits, we'll notice in
+                 * remove_clients_for_connection() so we can end the phase
+                 * before the timeout if everything goes well */
         } else {
                 end_phase (manager);
         }
@@ -888,6 +864,16 @@ cancel_end_session (GsmManager *manager)
         /* switch back to running phase */
         g_debug ("GsmManager: Cancelling the end of session");
 
+        if (manager->priv->initiated_ck_stop) {
+                GsmConsolekit *consolekit;
+
+                manager->priv->initiated_ck_stop = FALSE;
+
+                consolekit = gsm_get_consolekit ();
+                gsm_consolekit_cancel_stop (consolekit);
+                g_object_unref (consolekit);
+        }
+
         /* remove the dialog before we remove the inhibitors, else the dialog
          * will activate itself automatically when the last inhibitor will be
          * removed */
@@ -1033,6 +1019,48 @@ manager_attempt_suspend (GsmManager *manager)
 }
 
 static void
+quit_request_completed (GsmConsolekit *consolekit,
+                        GError        *error,
+                        GsmManager    *manager)
+{
+        g_object_unref (consolekit);
+
+        if (error != NULL) {
+                cancel_end_session (manager);
+        }
+}
+
+static void
+manager_attempt_stop_restart (GsmManager *manager)
+{
+        GsmConsolekit *consolekit;
+
+        consolekit = gsm_get_consolekit ();
+        switch (manager->priv->logout_type) {
+        case GSM_MANAGER_LOGOUT_REBOOT:
+                g_signal_connect (consolekit,
+                                  "request-completed",
+                                  G_CALLBACK (quit_request_completed),
+                                  manager);
+                gsm_consolekit_attempt_restart (consolekit);
+                break;
+        case GSM_MANAGER_LOGOUT_SHUTDOWN:
+                g_signal_connect (consolekit,
+                                  "request-completed",
+                                  G_CALLBACK (quit_request_completed),
+                                  manager);
+                gsm_consolekit_attempt_stop (consolekit);
+                break;
+        default:
+                g_warning ("Unexpected logout type %d when attempting to restart or stop",
+                           manager->priv->logout_type);
+                /* we should never have anything else */
+                break;
+        }
+        g_object_unref (consolekit);
+}
+
+static void
 do_inhibit_dialog_action (GsmManager *manager,
                           int         action)
 {
@@ -1046,12 +1074,17 @@ do_inhibit_dialog_action (GsmManager *manager,
         case GSM_LOGOUT_ACTION_SLEEP:
                 manager_attempt_suspend (manager);
                 break;
-        case GSM_LOGOUT_ACTION_SHUTDOWN:
-        case GSM_LOGOUT_ACTION_REBOOT:
         case GSM_LOGOUT_ACTION_LOGOUT:
                 manager->priv->forceful_logout = TRUE;
                 end_phase (manager);
                 break;
+        case GSM_LOGOUT_ACTION_SHUTDOWN:
+        case GSM_LOGOUT_ACTION_REBOOT:
+                if (gsm_manager_is_logout_inhibited (manager)) {
+                        manager->priv->forceful_logout = TRUE;
+                }
+                manager_attempt_stop_restart (manager);
+                break;
         default:
                 g_assert_not_reached ();
                 break;
@@ -1098,24 +1131,10 @@ inhibit_dialog_response (GsmInhibitDialog *dialog,
 }
 
 static void
-query_end_session_complete (GsmManager *manager)
+inhibit_dialog_present (GsmManager *manager)
 {
         GsmLogoutAction action;
 
-        g_debug ("GsmManager: query end session complete");
-
-        /* Remove the timeout since this can be called from outside the timer
-         * and we don't want to have it called twice */
-        if (manager->priv->query_timeout_id > 0) {
-                g_source_remove (manager->priv->query_timeout_id);
-                manager->priv->query_timeout_id = 0;
-        }
-
-        if (! gsm_manager_is_logout_inhibited (manager)) {
-                end_phase (manager);
-                return;
-        }
-
         if (manager->priv->inhibit_dialog != NULL) {
                 g_debug ("GsmManager: inhibit dialog already up");
                 gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog));
@@ -1127,12 +1146,10 @@ query_end_session_complete (GsmManager *manager)
                 action = GSM_LOGOUT_ACTION_LOGOUT;
                 break;
         case GSM_MANAGER_LOGOUT_REBOOT:
-        case GSM_MANAGER_LOGOUT_REBOOT_INTERACT:
         case GSM_MANAGER_LOGOUT_REBOOT_GDM:
                 action = GSM_LOGOUT_ACTION_REBOOT;
                 break;
         case GSM_MANAGER_LOGOUT_SHUTDOWN:
-        case GSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT:
         case GSM_MANAGER_LOGOUT_SHUTDOWN_GDM:
                 action = GSM_LOGOUT_ACTION_SHUTDOWN;
                 break;
@@ -1151,12 +1168,222 @@ query_end_session_complete (GsmManager *manager)
                                                                 manager->priv->clients,
                                                                 action);
 
+        if (action == GSM_LOGOUT_ACTION_SHUTDOWN ||
+            action == GSM_LOGOUT_ACTION_REBOOT) {
+                GsmConsolekit *consolekit;
+                GSList *sessions;
+                GSList *inhibitors;
+                GSList *s, *l;
+                GdkPixbuf *pixbuf;
+                const gchar *user;
+                gchar *reason;
+                gchar *session;
+                gchar *is;
+
+                pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+                                                   "stock_person",
+                                                   32,
+                                                   GTK_ICON_LOOKUP_FORCE_SIZE,
+                                                   NULL);
+
+                consolekit = gsm_get_consolekit ();
+                sessions = gsm_consolekit_get_sessions (consolekit);
+                inhibitors = gsm_consolekit_get_inhibitors (consolekit);
+
+                for (s = sessions; s; s = s->next) {
+                        session = s->data;
+
+                        user = gsm_consolekit_get_session_user (consolekit, session);
+                        reason = _("User session");
+                        for (l = inhibitors; l; l = l->next) {
+                                is = gsm_consolekit_get_inhibitor_session (consolekit, l->data);
+                                if (g_strcmp0 (is, session) == 0) {
+                                        reason = gsm_consolekit_get_inhibitor_reason (consolekit, l->data);
+                                        g_free (l->data);
+                                        inhibitors = g_slist_delete_link (inhibitors, l);
+                                        break;
+                                }
+                        }
+
+                        if (g_strcmp0 (session, gsm_consolekit_get_current_session_id (consolekit)) == 0)
+                                continue;
+
+                        gsm_inhibit_dialog_add_item (GSM_INHIBIT_DIALOG (manager->priv->inhibit_dialog),
+                                                     user, reason, pixbuf);
+                }
+                g_slist_foreach (sessions, (GFunc)g_free, NULL);
+                g_slist_free (sessions);
+                if (pixbuf)
+                        g_object_unref (pixbuf);
+
+                pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+                                                   "gtk-execute",
+                                                   32,
+                                                   GTK_ICON_LOOKUP_FORCE_SIZE,
+                                                   NULL);
+
+                for (l = inhibitors; l; l = l->next) {
+                        is = gsm_consolekit_get_inhibitor_session (consolekit, l->data);
+                        /* ignore session inhibitors unless we show their session */
+                        if (is && *is)
+                                continue;
+
+                        reason = gsm_consolekit_get_inhibitor_reason (consolekit, l->data);
+                        gsm_inhibit_dialog_add_item (GSM_INHIBIT_DIALOG (manager->priv->inhibit_dialog),
+                                                     _("System process"), reason, pixbuf);
+                }
+                g_slist_foreach (inhibitors, (GFunc)g_free, NULL);
+                g_slist_free (inhibitors);
+                if (pixbuf)
+                        g_object_unref (pixbuf);
+
+                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);
+}
+
+static void
+on_consolekit_query_stop_completed (GsmConsolekit               *consolekit,
+                                    GsmConsoleKitStopCanProceed  can_proceed,
+                                    unsigned int                 inhibitors_nb,
+                                    unsigned int                 session_nb,
+                                    GError                      *error,
+                                    GsmManager                  *manager)
+{
+        if (error != NULL) {
+                /* ConsoleKit stop process didn't work, we fallback to the old
+                 * way */
+                manager->priv->initiated_ck_stop = FALSE;
+
+                switch (manager->priv->logout_type) {
+                case GSM_MANAGER_LOGOUT_REBOOT:
+                        manager->priv->logout_type = GSM_MANAGER_LOGOUT_REBOOT_GDM;
+                        break;
+                case GSM_MANAGER_LOGOUT_SHUTDOWN:
+                        manager->priv->logout_type = GSM_MANAGER_LOGOUT_SHUTDOWN_GDM;
+                        break;
+                default:
+                        /* we should never have anything else */
+                        g_assert_not_reached ();
+                        break;
+                }
+
+                g_assert (manager->priv->phase == GSM_MANAGER_PHASE_QUERY_END_SESSION);
+
+                if (!gsm_manager_is_logout_inhibited (manager)) {
+                        end_phase (manager);
+                        return;
+                }
+
+                if (manager->priv->inhibit_dialog)
+                        gtk_widget_destroy (GTK_WIDGET (manager->priv->inhibit_dialog));
+                manager->priv->inhibit_dialog = NULL;
+
+                inhibit_dialog_present (manager);
+                return;
+        }
+
+        if (can_proceed == GSM_CONSOLEKIT_STOP_NOT_ALLOWED) {
+                //TODO: still show some inhibit dialog to explain what's going on, but just listing the other sessions. Note that we will probably need to destroy this inhibit dialog if we start a new logout process.
+                cancel_end_session (manager);
+                return;
+        }
+
+        // TODO We currently do the stupid way: ignore the inhibitors that CK gives us
+
+        g_print ("query-stop-completed: logout inhibited: %d, ck inhibitors: %d, sessions: %d\n",
+                gsm_manager_is_logout_inhibited (manager),
+                inhibitors_nb, session_nb);
+        if (gsm_manager_is_logout_inhibited (manager) ||
+            inhibitors_nb > 0 || session_nb > 1)  {
+                inhibit_dialog_present (manager);
+                return;
+        }
+
+        manager_attempt_stop_restart (manager);
+}
+
+
+static void
+query_end_session_complete (GsmManager *manager)
+{
+        GsmConsolekit *consolekit;
+
+        g_debug ("GsmManager: query end session complete");
+
+        /* Remove the timeout since this can be called from outside the timer
+         * and we don't want to have it called twice */
+        if (manager->priv->query_timeout_id > 0) {
+                g_source_remove (manager->priv->query_timeout_id);
+                manager->priv->query_timeout_id = 0;
+        }
+
+        switch (manager->priv->logout_type) {
+        case GSM_MANAGER_LOGOUT_LOGOUT:
+                break;
+        case GSM_MANAGER_LOGOUT_REBOOT:
+        case GSM_MANAGER_LOGOUT_SHUTDOWN:
+                //TODO: would be nice to be able to show the inhibit dialog already, and add a spinner until we get inhibitors from CK too displayed there
+                //TODO: maybe change the timeout for the query_stop dbus call so that we don't wait too long here?
+                /* Let's start the ConsoleKit Stop process */
+                consolekit = gsm_get_consolekit ();
+                g_signal_connect (consolekit,
+                                  "query-stop-completed",
+                                  G_CALLBACK (on_consolekit_query_stop_completed),
+                                  manager);
+
+                manager->priv->initiated_ck_stop = TRUE;
+                gsm_consolekit_query_stop (consolekit);
+                g_object_unref (consolekit);
+                break;
+        case GSM_MANAGER_LOGOUT_REBOOT_GDM:
+        case GSM_MANAGER_LOGOUT_SHUTDOWN_GDM:
+                /* at this point, we should never have the GDM types */
+                g_assert_not_reached ();
+                break;
+        default:
+                g_assert_not_reached ();
+                break;
+        }
+
+        /* If we initiated the ConsoleKit stop process, we will continue when
+         * we the QueryStop call returns from ConsoleKit. */
+        if (manager->priv->initiated_ck_stop) {
+                return;
+        }
+
+        if (manager->priv->received_query_stop) {
+                /* Reply to the QueryStop ConsoleKit signal */
+                manager->priv->received_query_stop = FALSE;
 
+                consolekit = gsm_get_consolekit ();
+
+                if (gsm_manager_is_logout_inhibited (manager)) {
+                        //FIXME: build a better reason
+                        gsm_consolekit_stop_response (consolekit, FALSE,
+                                                      _("Session is currently inhibited."));
+                } else {
+                        gsm_consolekit_stop_response (consolekit, TRUE, NULL);
+                }
+
+                g_object_unref (consolekit);
+
+                return;
+        }
+
+        if (manager->priv->logout_type == GSM_MANAGER_LOGOUT_LOGOUT) {
+                if (gsm_manager_is_logout_inhibited (manager)) {
+                        inhibit_dialog_present (manager);
+                }
+                else {
+                        end_phase (manager);
+                }
+        }
 }
 
 static guint32
@@ -1284,6 +1511,7 @@ start_phase (GsmManager *manager)
         g_slist_free (manager->priv->next_query_clients);
         manager->priv->next_query_clients = NULL;
 
+        //FIXME: maybe actually do what the timeout should have done, so it's not lost?
         if (manager->priv->query_timeout_id > 0) {
                 g_source_remove (manager->priv->query_timeout_id);
                 manager->priv->query_timeout_id = 0;
@@ -1357,16 +1585,174 @@ debug_app_summary (GsmManager *manager)
         }
 }
 
+static void
+on_consolekit_query_stop (GsmConsolekit *consolekit,
+                          GsmManager    *manager)
+{
+        g_debug ("GsmManager: QueryStop from ConsoleKit");
+
+        /* if we initiated the ConsoleKit stop process, then we're already
+         * ready so we can reply immediately */
+        if (manager->priv->initiated_ck_stop) {
+                gsm_consolekit_stop_response (consolekit, TRUE, NULL);
+                return;
+        }
+
+        /* In theory, we can not be in the process of ending the session with
+         * ConsoleKit support and receive this signal. But we still try to
+         * handle it the best way possible, in case of a ConsoleKit bug, or for
+         * future changes in semantics.
+         *
+         * If we're already in the process of ending the session, we have two
+         * cases:
+         *   - we're in the middle of GSM_MANAGER_PHASE_QUERY_END_SESSION: we
+         *     don't want to reply immediately, since this will be done once we
+         *     reach the end of the phase.
+         *   - we're at the end of GSM_MANAGER_PHASE_QUERY_END_SESSION, or
+         *     later: in this case, we can reply immediately since we're ready
+         *     to move on anyway or we've already moved on.
+         */
+        if (manager->priv->phase == GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+                g_warning ("Receiving a QueryStop signal from ConsoleKit "
+                           "while already in the process of ending the "
+                           "session (phase %s)",
+                           phase_num_to_name (manager->priv->phase));
+                /* We're at the end of the phase */
+                if (manager->priv->query_timeout_id > 0) {
+                        gsm_consolekit_stop_response (consolekit, TRUE, NULL);
+                }
+                return;
+        } else if (manager->priv->phase > GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+                g_warning ("Receiving a QueryStop signal from ConsoleKit "
+                           "while already in the process of ending the "
+                           "session (phase %s)",
+                           phase_num_to_name (manager->priv->phase));
+                gsm_consolekit_stop_response (consolekit, TRUE, NULL);
+                return;
+        }
+
+        /* last case: we're in a running session, or even before that. We can
+         * directly move to the phase starting the end process */
+
+        /* no user interaction is allowed */
+        manager->priv->forceful_logout = TRUE;
+        manager->priv->logout_type = GSM_MANAGER_LOGOUT_LOGOUT;
+        manager->priv->received_query_stop = TRUE;
+
+        //FIXME: how to make sure the internal timeout from CK is > internal timeout of gnome-session for this phase?
+        gsm_manager_set_phase (manager, GSM_MANAGER_PHASE_QUERY_END_SESSION);
+        start_phase (manager);
+}
+
+static void
+on_consolekit_stop (GsmConsolekit *consolekit,
+                    GsmManager    *manager)
+{
+        g_debug ("GsmManager: Stop from ConsoleKit");
+
+        //FIXME: how to make sure the internal timeout from CK is > internal timeout of gnome-session for END_SESSION + EXIT?
+
+        switch (manager->priv->phase) {
+        case GSM_MANAGER_PHASE_STARTUP:
+        case GSM_MANAGER_PHASE_INITIALIZATION:
+        case GSM_MANAGER_PHASE_WINDOW_MANAGER:
+        case GSM_MANAGER_PHASE_PANEL:
+        case GSM_MANAGER_PHASE_DESKTOP:
+        case GSM_MANAGER_PHASE_APPLICATION:
+        case GSM_MANAGER_PHASE_RUNNING:
+                /* This should not happen, since we should have had a QueryStop
+                 * before. Still handle it. */
+                g_warning ("Receiving a Stop signal from ConsoleKit "
+                           "while not in the process of ending the "
+                           "session (phase %s)",
+                           phase_num_to_name (manager->priv->phase));
+
+                /* no user interaction is allowed */
+                manager->priv->forceful_logout = TRUE;
+                manager->priv->logout_type = GSM_MANAGER_LOGOUT_LOGOUT;
+
+                gsm_manager_set_phase (manager, GSM_MANAGER_PHASE_END_SESSION);
+                start_phase (manager);
+                break;
+        case GSM_MANAGER_PHASE_QUERY_END_SESSION:
+                /* Are we at the end of the phase? If no, then do as if we
+                 * timed out. */
+                if (manager->priv->query_timeout_id > 0) {
+                        g_source_remove (manager->priv->query_timeout_id);
+                        manager->priv->query_timeout_id = 0;
+                        _on_query_end_session_timeout (manager);
+                }
+
+                end_phase (manager);
+                break;
+        /* If we're in GSM_MANAGER_PHASE_END_SESSION or in
+         * GSM_MANAGER_PHASE_EXIT, then we're already in the process of ending
+         * everything, and we'll send the reply when we'll be done. Unless
+         * we're already done (end of GSM_MANAGER_PHASE_EXIT).
+         */
+        case GSM_MANAGER_PHASE_END_SESSION:
+                g_warning ("Receiving a Stop signal from ConsoleKit while "
+                           "already finishing the process of ending the "
+                           "session (phase %s)",
+                           phase_num_to_name (manager->priv->phase));
+                break;
+        case GSM_MANAGER_PHASE_EXIT:
+                g_warning ("Receiving a Stop signal from ConsoleKit while "
+                           "already finishing the process of ending the "
+                           "session (phase %s)",
+                           phase_num_to_name (manager->priv->phase));
+
+                /* We're at the end of the phase */
+                if (gsm_store_size (manager->priv->clients) == 0) {
+                        gsm_consolekit_stop_response (consolekit, TRUE, NULL);
+                }
+                break;
+        default:
+                g_assert_not_reached ();
+                break;
+        }
+}
+
+static void
+on_consolekit_cancel_stop (GsmConsolekit *consolekit,
+                           GsmManager    *manager)
+{
+        g_debug ("GsmManager: CancelStop from ConsoleKit");
+
+        cancel_end_session (manager);
+}
+
 void
 gsm_manager_start (GsmManager *manager)
 {
+        GsmConsolekit *consolekit;
+
         g_debug ("GsmManager: GSM starting to manage");
 
         g_return_if_fail (GSM_IS_MANAGER (manager));
 
+        //FIXME is this the better place to do that? Maybe we should only do it
+        //when we start RUNNING?
+        //FIXME unref consolekit, but when? Or should we just keep a ref all the time?
+        consolekit = gsm_get_consolekit ();
+        g_signal_connect (consolekit,
+                          "query-stop",
+                          G_CALLBACK (on_consolekit_query_stop),
+                          manager);
+        g_signal_connect (consolekit,
+                          "stop",
+                          G_CALLBACK (on_consolekit_stop),
+                          manager);
+        g_signal_connect (consolekit,
+                          "cancel-stop",
+                          G_CALLBACK (on_consolekit_cancel_stop),
+                          manager);
+
         gsm_manager_set_phase (manager, GSM_MANAGER_PHASE_INITIALIZATION);
         debug_app_summary (manager);
         start_phase (manager);
+
+        g_object_unref (consolekit);
 }
 
 static gboolean
@@ -1640,6 +2026,7 @@ remove_inhibitors_for_connection (GsmManager *manager,
 
         debug_inhibitors (manager);
 
+        g_print ("remove inhibitors for bus name %s\n", service_name);
         n_removed = gsm_store_foreach_remove (manager->priv->inhibitors,
                                               (GsmStoreFunc)inhibitor_has_bus_name,
                                               &data);
@@ -1876,6 +2263,7 @@ on_client_end_session_response (GsmClient  *client,
 
         g_debug ("GsmManager: Response from end session request: is-ok=%d do-last=%d cancel=%d reason=%s", is_ok, do_last, cancel, reason ? reason :"");
 
+        //FIXME Cancel not allowed if we're in QUERY_END_SESSION or END_SESSION because of CK
         if (cancel) {
                 cancel_end_session (manager);
                 return;
@@ -1922,7 +2310,8 @@ on_client_end_session_response (GsmClient  *client,
         }
 
         if (manager->priv->phase == GSM_MANAGER_PHASE_QUERY_END_SESSION) { 
-                if (manager->priv->query_clients == NULL) {
+                if (manager->priv->query_clients == NULL &&
+                    manager->priv->query_timeout_id > 0) {
                         query_end_session_complete (manager);
                 }
         } else if (manager->priv->phase == GSM_MANAGER_PHASE_END_SESSION) {
@@ -2407,6 +2796,7 @@ on_presence_status_changed (GsmPresence  *presence,
         consolekit = gsm_get_consolekit ();
         gsm_consolekit_set_session_idle (consolekit,
                                          (status == GSM_PRESENCE_STATUS_IDLE));
+	g_object_unref (consolekit);
 }
 
 static void
@@ -2579,133 +2969,29 @@ gsm_manager_is_suspend_inhibited (GsmManager *manager)
 }
 
 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");
 
-        /* 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.
-         */
+        /* Note: we don't start the ConsoleKit stop process here because we
+         * want to let apps interact with the user if they need to. Since we're
+         * initiating the process, that's fine. */
 
-        consolekit = gsm_get_consolekit ();
-        g_signal_connect (consolekit,
-                          "privileges-completed",
-                          G_CALLBACK (request_reboot_privileges_completed),
-                          manager);
-        success = gsm_consolekit_get_restart_privileges (consolekit);
+        manager->priv->logout_type = GSM_MANAGER_LOGOUT_REBOOT;
 
-        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);
-        }
-}
-
-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_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);
-        }
+        end_phase (manager);
 }
 
 static void
 request_shutdown (GsmManager *manager)
 {
-        GsmConsolekit *consolekit;
-        gboolean       success;
-
         g_debug ("GsmManager: requesting shutdown");
 
-        /* See the comment in request_reboot() for some more details about how
-         * this works. */
+        /* See comment in request_reboot() */
 
-        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->logout_type = GSM_MANAGER_LOGOUT_SHUTDOWN;
 
-        if (!success) {
-                g_signal_handlers_disconnect_by_func (consolekit,
-                                                      request_shutdown_privileges_completed,
-                                                      manager);
-                g_object_unref (consolekit);
-
-                manager->priv->logout_type = GSM_MANAGER_LOGOUT_SHUTDOWN_GDM;
-                end_phase (manager);
-        }
+        end_phase (manager);
 }
 
 static void
diff --git a/gnome-session/gsm-marshal.list b/gnome-session/gsm-marshal.list
index f31a8b1..62941c2 100644
--- a/gnome-session/gsm-marshal.list
+++ b/gnome-session/gsm-marshal.list
@@ -1,3 +1,3 @@
 BOOLEAN:POINTER
 VOID:BOOLEAN,BOOLEAN,BOOLEAN,STRING
-VOID:BOOLEAN,BOOLEAN,POINTER
+VOID:UINT,UINT,UINT,POINTER
diff --git a/gnome-session/main.c b/gnome-session/main.c
index 87d46ae..7b39be7 100644
--- a/gnome-session/main.c
+++ b/gnome-session/main.c
@@ -57,7 +57,7 @@
 
 static gboolean failsafe = FALSE;
 static gboolean show_version = FALSE;
-static gboolean debug = FALSE;
+static gboolean debug = TRUE;
 
 static void
 on_bus_name_lost (DBusGProxy *bus_proxy,
