aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorXan Lopez <xan@igalia.com>2012-03-28 23:23:17 +0800
committerXan Lopez <xan@igalia.com>2012-03-28 23:23:17 +0800
commitdd3af2804d1ddf339f34d8d0d42b8d0f64282198 (patch)
treed7148793d39671b964b69751c8573f6c41d5c257 /lib
parent71046aadc2a1febb8d35bb5f6764c5d7ae8fad6c (diff)
downloadgsoc2013-epiphany-dd3af2804d1ddf339f34d8d0d42b8d0f64282198.tar
gsoc2013-epiphany-dd3af2804d1ddf339f34d8d0d42b8d0f64282198.tar.gz
gsoc2013-epiphany-dd3af2804d1ddf339f34d8d0d42b8d0f64282198.tar.bz2
gsoc2013-epiphany-dd3af2804d1ddf339f34d8d0d42b8d0f64282198.tar.lz
gsoc2013-epiphany-dd3af2804d1ddf339f34d8d0d42b8d0f64282198.tar.xz
gsoc2013-epiphany-dd3af2804d1ddf339f34d8d0d42b8d0f64282198.tar.zst
gsoc2013-epiphany-dd3af2804d1ddf339f34d8d0d42b8d0f64282198.zip
Rip out the EggSMClient code
The brave new world is to use the session support in GtkApplication.
Diffstat (limited to 'lib')
-rw-r--r--lib/egg/Makefile.am4
-rw-r--r--lib/egg/eggsmclient-private.h59
-rw-r--r--lib/egg/eggsmclient-xsmp.c1409
-rw-r--r--lib/egg/eggsmclient.c610
-rw-r--r--lib/egg/eggsmclient.h123
-rw-r--r--lib/egg/eggsmclient.patch198
6 files changed, 0 insertions, 2403 deletions
diff --git a/lib/egg/Makefile.am b/lib/egg/Makefile.am
index c3add0913..a869848c0 100644
--- a/lib/egg/Makefile.am
+++ b/lib/egg/Makefile.am
@@ -3,15 +3,11 @@ NULL =
EGGSOURCES = \
eggtreemultidnd.c \
eggdesktopfile.c \
- eggsmclient.c \
- eggsmclient-xsmp.c \
$(NULL)
EGGHEADERS = \
eggtreemultidnd.h \
eggdesktopfile.h \
- eggsmclient.h \
- eggsmclient-private.h \
$(NULL)
noinst_HEADERS = \
diff --git a/lib/egg/eggsmclient-private.h b/lib/egg/eggsmclient-private.h
deleted file mode 100644
index 0c98eeed8..000000000
--- a/lib/egg/eggsmclient-private.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* eggsmclient-private.h
- * Copyright (C) 2007 Novell, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 __EGG_SM_CLIENT_PRIVATE_H__
-#define __EGG_SM_CLIENT_PRIVATE_H__
-
-#include <gtk/gtk.h>
-
-#if !GTK_CHECK_VERSION(2,91,7) && !GTK_CHECK_VERSION(3,0,0)
-/* GTK+ 3 includes this automatically */
-#include <gdkconfig.h>
-#endif
-
-#include "eggsmclient.h"
-
-G_BEGIN_DECLS
-
-GKeyFile *egg_sm_client_save_state (EggSMClient *client);
-void egg_sm_client_quit_requested (EggSMClient *client);
-void egg_sm_client_quit_cancelled (EggSMClient *client);
-void egg_sm_client_quit (EggSMClient *client);
-
-#if defined (GDK_WINDOWING_X11)
-# ifdef EGG_SM_CLIENT_BACKEND_XSMP
-GType egg_sm_client_xsmp_get_type (void);
-EggSMClient *egg_sm_client_xsmp_new (void);
-# endif
-# ifdef EGG_SM_CLIENT_BACKEND_DBUS
-GType egg_sm_client_dbus_get_type (void);
-EggSMClient *egg_sm_client_dbus_new (void);
-# endif
-#elif defined (GDK_WINDOWING_WIN32)
-GType egg_sm_client_win32_get_type (void);
-EggSMClient *egg_sm_client_win32_new (void);
-#elif defined (GDK_WINDOWING_QUARTZ)
-GType egg_sm_client_osx_get_type (void);
-EggSMClient *egg_sm_client_osx_new (void);
-#endif
-
-G_END_DECLS
-
-
-#endif /* __EGG_SM_CLIENT_PRIVATE_H__ */
diff --git a/lib/egg/eggsmclient-xsmp.c b/lib/egg/eggsmclient-xsmp.c
deleted file mode 100644
index ec89767da..000000000
--- a/lib/egg/eggsmclient-xsmp.c
+++ /dev/null
@@ -1,1409 +0,0 @@
-/*
- * Copyright (C) 2007 Novell, Inc.
- *
- * Inspired by various other pieces of code including GsmClient (C)
- * 2001 Havoc Pennington, GnomeClient (C) 1998 Carsten Schaar, and twm
- * session code (C) 1998 The Open Group.
- *
- * 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.
- */
-
-#include "config.h"
-
-#include "eggsmclient.h"
-#include "eggsmclient-private.h"
-
-#include "eggdesktopfile.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <X11/SM/SMlib.h>
-
-#include <gdk/gdkx.h>
-
-#define EGG_TYPE_SM_CLIENT_XSMP (egg_sm_client_xsmp_get_type ())
-#define EGG_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMP))
-#define EGG_SM_CLIENT_XSMP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass))
-#define EGG_IS_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_XSMP))
-#define EGG_IS_SM_CLIENT_XSMP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_XSMP))
-#define EGG_SM_CLIENT_XSMP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass))
-
-typedef struct _EggSMClientXSMP EggSMClientXSMP;
-typedef struct _EggSMClientXSMPClass EggSMClientXSMPClass;
-
-/* These mostly correspond to the similarly-named states in section
- * 9.1 of the XSMP spec. Some of the states there aren't represented
- * here, because we don't need them. SHUTDOWN_CANCELLED is slightly
- * different from the spec; we use it when the client is IDLE after a
- * ShutdownCancelled message, but the application is still interacting
- * and doesn't know the shutdown has been cancelled yet.
- */
-typedef enum
-{
- XSMP_STATE_IDLE,
- XSMP_STATE_SAVE_YOURSELF,
- XSMP_STATE_INTERACT_REQUEST,
- XSMP_STATE_INTERACT,
- XSMP_STATE_SAVE_YOURSELF_DONE,
- XSMP_STATE_SHUTDOWN_CANCELLED,
- XSMP_STATE_CONNECTION_CLOSED
-} EggSMClientXSMPState;
-
-static const char *state_names[] = {
- "idle",
- "save-yourself",
- "interact-request",
- "interact",
- "save-yourself-done",
- "shutdown-cancelled",
- "connection-closed"
-};
-
-#define EGG_SM_CLIENT_XSMP_STATE(xsmp) (state_names[(xsmp)->state])
-
-struct _EggSMClientXSMP
-{
- EggSMClient parent;
-
- SmcConn connection;
- char *client_id;
-
- EggSMClientXSMPState state;
- char **restart_command;
- gboolean set_restart_command;
- int restart_style;
- char **discard_command;
- gboolean set_discard_command;
-
- guint idle;
-
- /* Current SaveYourself state */
- guint expecting_initial_save_yourself : 1;
- guint need_save_state : 1;
- guint need_quit_requested : 1;
- guint interact_errors : 1;
- guint shutting_down : 1;
-
- /* Todo list */
- guint waiting_to_set_initial_properties : 1;
- guint waiting_to_emit_quit : 1;
- guint waiting_to_emit_quit_cancelled : 1;
- guint waiting_to_save_myself : 1;
-
-};
-
-struct _EggSMClientXSMPClass
-{
- EggSMClientClass parent_class;
-
-};
-
-static void sm_client_xsmp_startup (EggSMClient *client,
- const char *client_id);
-static void sm_client_xsmp_set_restart_command (EggSMClient *client,
- int argc,
- const char **argv);
-static void sm_client_xsmp_set_discard_command (EggSMClient *client,
- int argc,
- const char **argv);
-static void sm_client_xsmp_will_quit (EggSMClient *client,
- gboolean will_quit);
-static gboolean sm_client_xsmp_end_session (EggSMClient *client,
- EggSMClientEndStyle style,
- gboolean request_confirmation);
-
-static void xsmp_save_yourself (SmcConn smc_conn,
- SmPointer client_data,
- int save_style,
- Bool shutdown,
- int interact_style,
- Bool fast);
-static void xsmp_die (SmcConn smc_conn,
- SmPointer client_data);
-static void xsmp_save_complete (SmcConn smc_conn,
- SmPointer client_data);
-static void xsmp_shutdown_cancelled (SmcConn smc_conn,
- SmPointer client_data);
-static void xsmp_interact (SmcConn smc_conn,
- SmPointer client_data);
-
-static SmProp *array_prop (const char *name,
- ...);
-static SmProp *ptrarray_prop (const char *name,
- GPtrArray *values);
-static SmProp *string_prop (const char *name,
- const char *value);
-static SmProp *card8_prop (const char *name,
- unsigned char value);
-
-static void set_properties (EggSMClientXSMP *xsmp, ...);
-static void delete_properties (EggSMClientXSMP *xsmp, ...);
-
-static GPtrArray *generate_command (char **argv,
- const char *client_id,
- const char *state_file);
-
-static void save_state (EggSMClientXSMP *xsmp);
-static void do_save_yourself (EggSMClientXSMP *xsmp);
-static void update_pending_events (EggSMClientXSMP *xsmp);
-
-static void ice_init (void);
-static gboolean process_ice_messages (IceConn ice_conn);
-static void smc_error_handler (SmcConn smc_conn,
- Bool swap,
- int offending_minor_opcode,
- unsigned long offending_sequence,
- int error_class,
- int severity,
- SmPointer values);
-
-G_DEFINE_TYPE (EggSMClientXSMP, egg_sm_client_xsmp, EGG_TYPE_SM_CLIENT)
-
-static void
-egg_sm_client_xsmp_init (EggSMClientXSMP *xsmp)
-{
- xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
- xsmp->connection = NULL;
- xsmp->restart_style = SmRestartIfRunning;
-}
-
-static void
-egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass)
-{
- EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
-
- sm_client_class->startup = sm_client_xsmp_startup;
- sm_client_class->set_restart_command = sm_client_xsmp_set_restart_command;
- sm_client_class->set_discard_command = sm_client_xsmp_set_discard_command;
- sm_client_class->will_quit = sm_client_xsmp_will_quit;
- sm_client_class->end_session = sm_client_xsmp_end_session;
-}
-
-EggSMClient *
-egg_sm_client_xsmp_new (void)
-{
- if (!g_getenv ("SESSION_MANAGER"))
- return NULL;
-
- return g_object_new (EGG_TYPE_SM_CLIENT_XSMP, NULL);
-}
-
-static gboolean
-sm_client_xsmp_set_initial_properties (gpointer user_data)
-{
- EggSMClientXSMP *xsmp = user_data;
- EggDesktopFile *desktop_file;
- GPtrArray *clone, *restart;
- char pid_str[64];
-
- if (xsmp->idle)
- {
- g_source_remove (xsmp->idle);
- xsmp->idle = 0;
- }
- xsmp->waiting_to_set_initial_properties = FALSE;
-
- if (egg_sm_client_get_mode () == EGG_SM_CLIENT_MODE_NO_RESTART)
- xsmp->restart_style = SmRestartNever;
-
- /* Parse info out of desktop file */
- desktop_file = egg_get_desktop_file ();
- if (desktop_file)
- {
- GError *err = NULL;
- char *cmdline, **argv;
- int argc;
-
- if (xsmp->restart_style == SmRestartIfRunning)
- {
- if (egg_desktop_file_get_boolean (desktop_file,
- "X-GNOME-AutoRestart", NULL))
- xsmp->restart_style = SmRestartImmediately;
- }
-
- if (!xsmp->set_restart_command)
- {
- cmdline = egg_desktop_file_parse_exec (desktop_file, NULL, &err);
- if (cmdline && g_shell_parse_argv (cmdline, &argc, &argv, &err))
- {
- egg_sm_client_set_restart_command (EGG_SM_CLIENT (xsmp),
- argc, (const char **)argv);
- g_strfreev (argv);
- }
- else
- {
- g_warning ("Could not parse Exec line in desktop file: %s",
- err->message);
- g_error_free (err);
- }
- g_free (cmdline);
- }
- }
-
- if (!xsmp->set_restart_command)
- xsmp->restart_command = g_strsplit (g_get_prgname (), " ", -1);
-
- clone = generate_command (xsmp->restart_command, NULL, NULL);
- restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL);
-
- g_debug ("Setting initial properties");
-
- /* Program, CloneCommand, RestartCommand, and UserID are required.
- * ProcessID isn't required, but the SM may be able to do something
- * useful with it.
- */
- g_snprintf (pid_str, sizeof (pid_str), "%lu", (gulong) getpid ());
- set_properties (xsmp,
- string_prop (SmProgram, g_get_prgname ()),
- ptrarray_prop (SmCloneCommand, clone),
- ptrarray_prop (SmRestartCommand, restart),
- string_prop (SmUserID, g_get_user_name ()),
- string_prop (SmProcessID, pid_str),
- card8_prop (SmRestartStyleHint, xsmp->restart_style),
- NULL);
- g_ptr_array_free (clone, TRUE);
- g_ptr_array_free (restart, TRUE);
-
- if (desktop_file)
- {
- set_properties (xsmp,
- string_prop ("_GSM_DesktopFile", egg_desktop_file_get_source (desktop_file)),
- NULL);
- }
-
- update_pending_events (xsmp);
- return FALSE;
-}
-
-/* This gets called from two different places: xsmp_die() (when the
- * server asks us to disconnect) and process_ice_messages() (when the
- * server disconnects unexpectedly).
- */
-static void
-sm_client_xsmp_disconnect (EggSMClientXSMP *xsmp)
-{
- SmcConn connection;
-
- if (!xsmp->connection)
- return;
-
- g_debug ("Disconnecting");
-
- connection = xsmp->connection;
- xsmp->connection = NULL;
- SmcCloseConnection (connection, 0, NULL);
- xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
-
- xsmp->waiting_to_save_myself = FALSE;
- update_pending_events (xsmp);
-}
-
-static void
-sm_client_xsmp_startup (EggSMClient *client,
- const char *client_id)
-{
- EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
- SmcCallbacks callbacks;
- char *ret_client_id;
- char error_string_ret[256];
-
- xsmp->client_id = g_strdup (client_id);
-
- ice_init ();
- SmcSetErrorHandler (smc_error_handler);
-
- callbacks.save_yourself.callback = xsmp_save_yourself;
- callbacks.die.callback = xsmp_die;
- callbacks.save_complete.callback = xsmp_save_complete;
- callbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
-
- callbacks.save_yourself.client_data = xsmp;
- callbacks.die.client_data = xsmp;
- callbacks.save_complete.client_data = xsmp;
- callbacks.shutdown_cancelled.client_data = xsmp;
-
- client_id = NULL;
- error_string_ret[0] = '\0';
- xsmp->connection =
- SmcOpenConnection (NULL, xsmp, SmProtoMajor, SmProtoMinor,
- SmcSaveYourselfProcMask | SmcDieProcMask |
- SmcSaveCompleteProcMask |
- SmcShutdownCancelledProcMask,
- &callbacks,
- xsmp->client_id, &ret_client_id,
- sizeof (error_string_ret), error_string_ret);
-
- if (!xsmp->connection)
- {
- g_warning ("Failed to connect to the session manager: %s\n",
- error_string_ret[0] ?
- error_string_ret : "no error message given");
- xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
- return;
- }
-
- /* We expect a pointless initial SaveYourself if either (a) we
- * didn't have an initial client ID, or (b) we DID have an initial
- * client ID, but the server rejected it and gave us a new one.
- */
- if (!xsmp->client_id ||
- (ret_client_id && strcmp (xsmp->client_id, ret_client_id) != 0))
- xsmp->expecting_initial_save_yourself = TRUE;
-
- if (ret_client_id)
- {
- g_free (xsmp->client_id);
- xsmp->client_id = g_strdup (ret_client_id);
- free (ret_client_id);
-
- gdk_threads_enter ();
-#if !GTK_CHECK_VERSION(2,91,7) && !GTK_CHECK_VERSION(3,0,0)
- gdk_set_sm_client_id (xsmp->client_id);
-#else
- gdk_x11_set_sm_client_id (xsmp->client_id);
-#endif
- gdk_threads_leave ();
-
- g_debug ("Got client ID \"%s\"", xsmp->client_id);
- }
-
- xsmp->state = XSMP_STATE_IDLE;
-
- /* Do not set the initial properties until we reach the main loop,
- * so that the application has a chance to call
- * egg_set_desktop_file(). (This may also help the session manager
- * have a better idea of when the application is fully up and
- * running.)
- */
- xsmp->waiting_to_set_initial_properties = TRUE;
- xsmp->idle = g_idle_add (sm_client_xsmp_set_initial_properties, client);
-}
-
-static void
-sm_client_xsmp_set_restart_command (EggSMClient *client,
- int argc,
- const char **argv)
-{
- EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
- int i;
-
- g_strfreev (xsmp->restart_command);
-
- xsmp->restart_command = g_new (char *, argc + 1);
- for (i = 0; i < argc; i++)
- xsmp->restart_command[i] = g_strdup (argv[i]);
- xsmp->restart_command[i] = NULL;
-
- xsmp->set_restart_command = TRUE;
-}
-
-static void
-sm_client_xsmp_set_discard_command (EggSMClient *client,
- int argc,
- const char **argv)
-{
- EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
- int i;
-
- g_strfreev (xsmp->discard_command);
-
- xsmp->discard_command = g_new (char *, argc + 1);
- for (i = 0; i < argc; i++)
- xsmp->discard_command[i] = g_strdup (argv[i]);
- xsmp->discard_command[i] = NULL;
-
- xsmp->set_discard_command = TRUE;
-}
-
-static void
-sm_client_xsmp_will_quit (EggSMClient *client,
- gboolean will_quit)
-{
- EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
-
- if (xsmp->state == XSMP_STATE_CONNECTION_CLOSED)
- {
- /* The session manager has already exited! Schedule a quit
- * signal.
- */
- xsmp->waiting_to_emit_quit = TRUE;
- update_pending_events (xsmp);
- return;
- }
- else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
- {
- /* We received a ShutdownCancelled message while the application
- * was interacting; Schedule a quit_cancelled signal.
- */
- xsmp->waiting_to_emit_quit_cancelled = TRUE;
- update_pending_events (xsmp);
- return;
- }
-
- g_return_if_fail (xsmp->state == XSMP_STATE_INTERACT);
-
- g_debug ("Sending InteractDone(%s)", will_quit ? "False" : "True");
- SmcInteractDone (xsmp->connection, !will_quit);
-
- if (will_quit && xsmp->need_save_state)
- save_state (xsmp);
-
- g_debug ("Sending SaveYourselfDone(%s)", will_quit ? "True" : "False");
- SmcSaveYourselfDone (xsmp->connection, will_quit);
- xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
-}
-
-static gboolean
-sm_client_xsmp_end_session (EggSMClient *client,
- EggSMClientEndStyle style,
- gboolean request_confirmation)
-{
- EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
- int save_type;
-
- /* To end the session via XSMP, we have to send a
- * SaveYourselfRequest. We aren't allowed to do that if anything
- * else is going on, but we don't want to expose this fact to the
- * application. So we do our best to patch things up here...
- *
- * In the worst case, this method might block for some length of
- * time in process_ice_messages, but the only time that code path is
- * honestly likely to get hit is if the application tries to end the
- * session as the very first thing it does, in which case it
- * probably won't actually block anyway. It's not worth gunking up
- * the API to try to deal nicely with the other 0.01% of cases where
- * this happens.
- */
-
- while (xsmp->state != XSMP_STATE_IDLE ||
- xsmp->expecting_initial_save_yourself)
- {
- /* If we're already shutting down, we don't need to do anything. */
- if (xsmp->shutting_down)
- return TRUE;
-
- switch (xsmp->state)
- {
- case XSMP_STATE_CONNECTION_CLOSED:
- return FALSE;
-
- case XSMP_STATE_SAVE_YOURSELF:
- /* Trying to log out from the save_state callback? Whatever.
- * Abort the save_state.
- */
- SmcSaveYourselfDone (xsmp->connection, FALSE);
- xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
- break;
-
- case XSMP_STATE_INTERACT_REQUEST:
- case XSMP_STATE_INTERACT:
- case XSMP_STATE_SHUTDOWN_CANCELLED:
- /* Already in a shutdown-related state, just ignore
- * the new shutdown request...
- */
- return TRUE;
-
- case XSMP_STATE_IDLE:
- if (xsmp->waiting_to_set_initial_properties)
- sm_client_xsmp_set_initial_properties (xsmp);
-
- if (!xsmp->expecting_initial_save_yourself)
- break;
- /* else fall through */
-
- case XSMP_STATE_SAVE_YOURSELF_DONE:
- /* We need to wait for some response from the server.*/
- process_ice_messages (SmcGetIceConnection (xsmp->connection));
- break;
-
- default:
- /* Hm... shouldn't happen */
- return FALSE;
- }
- }
-
- /* xfce4-session will do the wrong thing if we pass SmSaveGlobal and
- * the user chooses to save the session. But gnome-session will do
- * the wrong thing if we pass SmSaveBoth and the user chooses NOT to
- * save the session... Sigh.
- */
- if (!strcmp (SmcVendor (xsmp->connection), "xfce4-session"))
- save_type = SmSaveBoth;
- else
- save_type = SmSaveGlobal;
-
- g_debug ("Sending SaveYourselfRequest(SmSaveGlobal, Shutdown, SmInteractStyleAny, %sFast)", request_confirmation ? "!" : "");
- SmcRequestSaveYourself (xsmp->connection,
- save_type,
- True, /* shutdown */
- SmInteractStyleAny,
- !request_confirmation, /* fast */
- True /* global */);
- return TRUE;
-}
-
-static gboolean
-idle_do_pending_events (gpointer data)
-{
- EggSMClientXSMP *xsmp = data;
- EggSMClient *client = data;
-
- gdk_threads_enter ();
-
- xsmp->idle = 0;
-
- if (xsmp->waiting_to_emit_quit)
- {
- xsmp->waiting_to_emit_quit = FALSE;
- egg_sm_client_quit (client);
- goto out;
- }
-
- if (xsmp->waiting_to_emit_quit_cancelled)
- {
- xsmp->waiting_to_emit_quit_cancelled = FALSE;
- egg_sm_client_quit_cancelled (client);
- xsmp->state = XSMP_STATE_IDLE;
- }
-
- if (xsmp->waiting_to_save_myself)
- {
- xsmp->waiting_to_save_myself = FALSE;
- do_save_yourself (xsmp);
- }
-
- out:
- gdk_threads_leave ();
- return FALSE;
-}
-
-static void
-update_pending_events (EggSMClientXSMP *xsmp)
-{
- gboolean want_idle =
- xsmp->waiting_to_emit_quit ||
- xsmp->waiting_to_emit_quit_cancelled ||
- xsmp->waiting_to_save_myself;
-
- if (want_idle)
- {
- if (xsmp->idle == 0)
- xsmp->idle = g_idle_add (idle_do_pending_events, xsmp);
- }
- else
- {
- if (xsmp->idle != 0)
- g_source_remove (xsmp->idle);
- xsmp->idle = 0;
- }
-}
-
-static void
-fix_broken_state (EggSMClientXSMP *xsmp, const char *message,
- gboolean send_interact_done,
- gboolean send_save_yourself_done)
-{
- g_warning ("Received XSMP %s message in state %s: client or server error",
- message, EGG_SM_CLIENT_XSMP_STATE (xsmp));
-
- /* Forget any pending SaveYourself plans we had */
- xsmp->waiting_to_save_myself = FALSE;
- update_pending_events (xsmp);
-
- if (send_interact_done)
- SmcInteractDone (xsmp->connection, False);
- if (send_save_yourself_done)
- SmcSaveYourselfDone (xsmp->connection, True);
-
- xsmp->state = send_save_yourself_done ? XSMP_STATE_SAVE_YOURSELF_DONE : XSMP_STATE_IDLE;
-}
-
-/* SM callbacks */
-
-static void
-xsmp_save_yourself (SmcConn smc_conn,
- SmPointer client_data,
- int save_type,
- Bool shutdown,
- int interact_style,
- Bool fast)
-{
- EggSMClientXSMP *xsmp = client_data;
- gboolean wants_quit_requested;
-
- g_debug ("Received SaveYourself(%s, %s, %s, %s) in state %s",
- save_type == SmSaveLocal ? "SmSaveLocal" :
- save_type == SmSaveGlobal ? "SmSaveGlobal" : "SmSaveBoth",
- shutdown ? "Shutdown" : "!Shutdown",
- interact_style == SmInteractStyleAny ? "SmInteractStyleAny" :
- interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" :
- "SmInteractStyleNone", fast ? "Fast" : "!Fast",
- EGG_SM_CLIENT_XSMP_STATE (xsmp));
-
- if (xsmp->state != XSMP_STATE_IDLE &&
- xsmp->state != XSMP_STATE_SHUTDOWN_CANCELLED)
- {
- fix_broken_state (xsmp, "SaveYourself", FALSE, TRUE);
- return;
- }
-
- if (xsmp->waiting_to_set_initial_properties)
- sm_client_xsmp_set_initial_properties (xsmp);
-
- /* If this is the initial SaveYourself, ignore it; we've already set
- * properties and there's no reason to actually save state too.
- */
- if (xsmp->expecting_initial_save_yourself)
- {
- xsmp->expecting_initial_save_yourself = FALSE;
-
- if (save_type == SmSaveLocal &&
- interact_style == SmInteractStyleNone &&
- !shutdown && !fast)
- {
- g_debug ("Sending SaveYourselfDone(True) for initial SaveYourself");
- SmcSaveYourselfDone (xsmp->connection, True);
- /* As explained in the comment at the end of
- * do_save_yourself(), SAVE_YOURSELF_DONE is the correct
- * state here, not IDLE.
- */
- xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
- return;
- }
- else
- g_warning ("First SaveYourself was not the expected one!");
- }
-
- /* Even ignoring the "fast" flag completely, there are still 18
- * different combinations of save_type, shutdown and interact_style.
- * We interpret them as follows:
- *
- * Type Shutdown Interact Interpretation
- * G F A/E/N do nothing (1)
- * G T N do nothing (1)*
- * G T A/E quit_requested (2)
- * L/B F A/E/N save_state (3)
- * L/B T N save_state (3)*
- * L/B T A/E quit_requested, then save_state (4)
- *
- * 1. Do nothing, because the SM asked us to do something
- * uninteresting (save open files, but then don't quit
- * afterward) or rude (save open files without asking the user
- * for confirmation).
- *
- * 2. Request interaction and then emit ::quit_requested. This
- * perhaps isn't quite correct for the SmInteractStyleErrors
- * case, but we don't care.
- *
- * 3. Emit ::save_state. The SmSaveBoth SaveYourselfs in these
- * rows essentially get demoted to SmSaveLocal, because their
- * Global halves correspond to "do nothing".
- *
- * 4. Request interaction, emit ::quit_requested, and then emit
- * ::save_state after interacting. This is the SmSaveBoth
- * equivalent of #2, but we also promote SmSaveLocal shutdown
- * SaveYourselfs to SmSaveBoth here, because we want to give
- * the user a chance to save open files before quitting.
- *
- * (* It would be nice if we could do something useful when the
- * session manager sends a SaveYourself with shutdown True and
- * SmInteractStyleNone. But we can't, so we just pretend it didn't
- * even tell us it was shutting down. The docs for ::quit mention
- * that it might not always be preceded by ::quit_requested.)
- */
-
- /* As an optimization, we don't actually request interaction and
- * emit ::quit_requested if the application isn't listening to the
- * signal.
- */
- wants_quit_requested = g_signal_has_handler_pending (xsmp, g_signal_lookup ("quit_requested", EGG_TYPE_SM_CLIENT), 0, FALSE);
-
- xsmp->need_save_state = (save_type != SmSaveGlobal);
- xsmp->need_quit_requested = (shutdown && wants_quit_requested &&
- interact_style != SmInteractStyleNone);
- xsmp->interact_errors = (interact_style == SmInteractStyleErrors);
-
- xsmp->shutting_down = shutdown;
-
- do_save_yourself (xsmp);
-}
-
-static void
-do_save_yourself (EggSMClientXSMP *xsmp)
-{
- if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
- {
- /* The SM cancelled a previous SaveYourself, but we haven't yet
- * had a chance to tell the application, so we can't start
- * processing this SaveYourself yet.
- */
- xsmp->waiting_to_save_myself = TRUE;
- update_pending_events (xsmp);
- return;
- }
-
- if (xsmp->need_quit_requested)
- {
- xsmp->state = XSMP_STATE_INTERACT_REQUEST;
-
- g_debug ("Sending InteractRequest(%s)",
- xsmp->interact_errors ? "Error" : "Normal");
- SmcInteractRequest (xsmp->connection,
- xsmp->interact_errors ? SmDialogError : SmDialogNormal,
- xsmp_interact,
- xsmp);
- return;
- }
-
- if (xsmp->need_save_state)
- {
- save_state (xsmp);
-
- /* Though unlikely, the client could have been disconnected
- * while the application was saving its state.
- */
- if (!xsmp->connection)
- return;
- }
-
- g_debug ("Sending SaveYourselfDone(True)");
- SmcSaveYourselfDone (xsmp->connection, True);
-
- /* The client state diagram in the XSMP spec says that after a
- * non-shutdown SaveYourself, we go directly back to "idle". But
- * everything else in both the XSMP spec and the libSM docs
- * disagrees.
- */
- xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
-}
-
-static void
-save_state (EggSMClientXSMP *xsmp)
-{
- GKeyFile *state_file;
- char *state_file_path, *data;
- EggDesktopFile *desktop_file;
- GPtrArray *restart, *discard;
- int offset, fd;
-
- /* We set xsmp->state before emitting save_state, but our caller is
- * responsible for setting it back afterward.
- */
- xsmp->state = XSMP_STATE_SAVE_YOURSELF;
-
- state_file = egg_sm_client_save_state ((EggSMClient *)xsmp);
- if (!state_file)
- {
- restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL);
- set_properties (xsmp,
- ptrarray_prop (SmRestartCommand, restart),
- NULL);
- g_ptr_array_free (restart, TRUE);
-
- if (xsmp->set_discard_command)
- {
- discard = generate_command (xsmp->discard_command, NULL, NULL);
- set_properties (xsmp,
- ptrarray_prop (SmDiscardCommand, discard),
- NULL);
- g_ptr_array_free (discard, TRUE);
- }
- else
- delete_properties (xsmp, SmDiscardCommand, NULL);
-
- return;
- }
-
- desktop_file = egg_get_desktop_file ();
- if (desktop_file)
- {
- GKeyFile *merged_file;
- char *desktop_file_path;
-
- merged_file = g_key_file_new ();
- desktop_file_path =
- g_filename_from_uri (egg_desktop_file_get_source (desktop_file),
- NULL, NULL);
- if (desktop_file_path &&
- g_key_file_load_from_file (merged_file, desktop_file_path,
- G_KEY_FILE_KEEP_COMMENTS |
- G_KEY_FILE_KEEP_TRANSLATIONS, NULL))
- {
- guint g, k, i;
- char **groups, **keys, *value, *exec;
-
- groups = g_key_file_get_groups (state_file, NULL);
- for (g = 0; groups[g]; g++)
- {
- keys = g_key_file_get_keys (state_file, groups[g], NULL, NULL);
- for (k = 0; keys[k]; k++)
- {
- value = g_key_file_get_value (state_file, groups[g],
- keys[k], NULL);
- if (value)
- {
- g_key_file_set_value (merged_file, groups[g],
- keys[k], value);
- g_free (value);
- }
- }
- g_strfreev (keys);
- }
- g_strfreev (groups);
-
- g_key_file_free (state_file);
- state_file = merged_file;
-
- /* Update Exec key using "--sm-client-state-file %k" */
- restart = generate_command (xsmp->restart_command,
- NULL, "%k");
- for (i = 0; i < restart->len; i++)
- restart->pdata[i] = g_shell_quote (restart->pdata[i]);
- g_ptr_array_add (restart, NULL);
- exec = g_strjoinv (" ", (char **)restart->pdata);
- g_strfreev ((char **)restart->pdata);
- g_ptr_array_free (restart, FALSE);
-
- g_key_file_set_string (state_file, EGG_DESKTOP_FILE_GROUP,
- EGG_DESKTOP_FILE_KEY_EXEC,
- exec);
- g_free (exec);
- }
- else
- desktop_file = NULL;
-
- g_free (desktop_file_path);
- }
-
- /* Now write state_file to disk. (We can't use mktemp(), because
- * that requires the filename to end with "XXXXXX", and we want
- * it to end with ".desktop".)
- */
-
- data = g_key_file_to_data (state_file, NULL, NULL);
- g_key_file_free (state_file);
-
- offset = 0;
- while (1)
- {
- state_file_path = g_strdup_printf ("%s%csession-state%c%s-%ld.%s",
- g_get_user_config_dir (),
- G_DIR_SEPARATOR, G_DIR_SEPARATOR,
- g_get_prgname (),
- (long)time (NULL) + offset,
- desktop_file ? "desktop" : "state");
-
- fd = open (state_file_path, O_WRONLY | O_CREAT | O_EXCL, 0644);
- if (fd == -1)
- {
- if (errno == EEXIST)
- {
- offset++;
- g_free (state_file_path);
- continue;
- }
- else if (errno == ENOTDIR || errno == ENOENT)
- {
- char *sep = strrchr (state_file_path, G_DIR_SEPARATOR);
-
- *sep = '\0';
- if (g_mkdir_with_parents (state_file_path, 0755) != 0)
- {
- g_warning ("Could not create directory '%s'",
- state_file_path);
- g_free (state_file_path);
- state_file_path = NULL;
- break;
- }
-
- continue;
- }
-
- g_warning ("Could not create file '%s': %s",
- state_file_path, g_strerror (errno));
- g_free (state_file_path);
- state_file_path = NULL;
- break;
- }
-
- close (fd);
- g_file_set_contents (state_file_path, data, -1, NULL);
- break;
- }
- g_free (data);
-
- restart = generate_command (xsmp->restart_command, xsmp->client_id,
- state_file_path);
- set_properties (xsmp,
- ptrarray_prop (SmRestartCommand, restart),
- NULL);
- g_ptr_array_free (restart, TRUE);
-
- if (state_file_path)
- {
- set_properties (xsmp,
- array_prop (SmDiscardCommand,
- "/bin/rm", "-rf", state_file_path,
- NULL),
- NULL);
- g_free (state_file_path);
- }
-}
-
-static void
-xsmp_interact (SmcConn smc_conn,
- SmPointer client_data)
-{
- EggSMClientXSMP *xsmp = client_data;
- EggSMClient *client = client_data;
-
- g_debug ("Received Interact message in state %s",
- EGG_SM_CLIENT_XSMP_STATE (xsmp));
-
- if (xsmp->state != XSMP_STATE_INTERACT_REQUEST)
- {
- fix_broken_state (xsmp, "Interact", TRUE, TRUE);
- return;
- }
-
- xsmp->state = XSMP_STATE_INTERACT;
- egg_sm_client_quit_requested (client);
-}
-
-static void
-xsmp_die (SmcConn smc_conn,
- SmPointer client_data)
-{
- EggSMClientXSMP *xsmp = client_data;
- EggSMClient *client = client_data;
-
- g_debug ("Received Die message in state %s",
- EGG_SM_CLIENT_XSMP_STATE (xsmp));
-
- sm_client_xsmp_disconnect (xsmp);
- egg_sm_client_quit (client);
-}
-
-static void
-xsmp_save_complete (SmcConn smc_conn,
- SmPointer client_data)
-{
- EggSMClientXSMP *xsmp = client_data;
-
- g_debug ("Received SaveComplete message in state %s",
- EGG_SM_CLIENT_XSMP_STATE (xsmp));
-
- if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE)
- xsmp->state = XSMP_STATE_IDLE;
- else
- fix_broken_state (xsmp, "SaveComplete", FALSE, FALSE);
-}
-
-static void
-xsmp_shutdown_cancelled (SmcConn smc_conn,
- SmPointer client_data)
-{
- EggSMClientXSMP *xsmp = client_data;
- EggSMClient *client = client_data;
-
- g_debug ("Received ShutdownCancelled message in state %s",
- EGG_SM_CLIENT_XSMP_STATE (xsmp));
-
- xsmp->shutting_down = FALSE;
-
- if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE)
- {
- /* We've finished interacting and now the SM has agreed to
- * cancel the shutdown.
- */
- xsmp->state = XSMP_STATE_IDLE;
- egg_sm_client_quit_cancelled (client);
- }
- else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
- {
- /* Hm... ok, so we got a shutdown SaveYourself, which got
- * cancelled, but the application was still interacting, so we
- * didn't tell it yet, and then *another* SaveYourself arrived,
- * which we must still be waiting to tell the app about, except
- * that now that SaveYourself has been cancelled too! Dizzy yet?
- */
- xsmp->waiting_to_save_myself = FALSE;
- update_pending_events (xsmp);
- }
- else
- {
- g_debug ("Sending SaveYourselfDone(False)");
- SmcSaveYourselfDone (xsmp->connection, False);
-
- if (xsmp->state == XSMP_STATE_INTERACT)
- {
- /* The application is currently interacting, so we can't
- * tell it about the cancellation yet; we will wait until
- * after it calls egg_sm_client_will_quit().
- */
- xsmp->state = XSMP_STATE_SHUTDOWN_CANCELLED;
- }
- else
- {
- /* The shutdown was cancelled before the application got a
- * chance to interact.
- */
- xsmp->state = XSMP_STATE_IDLE;
- }
- }
-}
-
-/* Utilities */
-
-/* Create a restart/clone/Exec command based on @restart_command.
- * If @client_id is non-%NULL, add "--sm-client-id @client_id".
- * If @state_file is non-%NULL, add "--sm-client-state-file @state_file".
- *
- * None of the input strings are g_strdup()ed; the caller must keep
- * them around until it is done with the returned GPtrArray, and must
- * then free the array, but not its contents.
- */
-static GPtrArray *
-generate_command (char **argv, const char *client_id,
- const char *state_file)
-{
- GPtrArray *cmd;
- int i;
-
- cmd = g_ptr_array_new ();
- g_ptr_array_add (cmd, argv[0]);
-
- if (client_id)
- {
- g_ptr_array_add (cmd, "--sm-client-id");
- g_ptr_array_add (cmd, (char *)client_id);
- }
-
- if (state_file)
- {
- g_ptr_array_add (cmd, "--sm-client-state-file");
- g_ptr_array_add (cmd, (char *)state_file);
- }
-
- for (i = 1; argv[i]; i++)
- g_ptr_array_add (cmd, argv[i]);
-
- return cmd;
-}
-
-/* Takes a NULL-terminated list of SmProp * values, created by
- * array_prop, ptrarray_prop, string_prop, card8_prop, sets them, and
- * frees them.
- */
-static void
-set_properties (EggSMClientXSMP *xsmp, ...)
-{
- GPtrArray *props;
- SmProp *prop;
- va_list ap;
- guint i;
-
- props = g_ptr_array_new ();
-
- va_start (ap, xsmp);
- while ((prop = va_arg (ap, SmProp *)))
- g_ptr_array_add (props, prop);
- va_end (ap);
-
- if (xsmp->connection)
- {
- SmcSetProperties (xsmp->connection, props->len,
- (SmProp **)props->pdata);
- }
-
- for (i = 0; i < props->len; i++)
- {
- prop = props->pdata[i];
- g_free (prop->vals);
- g_free (prop);
- }
- g_ptr_array_free (props, TRUE);
-}
-
-/* Takes a NULL-terminated list of property names and deletes them. */
-static void
-delete_properties (EggSMClientXSMP *xsmp, ...)
-{
- GPtrArray *props;
- char *prop;
- va_list ap;
-
- if (!xsmp->connection)
- return;
-
- props = g_ptr_array_new ();
-
- va_start (ap, xsmp);
- while ((prop = va_arg (ap, char *)))
- g_ptr_array_add (props, prop);
- va_end (ap);
-
- SmcDeleteProperties (xsmp->connection, props->len,
- (char **)props->pdata);
-
- g_ptr_array_free (props, TRUE);
-}
-
-/* Takes an array of strings and creates a LISTofARRAY8 property. The
- * strings are neither dupped nor freed; they need to remain valid
- * until you're done with the SmProp.
- */
-static SmProp *
-array_prop (const char *name, ...)
-{
- SmProp *prop;
- SmPropValue pv;
- GArray *vals;
- char *value;
- va_list ap;
-
- prop = g_new (SmProp, 1);
- prop->name = (char *)name;
- prop->type = SmLISTofARRAY8;
-
- vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue));
-
- va_start (ap, name);
- while ((value = va_arg (ap, char *)))
- {
- pv.length = strlen (value);
- pv.value = value;
- g_array_append_val (vals, pv);
- }
-
- prop->num_vals = vals->len;
- prop->vals = (SmPropValue *)vals->data;
-
- g_array_free (vals, FALSE);
-
- return prop;
-}
-
-/* Takes a GPtrArray of strings and creates a LISTofARRAY8 property.
- * The array contents are neither dupped nor freed; they need to
- * remain valid until you're done with the SmProp.
- */
-static SmProp *
-ptrarray_prop (const char *name, GPtrArray *values)
-{
- SmProp *prop;
- SmPropValue pv;
- GArray *vals;
- guint i;
-
- prop = g_new (SmProp, 1);
- prop->name = (char *)name;
- prop->type = SmLISTofARRAY8;
-
- vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue));
-
- for (i = 0; i < values->len; i++)
- {
- pv.length = strlen (values->pdata[i]);
- pv.value = values->pdata[i];
- g_array_append_val (vals, pv);
- }
-
- prop->num_vals = vals->len;
- prop->vals = (SmPropValue *)vals->data;
-
- g_array_free (vals, FALSE);
-
- return prop;
-}
-
-/* Takes a string and creates an ARRAY8 property. The string is
- * neither dupped nor freed; it needs to remain valid until you're
- * done with the SmProp.
- */
-static SmProp *
-string_prop (const char *name, const char *value)
-{
- SmProp *prop;
-
- prop = g_new (SmProp, 1);
- prop->name = (char *)name;
- prop->type = SmARRAY8;
-
- prop->num_vals = 1;
- prop->vals = g_new (SmPropValue, 1);
-
- prop->vals[0].length = strlen (value);
- prop->vals[0].value = (char *)value;
-
- return prop;
-}
-
-/* Takes a char and creates a CARD8 property. */
-static SmProp *
-card8_prop (const char *name, unsigned char value)
-{
- SmProp *prop;
- char *card8val;
-
- /* To avoid having to allocate and free prop->vals[0], we cheat and
- * make vals a 2-element-long array and then use the second element
- * to store value.
- */
-
- prop = g_new (SmProp, 1);
- prop->name = (char *)name;
- prop->type = SmCARD8;
-
- prop->num_vals = 1;
- prop->vals = g_new (SmPropValue, 2);
- card8val = (char *)(&prop->vals[1]);
- card8val[0] = value;
-
- prop->vals[0].length = 1;
- prop->vals[0].value = card8val;
-
- return prop;
-}
-
-/* ICE code. This makes no effort to play nice with anyone else trying
- * to use libICE. Fortunately, no one uses libICE for anything other
- * than SM. (DCOP uses ICE, but it has its own private copy of
- * libICE.)
- *
- * When this moves to gtk, it will need to be cleverer, to avoid
- * tripping over old apps that use GnomeClient or that use libSM
- * directly.
- */
-
-#include <X11/ICE/ICElib.h>
-#include <fcntl.h>
-
-static void ice_error_handler (IceConn ice_conn,
- Bool swap,
- int offending_minor_opcode,
- unsigned long offending_sequence,
- int error_class,
- int severity,
- IcePointer values);
-static void ice_io_error_handler (IceConn ice_conn);
-static void ice_connection_watch (IceConn ice_conn,
- IcePointer client_data,
- Bool opening,
- IcePointer *watch_data);
-
-static void
-ice_init (void)
-{
- IceSetIOErrorHandler (ice_io_error_handler);
- IceSetErrorHandler (ice_error_handler);
- IceAddConnectionWatch (ice_connection_watch, NULL);
-}
-
-static gboolean
-process_ice_messages (IceConn ice_conn)
-{
- IceProcessMessagesStatus status;
-
- gdk_threads_enter ();
- status = IceProcessMessages (ice_conn, NULL, NULL);
- gdk_threads_leave ();
-
- switch (status)
- {
- case IceProcessMessagesSuccess:
- return TRUE;
-
- case IceProcessMessagesIOError:
- sm_client_xsmp_disconnect (IceGetConnectionContext (ice_conn));
- return FALSE;
-
- case IceProcessMessagesConnectionClosed:
- return FALSE;
-
- default:
- g_assert_not_reached ();
- }
-}
-
-static gboolean
-ice_iochannel_watch (GIOChannel *channel,
- GIOCondition condition,
- gpointer client_data)
-{
- return process_ice_messages (client_data);
-}
-
-static void
-ice_connection_watch (IceConn ice_conn,
- IcePointer client_data,
- Bool opening,
- IcePointer *watch_data)
-{
- guint watch_id;
-
- if (opening)
- {
- GIOChannel *channel;
- int fd = IceConnectionNumber (ice_conn);
-
- fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
- channel = g_io_channel_unix_new (fd);
- watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR,
- ice_iochannel_watch, ice_conn);
- g_io_channel_unref (channel);
-
- *watch_data = GUINT_TO_POINTER (watch_id);
- }
- else
- {
- watch_id = GPOINTER_TO_UINT (*watch_data);
- g_source_remove (watch_id);
- }
-}
-
-static void
-ice_error_handler (IceConn ice_conn,
- Bool swap,
- int offending_minor_opcode,
- unsigned long offending_sequence,
- int error_class,
- int severity,
- IcePointer values)
-{
- /* Do nothing */
-}
-
-static void
-ice_io_error_handler (IceConn ice_conn)
-{
- /* Do nothing */
-}
-
-static void
-smc_error_handler (SmcConn smc_conn,
- Bool swap,
- int offending_minor_opcode,
- unsigned long offending_sequence,
- int error_class,
- int severity,
- SmPointer values)
-{
- /* Do nothing */
-}
diff --git a/lib/egg/eggsmclient.c b/lib/egg/eggsmclient.c
deleted file mode 100644
index 85aaee4e2..000000000
--- a/lib/egg/eggsmclient.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- * Copyright (C) 2007 Novell, Inc.
- *
- * 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.
- */
-
-#include "config.h"
-
-#include <string.h>
-#include <glib/gi18n.h>
-
-#include "eggsmclient.h"
-#include "eggsmclient-private.h"
-
-static void egg_sm_client_debug_handler (const char *log_domain,
- GLogLevelFlags log_level,
- const char *message,
- gpointer user_data);
-
-enum {
- SAVE_STATE,
- QUIT_REQUESTED,
- QUIT_CANCELLED,
- QUIT,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL];
-
-struct _EggSMClientPrivate {
- GKeyFile *state_file;
-};
-
-#define EGG_SM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_SM_CLIENT, EggSMClientPrivate))
-
-G_DEFINE_TYPE (EggSMClient, egg_sm_client, G_TYPE_OBJECT)
-
-static EggSMClient *global_client;
-static EggSMClientMode global_client_mode = EGG_SM_CLIENT_MODE_NORMAL;
-
-static void
-egg_sm_client_init (EggSMClient *client)
-{
- ;
-}
-
-static void
-egg_sm_client_class_init (EggSMClientClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (EggSMClientPrivate));
-
- /**
- * EggSMClient::save_state:
- * @client: the client
- * @state_file: a #GKeyFile to save state information into
- *
- * Emitted when the session manager has requested that the
- * application save information about its current state. The
- * application should save its state into @state_file, and then the
- * session manager may then restart the application in a future
- * session and tell it to initialize itself from that state.
- *
- * You should not save any data into @state_file's "start group"
- * (ie, the %NULL group). Instead, applications should save their
- * data into groups with names that start with the application name,
- * and libraries that connect to this signal should save their data
- * into groups with names that start with the library name.
- *
- * Alternatively, rather than (or in addition to) using @state_file,
- * the application can save its state by calling
- * egg_sm_client_set_restart_command() during the processing of this
- * signal (eg, to include a list of files to open).
- **/
- signals[SAVE_STATE] =
- g_signal_new ("save_state",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EggSMClientClass, save_state),
- NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1, G_TYPE_POINTER);
-
- /**
- * EggSMClient::quit_requested:
- * @client: the client
- *
- * Emitted when the session manager requests that the application
- * exit (generally because the user is logging out). The application
- * should decide whether or not it is willing to quit (perhaps after
- * asking the user what to do with documents that have unsaved
- * changes) and then call egg_sm_client_will_quit(), passing %TRUE
- * or %FALSE to give its answer to the session manager. (It does not
- * need to give an answer before returning from the signal handler;
- * it can interact with the user asynchronously and then give its
- * answer later on.) If the application does not connect to this
- * signal, then #EggSMClient will automatically return %TRUE on its
- * behalf.
- *
- * The application should not save its session state as part of
- * handling this signal; if the user has requested that the session
- * be saved when logging out, then ::save_state will be emitted
- * separately.
- *
- * If the application agrees to quit, it should then wait for either
- * the ::quit_cancelled or ::quit signals to be emitted.
- **/
- signals[QUIT_REQUESTED] =
- g_signal_new ("quit_requested",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EggSMClientClass, quit_requested),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- /**
- * EggSMClient::quit_cancelled:
- * @client: the client
- *
- * Emitted when the session manager decides to cancel a logout after
- * the application has already agreed to quit. After receiving this
- * signal, the application can go back to what it was doing before
- * receiving the ::quit_requested signal.
- **/
- signals[QUIT_CANCELLED] =
- g_signal_new ("quit_cancelled",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EggSMClientClass, quit_cancelled),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- /**
- * EggSMClient::quit:
- * @client: the client
- *
- * Emitted when the session manager wants the application to quit
- * (generally because the user is logging out). The application
- * should exit as soon as possible after receiving this signal; if
- * it does not, the session manager may choose to forcibly kill it.
- *
- * Normally a GUI application would only be sent a ::quit if it
- * agreed to quit in response to a ::quit_requested signal. However,
- * this is not guaranteed; in some situations the session manager
- * may decide to end the session without giving applications a
- * chance to object.
- **/
- signals[QUIT] =
- g_signal_new ("quit",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EggSMClientClass, quit),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-}
-
-static gboolean sm_client_disable = FALSE;
-static char *sm_client_state_file = NULL;
-static char *sm_client_id = NULL;
-static char *sm_config_prefix = NULL;
-
-static gboolean
-sm_client_post_parse_func (GOptionContext *context,
- GOptionGroup *group,
- gpointer data,
- GError **error)
-{
- EggSMClient *client = egg_sm_client_get ();
-
- if (sm_client_id == NULL)
- {
- const gchar *desktop_autostart_id;
-
- desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
-
- if (desktop_autostart_id != NULL)
- sm_client_id = g_strdup (desktop_autostart_id);
- }
-
- /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
- * use the same client id. */
- g_unsetenv ("DESKTOP_AUTOSTART_ID");
-
- if (EGG_SM_CLIENT_GET_CLASS (client)->startup)
- EGG_SM_CLIENT_GET_CLASS (client)->startup (client, sm_client_id);
- return TRUE;
-}
-
-/**
- * egg_sm_client_get_option_group:
- *
- * Creates a %GOptionGroup containing the session-management-related
- * options. You should add this group to the application's
- * %GOptionContext if you want to use #EggSMClient.
- *
- * Return value: the %GOptionGroup
- **/
-GOptionGroup *
-egg_sm_client_get_option_group (void)
-{
- const GOptionEntry entries[] = {
- { "sm-client-disable", 0, 0,
- G_OPTION_ARG_NONE, &sm_client_disable,
- N_("Disable connection to session manager"), NULL },
- { "sm-client-state-file", 0, 0,
- G_OPTION_ARG_FILENAME, &sm_client_state_file,
- N_("Specify file containing saved configuration"), N_("FILE") },
- { "sm-client-id", 0, 0,
- G_OPTION_ARG_STRING, &sm_client_id,
- N_("Specify session management ID"), N_("ID") },
- /* GnomeClient compatibility option */
- { "sm-disable", 0, G_OPTION_FLAG_HIDDEN,
- G_OPTION_ARG_NONE, &sm_client_disable,
- NULL, NULL },
- /* GnomeClient compatibility option. This is a dummy option that only
- * exists so that sessions saved by apps with GnomeClient can be restored
- * later when they've switched to EggSMClient. See bug #575308.
- */
- { "sm-config-prefix", 0, G_OPTION_FLAG_HIDDEN,
- G_OPTION_ARG_STRING, &sm_config_prefix,
- NULL, NULL },
- { NULL }
- };
- GOptionGroup *group;
-
- /* Use our own debug handler for the "EggSMClient" domain. */
- g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
- egg_sm_client_debug_handler, NULL);
-
- 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_parse_hooks (group, NULL, sm_client_post_parse_func);
-
- return group;
-}
-
-/**
- * egg_sm_client_set_mode:
- * @mode: an #EggSMClient mode
- *
- * Sets the "mode" of #EggSMClient as follows:
- *
- * %EGG_SM_CLIENT_MODE_DISABLED: Session management is completely
- * disabled. The application will not even connect to the session
- * manager. (egg_sm_client_get() will still return an #EggSMClient,
- * but it will just be a dummy object.)
- *
- * %EGG_SM_CLIENT_MODE_NO_RESTART: The application will connect to
- * the session manager (and thus will receive notification when the
- * user is logging out, etc), but will request to not be
- * automatically restarted with saved state in future sessions.
- *
- * %EGG_SM_CLIENT_MODE_NORMAL: The default. #EggSMCLient will
- * function normally.
- *
- * This must be called before the application's main loop begins.
- **/
-void
-egg_sm_client_set_mode (EggSMClientMode mode)
-{
- global_client_mode = mode;
-}
-
-/**
- * egg_sm_client_get_mode:
- *
- * Gets the global #EggSMClientMode. See egg_sm_client_set_mode()
- * for details.
- *
- * Return value: the global #EggSMClientMode
- **/
-EggSMClientMode
-egg_sm_client_get_mode (void)
-{
- return global_client_mode;
-}
-
-/**
- * egg_sm_client_get:
- *
- * Returns the master #EggSMClient for the application.
- *
- * On platforms that support saved sessions (ie, POSIX/X11), the
- * application will only request to be restarted by the session
- * manager if you call egg_set_desktop_file() to set an application
- * desktop file. In particular, if the desktop file contains the key
- * "X
- *
- * Return value: the master #EggSMClient.
- **/
-EggSMClient *
-egg_sm_client_get (void)
-{
- if (!global_client)
- {
- if (global_client_mode != EGG_SM_CLIENT_MODE_DISABLED &&
- !sm_client_disable)
- {
-#if defined (GDK_WINDOWING_WIN32)
- global_client = egg_sm_client_win32_new ();
-#elif defined (GDK_WINDOWING_QUARTZ)
- global_client = egg_sm_client_osx_new ();
-#else
- /* If both D-Bus and XSMP are compiled in, try XSMP first
- * (since it supports state saving) and fall back to D-Bus
- * if XSMP isn't available.
- */
-# ifdef EGG_SM_CLIENT_BACKEND_XSMP
- global_client = egg_sm_client_xsmp_new ();
-# endif
-# ifdef EGG_SM_CLIENT_BACKEND_DBUS
- if (!global_client)
- global_client = egg_sm_client_dbus_new ();
-# endif
-#endif
- }
-
- /* Fallback: create a dummy client, so that callers don't have
- * to worry about a %NULL return value.
- */
- if (!global_client)
- global_client = g_object_new (EGG_TYPE_SM_CLIENT, NULL);
- }
-
- return global_client;
-}
-
-/**
- * egg_sm_client_is_resumed:
- * @client: the client
- *
- * Checks whether or not the current session has been resumed from
- * a previous saved session. If so, the application should call
- * egg_sm_client_get_state_file() and restore its state from the
- * returned #GKeyFile.
- *
- * Return value: %TRUE if the session has been resumed
- **/
-gboolean
-egg_sm_client_is_resumed (EggSMClient *client)
-{
- g_return_val_if_fail (client == global_client, FALSE);
-
- return sm_client_state_file != NULL;
-}
-
-/**
- * egg_sm_client_get_state_file:
- * @client: the client
- *
- * If the application was resumed by the session manager, this will
- * return the #GKeyFile containing its state from the previous
- * session.
- *
- * Note that other libraries and #EggSMClient itself may also store
- * state in the key file, so if you call egg_sm_client_get_groups(),
- * on it, the return value will likely include groups that you did not
- * put there yourself. (It is also not guaranteed that the first
- * group created by the application will still be the "start group"
- * when it is resumed.)
- *
- * Return value: the #GKeyFile containing the application's earlier
- * state, or %NULL on error. You should not free this key file; it
- * is owned by @client.
- **/
-GKeyFile *
-egg_sm_client_get_state_file (EggSMClient *client)
-{
- EggSMClientPrivate *priv = EGG_SM_CLIENT_GET_PRIVATE (client);
- char *state_file_path;
- GError *err = NULL;
-
- g_return_val_if_fail (client == global_client, NULL);
-
- if (!sm_client_state_file)
- return NULL;
- if (priv->state_file)
- return priv->state_file;
-
- if (!strncmp (sm_client_state_file, "file://", 7))
- state_file_path = g_filename_from_uri (sm_client_state_file, NULL, NULL);
- else
- state_file_path = g_strdup (sm_client_state_file);
-
- priv->state_file = g_key_file_new ();
- if (!g_key_file_load_from_file (priv->state_file, state_file_path, 0, &err))
- {
- g_warning ("Could not load SM state file '%s': %s",
- sm_client_state_file, err->message);
- g_clear_error (&err);
- g_key_file_free (priv->state_file);
- priv->state_file = NULL;
- }
-
- g_free (state_file_path);
- return priv->state_file;
-}
-
-/**
- * egg_sm_client_set_restart_command:
- * @client: the client
- * @argc: the length of @argv
- * @argv: argument vector
- *
- * Sets the command used to restart @client if it does not have a
- * .desktop file that can be used to find its restart command.
- *
- * This can also be used when handling the ::save_state signal, to
- * save the current state via an updated command line. (Eg, providing
- * a list of filenames to open when the application is resumed.)
- **/
-void
-egg_sm_client_set_restart_command (EggSMClient *client,
- int argc,
- const char **argv)
-{
- g_return_if_fail (EGG_IS_SM_CLIENT (client));
-
- if (EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command)
- EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command (client, argc, argv);
-}
-
-/**
- * egg_sm_client_set_discard_command:
- * @client: the client
- * @argc: the length of @argv
- * @argv: argument vector
- *
- * Sets the command used to discard a custom state file if using
- * egg_sm_client_set_restart_command(), which must be called before
- * using this function.
- **/
-void
-egg_sm_client_set_discard_command (EggSMClient *client,
- int argc,
- const char **argv)
-{
- g_return_if_fail (EGG_IS_SM_CLIENT (client));
-
- if (EGG_SM_CLIENT_GET_CLASS (client)->set_discard_command)
- EGG_SM_CLIENT_GET_CLASS (client)->set_discard_command (client, argc, argv);
-}
-
-/**
- * egg_sm_client_will_quit:
- * @client: the client
- * @will_quit: whether or not the application is willing to quit
- *
- * This MUST be called in response to the ::quit_requested signal, to
- * indicate whether or not the application is willing to quit. The
- * application may call it either directly from the signal handler, or
- * at some later point (eg, after asynchronously interacting with the
- * user).
- *
- * If the application does not connect to ::quit_requested,
- * #EggSMClient will call this method on its behalf (passing %TRUE
- * for @will_quit).
- *
- * After calling this method, the application should wait to receive
- * either ::quit_cancelled or ::quit.
- **/
-void
-egg_sm_client_will_quit (EggSMClient *client,
- gboolean will_quit)
-{
- g_return_if_fail (EGG_IS_SM_CLIENT (client));
-
- if (EGG_SM_CLIENT_GET_CLASS (client)->will_quit)
- EGG_SM_CLIENT_GET_CLASS (client)->will_quit (client, will_quit);
-}
-
-/**
- * egg_sm_client_end_session:
- * @style: a hint at how to end the session
- * @request_confirmation: whether or not the user should get a chance
- * to confirm the action
- *
- * Requests that the session manager end the current session. @style
- * indicates how the session should be ended, and
- * @request_confirmation indicates whether or not the user should be
- * given a chance to confirm the logout/reboot/shutdown. Both of these
- * flags are merely hints though; the session manager may choose to
- * ignore them.
- *
- * Return value: %TRUE if the request was sent; %FALSE if it could not
- * be (eg, because it could not connect to the session manager).
- **/
-gboolean
-egg_sm_client_end_session (EggSMClientEndStyle style,
- gboolean request_confirmation)
-{
- EggSMClient *client = egg_sm_client_get ();
-
- g_return_val_if_fail (EGG_IS_SM_CLIENT (client), FALSE);
-
- if (EGG_SM_CLIENT_GET_CLASS (client)->end_session)
- {
- return EGG_SM_CLIENT_GET_CLASS (client)->end_session (client, style,
- request_confirmation);
- }
- else
- return FALSE;
-}
-
-/* Signal-emitting callbacks from platform-specific code */
-
-GKeyFile *
-egg_sm_client_save_state (EggSMClient *client)
-{
- GKeyFile *state_file;
- char *group;
-
- g_return_val_if_fail (client == global_client, NULL);
-
- state_file = g_key_file_new ();
-
- g_debug ("Emitting save_state");
- g_signal_emit (client, signals[SAVE_STATE], 0, state_file);
- g_debug ("Done emitting save_state");
-
- group = g_key_file_get_start_group (state_file);
- if (group)
- {
- g_free (group);
- return state_file;
- }
- else
- {
- g_key_file_free (state_file);
- return NULL;
- }
-}
-
-void
-egg_sm_client_quit_requested (EggSMClient *client)
-{
- g_return_if_fail (client == global_client);
-
- if (!g_signal_has_handler_pending (client, signals[QUIT_REQUESTED], 0, FALSE))
- {
- g_debug ("Not emitting quit_requested because no one is listening");
- egg_sm_client_will_quit (client, TRUE);
- return;
- }
-
- g_debug ("Emitting quit_requested");
- g_signal_emit (client, signals[QUIT_REQUESTED], 0);
- g_debug ("Done emitting quit_requested");
-}
-
-void
-egg_sm_client_quit_cancelled (EggSMClient *client)
-{
- g_return_if_fail (client == global_client);
-
- g_debug ("Emitting quit_cancelled");
- g_signal_emit (client, signals[QUIT_CANCELLED], 0);
- g_debug ("Done emitting quit_cancelled");
-}
-
-void
-egg_sm_client_quit (EggSMClient *client)
-{
- g_return_if_fail (client == global_client);
-
- g_debug ("Emitting quit");
- g_signal_emit (client, signals[QUIT], 0);
- g_debug ("Done emitting quit");
-
- /* FIXME: should we just call gtk_main_quit() here? */
-}
-
-static void
-egg_sm_client_debug_handler (const char *log_domain,
- GLogLevelFlags log_level,
- const char *message,
- gpointer user_data)
-{
- static int debug = -1;
-
- if (debug < 0)
- debug = (g_getenv ("EGG_SM_CLIENT_DEBUG") != NULL);
-
- if (debug)
- g_log_default_handler (log_domain, log_level, message, NULL);
-}
diff --git a/lib/egg/eggsmclient.h b/lib/egg/eggsmclient.h
deleted file mode 100644
index f13bcecc0..000000000
--- a/lib/egg/eggsmclient.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* eggsmclient.h
- * Copyright (C) 2007 Novell, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 __EGG_SM_CLIENT_H__
-#define __EGG_SM_CLIENT_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define EGG_TYPE_SM_CLIENT (egg_sm_client_get_type ())
-#define EGG_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT, EggSMClient))
-#define EGG_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT, EggSMClientClass))
-#define EGG_IS_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT))
-#define EGG_IS_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT))
-#define EGG_SM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT, EggSMClientClass))
-
-typedef struct _EggSMClient EggSMClient;
-typedef struct _EggSMClientClass EggSMClientClass;
-typedef struct _EggSMClientPrivate EggSMClientPrivate;
-
-typedef enum {
- EGG_SM_CLIENT_END_SESSION_DEFAULT,
- EGG_SM_CLIENT_LOGOUT,
- EGG_SM_CLIENT_REBOOT,
- EGG_SM_CLIENT_SHUTDOWN
-} EggSMClientEndStyle;
-
-typedef enum {
- EGG_SM_CLIENT_MODE_DISABLED,
- EGG_SM_CLIENT_MODE_NO_RESTART,
- EGG_SM_CLIENT_MODE_NORMAL
-} EggSMClientMode;
-
-struct _EggSMClient
-{
- GObject parent;
-
-};
-
-struct _EggSMClientClass
-{
- GObjectClass parent_class;
-
- /* signals */
- void (*save_state) (EggSMClient *client,
- GKeyFile *state_file);
-
- void (*quit_requested) (EggSMClient *client);
- void (*quit_cancelled) (EggSMClient *client);
- void (*quit) (EggSMClient *client);
-
- /* virtual methods */
- void (*startup) (EggSMClient *client,
- const char *client_id);
- void (*set_restart_command) (EggSMClient *client,
- int argc,
- const char **argv);
- void (*set_discard_command) (EggSMClient *client,
- int argc,
- const char **argv);
- void (*will_quit) (EggSMClient *client,
- gboolean will_quit);
- gboolean (*end_session) (EggSMClient *client,
- EggSMClientEndStyle style,
- gboolean request_confirmation);
-
- /* Padding for future expansion */
- void (*_egg_reserved1) (void);
- void (*_egg_reserved2) (void);
- void (*_egg_reserved3) (void);
- void (*_egg_reserved4) (void);
-};
-
-GType egg_sm_client_get_type (void) G_GNUC_CONST;
-
-GOptionGroup *egg_sm_client_get_option_group (void);
-
-/* Initialization */
-void egg_sm_client_set_mode (EggSMClientMode mode);
-EggSMClientMode egg_sm_client_get_mode (void);
-EggSMClient *egg_sm_client_get (void);
-
-/* Resuming a saved session */
-gboolean egg_sm_client_is_resumed (EggSMClient *client);
-GKeyFile *egg_sm_client_get_state_file (EggSMClient *client);
-
-/* Alternate means of saving state */
-void egg_sm_client_set_restart_command (EggSMClient *client,
- int argc,
- const char **argv);
-void egg_sm_client_set_discard_command (EggSMClient *client,
- int argc,
- const char **argv);
-
-/* Handling "quit_requested" signal */
-void egg_sm_client_will_quit (EggSMClient *client,
- gboolean will_quit);
-
-/* Initiate a logout/reboot/shutdown */
-gboolean egg_sm_client_end_session (EggSMClientEndStyle style,
- gboolean request_confirmation);
-
-G_END_DECLS
-
-
-#endif /* __EGG_SM_CLIENT_H__ */
diff --git a/lib/egg/eggsmclient.patch b/lib/egg/eggsmclient.patch
deleted file mode 100644
index 728902740..000000000
--- a/lib/egg/eggsmclient.patch
+++ /dev/null
@@ -1,198 +0,0 @@
-diff --git a/libegg/smclient/eggdesktopfile.c b/libegg/smclient/eggdesktopfile.c
-index 357e548..c185998 100644
---- a/libegg/smclient/eggdesktopfile.c
-+++ b/libegg/smclient/eggdesktopfile.c
-@@ -1440,6 +1440,7 @@ egg_set_desktop_file (const char *desktop_file_path)
- g_error_free (error);
- }
-
-+#if 0
- if (egg_desktop_file) {
- /* Set localized application name and default window icon */
- if (egg_desktop_file->name)
-@@ -1452,6 +1453,7 @@ egg_set_desktop_file (const char *desktop_file_path)
- gtk_window_set_default_icon_name (egg_desktop_file->icon);
- }
- }
-+#endif
-
- G_UNLOCK (egg_desktop_file);
- }
-diff --git a/libegg/smclient/eggsmclient-xsmp.c b/libegg/smclient/eggsmclient-xsmp.c
-index 1a56156..81af7d2 100644
---- a/libegg/smclient/eggsmclient-xsmp.c
-+++ b/libegg/smclient/eggsmclient-xsmp.c
-@@ -88,6 +88,8 @@ struct _EggSMClientXSMP
- char **restart_command;
- gboolean set_restart_command;
- int restart_style;
-+ char **discard_command;
-+ gboolean set_discard_command;
-
- guint idle;
-
-@@ -117,6 +119,9 @@ static void sm_client_xsmp_startup (EggSMClient *client,
- static void sm_client_xsmp_set_restart_command (EggSMClient *client,
- int argc,
- const char **argv);
-+static void sm_client_xsmp_set_discard_command (EggSMClient *client,
-+ int argc,
-+ const char **argv);
- static void sm_client_xsmp_will_quit (EggSMClient *client,
- gboolean will_quit);
- static gboolean sm_client_xsmp_end_session (EggSMClient *client,
-@@ -150,7 +155,7 @@ static SmProp *card8_prop (const char *name,
- static void set_properties (EggSMClientXSMP *xsmp, ...);
- static void delete_properties (EggSMClientXSMP *xsmp, ...);
-
--static GPtrArray *generate_command (char **restart_command,
-+static GPtrArray *generate_command (char **argv,
- const char *client_id,
- const char *state_file);
-
-@@ -185,6 +190,7 @@ egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass)
-
- sm_client_class->startup = sm_client_xsmp_startup;
- sm_client_class->set_restart_command = sm_client_xsmp_set_restart_command;
-+ sm_client_class->set_discard_command = sm_client_xsmp_set_discard_command;
- sm_client_class->will_quit = sm_client_xsmp_will_quit;
- sm_client_class->end_session = sm_client_xsmp_end_session;
- }
-@@ -404,6 +410,24 @@ sm_client_xsmp_set_restart_command (EggSMClient *client,
- }
-
- static void
-+sm_client_xsmp_set_discard_command (EggSMClient *client,
-+ int argc,
-+ const char **argv)
-+{
-+ EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
-+ int i;
-+
-+ g_strfreev (xsmp->discard_command);
-+
-+ xsmp->discard_command = g_new (char *, argc + 1);
-+ for (i = 0; i < argc; i++)
-+ xsmp->discard_command[i] = g_strdup (argv[i]);
-+ xsmp->discard_command[i] = NULL;
-+
-+ xsmp->set_discard_command = TRUE;
-+}
-+
-+static void
- sm_client_xsmp_will_quit (EggSMClient *client,
- gboolean will_quit)
- {
-@@ -771,7 +795,7 @@ save_state (EggSMClientXSMP *xsmp)
- GKeyFile *state_file;
- char *state_file_path, *data;
- EggDesktopFile *desktop_file;
-- GPtrArray *restart;
-+ GPtrArray *restart, *discard;
- int offset, fd;
-
- /* We set xsmp->state before emitting save_state, but our caller is
-@@ -787,7 +811,18 @@ save_state (EggSMClientXSMP *xsmp)
- ptrarray_prop (SmRestartCommand, restart),
- NULL);
- g_ptr_array_free (restart, TRUE);
-- delete_properties (xsmp, SmDiscardCommand, NULL);
-+
-+ if (xsmp->set_discard_command)
-+ {
-+ discard = generate_command (xsmp->discard_command, NULL, NULL);
-+ set_properties (xsmp,
-+ ptrarray_prop (SmDiscardCommand, discard),
-+ NULL);
-+ g_ptr_array_free (discard, TRUE);
-+ }
-+ else
-+ delete_properties (xsmp, SmDiscardCommand, NULL);
-+
- return;
- }
-
-@@ -1041,14 +1076,14 @@ xsmp_shutdown_cancelled (SmcConn smc_conn,
- * then free the array, but not its contents.
- */
- static GPtrArray *
--generate_command (char **restart_command, const char *client_id,
-+generate_command (char **argv, const char *client_id,
- const char *state_file)
- {
- GPtrArray *cmd;
- int i;
-
- cmd = g_ptr_array_new ();
-- g_ptr_array_add (cmd, restart_command[0]);
-+ g_ptr_array_add (cmd, argv[0]);
-
- if (client_id)
- {
-@@ -1062,8 +1097,8 @@ generate_command (char **restart_command, const char *client_id,
- g_ptr_array_add (cmd, (char *)state_file);
- }
-
-- for (i = 1; restart_command[i]; i++)
-- g_ptr_array_add (cmd, restart_command[i]);
-+ for (i = 1; argv[i]; i++)
-+ g_ptr_array_add (cmd, argv[i]);
-
- return cmd;
- }
-diff --git a/libegg/smclient/eggsmclient.c b/libegg/smclient/eggsmclient.c
-index efa901d..85aaee4 100644
---- a/libegg/smclient/eggsmclient.c
-+++ b/libegg/smclient/eggsmclient.c
-@@ -445,6 +445,27 @@ egg_sm_client_set_restart_command (EggSMClient *client,
- }
-
- /**
-+ * egg_sm_client_set_discard_command:
-+ * @client: the client
-+ * @argc: the length of @argv
-+ * @argv: argument vector
-+ *
-+ * Sets the command used to discard a custom state file if using
-+ * egg_sm_client_set_restart_command(), which must be called before
-+ * using this function.
-+ **/
-+void
-+egg_sm_client_set_discard_command (EggSMClient *client,
-+ int argc,
-+ const char **argv)
-+{
-+ g_return_if_fail (EGG_IS_SM_CLIENT (client));
-+
-+ if (EGG_SM_CLIENT_GET_CLASS (client)->set_discard_command)
-+ EGG_SM_CLIENT_GET_CLASS (client)->set_discard_command (client, argc, argv);
-+}
-+
-+/**
- * egg_sm_client_will_quit:
- * @client: the client
- * @will_quit: whether or not the application is willing to quit
-diff --git a/libegg/smclient/eggsmclient.h b/libegg/smclient/eggsmclient.h
-index e620b75..f13bcec 100644
---- a/libegg/smclient/eggsmclient.h
-+++ b/libegg/smclient/eggsmclient.h
-@@ -72,6 +72,9 @@ struct _EggSMClientClass
- void (*set_restart_command) (EggSMClient *client,
- int argc,
- const char **argv);
-+ void (*set_discard_command) (EggSMClient *client,
-+ int argc,
-+ const char **argv);
- void (*will_quit) (EggSMClient *client,
- gboolean will_quit);
- gboolean (*end_session) (EggSMClient *client,
-@@ -102,6 +105,9 @@ GKeyFile *egg_sm_client_get_state_file (EggSMClient *client);
- void egg_sm_client_set_restart_command (EggSMClient *client,
- int argc,
- const char **argv);
-+void egg_sm_client_set_discard_command (EggSMClient *client,
-+ int argc,
-+ const char **argv);
-
- /* Handling "quit_requested" signal */
- void egg_sm_client_will_quit (EggSMClient *client,