[Xfce4-commits] <libxfce4ui:new-sm-client> add first cut of a session management client
Brian J. Tarricone
brian at tarricone.org
Tue Sep 15 05:22:02 CEST 2009
Updating branch refs/heads/new-sm-client
to 6cb7545b7a1b15af2771e6c6be0a763110ccf070 (commit)
from fe8612ecbb27283245f2b2b20e748996fc7a1cb0 (commit)
commit 6cb7545b7a1b15af2771e6c6be0a763110ccf070
Author: Brian J. Tarricone <brian at tarricone.org>
Date: Mon Sep 14 20:18:10 2009 -0700
add first cut of a session management client
API is not frozen, and it's not well tested. it does compile, and it
does successfully connect to the session manager on startup, but that's
about all i can say about it at this point.
libxfce4ui/Makefile.am | 51 +-
libxfce4ui/libxfce4ui.h | 2 +
libxfce4ui/libxfce4ui.symbols | 43 +
libxfce4ui/xfce-sm-client.c | 2250 +++++++++++++++++++++++++++++++++++++++++
libxfce4ui/xfce-sm-client.h | 184 ++++
5 files changed, 2528 insertions(+), 2 deletions(-)
diff --git a/libxfce4ui/Makefile.am b/libxfce4ui/Makefile.am
index 6f2ff89..c48cb75 100644
--- a/libxfce4ui/Makefile.am
+++ b/libxfce4ui/Makefile.am
@@ -13,18 +13,27 @@ INCLUDES = \
lib_LTLIBRARIES = libxfce4ui-1.la
+libxfce4ui_enum_headers = \
+ xfce-sm-client.h
+
libxfce4ui_headers = \
libxfce4ui.h \
libxfce4ui-config.h \
+ libxfce4ui-enum-types.h \
xfce-dialogs.h \
xfce-gdk-extensions.h \
xfce-gtk-extensions.h \
xfce-spawn.h \
- xfce-titled-dialog.h
+ xfce-titled-dialog.h \
+ $(libxfce4ui_enum_headers)
libxfce4ui_built_sources = \
libxfce4ui-alias.h \
- libxfce4ui-aliasdef.c
+ libxfce4ui-aliasdef.c \
+ libxfce4ui-enum-types.c \
+ libxfce4ui-enum-types.h \
+ libxfce4ui-marshal.c \
+ libxfce4ui-marshal.h
libxfce4ui_includedir = \
$(includedir)/xfce4/libxfce4ui-$(LIBXFCE4UI_VERSION_API)/libxfce4ui
@@ -42,6 +51,7 @@ libxfce4ui_1_la_SOURCES = \
xfce-gtk-extensions.c \
xfce-heading.c \
xfce-heading.h \
+ xfce-sm-client.c \
xfce-spawn.c \
xfce-titled-dialog.c
@@ -97,6 +107,43 @@ libxfce4ui-alias.h: make-libxfce4ui-alias.pl libxfce4ui.symbols
libxfce4ui-aliasdef.c: make-libxfce4ui-alias.pl libxfce4ui.symbols
$(PERL) $(srcdir)/make-libxfce4ui-alias.pl -def < $(srcdir)/libxfce4ui.symbols > libxfce4ui-aliasdef.c
+
+libxfce4ui-marshal.h: stamp-libxfce4ui-marshal.h
+ @true
+stamp-libxfce4ui-marshal.h: libxfce4ui-marshal.list Makefile
+ glib-genmarshal --prefix=_libxfce4ui_marshal --header $(srcdir)/libxfce4ui-marshal.list >xgen-lmh
+ cmp -s xgen-lmh libxfce4-marshal.h || cp xgen-lmh libxfce4ui-marshal.h
+ rm -f xgen-lmh
+ echo timestamp >$(@F)
+
+libxfce4ui-marshal.c: libxfce4ui-marshal.list Makefile
+ glib-genmarshal --prefix=_libxfce4ui_marshal --body $(srcdir)/libxfce4ui-marshal.list >xgen-lmc
+ cmp -s xgen-lmc libxfce4-marshal.c || cp xgen-lmc libxfce4ui-marshal.c
+ rm -f xgen-lmc
+
+libxfce4ui-enum-types.h: stamp-libxfce4ui-enum-types.h
+ @true
+stamp-libxfce4ui-enum-types.h: $(libxfce4ui_enum_headers) Makefile
+ ( cd $(srcdir) && glib-mkenums \
+ --fhead "#ifndef __LIBXFCE4UI_ENUM_TYPES_H__\n#define __LIBXFCE4UI_ENUM_TYPES_H__\n\nG_BEGIN_DECLS\n\n" \
+ --fprod "/* enumerations from \"@filename@\" */\n\n" \
+ --vhead "GType @enum_name at _get_type(void) G_GNUC_CONST;\n#define XFCE_TYPE_ at ENUMSHORT@ (@enum_name at _get_type())\n\n" \
+ --ftail "G_END_DECLS\n\n#endif /* !__LIBXFCE4UI_ENUM_TYPES_H__ */" \
+ $(libxfce4ui_enum_headers) ) >xgen-leth
+ cmp -s xgen-leth libxfce4ui-enum-types.h || cp xgen-leth libxfce4ui-enum-types.h
+ rm -f xgen-leth
+ echo timestamp > $(@F)
+libxfce4ui-enum-types.c: $(libxfce4ui_enum_headers) Makefile
+ ( cd $(srcdir) && glib-mkenums \
+ --fhead "#include <libxfce4ui/libxfce4ui.h>\n#include <libxfce4ui/libxfce4ui-alias.h>\n\n" \
+ --fprod "/* enumerations from \"@filename@\" */\n\n" \
+ --vhead "GType\n at enum_name@_get_type(void)\n{\n static GType type = 0;\n\n if(!type) {\n static const G at Type@Value values[] = {"\
+ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
+ --vtail " { 0, NULL, NULL }\n\t};\n\ttype = g_ at type@_register_static(\"@EnumName@\", values);\n }\n\n return type;\n}\n\n" \
+ --ftail "\n#define __LIBXFCE4UI_ENUM_TYPES_C__\n#include \"libxfce4ui-aliasdef.c\"\n" \
+ $(libxfce4ui_enum_headers) ) > xgen-letc
+ cp xgen-letc libxfce4ui-enum-types.c
+ rm -f xgen-letc
endif
# required for gtk-doc
diff --git a/libxfce4ui/libxfce4ui.h b/libxfce4ui/libxfce4ui.h
index abd859e..f494bc9 100644
--- a/libxfce4ui/libxfce4ui.h
+++ b/libxfce4ui/libxfce4ui.h
@@ -28,7 +28,9 @@
#include <libxfce4ui/xfce-gdk-extensions.h>
#include <libxfce4ui/xfce-gtk-extensions.h>
#include <libxfce4ui/xfce-spawn.h>
+#include <libxfce4ui/xfce-sm-client.h>
#include <libxfce4ui/xfce-titled-dialog.h>
+#include <libxfce4ui/libxfce4ui-enum-types.h>
#undef LIBXFCE4UI_INSIDE_LIBXFCE4UI_H
diff --git a/libxfce4ui/libxfce4ui.symbols b/libxfce4ui/libxfce4ui.symbols
index 0f79e52..5f9fd3d 100644
--- a/libxfce4ui/libxfce4ui.symbols
+++ b/libxfce4ui/libxfce4ui.symbols
@@ -46,6 +46,16 @@ libxfce4ui_check_version
#endif
#endif
+/* libxfce4ui-enum-types functions */
+#if IN_HEADER(__LIBXFCE4UI_ENUM_TYPES_H__)
+#if IN_SOURCE(__LIBXFCE4UI_ENUM_TYPES_C__)
+xfce_sm_client_restart_style_get_type
+xfce_sm_client_state_get_type
+xfce_sm_client_priority_get_type
+xfce_sm_client_shutdown_hint_get_type
+#endif
+#endif
+
/* xfce-dialogs functions */
#if IN_HEADER(__XFCE_DIALOGS_H__)
#if IN_SOURCE(__XFCE_DIALOGS_C__)
@@ -83,6 +93,39 @@ xfce_spawn_command_line_on_screen
#endif
#endif
+/* xfce-sm-client functions */
+#if IN_HEADER(__XFCE_SM_CLIENT_H__)
+#if IN_SOURCE(__XFCE_SM_CLIENT_C__)
+xfce_sm_client_get_type
+xfce_sm_client_get_option_group
+xfce_sm_client_get
+xfce_sm_client_get_with_argv
+xfce_sm_client_get_full
+xfce_sm_client_connect
+xfce_sm_client_disconnect
+xfce_sm_client_request_shutdown
+xfce_sm_client_get_state
+xfce_sm_client_get_client_id
+xfce_sm_client_get_state_file
+xfce_sm_client_set_restart_style
+xfce_sm_client_get_restart_style
+xfce_sm_client_set_priority
+xfce_sm_client_get_priority
+xfce_sm_client_set_program
+xfce_sm_client_get_program
+xfce_sm_client_set_clone_command
+xfce_sm_client_get_clone_command
+xfce_sm_client_set_resign_command
+xfce_sm_client_get_resign_command
+xfce_sm_client_set_restart_command
+xfce_sm_client_get_restart_command
+xfce_sm_client_set_discard_command
+xfce_sm_client_get_discard_command
+xfce_sm_client_set_shutdown_command
+xfce_sm_client_get_shutdown_command
+#endif
+#endif
+
/* xfce-titled-dialog functions */
#if IN_HEADER(__XFCE_TITLED_DIALOG_H__)
#if IN_SOURCE(__XFCE_TITLED_DIALOG_C__)
diff --git a/libxfce4ui/xfce-sm-client.c b/libxfce4ui/xfce-sm-client.c
new file mode 100644
index 0000000..edb2b70
--- /dev/null
+++ b/libxfce4ui/xfce-sm-client.c
@@ -0,0 +1,2250 @@
+/* xfce4
+ * Copyright (C) 1999 Olivier Fourdan (fourdan at xfce.org)
+ * Copyright (C) 2009 Brian Tarricone <brian at tarricone.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_LIBSM
+#include <X11/ICE/ICElib.h>
+#include <X11/SM/SMlib.h>
+#endif
+
+#include <gdk/gdkwindow.h>
+#include <gtk/gtk.h>
+
+#include <libxfce4util/libxfce4util.h>
+
+#include "xfce-sm-client.h"
+#include "libxfce4ui-marshal.h"
+#include "libxfce4ui-enum-types.h"
+
+#define SM_ID_ARG "--sm-client-id"
+#define DPY_ARG "--display"
+
+#define SM_ARG_APPEND 1
+#define SM_ARG_REMOVE 2
+
+#define xfce_safe_strcmp(s1, s2) ( (!s1 && !s2) \
+ ? 0 : (!s1 \
+ ? -1 : (!s2 \
+ ? 1 : strcmp(s1, s2))) )
+
+struct _XfceSMClientPrivate
+{
+#ifdef HAVE_LIBSM
+ SmcConn session_connection;
+#endif
+
+ XfceSMClientState state;
+ XfceSMClientRestartStyle restart_style;
+
+ gchar priority;
+
+ gchar *client_id;
+
+ gchar *current_directory;
+ gchar *program;
+ gchar **clone_command;
+ gchar **resign_command;
+ gchar **restart_command;
+ gchar **discard_command;
+ gchar **shutdown_command;
+
+ guint32 resumed:1,
+ needs_save_state:1,
+ shutdown_cancelled:1;
+
+ guint argc;
+ gchar **argv;
+
+ gchar *state_file;
+};
+
+typedef struct
+{
+ guint argc;
+ gchar **argv;
+ gchar *client_id;
+ gboolean sm_disable;
+} XfceSMClientStartupOptions;
+
+enum
+{
+ SIG_SAVE_STATE = 0,
+ SIG_SAVE_STATE_EXTENDED,
+ SIG_QUIT_REQUESTED,
+ SIG_QUIT,
+ SIG_QUIT_CANCELLED,
+ SIG_STATE_CHANGED,
+ N_SIGS
+};
+
+enum
+{
+ PROP0 = 0,
+ PROP_SESSION_CONNECTION,
+ PROP_STATE,
+ PROP_RESUMED,
+ PROP_RESTART_STYLE,
+ PROP_PRIORITY,
+ PROP_CLIENT_ID,
+ PROP_CURRENT_DIRECTORY,
+ PROP_PROGRAM,
+ PROP_CLONE_COMMAND,
+ PROP_RESIGN_COMMAND,
+ PROP_RESTART_COMMAND,
+ PROP_DISCARD_COMMAND,
+ PROP_SHUTDOWN_COMMAND,
+ PROP_ARGC,
+ PROP_ARGV,
+};
+
+static void xfce_sm_client_get_property(GObject *obj,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void xfce_sm_client_set_property(GObject *obj,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static GObject *xfce_sm_client_constructor(GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_params);
+static void xfce_sm_client_finalize(GObject *obj);
+
+static void xfce_sm_client_set_client_id(XfceSMClient *sm_client,
+ const gchar *client_id);
+static void xfce_sm_client_parse_argv(XfceSMClient *sm_client);
+
+
+static guint signals[N_SIGS] = { 0, };
+static XfceSMClientStartupOptions startup_options = { 0, NULL, NULL, FALSE };
+static XfceSMClient *sm_client_singleton = NULL;
+
+
+G_DEFINE_TYPE(XfceSMClient, xfce_sm_client, G_TYPE_OBJECT)
+
+
+static void
+xfce_sm_client_class_init(XfceSMClientClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *)klass;
+
+ g_type_class_add_private(klass, sizeof(XfceSMClientPrivate));
+
+ gobject_class->get_property = xfce_sm_client_get_property;
+ gobject_class->set_property = xfce_sm_client_set_property;
+ gobject_class->constructor = xfce_sm_client_constructor;
+ gobject_class->finalize = xfce_sm_client_finalize;
+
+ /**
+ * XfceSMClient::save-state:
+ * @sm_client: An #XfceSMClient
+ *
+ * Signals the client that it should save a copy of its current state
+ * such that it could be restarted later in exactly the same state as
+ * it is at the time of signal emission.
+ *
+ * If the state is simple enough to be encoded in the application's
+ * command line, xfce_sm_client_set_restart_command() can be used
+ * to set that command line. For more complex state data,
+ * xfce_sm_client_get_state_file() should be used.
+ *
+ * The application should attempt to save its state as quickly as
+ * possible, and MUST NOT interact with the user as a part of saving
+ * state.
+ **/
+ signals[SIG_SAVE_STATE] = g_signal_new("save-state",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(XfceSMClientClass,
+ save_state_extended),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE, 1,
+ G_TYPE_BOOLEAN);
+
+ /**
+ * XfceSMClient::save-state-extended:
+ * @sm_client: An #XfceSMClient
+ *
+ * Allows the application to save extra state information after all
+ * other applications in the session have had a chance to save their
+ * state. This is mainly used by the window manager to save window
+ * positions. Most applications should not need to connect to this
+ * signal.
+ **/
+ signals[SIG_SAVE_STATE_EXTENDED] = g_signal_new("save-state-extended",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(XfceSMClientClass,
+ save_state_extended),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /**
+ * XfceSMClient::quit-requested:
+ * @sm_client: An #XfceSMClient
+ *
+ * Signals the client that the session manager will soon want the
+ * application to quit, perhaps as a part of ending the session
+ * (but this should not be assumed). The application can take
+ * this opportunity to prompt the user to save any unsaved work
+ * to disk.
+ *
+ * This signal also expects a return value from the handler. If the
+ * application wishes to cancel the quit request (perhaps because the
+ * user selected "Cancel" in prompts to save unsaved work), it should
+ * return %TRUE from the handler. If the application is satisfied
+ * with possibly needing to quit soon, the handler should return %FALSE.
+ **/
+ signals[SIG_QUIT_REQUESTED] = g_signal_new("quit-requested",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(XfceSMClientClass,
+ quit_requested),
+ g_signal_accumulator_true_handled,
+ NULL,
+ _libxfce4ui_marshal_BOOLEAN__VOID,
+ G_TYPE_BOOLEAN, 0);
+
+ /**
+ * XfceSMClient::quit:
+ * @sm_client: An #XfceSMClient
+ *
+ * Emitted when the application is required to quit. This is not
+ * optional: if the client does not quit a short time after receiving
+ * this signal, it will likely be terminated in some other way. While
+ * not required, the applicatiokn will usually receive quit-requested
+ * before receiving quit. If the application does not connect to this
+ * signal, #XfceSMClient will call exit(3) with an exit code of zero
+ * on behalf of the application.
+ **/
+ signals[SIG_QUIT] = g_signal_new("quit",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(XfceSMClientClass,
+ quit),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /**
+ * XfceSMClient::quit-cancelled:
+ * @sm_client: An #XfceSMClient
+ *
+ * Informs the application that it will not need to quit. In most cases,
+ * quit-cancelled will be emitted a short time after quit-requested.
+ **/
+ signals[SIG_QUIT_CANCELLED] = g_signal_new("quit-cancelled",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(XfceSMClientClass,
+ quit_cancelled),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /**
+ * XfceSMClient::state-changed
+ * @sm_client: An #XfceSMClient
+ * @old_state: The client's previous state
+ * @new_state: The client's new (current) state
+ *
+ * Emitted whenever the client's internal session management state
+ * changes. This is mainly useful for debugging and other informative
+ * purposes. No actual actions should be taken based on the emission
+ * of this signal; instead, the application should make use of the other
+ * signals emitted on the object.
+ **/
+ signals[SIG_STATE_CHANGED] = g_signal_new("state-changed",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(XfceSMClientClass,
+ state_changed),
+ NULL, NULL,
+ _libxfce4ui_marshal_VOID__ENUM_ENUM,
+ G_TYPE_NONE, 2,
+ XFCE_TYPE_SM_CLIENT_STATE,
+ XFCE_TYPE_SM_CLIENT_STATE);
+
+ g_object_class_install_property(gobject_class, PROP_SESSION_CONNECTION,
+ g_param_spec_pointer("session-connection",
+ "Session connection descriptor",
+ "The raw pointer to the SmcConnection",
+ G_PARAM_READABLE));
+ g_object_class_install_property(gobject_class, PROP_STATE,
+ g_param_spec_enum("state",
+ "State",
+ "The client's current XSMP state",
+ XFCE_TYPE_SM_CLIENT_STATE,
+ XFCE_SM_CLIENT_STATE_DISCONNECTED,
+ G_PARAM_READABLE));
+ g_object_class_install_property(gobject_class, PROP_RESUMED,
+ g_param_spec_boolean("resumed",
+ "Resumed",
+ "Whether or not the client was resumed with previous state",
+ FALSE,
+ G_PARAM_READABLE));
+ g_object_class_install_property(gobject_class, PROP_RESTART_STYLE,
+ g_param_spec_enum("restart-style",
+ "Restart style",
+ "Specifies how the client should be restarted by the session manager",
+ XFCE_TYPE_SM_CLIENT_RESTART_STYLE,
+ XFCE_SM_CLIENT_RESTART_IF_RUNNING,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property(gobject_class, PROP_PRIORITY,
+ g_param_spec_char("priority",
+ "Priority",
+ "Determines the ordering in which this client is restarted",
+ G_MININT8, G_MAXINT8, 50,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property(gobject_class, PROP_CLIENT_ID,
+ g_param_spec_string("client-id",
+ "Client ID",
+ "A string uniquely identifying the current instance of this client",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property(gobject_class, PROP_CURRENT_DIRECTORY,
+ g_param_spec_string("current-directory",
+ "Current working directory",
+ "The directory that should be used as the working directory the next time this client is restarted",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property(gobject_class, PROP_PROGRAM,
+ g_param_spec_string("program",
+ "Program name",
+ "An string used to identify the application",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property(gobject_class, PROP_CLONE_COMMAND,
+ g_param_spec_boxed("clone-command",
+ "Clone command",
+ "A command used to launch a fresh instance of the application",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property(gobject_class, PROP_RESIGN_COMMAND,
+ g_param_spec_boxed("resign-command",
+ "Resign command",
+ "A command used to remove any saved state for the 'anyway' restart style",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property(gobject_class, PROP_RESTART_COMMAND,
+ g_param_spec_boxed("restart-command",
+ "Restart command",
+ "A command used to restart this application, preserving the current state",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property(gobject_class, PROP_DISCARD_COMMAND,
+ g_param_spec_boxed("discard-command",
+ "Discard command",
+ "A command used to discard any information about the current saved state",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property(gobject_class, PROP_SHUTDOWN_COMMAND,
+ g_param_spec_boxed("shutdown-command",
+ "Shutdown command",
+ "A command used at session end to clean up after an application started with the 'anyway' restart style",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ /* these are "private" properties */
+ g_object_class_install_property(gobject_class, PROP_ARGC,
+ g_param_spec_uint("argc",
+ "argc",
+ "Argument count passed to program",
+ 0, G_MAXUINT, 0,
+ G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property(gobject_class, PROP_ARGV,
+ g_param_spec_boxed("argv",
+ "argv",
+ "Argument vector passed to program",
+ G_TYPE_STRV,
+ G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+xfce_sm_client_init(XfceSMClient *sm_client)
+{
+ sm_client->priv = G_TYPE_INSTANCE_GET_PRIVATE(sm_client,
+ XFCE_TYPE_SM_CLIENT,
+ XfceSMClientPrivate);
+
+ sm_client->priv->state = XFCE_SM_CLIENT_STATE_DISCONNECTED;
+ sm_client->priv->program = g_get_prgname() ? g_strdup(g_get_prgname()) : g_strdup("<unknown program>");
+}
+
+static void
+xfce_sm_client_get_property(GObject *obj,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ XfceSMClient *sm_client = XFCE_SM_CLIENT(obj);
+
+ switch(property_id) {
+ case PROP_SESSION_CONNECTION:
+#ifdef HAVE_LIBSM
+ g_value_set_pointer(value, sm_client->priv->session_connection);
+#else
+ g_value_set_pointer(value, NULL);
+#endif
+ break;
+
+ case PROP_STATE:
+ g_value_set_enum(value, sm_client->priv->state);
+ break;
+
+ case PROP_RESUMED:
+ g_value_set_boolean(value, sm_client->priv->resumed);
+ break;
+
+ case PROP_RESTART_STYLE:
+ g_value_set_enum(value, sm_client->priv->restart_style);
+ break;
+
+ case PROP_PRIORITY:
+ g_value_set_char(value, sm_client->priv->priority);
+ break;
+
+ case PROP_CLIENT_ID:
+ g_value_set_string(value, sm_client->priv->client_id);
+ break;
+
+ case PROP_CURRENT_DIRECTORY:
+ g_value_set_string(value, sm_client->priv->current_directory);
+ break;
+
+ case PROP_PROGRAM:
+ g_value_set_string(value, sm_client->priv->program);
+ break;
+
+ case PROP_CLONE_COMMAND:
+ g_value_set_boxed(value, sm_client->priv->clone_command);
+ break;
+
+ case PROP_RESIGN_COMMAND:
+ g_value_set_boxed(value, sm_client->priv->resign_command);
+ break;
+
+ case PROP_RESTART_COMMAND:
+ g_value_set_boxed(value, sm_client->priv->restart_command);
+ break;
+
+ case PROP_DISCARD_COMMAND:
+ g_value_set_boxed(value, sm_client->priv->discard_command);
+ break;
+
+ case PROP_SHUTDOWN_COMMAND:
+ g_value_set_boxed(value, sm_client->priv->shutdown_command);
+ break;
+
+ case PROP_ARGC:
+ case PROP_ARGV:
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
+ }
+}
+
+static void
+xfce_sm_client_set_property(GObject *obj,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ XfceSMClient *sm_client = XFCE_SM_CLIENT(obj);
+
+ switch(property_id) {
+ case PROP_RESTART_STYLE:
+ xfce_sm_client_set_restart_style(sm_client,
+ g_value_get_enum(value));
+ break;
+
+ case PROP_PRIORITY:
+ xfce_sm_client_set_priority(sm_client, g_value_get_char(value));
+ break;
+
+ case PROP_CLIENT_ID:
+ xfce_sm_client_set_client_id(sm_client, g_value_get_string(value));
+ break;
+
+ case PROP_CURRENT_DIRECTORY:
+ xfce_sm_client_set_current_directory(sm_client,
+ g_value_get_string(value));
+ break;
+
+ case PROP_PROGRAM:
+ xfce_sm_client_set_program(sm_client, g_value_get_string(value));
+ break;
+
+ case PROP_CLONE_COMMAND:
+ xfce_sm_client_set_clone_command(sm_client,
+ g_value_get_boxed(value));
+ break;
+
+ case PROP_RESIGN_COMMAND:
+ xfce_sm_client_set_resign_command(sm_client,
+ g_value_get_boxed(value));
+ break;
+
+ case PROP_RESTART_COMMAND:
+ xfce_sm_client_set_restart_command(sm_client,
+ g_value_get_boxed(value));
+ break;
+
+ case PROP_DISCARD_COMMAND:
+ xfce_sm_client_set_discard_command(sm_client,
+ g_value_get_boxed(value));
+ break;
+
+ case PROP_SHUTDOWN_COMMAND:
+ xfce_sm_client_set_shutdown_command(sm_client,
+ g_value_get_boxed(value));
+ break;
+
+ case PROP_ARGC:
+ if(sm_client->priv->argc)
+ g_critical("XfceSMClient: Received argc twice");
+ else {
+ sm_client->priv->argc = g_value_get_uint(value);
+ xfce_sm_client_parse_argv(sm_client);
+ }
+ break;
+
+ case PROP_ARGV:
+ if(sm_client->priv->argv)
+ g_critical("XfceSMClient: Received argv twice");
+ else {
+ sm_client->priv->argv = g_value_dup_boxed(value);
+ xfce_sm_client_parse_argv(sm_client);
+ }
+ break;
+
+ case PROP_SESSION_CONNECTION:
+ case PROP_STATE:
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
+ }
+}
+
+static GObject *
+xfce_sm_client_constructor(GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ if(sm_client_singleton)
+ return G_OBJECT(sm_client_singleton);
+
+ return G_OBJECT_CLASS(xfce_sm_client_parent_class)->constructor(type,
+ n_construct_params,
+ construct_params);
+}
+
+static void
+xfce_sm_client_finalize(GObject *obj)
+{
+ XfceSMClient *sm_client = XFCE_SM_CLIENT(obj);
+
+ g_assert(sm_client == sm_client_singleton);
+ sm_client_singleton = NULL;
+
+#ifdef HAVE_LIBSM
+ if(sm_client->priv->session_connection)
+ xfce_sm_client_disconnect(sm_client);
+#endif
+
+ g_free(sm_client->priv->state_file);
+
+ g_free(sm_client->priv->client_id);
+ g_free(sm_client->priv->current_directory);
+ g_free(sm_client->priv->program);
+ g_strfreev(sm_client->priv->clone_command);
+ g_strfreev(sm_client->priv->resign_command);
+ g_strfreev(sm_client->priv->restart_command);
+ g_strfreev(sm_client->priv->discard_command);
+ g_strfreev(sm_client->priv->shutdown_command);
+
+ g_strfreev(sm_client->priv->argv);
+
+ G_OBJECT_CLASS(xfce_sm_client_parent_class)->finalize(obj);
+}
+
+
+
+static inline const gchar *
+str_from_state(XfceSMClientState state)
+{
+ switch(state) {
+ case XFCE_SM_CLIENT_STATE_IDLE:
+ return "IDLE";
+ case XFCE_SM_CLIENT_STATE_SAVING_PHASE_1:
+ return "SAVING_PHASE_1";
+ case XFCE_SM_CLIENT_STATE_WAITING_FOR_PHASE_2:
+ return "WAITING_FOR_PHASE_2";
+ case XFCE_SM_CLIENT_STATE_SAVING_PHASE_2:
+ return "SAVING_PHASE_2";
+ case XFCE_SM_CLIENT_STATE_WAITING_FOR_INTERACT:
+ return "WAITING_FOR_INTERACT";
+ case XFCE_SM_CLIENT_STATE_INTERACTING:
+ return "INTERACTING";
+ case XFCE_SM_CLIENT_STATE_FROZEN:
+ return "FROZEN";
+ case XFCE_SM_CLIENT_STATE_DISCONNECTED:
+ return "DISCONNECTED";
+ case XFCE_SM_CLIENT_STATE_REGISTERING:
+ return "REGISTERING";
+ default:
+ return "(unknown)";
+ }
+}
+
+static void
+xfce_sm_client_set_client_id(XfceSMClient *sm_client,
+ const gchar *client_id)
+{
+ if(!xfce_safe_strcmp(sm_client->priv->client_id, client_id))
+ return;
+
+ g_free(sm_client->priv->client_id);
+ sm_client->priv->client_id = g_strdup(client_id);
+
+ g_object_notify(G_OBJECT(sm_client), "client-id");
+}
+
+static void
+xfce_sm_client_parse_argv(XfceSMClient *sm_client)
+{
+ guint argc = 0;
+ gchar **argv = NULL;
+ gchar **clone_command = NULL;
+ guint clone_argc = 0;
+ const gchar *client_id = NULL;
+ int i;
+
+ if(sm_client->priv->argc == 0 || !sm_client->priv->argv)
+ return;
+
+ argc = sm_client->priv->argc;
+ argv = sm_client->priv->argv;
+
+ clone_command = g_new0(gchar *, argc + 1);
+
+ for(i = 0; i < argc; ++i) {
+ if(!g_ascii_strncasecmp(argv[i], SM_ID_ARG, strlen(SM_ID_ARG))) {
+ if(argv[i][strlen(SM_ID_ARG)] == '=')
+ client_id = &(argv[i][strlen(SM_ID_ARG)+1]);
+ else
+ client_id = argv[++i];
+ } else
+ clone_command[clone_argc++] = argv[i];
+ }
+
+ if(client_id)
+ xfce_sm_client_set_client_id(sm_client, client_id);
+ xfce_sm_client_set_restart_command(sm_client, argv);
+ xfce_sm_client_set_clone_command(sm_client, clone_command);
+
+ g_free(clone_command);
+
+ sm_client->priv->argc = 0;
+ g_strfreev(sm_client->priv->argv);
+ sm_client->priv->argv = NULL;
+}
+
+#ifdef HAVE_LIBSM
+
+static void
+xfce_sm_client_set_state(XfceSMClient *sm_client,
+ XfceSMClientState new_state)
+{
+ XfceSMClientState old_state = sm_client->priv->state;
+
+ if(G_UNLIKELY(old_state == new_state))
+ return;
+
+ g_debug("XfceSMClient: %s -> %s", str_from_state(old_state),
+ str_from_state(new_state));
+
+ sm_client->priv->state = new_state;
+
+ g_signal_emit(G_OBJECT(sm_client), signals[SIG_STATE_CHANGED], 0,
+ old_state, new_state);
+}
+
+static inline char
+xsmp_restart_style_from_enum(XfceSMClientRestartStyle style)
+{
+ switch(style) {
+ case XFCE_SM_CLIENT_RESTART_ANYWAY:
+ return SmRestartAnyway;
+ case XFCE_SM_CLIENT_RESTART_IMMEDIATELY:
+ return SmRestartImmediately;
+ case XFCE_SM_CLIENT_RESTART_NEVER:
+ return SmRestartNever;
+ case XFCE_SM_CLIENT_RESTART_IF_RUNNING:
+ default:
+ return SmRestartIfRunning;
+ }
+}
+
+
+static void xsmp_save_phase_2(SmcConn smc_conn,
+ SmPointer client_data);
+static void xsmp_interact(SmcConn smc_conn,
+ SmPointer client_data);
+static void xsmp_shutdown_cancelled(SmcConn smc_conn,
+ SmPointer client_data);
+static void xsmp_save_complete(SmcConn smc_conn,
+ SmPointer client_data);
+static void xsmp_die(SmcConn smc_conn,
+ SmPointer client_data);
+static void xsmp_save_yourself(SmcConn smc_conn,
+ SmPointer client_data,
+ int save_style,
+ Bool shutdown,
+ int interact_style,
+ Bool fast);
+
+static void xfce_sm_client_set_clone_restart_commands(XfceSMClient *sm_client);
+
+
+static IceIOErrorHandler xsmp_ice_installed_handler = NULL;
+
+
+/* This is called when data is available on an ICE connection. */
+static gboolean
+xsmp_process_ice_messages(GIOChannel *channel,
+ GIOCondition condition,
+ gpointer client_data)
+{
+ IceConn connection = (IceConn)client_data;
+ IceProcessMessagesStatus status;
+
+ status = IceProcessMessages(connection, NULL, NULL);
+ if(status == IceProcessMessagesIOError) {
+ g_warning("Disconnected from session manager.");
+ /* We were disconnected */
+ IceSetShutdownNegotiation(connection, False);
+ IceCloseConnection(connection);
+ }
+
+ return TRUE;
+}
+
+/* This is called when a new ICE connection is made. It arranges for
+ the ICE connection to be handled via the event loop. */
+static void
+xsmp_new_ice_connection(IceConn connection,
+ IcePointer client_data,
+ Bool opening,
+ IcePointer *watch_data)
+{
+ guint input_id;
+
+ if(opening) {
+ /* Make sure we don't pass on these file descriptors to any
+ * exec'ed children
+ */
+ GIOChannel *channel;
+
+ fcntl(IceConnectionNumber(connection), F_SETFD,
+ fcntl(IceConnectionNumber(connection), F_GETFD) | FD_CLOEXEC);
+
+ channel = g_io_channel_unix_new(IceConnectionNumber(connection));
+
+ input_id = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
+ xsmp_process_ice_messages, connection);
+
+ g_io_channel_unref(channel);
+
+ *watch_data = (IcePointer)GUINT_TO_POINTER(input_id);
+ } else {
+ input_id = GPOINTER_TO_UINT((gpointer)*watch_data);
+
+ g_source_remove(input_id);
+ }
+}
+
+static void
+xsmp_ice_io_error_handler(IceConn connection)
+{
+ g_warning("ICE I/O Error");
+
+ if(xsmp_ice_installed_handler)
+ xsmp_ice_installed_handler(connection);
+}
+
+static void
+xsmp_ice_init(void)
+{
+ static gsize inited = 0;
+
+ if(g_once_init_enter(&inited)) {
+ IceIOErrorHandler default_handler;
+
+ xsmp_ice_installed_handler = IceSetIOErrorHandler(NULL);
+ default_handler = IceSetIOErrorHandler(xsmp_ice_io_error_handler);
+
+ if(xsmp_ice_installed_handler == default_handler)
+ xsmp_ice_installed_handler = NULL;
+
+ IceAddConnectionWatch(xsmp_new_ice_connection, NULL);
+
+ g_once_init_leave(&inited, 1);
+ }
+}
+
+static void
+xfce_sm_client_handle_save_yourself(XfceSMClient *sm_client,
+ gboolean do_quit_requested,
+ int dialog_type,
+ gboolean do_save_state)
+{
+ if(do_quit_requested
+ && g_signal_has_handler_pending(G_OBJECT(sm_client),
+ signals[SIG_QUIT_REQUESTED],
+ 0, FALSE))
+ {
+ Status status;
+
+ status = SmcInteractRequest(sm_client->priv->session_connection,
+ dialog_type, xsmp_interact,
+ (SmPointer)sm_client);
+
+ if(status) {
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_WAITING_FOR_INTERACT);
+ sm_client->priv->needs_save_state = do_save_state;
+ /* we want save-state to happen *after* quit-requested if we're
+ * doing both, but we can't do quit-requested until we hear
+ * about our interact request */
+ return;
+ } else {
+ /* if the interact request failed, fall through and at least
+ * attempt to save state below if appropriate */
+ g_warning("SmcInteractRequest failed!");
+ }
+ }
+
+ if(do_save_state)
+ g_signal_emit(G_OBJECT(sm_client), signals[SIG_SAVE_STATE], 0, NULL);
+
+ if(sm_client->priv->shutdown_cancelled) {
+ /* this is a slightly bizarre case that probably won't happen.
+ * if we got to this point, then we didn't do quit-requested,
+ * but the system was shutting down, and then it was later
+ * cancelled. since we never did a quit-requested, the client
+ * probably won't expect a quit-cancelled, so we do nothing here. */
+ sm_client->priv->shutdown_cancelled = FALSE;
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_IDLE);
+ } else {
+ /* otherwise, we're just done with the SaveYourself here */
+ SmcSaveYourselfDone(sm_client->priv->session_connection, True);
+ /* the XSMP spec state diagram says to go right back to IDLE after a
+ * non-shutdown SaveYourself, but everything else in the spec disagrees:
+ * we need to wait for a SaveComplete before going back to IDLE */
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_FROZEN);
+ }
+}
+
+static void
+xsmp_save_phase_2(SmcConn smc_conn,
+ SmPointer client_data)
+{
+ XfceSMClient *sm_client = XFCE_SM_CLIENT(client_data);
+
+ TRACE("entering");
+
+ /* As a simplification, we won't support interacting in save phase 2,
+ * even though XSMP allows an interact request (errors only) from
+ * phase 2. In our SM client's terminolgy, we support save-state
+ * but not quit-requested for phase 2. */
+
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_SAVING_PHASE_2);
+
+ g_signal_emit(G_OBJECT(sm_client), signals[SIG_SAVE_STATE_EXTENDED], 0, NULL);
+
+ SmcSaveYourselfDone(sm_client->priv->session_connection, True);
+ /* the XSMP spec state diagram says to go right back to IDLE after a
+ * non-shutdown SaveYourself, but everything else in the spec disagrees:
+ * we need to wait for a SaveComplete before going back to IDLE */
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_FROZEN);
+
+ if(sm_client->priv->shutdown_cancelled) {
+ /* if we get here, we received ShutdownCancelled while in a recursive
+ * invocation of the main loop in save-state-extended. in this case, we
+ * go back to idle and send quit-cancelled. */
+ sm_client->priv->shutdown_cancelled = FALSE;
+
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_IDLE);
+ g_signal_emit(G_OBJECT(sm_client), signals[SIG_QUIT_CANCELLED], 0,
+ NULL);
+ }
+}
+
+static void
+xsmp_save_yourself(SmcConn smc_conn,
+ SmPointer client_data,
+ int save_style,
+ Bool shutdown,
+ int interact_style,
+ Bool fast)
+{
+ XfceSMClient *sm_client = XFCE_SM_CLIENT(client_data);
+ gboolean do_save_state, do_quit_requested;
+
+ TRACE("entering (save_style=%s, shutdown=%s, interact_style=%s, fast=%s",
+ save_style == SmSaveGlobal ? "global" : (save_style == SmSaveLocal ? "local" : "both"),
+ shutdown ? "true" : "false",
+ interact_style == SmInteractStyleNone ? "none" : (interact_style == SmInteractStyleErrors ? "errors" : "any"),
+ fast ? "true" : "false");
+
+ /* The first SaveYourself after registering for the first time
+ * is a special case (SM specs 7.2).
+ */
+ if(sm_client->priv->state == XFCE_SM_CLIENT_STATE_REGISTERING) {
+ if(save_style == SmSaveLocal
+ && interact_style == SmInteractStyleNone
+ && !shutdown
+ && !fast)
+ {
+ xfce_sm_client_set_clone_restart_commands(sm_client);
+ SmcSaveYourselfDone(sm_client->priv->session_connection, True);
+ /* XSMP spec state diagram says idle, but the rest of the spec disagrees */
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_FROZEN);
+ } else {
+ g_warning("Initial SaveYourself had unexpected parameters");
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_IDLE);
+ }
+
+ return;
+ }
+
+ if(sm_client->priv->state != XFCE_SM_CLIENT_STATE_IDLE) {
+ g_warning("Got SaveYourself while in phase %s, ignoring",
+ str_from_state(sm_client->priv->state));
+ SmcSaveYourselfDone(sm_client->priv->session_connection, True);
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_FROZEN);
+ return;
+ }
+
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_SAVING_PHASE_1);
+
+ /* Most of this logic is taken from EggSMClient. There are many
+ * combinations of parameters to the SaveYourself request, but we're
+ * going to boil them down to a few possibilities:
+ *
+ * 1. Do nothing if:
+ * a) Global save and we're not shutting down, as this is
+ * somewhat pointless.
+ * b) Global save and we're shutting down, but the SM isn't
+ * going to let us interact, because we can't do anything
+ * anyway.
+ * 2. Emit save-state if:
+ * a) Local (or Both) save and we're not shutting down. We
+ * ignore the Global part of the Both save since prompting
+ * to save files when not shutting down is stupid.
+ * b) Local (or Both) save and we *are* shutting down, but
+ * aren't allowed to interact. Here a save-state is just
+ * the best we can do. We ignore the Global part of a
+ * Both save because it's unlikely we can (or should) save
+ * without user interaction.
+ * 3. Emit quit-requested if:
+ * a) Global save, we're shutting down, and we're allowed to
+ * interact.
+ * 4. Emit quit-requested followed by save-state if:
+ * a) Local or Both save, we're shutting down, and we're
+ * allowed to interact. If it's a Local save, we promote
+ * it to a Both save since shutting down without asking
+ * the user to save their work when it's allowed is rude.
+ *
+ * We ignore the 'fast' parameter. I really don't expect any
+ * client to do anything differently based on its value.
+ */
+
+ do_quit_requested = (shutdown && interact_style != SmInteractStyleNone);
+ do_save_state = (save_style != SmSaveGlobal);
+
+ xfce_sm_client_handle_save_yourself(sm_client, do_quit_requested,
+ (interact_style == SmInteractStyleAny
+ ? SmDialogNormal : SmDialogError),
+ do_save_state);
+}
+
+static void
+xsmp_die(SmcConn smc_conn,
+ SmPointer client_data)
+{
+ XfceSMClient *sm_client = XFCE_SM_CLIENT(client_data);
+
+ TRACE("entering");
+
+ xfce_sm_client_disconnect(sm_client);
+
+ /* here we give the app a chance to gracefully quit. if the app
+ * has indicated it doesn't want to (by not connecting to the quit
+ * signal), then we force the exit here. */
+
+ if(g_signal_has_handler_pending(G_OBJECT(sm_client), signals[SIG_QUIT],
+ 0, FALSE))
+ {
+ g_signal_emit(G_OBJECT(sm_client), signals[SIG_QUIT], 0, NULL);
+ } else
+ exit(0);
+}
+
+static void
+xsmp_save_complete(SmcConn smc_conn,
+ SmPointer client_data)
+{
+ XfceSMClient *sm_client = XFCE_SM_CLIENT(client_data);
+
+ TRACE("entering");
+
+ if(sm_client->priv->state != XFCE_SM_CLIENT_STATE_FROZEN)
+ g_warning("Got SaveComplete in unexpected state");
+
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_IDLE);
+}
+
+static void
+xsmp_shutdown_cancelled(SmcConn smc_conn,
+ SmPointer client_data)
+{
+ XfceSMClient *sm_client = XFCE_SM_CLIENT(client_data);
+
+ TRACE("entering");
+
+ switch(sm_client->priv->state) {
+ case XFCE_SM_CLIENT_STATE_FROZEN:
+ case XFCE_SM_CLIENT_STATE_WAITING_FOR_PHASE_2:
+ /* if the client has already handled quit-requested, we just go
+ * back to idle and inform the client that shutdown was
+ * cancelled. */
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_IDLE);
+ g_signal_emit(G_OBJECT(sm_client), signals[SIG_QUIT_CANCELLED],
+ 0, NULL);
+ break;
+
+ case XFCE_SM_CLIENT_STATE_WAITING_FOR_INTERACT:
+ /* if we're waiting to interact (thus waiting to send
+ * quit-requested), we just cancel that, and in this case we finish
+ * the SaveYourself and move on. we don't inform the client of
+ * the cancellation since we haven't gotten to inform them about
+ * the shutdown in the first place. */
+ SmcSaveYourselfDone(sm_client->priv->session_connection, True);
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_IDLE);
+ break;
+
+ case XFCE_SM_CLIENT_STATE_INTERACTING:
+ case XFCE_SM_CLIENT_STATE_SAVING_PHASE_1:
+ case XFCE_SM_CLIENT_STATE_SAVING_PHASE_2:
+ /* this should only happen if the client is currently *inside* one
+ * of the quit-requested, save-state, or save-state-extended
+ * handlers and is presumably inside a recursive invocation of the
+ * main loop. we shouldn't inform them of anything just yet, but
+ * we'll set a flag so we can do so when they return. */
+ sm_client->priv->shutdown_cancelled = TRUE;
+ break;
+
+ default:
+ g_warning("got ShutdownCancelled while in unexpected state");
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_IDLE);
+ break;
+ }
+}
+
+static void
+xsmp_interact(SmcConn smc_conn,
+ SmPointer client_data)
+{
+ XfceSMClient *sm_client = XFCE_SM_CLIENT(client_data);
+ gboolean cancel = FALSE;
+
+ TRACE("entering");
+
+ /* since we don't support interacting during phase 2, the only time
+ * we should receive an interact message is during a normal save
+ * yourself. */
+
+ if(sm_client->priv->state != XFCE_SM_CLIENT_STATE_WAITING_FOR_INTERACT) {
+ g_warning("Got Interact message when not waiting for one");
+ /* FIXME: not sure if this is the best response to this. we might
+ * want to actually go through with sending quit-requested etc. */
+ SmcInteractDone(sm_client->priv->session_connection, False);
+ SmcSaveYourselfDone(sm_client->priv->session_connection, True);
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_FROZEN);
+ return;
+ }
+
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_INTERACTING);
+
+ /* at this point we're ready to emit quit-requested */
+ g_signal_emit(G_OBJECT(sm_client), signals[SIG_QUIT_REQUESTED], 0,
+ &cancel);
+
+ if(sm_client->priv->shutdown_cancelled) {
+ /* if we get here, we received ShutdownCancelled while in a recursive
+ * invocation of the main loop in quit-requested. in this case, we
+ * go back to idle and send quit-cancelled. */
+ sm_client->priv->shutdown_cancelled = FALSE;
+ cancel = TRUE;
+
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_IDLE);
+ g_signal_emit(G_OBJECT(sm_client), signals[SIG_QUIT_CANCELLED], 0,
+ NULL);
+ } else {
+ /* we only send InteractDone if we didn't get ShutdownCancelled */
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_FROZEN);
+ SmcInteractDone(sm_client->priv->session_connection, cancel);
+ }
+
+ if(cancel) {
+ /* if we requested (or got) a shutdown cancellation, we skip the
+ * save-state signal. */
+ sm_client->priv->needs_save_state = FALSE;
+ } else if(sm_client->priv->needs_save_state) {
+ /* if we still have a pending save-state, send that now */
+ sm_client->priv->needs_save_state = FALSE;
+ g_signal_emit(G_OBJECT(sm_client), signals[SIG_SAVE_STATE], 0, NULL);
+
+ if(sm_client->priv->shutdown_cancelled) {
+ /* this is exceedingly unlikely, but it could happen here too */
+ sm_client->priv->shutdown_cancelled = FALSE;
+ cancel = TRUE;
+
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_IDLE);
+ g_signal_emit(G_OBJECT(sm_client), signals[SIG_QUIT_CANCELLED], 0,
+ NULL);
+ }
+ }
+
+ /* if the app also wants a phase 2 save, we request it now */
+ if(!cancel && g_signal_has_handler_pending(G_OBJECT(sm_client),
+ signals[SIG_SAVE_STATE_EXTENDED],
+ 0, FALSE))
+ {
+ Status status;
+
+ status = SmcRequestSaveYourselfPhase2(sm_client->priv->session_connection,
+ xsmp_save_phase_2,
+ (SmPointer)sm_client);
+ if(status) {
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_WAITING_FOR_PHASE_2);
+ return;
+ }
+ }
+
+ /* finally, signal to the SM that we're done. we also fall through and
+ * bail to this if a phase2 request failed for some reason. */
+ SmcSaveYourselfDone(sm_client->priv->session_connection, True);
+}
+
+static void
+xfce_sm_client_set_property_from_command(XfceSMClient *sm_client,
+ const char *property_name,
+ gchar **command,
+ gint alter_sm_id)
+{
+ SmProp prop, *props[1];
+ gchar **args;
+ gint i;
+ gint argc;
+ SmPropValue *vals;
+
+ if(!command || !sm_client->priv->session_connection)
+ return;
+
+ args = command;
+ for(argc = 0; *args; args++) {
+ if(alter_sm_id == SM_ARG_APPEND
+ && !g_ascii_strncasecmp(*args, SM_ID_ARG, strlen(SM_ID_ARG)))
+ {
+ alter_sm_id = FALSE;
+ }
+ argc++;
+ }
+
+ if(alter_sm_id == SM_ARG_APPEND)
+ argc += 2;
+ vals = g_new(SmPropValue, argc);
+
+ i = 0;
+ while(*command) {
+ if(alter_sm_id == SM_ARG_REMOVE
+ && !g_ascii_strncasecmp(*command, SM_ID_ARG, strlen(SM_ID_ARG)))
+ {
+ /* skip the argument after SM_ID_ARG */
+ if(command[1])
+ command++;
+ } else {
+ vals[i].length = strlen(*command);
+ vals[i++].value = *command;
+ }
+ command++;
+ }
+
+ if(alter_sm_id == SM_ARG_APPEND) {
+ vals[i].length = strlen(SM_ID_ARG);
+ vals[i++].value = SM_ID_ARG;
+ vals[i].length = strlen(sm_client->priv->client_id);
+ vals[i++].value = sm_client->priv->client_id;
+ }
+
+ prop.name = (char *)property_name;
+ prop.type = SmLISTofARRAY8;
+ prop.vals = vals;
+ prop.num_vals = i;
+
+ props[0] = ∝
+ SmcSetProperties(sm_client->priv->session_connection, 1, props);
+ g_free(vals);
+}
+
+static void
+xfce_sm_client_set_clone_restart_commands(XfceSMClient *sm_client)
+{
+ /* Restart */
+ xfce_sm_client_set_property_from_command(sm_client, SmRestartCommand,
+ sm_client->priv->restart_command,
+ SM_ARG_APPEND);
+
+ /* Clone */
+ xfce_sm_client_set_property_from_command(sm_client, SmCloneCommand,
+ (sm_client->priv->clone_command
+ ? sm_client->priv->clone_command
+ : sm_client->priv->restart_command),
+ SM_ARG_REMOVE);
+
+ /* Resign */
+ xfce_sm_client_set_property_from_command(sm_client, SmResignCommand,
+ sm_client->priv->resign_command,
+ FALSE);
+
+ /* Discard */
+ xfce_sm_client_set_property_from_command(sm_client, SmDiscardCommand,
+ sm_client->priv->discard_command,
+ FALSE);
+
+ /* Shutdown */
+ xfce_sm_client_set_property_from_command(sm_client, SmShutdownCommand,
+ sm_client->priv->shutdown_command,
+ FALSE);
+}
+
+#endif
+
+
+/**
+ * xfce_sm_client_get_option_group:
+ * @argc: The application's argument count
+ * @argv: The application's argument vector
+ *
+ * Constructs a #GOptionGroup suitable for using with Glib's
+ * command-line option parser, whether it is being used directly,
+ * or indirectly via gtk_init_with_args() or similar.
+ *
+ * This function is a bit sneaky in that it will make a copy of
+ * the program's argc and argv *before* gtk_init() etc. has a chance
+ * to mess around with it, so #XfceSMClient can later construct an
+ * accurate restart command.
+ *
+ * Returns: A new #GOptionGroup
+ **/
+GOptionGroup *
+xfce_sm_client_get_option_group(guint argc,
+ gchar **argv)
+{
+ const GOptionEntry entries[] = {
+ { "sm-client-id", 0, 0, G_OPTION_ARG_STRING, &startup_options.client_id, N_("Session management client ID"), N_("ID") },
+ { "sm-client-disable", 0, 0, G_OPTION_ARG_NONE, &startup_options.sm_disable, N_("Disable session management"), NULL },
+ { NULL, },
+ };
+ GOptionGroup *group = NULL;
+
+ startup_options.argc = argc;
+ g_strfreev(startup_options.argv);
+ if(argv)
+ startup_options.argv = g_strdupv(argv);
+
+ group = g_option_group_new("sm-client", _("Session management options"),
+ _("Show session management options"), NULL,
+ NULL);
+ g_option_group_add_entries(group, entries);
+ g_option_group_set_translation_domain(group, GETTEXT_PACKAGE);
+
+ return group;
+}
+
+/**
+ * xfce_sm_client_get:
+ *
+ * Gets the application's SM client instance. This is best
+ * used with xfce_sm_client_get_option_group() above (and using
+ * the returned #GOptionGroup with g_option_context_parse()), as the
+ * command line parsing will figure out many of the SM client's
+ * required property values for you.
+ *
+ * If you are not using Gtk or Glib's command-line option parser,
+ * take a look at xfce_sm_client_new_with_argv() and
+ * xfce_sm_client_new_full().
+ *
+ * If you have already created an #XfceSMClient instance using
+ * this function or one of the xfce_sm_client_new_*() functions,
+ * this will return the same instance.
+ *
+ * Returns: A new or existing #XfceSMClient
+ **/
+XfceSMClient *
+xfce_sm_client_get()
+{
+ return g_object_new(XFCE_TYPE_SM_CLIENT,
+ "argc", startup_options.argc,
+ "argv", startup_options.argv,
+ "client-id", startup_options.client_id,
+ NULL);
+}
+
+/**
+ * xfce_sm_client_new_with_argv:
+ * @argc: The number of arguments passed to main()
+ * @argv: The argument vector passed to main()
+ * @restart_style: An #XfceSMClientRestartStyle
+ * @priority: A restart priority
+ *
+ * Creates a new #XfceSMClient instance. It attempts to
+ * set all required properties using the app's command line.
+ * Note that this function does not actually connect to the session
+ * manager, so other actions can be taken (such as setting custom
+ * properties or connecting signals) before calling
+ * xfce_sm_client_connect().
+ *
+ * If you are using Gtk or Glib's command-line option parser,
+ * it is recommended that you use xfce_sm_client_get_option_group()
+ * and xfce_sm_client_get() instead.
+ *
+ * Returns: A new #XfceSMClient instance
+ **/
+XfceSMClient *
+xfce_sm_client_new_with_argv(guint argc,
+ gchar **argv,
+ XfceSMClientRestartStyle restart_style,
+ gchar priority)
+{
+ return g_object_new(XFCE_TYPE_SM_CLIENT,
+ "argc", argc,
+ "argv", argv,
+ "restart-style", restart_style,
+ "priority", priority,
+ NULL);
+}
+
+/**
+ * xfce_sm_client_get_full:
+ * @restart_style: An XfceSMClientRestartStyle
+ * @priority: A restart priority
+ * @resumed_client_id: The client id used in the previous session
+ * @program: A program identifier string
+ * @current_directory: The application's working directory
+ * @restart_command: A command that can resume the application's
+ * saved state
+ * @clone_command: A command that can start a fresh copy of the
+ * application
+ * @discard_command: A command that cleans up the application's
+ * state when removed from the session
+ * @resign_command: A command that cleans up the application's
+ * state when removed from restart-always state
+ * @shutdown_command: A command run on shutdown for applications
+ * with the restart-always style
+ *
+ * Creates a new SM client instance, allowing the application
+ * fine-grained control over the initial properties set.
+ * Note that this function does not actually connect to the session
+ * manager, so other actions can be taken (such as setting custom
+ * properties or connecting signals) before calling
+ * xfce_sm_client_connect().
+ *
+ * It is recommended to use xfce_sm_client_get_with_argv(), or,
+ * if you are using Gtk or Glib's command-line option parser,
+ * xfce_sm_client_get_option_group() and xfce_sm_client_get() instead.
+ *
+ * Returns: A new #XfceSMClient instance
+ **/
+XfceSMClient *
+xfce_sm_client_new_full(XfceSMClientRestartStyle restart_style,
+ gchar priority,
+ const gchar *resumed_client_id,
+ const gchar *program,
+ const gchar *current_directory,
+ const gchar **restart_command,
+ const gchar **clone_command,
+ const gchar **discard_command,
+ const gchar **resign_command,
+ const gchar **shutdown_command)
+{
+ return g_object_new(XFCE_TYPE_SM_CLIENT,
+ "restart-style", restart_style,
+ "priority", priority,
+ "client-id", resumed_client_id,
+ "program", program,
+ "current-directory", current_directory,
+ "restart-command", restart_command,
+ "clone-command", clone_command,
+ "resign-command", resign_command,
+ "shutdown-command", shutdown_command,
+ NULL);
+}
+
+/**
+ * xfce_sm_client_connect:
+ * @sm_client: An #XfceSMClient
+ * @error: A #GError location.
+ *
+ * Attempts to connect to the session manager.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise. If an error
+ * occurs, @error will be set.
+ **/
+gboolean
+xfce_sm_client_connect(XfceSMClient *sm_client,
+ GError **error)
+{
+#ifdef HAVE_LIBSM
+ char buf[256] = "";
+ unsigned long mask;
+ SmcCallbacks callbacks;
+ SmProp prop1, prop2, prop3, prop4, prop5, prop6, *props[6];
+ SmPropValue prop1val, prop2val, prop3val, prop4val, prop5val, prop6val;
+ char pid[32];
+ char hint = SmRestartIfRunning;
+ char priority = sm_client->priv->priority;
+ char *given_client_id = NULL;
+#endif
+
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), FALSE);
+ g_return_val_if_fail(!error || !*error, FALSE);
+
+ if(startup_options.sm_disable)
+ return TRUE;
+
+#ifdef HAVE_LIBSM
+ xsmp_ice_init();
+
+ mask = SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask
+ | SmcShutdownCancelledProcMask;
+
+ callbacks.save_yourself.callback = xsmp_save_yourself;
+ callbacks.save_yourself.client_data = (SmPointer)sm_client;
+
+ callbacks.die.callback = xsmp_die;
+ callbacks.die.client_data = (SmPointer)sm_client;
+
+ callbacks.save_complete.callback = xsmp_save_complete;
+ callbacks.save_complete.client_data = (SmPointer)sm_client;
+
+ callbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
+ callbacks.shutdown_cancelled.client_data = (SmPointer)sm_client;
+
+ sm_client->priv->session_connection = SmcOpenConnection(NULL, NULL,
+ SmProtoMajor,
+ SmProtoMinor,
+ mask,
+ &callbacks,
+ (char *)sm_client->priv->client_id,
+ &given_client_id,
+ sizeof(buf)-1,
+ buf);
+
+ if(!sm_client->priv->session_connection) {
+ if(error) {
+ /* FIXME: error domain/code */
+ g_set_error(error, 0, 1,
+ _("Failed to connect to the session manager: %s"), buf);
+ }
+ return FALSE;
+ } else if(!given_client_id) {
+ if(error) {
+ /* FIXME: error domain/code */
+ g_set_error(error, 0, 1,
+ _("Session manager did not return a valid client id"));
+ }
+ return FALSE;
+ }
+
+ if(sm_client->priv->client_id
+ && !strcmp(sm_client->priv->client_id, given_client_id))
+ {
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_IDLE);
+ sm_client->priv->resumed = TRUE;
+ g_object_notify(G_OBJECT(sm_client), "resumed");
+ } else {
+ xfce_sm_client_set_client_id(sm_client, given_client_id);
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_REGISTERING);
+ }
+
+ free(given_client_id);
+
+ gdk_set_sm_client_id(sm_client->priv->client_id);
+
+ hint = xsmp_restart_style_from_enum(sm_client->priv->restart_style);
+
+ prop1.name = SmProgram;
+ prop1.type = SmARRAY8;
+ prop1.num_vals = 1;
+ prop1.vals = &prop1val;
+ prop1val.value = sm_client->priv->program;
+ prop1val.length = strlen(sm_client->priv->program);
+
+ prop2.name = SmUserID;
+ prop2.type = SmARRAY8;
+ prop2.num_vals = 1;
+ prop2.vals = &prop2val;
+ prop2val.value = (char *)g_get_user_name();
+ prop2val.length = strlen(prop2val.value);
+
+ prop3.name = SmRestartStyleHint;
+ prop3.type = SmCARD8;
+ prop3.num_vals = 1;
+ prop3.vals = &prop3val;
+ prop3val.value = &hint;
+ prop3val.length = 1;
+
+ g_snprintf(pid, sizeof(pid), "%d", getpid());
+ prop4.name = SmProcessID;
+ prop4.type = SmARRAY8;
+ prop4.num_vals = 1;
+ prop4.vals = &prop4val;
+ prop4val.value = pid;
+ prop4val.length = strlen(prop4val.value);
+
+ prop5.name = SmCurrentDirectory;
+ prop5.type = SmARRAY8;
+ prop5.num_vals = 1;
+ prop5.vals = &prop5val;
+ if(sm_client->priv->current_directory)
+ prop5val.value = (char *)sm_client->priv->current_directory;
+ else
+ prop5val.value = (char *)xfce_get_homedir();
+ prop5val.length = strlen(prop5val.value);
+
+ prop6.name = "_GSM_Priority";
+ prop6.type = SmCARD8;
+ prop6.num_vals = 1;
+ prop6.vals = &prop6val;
+ prop6val.value = &priority;
+ prop6val.length = 1;
+
+ props[0] = &prop1;
+ props[1] = &prop2;
+ props[2] = &prop3;
+ props[3] = &prop4;
+ props[4] = &prop5;
+ props[5] = &prop6;
+
+ SmcSetProperties(sm_client->priv->session_connection, 6, props);
+
+ g_object_notify(G_OBJECT(sm_client), "session-connection");
+#endif
+
+ return TRUE;
+}
+
+/**
+ * xfce_sm_client_disconnect:
+ * @sm_client: An #XfceSMClient
+ *
+ * Disconnects the application from the session manager.
+ *
+ * Note: This may not remove the application from the saved
+ * session (if any) if the user later does not choose to save
+ * the session when logging out.
+ *
+ **/
+void
+xfce_sm_client_disconnect(XfceSMClient *sm_client)
+{
+ if(startup_options.sm_disable)
+ return;
+
+#ifdef HAVE_LIBSM
+ if(G_UNLIKELY(!sm_client->priv->session_connection)) {
+ g_warning("%s() called with no session connection", G_STRFUNC);
+ return;
+ }
+
+ if(sm_client->priv->restart_style == XFCE_SM_CLIENT_RESTART_IMMEDIATELY)
+ xfce_sm_client_set_restart_style(sm_client, XFCE_SM_CLIENT_RESTART_IF_RUNNING);
+
+ SmcCloseConnection(sm_client->priv->session_connection, 0, NULL);
+ sm_client->priv->session_connection = NULL;
+ gdk_set_sm_client_id(NULL);
+
+ g_object_notify(G_OBJECT(sm_client), "session-connection");
+ xfce_sm_client_set_state(sm_client, XFCE_SM_CLIENT_STATE_DISCONNECTED);
+#endif
+}
+
+/**
+ * xfce_sm_client_is_resumed:
+ * @sm_client: An #XfceSMClient
+ *
+ * Determines whether the application was resumed from a previous
+ * session, or if the application has been started fresh with no
+ * state information associated with it.
+ *
+ * Returns: %TRUE if resumed from a previous session, %FALSE otherwise
+ **/
+gboolean
+xfce_sm_client_is_resumed(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), FALSE);
+ return sm_client->priv->resumed;
+}
+
+/**
+ * xfce_sm_client_request_shutdown:
+ * @sm_client: An #XfceSMClient
+ * @shutdown_hint: The type of shutdown requested
+ *
+ * Sends a request to the session manager to end the session.
+ * Depending on @hint, the session manager may prompt for a
+ * certain action (log out, halt, reboot, etc.) or may take the
+ * requested action without user intervention.
+ *
+ * Note: The session manager may or may not support all requested
+ * actions, and is also free to ignore the requested action.
+ **/
+void
+xfce_sm_client_request_shutdown(XfceSMClient *sm_client,
+ XfceSMClientShutdownHint shutdown_hint)
+{
+ g_return_if_fail(XFCE_IS_SM_CLIENT(sm_client));
+
+ if(startup_options.sm_disable)
+ return;
+
+ /* TODO: support xfce4-session's DBus interface */
+
+#ifdef HAVE_LIBSM
+ if(G_LIKELY(sm_client->priv->session_connection)) {
+ SmcRequestSaveYourself(sm_client->priv->session_connection, SmSaveBoth,
+ True, SmInteractStyleAny, False, True);
+ }
+#endif
+}
+
+/**
+ * xfce_sm_client_set_restart_style:
+ * @sm_client: An #XfceSMClient
+ * @restart_style: An #XfceSMClientRestartStyle value
+ *
+ * Sets the restart style hint to @restart_style.
+ **/
+void
+xfce_sm_client_set_restart_style(XfceSMClient *sm_client,
+ XfceSMClientRestartStyle restart_style)
+{
+ g_return_if_fail(XFCE_IS_SM_CLIENT(sm_client));
+
+ if(sm_client->priv->restart_style == restart_style)
+ return;
+
+ sm_client->priv->restart_style = restart_style;
+
+#ifdef HAVE_LIBSM
+ if(sm_client->priv->session_connection) {
+ SmProp prop, *props[1];
+ SmPropValue propval;
+ char hint;
+
+ hint = xsmp_restart_style_from_enum(sm_client->priv->restart_style);
+
+ prop.name = SmRestartStyleHint;
+ prop.type = SmCARD8;
+ prop.num_vals = 1;
+ prop.vals = &propval;
+ propval.value = &hint;
+ propval.length = 1;
+ props[0] = ∝
+
+ SmcSetProperties(sm_client->priv->session_connection, 1, props);
+ }
+#endif /* HAVE_LIBSM */
+
+ g_object_notify(G_OBJECT(sm_client), "restart-style");
+}
+
+/**
+ * xfce_sm_client_set_priority:
+ * @sm_client: An #XfceSMClient
+ * @priority: A 8-bit signed priority value
+ *
+ * Sets the startup priority for @sm_client to @priority. Note
+ * that the default priority for applications is 50; lower values
+ * should be reserved for components of the desktop environment.
+ **/
+void
+xfce_sm_client_set_priority(XfceSMClient *sm_client,
+ gchar priority)
+{
+ g_return_if_fail(XFCE_IS_SM_CLIENT(sm_client));
+
+ if(sm_client->priv->priority == priority)
+ return;
+
+ sm_client->priv->priority = priority;
+
+#ifdef HAVE_LIBSM
+ if(sm_client->priv->session_connection) {
+ SmProp prop, *props[1];
+ SmPropValue propval;
+
+ prop.name = "_GSM_Priority";
+ prop.type = SmCARD8;
+ prop.num_vals = 1;
+ prop.vals = &propval;
+ propval.value = &sm_client->priv->priority;
+ propval.length = 1;
+ props[0] = ∝
+
+ SmcSetProperties(sm_client->priv->session_connection, 1, props);
+ }
+#endif /* HAVE_LIBSM */
+
+ g_object_notify(G_OBJECT(sm_client), "priority");
+}
+
+/**
+ * xfce_sm_client_set_current_directory:
+ * @sm_client: An #XfceSMClient
+ * @current_directory: A valid path name
+ *
+ * Sets the startup working directory of @sm_client to
+ * @current_directory. If unset, defaults to the user's
+ * home directory.
+ **/
+void
+xfce_sm_client_set_current_directory(XfceSMClient *sm_client,
+ const gchar *current_directory)
+{
+ g_return_if_fail(XFCE_IS_SM_CLIENT(sm_client));
+
+ if(!xfce_safe_strcmp(sm_client->priv->current_directory, current_directory))
+ return;
+
+ if(!current_directory)
+ current_directory = xfce_get_homedir();
+
+ g_free(sm_client->priv->current_directory);
+ sm_client->priv->current_directory = g_strdup(current_directory);
+
+#ifdef HAVE_LIBSM
+ if(sm_client->priv->session_connection) {
+ SmProp prop, *props[1];
+ SmPropValue propval;
+
+ prop.name = SmCurrentDirectory;
+ prop.type = SmARRAY8;
+ prop.num_vals = 1;
+ prop.vals = &propval;
+ propval.value = sm_client->priv->current_directory;
+ propval.length = strlen(propval.value);
+ props[0] = ∝
+
+ SmcSetProperties(sm_client->priv->session_connection, 1, props);
+ }
+#endif /* HAVE_LIBSM */
+
+ g_object_notify(G_OBJECT(sm_client), "current-directory");
+}
+
+/**
+ * xfce_sm_client_set_program:
+ * @sm_client: An XfceSMClient
+ * @program: A program identifier string
+ *
+ * Sets an identifier string for your application. This string is not
+ * intended to be user-visible, but in some cases may be, so it may be
+ * useful to use something that isn't totally incomprehensible. If
+ * unset, it will default to the value returned by g_get_prgname().
+ **/
+void
+xfce_sm_client_set_program(XfceSMClient *sm_client,
+ const gchar *program)
+{
+ g_return_if_fail(XFCE_IS_SM_CLIENT(sm_client));
+
+ if(!xfce_safe_strcmp(sm_client->priv->program, program))
+ return;
+
+ if(!program)
+ program = g_get_prgname() ? g_get_prgname() : "<unknown program>";
+
+ g_free(sm_client->priv->program);
+ sm_client->priv->program = g_strdup(program);
+
+#ifdef HAVE_LIBSM
+ if(sm_client->priv->session_connection) {
+ SmProp prop, *props[1];
+ SmPropValue propval;
+
+ prop.name = SmProgram;
+ prop.type = SmARRAY8;
+ prop.num_vals = 1;
+ prop.vals = &propval;
+ propval.value = sm_client->priv->program;
+ propval.length = strlen(sm_client->priv->program);
+
+ SmcSetProperties(sm_client->priv->session_connection, 1, props);
+ }
+#endif /* HAVE_LIBSM */
+
+ g_object_notify(G_OBJECT(sm_client), "program");
+}
+
+static gchar **
+copy_command(gchar **command,
+ gchar **value)
+{
+ if(command != value) {
+ g_strfreev(command);
+ command = NULL;
+ }
+
+ if(value)
+ command = g_strdupv(value);
+
+ return command;
+}
+
+/**
+ * xfce_sm_client_set_clone_command:
+ * @sm_client: An #XfceSMClient
+ * @clone_command: An argument vector
+ *
+ * Sets the application's "clone" command, which is used to start
+ * a fresh copy of the application, without restoring any state
+ * from a previous run.
+ *
+ * If unset, this will default to the restart command, with
+ * any session management related arguments removed.
+ **/
+void
+xfce_sm_client_set_clone_command(XfceSMClient *sm_client,
+ gchar **clone_command)
+{
+ g_return_if_fail(XFCE_IS_SM_CLIENT(sm_client));
+ sm_client->priv->clone_command = copy_command(sm_client->priv->clone_command,
+ clone_command);
+#ifdef HAVE_LIBSM
+ xfce_sm_client_set_property_from_command(sm_client, SmCloneCommand,
+ sm_client->priv->clone_command,
+ SM_ARG_REMOVE);
+#endif
+ g_object_notify(G_OBJECT(sm_client), "clone-command");
+}
+
+/**
+ * xfce_sm_client_set_resign_command:
+ * @sm_client: An #XfceSMClient
+ * @resign_command: An argument vector
+ *
+ * Sets the application's "resign" command, which is used to clean
+ * up saved state when an appliction with restart style "always"
+ * is removed from the session.
+ *
+ * If unset, defaults to %NULL.
+ **/
+void
+xfce_sm_client_set_resign_command(XfceSMClient *sm_client,
+ gchar **resign_command)
+{
+ g_return_if_fail(XFCE_IS_SM_CLIENT(sm_client));
+ sm_client->priv->resign_command = copy_command(sm_client->priv->resign_command,
+ resign_command);
+#ifdef HAVE_LIBSM
+ xfce_sm_client_set_property_from_command(sm_client, SmResignCommand,
+ sm_client->priv->resign_command,
+ FALSE);
+#endif
+ g_object_notify(G_OBJECT(sm_client), "resign-command");
+}
+
+/**
+ * xfce_sm_client_set_restart_command:
+ * @sm_client: An #XfceSMClient
+ * @restart_command: An argument vector
+ *
+ * Sets the application's "restart" command, which is used to restart
+ * the application and restore any saved state from the previous
+ * run.
+ *
+ * If unset, defaults to the command used to start this instance
+ * of the application, with session management related arguments
+ * added (if not already present).
+ **/
+void
+xfce_sm_client_set_restart_command(XfceSMClient *sm_client,
+ gchar **restart_command)
+{
+ g_return_if_fail(XFCE_IS_SM_CLIENT(sm_client));
+ sm_client->priv->restart_command = copy_command(sm_client->priv->restart_command,
+ restart_command);
+#ifdef HAVE_LIBSM
+ xfce_sm_client_set_property_from_command(sm_client, SmRestartCommand,
+ sm_client->priv->restart_command,
+ SM_ARG_APPEND);
+#endif
+ g_object_notify(G_OBJECT(sm_client), "restart-command");
+}
+
+/**
+ * xfce_sm_client_set_discard_command:
+ * @sm_client: An #XfceSMClient
+ * @discard_command: An argument vector
+ *
+ * Sets the application's "restart" command, which is used to restart
+ * the application and restore any saved state from the previous
+ * run.
+ *
+ * If unset, defaults to the command used to start this instance
+ * of the application, with session management related arguments
+ * added (if not already present).
+ **/
+void
+xfce_sm_client_set_discard_command(XfceSMClient *sm_client,
+ gchar **discard_command)
+{
+ g_return_if_fail(XFCE_IS_SM_CLIENT(sm_client));
+ sm_client->priv->discard_command = copy_command(sm_client->priv->discard_command,
+ discard_command);
+#ifdef HAVE_LIBSM
+ xfce_sm_client_set_property_from_command(sm_client, SmDiscardCommand,
+ sm_client->priv->discard_command,
+ FALSE);
+#endif
+ g_object_notify(G_OBJECT(sm_client), "discard-command");
+}
+
+/**
+ * xfce_sm_client_set_shutdown_command:
+ * @sm_client: An #XfceSMClient
+ * @shutdown_command: An argument vector
+ *
+ * Sets the application's "shutdown" command, which is executed for
+ * 'restart-always' style applications when the session ends.
+ *
+ * If unset, defaults to %NULL.
+ **/
+void
+xfce_sm_client_set_shutdown_command(XfceSMClient *sm_client,
+ gchar **shutdown_command)
+{
+ g_return_if_fail(XFCE_IS_SM_CLIENT(sm_client));
+ sm_client->priv->shutdown_command = copy_command(sm_client->priv->shutdown_command,
+ shutdown_command);
+#ifdef HAVE_LIBSM
+ xfce_sm_client_set_property_from_command(sm_client, SmShutdownCommand,
+ sm_client->priv->shutdown_command,
+ FALSE);
+#endif
+ g_object_notify(G_OBJECT(sm_client), "shutdown-command");
+}
+
+/**
+ * xfce_sm_client_get_state:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's state. Note that this value
+ * is very specific to the X Session Management Protocol.
+ *
+ * If the state is %XFCE_SM_CLIENT_STATE_FROZEN, the application
+ * should attempt to disallow user interaction.
+ *
+ * Returns: a value from the #XfceSMClientState enum
+ **/
+XfceSMClientState
+xfce_sm_client_get_state(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client),
+ XFCE_SM_CLIENT_STATE_DISCONNECTED);
+ return sm_client->priv->state;
+}
+
+/**
+ * xfce_sm_client_get_restart_style:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's restart style. See
+ * xfce_sm_client_set_restart_style() for more information.
+ *
+ * Returns: a value from the #XfceSMClientRestartStyle enum
+ **/
+XfceSMClientRestartStyle
+xfce_sm_client_get_restart_style(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client),
+ XFCE_SM_CLIENT_RESTART_IF_RUNNING);
+ return sm_client->priv->restart_style;
+}
+
+/**
+ * xfce_sm_client_get_priority:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's restart priority. See
+ * xfce_sm_client_set_priority() for more information.
+ *
+ * Returns: a value from #G_MININT8 to #G_MAXINT8
+ **/
+gchar
+xfce_sm_client_get_priority(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client),
+ XFCE_SM_CLIENT_PRIORITY_DEFAULT);
+ return sm_client->priv->priority;
+}
+
+/**
+ * xfce_sm_client_get_client_id:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's unique ID. This ID can
+ * be used to construct a filename used to restore the
+ * application's state. Note that this value is only
+ * guaranteed to be valid if connected to the session manager.
+ *
+ * Note: Instead of constructing a state filename, it is
+ * recommended to use xfce_sm_client_get_state_file().
+ *
+ * Returns: an opaque object-owned string
+ **/
+G_CONST_RETURN gchar *
+xfce_sm_client_get_client_id(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), NULL);
+ return sm_client->priv->client_id;
+}
+
+/**
+ * xfce_sm_client_get_state_file:
+ * @sm_client: An #XfceSMClient
+ *
+ * Constructs a filename that can be used to restore or save
+ * state information.
+ *
+ * When saving state, ote that this file may already exist (and
+ * may have been used for saving previous state for the
+ * application), so the application should first remove or empty
+ * the file if it requires a fresh state file.
+ *
+ * On the next application start, this function can be used to
+ * check to see if there is any previous saved state, and, if so,
+ * the state can be restored from the file.
+ *
+ * This function will use a standard location and naming scheme
+ * as handle state cleanup (setting of the discard command or
+ * resign command) for you.
+ *
+ * Before calling this function, the application must have a
+ * valid program identifier set (see xfce_sm_client_set_program())
+ * and a valid client ID (see xfce_sm_client_get_client_id()).
+ *
+ * Returns: a file name string, owned by the object
+ **/
+G_CONST_RETURN gchar *
+xfce_sm_client_get_state_file(XfceSMClient *sm_client)
+{
+ gchar *resource, *p;
+
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), NULL);
+
+ if(sm_client->priv->state_file)
+ return sm_client->priv->state_file;
+
+ g_return_val_if_fail(sm_client->priv->program, NULL);
+ g_return_val_if_fail(sm_client->priv->client_id, NULL);
+
+ resource = g_strdup_printf("sessions/%s-%s.state",
+ sm_client->priv->program,
+ sm_client->priv->client_id);
+ for(p = resource; *p; p++) {
+ if(*p == '/')
+ *p = '_';
+ }
+
+ sm_client->priv->state_file = xfce_resource_save_location(XFCE_RESOURCE_CACHE,
+ resource, TRUE);
+ if(!sm_client->priv->state_file) {
+ g_critical("XfceSMClient: Unable to create state file as "
+ "\"$XDG_CACHE_HOME/%s\"", resource);
+ }
+
+ g_free(resource);
+
+#ifdef HAVE_LIBSM
+ if(G_LIKELY(sm_client->priv->state_file)
+ && sm_client->priv->session_connection
+ && !sm_client->priv->discard_command)
+ {
+ sm_client->priv->discard_command = g_new0(gchar *, 4);
+ sm_client->priv->discard_command[0] = g_strdup("rm");
+ sm_client->priv->discard_command[1] = g_strdup("-f");
+ sm_client->priv->discard_command[2] = g_strdup(sm_client->priv->state_file);
+
+ xfce_sm_client_set_property_from_command(sm_client, SmDiscardCommand,
+ sm_client->priv->discard_command,
+ FALSE);
+ }
+#endif
+
+ return sm_client->priv->state_file;
+}
+
+/**
+ * xfce_sm_client_get_current_directory:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's working directory. See
+ * xfce_sm_client_set_current_directory() for more information.
+ *
+ * Returns: an object-owned string
+ **/
+G_CONST_RETURN gchar *
+xfce_sm_client_get_current_directory(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), NULL);
+ return sm_client->priv->current_directory;
+}
+
+/**
+ * xfce_sm_client_get_program:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's program identifier. See
+ * xfce_sm_client_set_program() for more information.
+ *
+ * Returns: an object-owned string
+ **/
+G_CONST_RETURN gchar *
+xfce_sm_client_get_program(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), NULL);
+ return sm_client->priv->program;
+}
+
+/**
+ * xfce_sm_client_get_clone_command:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's clone command. See
+ * xfce_sm_client_set_clone_command() for more information.
+ *
+ * Returns: an object-owned string vector
+ **/
+gchar **
+xfce_sm_client_get_clone_command(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), NULL);
+ return sm_client->priv->clone_command;
+}
+
+/**
+ * xfce_sm_client_get_resign_command:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's resign command. See
+ * xfce_sm_client_set_resign_command() for more information.
+ *
+ * Returns: an object-owned string vector
+ **/
+gchar **
+xfce_sm_client_get_resign_command(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), NULL);
+ return sm_client->priv->resign_command;
+}
+
+/**
+ * xfce_sm_client_get_restart_command:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's restart command. See
+ * xfce_sm_client_set_restart_command() for more information.
+ *
+ * Returns: an object-owned string vector
+ **/
+gchar **
+xfce_sm_client_get_restart_command(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), NULL);
+ return sm_client->priv->restart_command;
+}
+
+/**
+ * xfce_sm_client_get_discard_command:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's discard command. See
+ * xfce_sm_client_set_discard_command() for more information.
+ *
+ * Returns: an object-owned string vector
+ **/
+gchar **
+xfce_sm_client_get_discard_command(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), NULL);
+ return sm_client->priv->discard_command;
+}
+
+/**
+ * xfce_sm_client_get_shutdown_command:
+ * @sm_client: An #XfceSMClient
+ *
+ * Retrieves the session client's shutdown command. See
+ * xfce_sm_client_set_shutdown_command() for more information.
+ *
+ * Returns: an object-owned string vector
+ **/
+gchar **
+xfce_sm_client_get_shutdown_command(XfceSMClient *sm_client)
+{
+ g_return_val_if_fail(XFCE_IS_SM_CLIENT(sm_client), NULL);
+ return sm_client->priv->shutdown_command;
+}
diff --git a/libxfce4ui/xfce-sm-client.h b/libxfce4ui/xfce-sm-client.h
new file mode 100644
index 0000000..439e8fa
--- /dev/null
+++ b/libxfce4ui/xfce-sm-client.h
@@ -0,0 +1,184 @@
+/* xfce4
+ * Copyright (C) 1999 Olivier Fourdan (fourdan at xfce.org)
+ * Copyright (c) 2009 Brian Tarricone <brian at terricone.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XFCE_SM_CLIENT_H__
+#define __XFCE_SM_CLIENT_H__
+
+#if !defined(LIBXFCE4UI_INSIDE_LIBXFCE4UI_H) && !defined(LIBXFCE4UI_COMPILATION)
+#error "Only <libxfce4ui/libxfce4ui.h> can be included directly, this file is not part of the public API."
+#endif
+
+#include <glib-object.h>
+
+#define XFCE_TYPE_SM_CLIENT (xfce_sm_client_get_type())
+#define XFCE_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFCE_TYPE_SM_CLIENT, XfceSMClient))
+#define XFCE_IS_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFCE_TYPE_SM_CLIENT))
+#define XFCE_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XFCE_TYPE_SM_CLIENT, XfceSMClientClass))
+#define XFCE_IS_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), XFCE_TYPE_SM_CLIENT))
+#define XFCE_SM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XFCE_TYPE_SM_CLIENT, XfceSMClientClass))
+
+G_BEGIN_DECLS
+
+typedef enum /*< prefix=XFCE_SM_CLIENT_RESTART_ >*/
+{
+ XFCE_SM_CLIENT_RESTART_IF_RUNNING = 0,
+ XFCE_SM_CLIENT_RESTART_ANYWAY, /* TODO: maybe not support this? */
+ XFCE_SM_CLIENT_RESTART_IMMEDIATELY,
+ XFCE_SM_CLIENT_RESTART_NEVER, /* TODO: maybe not support this? */
+} XfceSMClientRestartStyle;
+
+typedef enum
+{
+ XFCE_SM_CLIENT_STATE_IDLE = 0,
+ XFCE_SM_CLIENT_STATE_SAVING_PHASE_1,
+ XFCE_SM_CLIENT_STATE_WAITING_FOR_PHASE_2,
+ XFCE_SM_CLIENT_STATE_SAVING_PHASE_2,
+ XFCE_SM_CLIENT_STATE_WAITING_FOR_INTERACT,
+ XFCE_SM_CLIENT_STATE_INTERACTING,
+ XFCE_SM_CLIENT_STATE_FROZEN,
+ XFCE_SM_CLIENT_STATE_DISCONNECTED,
+ XFCE_SM_CLIENT_STATE_REGISTERING,
+} XfceSMClientState;
+
+typedef enum
+{
+ XFCE_SM_CLIENT_PRIORITY_HIGHEST = 0,
+ XFCE_SM_CLIENT_PRIORITY_WM = 15,
+ XFCE_SM_CLIENT_PRIORITY_DESKTOP = 25,
+ XFCE_SM_CLIENT_PRIORITY_CORE = 35,
+ XFCE_SM_CLIENT_PRIORITY_DEFAULT = 50,
+} XfceSMClientPriority;
+
+typedef enum
+{
+ XFCE_SM_CLIENT_SHUTDOWN_HINT_ASK = 0,
+ XFCE_SM_CLIENT_SHUTDOWN_HINT_LOGOUT,
+ XFCE_SM_CLIENT_SHUTDOWN_HINT_HALT,
+ XFCE_SM_CLIENT_SHUTDOWN_HINT_REBOOT,
+} XfceSMClientShutdownHint;
+
+typedef struct _XfceSMClient XfceSMClient;
+typedef struct _XfceSMClientClass XfceSMClientClass;
+typedef struct _XfceSMClientPrivate XfceSMClientPrivate;
+
+struct _XfceSMClient
+{
+ GObject parent;
+
+ /*< private >*/
+ XfceSMClientPrivate *priv;
+};
+
+struct _XfceSMClientClass
+{
+ GObjectClass parent;
+
+ /*< signals >*/
+
+ void (*save_state)(XfceSMClient *sm_client);
+ void (*save_state_extended)(XfceSMClient *sm_client);
+
+ /* return TRUE to cancel shutdown */
+ gboolean (*quit_requested)(XfceSMClient *sm_client);
+
+ void (*quit)(XfceSMClient *sm_client);
+
+ void (*quit_cancelled)(XfceSMClient *sm_client);
+
+ void (*state_changed)(XfceSMClient *sm_client,
+ XfceSMClientState old_state,
+ XfceSMClientState new_state);
+
+ void (*_xfce_reserved0)(void);
+ void (*_xfce_reserved1)(void);
+ void (*_xfce_reserved2)(void);
+ void (*_xfce_reserved3)(void);
+};
+
+
+GType xfce_sm_client_get_type(void) G_GNUC_CONST;
+
+GOptionGroup *xfce_sm_client_get_option_group(guint argc,
+ gchar **argv);
+
+XfceSMClient *xfce_sm_client_get();
+
+XfceSMClient *xfce_sm_client_get_with_argv(guint argc,
+ gchar **argv,
+ XfceSMClientRestartStyle restart_style,
+ gchar priority);
+
+XfceSMClient *xfce_sm_client_get_full(XfceSMClientRestartStyle restart_style,
+ gchar priority,
+ const gchar *resumed_client_id,
+ const gchar *program,
+ const gchar *current_directory,
+ const gchar **restart_command,
+ const gchar **clone_command,
+ const gchar **discard_command,
+ const gchar **resign_command,
+ const gchar **shutdown_command);
+
+gboolean xfce_sm_client_connect(XfceSMClient *sm_client,
+ GError **error);
+void xfce_sm_client_disconnect(XfceSMClient *sm_client);
+
+gboolean xfce_sm_client_is_resumed(XfceSMClient *sm_client);
+
+void xfce_sm_client_request_shutdown(XfceSMClient *sm_client,
+ XfceSMClientShutdownHint shutdown_hint);
+
+XfceSMClientState xfce_sm_client_get_state(XfceSMClient *sm_client);
+
+G_CONST_RETURN gchar *xfce_sm_client_get_client_id(XfceSMClient *sm_client);
+
+G_CONST_RETURN gchar *xfce_sm_client_get_state_file(XfceSMClient *sm_client);
+
+void xfce_sm_client_set_restart_style(XfceSMClient *sm_client,
+ XfceSMClientRestartStyle restart_style);
+XfceSMClientRestartStyle xfce_sm_client_get_restart_style(XfceSMClient *sm_client);
+
+void xfce_sm_client_set_priority(XfceSMClient *sm_client, gchar value);
+gchar xfce_sm_client_get_priority(XfceSMClient *sm_client);
+
+void xfce_sm_client_set_current_directory(XfceSMClient *sm_client, gchar const* value);
+G_CONST_RETURN gchar *xfce_sm_client_get_current_directory(XfceSMClient *sm_client);
+
+void xfce_sm_client_set_program(XfceSMClient *sm_client, gchar const* value);
+G_CONST_RETURN gchar *xfce_sm_client_get_program(XfceSMClient *sm_client);
+
+void xfce_sm_client_set_clone_command(XfceSMClient *sm_client, gchar** const value);
+gchar **xfce_sm_client_get_clone_command(XfceSMClient *sm_client);
+
+void xfce_sm_client_set_resign_command(XfceSMClient *sm_client, gchar** const value);
+gchar **xfce_sm_client_get_resign_command(XfceSMClient *sm_client);
+
+void xfce_sm_client_set_restart_command(XfceSMClient *sm_client, gchar** const value);
+gchar **xfce_sm_client_get_restart_command(XfceSMClient *sm_client);
+
+void xfce_sm_client_set_discard_command(XfceSMClient *sm_client, gchar** const value);
+gchar **xfce_sm_client_get_discard_command(XfceSMClient *sm_client);
+
+void xfce_sm_client_set_shutdown_command(XfceSMClient *sm_client, gchar** const value);
+gchar **xfce_sm_client_get_shutdown_command(XfceSMClient *sm_client);
+
+G_END_DECLS
+
+#endif /* __XFCE_SM_CLIENT_H__ */
More information about the Xfce4-commits
mailing list