---
 gnome-panel/Makefile.am                           |    4 
 gnome-panel/libpanel-util/panel-session-manager.c |   23 +
 gnome-panel/panel-gdm.c                           |  417 ++++++++++++++++++++++
 gnome-panel/panel-gdm.h                           |   52 ++
 gnome-panel/panel-logout.c                        |  402 +++++++++++++++++++++
 gnome-panel/panel-logout.h                        |   66 +++
 gnome-panel/panel-session.c                       |   28 +
 gnome-panel/panel-session.h                       |    1 
 8 files changed, 993 insertions(+)

Index: b/gnome-panel/panel-gdm.c
===================================================================
--- /dev/null
+++ b/gnome-panel/panel-gdm.c
@@ -0,0 +1,417 @@
+/*
+ * gdm-protocol.c: GDM logout action protocol implementation
+ *
+ * Copyright (C) 2005 Raffaele Sandrini
+ * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2002, 2003 George Lebl
+ * Copyright (C) 2001 Queen of England,
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ *      Raffaele Sandrini <rasa@gmx.ch>
+ *      George Lebl <jirka@5z.com>
+ *      Mark McLoughlin <mark@skynet.ie>
+ */
+
+#include <config.h>
+
+#include "panel-gdm.h"
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <X11/Xauth.h>
+#include <gdk/gdk.h>
+
+#define GDM_PROTOCOL_UPDATE_INTERVAL 1 /* seconds */
+
+#define GDM_PROTOCOL_SOCKET_PATH "/var/run/gdm_socket"
+
+#define GDM_PROTOCOL_MSG_CLOSE         "CLOSE"
+#define GDM_PROTOCOL_MSG_VERSION       "VERSION"
+#define GDM_PROTOCOL_MSG_AUTHENTICATE  "AUTH_LOCAL"
+#define GDM_PROTOCOL_MSG_QUERY_ACTION  "QUERY_LOGOUT_ACTION"
+#define GDM_PROTOCOL_MSG_SET_ACTION    "SET_SAFE_LOGOUT_ACTION"
+#define GDM_PROTOCOL_MSG_FLEXI_XSERVER "FLEXI_XSERVER"
+
+#define GDM_ACTION_STR_NONE     "NONE"
+#define GDM_ACTION_STR_SHUTDOWN "HALT"
+#define GDM_ACTION_STR_REBOOT   "REBOOT"
+#define GDM_ACTION_STR_SUSPEND  "SUSPEND"
+
+typedef struct {
+        int fd;
+	char *auth_cookie;
+
+        GdmLogoutAction available_actions;
+        GdmLogoutAction current_actions;
+
+        time_t last_update;
+} GdmProtocolData;
+
+static GdmProtocolData gdm_protocol_data = {
+        0,
+        NULL,
+        GDM_LOGOUT_ACTION_NONE,
+        GDM_LOGOUT_ACTION_NONE,
+        0
+};
+
+static char *
+gdm_send_protocol_msg (GdmProtocolData *data,
+                       const char      *msg)
+{
+        GString *retval;
+        char     buf[256];
+        char    *p;
+        int      len;
+
+        p = g_strconcat (msg, "\n", NULL);
+        if (write (data->fd, p, strlen (p)) < 0) {
+                g_free (p);
+
+                g_warning ("Failed to send message to GDM: %s",
+                           g_strerror (errno));
+                return NULL;
+        }
+        g_free (p);
+
+        p = NULL;
+        retval = NULL;
+        while ((len = read (data->fd, buf, sizeof (buf) - 1)) > 0) {
+                buf[len] = '\0';
+
+                if (!retval)
+                        retval = g_string_new (buf);
+                else
+                        retval = g_string_append (retval, buf);
+
+                if ((p = strchr (retval->str, '\n')))
+                        break;
+        }
+
+        if (p) *p = '\0';
+
+        return retval ? g_string_free (retval, FALSE) : NULL;
+}
+
+static char *
+get_display_number (void)
+{
+        const char *display_name;
+        char       *retval;
+        char       *p;
+
+        display_name = gdk_display_get_name (gdk_display_get_default ());
+
+        p = strchr (display_name, ':');
+        if (!p)
+                return g_strdup ("0");
+
+        while (*p == ':') p++;
+
+        retval = g_strdup (p);
+
+        p = strchr (retval, '.');
+        if (p != NULL)
+                *p = '\0';
+
+        return retval;
+}
+
+static gboolean
+gdm_authenticate_connection (GdmProtocolData *data)
+{
+#define GDM_MIT_MAGIC_COOKIE_LEN 16
+
+        const char *xau_path;
+        FILE       *f;
+        Xauth      *xau;
+        char       *display_number;
+        gboolean    retval;
+
+        if (data->auth_cookie) {
+                char *msg;
+                char *response;
+
+                msg = g_strdup_printf (GDM_PROTOCOL_MSG_AUTHENTICATE " %s",
+                                       data->auth_cookie);
+                response = gdm_send_protocol_msg (data, msg);
+                g_free (msg);
+
+                if (response && !strcmp (response, "OK")) {
+                        g_free (response);
+                        return TRUE;
+                } else {
+                        g_free (response);
+                        g_free (data->auth_cookie);
+                        data->auth_cookie = NULL;
+                }
+        }
+
+        if (!(xau_path = XauFileName ()))
+                return FALSE;
+
+        if (!(f = fopen (xau_path, "r")))
+                return FALSE;
+
+        retval = FALSE;
+        display_number = get_display_number ();
+
+        while ((xau = XauReadAuth (f))) {
+                char  buffer[40]; /* 2*16 == 32, so 40 is enough */
+                char *msg;
+                char *response;
+                int   i;
+
+                if (xau->family != FamilyLocal ||
+                    strncmp (xau->number, display_number, xau->number_length) ||
+                    strncmp (xau->name, "MIT-MAGIC-COOKIE-1", xau->name_length) ||
+                    xau->data_length != GDM_MIT_MAGIC_COOKIE_LEN) {
+                        XauDisposeAuth (xau);
+                        continue;
+                }
+
+                for (i = 0; i < GDM_MIT_MAGIC_COOKIE_LEN; i++)
+                        g_snprintf (buffer + 2*i, 3, "%02x", (guint)(guchar)xau->data[i]);
+
+                XauDisposeAuth (xau);
+
+                msg = g_strdup_printf (GDM_PROTOCOL_MSG_AUTHENTICATE " %s", buffer);
+                response = gdm_send_protocol_msg (data, msg);
+                g_free (msg);
+
+                if (response && !strcmp (response, "OK")) {
+			data->auth_cookie = g_strdup (buffer);
+                        g_free (response);
+                        retval = TRUE;
+                        break;
+                }
+
+                g_free (response);
+        }
+
+        g_free (display_number);
+
+        fclose (f);
+
+        return retval;
+
+#undef GDM_MIT_MAGIC_COOKIE_LEN
+}
+
+static void
+gdm_shutdown_protocol_connection (GdmProtocolData *data)
+{
+        if (data->fd)
+                close (data->fd);
+        data->fd = 0;
+}
+
+static gboolean
+gdm_init_protocol_connection (GdmProtocolData *data)
+{
+        struct sockaddr_un  addr;
+        char               *response;
+
+        g_assert (data->fd <= 0);
+
+        data->fd = socket (AF_UNIX, SOCK_STREAM, 0);
+        if (data->fd < 0) {
+                g_warning ("Failed to create GDM socket: %s",
+                           g_strerror (errno));
+		gdm_shutdown_protocol_connection (data);
+                return FALSE;
+        }
+
+	if (g_file_test (GDM_PROTOCOL_SOCKET_PATH, G_FILE_TEST_EXISTS))
+	  strcpy (addr.sun_path, GDM_PROTOCOL_SOCKET_PATH);
+	else
+	  strcpy (addr.sun_path, "/tmp/.gdm_socket");
+
+	addr.sun_family = AF_UNIX;
+
+        if (connect (data->fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
+                g_warning ("Failed to establish a connection with GDM: %s",
+                           g_strerror (errno));
+		gdm_shutdown_protocol_connection (data);
+                return FALSE;
+        }
+
+        response = gdm_send_protocol_msg (data, GDM_PROTOCOL_MSG_VERSION);
+        if (!response || strncmp (response, "GDM ", strlen ("GDM ") != 0)) {
+                g_free (response);
+
+                g_warning ("Failed to get protocol version from GDM");
+		gdm_shutdown_protocol_connection (data);
+
+                return FALSE;
+        }
+	g_free (response);
+
+        if (!gdm_authenticate_connection (data)) {
+                g_warning ("Failed to authenticate with GDM");
+		gdm_shutdown_protocol_connection (data);
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+static void
+gdm_parse_query_response (GdmProtocolData *data,
+                          const char      *response)
+{
+        char **actions;
+        int    i;
+
+        data->available_actions = GDM_LOGOUT_ACTION_NONE;
+        data->current_actions   = GDM_LOGOUT_ACTION_NONE;
+
+        if (strncmp (response, "OK ", 3) != 0)
+                return;
+
+        response += 3;
+
+        actions = g_strsplit (response, ";", -1);
+        for (i = 0; actions[i]; i++) {
+                GdmLogoutAction  action = GDM_LOGOUT_ACTION_NONE;
+                gboolean         selected = FALSE;
+                char            *str = actions [i];
+                int              len;
+
+                len = strlen (str);
+                if (!len)
+                        continue;
+
+                if (str[len - 1] == '!') {
+                        selected = TRUE;
+                        str[len - 1] = '\0';
+                }
+
+                if (!strcmp (str, GDM_ACTION_STR_SHUTDOWN))
+                        action = GDM_LOGOUT_ACTION_SHUTDOWN;
+                else if (!strcmp (str, GDM_ACTION_STR_REBOOT))
+                        action = GDM_LOGOUT_ACTION_REBOOT;
+                else if (!strcmp (str, GDM_ACTION_STR_SUSPEND))
+                        action = GDM_LOGOUT_ACTION_SUSPEND;
+
+                data->available_actions |= action;
+                if (selected)
+                        data->current_actions |= action;
+        }
+
+        g_strfreev (actions);
+}
+
+static void
+gdm_update_logout_actions (GdmProtocolData *data)
+{
+        time_t  current_time;
+        char   *response;
+
+        current_time = time (NULL);
+        if (current_time <= (data->last_update + GDM_PROTOCOL_UPDATE_INTERVAL))
+                return;
+
+        data->last_update = current_time;
+
+        if (!gdm_init_protocol_connection (data))
+                return;
+
+        if ((response = gdm_send_protocol_msg (data, GDM_PROTOCOL_MSG_QUERY_ACTION))) {
+                gdm_parse_query_response (data, response);
+                g_free (response);
+        }
+
+        gdm_shutdown_protocol_connection (data);
+}
+
+gboolean
+gdm_supports_logout_action (GdmLogoutAction action)
+{
+        gdm_update_logout_actions (&gdm_protocol_data);
+
+        return (gdm_protocol_data.available_actions & action) != 0;
+}
+
+GdmLogoutAction
+gdm_get_logout_action (void)
+{
+        gdm_update_logout_actions (&gdm_protocol_data);
+
+        return gdm_protocol_data.current_actions;
+}
+
+void
+gdm_set_logout_action (GdmLogoutAction action)
+{
+	char *action_str = NULL;
+        char *msg;
+        char *response;
+
+        if (!gdm_init_protocol_connection (&gdm_protocol_data))
+                return;
+
+        switch (action) {
+        case GDM_LOGOUT_ACTION_NONE:
+                action_str = GDM_ACTION_STR_NONE;
+                break;
+        case GDM_LOGOUT_ACTION_SHUTDOWN:
+                action_str = GDM_ACTION_STR_SHUTDOWN;
+                break;
+        case GDM_LOGOUT_ACTION_REBOOT:
+                action_str = GDM_ACTION_STR_REBOOT;
+                break;
+        case GDM_LOGOUT_ACTION_SUSPEND:
+                action_str = GDM_ACTION_STR_SUSPEND;
+                break;
+        }
+
+        msg = g_strdup_printf (GDM_PROTOCOL_MSG_SET_ACTION " %s", action_str);
+
+        response = gdm_send_protocol_msg (&gdm_protocol_data, msg);
+
+        g_free (msg);
+        g_free (response);
+
+	gdm_protocol_data.last_update = 0;
+
+        gdm_shutdown_protocol_connection (&gdm_protocol_data);
+}
+
+void
+gdm_new_login (void)
+{
+        char *response;
+
+        if (!gdm_init_protocol_connection (&gdm_protocol_data))
+                return;
+
+        response = gdm_send_protocol_msg (&gdm_protocol_data,
+					  GDM_PROTOCOL_MSG_FLEXI_XSERVER);
+
+        g_free (response);
+
+	gdm_protocol_data.last_update = 0;
+
+        gdm_shutdown_protocol_connection (&gdm_protocol_data);
+}
Index: b/gnome-panel/panel-logout.c
===================================================================
--- /dev/null
+++ b/gnome-panel/panel-logout.c
@@ -0,0 +1,402 @@
+/*
+ * panel-logout.c:
+ *
+ * Copyright (C) 2006 Vincent Untz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ *	Vincent Untz <vuntz@gnome.org>
+ */
+
+
+#include <config.h>
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkstock.h>
+
+#include <libpanel-util/panel-power-manager.h>
+
+#include "panel-logout.h"
+#include "panel-gdm.h"
+#include "panel-session.h"
+#include "panel-icon-names.h"
+
+#define PANEL_LOGOUT_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_LOGOUT_DIALOG, PanelLogoutDialogPrivate))
+
+#define AUTOMATIC_ACTION_TIMEOUT 60
+
+enum {
+	PANEL_LOGOUT_RESPONSE_LOGOUT,
+	PANEL_LOGOUT_RESPONSE_SWITCH_USER,
+	PANEL_LOGOUT_RESPONSE_SHUTDOWN,
+	PANEL_LOGOUT_RESPONSE_REBOOT,
+	PANEL_LOGOUT_RESPONSE_STD,
+	PANEL_LOGOUT_RESPONSE_STR
+};
+
+struct _PanelLogoutDialogPrivate {
+	PanelLogoutDialogType type;
+
+	PanelPowerManager    *power_manager;
+
+	int                   timeout;
+	unsigned int          timeout_id;
+
+	unsigned int          default_response;
+};
+
+static PanelLogoutDialog *current_dialog = NULL;
+
+static void panel_logout_destroy (PanelLogoutDialog *logout_dialog,
+				  gpointer           data);
+static void panel_logout_response (PanelLogoutDialog *logout_dialog,
+				   guint              response_id,
+				   gpointer           data);
+
+enum {
+  PROP_0,
+  PROP_MESSAGE_TYPE
+};
+G_DEFINE_TYPE (PanelLogoutDialog, panel_logout, GTK_TYPE_MESSAGE_DIALOG);
+
+static void
+panel_logout_set_property (GObject      *object,
+			   guint         prop_id,
+			   const GValue *value,
+			   GParamSpec   *pspec)
+{
+	switch (prop_id) {
+	case PROP_MESSAGE_TYPE:
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+panel_logout_get_property (GObject     *object,
+			   guint        prop_id,
+			   GValue      *value,
+			   GParamSpec  *pspec)
+{
+	switch (prop_id) {
+	case PROP_MESSAGE_TYPE:
+		g_value_set_enum (value, GTK_MESSAGE_WARNING);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+panel_logout_class_init (PanelLogoutDialogClass *klass)
+{
+	GObjectClass *gobject_class;
+
+	gobject_class = G_OBJECT_CLASS (klass);
+
+	/* This is a workaround to avoid a stupid crash: libgnomeui
+	 * listens for the "show" signal on all GtkMessageDialog and
+	 * gets the "message-type" of the dialogs. We will crash when
+	 * it accesses this property if we don't override it since we
+	 * didn't define it. */
+	gobject_class->set_property = panel_logout_set_property;
+	gobject_class->get_property = panel_logout_get_property;
+
+	g_object_class_override_property (gobject_class,
+					  PROP_MESSAGE_TYPE,
+					  "message-type");
+
+	g_type_class_add_private (klass, sizeof (PanelLogoutDialogPrivate));
+}
+
+static void
+panel_logout_init (PanelLogoutDialog *logout_dialog)
+{
+	logout_dialog->priv = PANEL_LOGOUT_DIALOG_GET_PRIVATE (logout_dialog);
+
+	logout_dialog->priv->timeout_id = 0;
+	logout_dialog->priv->timeout    = 0;
+	logout_dialog->priv->default_response = GTK_RESPONSE_CANCEL;
+
+	/* FIXME: we should most probably use gtk_window_set_transient_for(PANEL) */
+	gtk_window_set_skip_taskbar_hint (GTK_WINDOW (logout_dialog), TRUE);
+	gtk_window_set_keep_above (GTK_WINDOW (logout_dialog), TRUE);
+	gtk_window_stick (GTK_WINDOW (logout_dialog));
+	gtk_window_set_position (GTK_WINDOW (logout_dialog),
+				 GTK_WIN_POS_CENTER_ALWAYS);
+
+	logout_dialog->priv->power_manager = panel_power_manager_get ();
+
+	g_signal_connect (logout_dialog, "destroy",
+			  G_CALLBACK (panel_logout_destroy), NULL);
+	g_signal_connect (logout_dialog, "response",
+			  G_CALLBACK (panel_logout_response), NULL);
+}
+
+static void
+panel_logout_destroy (PanelLogoutDialog *logout_dialog,
+		      gpointer           data)
+{
+	if (logout_dialog->priv->timeout_id != 0)
+		g_source_remove (logout_dialog->priv->timeout_id);
+	logout_dialog->priv->timeout_id = 0;
+
+	g_object_unref (logout_dialog->priv->power_manager);
+	logout_dialog->priv->power_manager = NULL;
+
+	current_dialog = NULL;
+}
+
+static void
+panel_logout_response (PanelLogoutDialog *logout_dialog,
+		       guint      response_id,
+		       gpointer   data)
+{
+	PanelPowerManager *power_manager;
+
+	power_manager = g_object_ref (logout_dialog->priv->power_manager);
+	gtk_widget_destroy (GTK_WIDGET (logout_dialog));
+
+	switch (response_id) {
+	case GTK_RESPONSE_CANCEL:
+		break;
+	case PANEL_LOGOUT_RESPONSE_LOGOUT:
+		gdm_set_logout_action (GDM_LOGOUT_ACTION_NONE);
+		panel_session_request_logout ();
+		break;
+	case PANEL_LOGOUT_RESPONSE_SWITCH_USER:
+		gdm_new_login ();
+		break;
+	case PANEL_LOGOUT_RESPONSE_SHUTDOWN:
+		gdm_set_logout_action (GDM_LOGOUT_ACTION_SHUTDOWN);
+		panel_session_request_logout ();
+		break;
+	case PANEL_LOGOUT_RESPONSE_REBOOT:
+		gdm_set_logout_action (GDM_LOGOUT_ACTION_REBOOT);
+		panel_session_request_logout ();
+		break;
+	case PANEL_LOGOUT_RESPONSE_STD:
+		if (panel_power_manager_can_hibernate (power_manager))
+			panel_power_manager_attempt_hibernate (power_manager);
+		break;
+	case PANEL_LOGOUT_RESPONSE_STR:
+		if (panel_power_manager_can_suspend (power_manager))
+			panel_power_manager_attempt_suspend (power_manager);
+		break;
+	case GTK_RESPONSE_NONE:
+	case GTK_RESPONSE_DELETE_EVENT:
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+	g_object_unref (power_manager);
+}
+
+static gboolean
+panel_logout_timeout (gpointer data)
+{
+	PanelLogoutDialog *logout_dialog;
+	char              *secondary_text;
+	char              *name;
+	int                seconds_to_show;
+
+	logout_dialog = (PanelLogoutDialog *) data;
+
+	if (!logout_dialog->priv->timeout) {
+		gtk_dialog_response (GTK_DIALOG (logout_dialog),
+				     logout_dialog->priv->default_response);
+
+		return FALSE;
+	}
+
+	if (logout_dialog->priv->timeout <= 30)
+		seconds_to_show = logout_dialog->priv->timeout;
+	else {
+		seconds_to_show = (logout_dialog->priv->timeout/10) * 10;
+		if (logout_dialog->priv->timeout % 10)
+			seconds_to_show += 10;
+	}
+
+	switch (logout_dialog->priv->type) {
+	case PANEL_LOGOUT_DIALOG_LOGOUT:
+		secondary_text = ngettext ("You are currently logged in as "
+					   "\"%s\".\n"
+					   "You will be automatically logged "
+					   "out in %d second.",
+					   "You are currently logged in as "
+					   "\"%s\".\n"
+					   "You will be automatically logged "
+					   "out in %d seconds.",
+					   seconds_to_show);
+		break;
+	case PANEL_LOGOUT_DIALOG_SHUTDOWN:
+		secondary_text = ngettext ("You are currently logged in as "
+					   "\"%s\".\n"
+					   "This system will be automatically "
+					   "shut down in %d second.",
+					   "You are currently logged in as "
+					   "\"%s\".\n"
+					   "This system will be automatically "
+					   "shut down in %d seconds.",
+					   seconds_to_show);
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	name = g_locale_to_utf8 (g_get_real_name (), -1, NULL, NULL, NULL);
+	if (!name || name[0] == '\0' || strcmp (name, "Unknown") == 0)
+		name = g_locale_to_utf8 (g_get_user_name (), -1 , NULL, NULL, NULL);
+
+	if (!name)
+		name = g_strdup (g_get_user_name ());
+
+	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (logout_dialog),
+						  secondary_text,
+						  name,
+						  seconds_to_show,
+						  NULL);
+
+	logout_dialog->priv->timeout--;
+
+	g_free (name);
+
+	return TRUE;
+}
+
+static void
+panel_logout_set_timeout (PanelLogoutDialog *logout_dialog)
+{
+	logout_dialog->priv->timeout = AUTOMATIC_ACTION_TIMEOUT;
+
+	/* Sets the secondary text */
+	panel_logout_timeout (logout_dialog);
+
+	if (logout_dialog->priv->timeout_id != 0)
+		g_source_remove (logout_dialog->priv->timeout_id);
+
+	logout_dialog->priv->timeout_id = g_timeout_add (1000,
+							 panel_logout_timeout,
+							 logout_dialog);
+}
+
+void
+panel_logout_new (PanelLogoutDialogType  type,
+		  GdkScreen             *screen,
+		  guint32                activate_time)
+{
+	PanelLogoutDialog *logout_dialog;
+	char              *icon_name;
+	char              *primary_text;
+
+	if (current_dialog != NULL) {
+		if (current_dialog->priv->type == type) {
+			gtk_window_set_screen (GTK_WINDOW (current_dialog),
+					       screen);
+			gtk_window_present_with_time (GTK_WINDOW (current_dialog),
+						      activate_time);
+			panel_logout_set_timeout (current_dialog);
+			//FIXME center the dialog on screen, and reset sticky and above_all?
+			return;
+		} else {
+			gtk_widget_destroy (GTK_WIDGET (current_dialog));
+		}
+	}
+
+	logout_dialog = g_object_new (PANEL_TYPE_LOGOUT_DIALOG, NULL);
+	current_dialog = logout_dialog;
+
+	gtk_window_set_title (GTK_WINDOW (logout_dialog), "");
+
+	logout_dialog->priv->type = type;
+
+	icon_name    = NULL;
+	primary_text = NULL;
+
+	switch (type) {
+	case PANEL_LOGOUT_DIALOG_LOGOUT:
+		icon_name      = PANEL_ICON_LOGOUT;
+		primary_text   = _("Log out of this system now?");
+		// FIXME need to verify that this response can be used
+		logout_dialog->priv->default_response = PANEL_LOGOUT_DIALOG_LOGOUT;
+
+		//FIXME is gdm running?
+		gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+				       _("_Switch User"),
+				       PANEL_LOGOUT_RESPONSE_SWITCH_USER);
+		gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+				       GTK_STOCK_CANCEL,
+				       GTK_RESPONSE_CANCEL);
+		gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+				       _("_Log Out"),
+				       PANEL_LOGOUT_RESPONSE_LOGOUT);
+		break;
+	case PANEL_LOGOUT_DIALOG_SHUTDOWN:
+		icon_name      = PANEL_ICON_SHUTDOWN;
+		primary_text   = _("Shut down this system now?");
+
+		logout_dialog->priv->default_response = PANEL_LOGOUT_RESPONSE_SHUTDOWN;
+		if (panel_power_manager_can_suspend (logout_dialog->priv->power_manager))
+			gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+					       _("S_uspend"),
+					       PANEL_LOGOUT_RESPONSE_STR);
+
+		if (panel_power_manager_can_hibernate (logout_dialog->priv->power_manager))
+			gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+					       _("_Hibernate"),
+					       PANEL_LOGOUT_RESPONSE_STD);
+
+		if (gdm_supports_logout_action (GDM_LOGOUT_ACTION_REBOOT))
+			gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+					       _("_Restart"),
+					       PANEL_LOGOUT_RESPONSE_REBOOT);
+
+		gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+				       GTK_STOCK_CANCEL,
+				       GTK_RESPONSE_CANCEL);
+
+		if (gdm_supports_logout_action (GDM_LOGOUT_ACTION_SHUTDOWN))
+			gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+					       _("_Shut Down"),
+					       PANEL_LOGOUT_RESPONSE_SHUTDOWN);
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	gtk_image_set_from_icon_name (GTK_IMAGE (GTK_MESSAGE_DIALOG (logout_dialog)->image),
+				      icon_name, GTK_ICON_SIZE_DIALOG);
+
+	gtk_label_set_text (GTK_LABEL (GTK_MESSAGE_DIALOG (logout_dialog)->label),
+			    primary_text);
+
+	gtk_dialog_set_default_response (GTK_DIALOG (logout_dialog),
+					 logout_dialog->priv->default_response);
+
+	panel_logout_set_timeout (logout_dialog);
+
+	gtk_window_set_screen (GTK_WINDOW (logout_dialog), screen);
+	gtk_widget_show (GTK_WIDGET (logout_dialog));
+	gdk_window_focus (GTK_WIDGET (current_dialog)->window, activate_time);
+}
Index: b/gnome-panel/panel-gdm.h
===================================================================
--- /dev/null
+++ b/gnome-panel/panel-gdm.h
@@ -0,0 +1,52 @@
+/*
+ * gdm-logout-action.h: GDM logout action protocol implementation
+ *
+ * Copyright (C) 2005 Raffaele Sandrini
+ * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2002, 2003 George Lebl
+ * Copyright (C) 2001 Queen of England,
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ *      Raffaele Sandrini <rasa@gmx.ch>
+ *      George Lebl <jirka@5z.com>
+ *      Mark McLoughlin <mark@skynet.ie>
+ */
+
+#ifndef __GDM_LOGOUT_ACTION_H__
+#define __GDM_LOGOUT_ACTION_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+        GDM_LOGOUT_ACTION_NONE     = 0,
+        GDM_LOGOUT_ACTION_SHUTDOWN = 1 << 0,
+        GDM_LOGOUT_ACTION_REBOOT   = 1 << 1,
+        GDM_LOGOUT_ACTION_SUSPEND  = 1 << 2
+} GdmLogoutAction;
+
+gboolean gdm_supports_logout_action (GdmLogoutAction action);
+
+void            gdm_set_logout_action (GdmLogoutAction action);
+GdmLogoutAction gdm_get_logout_action (void);
+void            gdm_new_login         (void);
+
+G_END_DECLS
+
+#endif /* __GDM_LOGOUT_ACTION_H__ */
Index: b/gnome-panel/panel-logout.h
===================================================================
--- /dev/null
+++ b/gnome-panel/panel-logout.h
@@ -0,0 +1,66 @@
+/*
+ * panel-logout.h:
+ *
+ * Copyright (C) 2006 Vincent Untz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ *	Vincent Untz <vuntz@gnome.org>
+ */
+
+#ifndef PANEL_LOGOUT_H
+#define PANEL_LOGOUT_H
+
+#include "gtk/gtkmessagedialog.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+	PANEL_LOGOUT_DIALOG_LOGOUT,
+	PANEL_LOGOUT_DIALOG_SHUTDOWN
+} PanelLogoutDialogType;
+
+#define PANEL_TYPE_LOGOUT_DIALOG         (panel_logout_get_type ())
+#define PANEL_LOGOUT_DIALOG(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_LOGOUT_DIALOG, PanelLogoutDialog))
+#define PANEL_LOGOUT_DIALOG_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_LOGOUT_DIALOG, PanelLogoutDialogClass))
+#define PANEL_IS_LOGOUT_DIALOG(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_LOGOUT_DIALOG))
+#define PANEL_IS_LOGOUT_DIALOG_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_LOGOUT_DIALOG))
+#define PANEL_LOGOUT_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_LOGOUT_DIALOG, PanelLogoutDialogClass))
+
+typedef struct _PanelLogoutDialog        PanelLogoutDialog;
+typedef struct _PanelLogoutDialogClass   PanelLogoutDialogClass;
+typedef struct _PanelLogoutDialogPrivate PanelLogoutDialogPrivate;
+
+struct _PanelLogoutDialog {
+	GtkMessageDialog          parent;
+
+	PanelLogoutDialogPrivate *priv;
+};
+
+struct _PanelLogoutDialogClass {
+	GtkMessageDialogClass   parent_class;
+};
+
+GType  panel_logout_get_type          (void) G_GNUC_CONST;
+
+void panel_logout_new (PanelLogoutDialogType  type,
+		       GdkScreen             *screen,
+		       guint32                activate_time);
+
+G_END_DECLS
+
+#endif /* PANEL_LOGOUT_H */
Index: b/gnome-panel/panel-session.c
===================================================================
--- a/gnome-panel/panel-session.c
+++ b/gnome-panel/panel-session.c
@@ -32,6 +32,34 @@
 #include "panel-profile.h"
 #include "panel-shell.h"
 
+void
+panel_session_request_logout (void)
+{
+	GnomeClient *client;
+	static int   recursion_guard = 0;
+
+	if (recursion_guard)
+		return;
+
+	recursion_guard++;
+
+	if (!(client = gnome_master_client ()))
+		return;
+
+	/* Only request a Global save. We only want a Local
+	 * save if the user selects 'Save current setup'
+	 * from the dialog.
+	 */
+	gnome_client_request_save (client,
+				   GNOME_SAVE_GLOBAL,
+				   TRUE,
+				   GNOME_INTERACT_ANY,
+				   TRUE, /* do not use the gnome-session gui */
+				   TRUE);
+
+	recursion_guard--;
+}
+
 static void
 panel_session_handle_die_request (GnomeClient *client)
 {
Index: b/gnome-panel/panel-session.h
===================================================================
--- a/gnome-panel/panel-session.h
+++ b/gnome-panel/panel-session.h
@@ -29,6 +29,7 @@ G_BEGIN_DECLS
 
 void panel_session_init           (void);
 void panel_session_do_not_restart (void);
+void panel_session_request_logout (void);
 
 G_END_DECLS
 
Index: b/gnome-panel/Makefile.am
===================================================================
--- a/gnome-panel/Makefile.am
+++ b/gnome-panel/Makefile.am
@@ -97,6 +97,8 @@ panel_sources =			\
 	panel-force-quit.c	\
 	panel-lockdown.c	\
 	panel-addto.c		\
+	panel-logout.c		\
+	panel-gdm.c		\
 	panel-ditem-editor.c	\
 	$(NULL)
 
@@ -143,6 +145,8 @@ panel_headers =			\
 	panel-force-quit.h	\
 	panel-lockdown.h	\
 	panel-addto.h		\
+	panel-logout.h		\
+	panel-gdm.h		\
 	panel-ditem-editor.h	\
 	panel-icon-names.h	\
 	$(NULL)
Index: b/gnome-panel/libpanel-util/panel-session-manager.c
===================================================================
--- a/gnome-panel/libpanel-util/panel-session-manager.c
+++ b/gnome-panel/libpanel-util/panel-session-manager.c
@@ -23,10 +23,13 @@
  */
 
 #include <dbus/dbus-glib.h>
+#include <gtk/gtk.h>
 
 #include "panel-cleanup.h"
 #include "panel-dbus-service.h"
 
+#include "panel-logout.h"
+#include "panel-session.h"
 #include "panel-session-manager.h"
 
 static GObject *panel_session_manager_constructor (GType                  type,
@@ -96,6 +99,20 @@ panel_session_manager_request_logout (Pa
 		g_warning ("Could not connect to session manager: %s",
 			   error->message);
 		g_error_free (error);
+
+		/* Fall back to the old way */
+		switch (mode) {
+		case PANEL_SESSION_MANAGER_LOGOUT_MODE_NORMAL:
+			panel_logout_new (PANEL_LOGOUT_DIALOG_LOGOUT,
+					  gdk_screen_get_default (),
+					  gtk_get_current_event_time ());
+			break;
+		case PANEL_SESSION_MANAGER_LOGOUT_MODE_NO_CONFIRMATION:
+			panel_session_request_logout ();
+			break;
+		default:
+			g_warning ("Invalid mode requested for logout");
+		}
 		return;
 	}
 
@@ -126,6 +143,12 @@ panel_session_manager_request_shutdown (
 		g_warning ("Could not connect to session manager: %s",
 			   error->message);
 		g_error_free (error);
+
+		/* Fall back to the old way */
+		panel_logout_new (PANEL_LOGOUT_DIALOG_SHUTDOWN,
+				  gdk_screen_get_default (),
+				  gtk_get_current_event_time ());
+
 		return;
 	}
 
