[gtk+] GtkApplication: Add OS X implementation from EggSMClient
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] GtkApplication: Add OS X implementation from EggSMClient
- Date: Sun, 8 Jan 2012 00:53:03 +0000 (UTC)
commit bb957e5389ea93a70745bd07efb73ba9fb40e684
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Jan 7 19:52:14 2012 -0500
GtkApplication: Add OS X implementation from EggSMClient
gtk/gtkapplication.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 180 insertions(+), 6 deletions(-)
---
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c
index f5eb08b..fa2da08 100644
--- a/gtk/gtkapplication.c
+++ b/gtk/gtkapplication.c
@@ -39,6 +39,8 @@
#ifdef GDK_WINDOWING_QUARTZ
#include "gtkquartz-menu.h"
#import <Cocoa/Cocoa.h>
+#include <Carbon/Carbon.h>
+#include <CoreServices/CoreServices.h>
#endif
#include <gdk/gdk.h>
@@ -159,6 +161,9 @@ struct _GtkApplicationPrivate
#ifdef GDK_WINDOWING_QUARTZ
GActionMuxer *muxer;
GMenu *combined;
+
+ AppleEvent quit_event, quit_reply;
+ gboolean quit_requested, quitting;
#endif
};
@@ -225,7 +230,6 @@ window_prefix_from_appid (const gchar *appid)
static void gtk_application_startup_session_dbus (GtkApplication *app);
-
static void
gtk_application_startup_x11 (GtkApplication *application)
{
@@ -268,6 +272,8 @@ gtk_application_menu_changed_quartz (GObject *object,
gtk_quartz_set_main_menu (G_MENU_MODEL (combined), G_ACTION_OBSERVABLE (application->priv->muxer));
}
+static void gtk_application_startup_session_quartz (GtkApplication *app);
+
static void
gtk_application_startup_quartz (GtkApplication *application)
{
@@ -279,6 +285,8 @@ gtk_application_startup_quartz (GtkApplication *application)
g_signal_connect (application, "notify::app-menu", G_CALLBACK (gtk_application_menu_changed_quartz), NULL);
g_signal_connect (application, "notify::menubar", G_CALLBACK (gtk_application_menu_changed_quartz), NULL);
gtk_application_menu_changed_quartz (G_OBJECT (application), NULL, NULL);
+
+ gtk_application_startup_session_quartz (application);
}
static void
@@ -1448,15 +1456,181 @@ gtk_application_end_session (GtkApplication *application,
return TRUE;
}
+#elif defined(GDK_WINDOWING_QUARTZ)
+
+/* OS X implementation copied from EggSMClient */
+
+static gboolean
+idle_quit_requested (gpointer client)
+{
+ g_signal_emit (client, gtk_application_signals[QUIT_REQUESTED], 0);
+
+ return FALSE;
+}
+
+static pascal OSErr
+quit_requested (const AppleEvent *aevt,
+ AppleEvent *reply,
+ long refcon)
+{
+ GtkApplication *app = GSIZE_TO_POINTER ((gsize)refcon);
+
+ g_return_val_if_fail (!app->priv->quit_requested, userCanceledErr);
+
+ /* FIXME AEInteractWithUser? */
+ osx->quit_requested = TRUE;
+ AEDuplicateDesc (aevt, &app->priv->quit_event);
+ AEDuplicateDesc (reply, &app->priv->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, app);
+
+ return noErr;
+}
+
+static void
+gtk_application_startup_session_quartz (GtkApplication *app)
+{
+ if (app->priv->register_session)
+ AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
+ NewAEEventHandlerUPP (quit_requested),
+ (long)GPOINTER_TO_SIZE (app), false);
+}
+
+static pascal OSErr
+quit_requested_resumed (const AppleEvent *aevt,
+ AppleEvent *reply,
+ long refcon)
+{
+ GtkApplication *app = GSIZE_TO_POINTER ((gsize)refcon);
+
+ app->priv->quit_requested = FALSE;
+
+ return app->priv->quitting ? noErr : userCanceledErr;
+}
+
+static gboolean
+idle_will_quit (gpointer data)
+{
+ GtkApplication *app = data;
+
+ /* Resume the event with a new handler that will return
+ * a value to the system
+ */
+ AEResumeTheCurrentEvent (&app->priv->quit_event, &app->priv->quit_reply,
+ NewAEEventHandlerUPP (quit_requested_resumed),
+ (long)GPOINTER_TO_SIZE (app));
+
+ AEDisposeDesc (&app->quit->quit_event);
+ AEDisposeDesc (&app->quit->quit_reply);
+
+ if (app->priv->quitting)
+ g_signal_emit (app, gtk_application_signals[QUIT], 0);
+
+ return FALSE;
+}
+
+void
+gtk_application_quit_response (GtkApplication *application,
+ gboolean will_quit,
+ const gchar *reason)
+{
+ g_return_if_fail (GTK_IS_APPLICATION (application));
+ g_return_if_fail (!g_application_get_is_remote (G_APPLICATION (application)));
+ g_return_if_fail (application->priv->quit_requested);
+
+ application->priv->quitting = will_quit;
+
+ /* Finish in an idle handler since the caller might have called
+ * gtk_application_quit_response() from inside the ::quit-requested
+ * signal handler, but may not expect the ::quit signal to arrive
+ * during the gtk_application_quit_response() call.
+ */
+ g_idle_add (idle_will_quit, application);
+}
+
+guint
+gtk_application_inhibit (GtkApplication *application,
+ GtkWindow *window,
+ GtkApplicationInhibitFlags flags,
+ const gchar *reason)
+{
+ return 0;
+}
+
+void
+gtk_application_uninhibit (GtkApplication *application,
+ guint cookie)
+{
+}
+
+gboolean
+gtk_application_is_inhibited (GtkApplication *application,
+ GtkApplicationInhibitFlags flags)
+{
+ return FALSE;
+}
+
+gboolean
+gtk_application_end_session (GtkApplication *application,
+ GtkApplicationEndStyle *style,
+ gboolean request_confirmation)
+{
+ static const ProcessSerialNumber loginwindow_psn = { 0, kSystemProcess };
+ AppleEvent event = { typeNull, NULL };
+ AppleEvent reply = { typeNull, NULL };
+ AEAddressDesc target;
+ AEEventID id;
+ OSErr err;
+
+ switch (style)
+ {
+ case GTK_APPLICATION_LOGOUT:
+ id = request_confirmation ? kAELogOut : kAEReallyLogOut;
+ break;
+ case GTK_APPLICATION_REBOOT:
+ id = request_confirmation ? kAEShowRestartDialog : kAERestart;
+ break;
+ case GTK_APPLICATION_SHUTDOWN:
+ id = request_confirmation ? kAEShowShutdownDialog : kAEShutDown;
+ break;
+ }
+
+ err = AECreateDesc (typeProcessSerialNumber, &loginwindow_psn,
+ sizeof (loginwindow_psn), &target);
+ if (err != noErr)
+ {
+ g_warning ("Could not create descriptor for loginwindow: %d", err);
+ return FALSE;
+ }
+
+ 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;
+}
+
#else
/* Trivial implementation.
*
- * EggSMClient has working Win32 and OSX implementations of
- * ::quit-requested, ::quit, ::quit-cancelled that should be
- * copied here eventually.
- *
- * For the inhibit API, see
+ * For the inhibit API on Windows, see
* http://msdn.microsoft.com/en-us/library/ms700677%28VS.85%29.aspx
*/
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]