libegg r904 - trunk/libegg/smclient
- From: danw svn gnome org
- To: svn-commits-list gnome org
- Subject: libegg r904 - trunk/libegg/smclient
- Date: Fri, 3 Oct 2008 16:00:06 +0000 (UTC)
Author: danw
Date: Fri Oct 3 16:00:03 2008
New Revision: 904
URL: http://svn.gnome.org/viewvc/libegg?rev=904&view=rev
Log:
* eggsmclient-osx.c: Implement.
* Makefile.am: add stuff for OS X build
* egg-session-end.c: fix the --shutdown/--reboot args to actually
work
* README: update
Modified:
trunk/libegg/smclient/ChangeLog
trunk/libegg/smclient/Makefile.am
trunk/libegg/smclient/README
trunk/libegg/smclient/egg-session-end.c
trunk/libegg/smclient/eggsmclient-osx.c
Modified: trunk/libegg/smclient/Makefile.am
==============================================================================
--- trunk/libegg/smclient/Makefile.am (original)
+++ trunk/libegg/smclient/Makefile.am Fri Oct 3 16:00:03 2008
@@ -1,10 +1,13 @@
if PLATFORM_WIN32
-platform_defines =
-platform_ltlibraries =
-platform_libs =
platform_sources = eggsmclient-win32.c
-platform_app_ldflags = -mwindows
-platform_programs =
+platform_logout_test_ldflags = -mwindows
+else
+if PLATFORM_OSX
+platform_defines = -xobjective-c
+platform_ldflags = -framework Carbon
+platform_session_end_ldflags = -framework Carbon
+platform_logout_test_ldflags = -framework Carbon
+platform_sources = eggsmclient-osx.c
else
platform_defines = -DEGG_SM_CLIENT_BACKEND_XSMP
platform_ltlibraries = \
@@ -12,9 +15,9 @@
libeggsmclient-gnome.la
platform_libs = libeggdesktopfile.la -lSM -lICE
platform_sources = eggsmclient-xsmp.c
-platform_app_ldflags =
platform_programs = egg-launch
endif
+endif
INCLUDES = \
-DG_LOG_DOMAIN=\""EggSMClient"\" \
@@ -30,6 +33,9 @@
$(EGG_SMCLIENT_LIBS) \
$(platform_libs)
+libeggsmclient_la_LDFLAGS = \
+ $(platform_ldflags)
+
libeggsmclient_la_SOURCES = \
eggsmclient.c \
eggsmclient.h \
@@ -66,6 +72,9 @@
egg_session_end_LDADD = \
libeggsmclient.la
+egg_session_end_LDFLAGS = \
+ $(platform_session_end_ldflags)
+
logout_test_SOURCES = \
logout-test.c
@@ -73,7 +82,7 @@
libeggsmclient.la
logout_test_LDFLAGS = \
- $(platform_app_ldflags)
+ $(platform_logout_test_ldflags)
egg_launch_SOURCES = \
egg-launch.c
Modified: trunk/libegg/smclient/README
==============================================================================
--- trunk/libegg/smclient/README (original)
+++ trunk/libegg/smclient/README Fri Oct 3 16:00:03 2008
@@ -8,7 +8,7 @@
cleanly when the session ends too. OTOH, making glib depend on libSM
would obviously suck. Using dlopen may be a good solution.
-EggDesktopItem is proposed gtk-level rewrite of GnomeDesktopItem. See
+EggDesktopFile is proposed gtk-level rewrite of GnomeDesktopItem. See
http://bugzilla.gnome.org/show_bug.cgi?id=415070
@@ -35,6 +35,15 @@
You need to call g_thread_null(NULL) to initialize threads.
+If you are building on OS X:
+
+ You need to link your application with the Cocoa framework
+ (-framework Cocoa). Libtool doesn't record framework
+ dependencies, and since for libegg purposes we're only
+ building libeggsmclient as a static library, the dependency
+ doesn't get recorded by the linker either, so you have to add
+ it by hand.
+
Using EggSMClient
-----------------
@@ -71,7 +80,7 @@
gtk_get_option_group() to it. See egg-session-end.c for an
example.)
- You should also call egg_set_desktop_file() (in
+ On Linux/Unix, you should also call egg_set_desktop_file() (in
"eggdesktopfile.h"), passing it the path to your application's
installed .desktop file. (This will be used for some
SM-related purposes and will also be used to initialize your
@@ -135,10 +144,6 @@
on them. (If the application must have its working directory restored,
it can just save and restore it itself.)
-(There probably needs to be a way to set _GSM_Priority, for
-compatibility with the current gnome-session; this will probably be
-done via another .desktop key.)
-
The "save_yourself" signal/callback is split into two signals in
EggSMClient: save_state and quit_requested. Most GnomeClient-based
apps only implement the state-saving functionality currently, so they
@@ -217,7 +222,8 @@
- egg-session-end.c: A replacement for gnome-session-save.
(Well, actually only for "gnome-session-save --kill".)
Yes, the --reboot and --shutdown arguments are only there to
- tease you.
+ tease you (with the XSMP backend at least; they work on OS
+ X.)
- logout-test.c: Sits around waiting for you to try to log
out, and then asks "are you sure", to test
@@ -228,14 +234,6 @@
Non-functional backends:
- - OS X: eggsmclient-osx.c is not quite a proof-of-concept.
- It's more of a handwave-of-concept. I don't have a working
- OS X machine at the moment, so I can't test/finish this.
-
- See http://developer.apple.com/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/BootProcess.html#//apple_ref/doc/uid/20002130-114618
- and other URLs linked from it for more info on the OS X
- logout process.
-
- D-Bus: There are a few references in the code to a
non-existent D-Bus session management client. The idea is
that once we have a session manager that implements that,
Modified: trunk/libegg/smclient/egg-session-end.c
==============================================================================
--- trunk/libegg/smclient/egg-session-end.c (original)
+++ trunk/libegg/smclient/egg-session-end.c Fri Oct 3 16:00:03 2008
@@ -32,23 +32,33 @@
gboolean gui = FALSE;
static gboolean
-style_callback (const char *option_name, const char *value,
- gpointer data, GError **error)
+logout_callback (const char *option_name, const char *value,
+ gpointer data, GError **error)
{
- if (!strcmp (option_name, "logout"))
- style = EGG_SM_CLIENT_LOGOUT;
- else if (!strcmp (option_name, "reboot"))
- style = EGG_SM_CLIENT_REBOOT;
- else if (!strcmp (option_name, "shutdown"))
- style = EGG_SM_CLIENT_SHUTDOWN;
+ style = EGG_SM_CLIENT_LOGOUT;
+ return TRUE;
+}
+static gboolean
+reboot_callback (const char *option_name, const char *value,
+ gpointer data, GError **error)
+{
+ style = EGG_SM_CLIENT_REBOOT;
+ return TRUE;
+}
+
+static gboolean
+shutdown_callback (const char *option_name, const char *value,
+ gpointer data, GError **error)
+{
+ style = EGG_SM_CLIENT_SHUTDOWN;
return TRUE;
}
static const GOptionEntry options[] = {
- { "logout", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, style_callback, N_("Logout (as opposed to rebooting or shutting down)"), NULL },
- { "reboot", 'r', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, style_callback, N_("Reboot"), NULL },
- { "shutdown", 's', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, style_callback, N_("Shut down computer"), NULL },
+ { "logout", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, logout_callback, N_("Logout (as opposed to rebooting or shutting down)"), NULL },
+ { "reboot", 'r', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, reboot_callback, N_("Reboot"), NULL },
+ { "shutdown", 's', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, shutdown_callback, N_("Shut down computer"), NULL },
{ "gui", 'g', 0, G_OPTION_ARG_NONE, &gui, N_("Use dialog boxes for errors"), NULL },
{ "no-confirmation", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &confirm, N_("Don't give the user a chance to confirm"), NULL },
Modified: trunk/libegg/smclient/eggsmclient-osx.c
==============================================================================
--- trunk/libegg/smclient/eggsmclient-osx.c (original)
+++ trunk/libegg/smclient/eggsmclient-osx.c Fri Oct 3 16:00:03 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;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]