totem r5805 - in trunk: . src
- From: chpe svn gnome org
- To: svn-commits-list gnome org
- Subject: totem r5805 - in trunk: . src
- Date: Sun, 23 Nov 2008 21:19:54 +0000 (UTC)
Author: chpe
Date: Sun Nov 23 21:19:54 2008
New Revision: 5805
URL: http://svn.gnome.org/viewvc/totem?rev=5805&view=rev
Log:
Bug 560328 â update smclient with latest libegg
Removed:
trunk/src/eggsmclient-2.patch
trunk/src/eggsmclient-3.patch
Modified:
trunk/ChangeLog
trunk/src/eggdesktopfile.c
trunk/src/eggdesktopfile.h
trunk/src/eggsmclient-1.patch
trunk/src/eggsmclient-osx.c
trunk/src/eggsmclient-win32.c
trunk/src/eggsmclient-xsmp.c
trunk/src/eggsmclient.c
Modified: trunk/src/eggdesktopfile.c
==============================================================================
--- trunk/src/eggdesktopfile.c (original)
+++ trunk/src/eggdesktopfile.c Sun Nov 23 21:19:54 2008
@@ -31,7 +31,6 @@
#include <unistd.h>
#include <glib/gi18n.h>
-#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
@@ -56,7 +55,6 @@
EggDesktopFile *
egg_desktop_file_new (const char *desktop_file_path, GError **error)
{
- EggDesktopFile *desktop_file;
GKeyFile *key_file;
key_file = g_key_file_new ();
@@ -66,13 +64,8 @@
return NULL;
}
- desktop_file = egg_desktop_file_new_from_key_file (key_file,
- desktop_file_path,
- error);
- if (!desktop_file)
- g_key_file_free (key_file);
-
- return desktop_file;
+ return egg_desktop_file_new_from_key_file (key_file, desktop_file_path,
+ error);
}
/**
@@ -106,9 +99,42 @@
full_path,
error);
g_free (full_path);
- if (!desktop_file)
- g_key_file_free (key_file);
+ return desktop_file;
+}
+
+/**
+ * egg_desktop_file_new_from_dirs:
+ * @desktop_file_path: relative path to a Freedesktop-style Desktop file
+ * @search_dirs: NULL-terminated array of directories to search
+ * @error: error pointer
+ *
+ * Looks for @desktop_file_path in the paths returned from
+ * g_get_user_data_dir() and g_get_system_data_dirs(), and creates
+ * a new #EggDesktopFile from it.
+ *
+ * Return value: the new #EggDesktopFile, or %NULL on error.
+ **/
+EggDesktopFile *
+egg_desktop_file_new_from_dirs (const char *desktop_file_path,
+ const char **search_dirs,
+ GError **error)
+{
+ EggDesktopFile *desktop_file;
+ GKeyFile *key_file;
+ char *full_path;
+
+ key_file = g_key_file_new ();
+ if (!g_key_file_load_from_dirs (key_file, desktop_file_path, search_dirs,
+ &full_path, 0, error))
+ {
+ g_key_file_free (key_file);
+ return NULL;
+ }
+ desktop_file = egg_desktop_file_new_from_key_file (key_file,
+ full_path,
+ error);
+ g_free (full_path);
return desktop_file;
}
@@ -119,8 +145,8 @@
* @error: error pointer
*
* Creates a new #EggDesktopFile for @key_file. Assumes ownership of
- * @key_file on success (meaning it will be freed when the desktop_file
- * is freed).
+ * @key_file (on success or failure); you should consider @key_file to
+ * be freed after calling this function.
*
* Return value: the new #EggDesktopFile, or %NULL on error.
**/
@@ -137,6 +163,7 @@
g_set_error (error, EGG_DESKTOP_FILE_ERROR,
EGG_DESKTOP_FILE_ERROR_INVALID,
_("File is not a valid .desktop file"));
+ g_key_file_free (key_file);
return NULL;
}
@@ -160,13 +187,14 @@
EGG_DESKTOP_FILE_ERROR_INVALID,
_("Unrecognized desktop file Version '%s'"), version);
g_free (version);
+ g_key_file_free (key_file);
return NULL;
}
- else
g_free (version);
}
desktop_file = g_new0 (EggDesktopFile, 1);
+ desktop_file->key_file = key_file;
if (g_path_is_absolute (source))
desktop_file->source = g_filename_to_uri (source, NULL, NULL);
@@ -202,7 +230,7 @@
if (!exec)
{
egg_desktop_file_free (desktop_file);
- g_free(type);
+ g_free (type);
return NULL;
}
@@ -235,7 +263,7 @@
if (!url)
{
egg_desktop_file_free (desktop_file);
- g_free(type);
+ g_free (type);
return NULL;
}
g_free (url);
@@ -245,7 +273,7 @@
else
desktop_file->type = EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED;
- g_free(type);
+ g_free (type);
/* Check the Icon key */
desktop_file->icon = g_key_file_get_string (key_file,
@@ -270,7 +298,6 @@
}
}
- desktop_file->key_file = key_file;
return desktop_file;
}
@@ -291,22 +318,6 @@
}
/**
- * egg_desktop_file_get_key_file:
- * @desktop_file: an #EggDesktopFile
- *
- * Gets the #GKeyFile associated with @desktop_file. You must not free
- * this value, and changes made to it will not be reflected by
- * @desktop_file.
- *
- * Return value: the #GKeyFile associated with @desktop_file.
- **/
-GKeyFile *
-egg_desktop_file_get_key_file (EggDesktopFile *desktop_file)
-{
- return desktop_file->key_file;
-}
-
-/**
* egg_desktop_file_get_source:
* @desktop_file: an #EggDesktopFile
*
@@ -369,6 +380,81 @@
return desktop_file->icon;
}
+gboolean
+egg_desktop_file_has_key (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_has_key (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+char *
+egg_desktop_file_get_string (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_get_string (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+char *
+egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ GError **error)
+{
+ return g_key_file_get_locale_string (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key, locale,
+ error);
+}
+
+gboolean
+egg_desktop_file_get_boolean (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_get_boolean (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+double
+egg_desktop_file_get_numeric (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_get_double (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+char **
+egg_desktop_file_get_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ gsize *length,
+ GError **error)
+{
+ return g_key_file_get_string_list (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key, length,
+ error);
+}
+
+char **
+egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ gsize *length,
+ GError **error)
+{
+ return g_key_file_get_locale_string_list (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ locale, length,
+ error);
+}
+
/**
* egg_desktop_file_can_launch:
* @desktop_file: an #EggDesktopFile
@@ -939,7 +1025,7 @@
static GPtrArray *
array_putenv (GPtrArray *env, char *variable)
{
- int i, keylen;
+ guint i, keylen;
if (!env)
{
@@ -1136,6 +1222,9 @@
startup_id = NULL;
#endif /* GTK 2.12 */
+ if (env != NULL)
+ g_ptr_array_add (env, NULL);
+
current_success =
g_spawn_async_with_pipes (directory,
argv,
Modified: trunk/src/eggdesktopfile.h
==============================================================================
--- trunk/src/eggdesktopfile.h (original)
+++ trunk/src/eggdesktopfile.h Sun Nov 23 21:19:54 2008
@@ -31,22 +31,23 @@
EGG_DESKTOP_FILE_TYPE_APPLICATION,
EGG_DESKTOP_FILE_TYPE_LINK,
- EGG_DESKTOP_FILE_TYPE_DIRECTORY,
+ EGG_DESKTOP_FILE_TYPE_DIRECTORY
} EggDesktopFileType;
EggDesktopFile *egg_desktop_file_new (const char *desktop_file_path,
GError **error);
-EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
- GError **error);
-EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *desktop,
+EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
+ GError **error);
+EggDesktopFile *egg_desktop_file_new_from_dirs (const char *desktop_file_path,
+ const char **search_dirs,
+ GError **error);
+EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *key_file,
const char *source,
GError **error);
void egg_desktop_file_free (EggDesktopFile *desktop_file);
-GKeyFile *egg_desktop_file_get_key_file (EggDesktopFile *desktop_file);
-
const char *egg_desktop_file_get_source (EggDesktopFile *desktop_file);
EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file);
@@ -109,6 +110,34 @@
#define EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS "StartupWMClass"
#define EGG_DESKTOP_FILE_KEY_URL "URL"
+/* Accessors */
+gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error);
+char *egg_desktop_file_get_string (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error) G_GNUC_MALLOC;
+char *egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ GError **error) G_GNUC_MALLOC;
+gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error);
+double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error);
+char **egg_desktop_file_get_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+char **egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+
+
/* Errors */
#define EGG_DESKTOP_FILE_ERROR egg_desktop_file_error_quark()
@@ -117,7 +146,7 @@
typedef enum {
EGG_DESKTOP_FILE_ERROR_INVALID,
EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
- EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION,
+ EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION
} EggDesktopFileError;
/* Global application desktop file */
Modified: trunk/src/eggsmclient-1.patch
==============================================================================
--- trunk/src/eggsmclient-1.patch (original)
+++ trunk/src/eggsmclient-1.patch Sun Nov 23 21:19:54 2008
@@ -1,4 +1,4 @@
-From 9306b131e558c339b9e7d3e21b94a172e208da12 Mon Sep 17 00:00:00 2001
+From 2b5284a034b47858eee43c0e8067d8c6d9d2a867 Mon Sep 17 00:00:00 2001
From: Christian Persch <chpe gnome org>
Date: Wed, 24 Sep 2008 13:33:57 +0200
Subject: [PATCH] Add egg_sm_client_set_discard_command() to set the discard command when using egg_sm_client_set_restart_command(), to ease porting from GnomeClient without needing to support a new session file format.
@@ -10,10 +10,10 @@
3 files changed, 69 insertions(+), 7 deletions(-)
diff --git a/libegg/smclient/eggsmclient-xsmp.c b/libegg/smclient/eggsmclient-xsmp.c
-index eebce07..32faa5a 100644
+index e4b11f6..dcaf36b 100644
--- a/libegg/smclient/eggsmclient-xsmp.c
+++ b/libegg/smclient/eggsmclient-xsmp.c
-@@ -89,6 +89,8 @@ struct _EggSMClientXSMP
+@@ -88,6 +88,8 @@ struct _EggSMClientXSMP
char **restart_command;
gboolean set_restart_command;
int restart_style;
@@ -22,7 +22,7 @@
guint idle;
-@@ -118,6 +120,9 @@ static void sm_client_xsmp_startup (EggSMClient *client,
+@@ -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);
@@ -32,7 +32,7 @@
static void sm_client_xsmp_will_quit (EggSMClient *client,
gboolean will_quit);
static gboolean sm_client_xsmp_end_session (EggSMClient *client,
-@@ -151,7 +156,7 @@ static SmProp *card8_prop (const char *name,
+@@ -150,7 +155,7 @@ static SmProp *card8_prop (const char *name,
static void set_properties (EggSMClientXSMP *xsmp, ...);
static void delete_properties (EggSMClientXSMP *xsmp, ...);
@@ -41,7 +41,7 @@
const char *client_id,
const char *state_file);
-@@ -186,6 +191,7 @@ egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass)
+@@ -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;
@@ -49,7 +49,7 @@
sm_client_class->will_quit = sm_client_xsmp_will_quit;
sm_client_class->end_session = sm_client_xsmp_end_session;
}
-@@ -410,6 +416,24 @@ sm_client_xsmp_set_restart_command (EggSMClient *client,
+@@ -404,6 +410,24 @@ sm_client_xsmp_set_restart_command (EggSMClient *client,
}
static void
@@ -74,7 +74,7 @@
sm_client_xsmp_will_quit (EggSMClient *client,
gboolean will_quit)
{
-@@ -801,7 +825,7 @@ save_state (EggSMClientXSMP *xsmp)
+@@ -771,7 +795,7 @@ save_state (EggSMClientXSMP *xsmp)
GKeyFile *state_file;
char *state_file_path, *data;
EggDesktopFile *desktop_file;
@@ -83,7 +83,7 @@
int offset, fd;
/* We set xsmp->state before emitting save_state, but our caller is
-@@ -817,7 +841,18 @@ save_state (EggSMClientXSMP *xsmp)
+@@ -787,7 +811,18 @@ save_state (EggSMClientXSMP *xsmp)
ptrarray_prop (SmRestartCommand, restart),
NULL);
g_ptr_array_free (restart, TRUE);
@@ -103,7 +103,7 @@
return;
}
-@@ -1040,14 +1075,14 @@ xsmp_shutdown_cancelled (SmcConn smc_conn,
+@@ -1034,14 +1069,14 @@ xsmp_shutdown_cancelled (SmcConn smc_conn,
* then free the array, but not its contents.
*/
static GPtrArray *
@@ -120,7 +120,7 @@
if (client_id)
{
-@@ -1061,8 +1096,8 @@ generate_command (char **restart_command, const char *client_id,
+@@ -1055,8 +1090,8 @@ generate_command (char **restart_command, const char *client_id,
g_ptr_array_add (cmd, (char *)state_file);
}
@@ -132,10 +132,10 @@
return cmd;
}
diff --git a/libegg/smclient/eggsmclient.c b/libegg/smclient/eggsmclient.c
-index dedc680..f8cd242 100644
+index 8e2254f..6bec6ed 100644
--- a/libegg/smclient/eggsmclient.c
+++ b/libegg/smclient/eggsmclient.c
-@@ -424,6 +424,27 @@ egg_sm_client_set_restart_command (EggSMClient *client,
+@@ -437,6 +437,27 @@ egg_sm_client_set_restart_command (EggSMClient *client,
}
/**
@@ -188,5 +188,5 @@
/* Handling "quit_requested" signal */
void egg_sm_client_will_quit (EggSMClient *client,
--
-1.5.6
+1.6.0.2.GIT
Modified: trunk/src/eggsmclient-osx.c
==============================================================================
--- trunk/src/eggsmclient-osx.c (original)
+++ trunk/src/eggsmclient-osx.c Sun Nov 23 21:19:54 2008
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -17,11 +18,28 @@
* Boston, MA 02111-1307, USA.
*/
-#include "config.h"
+/* EggSMClientOSX
+ *
+ * For details on the OS X logout process, see:
+ * http://developer.apple.com/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/BootProcess.html#//apple_ref/doc/uid/20002130-114618
+ *
+ * EggSMClientOSX registers for the kAEQuitApplication AppleEvent; the
+ * handler we register (quit_requested()) will be invoked from inside
+ * the quartz event-handling code (specifically, from inside
+ * [NSApplication nextEventMatchingMask]) when an AppleEvent arrives.
+ * We use AESuspendTheCurrentEvent() and AEResumeTheCurrentEvent() to
+ * allow asynchronous / non-main-loop-reentering processing of the
+ * quit request. (These are part of the Carbon framework; it doesn't
+ * seem to be possible to handle AppleEvents asynchronously from
+ * Cocoa.)
+ */
-#define G_LOG_DOMAIN "EggSMClient"
+#include "config.h"
-#include "eggsmclient.h"
+#include "eggsmclient-private.h"
+#include <gdk/gdkquartz.h>
+#include <Carbon/Carbon.h>
+#include <CoreServices/CoreServices.h>
#define EGG_TYPE_SM_CLIENT_OSX (egg_sm_client_osx_get_type ())
#define EGG_SM_CLIENT_OSX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSX))
@@ -36,7 +54,9 @@
struct _EggSMClientOSX {
EggSMClient parent;
-}
+ AppleEvent quit_event, quit_reply;
+ gboolean quit_requested, quitting;
+};
struct _EggSMClientOSXClass
{
@@ -52,14 +72,12 @@
EggSMClientEndStyle style,
gboolean request_confirmation);
-static GdkFilterReturn sm_client_osx_filter (GdkXEvent *xevent,
- GdkEvent *event,
- gpointer data);
+static pascal OSErr quit_requested (const AppleEvent *, AppleEvent *, long);
G_DEFINE_TYPE (EggSMClientOSX, egg_sm_client_osx, EGG_TYPE_SM_CLIENT)
static void
-egg_sm_client_osx_init (EggSMClientOSX *osxclient)
+egg_sm_client_osx_init (EggSMClientOSX *osx)
{
;
}
@@ -81,78 +99,137 @@
}
static void
-sm_client_osx_startup (EggSMClient *client)
+sm_client_osx_startup (EggSMClient *client,
+ const char *client_id)
+{
+ AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
+ NewAEEventHandlerUPP (quit_requested),
+ (long)GPOINTER_TO_SIZE (client), false);
+}
+
+static gboolean
+idle_quit_requested (gpointer client)
+{
+ egg_sm_client_quit_requested (client);
+ return FALSE;
+}
+
+static pascal OSErr
+quit_requested (const AppleEvent *aevt, AppleEvent *reply, long refcon)
+{
+ EggSMClient *client = GSIZE_TO_POINTER ((gsize)refcon);
+ EggSMClientOSX *osx = GSIZE_TO_POINTER ((gsize)refcon);
+
+ g_return_val_if_fail (!osx->quit_requested, userCanceledErr);
+
+ /* FIXME AEInteractWithUser? */
+
+ osx->quit_requested = TRUE;
+ AEDuplicateDesc (aevt, &osx->quit_event);
+ AEDuplicateDesc (reply, &osx->quit_reply);
+ AESuspendTheCurrentEvent (aevt);
+
+ /* Don't emit the "quit_requested" signal immediately, since we're
+ * called from a weird point in the guts of gdkeventloop-quartz.c
+ */
+ g_idle_add (idle_quit_requested, client);
+ return noErr;
+}
+
+static pascal OSErr
+quit_requested_resumed (const AppleEvent *aevt, AppleEvent *reply, long refcon)
+{
+ EggSMClientOSX *osx = GSIZE_TO_POINTER ((gsize)refcon);
+
+ osx->quit_requested = FALSE;
+ return osx->quitting ? noErr : userCanceledErr;
+}
+
+static gboolean
+idle_will_quit (gpointer client)
{
- gdk_window_add_filter (NULL, sm_client_osx_filter, client);
+ EggSMClientOSX *osx = (EggSMClientOSX *)client;
+
+ /* Resume the event with a new handler that will return a value to
+ * the system.
+ */
+ AEResumeTheCurrentEvent (&osx->quit_event, &osx->quit_reply,
+ NewAEEventHandlerUPP (quit_requested_resumed),
+ (long)GPOINTER_TO_SIZE (client));
+ AEDisposeDesc (&osx->quit_event);
+ AEDisposeDesc (&osx->quit_reply);
+
+ if (osx->quitting)
+ egg_sm_client_quit (client);
+ return FALSE;
}
-void
+static void
sm_client_osx_will_quit (EggSMClient *client,
gboolean will_quit)
{
- EggSMClientOSX *osxclient = (EggSMClientOSX *)client;
+ EggSMClientOSX *osx = (EggSMClientOSX *)client;
- if (will_quit)
- {
- /* OS X doesn't send another message. We're supposed to just
- * quit after agreeing that it's OK.
- *
- * FIXME: do it from an idle handler though.
- */
- egg_sm_client_quit (client);
- }
- else
- {
- /* FIXME: "respond to the event by returning a userCancelledErr
- * error"
- */
- }
+ g_return_if_fail (osx->quit_requested);
+
+ osx->quitting = will_quit;
+
+ /* Finish in an idle handler since the caller might have called
+ * egg_sm_client_will_quit() from inside the "quit_requested" signal
+ * handler, but may not expect the "quit" signal to arrive during
+ * the _will_quit() call.
+ */
+ g_idle_add (idle_will_quit, client);
}
-void
+static gboolean
sm_client_osx_end_session (EggSMClient *client,
EggSMClientEndStyle style,
gboolean request_confirmation)
{
- EggSMClientOSX *osxclient = (EggSMClientOSX *)client;
- FIXME_t event;
+ static const ProcessSerialNumber loginwindow_psn = { 0, kSystemProcess };
+ AppleEvent event = { typeNull, NULL }, reply = { typeNull, NULL };
+ AEAddressDesc target;
+ AEEventID id;
+ OSErr err;
switch (style)
{
case EGG_SM_CLIENT_END_SESSION_DEFAULT:
- case EGG_SM_CLIENT_END_LOGOUT:
- event = request_confirmation ? kAELogOut : kAEReallyLogOut;
+ case EGG_SM_CLIENT_LOGOUT:
+ id = request_confirmation ? kAELogOut : kAEReallyLogOut;
break;
- case EGG_SM_CLIENT_END_REBOOT:
- event = request_confirmation ? kAEShowRestartDialog : kAERestart;
+ case EGG_SM_CLIENT_REBOOT:
+ id = request_confirmation ? kAEShowRestartDialog : kAERestart;
break;
- case EGG_SM_CLIENT_END_SHUTDOWN:
- event = request_confirmation ? kAEShowShutdownDialog : kAEShutDown;
+ case EGG_SM_CLIENT_SHUTDOWN:
+ id = request_confirmation ? kAEShowShutdownDialog : kAEShutDown;
break;
}
- /* FIXME: send event to loginwindow process */
-}
-
-static GdkFilterReturn
-egg_sm_client_osx_filter (GdkXEvent *xevent,
- GdkEvent *event,
- gpointer data)
-{
- EggSMClientOSX *osxclient = data;
- EggSMClient *client = data;
- NSEvent *nsevent = (NSEvent *)xevent;
-
- switch (FIXME_get_apple_event_type (nsevent))
+ err = AECreateDesc (typeProcessSerialNumber, &loginwindow_psn,
+ sizeof (loginwindow_psn), &target);
+ if (err != noErr)
{
- case kAEQuitApplication:
- if (FIXME_app_is_a_foreground_app)
- egg_sm_client_quit_requested (client);
- else
- egg_sm_client_quit (client);
- return GDK_FILTER_REMOVE;
+ g_warning ("Could not create descriptor for loginwindow: %d", err);
+ return FALSE;
+ }
- default:
- return GDK_FILTER_CONTINUE;
+ err = AECreateAppleEvent (kCoreEventClass, id, &target,
+ kAutoGenerateReturnID, kAnyTransactionID,
+ &event);
+ AEDisposeDesc (&target);
+ if (err != noErr)
+ {
+ g_warning ("Could not create logout AppleEvent: %d", err);
+ return FALSE;
}
+
+ err = AESend (&event, &reply, kAENoReply, kAENormalPriority,
+ kAEDefaultTimeout, NULL, NULL);
+ AEDisposeDesc (&event);
+ if (err == noErr)
+ AEDisposeDesc (&reply);
+
+ return err == noErr;
}
Modified: trunk/src/eggsmclient-win32.c
==============================================================================
--- trunk/src/eggsmclient-win32.c (original)
+++ trunk/src/eggsmclient-win32.c Sun Nov 23 21:19:54 2008
@@ -17,6 +17,35 @@
* Boston, MA 02111-1307, USA.
*/
+/* EggSMClientWin32
+ *
+ * For details on the Windows XP logout process, see:
+ * http://msdn.microsoft.com/en-us/library/aa376876.aspx.
+ *
+ * Vista adds some new APIs which EggSMClient does not make use of; see
+ * http://msdn.microsoft.com/en-us/library/ms700677(VS.85).aspx
+ *
+ * When shutting down, Windows sends every top-level window a
+ * WM_QUERYENDSESSION event, which the application must respond to
+ * synchronously, saying whether or not it will quit. To avoid main
+ * loop re-entrancy problems (and to avoid having to muck about too
+ * much with the guts of the gdk-win32 main loop), we watch for this
+ * event in a separate thread, which then signals the main thread and
+ * waits for the main thread to handle the event. Since we don't want
+ * to require g_thread_init() to be called, we do this all using
+ * Windows-specific thread methods.
+ *
+ * After the application handles the WM_QUERYENDSESSION event,
+ * Windows then sends it a WM_ENDSESSION event with a TRUE or FALSE
+ * parameter indicating whether the session is or is not actually
+ * going to end now. We handle this from the other thread as well.
+ *
+ * As mentioned above, Vista introduces several additional new APIs
+ * that don't fit into the (current) EggSMClient API. Windows also has
+ * an entirely separate shutdown-notification scheme for non-GUI apps,
+ * which we also don't handle here.
+ */
+
#include "config.h"
#include "eggsmclient-private.h"
@@ -25,6 +54,7 @@
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#include <windows.h>
+#include <process.h>
#define EGG_TYPE_SM_CLIENT_WIN32 (egg_sm_client_win32_get_type ())
#define EGG_SM_CLIENT_WIN32(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32))
@@ -39,7 +69,10 @@
struct _EggSMClientWin32 {
EggSMClient parent;
- GAsyncQueue *msg_queue;
+ HANDLE message_event, response_event;
+
+ volatile GSourceFunc event;
+ volatile gboolean will_quit;
};
struct _EggSMClientWin32Class
@@ -56,7 +89,10 @@
EggSMClientEndStyle style,
gboolean request_confirmation);
-static gpointer sm_client_thread (gpointer data);
+static GSource *g_win32_handle_source_add (HANDLE handle, GSourceFunc callback,
+ gpointer user_data);
+static gboolean got_message (gpointer user_data);
+static void sm_client_thread (gpointer data);
G_DEFINE_TYPE (EggSMClientWin32, egg_sm_client_win32, EGG_TYPE_SM_CLIENT)
@@ -88,9 +124,10 @@
{
EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
- /* spawn another thread to listen for logout signals on */
- win32->msg_queue = g_async_queue_new ();
- g_thread_create (sm_client_thread, client, FALSE, NULL);
+ win32->message_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+ win32->response_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+ g_win32_handle_source_add (win32->message_event, got_message, win32);
+ _beginthread (sm_client_thread, 0, client);
}
static void
@@ -99,8 +136,8 @@
{
EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
- /* Can't push NULL onto a GAsyncQueue, so we add 1 to the value... */
- g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (will_quit + 1));
+ win32->will_quit = will_quit;
+ SetEvent (win32->response_event);
}
static gboolean
@@ -159,7 +196,7 @@
egg_sm_client_quit (smclient);
gdk_threads_leave ();
- g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (1));
+ SetEvent (win32->response_event);
return FALSE;
}
@@ -172,25 +209,80 @@
egg_sm_client_quit_cancelled (smclient);
gdk_threads_leave ();
- g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (1));
+ SetEvent (win32->response_event);
return FALSE;
}
+static gboolean
+got_message (gpointer smclient)
+{
+ EggSMClientWin32 *win32 = smclient;
+
+ win32->event (win32);
+ return TRUE;
+}
-/* logout-listener thread */
+/* Windows HANDLE GSource */
+
+typedef struct {
+ GSource source;
+ GPollFD pollfd;
+} GWin32HandleSource;
+
+static gboolean
+g_win32_handle_source_prepare (GSource *source, gint *timeout)
+{
+ *timeout = -1;
+ return FALSE;
+}
+
+static gboolean
+g_win32_handle_source_check (GSource *source)
+{
+ GWin32HandleSource *hsource = (GWin32HandleSource *)source;
+
+ return hsource->pollfd.revents;
+}
+
+static gboolean
+g_win32_handle_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
+{
+ return (*callback) (user_data);
+}
+
+static void
+g_win32_handle_source_finalize (GSource *source)
+{
+ ;
+}
-static int
-async_emit (EggSMClientWin32 *win32, GSourceFunc emitter)
+GSourceFuncs g_win32_handle_source_funcs = {
+ g_win32_handle_source_prepare,
+ g_win32_handle_source_check,
+ g_win32_handle_source_dispatch,
+ g_win32_handle_source_finalize
+};
+
+static GSource *
+g_win32_handle_source_add (HANDLE handle, GSourceFunc callback, gpointer user_data)
{
- /* ensure message queue is empty */
- while (g_async_queue_try_pop (win32->msg_queue))
- ;
-
- /* Emit signal in the main thread and wait for a response */
- g_idle_add (emitter, win32);
- return GPOINTER_TO_INT (g_async_queue_pop (win32->msg_queue)) - 1;
+ GWin32HandleSource *hsource;
+ GSource *source;
+
+ source = g_source_new (&g_win32_handle_source_funcs, sizeof (GWin32HandleSource));
+ hsource = (GWin32HandleSource *)source;
+ hsource->pollfd.fd = (int)handle;
+ hsource->pollfd.events = G_IO_IN;
+ hsource->pollfd.revents = 0;
+ g_source_add_poll (source, &hsource->pollfd);
+
+ g_source_set_callback (source, callback, user_data, NULL);
+ g_source_attach (source, NULL);
+ return source;
}
+/* logout-listener thread */
+
LRESULT CALLBACK
sm_client_win32_window_procedure (HWND hwnd,
UINT message,
@@ -203,19 +295,27 @@
switch (message)
{
case WM_QUERYENDSESSION:
- return async_emit (win32, emit_quit_requested);
+ win32->event = emit_quit_requested;
+ SetEvent (win32->message_event);
+
+ WaitForSingleObject (win32->response_event, INFINITE);
+ return win32->will_quit;
case WM_ENDSESSION:
if (wParam)
{
/* The session is ending */
- async_emit (win32, emit_quit);
+ win32->event = emit_quit;
}
else
{
/* Nope, the session *isn't* ending */
- async_emit (win32, emit_quit_cancelled);
+ win32->event = emit_quit_cancelled;
}
+
+ SetEvent (win32->message_event);
+ WaitForSingleObject (win32->response_event, INFINITE);
+
return 0;
default:
@@ -223,7 +323,7 @@
}
}
-static gpointer
+static void
sm_client_thread (gpointer smclient)
{
HINSTANCE instance;
@@ -250,6 +350,4 @@
/* main loop */
while (GetMessage (&msg, NULL, 0, 0))
DispatchMessage (&msg);
-
- return NULL;
}
Modified: trunk/src/eggsmclient-xsmp.c
==============================================================================
--- trunk/src/eggsmclient-xsmp.c (original)
+++ trunk/src/eggsmclient-xsmp.c Sun Nov 23 21:19:54 2008
@@ -62,11 +62,10 @@
XSMP_STATE_INTERACT,
XSMP_STATE_SAVE_YOURSELF_DONE,
XSMP_STATE_SHUTDOWN_CANCELLED,
- XSMP_STATE_CONNECTION_CLOSED,
+ XSMP_STATE_CONNECTION_CLOSED
} EggSMClientXSMPState;
static const char *state_names[] = {
- "start",
"idle",
"save-yourself",
"interact-request",
@@ -227,19 +226,14 @@
desktop_file = egg_get_desktop_file ();
if (desktop_file)
{
- GKeyFile *key_file;
GError *err = NULL;
char *cmdline, **argv;
int argc;
- key_file = egg_desktop_file_get_key_file (desktop_file);
-
if (xsmp->restart_style == SmRestartIfRunning)
{
- if (g_key_file_has_key (key_file, EGG_DESKTOP_FILE_GROUP,
- "X-GNOME-AutoRestart", NULL) &&
- g_key_file_get_boolean (key_file, EGG_DESKTOP_FILE_GROUP,
- "X-GNOME-AutoRestart", NULL))
+ if (egg_desktop_file_get_boolean (desktop_file,
+ "X-GNOME-AutoRestart", NULL))
xsmp->restart_style = SmRestartImmediately;
}
@@ -796,30 +790,6 @@
}
static void
-merge_keyfiles (GKeyFile *dest, GKeyFile *source)
-{
- int g, k;
- char **groups, **keys, *value;
-
- groups = g_key_file_get_groups (source, NULL);
- for (g = 0; groups[g]; g++)
- {
- keys = g_key_file_get_keys (source, groups[g], NULL, NULL);
- for (k = 0; keys[k]; k++)
- {
- value = g_key_file_get_value (source, groups[g], keys[k], NULL);
- if (value)
- {
- g_key_file_set_value (dest, groups[g], keys[k], value);
- g_free (value);
- }
- }
- g_strfreev (keys);
- }
- g_strfreev (groups);
-}
-
-static void
save_state (EggSMClientXSMP *xsmp)
{
GKeyFile *state_file;
@@ -860,30 +830,54 @@
if (desktop_file)
{
GKeyFile *merged_file;
- char *exec;
- int i;
merged_file = g_key_file_new ();
- merge_keyfiles (merged_file, egg_desktop_file_get_key_file (desktop_file));
- merge_keyfiles (merged_file, state_file);
+ if (g_key_file_load_from_file (merged_file,
+ egg_desktop_file_get_source (desktop_file),
+ G_KEY_FILE_KEEP_COMMENTS |
+ G_KEY_FILE_KEEP_TRANSLATIONS, NULL))
+ {
+ guint g, k, i;
+ char **groups, **keys, *value, *exec;
- g_key_file_free (state_file);
- state_file = merged_file;
+ 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);
- /* 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);
+ 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);
+
+ }
}
/* Now write state_file to disk. (We can't use mktemp(), because
@@ -1112,7 +1106,7 @@
GPtrArray *props;
SmProp *prop;
va_list ap;
- int i;
+ guint i;
props = g_ptr_array_new ();
@@ -1205,7 +1199,7 @@
SmProp *prop;
SmPropValue pv;
GArray *vals;
- int i;
+ guint i;
prop = g_new (SmProp, 1);
prop->name = (char *)name;
Modified: trunk/src/eggsmclient.c
==============================================================================
--- trunk/src/eggsmclient.c (original)
+++ trunk/src/eggsmclient.c Sun Nov 23 21:19:54 2008
@@ -187,6 +187,20 @@
{
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;
@@ -303,16 +317,16 @@
#elif defined (GDK_WINDOWING_QUARTZ)
global_client = egg_sm_client_osx_new ();
#else
- /* If both D-Bus and XSMP are compiled in, try D-Bus first
- * and fall back to XSMP if D-Bus session management isn't
- * available.
+ /* 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_DBUS
- global_client = egg_sm_client_dbus_new ();
-# endif
# 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_xsmp_new ();
+ global_client = egg_sm_client_dbus_new ();
# endif
#endif
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]