Commit c9023492 authored by Benedikt Meurer's avatar Benedikt Meurer

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)
parent b177765d
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.
......
......@@ -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 **********************************
......
......@@ -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 \
......
......@@ -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));
......
......@@ -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))))
/**
......
/* $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 */
}
/* $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__ */
/* $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