diff options
author | Nick Schermer <nick@xfce.org> | 2011-11-06 21:59:43 +0100 |
---|---|---|
committer | Nick Schermer <nick@xfce.org> | 2012-03-24 22:24:35 +0100 |
commit | 4002e8d4ef3905e878e44633c076f8e7d42fd91b (patch) | |
tree | 55f0bb8949e63a00f15db6c8bf15053ed4c19a70 | |
parent | e90852df0f772184546320871c69d3358699d182 (diff) | |
download | xfce4-session-4002e8d4ef3905e878e44633c076f8e7d42fd91b.tar.gz |
Remove suspend/hibernate, split consolekit and rebuild dialog.
Way too many changes in 1 commit, but it's all related.
-rw-r--r-- | configure.in.in | 14 | ||||
-rw-r--r-- | libxfsm/xfsm-util.c | 19 | ||||
-rw-r--r-- | libxfsm/xfsm-util.h | 2 | ||||
-rwxr-xr-x | scripts/xinitrc.in.in | 2 | ||||
-rw-r--r-- | xfce4-session/Makefile.am | 7 | ||||
-rw-r--r-- | xfce4-session/main.c | 28 | ||||
-rw-r--r-- | xfce4-session/xfsm-consolekit.c | 337 | ||||
-rw-r--r-- | xfce4-session/xfsm-consolekit.h | 54 | ||||
-rw-r--r-- | xfce4-session/xfsm-error.h | 2 | ||||
-rw-r--r-- | xfce4-session/xfsm-fadeout.c | 9 | ||||
-rw-r--r-- | xfce4-session/xfsm-fadeout.h | 1 | ||||
-rw-r--r-- | xfce4-session/xfsm-global.c | 19 | ||||
-rw-r--r-- | xfce4-session/xfsm-global.h | 10 | ||||
-rw-r--r-- | xfce4-session/xfsm-logout-dialog.c | 1321 | ||||
-rw-r--r-- | xfce4-session/xfsm-logout-dialog.h | 20 | ||||
-rw-r--r-- | xfce4-session/xfsm-manager.c | 20 | ||||
-rw-r--r-- | xfce4-session/xfsm-manager.h | 1 | ||||
-rw-r--r-- | xfce4-session/xfsm-shutdown-helper.c | 1862 | ||||
-rw-r--r-- | xfce4-session/xfsm-shutdown-helper.h | 64 | ||||
-rw-r--r-- | xfce4-session/xfsm-shutdown.c | 716 | ||||
-rw-r--r-- | xfce4-session/xfsm-shutdown.h | 73 |
21 files changed, 1927 insertions, 2654 deletions
diff --git a/configure.in.in b/configure.in.in index 980bc35c..c80e5e53 100644 --- a/configure.in.in +++ b/configure.in.in @@ -62,7 +62,7 @@ AC_HEADER_STDC AC_CHECK_HEADERS([asm/unistd.h errno.h fcntl.h limits.h \ netdb.h pwd.h signal.h stdarg.h sys/param.h sys/resource.h \ sys/socket.h sys/time.h sys/wait.h sys/utsname.h time.h \ - unistd.h sys/param.h sys/user.h sys/sysctl.h]) + unistd.h sys/param.h sys/user.h sys/sysctl.h math.h]) AC_CHECK_FUNCS([getaddrinfo gethostbyname gethostname getpwuid setsid \ sigaction strdup sync vfork]) @@ -142,18 +142,6 @@ else AC_MSG_RESULT([yes]) fi -dnl Check whether to create session screenshots -AC_ARG_ENABLE([session-screenshots], -AC_HELP_STRING([--enable-session-screenshots], [Create screenshots of sessions on logout]), - [], [enable_session_screenshots=no]) -AC_MSG_CHECKING([whether to create screenshots of sessions on logout]) -if test x"$enable_session_screenshots" != x"yes"; then - AC_MSG_RESULT([no]) -else - AC_DEFINE([SESSION_SCREENSHOTS], [1], [Define for session screenshots]) - AC_MSG_RESULT([yes]) -fi - dnl dnl D-Bus RUNTIME Dependencies dnl diff --git a/libxfsm/xfsm-util.c b/libxfsm/xfsm-util.c index e766c25c..ddd9d2a6 100644 --- a/libxfsm/xfsm-util.c +++ b/libxfsm/xfsm-util.c @@ -175,23 +175,14 @@ xfsm_window_add_border (GtkWindow *window) gtk_container_add (GTK_CONTAINER (window), box1); } - -void -xfsm_window_grab_input (GtkWindow *window) -{ - GdkWindow *xwindow = GTK_WIDGET (window)->window; - - gdk_pointer_grab (xwindow, TRUE, 0, NULL, NULL, GDK_CURRENT_TIME); - gdk_keyboard_grab (xwindow, FALSE, GDK_CURRENT_TIME); - XSetInputFocus (GDK_DISPLAY (), GDK_WINDOW_XWINDOW (xwindow), - RevertToParent, CurrentTime); -} - - XfconfChannel* xfsm_open_config (void) { - return xfconf_channel_get ("xfce4-session"); + static XfconfChannel *channel = NULL; + + if (G_UNLIKELY (channel == NULL)) + channel = xfconf_channel_get ("xfce4-session"); + return channel; } gchar* diff --git a/libxfsm/xfsm-util.h b/libxfsm/xfsm-util.h index b215b54b..8ca9fc25 100644 --- a/libxfsm/xfsm-util.h +++ b/libxfsm/xfsm-util.h @@ -47,8 +47,6 @@ gboolean xfsm_strv_equal (gchar **a, gchar **b); void xfsm_window_add_border (GtkWindow *window); -void xfsm_window_grab_input (GtkWindow *window); - XfconfChannel *xfsm_open_config (void); gchar *xfsm_gdk_display_get_fullname (GdkDisplay *display); diff --git a/scripts/xinitrc.in.in b/scripts/xinitrc.in.in index e63eac1b..1395fb5e 100755 --- a/scripts/xinitrc.in.in +++ b/scripts/xinitrc.in.in @@ -212,7 +212,7 @@ fi # Run xfce4-session if installed if which xfce4-session >/dev/null 2>&1; then - xfce4-session + ck-launch-session xfce4-session if test "$ssh_agent_kill_cmd"; then echo "running '$ssh_agent_kill_cmd'" diff --git a/xfce4-session/Makefile.am b/xfce4-session/Makefile.am index 9c845b92..089d3c56 100644 --- a/xfce4-session/Makefile.am +++ b/xfce4-session/Makefile.am @@ -37,6 +37,8 @@ xfce4_session_SOURCES = \ xfsm-compat-gnome.h \ xfsm-compat-kde.c \ xfsm-compat-kde.h \ + xfsm-consolekit.c \ + xfsm-consolekit.h \ xfsm-dns.c \ xfsm-dns.h \ xfsm-error.c \ @@ -55,8 +57,6 @@ xfce4_session_SOURCES = \ xfsm-properties.h \ xfsm-shutdown.c \ xfsm-shutdown.h \ - xfsm-shutdown-helper.c \ - xfsm-shutdown-helper.h \ xfsm-splash-screen.c \ xfsm-splash-screen.h \ xfsm-startup.c \ @@ -95,7 +95,8 @@ xfce4_session_LDADD = \ $(DBUS_GLIB_LIBS) \ $(LIBWNCK_LIBS) \ $(XFCONF_LIBS) \ - $(GNOME_KEYRING_LIBS) + $(GNOME_KEYRING_LIBS) \ + -lm xfce4_session_DEPENDENCIES = \ $(top_builddir)/libxfsm/libxfsm-4.6.la diff --git a/xfce4-session/main.c b/xfce4-session/main.c index e88b8952..ddac4077 100644 --- a/xfce4-session/main.c +++ b/xfce4-session/main.c @@ -195,11 +195,13 @@ xfsm_dbus_cleanup (void) int main (int argc, char **argv) { - XfsmManager *manager; - XfsmShutdownType shutdown_type; - GError *error = NULL; - GdkDisplay *dpy; - XfconfChannel *channel; + XfsmManager *manager; + GError *error = NULL; + GdkDisplay *dpy; + XfconfChannel *channel; + XfsmShutdownType shutdown_type; + XfsmShutdown *shutdown; + gboolean succeed; xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8"); @@ -261,13 +263,25 @@ main (int argc, char **argv) xfsm_manager_restart (manager); gtk_main (); - + shutdown_type = xfsm_manager_get_shutdown_type (manager); + g_object_unref (manager); g_object_unref (channel); xfsm_dbus_cleanup (); ice_cleanup (); - return xfsm_shutdown (shutdown_type); + if (shutdown_type == XFSM_SHUTDOWN_SHUTDOWN + || shutdown_type == XFSM_SHUTDOWN_RESTART) + { + shutdown = xfsm_shutdown_get (); + succeed = xfsm_shutdown_try_type (shutdown, shutdown_type, &error); + if (!succeed) + g_warning ("Failed to shutdown/restart: %s", ERROR_MSG (error)); + g_object_unref (shutdown); + return succeed ? EXIT_SUCCESS : EXIT_FAILURE; + } + + return EXIT_SUCCESS; } diff --git a/xfce4-session/xfsm-consolekit.c b/xfce4-session/xfsm-consolekit.c new file mode 100644 index 00000000..d11c8105 --- /dev/null +++ b/xfce4-session/xfsm-consolekit.c @@ -0,0 +1,337 @@ +/*- + * Copyright (c) 2010 Ali Abdallah <aliov@xfce.org> + * Copyright (c) 2011 Nick Schermer <nick@xfce.org> + * All rights reserved. + * + * 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, 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. + */ + + +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include <xfce4-session/xfsm-consolekit.h> + + + +#define CK_NAME "org.freedesktop.ConsoleKit" +#define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager" +#define CK_MANAGER_NAME CK_NAME ".Manager" + + + +static void xfsm_consolekit_finalize (GObject *object); +static gboolean xfsm_consolekit_proxy_ensure (XfsmConsolekit *consolekit, + GError **error); +static void xfsm_consolekit_proxy_free (XfsmConsolekit *consolekit); + + + +struct _XfsmConsolekitClass +{ + GObjectClass __parent__; +}; + +struct _XfsmConsolekit +{ + GObject __parent__; + + DBusGConnection *dbus_conn; + DBusGProxy *ck_proxy; + DBusGProxy *dbus_proxy; +}; + + + +G_DEFINE_TYPE (XfsmConsolekit, xfsm_consolekit, G_TYPE_OBJECT) + + + +static void +xfsm_consolekit_class_init (XfsmConsolekitClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = xfsm_consolekit_finalize; +} + + + +static void +xfsm_consolekit_init (XfsmConsolekit *consolekit) +{ +} + + + +static void +xfsm_consolekit_finalize (GObject *object) +{ + xfsm_consolekit_proxy_free (XFSM_CONSOLEKIT (object)); + + (*G_OBJECT_CLASS (xfsm_consolekit_parent_class)->finalize) (object); +} + + + +static DBusHandlerResult +xfsm_consolekit_dbus_filter (DBusConnection *connection, + DBusMessage *message, + gpointer data) +{ + g_return_val_if_fail (XFSM_IS_CONSOLEKIT (data), DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + + if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") + && g_strcmp0 (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) + { + xfsm_consolekit_proxy_free (XFSM_CONSOLEKIT (data)); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + + +static void +xfsm_consolekit_name_owner_changed (DBusGProxy *dbus_proxy, + const gchar *name, + const gchar *prev_owner, + const gchar *new_owner, + XfsmConsolekit *consolekit) +{ + GError *err = NULL; + + g_return_if_fail (XFSM_IS_CONSOLEKIT (consolekit)); + g_return_if_fail (consolekit->dbus_proxy == dbus_proxy); + + if (g_strcmp0 (name, CK_NAME) == 0) + { + /* only reconnect the consolekit proxy */ + if (consolekit->ck_proxy != NULL) + { + g_object_unref (G_OBJECT (consolekit->ck_proxy)); + consolekit->ck_proxy = NULL; + } + + if (!xfsm_consolekit_proxy_ensure (consolekit, &err)) + { + g_warning ("Failed to reconnect to consolekit: %s", err->message); + g_error_free (err); + } + } +} + + + +static gboolean +xfsm_consolekit_proxy_ensure (XfsmConsolekit *consolekit, + GError **error) +{ + GError *err = NULL; + DBusConnection *connection; + + if (consolekit->dbus_conn == NULL) + { + consolekit->dbus_conn = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err); + if (consolekit->dbus_conn == NULL) + goto error1; + + connection = dbus_g_connection_get_connection (consolekit->dbus_conn); + dbus_connection_set_exit_on_disconnect (connection, FALSE); + dbus_connection_add_filter (connection, xfsm_consolekit_dbus_filter, consolekit, NULL); + } + + if (consolekit->dbus_proxy == NULL) + { + consolekit->dbus_proxy = dbus_g_proxy_new_for_name_owner (consolekit->dbus_conn, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + &err); + if (consolekit->dbus_proxy == NULL) + goto error1; + + /* (dis)connect to consolekit if stopped/started */ + dbus_g_proxy_add_signal (consolekit->dbus_proxy, + "NameOwnerChanged", + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_INVALID); + + dbus_g_proxy_connect_signal (consolekit->dbus_proxy, + "NameOwnerChanged", + G_CALLBACK (xfsm_consolekit_name_owner_changed), + consolekit, NULL); + } + + if (consolekit->ck_proxy == NULL) + { + consolekit->ck_proxy = dbus_g_proxy_new_for_name_owner (consolekit->dbus_conn, + CK_NAME, + CK_MANAGER_PATH, + CK_MANAGER_NAME, + &err); + if (consolekit->ck_proxy == NULL) + goto error1; + } + + return TRUE; + + error1: + + g_propagate_error (error, err); + xfsm_consolekit_proxy_free (consolekit); + + return FALSE; +} + + + +static void +xfsm_consolekit_proxy_free (XfsmConsolekit *consolekit) +{ + DBusConnection *connection; + + if (consolekit->ck_proxy != NULL) + { + g_object_unref (G_OBJECT (consolekit->ck_proxy)); + consolekit->ck_proxy = NULL; + } + + if (consolekit->dbus_proxy != NULL) + { + g_object_unref (G_OBJECT (consolekit->dbus_proxy)); + consolekit->dbus_proxy = NULL; + } + + if (consolekit->dbus_conn != NULL) + { + connection = dbus_g_connection_get_connection (consolekit->dbus_conn); + dbus_connection_remove_filter (connection, + xfsm_consolekit_dbus_filter, + consolekit); + + dbus_g_connection_unref (consolekit->dbus_conn); + consolekit->dbus_conn = NULL; + } +} + + + +static gboolean +xfsm_consolekit_can_method (XfsmConsolekit *consolekit, + const gchar *method, + gboolean *can_method, + GError **error) +{ + g_return_val_if_fail (can_method != NULL, FALSE); + + /* never return true if something fails */ + *can_method = FALSE; + + if (!xfsm_consolekit_proxy_ensure (consolekit, error)) + return FALSE; + + return dbus_g_proxy_call (consolekit->ck_proxy, method, + error, G_TYPE_INVALID, + G_TYPE_BOOLEAN, can_method, + G_TYPE_INVALID); +} + + + +static gboolean +xfsm_consolekit_try_method (XfsmConsolekit *consolekit, + const gchar *method, + GError **error) +{ + if (!xfsm_consolekit_proxy_ensure (consolekit, error)) + return FALSE; + + return dbus_g_proxy_call (consolekit->ck_proxy, method, error, + G_TYPE_INVALID, G_TYPE_INVALID); +} + + + +XfsmConsolekit * +xfsm_consolekit_get (void) +{ + static XfsmConsolekit *object = NULL; + + if (G_LIKELY (object != NULL)) + { + g_object_ref (G_OBJECT (object)); + } + else + { + object = g_object_new (XFSM_TYPE_CONSOLEKIT, NULL); + g_object_add_weak_pointer (G_OBJECT (object), (gpointer) &object); + } + + return object; +} + + + +gboolean +xfsm_consolekit_try_restart (XfsmConsolekit *consolekit, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_CONSOLEKIT (consolekit), FALSE); + + return xfsm_consolekit_try_method (consolekit, "Restart", error); +} + + + +gboolean +xfsm_consolekit_try_shutdown (XfsmConsolekit *consolekit, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_CONSOLEKIT (consolekit), FALSE); + + return xfsm_consolekit_try_method (consolekit, "Stop", error); +} + + + +gboolean +xfsm_consolekit_can_restart (XfsmConsolekit *consolekit, + gboolean *can_restart, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_CONSOLEKIT (consolekit), FALSE); + + + return xfsm_consolekit_can_method (consolekit, "CanRestart", + can_restart, error); +} + + + +gboolean +xfsm_consolekit_can_shutdown (XfsmConsolekit *consolekit, + gboolean *can_shutdown, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_CONSOLEKIT (consolekit), FALSE); + + return xfsm_consolekit_can_method (consolekit, "CanStop", + can_shutdown, error); +} diff --git a/xfce4-session/xfsm-consolekit.h b/xfce4-session/xfsm-consolekit.h new file mode 100644 index 00000000..17dbe428 --- /dev/null +++ b/xfce4-session/xfsm-consolekit.h @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2003-2006 Benedikt Meurer <benny@xfce.org> + * Copyright (c) 2010 Ali Abdallah <aliov@xfce.org> + * Copyright (c) 2011 Nick Schermer <nick@xfce.org> + * All rights reserved. + * + * 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, 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. + */ + +#ifndef __XFSM_SHUTDOWN_HELPER_H__ +#define __XFSM_SHUTDOWN_HELPER_H__ + +typedef struct _XfsmConsolekitClass XfsmConsolekitClass; +typedef struct _XfsmConsolekit XfsmConsolekit; + +#define XFSM_TYPE_CONSOLEKIT (xfsm_consolekit_get_type ()) +#define XFSM_CONSOLEKIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFSM_TYPE_CONSOLEKIT, XfsmConsolekit)) +#define XFSM_CONSOLEKIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XFSM_TYPE_CONSOLEKIT, XfsmConsolekitClass)) +#define XFSM_IS_CONSOLEKIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFSM_TYPE_CONSOLEKIT)) +#define XFSM_IS_CONSOLEKIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFSM_TYPE_CONSOLEKIT)) +#define XFSM_CONSOLEKIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XFSM_TYPE_CONSOLEKIT, XfsmConsolekitClass)) + +GType xfsm_consolekit_get_type (void) G_GNUC_CONST; + +XfsmConsolekit *xfsm_consolekit_get (void); + +gboolean xfsm_consolekit_try_restart (XfsmConsolekit *consolekit, + GError **error); + +gboolean xfsm_consolekit_try_shutdown (XfsmConsolekit *consolekit, + GError **error); + +gboolean xfsm_consolekit_can_restart (XfsmConsolekit *consolekit, + gboolean *can_restart, + GError **error); + +gboolean xfsm_consolekit_can_shutdown (XfsmConsolekit *consolekit, + gboolean *can_shutdown, + GError **error); + +#endif /* !__XFSM_SHUTDOWN_HELPER_H__ */ diff --git a/xfce4-session/xfsm-error.h b/xfce4-session/xfsm-error.h index f2bedf94..22ff710c 100644 --- a/xfce4-session/xfsm-error.h +++ b/xfce4-session/xfsm-error.h @@ -23,6 +23,8 @@ #define XFSM_TYPE_ERROR (xfsm_error_get_type ()) #define XFSM_ERROR (xfsm_error_get_quark ()) +#define ERROR_MSG(err) ((err) != NULL ? (err)->message : "Error not set") + G_BEGIN_DECLS typedef enum diff --git a/xfce4-session/xfsm-fadeout.c b/xfce4-session/xfsm-fadeout.c index 9ee46915..91af5b68 100644 --- a/xfce4-session/xfsm-fadeout.c +++ b/xfce4-session/xfsm-fadeout.c @@ -120,6 +120,15 @@ xfsm_fadeout_new (GdkDisplay *display) void +xfsm_fadeout_clear (XfsmFadeout *fadeout) +{ + if (fadeout != NULL) + g_slist_foreach (fadeout->windows, (GFunc) gdk_window_clear, NULL); +} + + + +void xfsm_fadeout_destroy (XfsmFadeout *fadeout) { g_slist_foreach (fadeout->windows, (GFunc) gdk_window_hide, NULL); diff --git a/xfce4-session/xfsm-fadeout.h b/xfce4-session/xfsm-fadeout.h index 9b31af24..6cc80fe9 100644 --- a/xfce4-session/xfsm-fadeout.h +++ b/xfce4-session/xfsm-fadeout.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS; typedef struct _XfsmFadeout XfsmFadeout; XfsmFadeout *xfsm_fadeout_new (GdkDisplay *display); +void xfsm_fadeout_clear (XfsmFadeout *fadeout); void xfsm_fadeout_destroy (XfsmFadeout *fadeout); G_END_DECLS; diff --git a/xfce4-session/xfsm-global.c b/xfce4-session/xfsm-global.c index 1d5ed372..05f8d80a 100644 --- a/xfce4-session/xfsm-global.c +++ b/xfce4-session/xfsm-global.c @@ -142,30 +142,25 @@ xfsm_generate_client_id (SmsConn sms_conn) GdkPixbuf * xfsm_load_session_preview (const gchar *name) { -#ifdef SESSION_SCREENSHOTS GdkDisplay *display; - GdkPixbuf *pb; + GdkPixbuf *pb = NULL; gchar *display_name; - gchar *resource; gchar *filename; + gchar *path; /* determine thumb file */ display = gdk_display_get_default (); display_name = xfsm_gdk_display_get_fullname (display); - resource = g_strconcat ("sessions/thumbs-", display_name, - "/", name, ".png", NULL); - filename = xfce_resource_save_location (XFCE_RESOURCE_CACHE, resource, TRUE); + path = g_strconcat ("sessions/thumbs-", display_name, "/", name, ".png", NULL); + filename = xfce_resource_lookup (XFCE_RESOURCE_CACHE, path); g_free (display_name); - g_free (resource); - - pb = gdk_pixbuf_new_from_file (filename, NULL); + g_free (path); + if (filename != NULL) + pb = gdk_pixbuf_new_from_file (filename, NULL); g_free (filename); return pb; -#else - return NULL; -#endif } diff --git a/xfce4-session/xfsm-global.h b/xfce4-session/xfsm-global.h index 1fdfe8cc..273361fe 100644 --- a/xfce4-session/xfsm-global.h +++ b/xfce4-session/xfsm-global.h @@ -29,16 +29,6 @@ #include <xfce4-session/xfsm-splash-screen.h> #include <dbus/dbus.h> -typedef enum -{ - XFSM_SHUTDOWN_ASK = 0, - XFSM_SHUTDOWN_LOGOUT, - XFSM_SHUTDOWN_HALT, - XFSM_SHUTDOWN_REBOOT, - XFSM_SHUTDOWN_SUSPEND, - XFSM_SHUTDOWN_HIBERNATE, -} XfsmShutdownType; - typedef struct _FailsafeClient FailsafeClient; struct _FailsafeClient { diff --git a/xfce4-session/xfsm-logout-dialog.c b/xfce4-session/xfsm-logout-dialog.c index 8b2fc15a..32c92c27 100644 --- a/xfce4-session/xfsm-logout-dialog.c +++ b/xfce4-session/xfsm-logout-dialog.c @@ -1,29 +1,6 @@ /*- * Copyright (c) 2003-2004 Benedikt Meurer <benny@xfce.org> - * All rights reserved. - * - * 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, 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., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. - * - * Parts of this file where taken from gnome-session/logout.c, which - * was written by Owen Taylor <otaylor@redhat.com>. - */ - -/* $Id$ */ -/*- - * Copyright (c) 2003-2004 Benedikt Meurer <benny@xfce.org> + * Copyright (c) 2011 Nick Schermer <nick@xfce.org> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -62,18 +39,8 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif - -#ifdef HAVE_GETPWUID -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#endif - -#ifdef HAVE_ASM_UNISTD_H -#include <asm/unistd.h> /* for __NR_ioprio_set */ +#ifdef HAVE_MATH_H +#include <math.h> #endif #include <libxfce4util/libxfce4util.h> @@ -82,177 +49,122 @@ #include <libxfsm/xfsm-util.h> #include <xfce4-session/xfsm-logout-dialog.h> -#include <xfce4-session/xfsm-compat-gnome.h> -#include <xfce4-session/xfsm-compat-kde.h> #include <xfce4-session/xfsm-fadeout.h> #include <xfce4-session/xfsm-global.h> #include <xfce4-session/xfsm-legacy.h> -#include <xfce4-session/xfsm-shutdown-helper.h> +#include <xfce4-session/xfsm-error.h> -#define BORDER 6 +#ifdef GDK_WINDOWING_X11 +#include <X11/Xlib.h> +#include <gdk/gdkx.h> +#endif -static XfsmShutdownHelper *shutdown_helper = NULL; -static GtkWidget *shutdown_dialog = NULL; +#define BORDER 6 +#define SHOTSIZE 64 -#ifdef SESSION_SCREENSHOTS -static void -screenshot_save (const gchar *session_name, GdkPixmap *pm, GdkRectangle *area) -{ - gchar *display_name; - gchar *resource; - gchar *filename; - GdkDisplay *dpy; - GdkPixbuf *spb; - GdkPixbuf *pb; - pb = gdk_pixbuf_get_from_drawable (NULL, GDK_DRAWABLE (pm), NULL, - 0, 0, 0, 0, area->width, area->height); - if (pb != NULL) - { - /* scale down the pixbuf */ - spb = gdk_pixbuf_scale_simple (pb, 52, 43, GDK_INTERP_HYPER); +static void xfsm_logout_dialog_finalize (GObject *object); +static GtkWidget *xfsm_logout_dialog_button (const gchar *title, + const gchar *icon_name, + const gchar *icon_name_fallback, + XfsmShutdownType type, + XfsmLogoutDialog *dialog); +static void xfsm_logout_dialog_activate (XfsmLogoutDialog *dialog); - if (spb != NULL) - { - /* determine thumb file */ - dpy = gdk_drawable_get_display (GDK_DRAWABLE (pm)); - display_name = xfsm_gdk_display_get_fullname (dpy); - resource = g_strconcat ("sessions/thumbs-", display_name, - "/", session_name, ".png", NULL); - filename = xfce_resource_save_location (XFCE_RESOURCE_CACHE, - resource, TRUE); - g_free (display_name); - g_free (resource); - - gdk_pixbuf_save (spb, filename, "png", NULL, NULL); - - g_object_unref (G_OBJECT (spb)); - g_free (filename); - } - g_object_unref (G_OBJECT (pb)); - } -} -#endif +enum +{ + MODE_LOGOUT_BUTTONS, + MODE_ASK_PASSWORD, + MODE_SHOW_ERROR, + N_MODES +}; -static void -entry_activate_cb (GtkWidget *entry, GtkDialog *dialog) +struct _XfsmLogoutDialogClass { - gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); -} + GtkDialogClass __parent__; +}; -static void -logout_button_clicked (GtkWidget *b, gint *shutdown_type) +struct _XfsmLogoutDialog { - *shutdown_type = XFSM_SHUTDOWN_LOGOUT; + GtkDialog __parent__; - gtk_dialog_response (GTK_DIALOG (shutdown_dialog), GTK_RESPONSE_OK); -} + /* set when a button is clicked */ + XfsmShutdownType type_clicked; -static void -reboot_button_clicked (GtkWidget *b, gint *shutdown_type) -{ - *shutdown_type = XFSM_SHUTDOWN_REBOOT; + /* save session checkbox */ + GtkWidget *save_session; - gtk_dialog_response (GTK_DIALOG (shutdown_dialog), GTK_RESPONSE_OK); -} + /* mode widgets */ + GtkWidget *box[N_MODES]; -static void -halt_button_clicked (GtkWidget *b, gint *shutdown_type) -{ - *shutdown_type = XFSM_SHUTDOWN_HALT; + /* dialog buttons */ + GtkWidget *button_cancel; + GtkWidget *button_ok; + GtkWidget *button_close; - gtk_dialog_response (GTK_DIALOG (shutdown_dialog), GTK_RESPONSE_OK); -} + /* password entry */ + GtkWidget *password_entry; + + /* error label */ + GtkWidget *error_label; + + /* pm instance */ + XfsmShutdown *shutdown; +}; + + + +G_DEFINE_TYPE (XfsmLogoutDialog, xfsm_logout_dialog, GTK_TYPE_DIALOG) -static void -suspend_button_clicked (GtkWidget *b, gint *shutdown_type) -{ - *shutdown_type = XFSM_SHUTDOWN_SUSPEND; - gtk_dialog_response (GTK_DIALOG (shutdown_dialog), GTK_RESPONSE_OK); -} static void -hibernate_button_clicked (GtkWidget *b, gint *shutdown_type) +xfsm_logout_dialog_class_init (XfsmLogoutDialogClass *klass) { - *shutdown_type = XFSM_SHUTDOWN_HIBERNATE; + GObjectClass *gobject_class; - gtk_dialog_response (GTK_DIALOG (shutdown_dialog), GTK_RESPONSE_OK); + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = xfsm_logout_dialog_finalize; } -/* - */ -gboolean -xfsm_logout_dialog (const gchar *session_name, - XfsmShutdownType *shutdown_type, - gboolean *save_session) + + +static void +xfsm_logout_dialog_init (XfsmLogoutDialog *dialog) { - gboolean accessibility; - GtkIconTheme *icon_theme; - XfsmFadeout *fadeout = NULL; - GdkScreen *screen; - GtkWidget *dialog; - GtkWidget *label; - GtkWidget *dbox; - GtkWidget *hbox; - GtkWidget *vbox; - GtkWidget *vbox2; - GtkWidget *image; - GtkWidget *checkbox; - GtkWidget *entry_vbox; - GtkWidget *entry; - GtkWidget *hidden; - GtkWidget *logout_button; - GtkWidget *reboot_button; - GtkWidget *halt_button; - GtkWidget *suspend_button = NULL; - GtkWidget *hibernate_button = NULL; - GtkWidget *cancel_button; - GtkWidget *ok_button; - GdkPixbuf *icon; - gboolean saveonexit; - gboolean autosave; - gboolean prompt; - gboolean show_suspend; - gboolean show_hibernate; - - gboolean show_restart; - gboolean show_shutdown; - - gboolean require_password; - - gint monitor; - gint result; - XfceKiosk *kiosk; - gboolean kiosk_can_shutdown; - gboolean kiosk_can_save_session; + const gchar *username; + GtkWidget *label; + gchar *label_str; + PangoAttrList *attrs; + GtkWidget *vbox; + GtkWidget *main_vbox; + GtkWidget *hbox; + GtkWidget *button; + XfceKiosk *kiosk; + gboolean can_shutdown; + gboolean kiosk_can_shutdown; + gboolean kiosk_can_save_session; + gboolean save_session = FALSE; + gboolean can_restart; + gboolean can_suspend = FALSE; + gboolean can_hibernate = FALSE; + GError *error = NULL; XfconfChannel *channel; -#ifdef SESSION_SCREENSHOTS - GdkRectangle screenshot_area; - GdkWindow *root; - GdkPixmap *screenshot_pm = NULL; - GdkGC *screenshot_gc; -#endif -#ifdef HAVE_GETPWUID - struct passwd *pw; -#endif + GtkWidget *entry; + GtkWidget *image; + GtkWidget *separator; - g_return_val_if_fail(save_session != NULL, FALSE); - g_return_val_if_fail(shutdown_type != NULL, FALSE); + dialog->type_clicked = XFSM_SHUTDOWN_LOGOUT; - icon_theme = gtk_icon_theme_get_default (); - - /* destroy any previously running shutdown helper first */ - if (shutdown_helper != NULL) - { - g_object_unref (shutdown_helper); - shutdown_helper = NULL; - } + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); /* load kiosk settings */ kiosk = xfce_kiosk_new ("xfce4-session"); @@ -260,549 +172,744 @@ xfsm_logout_dialog (const gchar *session_name, kiosk_can_save_session = xfce_kiosk_query (kiosk, "SaveSession"); xfce_kiosk_free (kiosk); - /* load configuration */ + /* load xfconf settings */ channel = xfsm_open_config (); - channel = xfconf_channel_get ("xfce4-session"); - saveonexit = xfconf_channel_get_bool (channel, "/general/SaveOnExit", TRUE); - autosave = xfconf_channel_get_bool (channel, "/general/AutoSave", FALSE); - prompt = xfconf_channel_get_bool (channel, "/general/PromptOnLogout", TRUE); - show_suspend = xfconf_channel_get_bool (channel, "/shutdown/ShowSuspend", TRUE); - show_hibernate = xfconf_channel_get_bool (channel, "/shutdown/ShowHibernate", TRUE); - - /* make the session-save settings obey the kiosk settings */ - if (!kiosk_can_save_session) - { - saveonexit = FALSE; - autosave = FALSE; - } + if (kiosk_can_save_session) + save_session = xfconf_channel_get_bool (channel, "/general/SaveOnExit", TRUE); + + main_vbox = gtk_vbox_new (FALSE, BORDER); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_vbox, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (main_vbox), BORDER); + gtk_widget_show (main_vbox); + + /* label showing the users' name */ + username = g_get_real_name (); + if (username == NULL || *username == '\0') + username = g_get_user_name (); + + label_str = g_strdup_printf (_("Log out %s"), username); + label = gtk_label_new (label_str); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER); + gtk_box_pack_start (GTK_BOX (main_vbox), label, FALSE, TRUE, 0); + gtk_widget_show (label); + g_free (label_str); + + attrs = pango_attr_list_new (); + pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_LARGE)); + pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD)); + gtk_label_set_attributes (GTK_LABEL (label), attrs); + pango_attr_list_unref (attrs); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (main_vbox), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + /** + * Start mode MODE_LOGOUT_BUTTONS + **/ + dialog->box[MODE_LOGOUT_BUTTONS] = vbox = gtk_vbox_new (FALSE, BORDER); + gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0); - /* if PromptOnLogout is off, saving depends on AutoSave */ - if (!prompt) + hbox = gtk_hbox_new (TRUE, BORDER); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + gtk_widget_show (hbox); + + dialog->shutdown = xfsm_shutdown_get (); + + /** + * Cancel + **/ + dialog->button_cancel = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + + /** + * Ok, for password mode + **/ + dialog->button_ok = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_OK, + GTK_RESPONSE_OK); + gtk_widget_hide (dialog->button_ok); + + /** + * Close, for password error + **/ + dialog->button_close = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_CLOSE, + GTK_RESPONSE_CANCEL); + gtk_widget_hide (dialog->button_close); + + /** + * Logout + **/ + button = xfsm_logout_dialog_button (_("_Log Out"), "system-log-out", + "xfsm-logout", XFSM_SHUTDOWN_LOGOUT, + dialog); + + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_show (button); + gtk_widget_grab_focus (button); + + /** + * Reboot + **/ + can_restart = kiosk_can_shutdown; + if (can_restart) { - *shutdown_type = XFSM_SHUTDOWN_LOGOUT; - *save_session = autosave; + if (!xfsm_shutdown_can_restart (dialog->shutdown, &can_restart, &error)) + { + g_printerr ("%s: Querying CanRestart failed, %s\n\n", + PACKAGE_NAME, ERROR_MSG (error)); + g_clear_error (&error); - return TRUE; + can_restart = FALSE; + } } - /* spawn the helper early so we know what it supports when - * constructing the dialog */ - shutdown_helper = xfsm_shutdown_helper_new (); + button = xfsm_logout_dialog_button (_("_Restart"), "system-reboot", + "xfsm-reboot", XFSM_SHUTDOWN_RESTART, + dialog); - /* It's really bad here if someone else has the pointer - * grabbed, so we first grab the pointer and keyboard - * to an offscreen window, and then once we have the - * server grabbed, move that to our dialog. - */ - gtk_rc_reparse_all (); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_set_sensitive (button, can_restart); + gtk_widget_show (button); - /* get screen with pointer */ - screen = xfce_gdk_screen_get_active (&monitor); - if (screen == NULL) + /** + * Shutdown + **/ + can_shutdown = kiosk_can_shutdown; + if (can_shutdown) { - screen = gdk_screen_get_default (); - monitor = 0; + if (!xfsm_shutdown_can_shutdown (dialog->shutdown, &can_shutdown, &error)) + { + g_printerr ("%s: Querying CanShutdown failed. %s\n\n", + PACKAGE_NAME, ERROR_MSG (error)); + g_clear_error (&error); + + can_shutdown = FALSE; + } } - /* Try to grab Input on a hidden window first */ - hidden = gtk_invisible_new_for_screen (screen); - gtk_widget_show_now (hidden); + button = xfsm_logout_dialog_button (_("Shut _Down"), "system-shutdown", + "xfsm-shutdown", XFSM_SHUTDOWN_SHUTDOWN, + dialog); - accessibility = GTK_IS_ACCESSIBLE (gtk_widget_get_accessible (hidden)); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_set_sensitive (button, can_shutdown); + gtk_widget_show (button); - if (!accessibility) + /** + * Suspend and Hibernate + **/ + if (kiosk_can_shutdown) { - for (;;) + /** + * Suspend + * + * Hide the button if Xfpm is not installed + **/ + if (xfconf_channel_get_bool (channel, "/shutdown/ShowSuspend", TRUE)) { - if (gdk_pointer_grab (hidden->window, TRUE, 0, NULL, NULL, - GDK_CURRENT_TIME) == GDK_GRAB_SUCCESS) + if (xfsm_shutdown_can_suspend (dialog->shutdown, &can_suspend, &error)) { - if (gdk_keyboard_grab (hidden->window, FALSE, GDK_CURRENT_TIME) - == GDK_GRAB_SUCCESS) - { - break; - } + button = xfsm_logout_dialog_button (_("Sus_pend"), "system-suspend", + "xfsm-suspend", XFSM_SHUTDOWN_SUSPEND, + dialog); - gdk_pointer_ungrab (GDK_CURRENT_TIME); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_set_sensitive (button, can_suspend); + gtk_widget_show (button); + } + else + { + g_printerr ("%s: Querying CanSuspend failed. %s\n\n", + PACKAGE_NAME, ERROR_MSG (error)); + g_clear_error (&error); } - - g_usleep (50 * 1000); } -#ifdef SESSION_SCREENSHOTS - /* grab a screenshot */ - root = gdk_screen_get_root_window (screen); - gdk_screen_get_monitor_geometry (screen, monitor, &screenshot_area); - screenshot_pm = gdk_pixmap_new (GDK_DRAWABLE (root), - screenshot_area.width, - screenshot_area.height, - -1); - screenshot_gc = gdk_gc_new (GDK_DRAWABLE (screenshot_pm)); - gdk_gc_set_function (screenshot_gc, GDK_COPY); - gdk_gc_set_subwindow (screenshot_gc, TRUE); - gdk_draw_drawable (GDK_DRAWABLE (screenshot_pm), - screenshot_gc, - GDK_DRAWABLE (root), - screenshot_area.x, - screenshot_area.y, - 0, - 0, - screenshot_area.width, - screenshot_area.height); - g_object_unref (G_OBJECT (screenshot_gc)); -#endif - - /* display fadeout */ - fadeout = xfsm_fadeout_new (gtk_widget_get_display (hidden)); - gdk_flush (); + /** + * Hibernate + * + * Hide the button if Xfpm is not installed + **/ + if (xfconf_channel_get_bool (channel, "/shutdown/ShowHibernate", TRUE)) + { + if (xfsm_shutdown_can_hibernate (dialog->shutdown, &can_hibernate, &error)) + { + button = xfsm_logout_dialog_button (_("_Hibernate"), "system-hibernate", + "xfsm-hibernate", XFSM_SHUTDOWN_HIBERNATE, + dialog); - /* create confirm dialog */ - dialog = g_object_new (GTK_TYPE_DIALOG, - "type", GTK_WINDOW_POPUP, - NULL); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_set_sensitive (button, can_hibernate); + gtk_widget_show (button); + } + else + { + g_printerr ("%s: Querying CanHibernate failed. %s\n\n", + PACKAGE_NAME, ERROR_MSG (error)); + g_clear_error (&error); + } + } } - else + + /** + * Save session + **/ + if (kiosk_can_save_session + && !xfconf_channel_get_bool (channel, "/general/AutoSave", FALSE)) { - dialog = gtk_dialog_new (); - atk_object_set_role (gtk_widget_get_accessible (dialog), ATK_ROLE_ALERT); - gtk_window_set_decorated (GTK_WINDOW (dialog), FALSE); + dialog->save_session = gtk_check_button_new_with_mnemonic (_("_Save session for future logins")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->save_session), save_session); + gtk_box_pack_start (GTK_BOX (vbox), dialog->save_session, FALSE, TRUE, BORDER); + gtk_widget_show (dialog->save_session); } - shutdown_dialog = dialog; - - cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL); + attrs = pango_attr_list_new (); + pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD)); - ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OK, - GTK_RESPONSE_OK); + /** + * Start mode MODE_ASK_PASSWORD + **/ + dialog->box[MODE_ASK_PASSWORD] = vbox = gtk_vbox_new (FALSE, BORDER); + gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0); - gtk_widget_hide (ok_button); - - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); - gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); - gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); - gtk_window_set_screen (GTK_WINDOW (dialog), screen); + hbox = gtk_hbox_new (FALSE, BORDER * 2); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + gtk_widget_show (hbox); - dbox = GTK_DIALOG(dialog)->vbox; + image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + gtk_widget_show (image); - vbox = gtk_vbox_new(FALSE, BORDER); - gtk_box_pack_start(GTK_BOX(dbox), vbox, TRUE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER); - gtk_widget_show(vbox); + vbox = gtk_vbox_new (FALSE, BORDER); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + gtk_widget_show (vbox); -#ifdef HAVE_GETPWUID - pw = getpwuid (getuid ()); - if (G_LIKELY(pw && pw->pw_name && *pw->pw_name)) - { - gchar *text = g_strdup_printf (_("<span size='large'><b>Log out %s</b></span>"), pw->pw_name); - GtkWidget *logout_label = g_object_new (GTK_TYPE_LABEL, - "label", text, - "use-markup", TRUE, - "justify", GTK_JUSTIFY_CENTER, - "xalign", 0.5, - "yalign", 0.5, - NULL); - - gtk_widget_show (logout_label); - gtk_box_pack_start (GTK_BOX (vbox), logout_label, FALSE, FALSE, 0); - - g_free (text); - } -#endif + label = gtk_label_new (_("Please enter your password")); + gtk_misc_set_alignment (GTK_MISC (label), 0.00, 0.50); + gtk_label_set_attributes (GTK_LABEL (label), attrs); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); - hbox = gtk_hbox_new (TRUE, BORDER); + dialog->password_entry = entry = gtk_entry_new (); + gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE); + gtk_entry_set_width_chars (GTK_ENTRY (entry), 30); + gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); + g_signal_connect_swapped (G_OBJECT (entry), "activate", + G_CALLBACK (xfsm_logout_dialog_activate), dialog); + gtk_widget_show (entry); + + /** + * Start mode MODE_SHOW_ERROR + **/ + dialog->box[MODE_SHOW_ERROR] = vbox = gtk_vbox_new (FALSE, BORDER); + gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0); + + hbox = gtk_hbox_new (FALSE, BORDER * 2); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - - /* logout */ - logout_button = gtk_button_new (); - gtk_widget_show (logout_button); - gtk_box_pack_start (GTK_BOX (hbox), logout_button, TRUE, TRUE, 0); - - g_signal_connect (logout_button, "clicked", - G_CALLBACK (logout_button_clicked), shutdown_type); - - vbox2 = gtk_vbox_new (FALSE, BORDER); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), BORDER); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (logout_button), vbox2); - - icon = gtk_icon_theme_load_icon (icon_theme, - "system-log-out", - 32, - 0, - NULL); - if (!icon) - icon = gtk_icon_theme_load_icon (icon_theme, - "xfsm-logout", - 32, - GTK_ICON_LOOKUP_GENERIC_FALLBACK, - NULL); - - image = gtk_image_new_from_pixbuf (icon); - gtk_widget_show (image); - gtk_box_pack_start (GTK_BOX (vbox2), image, FALSE, FALSE, 0); - g_object_unref (icon); - label = gtk_label_new_with_mnemonic (_("_Log Out")); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); - - /* reboot */ - reboot_button = gtk_button_new (); - gtk_widget_show (reboot_button); - gtk_box_pack_start (GTK_BOX (hbox), reboot_button, TRUE, TRUE, 0); - - g_signal_connect (reboot_button, "clicked", - G_CALLBACK (reboot_button_clicked), shutdown_type); - - vbox2 = gtk_vbox_new (FALSE, BORDER); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), BORDER); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (reboot_button), vbox2); - - icon = gtk_icon_theme_load_icon (icon_theme, - "system-reboot", - 32, - 0, - NULL); - - if (!icon) - icon = gtk_icon_theme_load_icon (icon_theme, - "xfsm-reboot", - 32, - GTK_ICON_LOOKUP_GENERIC_FALLBACK, - NULL); - - image = gtk_image_new_from_pixbuf (icon); + image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_DIALOG); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); gtk_widget_show (image); - gtk_box_pack_start (GTK_BOX (vbox2), image, FALSE, FALSE, 0); - g_object_unref (icon); - label = gtk_label_new_with_mnemonic (_("_Restart")); + vbox = gtk_vbox_new (FALSE, BORDER); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + gtk_widget_show (vbox); + + label = gtk_label_new (_("An error occurred")); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0.00, 0.50); + gtk_label_set_attributes (GTK_LABEL (label), attrs); gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); - - g_object_get (shutdown_helper, - "user-can-restart", &show_restart, - NULL); - - if (!kiosk_can_shutdown || !show_restart ) - gtk_widget_set_sensitive (reboot_button, FALSE); - - /* halt */ - halt_button = gtk_button_new (); - gtk_widget_show (halt_button); - gtk_box_pack_start (GTK_BOX (hbox), halt_button, TRUE, TRUE, 0); - - g_signal_connect (halt_button, "clicked", - G_CALLBACK (halt_button_clicked), shutdown_type); - - vbox2 = gtk_vbox_new (FALSE, BORDER); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), BORDER); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (halt_button), vbox2); - - icon = gtk_icon_theme_load_icon (icon_theme, - "system-shutdown", - 32, - 0, - NULL); - - if (!icon) - icon = gtk_icon_theme_load_icon (icon_theme, - "xfsm-shutdown", - 32, - GTK_ICON_LOOKUP_GENERIC_FALLBACK, - NULL); - - image = gtk_image_new_from_pixbuf (icon); - gtk_widget_show (image); - gtk_box_pack_start (GTK_BOX (vbox2), image, FALSE, FALSE, 0); - g_object_unref (icon); - label = gtk_label_new_with_mnemonic (_("Shut _Down")); + label = gtk_label_new (_("Either the password you entered is " + "invalid, or the system administrator " + "disallows shutting down this computer " + "with your user account.")); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); - g_object_get (shutdown_helper, - "user-can-shutdown", &show_shutdown, - NULL); + pango_attr_list_unref (attrs); +} - if (!kiosk_can_shutdown || !show_shutdown) - gtk_widget_set_sensitive (halt_button, FALSE); - if (show_suspend) - g_object_get (shutdown_helper, - "user-can-suspend", &show_suspend, - NULL); - if (show_hibernate) - g_object_get (shutdown_helper, - "user-can-hibernate", &show_hibernate, - NULL); +static void +xfsm_logout_dialog_finalize (GObject *object) +{ + XfsmLogoutDialog *dialog = XFSM_LOGOUT_DIALOG (object); + g_object_unref (G_OBJECT (dialog->shutdown)); - if (kiosk_can_shutdown && (show_suspend || show_hibernate)) + (*G_OBJECT_CLASS (xfsm_logout_dialog_parent_class)->finalize) (object); +} + + + +static void +xfsm_logout_dialog_set_mode (XfsmLogoutDialog *dialog, + gint mode) +{ + gint i; + + for (i = 0; i < N_MODES; i++) + gtk_widget_set_visible (dialog->box[i], i == mode); + + gtk_widget_set_visible (dialog->button_cancel, mode != MODE_SHOW_ERROR); + gtk_widget_set_visible (dialog->button_ok, mode == MODE_ASK_PASSWORD); + gtk_widget_set_visible (dialog->button_close, mode == MODE_SHOW_ERROR); +} + + + +static void +xfsm_logout_dialog_button_clicked (GtkWidget *button, + XfsmLogoutDialog *dialog) +{ + gint *val; + + val = g_object_get_data (G_OBJECT (button), "shutdown-type"); + g_assert (val != NULL); + dialog->type_clicked = *val; + + gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); +} + + + +static GtkWidget * +xfsm_logout_dialog_button (const gchar *title, + const gchar *icon_name, + const gchar *icon_name_fallback, + XfsmShutdownType type, + XfsmLogoutDialog *dialog) +{ + GtkWidget *button; + GtkWidget *vbox; + GdkPixbuf *pixbuf; + GtkWidget *image; + GtkWidget *label; + static gint icon_size = 0; + gint w, h; + gint *val; + GtkIconTheme *icon_theme; + + g_return_val_if_fail (XFSM_IS_LOGOUT_DIALOG (dialog), NULL); + + val = g_new0 (gint, 1); + *val = type; + + button = gtk_button_new (); + g_object_set_data_full (G_OBJECT (button), "shutdown-type", val, g_free); + g_signal_connect (G_OBJECT (button), "clicked", + G_CALLBACK (xfsm_logout_dialog_button_clicked), dialog); + + vbox = gtk_vbox_new (FALSE, BORDER); + gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER); + gtk_container_add (GTK_CONTAINER (button), vbox); + gtk_widget_show (vbox); + + if (G_UNLIKELY (icon_size == 0)) { - hbox = gtk_hbox_new (FALSE, BORDER); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + if (gtk_icon_size_lookup (GTK_ICON_SIZE_DND, &w, &h)) + icon_size = MAX (w, h); + else + icon_size = 32; } - /* suspend */ - if (kiosk_can_shutdown && show_suspend) + icon_theme = gtk_icon_theme_get_for_screen (gtk_window_get_screen (GTK_WINDOW (dialog))); + pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name, icon_size, 0, NULL); + if (G_UNLIKELY (pixbuf == NULL)) { - suspend_button = gtk_button_new (); - gtk_widget_show (suspend_button); - gtk_box_pack_start (GTK_BOX (hbox), suspend_button, TRUE, TRUE, 0); - - g_signal_connect (suspend_button, "clicked", - G_CALLBACK (suspend_button_clicked), shutdown_type); - - vbox2 = gtk_vbox_new (FALSE, BORDER); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), BORDER); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (suspend_button), vbox2); - - icon = gtk_icon_theme_load_icon (icon_theme, - "system-suspend", - 32, - 0, - NULL); - - if (!icon) - icon = gtk_icon_theme_load_icon (icon_theme, - "xfsm-suspend", - 32, - GTK_ICON_LOOKUP_GENERIC_FALLBACK, + pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name_fallback, + icon_size, GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL); + } - image = gtk_image_new_from_pixbuf (icon); - gtk_widget_show (image); - gtk_box_pack_start (GTK_BOX (vbox2), image, FALSE, FALSE, 0); - g_object_unref (icon); + image = gtk_image_new_from_pixbuf (pixbuf); + gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0); + gtk_widget_show (image); - label = gtk_label_new_with_mnemonic (_("Sus_pend")); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); - } + label = gtk_label_new_with_mnemonic (title); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); - /* hibernate */ - if (kiosk_can_shutdown && show_hibernate) - { - hibernate_button = gtk_button_new (); - gtk_widget_show (hibernate_button); - gtk_box_pack_start (GTK_BOX (hbox), hibernate_button, TRUE, TRUE, 0); - - g_signal_connect (hibernate_button, "clicked", - G_CALLBACK (hibernate_button_clicked), shutdown_type); - - vbox2 = gtk_vbox_new (FALSE, BORDER); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), BORDER); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (hibernate_button), vbox2); - - icon = gtk_icon_theme_load_icon (icon_theme, - "system-hibernate", - 32, - 0, - NULL); - - if (!icon) - icon = gtk_icon_theme_load_icon (icon_theme, - "xfsm-hibernate", - 32, - GTK_ICON_LOOKUP_GENERIC_FALLBACK, - NULL); + return button; +} - image = gtk_image_new_from_pixbuf (icon); - gtk_widget_show (image); - gtk_box_pack_start (GTK_BOX (vbox2), image, FALSE, FALSE, 0); - g_object_unref (icon); - label = gtk_label_new_with_mnemonic (_("_Hibernate")); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); - } - /* save session */ - if (!autosave && kiosk_can_save_session) +static void +xfsm_logout_dialog_activate (XfsmLogoutDialog *dialog) +{ + g_return_if_fail (XFSM_IS_LOGOUT_DIALOG (dialog)); + gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); +} + + + +static GdkPixbuf * +xfsm_logout_dialog_screenshot_new (GdkScreen *screen) +{ + GdkRectangle rect, screen_rect; + GdkWindow *window; + GdkPixbuf *screenshot; + gint x, y; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + + screen_rect.x = 0; + screen_rect.y = 0; + screen_rect.width = gdk_screen_get_width (screen); + screen_rect.height = gdk_screen_get_height (screen); + + window = gdk_screen_get_root_window (screen); + gdk_drawable_get_size (GDK_DRAWABLE (window), &rect.width, &rect.height); + gdk_window_get_origin (window, &x, &y); + + rect.x = x; + rect.y = y; + + if (!gdk_rectangle_intersect (&rect, &screen_rect, &rect)) + return NULL; + + screenshot = gdk_pixbuf_get_from_drawable (NULL, + GDK_DRAWABLE (window), + NULL, + 0, 0, + 0, 0, + rect.width, + rect.height); + + gdk_display_beep (gdk_screen_get_display (screen)); + + return screenshot; +} + + + +static GdkPixbuf * +exo_gdk_pixbuf_scale_ratio (GdkPixbuf *source, + gint dest_size) +{ + gdouble wratio; + gdouble hratio; + gint source_width; + gint source_height; + gint dest_width; + gint dest_height; + + g_return_val_if_fail (GDK_IS_PIXBUF (source), NULL); + g_return_val_if_fail (dest_size > 0, NULL); + + source_width = gdk_pixbuf_get_width (source); + source_height = gdk_pixbuf_get_height (source); + + wratio = (gdouble) source_width / (gdouble) dest_size; + hratio = (gdouble) source_height / (gdouble) dest_size; + + if (hratio > wratio) { - checkbox = gtk_check_button_new_with_mnemonic( - _("_Save session for future logins")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), saveonexit); - gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, TRUE, BORDER); - gtk_widget_show(checkbox); + dest_width = rint (source_width / hratio); + dest_height = dest_size; } else { - checkbox = NULL; + dest_width = dest_size; + dest_height = rint (source_height / wratio); } - /* create small border */ - if (!accessibility) - xfsm_window_add_border (GTK_WINDOW (dialog)); + return gdk_pixbuf_scale_simple (source, MAX (dest_width, 1), + MAX (dest_height, 1), GDK_INTERP_BILINEAR); +} - /* center dialog on target monitor */ - gtk_window_set_screen (GTK_WINDOW (dialog), screen); - gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); - /* save portion of the root window covered by the dialog */ - if (!accessibility && shutdown_helper != NULL) + +static void +xfsm_logout_dialog_screenshot_save (GdkPixbuf *screenshot, + GdkScreen *screen, + const gchar *session_name) +{ + GdkPixbuf *scaled; + gchar *path; + gchar *display_name; + GdkDisplay *dpy; + GError *error = NULL; + gchar *filename; + + g_return_if_fail (GDK_IS_PIXBUF (screenshot)); + g_return_if_fail (GDK_IS_SCREEN (screen)); + + scaled = exo_gdk_pixbuf_scale_ratio (screenshot, SHOTSIZE); + if (G_LIKELY (scaled != NULL)) { - gtk_widget_realize (dialog); - gdk_window_set_override_redirect (dialog->window, TRUE); - gdk_window_raise (dialog->window); + dpy = gdk_screen_get_display (screen); + display_name = xfsm_gdk_display_get_fullname (dpy); + path = g_strconcat ("sessions/thumbs-", display_name, "/", session_name, ".png", NULL); + filename = xfce_resource_save_location (XFCE_RESOURCE_CACHE, path, TRUE); + g_free (display_name); + g_free (path); + + if (!gdk_pixbuf_save (scaled, filename, "png", &error, NULL)) + { + g_warning ("Failed to save session screenshot: %s", error->message); + g_error_free (error); + } + + g_free (filename); + g_object_unref (G_OBJECT (scaled)); } +} - /* need to realize the dialog first! */ - gtk_widget_show_now (dialog); - gtk_widget_grab_focus (logout_button); - /* Grab Keyboard and Mouse pointer */ - if (!accessibility) - xfsm_window_grab_input (GTK_WINDOW (dialog)); - /* run the logout dialog */ - result = gtk_dialog_run (GTK_DIALOG(dialog)); +static gint +xfsm_logout_dialog_run (GtkDialog *dialog, + gboolean grab_input) +{ + GdkWindow *window; + gint ret; - if (result == GTK_RESPONSE_OK) { - *save_session = autosave ? autosave : - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox)); - } + if (grab_input) + { + gtk_widget_show_now (GTK_WIDGET (dialog)); + + window = gtk_widget_get_window (GTK_WIDGET (dialog)); + if (gdk_keyboard_grab (window, FALSE, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS) + g_critical ("Failed to grab the keyboard for logout window"); + +#ifdef GDK_WINDOWING_X11 + /* force input to the dialog */ + gdk_error_trap_push (); + XSetInputFocus (GDK_DISPLAY (), + GDK_WINDOW_XWINDOW (window), + RevertToParent, CurrentTime); + gdk_error_trap_pop (); +#endif + } - gtk_widget_hide (dialog); + ret = gtk_dialog_run (dialog); + + if (grab_input) + gdk_keyboard_ungrab (GDK_CURRENT_TIME); + + return ret; +} + + + +gboolean +xfsm_logout_dialog (const gchar *session_name, + XfsmShutdownType *return_type, + gboolean *return_save_session) +{ + gint result; + GtkWidget *hidden; + gboolean a11y; + GtkWidget *dialog; + GdkScreen *screen; + gint monitor; + GdkPixbuf *screenshot = NULL; + XfsmFadeout *fadeout = NULL; + XfsmLogoutDialog *xfsm_dialog; + XfconfChannel *channel = xfsm_open_config (); + XfceKiosk *kiosk; + gboolean autosave; + gboolean kiosk_can_save_session; + const gchar *text; + XfsmPassState state; + + g_return_val_if_fail (return_type != NULL, FALSE); + g_return_val_if_fail (return_save_session != NULL, FALSE); + + /* get autosave state */ + kiosk = xfce_kiosk_new ("xfce4-session"); + kiosk_can_save_session = xfce_kiosk_query (kiosk, "SaveSession"); + xfce_kiosk_free (kiosk); - g_object_get (shutdown_helper, - "require-password", &require_password, - NULL); + if (kiosk_can_save_session) + autosave = xfconf_channel_get_bool (channel, "/general/AutoSave", FALSE); + else + autosave = FALSE; - /* ask password */ - if (result == GTK_RESPONSE_OK && *shutdown_type != XFSM_SHUTDOWN_LOGOUT - && require_password ) + /* check if we need to bother the user */ + if (!xfconf_channel_get_bool (channel, "/general/PromptOnLogout", TRUE)) { - gtk_widget_show (ok_button); + *return_type = XFSM_SHUTDOWN_LOGOUT; + *return_save_session = autosave; - gtk_widget_destroy (vbox); + return TRUE; + } - entry_vbox = gtk_vbox_new (FALSE, BORDER); - gtk_box_pack_start (GTK_BOX (dbox), entry_vbox, TRUE, TRUE, BORDER); - gtk_widget_show (entry_vbox); + /* decide on which screen we should show the dialog */ + screen = xfce_gdk_screen_get_active (&monitor); + if (G_UNLIKELY (screen == NULL)) + { + screen = gdk_screen_get_default (); + monitor = 0; + } - label = gtk_label_new (_("Please enter your password:")); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (entry_vbox), label, FALSE, FALSE, 0); + /* check if accessibility is enabled */ + hidden = gtk_invisible_new_for_screen (screen); + gtk_widget_show (hidden); + a11y = GTK_IS_ACCESSIBLE (gtk_widget_get_accessible (hidden)); - entry = gtk_entry_new (); - gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); - gtk_box_pack_start (GTK_BOX (entry_vbox), entry, TRUE, TRUE, 0); - g_signal_connect (G_OBJECT (entry), "activate", - G_CALLBACK (entry_activate_cb), dialog); - gtk_widget_show (entry); + if (G_LIKELY (!a11y)) + { + /* wait until we can grab the keyboard, we need this for + * the dialog when running it */ + for (;;) + { + if (gdk_keyboard_grab (gtk_widget_get_window (hidden), FALSE, + GDK_CURRENT_TIME) == GDK_GRAB_SUCCESS) + { + gdk_keyboard_ungrab (GDK_CURRENT_TIME); + break; + } - /* center dialog on target monitor */ - gtk_window_set_screen (GTK_WINDOW (dialog), screen); - gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); + g_usleep (G_USEC_PER_SEC / 20); + } + + /* make a screenshot */ + if (xfconf_channel_get_bool (channel, "/general/ShowScreenshots", TRUE)) + screenshot = xfsm_logout_dialog_screenshot_new (screen); - gtk_widget_show_now (dialog); - gtk_widget_grab_focus (entry); + /* display fadeout */ + fadeout = xfsm_fadeout_new (gdk_screen_get_display (screen)); + gdk_flush (); - /* Grab Keyboard and Mouse pointer */ - if (!accessibility) - xfsm_window_grab_input (GTK_WINDOW (dialog)); + dialog = g_object_new (XFSM_TYPE_LOGOUT_DIALOG, + "type", GTK_WINDOW_POPUP, + "screen", screen, NULL); - result = gtk_dialog_run (GTK_DIALOG (dialog)); + xfsm_window_add_border (GTK_WINDOW (dialog)); - if (result == GTK_RESPONSE_OK) + gtk_widget_realize (dialog); + gdk_window_set_override_redirect (dialog->window, TRUE); + gdk_window_raise (dialog->window); + } + else + { + dialog = g_object_new (XFSM_TYPE_LOGOUT_DIALOG, + "decorated", !a11y, + "screen", screen, NULL); + + gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE); + atk_object_set_role (gtk_widget_get_accessible (dialog), ATK_ROLE_ALERT); + } + + gtk_widget_destroy (hidden); + + xfsm_dialog = XFSM_LOGOUT_DIALOG (dialog); + + /* set mode */ + xfsm_logout_dialog_set_mode (xfsm_dialog, MODE_LOGOUT_BUTTONS); + + result = xfsm_logout_dialog_run (GTK_DIALOG (dialog), !a11y); + + gtk_widget_hide (dialog); + + if (result == GTK_RESPONSE_OK) + { + /* check if the sudo helper needs a password */ + if (xfsm_shutdown_password_require (xfsm_dialog->shutdown, xfsm_dialog->type_clicked)) { - const gchar *password = gtk_entry_get_text (GTK_ENTRY (entry)); + /* switch mode */ + xfsm_logout_dialog_set_mode (xfsm_dialog, MODE_ASK_PASSWORD); - if (!xfsm_shutdown_helper_send_password (shutdown_helper, password)) + /* don't leave artifacts on the background window */ + xfsm_fadeout_clear (fadeout); + + /* loop for sudo password tries */ + for (;;) { - gtk_label_set_text (GTK_LABEL (label), - _("<b>An error occurred</b>")); - gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_widget_grab_focus (xfsm_dialog->password_entry); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); + result = xfsm_logout_dialog_run (GTK_DIALOG (dialog), !a11y); - gtk_container_remove (GTK_CONTAINER ( - GTK_DIALOG (dialog)->action_area), cancel_button); - gtk_container_remove (GTK_CONTAINER ( - GTK_DIALOG (dialog)->action_area), ok_button); + if (result == GTK_RESPONSE_OK) + { + /* bit of visual feedback we're processing the password */ + gtk_widget_set_sensitive (xfsm_dialog->button_cancel, FALSE); + gtk_widget_set_sensitive (xfsm_dialog->button_ok, FALSE); - gtk_container_remove (GTK_CONTAINER (entry_vbox), entry); + /* update the widgets before we lock the loop */ + while (gtk_events_pending ()) + g_main_context_iteration (NULL, FALSE); - gtk_dialog_add_button (GTK_DIALOG (dialog), - GTK_STOCK_CLOSE, - GTK_RESPONSE_CANCEL); + /* send the password to the helper */ + text = gtk_entry_get_text (GTK_ENTRY (xfsm_dialog->password_entry)); + state = xfsm_shutdown_password_send (xfsm_dialog->shutdown, xfsm_dialog->type_clicked, text); + gtk_entry_set_text (GTK_ENTRY (xfsm_dialog->password_entry), ""); - label = gtk_label_new (_("Either the password you entered is " - "invalid, or the system administrator " - "disallows shutting down this computer " - "with your user account.")); - gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); - gtk_box_pack_start (GTK_BOX (entry_vbox), label, TRUE, TRUE, 0); - gtk_widget_show (label); + gtk_widget_set_sensitive (xfsm_dialog->button_cancel, TRUE); + gtk_widget_set_sensitive (xfsm_dialog->button_ok, TRUE); - /* center dialog on target monitor */ - gtk_window_set_screen (GTK_WINDOW (dialog), screen); - gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); + if (state == PASSWORD_RETRY) + continue; - gtk_widget_show_now (dialog); + if (state == PASSWORD_FAILED) + { + gtk_widget_hide (dialog); - /* Grab Keyboard and Mouse pointer */ - if (!accessibility) - xfsm_window_grab_input (GTK_WINDOW (dialog)); + xfsm_logout_dialog_set_mode (xfsm_dialog, MODE_SHOW_ERROR); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); - gtk_dialog_run (GTK_DIALOG (dialog)); + /* don't leave artifacts on the background window */ + xfsm_fadeout_clear (fadeout); - result = GTK_RESPONSE_CANCEL; - } - } - } + /* show error */ + xfsm_logout_dialog_run (GTK_DIALOG (dialog), !a11y); - gtk_widget_destroy(dialog); - gtk_widget_destroy(hidden); + result = GTK_RESPONSE_CANCEL; + } + } - shutdown_dialog = NULL; + /* cancel clicked, succeeded or helper killed */ + break; + } - /* Release Keyboard/Mouse pointer grab */ - if (!accessibility) - { - xfsm_fadeout_destroy (fadeout); + gtk_widget_hide (dialog); + } - gdk_pointer_ungrab (GDK_CURRENT_TIME); - gdk_keyboard_ungrab (GDK_CURRENT_TIME); - gdk_flush (); + if (result == GTK_RESPONSE_OK) + { + /* store autosave state */ + if (autosave) + *return_save_session = TRUE; + else if (xfsm_dialog->save_session != NULL) + *return_save_session = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (xfsm_dialog->save_session)); + else + *return_save_session = FALSE; + + /* return the clicked action */ + *return_type = xfsm_dialog->type_clicked; + } } - /* process all pending events first */ - while (gtk_events_pending ()) - g_main_context_iteration (NULL, FALSE); + if (fadeout != NULL) + xfsm_fadeout_destroy (fadeout); - /* - * remember the current settings. - */ + gtk_widget_destroy (dialog); + + /* store channel settings if everything worked fine */ if (result == GTK_RESPONSE_OK) { xfconf_channel_set_string (channel, "/general/SessionName", session_name); - xfconf_channel_set_bool (channel, "/general/SaveOnExit", *save_session); - } - else - { - g_object_unref (shutdown_helper); - shutdown_helper = NULL; + xfconf_channel_set_bool (channel, "/general/SaveOnExit", *return_save_session); } -#ifdef SESSION_SCREENSHOTS - if (screenshot_pm != NULL) + /* save the screenshot */ + if (screenshot != NULL) { if (result == GTK_RESPONSE_OK) - screenshot_save (session_name, screenshot_pm, &screenshot_area); - - g_object_unref (G_OBJECT (screenshot_pm)); + xfsm_logout_dialog_screenshot_save (screenshot, screen, session_name); + g_object_unref (G_OBJECT (screenshot)); } -#endif return (result == GTK_RESPONSE_OK); } diff --git a/xfce4-session/xfsm-logout-dialog.h b/xfce4-session/xfsm-logout-dialog.h index ed348b7a..2cb08828 100644 --- a/xfce4-session/xfsm-logout-dialog.h +++ b/xfce4-session/xfsm-logout-dialog.h @@ -22,10 +22,22 @@ #ifndef __XFSM_LOGOUT_DIALOG_H__ #define __XFSM_LOGOUT_DIALOG_H__ -#include <xfce4-session/xfsm-global.h> +#include <xfce4-session/xfsm-shutdown.h> -gboolean xfsm_logout_dialog (const gchar *session_name, - XfsmShutdownType *shutdown_type, - gboolean *save_session); +typedef struct _XfsmLogoutDialogClass XfsmLogoutDialogClass; +typedef struct _XfsmLogoutDialog XfsmLogoutDialog; + +#define XFSM_TYPE_LOGOUT_DIALOG (xfsm_logout_dialog_get_type ()) +#define XFSM_LOGOUT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFSM_TYPE_LOGOUT_DIALOG, XfsmLogoutDialog)) +#define XFSM_LOGOUT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XFSM_TYPE_LOGOUT_DIALOG, XfsmLogoutDialogClass)) +#define XFSM_IS_LOGOUT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFSM_TYPE_LOGOUT_DIALOG)) +#define XFSM_IS_LOGOUT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFSM_TYPE_LOGOUT_DIALOG)) +#define XFSM_LOGOUT_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XFSM_TYPE_LOGOUT_DIALOG, XfsmLogoutDialogClass)) + +GType xfsm_logout_dialog_get_type (void) G_GNUC_CONST; + +gboolean xfsm_logout_dialog (const gchar *session_name, + XfsmShutdownType *return_type, + gboolean *return_save_session); #endif diff --git a/xfce4-session/xfsm-manager.c b/xfce4-session/xfsm-manager.c index 9f87c482..367c11c9 100644 --- a/xfce4-session/xfsm-manager.c +++ b/xfce4-session/xfsm-manager.c @@ -71,7 +71,6 @@ #include <libwnck/libwnck.h> -#include <xfce4-session/xfsm-shutdown-helper.h> #include <libxfce4ui/libxfce4ui.h> #include <libxfsm/xfsm-splash-engine.h> @@ -1085,8 +1084,10 @@ xfsm_manager_save_yourself_global (XfsmManager *manager, XfsmShutdownType shutdown_type, gboolean allow_shutdown_save) { - gboolean shutdown_save = allow_shutdown_save; - GList *lp; + gboolean shutdown_save = allow_shutdown_save; + GList *lp; + XfsmShutdown *shutdown_helper; + GError *error = NULL; if (shutdown) { @@ -1111,14 +1112,11 @@ xfsm_manager_save_yourself_global (XfsmManager *manager, if (manager->shutdown_type == XFSM_SHUTDOWN_SUSPEND || manager->shutdown_type == XFSM_SHUTDOWN_HIBERNATE) { - XfsmShutdownHelper *shutdown_helper; - GError *error = NULL; - - shutdown_helper = xfsm_shutdown_helper_new (); + shutdown_helper = xfsm_shutdown_get (); - if (!xfsm_shutdown_helper_send_command (shutdown_helper, - manager->shutdown_type, - &error)) + if (!xfsm_shutdown_try_type (shutdown_helper, + manager->shutdown_type, + &error)) { xfce_message_dialog (NULL, _("Shutdown Failed"), GTK_STOCK_DIALOG_ERROR, @@ -1131,10 +1129,8 @@ xfsm_manager_save_yourself_global (XfsmManager *manager, g_error_free (error); } - /* clean up and return */ g_object_unref (shutdown_helper); - /* at this point, either we failed to suspend/hibernate, or we * successfully suspended/hibernated, and we've been woken back * up, so return control to the user */ diff --git a/xfce4-session/xfsm-manager.h b/xfce4-session/xfsm-manager.h index b12b143a..521bacc0 100644 --- a/xfce4-session/xfsm-manager.h +++ b/xfce4-session/xfsm-manager.h @@ -30,6 +30,7 @@ #include <xfce4-session/xfsm-client.h> #include <xfce4-session/xfsm-global.h> +#include <xfce4-session/xfsm-shutdown.h> G_BEGIN_DECLS diff --git a/xfce4-session/xfsm-shutdown-helper.c b/xfce4-session/xfsm-shutdown-helper.c deleted file mode 100644 index ef29f4f5..00000000 --- a/xfce4-session/xfsm-shutdown-helper.c +++ /dev/null @@ -1,1862 +0,0 @@ -/* $Id$ */ -/*- - * Copyright (c) 2003-2006 Benedikt Meurer <benny@xfce.org> - * Copyright (c) 2010 Ali Abdallah <aliov@xfce.org> - * All rights reserved. - * - * 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, 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., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include <sys/resource.h> -#endif -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif -#ifdef HAVE_SYS_USER_H -#include <sys/user.h> -#endif -#ifdef HAVE_SYS_SYSCTL_H -#include <sys/sysctl.h> -#endif - -#ifdef HAVE_MEMORY_H -#include <memory.h> -#endif -#include <stdio.h> -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif - -#include <dbus/dbus.h> -#include <dbus/dbus-glib-lowlevel.h> - -#include <libxfce4util/libxfce4util.h> - -#include <xfce4-session/xfsm-shutdown-helper.h> -#include <xfce4-session/xfsm-global.h> - -static void xfsm_shutdown_helper_finalize (GObject *object); - -static void xfsm_shutdown_helper_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); - -static void xfsm_shutdown_helper_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - -/** - * Suspend/Hibernate backend to use. - * - * upower, HAL, pmutils via sudo. - * - **/ -typedef enum -{ - XFSM_SLEEP_BACKEND_NOT_SUPPORTED, - XFSM_SLEEP_BACKEND_UPOWER, - XFSM_SLEEP_BACKEND_HAL, - XFSM_SLEEP_BACKEND_SUDO /*sudo pm-suspend ?*/ - -} XfsmSleepBackend; - -/** - * Shutdown/Reboot backend to use - * - * ConsoleKit, HAL, sudo - **/ -typedef enum -{ - XFSM_SHUTDOWN_BACKEND_NOT_SUPPORTED, - XFSM_SHUTDOWN_BACKEND_CONSOLE_KIT, - XFSM_SHUTDOWN_BACKEND_HAL, - XFSM_SHUTDOWN_BACKEND_SUDO - -} XfsmShutdownBackend; - -#ifdef ENABLE_POLKIT -/*DBus GTypes for polkit calls*/ -static GType polkit_subject_gtype = G_TYPE_INVALID; -static GType polkit_details_gtype = G_TYPE_INVALID; -static GType polkit_result_gtype = G_TYPE_INVALID; -#endif /*ENABLE_POLKIT*/ - -struct _XfsmShutdownHelper -{ - GObject parent; - - DBusGConnection *system_bus; - -#ifdef ENABLE_POLKIT - DBusGProxy *polkit_proxy; - GValueArray *polkit_subject; - GHashTable *polkit_details; - GHashTable *polkit_subject_hash; -#endif - - XfsmShutdownBackend shutdown_backend; - XfsmSleepBackend sleep_backend; - - gboolean auth_shutdown; - gboolean auth_restart; - gboolean auth_suspend; - gboolean auth_hibernate; - gboolean can_shutdown; - gboolean can_restart; - gboolean can_suspend; - gboolean can_hibernate; - - gboolean devkit_is_upower; - - /* Sudo data */ - gchar *sudo; - FILE *infile; - FILE *outfile; - pid_t pid; - gboolean require_password; - -}; - -struct _XfsmShutdownHelperClass -{ - GObjectClass parent_class; -}; - -enum -{ - PROP_0, - PROP_AUTHORIZED_TO_SHUTDOWN, - PROP_AUTHORIZED_TO_RESTART, - PROP_AUTHORIZED_TO_SUSPEND, - PROP_AUTHORIZED_TO_HIBERNATE, - PROP_CAN_SHUTDOWN, - PROP_CAN_RESTART, - PROP_CAN_SUSPEND, - PROP_CAN_HIBERNATE, - PROP_USER_CAN_SHUTDOWN, - PROP_USER_CAN_RESTART, - PROP_USER_CAN_SUSPEND, - PROP_USER_CAN_HIBERNATE, - PROP_REQUIRE_PASSWORD -}; - -G_DEFINE_TYPE (XfsmShutdownHelper, xfsm_shutdown_helper, G_TYPE_OBJECT) - -#ifdef ENABLE_POLKIT - -#if defined(__FreeBSD__) -/** - * Taken from polkitunixprocess.c code to get process start - * time from pid. - * - * Copyright (C) 2008 Red Hat, Inc. - * - **/ -static gboolean -get_kinfo_proc (pid_t pid, struct kinfo_proc *p) -{ - int mib[4]; - size_t len; - - len = 4; - sysctlnametomib ("kern.proc.pid", mib, &len); - - len = sizeof (struct kinfo_proc); - mib[3] = pid; - - if (sysctl (mib, 4, p, &len, NULL, 0) == -1) - return FALSE; - - return TRUE; -} -#endif /*if defined(__FreeBSD__)*/ - -static guint64 -get_start_time_for_pid (pid_t pid) -{ - guint64 start_time; -#if !defined(__FreeBSD__) - gchar *filename; - gchar *contents; - size_t length; - gchar **tokens; - guint num_tokens; - gchar *p; - gchar *endp; - - start_time = 0; - contents = NULL; - - filename = g_strdup_printf ("/proc/%d/stat", pid); - - if (!g_file_get_contents (filename, &contents, &length, NULL)) - goto out; - - /* start time is the token at index 19 after the '(process name)' entry - since only this - * field can contain the ')' character, search backwards for this to avoid malicious - * processes trying to fool us - */ - p = strrchr (contents, ')'); - if (p == NULL) - { - goto out; - } - p += 2; /* skip ') ' */ - - if (p - contents >= (int) length) - { - g_warning ("Error parsing file %s", filename); - goto out; - } - - tokens = g_strsplit (p, " ", 0); - - num_tokens = g_strv_length (tokens); - - if (num_tokens < 20) - { - g_warning ("Error parsing file %s", filename); - goto out; - } - - start_time = strtoull (tokens[19], &endp, 10); - if (endp == tokens[19]) - { - g_warning ("Error parsing file %s", filename); - goto out; - } - - g_strfreev (tokens); - - out: - g_free (filename); - g_free (contents); - -#else /*if !defined(__FreeBSD__)*/ - - struct kinfo_proc p; - - start_time = 0; - - if (! get_kinfo_proc (pid, &p)) - { - g_warning ("Error obtaining start time for %d (%s)", - (gint) pid, - g_strerror (errno)); - goto out; - } - - start_time = (guint64) p.ki_start.tv_sec; - -out: -#endif - - return start_time; -} - -static void -init_dbus_gtypes (void) -{ - if (G_UNLIKELY (polkit_subject_gtype == G_TYPE_INVALID ) ) - { - polkit_subject_gtype = - dbus_g_type_get_struct ("GValueArray", - G_TYPE_STRING, - dbus_g_type_get_map ("GHashTable", - G_TYPE_STRING, - G_TYPE_VALUE), - G_TYPE_INVALID); - } - - if (G_UNLIKELY (polkit_details_gtype == G_TYPE_INVALID )) - { - polkit_details_gtype = dbus_g_type_get_map ("GHashTable", - G_TYPE_STRING, - G_TYPE_STRING); - } - - if (G_UNLIKELY (polkit_result_gtype == G_TYPE_INVALID ) ) - { - polkit_result_gtype = - dbus_g_type_get_struct ("GValueArray", - G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN, - dbus_g_type_get_map ("GHashTable", - G_TYPE_STRING, - G_TYPE_STRING), - G_TYPE_INVALID); - } -} - -/** - * xfsm_shutdown_helper_init_polkit_data: - * - * Check for Pokit and - * Init the neccarry Polkit data an GTypes. - * - **/ -static gboolean -xfsm_shutdown_helper_init_polkit_data (XfsmShutdownHelper *helper) -{ - GValue hash_elem = { 0 }; - guint64 start_time; - gint pid; - - helper->polkit_proxy = - dbus_g_proxy_new_for_name (helper->system_bus, - "org.freedesktop.PolicyKit1", - "/org/freedesktop/PolicyKit1/Authority", - "org.freedesktop.PolicyKit1.Authority"); - - if (!helper->polkit_proxy) - return FALSE; - - pid = getpid (); - - start_time = get_start_time_for_pid (pid); - - if (G_LIKELY (start_time != 0)) - { - GValue val = { 0 }, pid_val = { 0 }, start_time_val = { 0 }; - - helper->polkit_subject = g_value_array_new (2); - helper->polkit_subject_hash = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, NULL); - g_value_init (&val, G_TYPE_STRING); - g_value_set_string (&val, "unix-process"); - g_value_array_append (helper->polkit_subject, &val); - - g_value_unset (&val); - - g_value_init (&pid_val, G_TYPE_UINT); - g_value_set_uint (&pid_val, pid); - g_hash_table_insert (helper->polkit_subject_hash, g_strdup ("pid"), &pid_val); - - g_value_init (&start_time_val, G_TYPE_UINT64); - g_value_set_uint64 (&start_time_val, start_time); - g_hash_table_insert (helper->polkit_subject_hash, g_strdup ("start-time"), &start_time_val); - } - else - { - g_warning ("Unable to create Polkit subject"); - return FALSE; - } - - - g_value_init (&hash_elem, - dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)); - - g_value_set_static_boxed (&hash_elem, helper->polkit_subject_hash); - g_value_array_append (helper->polkit_subject, &hash_elem); - - /** - * Polkit details, will leave it empty. - **/ - helper->polkit_details = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - - return TRUE; -} -#endif /*ENABLE_POLKIT*/ - -/** - * xfsm_shutdown_helper_check_sudo: - * - * Check if we can use sudo backend. - * Method is called if HAL, upower, consolekit are missing - * or the session was compiled without those services. - * - **/ -static gboolean -xfsm_shutdown_helper_check_sudo (XfsmShutdownHelper *helper) -{ - struct rlimit rlp; - gchar buf[15]; - gint parent_pipe[2]; - gint child_pipe[2]; - gint result; - gint n; - - helper->sudo = g_find_program_in_path ("sudo"); - - if ( G_UNLIKELY (helper->sudo == NULL ) ) - { - g_warning ("Program 'sudo' was not found."); - return FALSE; - } - - result = pipe (parent_pipe); - - if (result < 0) - { - g_warning ("Unable to create parent pipe: %s", strerror (errno)); - return FALSE; - } - - result = pipe (child_pipe); - if (result < 0) - { - g_warning ("Unable to create child pipe: %s", strerror (errno)); - goto error0; - } - - helper->pid = fork (); - - if (helper->pid < 0) - { - g_warning ("Unable to fork sudo helper: %s", strerror (errno)); - goto error1; - } - else if (helper->pid == 0) - { - /* setup signals */ - signal (SIGPIPE, SIG_IGN); - - /* setup environment */ - xfce_setenv ("LC_ALL", "C", TRUE); - xfce_setenv ("LANG", "C", TRUE); - xfce_setenv ("LANGUAGE", "C", TRUE); - - /* setup the 3 standard file handles */ - dup2 (child_pipe[0], STDIN_FILENO); - dup2 (parent_pipe[1], STDOUT_FILENO); - dup2 (parent_pipe[1], STDERR_FILENO); - - /* Close all other file handles */ - getrlimit (RLIMIT_NOFILE, &rlp); - for (n = 0; n < (gint) rlp.rlim_cur; ++n) - { - if (n != STDIN_FILENO && n != STDOUT_FILENO && n != STDERR_FILENO) - close (n); - } - - /* execute sudo with the helper */ - execl (helper->sudo, "sudo", "-H", "-S", "-p", - "XFSM_SUDO_PASS ", "--", XFSM_SHUTDOWN_HELPER_CMD, NULL); - _exit (127); - } - - close (parent_pipe[1]); - - /* read sudo/helper answer */ - n = read (parent_pipe[0], buf, 15); - if (n < 15) - { - g_warning ("Unable to read response from sudo helper: %s", - n < 0 ? strerror (errno) : "Unknown error"); - goto error1; - } - - helper->infile = fdopen (parent_pipe[0], "r"); - - if (helper->infile == NULL) - { - g_warning ("Unable to open parent pipe: %s", strerror (errno)); - goto error1; - } - - helper->outfile = fdopen (child_pipe[1], "w"); - - if (helper->outfile == NULL) - { - g_warning ("Unable to open child pipe: %s", strerror (errno)); - goto error2; - } - - if (memcmp (buf, "XFSM_SUDO_PASS ", 15) == 0) - { - helper->require_password = TRUE; - } - else if (memcmp (buf, "XFSM_SUDO_DONE ", 15) == 0) - { - helper->require_password = FALSE; - } - else - { - g_warning ("Got unexpected reply from sudo shutdown helper"); - goto error2; - } - - close (parent_pipe[1]); - close (child_pipe[0]); - - return TRUE; - -error2: - if (helper->infile != NULL) - { - fclose (helper->infile); - helper->infile = NULL; - } - - if (helper->outfile != NULL) - { - fclose (helper->outfile); - helper->outfile = NULL; - } - -error1: - close (child_pipe[0]); - close (child_pipe[1]); - -error0: - close (parent_pipe[0]); - close (parent_pipe[1]); - - return FALSE; -} - -#ifdef ENABLE_UPOWER -/** - * xfsm_shutdown_helper_get_power_props: - * - **/ -static GHashTable * -xfsm_shutdown_helper_get_power_props (XfsmShutdownHelper *helper, - const gchar *name, - const gchar *path, - const gchar *iface) -{ - DBusGProxy *proxy_prop; - GHashTable *props; - GType g_type_hash_map; - GError *error = NULL; - - proxy_prop = dbus_g_proxy_new_for_name (helper->system_bus, - name, - path, - DBUS_INTERFACE_PROPERTIES); - - if (!proxy_prop) - { - g_warning ("Unable to create proxy for %s", name); - return NULL; - } - - /* The Hash table is a pair of (strings, GValues) */ - g_type_hash_map = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE); - - dbus_g_proxy_call (proxy_prop, "GetAll", &error, - G_TYPE_STRING, iface, - G_TYPE_INVALID, - g_type_hash_map, &props, - G_TYPE_INVALID); - - g_object_unref (proxy_prop); - - if (error) - { - g_warning ("Method 'GetAll' failed : %s", error->message); - g_error_free (error); - return NULL; - } - - return props; -} - - -/** - * xfsm_shutdown_helper_check_devkit_upower: - * - * Check upower (formely devicekit-power) - * for hibernate and suspend availability. - * - * Returns: FALSE if failed to contact upower, TRUE otherwise. - **/ -static gboolean -xfsm_shutdown_helper_check_devkit_upower (XfsmShutdownHelper *helper) -{ - /** - * Get the properties on 'org.freedesktop.UPower' - * or 'org.freedesktop.DeviceKit.Power' - * - * DaemonVersion 's' - * CanSuspend' 'b' - * CanHibernate' 'b' - * OnBattery' 'b' - * OnLowBattery' 'b' - * LidIsClosed' 'b' - * LidIsPresent' 'b' - **/ - - GHashTable *props; - GValue *value; - const gchar *name, *path, *iface; - - /* Check for upower first */ - name = "org.freedesktop.UPower"; - path = "/org/freedesktop/UPower"; - iface = "org.freedesktop.UPower"; - - helper->devkit_is_upower = TRUE; - - props = xfsm_shutdown_helper_get_power_props (helper, - name, - path, - iface); - if (!props) - { - g_message ("UPower not found, trying DevKitPower"); - - name = "org.freedesktop.DeviceKit.Power"; - path = "/org/freedesktop/DeviceKit/Power"; - iface = "org.freedesktop.DeviceKit.Power"; - - helper->devkit_is_upower = FALSE; - - props = xfsm_shutdown_helper_get_power_props (helper, - name, - path, - iface); - if (!props) - { - g_message ("Devkit Power is not running or not installed"); - return FALSE; - } - } - - /*Get The CanSuspend bit*/ - value = g_hash_table_lookup (props, "CanSuspend"); - - if (G_LIKELY (value)) - { - helper->can_suspend = g_value_get_boolean (value); - } - else - { - g_warning ("No 'CanSuspend' property"); - } - - /*Get the CanHibernate bit*/ - value = g_hash_table_lookup (props, "CanHibernate"); - - if (G_LIKELY (value)) - { - helper->can_hibernate = g_value_get_boolean (value); - } - else - { - g_warning ("No 'CanHibernate' property"); - } - - g_hash_table_destroy (props); - - return TRUE; -} -#endif /*ENABLE_UPOWER*/ - - -/** - * xfsm_shutdown_helper_check_console_kit: - * - * Check Consolekit for methods: - * Stop (Shutdown), Restart. - **/ -#ifdef ENABLE_CONSOLE_KIT -static gboolean -xfsm_shutdown_helper_check_console_kit (XfsmShutdownHelper *helper) -{ - DBusGProxy *proxy; - GError *error = NULL; - gboolean ret; - - proxy = dbus_g_proxy_new_for_name (helper->system_bus, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager"); - - if (!proxy) - { - g_warning ("Failed to create proxy for 'org.freedesktop.ConsoleKit'"); - return FALSE; - } - - ret = dbus_g_proxy_call (proxy, "CanStop", &error, - G_TYPE_INVALID, - G_TYPE_BOOLEAN, &helper->can_shutdown, - G_TYPE_INVALID); - - if (error) - { - g_warning ("'CanStop' method failed : %s", error->message); - g_error_free (error); - goto out; - } - - dbus_g_proxy_call (proxy, "CanRestart", &error, - G_TYPE_INVALID, - G_TYPE_BOOLEAN, &helper->can_restart, - G_TYPE_INVALID); - - if (error) - { - g_warning ("'CanRestart' method failed : %s", error->message); - g_error_free (error); - goto out; - } - - ret = TRUE; - - out: - - g_object_unref (proxy); - - return ret; -} -#endif /*ENABLE_CONSOLE_KIT*/ - - -/** - * xfsm_shutdown_helper_check_hal: - * - * Check if HAL is running and for its PowerManagement bits - * - **/ -#ifdef ENABLE_HAL -static gboolean -xfsm_shutdown_helper_check_hal (XfsmShutdownHelper *helper) -{ - DBusGProxy *proxy_power; - DBusGProxy *proxy_device; - GError *error = NULL; - gboolean ret = FALSE; - - proxy_power = - dbus_g_proxy_new_for_name (helper->system_bus, - "org.freedesktop.Hal", - "/org/freedesktop/Hal/devices/computer", - "org.freedesktop.Hal.Device.SystemPowerManagement"); - - if (!proxy_power) - { - g_warning ("Failed to create proxy for 'org.freedesktop.Hal' "); - return FALSE; - } - - dbus_g_proxy_call (proxy_power, "JustToCheckUserPermission", &error, - G_TYPE_INVALID, - G_TYPE_INVALID); - - g_object_unref (proxy_power); - - if (G_LIKELY (error)) - { - /* The message passed dbus permission check? */ - if ( !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_UNKNOWN_METHOD) ) - { - g_error_free (error); - return FALSE; - } - - g_error_free (error); - error = NULL; - } - else - { - /*Something went wrong with HAL*/ - return FALSE; - } - - /* - * Message raised DBUS_GERROR_UNKNOWN_METHOD, so it reached HAL, - * we can consider thatn HAL allows us to use its power management interface - */ - helper->auth_shutdown = TRUE; - helper->auth_restart = TRUE; - helper->auth_suspend = TRUE; - helper->auth_hibernate = TRUE; - /* HAL doesn't have can_shutdown and can_reboot bits since it can always - shutdown and reboot the system */ - helper->can_shutdown = TRUE; - helper->can_restart = TRUE; - - /*Check to see is the system can_hibernate and can_suspend*/ - proxy_device = dbus_g_proxy_new_for_name (helper->system_bus, - "org.freedesktop.Hal", - "/org/freedesktop/Hal/devices/computer", - "org.freedesktop.Hal.Device"); - - if (!proxy_device) - return FALSE; - - dbus_g_proxy_call (proxy_device, "GetPropertyBoolean", &error, - G_TYPE_STRING, "power_management.can_hibernate", - G_TYPE_INVALID, - G_TYPE_BOOLEAN, &helper->can_hibernate, - G_TYPE_INVALID); - - if (error) - { - g_warning ("Method 'GetPropertyBoolean' failed : %s", error->message); - g_error_free (error); - goto out; - } - - dbus_g_proxy_call (proxy_device, "GetPropertyBoolean", &error, - G_TYPE_STRING, "power_management.can_suspend", - G_TYPE_INVALID, - G_TYPE_BOOLEAN, &helper->can_suspend, - G_TYPE_INVALID); - - if (error) - { - g_warning ("Method 'GetPropertyBoolean' failed : %s", error->message); - g_error_free (error); - goto out; - } - - ret = TRUE; - - out: - - g_object_unref (proxy_device); - - return ret; -} -#endif /*ENABLE_HAL*/ - -/** - * xfsm_shutdown_helper_check_polkit_authorization: - * - **/ -#ifdef ENABLE_POLKIT -static gboolean -xfsm_shutdown_helper_check_authorization (XfsmShutdownHelper *helper, - const gchar *action_id) -{ - GValueArray *result; - GValue result_val = { 0 }; - GError *error = NULL; - gboolean is_authorized = FALSE; - gboolean ret; - - /** - * <method name="CheckAuthorization"> - * <arg type="(sa{sv})" name="subject" direction="in"/> - * <arg type="s" name="action_id" direction="in"/> - * <arg type="a{ss}" name="details" direction="in"/> - * <arg type="u" name="flags" direction="in"/> - * <arg type="s" name="cancellation_id" direction="in"/> - * <arg type="(bba{ss})" name="result" direction="out"/> - * </method> - * - **/ - - g_return_val_if_fail (helper->polkit_proxy != NULL, FALSE); - g_return_val_if_fail (helper->polkit_subject, FALSE); - g_return_val_if_fail (helper->polkit_details, FALSE); - - /* Initialized DBus GTypes */ - init_dbus_gtypes (); - - result = g_value_array_new (0); - - ret = dbus_g_proxy_call (helper->polkit_proxy, "CheckAuthorization", &error, - polkit_subject_gtype, helper->polkit_subject, - G_TYPE_STRING, action_id, - polkit_details_gtype, helper->polkit_details, - G_TYPE_UINT, 0, - G_TYPE_STRING, NULL, - G_TYPE_INVALID, - polkit_result_gtype, &result, - G_TYPE_INVALID); - - if (G_LIKELY (ret)) - { - g_value_init (&result_val, polkit_result_gtype); - g_value_set_static_boxed (&result_val, result); - - dbus_g_type_struct_get (&result_val, - 0, &is_authorized, - G_MAXUINT); - g_value_unset (&result_val); - } - else if (error) - { - g_warning ("'CheckAuthorization' failed : %s", error->message); - g_error_free (error); - } - - g_value_array_free (result); - return is_authorized; -} -#endif /*ENABLE_POLKIT*/ - -/** - *xfsm_shutdown_helper_check_backends: - * - * Try to check what is the best available backend to use - * Supported: ConsoleKit, HAL, upower and sudo. - * - **/ -static void -xfsm_shutdown_helper_check_backends (XfsmShutdownHelper *helper) -{ -#ifdef ENABLE_POLKIT - /*if polkit data was successfully initialized*/ - gboolean polkit_ok = FALSE; -#endif - -#ifdef ENABLE_UPOWER - /*Check upower (formely devicekit-power)*/ - if ( xfsm_shutdown_helper_check_devkit_upower (helper) ) - helper->sleep_backend = XFSM_SLEEP_BACKEND_UPOWER; -#endif /* ENABLE_UPOWER */ - -#ifdef ENABLE_CONSOLE_KIT - if ( xfsm_shutdown_helper_check_console_kit (helper) ) - { - helper->shutdown_backend = XFSM_SHUTDOWN_BACKEND_CONSOLE_KIT; - /*ConsoleKit doesn't use Polkit*/ - helper->auth_shutdown = helper->can_shutdown; - helper->auth_restart = helper->can_restart; - } -#endif - - if ( helper->sleep_backend == XFSM_SLEEP_BACKEND_UPOWER ) - { -#ifdef ENABLE_POLKIT - - polkit_ok = xfsm_shutdown_helper_init_polkit_data (helper); - - if (polkit_ok) - { - const gchar *action_hibernate, *action_suspend; - - if (helper->devkit_is_upower) - { - action_hibernate = "org.freedesktop.upower.hibernate"; - action_suspend = "org.freedesktop.upower.suspend"; - } - else - { - action_hibernate = "org.freedesktop.devicekit.power.hibernate"; - action_suspend = "org.freedesktop.devicekit.power.suspend"; - } - - helper->auth_hibernate = - xfsm_shutdown_helper_check_authorization (helper, action_hibernate); - - helper->auth_suspend = - xfsm_shutdown_helper_check_authorization (helper, action_suspend); - } - else - { - helper->auth_hibernate = TRUE; - helper->auth_suspend = TRUE; - } -#else - helper->auth_hibernate = TRUE; - helper->auth_suspend = TRUE; -#endif /* ENABLE_POLKIT */ - } - - /* - * Use HAL just as a fallback. - */ -#ifdef ENABLE_HAL - if (helper->sleep_backend == XFSM_SLEEP_BACKEND_NOT_SUPPORTED || - helper->shutdown_backend == XFSM_SHUTDOWN_BACKEND_NOT_SUPPORTED) - { - if (xfsm_shutdown_helper_check_hal (helper)) - { - if (helper->shutdown_backend == XFSM_SHUTDOWN_BACKEND_NOT_SUPPORTED) - helper->shutdown_backend = XFSM_SHUTDOWN_BACKEND_HAL; - - if (helper->sleep_backend == XFSM_SLEEP_BACKEND_NOT_SUPPORTED) - helper->sleep_backend = XFSM_SLEEP_BACKEND_HAL; - } - } -#endif - - /* Fallback for sudo */ - if (helper->shutdown_backend == XFSM_SHUTDOWN_BACKEND_NOT_SUPPORTED) - { - if (xfsm_shutdown_helper_check_sudo (helper) ) - { - helper->shutdown_backend = XFSM_SHUTDOWN_BACKEND_SUDO; - helper->can_shutdown = TRUE; - helper->can_restart = TRUE; - helper->auth_shutdown = TRUE; - helper->auth_restart = TRUE; - } - } - -#ifdef DEBUG - { - const gchar *shutdown_str[] = {"Shutdown not supported", - "Using ConsoleKit for shutdown", - "Using HAL for shutdown", - "Using Sudo for shutdown", - NULL}; - - const gchar *sleep_str[] = {"Sleep not supported", - "Using UPower for sleep", - "Using HAL for sleep", - "Using Sudo for sleep", - NULL}; - - g_debug ("%s", shutdown_str[helper->shutdown_backend]); - g_debug ("%s", sleep_str[helper->sleep_backend]); - - g_debug ("can_shutdown=%d can_restart=%d can_hibernate=%d can_suspend=%d", - helper->can_shutdown, helper->can_restart, - helper->can_hibernate, helper->can_suspend); - - g_debug ("auth_shutdown=%d auth_restart=%d auth_hibernate=%d auth_suspend=%d", - helper->auth_shutdown, helper->auth_restart, - helper->auth_hibernate, helper->auth_suspend); - } -#endif - -#ifdef ENABLE_POLKIT - - if (polkit_ok) - { - g_hash_table_destroy (helper->polkit_details); - g_hash_table_destroy (helper->polkit_subject_hash); - g_value_array_free (helper->polkit_subject); - } - -#endif - -} - -static void -xfsm_shutdown_helper_class_init (XfsmShutdownHelperClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = xfsm_shutdown_helper_finalize; - - object_class->get_property = xfsm_shutdown_helper_get_property; - object_class->set_property = xfsm_shutdown_helper_set_property; - - /** - * XfsmShutdownHelper::authorized-to-shutdown - * - * Whether the user is allowed to preform shutdown. - **/ - g_object_class_install_property (object_class, - PROP_AUTHORIZED_TO_SHUTDOWN, - g_param_spec_boolean ("authorized-to-shutdown", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - - /** - * XfsmShutdownHelper::authorized-to-reboot - * - * Whether the user is allowed to preform reboot. - **/ - g_object_class_install_property (object_class, - PROP_AUTHORIZED_TO_RESTART, - g_param_spec_boolean ("authorized-to-restart", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - - /** - * XfsmShutdownHelper::authorized-to-suspend - * - * Whether the user is allowed to preform suspend. - **/ - g_object_class_install_property (object_class, - PROP_AUTHORIZED_TO_SUSPEND, - g_param_spec_boolean ("authorized-to-suspend", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - - /** - * XfsmShutdownHelper::authorized-to-hibernate - * - * Whether the user is allowed to preform hibernate. - **/ - g_object_class_install_property (object_class, - PROP_AUTHORIZED_TO_HIBERNATE, - g_param_spec_boolean ("authorized-to-hibernate", - NULL, NULL, FALSE, - G_PARAM_READABLE)); - - /** - * XfsmShutdownHelper::can-shutdown - * - * Whether the system can do shutdown. - **/ - g_object_class_install_property (object_class, - PROP_CAN_SHUTDOWN, - g_param_spec_boolean ("can-shutdown", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - - /** - * XfsmShutdownHelper::can-restart - * - * Whether the system can do restart. - **/ - g_object_class_install_property (object_class, - PROP_CAN_RESTART, - g_param_spec_boolean ("can-restart", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - - /** - * XfsmShutdownHelper::can-suspend - * - * Whether the system can do suspend. - **/ - g_object_class_install_property (object_class, - PROP_CAN_SUSPEND, - g_param_spec_boolean ("can-suspend", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - /** - * XfsmShutdownHelper::can-hibernate - * - * Whether the system can do hibernate. - **/ - g_object_class_install_property (object_class, - PROP_CAN_HIBERNATE, - g_param_spec_boolean ("can-hibernate", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - - /** - * XfsmShutdownHelper::user-can-shutdown - * - * Whether the user is allowed and the system can shutdown. - **/ - g_object_class_install_property (object_class, - PROP_USER_CAN_SHUTDOWN, - g_param_spec_boolean ("user-can-shutdown", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - - /** - * XfsmShutdownHelper::user-can-restart - * - * Whether the user is allowed and the system can restart. - **/ - g_object_class_install_property (object_class, - PROP_USER_CAN_RESTART, - g_param_spec_boolean ("user-can-restart", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - - /** - * XfsmShutdownHelper::user-can-suspend - * - * Whether the user is allowed and the system can suspend. - **/ - g_object_class_install_property (object_class, - PROP_USER_CAN_SUSPEND, - g_param_spec_boolean ("user-can-suspend", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - /** - * XfsmShutdownHelper::user-can-hibernate - * - * Whether the user is allowed and the system can hibernate. - **/ - g_object_class_install_property (object_class, - PROP_USER_CAN_HIBERNATE, - g_param_spec_boolean ("user-can-hibernate", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - - /** - * XfsmShutdownHelper::require-password - * - * Whether the shutdown operation requires a password to - * pass to sudo. - **/ - g_object_class_install_property (object_class, - PROP_REQUIRE_PASSWORD, - g_param_spec_boolean ("require-password", - NULL, NULL, - FALSE, - G_PARAM_READABLE)); - -} - -static void -xfsm_shutdown_helper_init (XfsmShutdownHelper *helper) -{ - GError *error = NULL; - -#ifdef ENABLE_POLKIT - helper->polkit_proxy = NULL; - helper->polkit_subject = NULL; - helper->polkit_details = NULL; - helper->polkit_subject_hash = NULL; -#endif - - helper->sudo = NULL; - helper->infile = NULL; - helper->outfile = NULL; - helper->pid = 0; - helper->require_password = FALSE; - - helper->sleep_backend = XFSM_SLEEP_BACKEND_NOT_SUPPORTED; - helper->shutdown_backend = XFSM_SHUTDOWN_BACKEND_NOT_SUPPORTED; - - helper->auth_shutdown = FALSE; - helper->auth_restart = FALSE; - helper->auth_suspend = FALSE; - helper->auth_hibernate = FALSE; - helper->can_shutdown = FALSE; - helper->can_restart = FALSE; - helper->can_suspend = FALSE; - helper->can_hibernate = FALSE; - - helper->system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); - - if (G_LIKELY (helper->system_bus)) - { - xfsm_shutdown_helper_check_backends (helper); - } - else - { - g_warning ("Failed to connect to the system bus : %s", error->message); - g_error_free (error); - - /* Unable to connect to the system bus, just try sudo */ - if (xfsm_shutdown_helper_check_sudo (helper)) - { - helper->shutdown_backend = XFSM_SHUTDOWN_BACKEND_SUDO; - - helper->can_shutdown = TRUE; - helper->can_restart = TRUE; - helper->auth_shutdown = TRUE; - helper->auth_restart = TRUE; - } - } -} - -static void xfsm_shutdown_helper_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -} - -static void xfsm_shutdown_helper_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - XfsmShutdownHelper *helper; - - helper = XFSM_SHUTDOWN_HELPER (object); - - switch (prop_id) - { - case PROP_AUTHORIZED_TO_SHUTDOWN: - g_value_set_boolean (value, helper->auth_shutdown); - break; - case PROP_AUTHORIZED_TO_RESTART: - g_value_set_boolean (value, helper->auth_restart); - break; - case PROP_AUTHORIZED_TO_SUSPEND: - g_value_set_boolean (value, helper->auth_suspend); - break; - case PROP_AUTHORIZED_TO_HIBERNATE: - g_value_set_boolean (value, helper->auth_hibernate); - break; - case PROP_CAN_SUSPEND: - g_value_set_boolean (value, helper->can_suspend); - break; - case PROP_CAN_HIBERNATE: - g_value_set_boolean (value, helper->can_hibernate); - break; - case PROP_CAN_RESTART: - g_value_set_boolean (value, helper->can_restart); - break; - case PROP_CAN_SHUTDOWN: - g_value_set_boolean (value, helper->can_shutdown); - break; - case PROP_USER_CAN_SUSPEND: - g_value_set_boolean (value, helper->can_suspend && helper->auth_suspend); - break; - case PROP_USER_CAN_HIBERNATE: - g_value_set_boolean (value, helper->can_hibernate && helper->auth_hibernate); - break; - case PROP_USER_CAN_RESTART: - g_value_set_boolean (value, helper->can_restart && helper->auth_restart); - break; - case PROP_USER_CAN_SHUTDOWN: - g_value_set_boolean (value, helper->can_shutdown && helper->auth_shutdown); - break; - case PROP_REQUIRE_PASSWORD: - g_value_set_boolean (value, helper->require_password); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -xfsm_shutdown_helper_finalize (GObject *object) -{ - XfsmShutdownHelper *helper; - gint status; - - helper = XFSM_SHUTDOWN_HELPER (object); - -#ifdef ENABLE_POLKIT - if (helper->polkit_proxy) - g_object_unref (helper->polkit_proxy); -#endif - - if (helper->system_bus) - dbus_g_connection_unref (helper->system_bus); - - if (helper->infile != NULL) - fclose (helper->infile); - - if (helper->outfile != NULL) - fclose (helper->outfile); - - if (helper->pid > 0) - waitpid (helper->pid, &status, 0); - - g_free (helper->sudo); - - G_OBJECT_CLASS (xfsm_shutdown_helper_parent_class)->finalize (object); -} - -/** - * xfsm_shutdown_helper_upower_sleep: - * @helper: a #XfsmShutdownHelper, - * @action: 'Hibernate' or 'Suspend' - * @error: a #GError - * - **/ -#ifdef ENABLE_UPOWER -static gboolean -xfsm_shutdown_helper_upower_sleep (XfsmShutdownHelper *helper, - const gchar *action, - GError **error) -{ - DBusGProxy *proxy; - GError *error_local = NULL; - const gchar *name, *path, *iface; - gboolean ret; - - if (helper->devkit_is_upower) - { - name = "org.freedesktop.UPower"; - path = "/org/freedesktop/UPower"; - iface = "org.freedesktop.UPower"; - } - else - { - name = "org.freedesktop.DeviceKit.Power"; - path = "/org/freedesktop/DeviceKit/Power"; - iface = "org.freedesktop.DeviceKit.Power"; - } - - g_message (G_STRLOC ": Using %s to %s", name, action); - - proxy = dbus_g_proxy_new_for_name_owner (helper->system_bus, - name, - path, - iface, - &error_local); - - if (!proxy) - { - g_warning ("Failed to create proxy for %s : %s", name, error_local->message); - g_set_error (error, 1, 0, "%s", error_local->message); - g_error_free (error_local); - return FALSE; - } - - ret = dbus_g_proxy_call (proxy, action, &error_local, - G_TYPE_INVALID, - G_TYPE_INVALID); - - g_object_unref (proxy); - - if (!ret) - { - /* DBus timeout?*/ - if (g_error_matches (error_local, DBUS_GERROR, DBUS_GERROR_NO_REPLY)) - { - g_error_free (error_local); - return TRUE; - } - else - { - g_set_error (error, 1, 0, "%s", error_local->message); - g_error_free (error_local); - return FALSE; - } - } - - return TRUE; -} -#endif /*ENABLE_UPOWER*/ - -/** - * xfsm_shutdown_helper_console_kit_shutdown: - * @helper: a #XfsmShutdownHelper, - * @action: 'Stop' for shutdown and 'Restart' for reboot. - * @error: a #GError - * - **/ -#ifdef ENABLE_CONSOLE_KIT -static gboolean -xfsm_shutdown_helper_console_kit_shutdown (XfsmShutdownHelper *helper, - const gchar *action, - GError **error) -{ - DBusGProxy *proxy; - GError *error_local = NULL; - gboolean ret; - - g_message (G_STRLOC ": Using ConsoleKit to %s", action); - - proxy = dbus_g_proxy_new_for_name_owner (helper->system_bus, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - &error_local); - - if (!proxy) - { - g_warning ("Failed to create proxy for 'org.freedesktop.ConsoleKit' : %s", error_local->message); - g_set_error (error, 1, 0, "%s", error_local->message); - g_error_free (error_local); - return FALSE; - } - - ret = dbus_g_proxy_call (proxy, action, &error_local, - G_TYPE_INVALID, - G_TYPE_INVALID); - - g_object_unref (proxy); - - if (!ret) - { - g_set_error (error, 1, 0, "%s", error_local->message); - g_error_free (error_local); - return FALSE; - } - - return TRUE; -} -#endif /*ENABLE_CONSOLE_KIT*/ - -/** - * xfsm_shutdown_helper_hal_send: - * @helper: a #XfsmShutdownHelper, - * @action: 'Reboot' 'Shutdown' 'Hibernate' 'Suspend' - * @error: a #GError - * - **/ -#ifdef ENABLE_HAL -static gboolean -xfsm_shutdown_helper_hal_send (XfsmShutdownHelper *helper, - const gchar *action, - GError **error) -{ - DBusGProxy *proxy; - GError *error_local = NULL; - gboolean ret; - gint return_code; - - g_message (G_STRLOC ": Using ConsoleKit to %s", action); - - proxy = dbus_g_proxy_new_for_name_owner (helper->system_bus, - "org.freedesktop.Hal", - "/org/freedesktop/Hal/devices/computer", - "org.freedesktop.Hal.Device.SystemPowerManagement", - &error_local); - if (!proxy) - { - g_warning ("Failed to create proxy for 'org.freedesktop.Hal' : %s", error_local->message); - g_set_error (error, 1, 0, "%s", error_local->message); - g_error_free (error_local); - return FALSE; - } - - if (!g_strcmp0 (action, "Suspend")) - { - gint seconds = 0; - ret = dbus_g_proxy_call (proxy, action, &error_local, - G_TYPE_INT, seconds, - G_TYPE_INVALID, - G_TYPE_INT, &return_code, - G_TYPE_INVALID); - } - else - { - ret = dbus_g_proxy_call (proxy, action, &error_local, - G_TYPE_INVALID, - G_TYPE_INT, &return_code, - G_TYPE_INVALID); - } - - g_object_unref (proxy); - - if (!ret) - { - /* A D-Bus timeout? */ - if (g_error_matches (error_local, DBUS_GERROR, DBUS_GERROR_NO_REPLY)) - { - g_error_free (error_local); - return TRUE; - } - else - { - g_set_error (error, 1, 0, "%s", error_local->message); - g_error_free (error_local); - return FALSE; - } - } - - return TRUE; -} -#endif /*ENABLE_HAL*/ - -/** - * xfsm_shutdown_helper_sudo_send: - * - * - **/ -static gboolean -xfsm_shutdown_helper_sudo_send (XfsmShutdownHelper *helper, - const gchar *action, - GError **error) -{ - gchar response[256]; - - fprintf (helper->outfile, "%s\n", action); - fflush (helper->outfile); - - g_message (G_STRLOC ": Using sudo to %s", action); - - if (ferror (helper->outfile)) - { - if (errno == EINTR) - { - /* probably succeeded but the helper got killed */ - return TRUE; - } - - g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), - _("Error sending command to shutdown helper: %s"), - strerror (errno)); - return FALSE; - } - - if (fgets (response, 256, helper->infile) == NULL) - { - if (errno == EINTR) - { - /* probably succeeded but the helper got killed */ - return TRUE; - } - - g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), - _("Error receiving response from shutdown helper: %s"), - strerror (errno)); - - return FALSE; - } - - if (strncmp (response, "SUCCEED", 7) != 0) - { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("Shutdown command failed")); - - return FALSE; - } - return TRUE; -} - -/** - * xfsm_shutdown_helper_new: - * - **/ -XfsmShutdownHelper * -xfsm_shutdown_helper_new (void) -{ - XfsmShutdownHelper *xfsm_shutdown_helper = NULL; - - xfsm_shutdown_helper = g_object_new (XFSM_TYPE_SHUTDOWN_HELPER, NULL); - - return xfsm_shutdown_helper; -} - -/** - * xfsm_shutdown_helper_send_password: - * - * Send password to sudo - * - **/ -gboolean xfsm_shutdown_helper_send_password (XfsmShutdownHelper *helper, const gchar *password) -{ - gssize result; - gchar buffer[1024]; - gsize failed; - gsize length; - gsize bytes; - gint fd; - - g_return_val_if_fail (password != NULL, FALSE); - g_return_val_if_fail (helper->shutdown_backend == XFSM_SHUTDOWN_BACKEND_SUDO, FALSE); - g_return_val_if_fail (helper->require_password, FALSE); - - g_snprintf (buffer, 1024, "%s\n", password); - length = strlen (buffer); - bytes = fwrite (buffer, 1, length, helper->outfile); - fflush (helper->outfile); - bzero (buffer, length); - - if (bytes != length) - { - fprintf (stderr, "Failed to write password (bytes=%lu, length=%lu)\n", (long)bytes, (long)length); - return FALSE; - } - - if (ferror (helper->outfile)) - { - fprintf (stderr, "Pipe error\n"); - return FALSE; - } - - fd = fileno (helper->infile); - - for (failed = length = 0;;) - { - result = read (fd, buffer + length, 256 - length); - - if (result < 0) - { - perror ("read"); - return FALSE; - } - else if (result == 0) - { - if (++failed > 20) - return FALSE; - continue; - } - else if (result + length >= 1024) - { - fprintf (stderr, "Too much output from sudo!\n"); - return FALSE; - } - - length += result; - buffer[length] = 0; - - if (length >= 15) - { - if (strncmp (buffer + (length - 15), "XFSM_SUDO_PASS ", 15) == 0) - { - return FALSE; - } - else if (strncmp (buffer + (length - 15), "XFSM_SUDO_DONE ", 15) == 0) - { - helper->require_password = FALSE; - break; - } - } - } - - return TRUE; -} - -/** - * xfsm_shutdown_helper_shutdown: - * - * - **/ -gboolean xfsm_shutdown_helper_shutdown (XfsmShutdownHelper *helper, GError **error) -{ - g_return_val_if_fail (!error || !*error, FALSE); - -#ifdef ENABLE_CONSOLE_KIT - if ( helper->shutdown_backend == XFSM_SHUTDOWN_BACKEND_CONSOLE_KIT ) - { - return xfsm_shutdown_helper_console_kit_shutdown (helper, "Stop", error); - } -#endif - -#ifdef ENABLE_HAL - if ( helper->shutdown_backend == XFSM_SHUTDOWN_BACKEND_HAL ) - { - return xfsm_shutdown_helper_hal_send (helper, "Shutdown", error); - } -#endif - - /*Use Sudo mode*/ - return xfsm_shutdown_helper_sudo_send (helper, "POWEROFF", error); - -} - -/** - * xfsm_shutdown_helper_restart: - * - * - **/ -gboolean xfsm_shutdown_helper_restart (XfsmShutdownHelper *helper, GError **error) -{ - g_return_val_if_fail (!error || !*error, FALSE); - -#ifdef ENABLE_CONSOLE_KIT - if ( helper->shutdown_backend == XFSM_SHUTDOWN_BACKEND_CONSOLE_KIT ) - { - return xfsm_shutdown_helper_console_kit_shutdown (helper, "Restart", error); - } -#endif - -#ifdef ENABLE_HAL - if ( helper->shutdown_backend == XFSM_SHUTDOWN_BACKEND_HAL ) - { - return xfsm_shutdown_helper_hal_send (helper, "Reboot", error); - } -#endif - - return xfsm_shutdown_helper_sudo_send (helper, "REBOOT", error); - -} - -/** - * xfsm_shutdown_helper_suspend: - * - **/ -gboolean xfsm_shutdown_helper_suspend (XfsmShutdownHelper *helper, GError **error) -{ - g_return_val_if_fail (!error || !*error, FALSE); - -#ifdef ENABLE_UPOWER - if ( helper->sleep_backend == XFSM_SLEEP_BACKEND_UPOWER ) - { - return xfsm_shutdown_helper_upower_sleep (helper, "Suspend", error); - } -#endif - -#ifdef ENABLE_HAL - if ( helper->sleep_backend == XFSM_SLEEP_BACKEND_HAL ) - { - return xfsm_shutdown_helper_hal_send (helper, "Suspend", error); - } -#endif - - g_set_error (error, 1, 0, "%s", _("Suspend failed, no backend supported")); - - return FALSE; -} - -/** - * xfsm_shutdown_helper_hibernate: - * - **/ -gboolean xfsm_shutdown_helper_hibernate (XfsmShutdownHelper *helper, GError **error) -{ - g_return_val_if_fail (!error || !*error, FALSE); - -#ifdef ENABLE_UPOWER - if ( helper->sleep_backend == XFSM_SLEEP_BACKEND_UPOWER ) - { - return xfsm_shutdown_helper_upower_sleep (helper, "Hibernate", error); - } -#endif - -#ifdef ENABLE_HAL - if ( helper->sleep_backend == XFSM_SLEEP_BACKEND_HAL ) - { - return xfsm_shutdown_helper_hal_send (helper, "Hibernate", error); - } -#endif - - g_set_error (error, 1, 0, "%s", _("Hibernate failed, no backend supported")); - - return FALSE; -} - -/** - * xfsm_shutdown_helper_send_command: - * - **/ -gboolean xfsm_shutdown_helper_send_command (XfsmShutdownHelper *helper, - XfsmShutdownType shutdown_type, - GError **error) -{ - g_return_val_if_fail (!error || !*error, FALSE); - - switch (shutdown_type) - { - case XFSM_SHUTDOWN_HALT: - return xfsm_shutdown_helper_shutdown (helper, error); - case XFSM_SHUTDOWN_REBOOT: - return xfsm_shutdown_helper_restart (helper, error); - case XFSM_SHUTDOWN_HIBERNATE: - return xfsm_shutdown_helper_hibernate (helper, error); - case XFSM_SHUTDOWN_SUSPEND: - return xfsm_shutdown_helper_suspend (helper, error); - default: - g_warn_if_reached (); - break; - } - - g_set_error (error, 1, 0, "%s", _("Shutdown Command not found")); - - return FALSE; -} diff --git a/xfce4-session/xfsm-shutdown-helper.h b/xfce4-session/xfsm-shutdown-helper.h deleted file mode 100644 index 4bacbe82..00000000 --- a/xfce4-session/xfsm-shutdown-helper.h +++ /dev/null @@ -1,64 +0,0 @@ -/* $Id$ */ -/*- - * Copyright (c) 2003-2006 Benedikt Meurer <benny@xfce.org> - * Copyright (c) 2010 Ali Abdallah <aliov@xfce.org> - * All rights reserved. - * - * 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, 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., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. - */ - -#ifndef __XFSM_SHUTDOWN_HELPER_H -#define __XFSM_SHUTDOWN_HELPER_H - -#include <glib-object.h> -#include <xfce4-session/xfsm-global.h> - -G_BEGIN_DECLS - -#define XFSM_TYPE_SHUTDOWN_HELPER (xfsm_shutdown_helper_get_type () ) -#define XFSM_SHUTDOWN_HELPER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), XFSM_TYPE_SHUTDOWN_HELPER, XfsmShutdownHelper)) -#define XFSM_IS_SHUTDOWN_HELPER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), XFSM_TYPE_SHUTDOWN_HELPER)) - -typedef struct _XfsmShutdownHelperClass XfsmShutdownHelperClass; -typedef struct _XfsmShutdownHelper XfsmShutdownHelper; - -GType xfsm_shutdown_helper_get_type (void) G_GNUC_CONST; - -XfsmShutdownHelper *xfsm_shutdown_helper_new (void); - -gboolean xfsm_shutdown_helper_send_password (XfsmShutdownHelper *helper, - const gchar *password); - -gboolean xfsm_shutdown_helper_shutdown (XfsmShutdownHelper *helper, - GError **error); - -gboolean xfsm_shutdown_helper_restart (XfsmShutdownHelper *helper, - GError **error); - -gboolean xfsm_shutdown_helper_suspend (XfsmShutdownHelper *helper, - GError **error); - -gboolean xfsm_shutdown_helper_hibernate (XfsmShutdownHelper *helper, - GError **error); - -gboolean xfsm_shutdown_helper_send_command (XfsmShutdownHelper *helper, - XfsmShutdownType shutdown_type, - GError **error); - - -G_END_DECLS - -#endif /* __XFSM_SHUTDOWN_HELPER_H */ diff --git a/xfce4-session/xfsm-shutdown.c b/xfce4-session/xfsm-shutdown.c index 9246c010..2436dcd1 100644 --- a/xfce4-session/xfsm-shutdown.c +++ b/xfce4-session/xfsm-shutdown.c @@ -1,6 +1,6 @@ -/* $Id$ */ /*- * Copyright (c) 2003-2004 Benedikt Meurer <benny@xfce.org> + * Copyright (c) 2011 Nick Schermer <nick@xfce.org> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -36,7 +36,19 @@ #ifdef HAVE_STRING_H #include <string.h> #endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> #include <libxfce4util/libxfce4util.h> #include <gtk/gtk.h> @@ -48,60 +60,682 @@ #include <xfce4-session/xfsm-fadeout.h> #include <xfce4-session/xfsm-global.h> #include <xfce4-session/xfsm-legacy.h> -#include <xfce4-session/xfsm-shutdown-helper.h> +#include <xfce4-session/xfsm-consolekit.h> + + + +static void xfsm_shutdown_finalize (GObject *object); +static void xfsm_shutdown_sudo_free (XfsmShutdown *shutdown); + + + +struct _XfsmShutdownClass +{ + GObjectClass __parent__; +}; + +typedef enum +{ + SUDO_NOT_INITIAZED, + SUDO_AVAILABLE, + SUDO_FAILED +} +HelperState; + +struct _XfsmShutdown +{ + GObject __parent__; + + XfsmConsolekit *consolekit; + + /* sudo helper */ + HelperState helper_state; + pid_t helper_pid; + FILE *helper_infile; + FILE *helper_outfile; + guint helper_watchid; + gboolean helper_require_password; +}; + + + +G_DEFINE_TYPE (XfsmShutdown, xfsm_shutdown, G_TYPE_OBJECT) + + + +static void +xfsm_shutdown_class_init (XfsmShutdownClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = xfsm_shutdown_finalize; +} + + + +static void +xfsm_shutdown_init (XfsmShutdown *shutdown) +{ + shutdown->consolekit = xfsm_consolekit_get (); + shutdown->helper_state = SUDO_NOT_INITIAZED; + shutdown->helper_require_password = FALSE; +} + + + +static void +xfsm_shutdown_finalize (GObject *object) +{ + XfsmShutdown *shutdown = XFSM_SHUTDOWN (object); + + g_object_unref (G_OBJECT (shutdown->consolekit)); + + /* close down helper */ + xfsm_shutdown_sudo_free (shutdown); + + (*G_OBJECT_CLASS (xfsm_shutdown_parent_class)->finalize) (object); +} + + + +static void +xfsm_shutdown_sudo_free (XfsmShutdown *shutdown) +{ + gint status; + + /* close down helper */ + if (shutdown->helper_infile != NULL) + { + fclose (shutdown->helper_infile); + shutdown->helper_infile = NULL; + } + + if (shutdown->helper_outfile != NULL) + { + fclose (shutdown->helper_outfile); + shutdown->helper_outfile = NULL; + } + + if (shutdown->helper_watchid > 0) + { + g_source_remove (shutdown->helper_watchid); + shutdown->helper_watchid = 0; + } + + if (shutdown->helper_pid > 0) + { + waitpid (shutdown->helper_pid, &status, 0); + shutdown->helper_pid = 0; + } + + /* reset state */ + shutdown->helper_state = SUDO_NOT_INITIAZED; +} + + + +static void +xfsm_shutdown_sudo_childwatch (GPid pid, + gint status, + gpointer data) +{ + /* close down sudo stuff */ + xfsm_shutdown_sudo_free (XFSM_SHUTDOWN (data)); +} + + + +static gboolean +xfsm_shutdown_sudo_init (XfsmShutdown *shutdown, + GError **error) +{ + gchar *cmd; + struct rlimit rlp; + gchar buf[15]; + gint parent_pipe[2]; + gint child_pipe[2]; + gint n; + + /* return state if we succeeded */ + if (shutdown->helper_state != SUDO_NOT_INITIAZED) + return shutdown->helper_state == SUDO_AVAILABLE; + + g_return_val_if_fail (shutdown->helper_infile == NULL, FALSE); + g_return_val_if_fail (shutdown->helper_outfile == NULL, FALSE); + g_return_val_if_fail (shutdown->helper_watchid == 0, FALSE); + g_return_val_if_fail (shutdown->helper_pid == 0, FALSE); + + /* assume it won't work for now */ + shutdown->helper_state = SUDO_FAILED; + + cmd = g_find_program_in_path ("sudo"); + if (G_UNLIKELY (cmd == NULL)) + { + g_set_error_literal (error, 1, 0, + "The program \"sudo\" was not found"); + return FALSE; + } + + if (pipe (parent_pipe) == -1) + { + g_set_error (error, 1, 0, + "Unable to create parent pipe: %s", + strerror (errno)); + goto err0; + } + + if (pipe (child_pipe) == -1) + { + g_set_error (error, 1, 0, + "Unable to create child pipe: %s", + strerror (errno)); + goto err1; + } + + shutdown->helper_pid = fork (); + if (shutdown->helper_pid < 0) + { + g_set_error (error, 1, 0, + "Unable to fork sudo helper: %s", + strerror (errno)); + goto err2; + } + else if (shutdown->helper_pid == 0) + { + /* setup signals */ + signal (SIGPIPE, SIG_IGN); + + /* setup environment */ + xfce_setenv ("LC_ALL", "C", TRUE); + xfce_setenv ("LANG", "C", TRUE); + xfce_setenv ("LANGUAGE", "C", TRUE); + + /* setup the 3 standard file handles */ + dup2 (child_pipe[0], STDIN_FILENO); + dup2 (parent_pipe[1], STDOUT_FILENO); + dup2 (parent_pipe[1], STDERR_FILENO); + + /* close all other file handles */ + getrlimit (RLIMIT_NOFILE, &rlp); + for (n = 0; n < (gint) rlp.rlim_cur; ++n) + { + if (n != STDIN_FILENO && n != STDOUT_FILENO && n != STDERR_FILENO) + close (n); + } + + /* execute sudo with the helper */ + execl (cmd, "sudo", "-H", "-S", "-p", + "XFSM_SUDO_PASS ", "--", + XFSM_SHUTDOWN_HELPER_CMD, NULL); + + g_free (cmd); + cmd = NULL; + + _exit (127); + } + else + { + /* watch the sudo helper */ + shutdown->helper_watchid = g_child_watch_add (shutdown->helper_pid, + xfsm_shutdown_sudo_childwatch, + shutdown); + } + + /* read sudo/helper answer */ + n = read (parent_pipe[0], buf, sizeof (buf)); + if (n < 15) + { + g_set_error (error, 1, 0, + "Unable to read response from sudo helper: %s", + n < 0 ? strerror (errno) : "Unknown error"); + goto err2; + } + + /* open pipe to receive replies from sudo */ + shutdown->helper_infile = fdopen (parent_pipe[0], "r"); + if (shutdown->helper_infile == NULL) + { + g_set_error (error, 1, 0, + "Unable to open parent pipe: %s", + strerror (errno)); + goto err2; + } + close (parent_pipe[1]); + + /* open pipe to send passwords to sudo */ + shutdown->helper_outfile = fdopen (child_pipe[1], "w"); + if (shutdown->helper_outfile == NULL) + { + g_set_error (error, 1, 0, + "Unable to open parent pipe: %s", + strerror (errno)); + goto err2; + } + close (child_pipe[0]); + + /* check if NOPASSWD is set in /etc/sudoers */ + if (memcmp (buf, "XFSM_SUDO_PASS ", 15) == 0) + { + shutdown->helper_require_password = TRUE; + } + else if (memcmp (buf, "XFSM_SUDO_DONE ", 15) == 0) + { + shutdown->helper_require_password = FALSE; + } + else + { + g_set_error (error, 1, 0, + "Got unexpected reply from sudo shutdown helper"); + goto err2; + } + + /* if we try again */ + shutdown->helper_state = SUDO_AVAILABLE; + + return TRUE; + +err2: + xfsm_shutdown_sudo_free (shutdown); + + close (child_pipe[0]); + close (child_pipe[1]); + +err1: + close (parent_pipe[0]); + close (parent_pipe[1]); + +err0: + g_free (cmd); + + shutdown->helper_pid = 0; + + return FALSE; +} + + + +static gboolean +xfsm_shutdown_sudo_try_action (XfsmShutdown *shutdown, + XfsmShutdownType type, + GError **error) +{ + const gchar *action; + gchar reply[256]; + + g_return_val_if_fail (shutdown->helper_state == SUDO_AVAILABLE, FALSE); + g_return_val_if_fail (shutdown->helper_outfile != NULL, FALSE); + g_return_val_if_fail (shutdown->helper_infile != NULL, FALSE); + g_return_val_if_fail (type == XFSM_SHUTDOWN_SHUTDOWN + || type == XFSM_SHUTDOWN_RESTART, FALSE); -gint -xfsm_shutdown(XfsmShutdownType type) + /* the command we send to sudo */ + if (type == XFSM_SHUTDOWN_SHUTDOWN) + action = "POWEROFF"; + else if (type == XFSM_SHUTDOWN_RESTART) + action = "REBOOT"; + else + return FALSE; + + /* write action to sudo helper */ + if (fprintf (shutdown->helper_outfile, "%s\n", action) > 0) + fflush (shutdown->helper_outfile); + + /* check if the write succeeded */ + if (ferror (shutdown->helper_outfile) != 0) + { + /* probably succeeded but the helper got killed */ + if (errno == EINTR) + return TRUE; + + g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), + _("Error sending command to shutdown helper: %s"), + strerror (errno)); + return FALSE; + } + + /* get responce from sudo helper */ + if (fgets (reply, sizeof (reply), shutdown->helper_infile) == NULL) + { + /* probably succeeded but the helper got killed */ + if (errno == EINTR) + return TRUE; + + g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), + _("Error receiving response from shutdown helper: %s"), + strerror (errno)); + return FALSE; + } + + if (strncmp (reply, "SUCCEED", 7) != 0) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Shutdown command failed")); + + return FALSE; + } + + return TRUE; +} + + + +static XfsmPassState +xfsm_shutdown_sudo_send_password (XfsmShutdown *shutdown, + const gchar *password) { - gboolean result; - GError *error = NULL; - XfsmShutdownHelper *shutdown_helper; + gchar buf[1024]; + gsize len_buf, len_send; + gint fd; + gsize len; + gssize result; + gint attempts; + const gchar *errmsg = NULL; + + g_return_val_if_fail (shutdown->helper_state == SUDO_AVAILABLE, PASSWORD_FAILED); + g_return_val_if_fail (shutdown->helper_outfile != NULL, PASSWORD_FAILED); + g_return_val_if_fail (shutdown->helper_infile != NULL, PASSWORD_FAILED); + g_return_val_if_fail (shutdown->helper_require_password, PASSWORD_FAILED); + g_return_val_if_fail (password != NULL, PASSWORD_FAILED); + + /* write password to sudo helper */ + g_snprintf (buf, sizeof (buf), "%s\n", password); + len_buf = strlen (buf); + len_send = fwrite (buf, 1, len_buf, shutdown->helper_outfile); + fflush (shutdown->helper_outfile); + bzero (buf, len_buf); - /* kludge */ - if (type == XFSM_SHUTDOWN_ASK) + if (len_send != len_buf + || ferror (shutdown->helper_outfile) != 0) { - g_warning ("xfsm_shutdown () passed XFSM_SHUTDOWN_ASK. This is a bug."); - type = XFSM_SHUTDOWN_LOGOUT; + errmsg = "Failed to send password to sudo"; + goto err1; } - /* these two remember if they were started or not */ - xfsm_compat_gnome_shutdown (); - xfsm_compat_kde_shutdown (); + fd = fileno (shutdown->helper_infile); + + for (len = 0, attempts = 0;;) + { + result = read (fd, buf + len, 256 - len); + + if (result < 0) + { + errmsg = "Failed to read data from sudo"; + goto err1; + } + else if (result == 0) + { + /* don't try too often */ + if (++attempts > 20) + { + errmsg = "Too many password attempts"; + goto err1; + } + + continue; + } + else if (result + len >= sizeof (buf)) + { + errmsg = "Received too much data from sudo"; + goto err1; + } - /* kill legacy clients */ - xfsm_legacy_shutdown (); + len += result; + buf[len] = '\0'; + + if (len >= 15) + { + if (g_str_has_suffix (buf, "XFSM_SUDO_PASS ")) + { + return PASSWORD_RETRY; + } + else if (g_str_has_suffix (buf, "XFSM_SUDO_DONE ")) + { + /* sudo is unlocked, no further passwords required */ + shutdown->helper_require_password = FALSE; + + return PASSWORD_SUCCEED; + } + } + } + + return PASSWORD_FAILED; + + err1: + + g_printerr (PACKAGE_NAME ": %s.\n\n", errmsg); + return PASSWORD_FAILED; +} -#if !defined(__NR_ioprio_set) && defined(HAVE_SYNC) - /* sync disk block in-core status with that on disk. if - * we have ioprio_set (), then we've already synced. */ - if (fork () == 0) + + +static gboolean +xfsm_shutdown_query_xfpm (XfsmShutdown *shutdown, + const gchar *method, + gboolean *can_method, + GError **error) +{ + DBusGConnection *conn; + DBusGProxy *proxy; + gboolean result = FALSE; + + g_return_val_if_fail (can_method != NULL, FALSE); + + /* never return true if something fails */ + *can_method = FALSE; + + conn = dbus_g_bus_get (DBUS_BUS_SESSION, error); + if (conn == NULL) + return FALSE; + + proxy = dbus_g_proxy_new_for_name_owner (conn, "org.xfce.Power.Manager", + "/org/xfce/PowerManager", + "org.xfce.Power.Manager", error); + if (proxy != NULL) + { + result = dbus_g_proxy_call (proxy, method, error, + G_TYPE_INVALID, + G_TYPE_BOOLEAN, can_method, + G_TYPE_INVALID); + g_object_unref (proxy); + } + + dbus_g_connection_unref (conn); + + return result; +} + + + +XfsmShutdown * +xfsm_shutdown_get (void) +{ + static XfsmShutdown *object = NULL; + + if (G_LIKELY (object != NULL)) + { + g_object_ref (G_OBJECT (object)); + } + else { -# ifdef HAVE_SETSID - setsid (); -# endif - sync (); - _exit (EXIT_SUCCESS); + object = g_object_new (XFSM_TYPE_SHUTDOWN, NULL); + g_object_add_weak_pointer (G_OBJECT (object), (gpointer) &object); } -#endif /* HAVE_SYNC */ - if (type == XFSM_SHUTDOWN_LOGOUT) - return EXIT_SUCCESS; + return object; +} + + + +gboolean +xfsm_shutdown_password_require (XfsmShutdown *shutdown, + XfsmShutdownType type) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), FALSE); + + /* the helper only handled shutdown and restart */ + if (type == XFSM_SHUTDOWN_SHUTDOWN || type == XFSM_SHUTDOWN_RESTART) + return shutdown->helper_require_password; + + return FALSE; +} + + + +XfsmPassState +xfsm_shutdown_password_send (XfsmShutdown *shutdown, + XfsmShutdownType type, + const gchar *password) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), PASSWORD_FAILED); + g_return_val_if_fail (password != NULL, PASSWORD_FAILED); + + if ((type == XFSM_SHUTDOWN_SHUTDOWN || type == XFSM_SHUTDOWN_RESTART) + && shutdown->helper_state == SUDO_AVAILABLE) + return xfsm_shutdown_sudo_send_password (shutdown, password); + + return PASSWORD_FAILED; +} - shutdown_helper = xfsm_shutdown_helper_new (); - result = xfsm_shutdown_helper_send_command (shutdown_helper, type, &error); - g_object_unref (shutdown_helper); - if (!result) + +gboolean +xfsm_shutdown_try_type (XfsmShutdown *shutdown, + XfsmShutdownType type, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), FALSE); + + switch (type) { - xfce_message_dialog (NULL, _("Shutdown Failed"), - GTK_STOCK_DIALOG_ERROR, - _("Unable to perform shutdown"), - error->message, - GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT, - NULL); - g_error_free (error); - return EXIT_FAILURE; + case XFSM_SHUTDOWN_SHUTDOWN: + return xfsm_shutdown_try_shutdown (shutdown, error); + + case XFSM_SHUTDOWN_RESTART: + return xfsm_shutdown_try_restart (shutdown, error); + + case XFSM_SHUTDOWN_SUSPEND: + return xfsm_shutdown_try_suspend (shutdown, error); + + case XFSM_SHUTDOWN_HIBERNATE: + return xfsm_shutdown_try_hibernate (shutdown, error); + + default: + g_set_error (error, 1, 0, _("Unknown shutdown method %d"), type); + break; } - return EXIT_SUCCESS; + return FALSE; +} + + + +gboolean +xfsm_shutdown_try_restart (XfsmShutdown *shutdown, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), FALSE); + + if (shutdown->helper_state == SUDO_AVAILABLE) + return xfsm_shutdown_sudo_try_action (shutdown, XFSM_SHUTDOWN_RESTART, error); + else + return xfsm_consolekit_try_restart (shutdown->consolekit, error); +} + + + +gboolean +xfsm_shutdown_try_shutdown (XfsmShutdown *shutdown, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), FALSE); + + if (shutdown->helper_state == SUDO_AVAILABLE) + return xfsm_shutdown_sudo_try_action (shutdown, XFSM_SHUTDOWN_SHUTDOWN, error); + else + return xfsm_consolekit_try_shutdown (shutdown->consolekit, error); +} + + + +gboolean +xfsm_shutdown_try_suspend (XfsmShutdown *shutdown, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), FALSE); + + return TRUE; +} + + + +gboolean +xfsm_shutdown_try_hibernate (XfsmShutdown *shutdown, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), FALSE); + + return TRUE; +} + + + +gboolean +xfsm_shutdown_can_restart (XfsmShutdown *shutdown, + gboolean *can_restart, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), FALSE); + + if (xfsm_consolekit_can_restart (shutdown->consolekit, can_restart, error)) + return TRUE; + + return xfsm_shutdown_sudo_init (shutdown, error); +} + + + +gboolean +xfsm_shutdown_can_shutdown (XfsmShutdown *shutdown, + gboolean *can_shutdown, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), FALSE); + + if (xfsm_consolekit_can_shutdown (shutdown->consolekit, can_shutdown, error)) + return TRUE; + + return xfsm_shutdown_sudo_init (shutdown, error); +} + + + +/* This function only queries the CanSuspend state of + * xfce4-power-manager. If this package is not installed, + * suspend is not supported. */ +gboolean +xfsm_shutdown_can_suspend (XfsmShutdown *shutdown, + gboolean *can_suspend, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), FALSE); + + return xfsm_shutdown_query_xfpm (shutdown, "CanSuspend", + can_suspend, error); +} + + + +/* This function only queries the CanHibernate state of + * xfce4-power-manager. If this package is not installed, + * hibernation is not supported. */ +gboolean +xfsm_shutdown_can_hibernate (XfsmShutdown *shutdown, + gboolean *can_hibernate, + GError **error) +{ + g_return_val_if_fail (XFSM_IS_SHUTDOWN (shutdown), FALSE); + + return xfsm_shutdown_query_xfpm (shutdown, "CanHibernate", + can_hibernate, error); } diff --git a/xfce4-session/xfsm-shutdown.h b/xfce4-session/xfsm-shutdown.h index 76d71458..2ec61f0a 100644 --- a/xfce4-session/xfsm-shutdown.h +++ b/xfce4-session/xfsm-shutdown.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 2003-2004 Benedikt Meurer <benny@xfce.org> + * Copyright (c) 2011 Nick Schermer <nick@xfce.org> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -21,8 +22,76 @@ #ifndef __XFSM_SHUTDOWN_H__ #define __XFSM_SHUTDOWN_H__ -#include <xfce4-session/xfsm-global.h> +typedef struct _XfsmShutdownClass XfsmShutdownClass; +typedef struct _XfsmShutdown XfsmShutdown; -gint xfsm_shutdown (XfsmShutdownType type); +#define XFSM_TYPE_SHUTDOWN (xfsm_shutdown_get_type ()) +#define XFSM_SHUTDOWN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFSM_TYPE_SHUTDOWN, XfsmShutdown)) +#define XFSM_SHUTDOWN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XFSM_TYPE_SHUTDOWN, XfsmShutdownClass)) +#define XFSM_IS_SHUTDOWN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFSM_TYPE_SHUTDOWN)) +#define XFSM_IS_SHUTDOWN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFSM_TYPE_SHUTDOWN)) +#define XFSM_SHUTDOWN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XFSM_TYPE_SHUTDOWN, XfsmShutdownClass)) + +typedef enum +{ + XFSM_SHUTDOWN_ASK = 0, + XFSM_SHUTDOWN_LOGOUT, + XFSM_SHUTDOWN_SHUTDOWN, + XFSM_SHUTDOWN_RESTART, + XFSM_SHUTDOWN_SUSPEND, + XFSM_SHUTDOWN_HIBERNATE, +} +XfsmShutdownType; + +typedef enum +{ + PASSWORD_RETRY, + PASSWORD_SUCCEED, + PASSWORD_FAILED +} +XfsmPassState; + +GType xfsm_shutdown_get_type (void) G_GNUC_CONST; + +XfsmShutdown *xfsm_shutdown_get (void); + +gboolean xfsm_shutdown_password_require (XfsmShutdown *shutdown, + XfsmShutdownType type); + +XfsmPassState xfsm_shutdown_password_send (XfsmShutdown *shutdown, + XfsmShutdownType type, + const gchar *password); + +gboolean xfsm_shutdown_try_type (XfsmShutdown *shutdown, + XfsmShutdownType type, + GError **error); + +gboolean xfsm_shutdown_try_restart (XfsmShutdown *shutdown, + GError **error); + +gboolean xfsm_shutdown_try_shutdown (XfsmShutdown *shutdown, + GError **error); + +gboolean xfsm_shutdown_try_suspend (XfsmShutdown *shutdown, + GError **error); + +gboolean xfsm_shutdown_try_hibernate (XfsmShutdown *shutdown, + GError **error); + +gboolean xfsm_shutdown_can_restart (XfsmShutdown *shutdown, + gboolean *can_restart, + GError **error); + +gboolean xfsm_shutdown_can_shutdown (XfsmShutdown *shutdown, + gboolean *can_shutdown, + GError **error); + +gboolean xfsm_shutdown_can_suspend (XfsmShutdown *shutdown, + gboolean *can_suspend, + GError **error); + +gboolean xfsm_shutdown_can_hibernate (XfsmShutdown *shutdown, + gboolean *can_hibernate, + GError **error); #endif /* !__XFSM_SHUTDOWN_H__ */ |