gnome-games r7986 - trunk/libgames-support
- From: chpe svn gnome org
- To: svn-commits-list gnome org
- Subject: gnome-games r7986 - trunk/libgames-support
- Date: Wed, 8 Oct 2008 20:03:58 +0000 (UTC)
Author: chpe
Date: Wed Oct 8 20:03:58 2008
New Revision: 7986
URL: http://svn.gnome.org/viewvc/gnome-games?rev=7986&view=rev
Log:
Update from libegg.
Add the diff to libegg upstream also as eggsmclient.patch so that it's
easy to reapply after updating from upstream.
Added:
trunk/libgames-support/eggsmclient.patch
Modified:
trunk/libgames-support/eggdesktopfile.c
trunk/libgames-support/eggdesktopfile.h
trunk/libgames-support/eggsmclient-osx.c
trunk/libgames-support/eggsmclient-win32.c
trunk/libgames-support/eggsmclient-xsmp.c
trunk/libgames-support/eggsmclient.c
Modified: trunk/libgames-support/eggdesktopfile.c
==============================================================================
--- trunk/libgames-support/eggdesktopfile.c (original)
+++ trunk/libgames-support/eggdesktopfile.c Wed Oct 8 20:03:58 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
@@ -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/libgames-support/eggdesktopfile.h
==============================================================================
--- trunk/libgames-support/eggdesktopfile.h (original)
+++ trunk/libgames-support/eggdesktopfile.h Wed Oct 8 20:03:58 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/libgames-support/eggsmclient-osx.c
==============================================================================
--- trunk/libgames-support/eggsmclient-osx.c (original)
+++ trunk/libgames-support/eggsmclient-osx.c Wed Oct 8 20:03:58 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/libgames-support/eggsmclient-win32.c
==============================================================================
--- trunk/libgames-support/eggsmclient-win32.c (original)
+++ trunk/libgames-support/eggsmclient-win32.c Wed Oct 8 20:03:58 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/libgames-support/eggsmclient-xsmp.c
==============================================================================
--- trunk/libgames-support/eggsmclient-xsmp.c (original)
+++ trunk/libgames-support/eggsmclient-xsmp.c Wed Oct 8 20:03:58 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;
}
@@ -423,8 +417,6 @@
EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
int i;
- g_return_if_fail (xsmp->set_restart_command);
-
g_strfreev (xsmp->discard_command);
xsmp->discard_command = g_new (char *, argc + 1);
@@ -798,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;
@@ -862,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))
+ {
+ int 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;
+ 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);
+ /* 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
Modified: trunk/libgames-support/eggsmclient.c
==============================================================================
--- trunk/libgames-support/eggsmclient.c (original)
+++ trunk/libgames-support/eggsmclient.c Wed Oct 8 20:03:58 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
}
Added: trunk/libgames-support/eggsmclient.patch
==============================================================================
--- (empty file)
+++ trunk/libgames-support/eggsmclient.patch Wed Oct 8 20:03:58 2008
@@ -0,0 +1,245 @@
+diff --git a/libegg/smclient/eggsmclient-xsmp.c b/libegg/smclient/eggsmclient-xsmp.c
+index 86dfdb7..71b0180 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;
+ }
+
+@@ -1034,14 +1069,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)
+ {
+@@ -1055,8 +1090,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 b24968d..6bec6ed 100644
+--- a/libegg/smclient/eggsmclient.c
++++ b/libegg/smclient/eggsmclient.c
+@@ -38,7 +38,7 @@ enum {
+ LAST_SIGNAL
+ };
+
+-static guint signals[LAST_SIGNAL] = { 0 };
++static guint signals[LAST_SIGNAL];
+
+ struct _EggSMClientPrivate {
+ GKeyFile *state_file;
+@@ -179,23 +179,6 @@ static gboolean sm_client_disable = FALSE;
+ static char *sm_client_state_file = NULL;
+ static char *sm_client_id = NULL;
+
+-static 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_STRING, &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") },
+- /* Compatibility options */
+- { "sm-disable", 0, G_OPTION_FLAG_HIDDEN,
+- G_OPTION_ARG_NONE, &sm_client_disable,
+- NULL, NULL },
+- { NULL }
+-};
+-
+ static gboolean
+ sm_client_post_parse_func (GOptionContext *context,
+ GOptionGroup *group,
+@@ -235,6 +218,22 @@ sm_client_post_parse_func (GOptionContext *context,
+ 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") },
++ /* Compatibility options */
++ { "sm-disable", 0, G_OPTION_FLAG_HIDDEN,
++ G_OPTION_ARG_NONE, &sm_client_disable,
++ NULL, NULL },
++ { NULL }
++ };
+ GOptionGroup *group;
+
+ /* Use our own debug handler for the "EggSMClient" domain. */
+@@ -242,8 +241,8 @@ egg_sm_client_get_option_group (void)
+ egg_sm_client_debug_handler, NULL);
+
+ group = g_option_group_new ("sm-client",
+- _("Session Management Options"),
+- _("Show Session Management options"),
++ _("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);
+@@ -438,6 +437,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,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]