summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenedikt Meurer <benny@xfce.org>2006-05-15 21:16:40 +0000
committerBenedikt Meurer <benny@xfce.org>2006-05-15 21:16:40 +0000
commitc90234920c9e254ec96c76ce2c0e1452c370698d (patch)
treeeb7ce3c57d757b4812ad1939538fbe2b12f772bb
parentb177765df5e07c13db7a96921f265042cdbf3887 (diff)
downloadthunar-c90234920c9e254ec96c76ce2c0e1452c370698d.tar.gz
2006-05-15 Benedikt Meurer <benny@xfce.org>
* thunar/thunar-file.h: Add convenience macro thunar_file_dup_uri(). * thunar/thunar-ice.{c,h}, thunar/thunar-session-client.{c,h}, thunar/main.c, thunar/Makefile.am, configure.in.in: Add session management support, based on XSM. Bug #1415. (Old svn revision: 21691)
-rw-r--r--ChangeLog7
-rw-r--r--configure.in.in5
-rw-r--r--thunar/Makefile.am11
-rw-r--r--thunar/main.c30
-rw-r--r--thunar/thunar-file.h10
-rw-r--r--thunar/thunar-ice.c141
-rw-r--r--thunar/thunar-ice.h31
-rw-r--r--thunar/thunar-session-client.c472
-rw-r--r--thunar/thunar-session-client.h42
9 files changed, 735 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 16e58fc5..956bbb2b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2006-05-15 Benedikt Meurer <benny@xfce.org>
+
+ * thunar/thunar-file.h: Add convenience macro thunar_file_dup_uri().
+ * thunar/thunar-ice.{c,h}, thunar/thunar-session-client.{c,h},
+ thunar/main.c, thunar/Makefile.am, configure.in.in: Add session
+ management support, based on XSM. Bug #1415.
+
2006-05-14 Benedikt Meurer <benny@xfce.org>
* thunar-vfs/thunar-vfs-job.c: Fix compile warning. Bug #1756.
diff --git a/configure.in.in b/configure.in.in
index f9d7bb10..3e814e82 100644
--- a/configure.in.in
+++ b/configure.in.in
@@ -173,6 +173,11 @@ XDT_CHECK_PACKAGE([LIBPNG], [libpng], [1.2.0], [],
XDT_CHECK_PACKAGE([LIBPNG], [libpng12], [1.2.0])
])
+dnl ********************************************
+dnl *** Check for session management support ***
+dnl ********************************************
+XDT_CHECK_LIBSM()
+
dnl **********************************
dnl *** Optional support for D-BUS ***
dnl **********************************
diff --git a/thunar/Makefile.am b/thunar/Makefile.am
index 54642d8b..d2f99de9 100644
--- a/thunar/Makefile.am
+++ b/thunar/Makefile.am
@@ -80,6 +80,8 @@ Thunar_SOURCES = \
thunar-gtk-extensions.h \
thunar-history.c \
thunar-history.h \
+ thunar-ice.c \
+ thunar-ice.h \
thunar-icon-factory.c \
thunar-icon-factory.h \
thunar-icon-renderer.c \
@@ -129,6 +131,8 @@ Thunar_SOURCES = \
thunar-renamer-pair.h \
thunar-renamer-progress.c \
thunar-renamer-progress.h \
+ thunar-session-client.c \
+ thunar-session-client.h \
thunar-shortcuts-icon-renderer.c \
thunar-shortcuts-icon-renderer.h \
thunar-shortcuts-model.c \
@@ -174,22 +178,23 @@ Thunar_SOURCES = \
thunar-window-ui.h
Thunar_CFLAGS = \
- $(CAIRO_CFLAGS) \
$(EXO_CFLAGS) \
$(GTHREAD_CFLAGS) \
+ $(LIBSM_CFLAGS) \
$(PLATFORM_CFLAGS)
Thunar_LDFLAGS = \
-no-undefined \
+ $(LIBSM_LDFLAGS) \
$(PLATFORM_LDFLAGS)
Thunar_LDADD = \
$(top_builddir)/tdb/libtdb.la \
$(top_builddir)/thunar-vfs/libthunar-vfs-$(THUNAR_VERSION_API).la \
$(top_builddir)/thunarx/libthunarx-$(THUNAR_VERSION_API).la \
- $(CAIRO_LIBS) \
$(EXO_LIBS) \
- $(GTHREAD_LIBS)
+ $(GTHREAD_LIBS) \
+ $(LIBSM_LIBS)
Thunar_DEPENDENCIES = \
$(top_builddir)/tdb/libtdb.la \
diff --git a/thunar/main.c b/thunar/main.c
index cfd39425..3165fcbb 100644
--- a/thunar/main.c
+++ b/thunar/main.c
@@ -34,6 +34,7 @@
#include <thunar/thunar-dbus-client.h>
#include <thunar/thunar-dbus-service.h>
#include <thunar/thunar-gobject-extensions.h>
+#include <thunar/thunar-session-client.h>
#include <thunar/thunar-stock.h>
@@ -41,10 +42,12 @@
/* --- globals --- */
static gboolean opt_bulk_rename = FALSE;
static gboolean opt_daemon = FALSE;
+static gchar *opt_sm_client_id = NULL;
static gboolean opt_quit = FALSE;
static gboolean opt_version = FALSE;
+
/* --- command line options --- */
static GOptionEntry option_entries[] =
{
@@ -54,6 +57,7 @@ static GOptionEntry option_entries[] =
#else
{ "daemon", 0, 0, G_OPTION_ARG_NONE, &opt_daemon, N_ ("Run in daemon mode (not supported)"), NULL, },
#endif
+ { "sm-client-id", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &opt_sm_client_id, NULL, NULL, },
#ifdef HAVE_DBUS
{ "quit", 'q', 0, G_OPTION_ARG_NONE, &opt_quit, N_ ("Quit a running Thunar instance"), NULL, },
#else
@@ -68,13 +72,14 @@ static GOptionEntry option_entries[] =
int
main (int argc, char **argv)
{
+ ThunarSessionClient *session_client;
#ifdef HAVE_DBUS
- ThunarDBusService *dbus_service;
+ ThunarDBusService *dbus_service;
#endif
- ThunarApplication *application;
- GError *error = NULL;
- gchar *working_directory;
- gchar **filenames = NULL;
+ ThunarApplication *application;
+ GError *error = NULL;
+ gchar *working_directory;
+ gchar **filenames = NULL;
/* setup translation domain */
xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
@@ -111,13 +116,10 @@ main (int argc, char **argv)
/* check if we should print version information */
if (G_UNLIKELY (opt_version))
{
- g_print ("%s %s (Xfce %s)\n", PACKAGE_NAME, PACKAGE_VERSION, xfce_version_string ());
- g_print ("\n");
+ g_print ("%s %s (Xfce %s)\n\n", PACKAGE_NAME, PACKAGE_VERSION, xfce_version_string ());
g_print ("%s\n", _("Copyright (c) 2004-2006"));
- g_print ("\t%s\n", _("The Thunar development team. All rights reserved."));
- g_print ("\n");
- g_print ("%s\n", _("Written by Benedikt Meurer <benny@xfce.org>."));
- g_print ("\n");
+ g_print ("\t%s\n\n", _("The Thunar development team. All rights reserved."));
+ g_print ("%s\n\n", _("Written by Benedikt Meurer <benny@xfce.org>."));
g_print (_("Please report bugs to <%s>."), PACKAGE_BUGREPORT);
g_print ("\n");
return EXIT_SUCCESS;
@@ -222,6 +224,9 @@ error0:
g_free (working_directory);
g_strfreev (filenames);
+ /* connect to the session manager */
+ session_client = thunar_session_client_new (opt_sm_client_id);
+
/* do not enter the main loop, unless we have atleast one window or we are in daemon mode */
if (thunar_application_has_windows (application) || thunar_application_get_daemon (application))
{
@@ -239,6 +244,9 @@ error0:
#endif
}
+ /* disconnect from the session manager */
+ g_object_unref (G_OBJECT (session_client));
+
/* release the application reference */
g_object_unref (G_OBJECT (application));
diff --git a/thunar/thunar-file.h b/thunar/thunar-file.h
index 11861b37..0fe7736a 100644
--- a/thunar/thunar-file.h
+++ b/thunar/thunar-file.h
@@ -299,6 +299,16 @@ GList *thunar_file_list_to_path_list (GList *file_list);
**/
#define thunar_file_get_free_space(file, free_space_return) (thunar_vfs_info_get_free_space (THUNAR_FILE ((file))->info, (free_space_return)))
+/**
+ * thunar_file_dup_uri:
+ * @file : a #ThunarFile instance.
+ *
+ * Returns the URI for the @file. The caller is responsible
+ * to free the returned string when no longer needed.
+ *
+ * Return value: the URI for @file.
+ **/
+#define thunar_file_dup_uri(file) (thunar_vfs_path_dup_uri (thunar_file_get_path ((file))))
/**
diff --git a/thunar/thunar-ice.c b/thunar/thunar-ice.c
new file mode 100644
index 00000000..13957ef9
--- /dev/null
+++ b/thunar/thunar-ice.c
@@ -0,0 +1,141 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_LIBSM
+#include <X11/ICE/ICElib.h>
+#endif
+
+#include <thunar/thunar-ice.h>
+
+
+
+#ifdef HAVE_LIBSM
+static void
+thunar_ice_error_handler (IceConn connection)
+{
+ /*
+ * The I/O error handler does whatever is necessary to respond
+ * to the I/O error and then returns, but it does not call
+ * IceCloseConnection. The ICE connection is given a "bad IO"
+ * status, and all future reads and writes to the connection
+ * are ignored. The next time IceProcessMessages is called it
+ * will return a status of IceProcessMessagesIOError. At that
+ * time, the application should call IceCloseConnection.
+ */
+}
+
+
+
+static gboolean
+thunar_ice_process_messages (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer client_data)
+{
+ IceProcessMessagesStatus status;
+ IceConn connection = client_data;
+
+ /* try to process pending messages */
+ status = IceProcessMessages (connection, NULL, NULL);
+ if (G_UNLIKELY (status == IceProcessMessagesIOError))
+ {
+ /* we were disconnected from the session manager */
+ IceSetShutdownNegotiation (connection, False);
+ IceCloseConnection (connection);
+ }
+
+ return TRUE;
+}
+
+
+
+static void
+thunar_ice_connection_watch (IceConn connection,
+ IcePointer client_data,
+ Bool opening,
+ IcePointer *watch_data)
+{
+ GIOChannel *channel;
+ guint watch_id;
+ gint fd;
+
+ if (G_LIKELY (opening))
+ {
+ /* determine the file descriptor */
+ fd = IceConnectionNumber (connection);
+
+ /* Make sure we don't pass on these file descriptors to an exec'd child process */
+ fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
+
+ /* allocate an I/O channel to watch the connection */
+ channel = g_io_channel_unix_new (fd);
+ watch_id = g_io_add_watch (channel, G_IO_ERR | G_IO_HUP | G_IO_IN, thunar_ice_process_messages, connection);
+ g_io_channel_unref (channel);
+
+ /* remember the watch id */
+ *watch_data = GUINT_TO_POINTER (watch_id);
+ }
+ else
+ {
+ /* remove the watch */
+ watch_id = GPOINTER_TO_UINT (*watch_data);
+ g_source_remove (watch_id);
+ }
+}
+#endif /* !HAVE_LIBSM */
+
+
+
+/**
+ * thunar_ice_init:
+ *
+ * This function should be called before you use any ICE functions.
+ * It will arrange for ICE connections to be read and dispatched via
+ * the Glib event loop mechanism. This function can be called any number
+ * of times without any harm.
+ **/
+void
+thunar_ice_init (void)
+{
+#ifdef HAVE_LIBSM
+ static gboolean initialized = FALSE;
+
+ if (G_LIKELY (!initialized))
+ {
+ /* setup our custom I/O error handler */
+ IceSetIOErrorHandler (thunar_ice_error_handler);
+
+ /* add the connection watch */
+ IceAddConnectionWatch (thunar_ice_connection_watch, NULL);
+
+ initialized = TRUE;
+ }
+#endif /* !HAVE_LIBSM */
+}
+
diff --git a/thunar/thunar-ice.h b/thunar/thunar-ice.h
new file mode 100644
index 00000000..c687aa71
--- /dev/null
+++ b/thunar/thunar-ice.h
@@ -0,0 +1,31 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __THUNAR_ICE_H__
+#define __THUNAR_ICE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS;
+
+void thunar_ice_init (void);
+
+G_END_DECLS;
+
+#endif /* !__THUNAR_ICE_H__ */
diff --git a/thunar/thunar-session-client.c b/thunar/thunar-session-client.c
new file mode 100644
index 00000000..1c57ad92
--- /dev/null
+++ b/thunar/thunar-session-client.c
@@ -0,0 +1,472 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.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_LIBSM
+#include <X11/SM/SMlib.h>
+#endif
+
+#include <thunar/thunar-application.h>
+#include <thunar/thunar-ice.h>
+#include <thunar/thunar-session-client.h>
+
+
+
+static void thunar_session_client_class_init (ThunarSessionClientClass *klass);
+static void thunar_session_client_init (ThunarSessionClient *session_client);
+static void thunar_session_client_finalize (GObject *object);
+#ifdef HAVE_LIBSM
+static gboolean thunar_session_client_connect (ThunarSessionClient *session_client,
+ const gchar *previous_id);
+static void thunar_session_client_restore (ThunarSessionClient *session_client);
+static void thunar_session_client_die (SmcConn connection,
+ ThunarSessionClient *session_client);
+static void thunar_session_client_save_complete (SmcConn connection,
+ ThunarSessionClient *session_client);
+static void thunar_session_client_save_yourself (SmcConn connection,
+ ThunarSessionClient *session_client,
+ gint save_type,
+ Bool shutdown,
+ gint interact_style,
+ Bool fast);
+static void thunar_session_client_shutdown_cancelled (SmcConn connection,
+ ThunarSessionClient *session_client);
+#endif /* !HAVE_LIBSM */
+
+
+
+struct _ThunarSessionClientClass
+{
+ GObjectClass __parent__;
+};
+
+struct _ThunarSessionClient
+{
+ GObject __parent__;
+ gchar *path;
+ gchar *id;
+
+#ifdef HAVE_LIBSM
+ SmcConn connection;
+#endif
+};
+
+
+
+static GObjectClass *thunar_session_client_parent_class;
+
+
+
+GType
+thunar_session_client_get_type (void)
+{
+ static GType type = G_TYPE_INVALID;
+
+ if (G_UNLIKELY (type == G_TYPE_INVALID))
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThunarSessionClientClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) thunar_session_client_class_init,
+ NULL,
+ NULL,
+ sizeof (ThunarSessionClient),
+ 0,
+ (GInstanceInitFunc) thunar_session_client_init,
+ NULL,
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT, I_("ThunarSessionClient"), &info, 0);
+ }
+
+ return type;
+}
+
+
+
+static void
+thunar_session_client_class_init (ThunarSessionClientClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ /* determine the parent type class */
+ thunar_session_client_parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = thunar_session_client_finalize;
+}
+
+
+
+static void
+thunar_session_client_init (ThunarSessionClient *session_client)
+{
+ /* initialize the ICE layer */
+ thunar_ice_init ();
+}
+
+
+
+static void
+thunar_session_client_finalize (GObject *object)
+{
+ ThunarSessionClient *session_client = THUNAR_SESSION_CLIENT (object);
+
+#ifdef HAVE_LIBSM
+ /* disconnect from the session manager */
+ if (G_LIKELY (session_client->connection != NULL))
+ SmcCloseConnection (session_client->connection, 0, NULL);
+#endif /* !HAVE_LIBSM */
+
+ /* release internal state */
+ g_free (session_client->path);
+ g_free (session_client->id);
+
+ (*G_OBJECT_CLASS (thunar_session_client_parent_class)->finalize) (object);
+}
+
+
+
+#ifdef HAVE_LIBSM
+static gboolean
+thunar_session_client_connect (ThunarSessionClient *session_client,
+ const gchar *previous_id)
+{
+ SmcCallbacks session_callbacks;
+ SmPropValue value_discard[3];
+ SmPropValue value_restart[4];
+ SmPropValue value_userid[1];
+ SmProp *properties[5];
+ SmProp prop_clone;
+ SmProp prop_discard;
+ SmProp prop_program;
+ SmProp prop_restart;
+ SmProp prop_userid;
+ gchar error_string[1];
+ gchar *spec;
+ gchar *id = NULL;
+
+ /* setup the session client callbacks */
+ session_callbacks.die.callback = (SmcDieProc) thunar_session_client_die;
+ session_callbacks.die.client_data = session_client;
+ session_callbacks.save_complete.callback = (SmcSaveCompleteProc) thunar_session_client_save_complete;
+ session_callbacks.save_complete.client_data = session_client;
+ session_callbacks.save_yourself.callback = (SmcSaveYourselfProc) thunar_session_client_save_yourself;
+ session_callbacks.save_yourself.client_data = session_client;
+ session_callbacks.shutdown_cancelled.callback = (SmcShutdownCancelledProc) thunar_session_client_shutdown_cancelled;
+ session_callbacks.shutdown_cancelled.client_data = session_client;
+
+ /* try to establish a connection to the session manager */
+ session_client->connection = SmcOpenConnection (NULL, NULL, SmProtoMajor, SmProtoMinor, SmcDieProcMask
+ | SmcSaveCompleteProcMask | SmcSaveYourselfProcMask
+ | SmcShutdownCancelledProcMask, &session_callbacks,
+ (gchar *) previous_id, &id, sizeof (error_string), error_string);
+ if (G_UNLIKELY (session_client->connection == NULL))
+ return FALSE;
+
+ /* tell GDK about our new session id */
+ gdk_set_sm_client_id (id);
+
+ /* remember the returned client id */
+ if (g_mem_is_system_malloc ())
+ {
+ /* just use the memory */
+ session_client->id = id;
+ }
+ else
+ {
+ /* use GLib memory management */
+ session_client->id = g_strdup (id);
+ free (id);
+ }
+
+ /* determine the session file path */
+ spec = g_strconcat ("sessions/Thunar-", session_client->id, NULL);
+ session_client->path = xfce_resource_save_location (XFCE_RESOURCE_CACHE, spec, TRUE);
+ g_free (spec);
+
+ /* verify that we were able to create the path to the file */
+ if (G_UNLIKELY (session_client->path == NULL))
+ {
+ /* disconnect from the session manager */
+ SmcCloseConnection (session_client->connection, 0, NULL);
+ session_client->connection = NULL;
+ return FALSE;
+ }
+
+ /* SmCloneCommand (see SmRestartCommand) */
+ prop_clone.name = SmCloneCommand;
+ prop_clone.type = SmLISTofARRAY8;
+ prop_clone.num_vals = 1;
+ prop_clone.vals = &value_restart[0];
+
+ /* SmDiscardCommand */
+ prop_discard.name = SmDiscardCommand;
+ prop_discard.type = SmLISTofARRAY8;
+ prop_discard.num_vals = G_N_ELEMENTS (value_discard);
+ prop_discard.vals = &value_discard[0];
+ value_discard[0].value = "rm";
+ value_discard[0].length = sizeof ("rm") - 1;
+ value_discard[1].value = "-f";
+ value_discard[1].length = sizeof ("-f") - 1;
+ value_discard[2].value = session_client->path;
+ value_discard[2].length = strlen (session_client->path);
+
+ /* SmProgram (see SmRestartCommand) */
+ prop_program.name = SmProgram;
+ prop_program.type = SmARRAY8;
+ prop_program.num_vals = 1;
+ prop_program.vals = &value_restart[0];
+
+ /* SmRestartCommand */
+ prop_restart.name = SmRestartCommand;
+ prop_restart.type = SmLISTofARRAY8;
+ prop_restart.num_vals = G_N_ELEMENTS (value_restart);
+ prop_restart.vals = &value_restart[0];
+ value_restart[0].value = "Thunar";
+ value_restart[0].length = sizeof ("Thunar") - 1;
+ value_restart[1].value = "--sm-client-id";
+ value_restart[1].length = sizeof ("--sm-client-id") - 1;
+ value_restart[2].value = session_client->id;
+ value_restart[2].length = strlen (session_client->id);
+ value_restart[3].value = "--daemon";
+ value_restart[3].length = sizeof ("--daemon") - 1;
+
+ /* SmUserID */
+ prop_userid.name = SmUserID;
+ prop_userid.type = SmARRAY8;
+ prop_userid.num_vals = G_N_ELEMENTS (value_userid);
+ prop_userid.vals = &value_userid[0];
+ value_userid[0].value = (gchar *) g_get_user_name ();
+ value_userid[0].length = strlen (value_userid[0].value);
+
+ /* setup the properties list */
+ properties[0] = &prop_clone;
+ properties[1] = &prop_discard;
+ properties[2] = &prop_program;
+ properties[3] = &prop_restart;
+ properties[4] = &prop_userid;
+
+ /* send the properties to the session manager */
+ SmcSetProperties (session_client->connection, G_N_ELEMENTS (properties), properties);
+
+ return TRUE;
+}
+
+
+
+static void
+thunar_session_client_restore (ThunarSessionClient *session_client)
+{
+ ThunarApplication *application;
+ const gchar *uri;
+ ThunarFile *directory;
+ GtkWidget *window;
+ XfceRc *rc;
+ gchar **roles;
+ guint n;
+
+ /* try to open the session file */
+ rc = xfce_rc_simple_open (session_client->path, TRUE);
+ if (G_UNLIKELY (rc == NULL))
+ return;
+
+ /* grab a reference on the application */
+ application = thunar_application_get ();
+
+ /* determine all window roles */
+ roles = xfce_rc_get_groups (rc);
+ for (n = 0; roles[n] != NULL; ++n)
+ {
+ /* enter the group */
+ xfce_rc_set_group (rc, roles[n]);
+
+ /* determine the URI for the new window */
+ uri = xfce_rc_read_entry (rc, "URI", NULL);
+ if (G_UNLIKELY (uri == NULL))
+ continue;
+
+ /* determine the directory for the new window */
+ directory = thunar_file_get_for_uri (uri, NULL);
+ if (G_UNLIKELY (directory == NULL))
+ continue;
+
+ /* verify that we have a directory */
+ if (thunar_file_is_directory (directory))
+ {
+ /* open the new window */
+ window = g_object_new (THUNAR_TYPE_WINDOW,
+ "current-directory", directory,
+ "role", roles[n],
+ NULL);
+ thunar_application_take_window (application, GTK_WINDOW (window));
+ gtk_widget_show (window);
+ }
+
+ /* cleanup */
+ g_object_unref (G_OBJECT (directory));
+ }
+
+ /* cleanup */
+ g_object_unref (G_OBJECT (application));
+ xfce_rc_close (rc);
+ g_strfreev (roles);
+}
+
+
+
+static void
+thunar_session_client_die (SmcConn connection,
+ ThunarSessionClient *session_client)
+{
+ g_return_if_fail (THUNAR_IS_SESSION_CLIENT (session_client));
+ g_return_if_fail (session_client->connection == connection);
+
+ /* terminate the application */
+ gtk_main_quit ();
+}
+
+
+
+static void
+thunar_session_client_save_complete (SmcConn connection,
+ ThunarSessionClient *session_client)
+{
+ g_return_if_fail (THUNAR_IS_SESSION_CLIENT (session_client));
+ g_return_if_fail (session_client->connection == connection);
+}
+
+
+
+static void
+thunar_session_client_save_yourself (SmcConn connection,
+ ThunarSessionClient *session_client,
+ gint save_type,
+ Bool shutdown,
+ gint interact_style,
+ Bool fast)
+{
+ ThunarApplication *application;
+ const gchar *role;
+ ThunarFile *directory;
+ GList *windows;
+ GList *lp;
+ gchar *uri;
+ FILE *fp;
+
+ g_return_if_fail (THUNAR_IS_SESSION_CLIENT (session_client));
+ g_return_if_fail (session_client->connection == connection);
+
+ /* check if we should save our current state */
+ if (save_type == SmSaveLocal || save_type == SmSaveBoth)
+ {
+ /* try to open the session file for writing */
+ fp = fopen (session_client->path, "w");
+ if (G_LIKELY (fp != NULL))
+ {
+ /* save the active windows */
+ application = thunar_application_get ();
+ windows = thunar_application_get_windows (application);
+ for (lp = windows; lp != NULL; lp = lp->next)
+ {
+ /* determine the directory for the window */
+ directory = thunar_window_get_current_directory (lp->data);
+ if (G_UNLIKELY (directory == NULL))
+ continue;
+
+ /* determine the role for the window */
+ role = gtk_window_get_role (lp->data);
+ if (G_UNLIKELY (role == NULL))
+ continue;
+
+ /* save the window */
+ uri = thunar_file_dup_uri (directory);
+ fprintf (fp, "[%s]\n", role);
+ fprintf (fp, "URI=%s\n\n", uri);
+ g_free (uri);
+ }
+
+ /* cleanup */
+ g_object_unref (G_OBJECT (application));
+ g_list_free (windows);
+ fclose (fp);
+ }
+ }
+
+ /* tell the session manager that we're done */
+ SmcSaveYourselfDone (connection, True);
+}
+
+
+
+static void
+thunar_session_client_shutdown_cancelled (SmcConn connection,
+ ThunarSessionClient *session_client)
+{
+ g_return_if_fail (THUNAR_IS_SESSION_CLIENT (session_client));
+ g_return_if_fail (session_client->connection == connection);
+}
+#endif /* !HAVE_LIBSM */
+
+
+
+/**
+ * thunar_session_client_new:
+ * @session_id : the previous session id, or %NULL.
+ *
+ * Allocates a new #ThunarSessionClient with the specified
+ * @session_id. If @session_id is %NULL the session manager
+ * will assign a new session id, otherwise the session for
+ * the specified id will be restored.
+ *
+ * Return value: the newly allocated #ThunarSessionClient.
+ **/
+ThunarSessionClient*
+thunar_session_client_new (const gchar *session_id)
+{
+ ThunarSessionClient *session_client;
+
+ /* allocate a new session client */
+ session_client = g_object_new (THUNAR_TYPE_SESSION_CLIENT, NULL);
+
+#ifdef HAVE_LIBSM
+ /* try to connect to the session manager and restore the previous session */
+ if (thunar_session_client_connect (session_client, session_id) && session_id != NULL)
+ thunar_session_client_restore (session_client);
+#endif /* !HAVE_LIBSM */
+
+ return session_client;
+}
+
diff --git a/thunar/thunar-session-client.h b/thunar/thunar-session-client.h
new file mode 100644
index 00000000..ed7a5605
--- /dev/null
+++ b/thunar/thunar-session-client.h
@@ -0,0 +1,42 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __THUNAR_SESSION_CLIENT_H__
+#define __THUNAR_SESSION_CLIENT_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS;
+
+typedef struct _ThunarSessionClientClass ThunarSessionClientClass;
+typedef struct _ThunarSessionClient ThunarSessionClient;
+
+#define THUNAR_TYPE_SESSION_CLIENT (thunar_session_client_get_type ())
+#define THUNAR_SESSION_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_SESSION_CLIENT, ThunarSessionClient))
+#define THUNAR_SESSION_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_SESSION_CLIENT, ThunarSessionClientClass))
+#define THUNAR_IS_SESSION_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_SESSION_CLIENT))
+#define THUNAR_IS_SESSION_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_SESSION_CLIENT))
+#define THUNAR_SESSION_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_SESSION_CLIENT, ThunarSessionClientClass))
+
+GType thunar_session_client_get_type (void) G_GNUC_CONST;
+ThunarSessionClient *thunar_session_client_new (const gchar *session_id) G_GNUC_MALLOC;
+
+G_END_DECLS;
+
+#endif /* !__THUNAR_SESSION_CLIENT_H__ */