summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Lortie <desrt@desrt.ca>2013-12-16 09:32:13 -0500
committerRyan Lortie <desrt@desrt.ca>2013-12-16 13:51:54 -0500
commit7fd81cf111863f819238431488b8ab0f0b943d68 (patch)
treea4fe8229064c6256269b2b9579a628163a673d22
parent2841c0ec542262218fd805443aaa5ca3cca6d6a0 (diff)
downloadgtk+-7fd81cf111863f819238431488b8ab0f0b943d68.tar.gz
Refactor GtkApplication
gtkapplication.c has turned into a bit of an #ifdef mess over time, and many of the current checks are incorrect. As an example, if you build Gtk for wayland, and exclude the X11 backend, much of the functionality required by wayland (such as exporting menu models) will be disabled. Solve that by introducing a backend mechanism to GtkApplication (named GtkApplicationImpl) similar to the one in GApplication. Add backends for Wayland, X11 and Quartz, with X11 and Wayland sharing a common 'DBus' superclass. GtkApplicationImpl | /--------------+-------------------\ | | GtkApplicationImplDBus GtkApplicationImplQuartz | /-----------+-----------------\ | | GtkApplicationImplX11 GtkApplicationImplWayland GtkApplicationImpl itself is essentially a bunch of vfuncs that serve as hooks for various things that the platform-specific backends may be interested in doing (startup, shutdown, managing windows, inhibit, etc.) With this change, all platform specific code has been removed from gtkapplication.c and gtkapplicationwindow.c (both of which are now free of #ifdefs, except for a UNIX-specific use of GDesktopAppInfo in gtkapplicationwindow.c). Additionally, because of the movement of the property-setting code out of GtkApplicationWindow, the _GTK_APPLICATION_ID properties (and friends) will be set on non-GtkApplicationWindows, such as dialogs. https://bugzilla.gnome.org/show_bug.cgi?id=720550
-rw-r--r--gtk/Makefile.am24
-rw-r--r--gtk/gtkapplication-dbus.c459
-rw-r--r--gtk/gtkapplication-quartz.c262
-rw-r--r--gtk/gtkapplication-wayland.c70
-rw-r--r--gtk/gtkapplication-x11.c89
-rw-r--r--gtk/gtkapplication.c757
-rw-r--r--gtk/gtkapplicationimpl.c185
-rw-r--r--gtk/gtkapplicationprivate.h178
-rw-r--r--gtk/gtkapplicationwindow.c114
-rw-r--r--gtk/gtkwindow.c6
10 files changed, 1336 insertions, 808 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index fdbfac5a3a..31c700eb3d 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -628,6 +628,7 @@ gtk_base_c_sources = \
gtkappchoosermodule.c \
gtkappchooseronline.c \
gtkapplication.c \
+ gtkapplicationimpl.c \
gtkapplicationwindow.c \
gtkarrow.c \
gtkaspectframe.c \
@@ -962,7 +963,15 @@ gtk_use_x11_c_sources = \
gtksocket.c \
gtkxembed.c \
gtktrayicon-x11.c \
+ gtkapplication-x11.c \
gtkmountoperation-x11.c
+
+gtk_use_wayland_c_sources = \
+ gtkapplication-wayland.c
+
+gtk_use_wayland_or_x11_c_sources = \
+ gtkapplication-dbus.c
+
gtk_use_win32_c_sources = \
gtkwin32embed.c \
gtkwin32embedwidget.c \
@@ -971,6 +980,7 @@ gtk_use_quartz_c_sources = \
gtksearchenginequartz.c \
gtkmountoperation-stub.c \
gtkmodelmenu-quartz.c \
+ gtkapplication-quartz.c \
gtkquartz.c
gtk_use_stub_c_sources = \
gtkmountoperation-stub.c
@@ -984,6 +994,20 @@ gtk_c_sources += $(gtk_use_x11_c_sources)
gtk_private_h_sources += $(gtk_use_x11_private_h_sources)
endif
+if USE_WAYLAND
+gtk_c_sources += $(gtk_use_wayland_c_sources)
+endif
+
+# pretty tricky way to write USE_WAYLAND || USE_X11...
+if USE_WAYLAND
+gtk_c_sources += $(gtk_use_wayland_or_x11_c_sources)
+else
+if USE_X11
+gtk_c_sources += $(gtk_use_wayland_or_x11_c_sources)
+else
+endif
+endif
+
gtk_use_win32_private_h_sources = \
gtkwin32embed.h \
gtkwin32embedwidget.h
diff --git a/gtk/gtkapplication-dbus.c b/gtk/gtkapplication-dbus.c
new file mode 100644
index 0000000000..667d2cae3e
--- /dev/null
+++ b/gtk/gtkapplication-dbus.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright © 2010 Codethink Limited
+ * Copyright © 2012 Red Hat, Inc.
+ * Copyright © 2013 Canonical Limited
+ *
+ * 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 licence, 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ * Matthias Clasen <mclasen@redhat.com>
+ */
+
+#include "config.h"
+
+#include "gtkapplicationprivate.h"
+
+G_DEFINE_TYPE (GtkApplicationImplDBus, gtk_application_impl_dbus, GTK_TYPE_APPLICATION_IMPL)
+
+
+static void
+unregister_client (GtkApplicationImplDBus *dbus)
+{
+ GError *error = NULL;
+
+ g_debug ("Unregistering client");
+
+ g_dbus_proxy_call_sync (dbus->sm_proxy,
+ "UnregisterClient",
+ g_variant_new ("(o)", dbus->client_path),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ &error);
+
+ if (error)
+ {
+ g_warning ("Failed to unregister client: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_clear_object (&dbus->client_proxy);
+
+ g_free (dbus->client_path);
+ dbus->client_path = NULL;
+}
+
+static void
+send_quit_response (GtkApplicationImplDBus *dbus,
+ gboolean will_quit,
+ const gchar *reason)
+{
+ g_debug ("Calling EndSessionResponse %d '%s'", will_quit, reason);
+
+ g_dbus_proxy_call (dbus->client_proxy,
+ "EndSessionResponse",
+ g_variant_new ("(bs)", will_quit, reason ? reason : ""),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL, NULL, NULL);
+}
+
+static void
+client_proxy_signal (GDBusProxy *proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GtkApplicationImplDBus *dbus = user_data;
+
+ if (g_str_equal (signal_name, "QueryEndSession"))
+ {
+ g_debug ("Received QueryEndSession");
+ send_quit_response (dbus, TRUE, NULL);
+ }
+ else if (g_str_equal (signal_name, "CancelEndSession"))
+ {
+ g_debug ("Received CancelEndSession");
+ }
+ else if (g_str_equal (signal_name, "EndSession"))
+ {
+ g_debug ("Received EndSession");
+ send_quit_response (dbus, TRUE, NULL);
+ unregister_client (dbus);
+ g_application_quit (G_APPLICATION (dbus->impl.application));
+ }
+ else if (g_str_equal (signal_name, "Stop"))
+ {
+ g_debug ("Received Stop");
+ unregister_client (dbus);
+ g_application_quit (G_APPLICATION (dbus->impl.application));
+ }
+}
+
+static void
+gtk_application_impl_dbus_startup (GtkApplicationImpl *impl,
+ gboolean register_session)
+{
+ GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
+ static gchar *client_id;
+ GError *error = NULL;
+ GVariant *res;
+
+ dbus->session = g_application_get_dbus_connection (G_APPLICATION (impl->application));
+
+ if (!dbus->session)
+ return;
+
+ dbus->application_id = g_application_get_application_id (G_APPLICATION (impl->application));
+ dbus->object_path = g_application_get_dbus_object_path (G_APPLICATION (impl->application));
+ dbus->unique_name = g_dbus_connection_get_unique_name (dbus->session);
+
+ if (client_id == NULL)
+ {
+ const gchar *desktop_autostart_id;
+
+ desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
+ /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
+ * use the same client id.
+ */
+ g_unsetenv ("DESKTOP_AUTOSTART_ID");
+ client_id = g_strdup (desktop_autostart_id ? desktop_autostart_id : "");
+ }
+
+ g_debug ("Connecting to session manager");
+
+ dbus->sm_proxy = g_dbus_proxy_new_sync (dbus->session,
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+ NULL,
+ "org.gnome.SessionManager",
+ "/org/gnome/SessionManager",
+ "org.gnome.SessionManager",
+ NULL,
+ &error);
+
+ if (error)
+ {
+ g_warning ("Failed to get a session proxy: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ /* FIXME: should we reuse the D-Bus application id here ? */
+ dbus->app_id = g_strdup (g_get_prgname ());
+
+ if (!register_session)
+ return;
+
+ g_debug ("Registering client '%s' '%s'", dbus->app_id, client_id);
+
+ res = g_dbus_proxy_call_sync (dbus->sm_proxy,
+ "RegisterClient",
+ g_variant_new ("(ss)", dbus->app_id, client_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ &error);
+
+ if (error)
+ {
+ g_warning ("Failed to register client: %s", error->message);
+ g_error_free (error);
+ g_clear_object (&dbus->sm_proxy);
+ return;
+ }
+
+ g_variant_get (res, "(o)", &dbus->client_path);
+ g_variant_unref (res);
+
+ g_debug ("Registered client at '%s'", dbus->client_path);
+
+ dbus->client_proxy = g_dbus_proxy_new_sync (dbus->session, 0,
+ NULL,
+ "org.gnome.SessionManager",
+ dbus->client_path,
+ "org.gnome.SessionManager.ClientPrivate",
+ NULL,
+ &error);
+ if (error)
+ {
+ g_warning ("Failed to get client proxy: %s", error->message);
+ g_error_free (error);
+ g_clear_object (&dbus->sm_proxy);
+ g_free (dbus->client_path);
+ dbus->client_path = NULL;
+ return;
+ }
+
+ g_signal_connect (dbus->client_proxy, "g-signal", G_CALLBACK (client_proxy_signal), dbus);
+}
+
+static void
+gtk_application_impl_dbus_shutdown (GtkApplicationImpl *impl)
+{
+}
+
+G_DEFINE_QUARK (GtkApplicationImplDBus export id, gtk_application_impl_dbus_export_id)
+
+static void
+gtk_application_impl_dbus_window_added (GtkApplicationImpl *impl,
+ GtkWindow *window)
+{
+ GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
+ GActionGroup *actions;
+ gchar *path;
+ guint id;
+
+ if (!dbus->session || !GTK_IS_APPLICATION_WINDOW (window))
+ return;
+
+ /* Export the action group of this window, based on its id */
+ actions = gtk_application_window_get_action_group (GTK_APPLICATION_WINDOW (window));
+
+ path = gtk_application_impl_dbus_get_window_path (dbus, window);
+ id = g_dbus_connection_export_action_group (dbus->session, path, actions, NULL);
+ g_free (path);
+
+ g_object_set_qdata (G_OBJECT (window), gtk_application_impl_dbus_export_id_quark (), GUINT_TO_POINTER (id));
+}
+
+static void
+gtk_application_impl_dbus_window_removed (GtkApplicationImpl *impl,
+ GtkWindow *window)
+{
+ GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
+ guint id;
+
+ id = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window), gtk_application_impl_dbus_export_id_quark ()));
+ if (id)
+ {
+ g_dbus_connection_unexport_action_group (dbus->session, id);
+ g_object_set_qdata (G_OBJECT (window), gtk_application_impl_dbus_export_id_quark (), NULL);
+ }
+}
+
+static void
+gtk_application_impl_dbus_active_window_changed (GtkApplicationImpl *impl,
+ GtkWindow *window)
+{
+}
+
+static void
+gtk_application_impl_dbus_publish_menu (GtkApplicationImplDBus *dbus,
+ const gchar *type,
+ GMenuModel *model,
+ guint *id,
+ gchar **path)
+{
+ gint i;
+
+ if (dbus->session == NULL)
+ return;
+
+ /* unexport any existing menu */
+ if (*id)
+ {
+ g_dbus_connection_unexport_menu_model (dbus->session, *id);
+ g_free (*path);
+ *path = NULL;
+ *id = 0;
+ }
+
+ /* export the new menu, if there is one */
+ if (model != NULL)
+ {
+ /* try getting the preferred name */
+ *path = g_strconcat (dbus->object_path, "/menus/", type, NULL);
+ *id = g_dbus_connection_export_menu_model (dbus->session, *path, model, NULL);
+
+ /* keep trying until we get a working name... */
+ for (i = 0; *id == 0; i++)
+ {
+ g_free (*path);
+ *path = g_strdup_printf ("%s/menus/%s%d", dbus->object_path, type, i);
+ *id = g_dbus_connection_export_menu_model (dbus->session, *path, model, NULL);
+ }
+ }
+}
+
+static void
+gtk_application_impl_dbus_set_app_menu (GtkApplicationImpl *impl,
+ GMenuModel *app_menu)
+{
+ GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
+
+ gtk_application_impl_dbus_publish_menu (dbus, "appmenu", app_menu, &dbus->app_menu_id, &dbus->app_menu_path);
+}
+
+static void
+gtk_application_impl_dbus_set_menubar (GtkApplicationImpl *impl,
+ GMenuModel *menubar)
+{
+ GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
+
+ gtk_application_impl_dbus_publish_menu (dbus, "menubar", menubar, &dbus->menubar_id, &dbus->menubar_path);
+}
+
+static GVariant *
+gtk_application_impl_dbus_real_get_window_system_id (GtkApplicationImplDBus *dbus,
+ GtkWindow *window)
+{
+ return g_variant_new_uint32 (0);
+}
+
+/* returns floating */
+static GVariant *
+gtk_application_impl_dbus_get_window_system_id (GtkApplicationImplDBus *dbus,
+ GtkWindow *window)
+{
+ return GTK_APPLICATION_IMPL_DBUS_GET_CLASS (dbus)->get_window_system_id (dbus, window);
+}
+
+static guint
+gtk_application_impl_dbus_inhibit (GtkApplicationImpl *impl,
+ GtkWindow *window,
+ GtkApplicationInhibitFlags flags,
+ const gchar *reason)
+{
+ GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
+ GVariant *res;
+ GError *error = NULL;
+ guint cookie;
+
+ if (dbus->sm_proxy == NULL)
+ return 0;
+
+ res = g_dbus_proxy_call_sync (dbus->sm_proxy,
+ "Inhibit",
+ g_variant_new ("(s@usu)",
+ g_application_get_application_id (G_APPLICATION (impl->application)),
+ gtk_application_impl_dbus_get_window_system_id (dbus, window),
+ reason,
+ flags),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ &error);
+
+ if (error)
+ {
+ g_warning ("Calling Inhibit failed: %s", error->message);
+ g_error_free (error);
+ return 0;
+ }
+
+ g_variant_get (res, "(u)", &cookie);
+ g_variant_unref (res);
+
+ return cookie;
+
+}
+
+static void
+gtk_application_impl_dbus_uninhibit (GtkApplicationImpl *impl,
+ guint cookie)
+{
+ GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
+
+ /* Application could only obtain a cookie through a session
+ * manager proxy, so it's valid to assert its presence here. */
+ g_return_if_fail (dbus->sm_proxy != NULL);
+
+ g_dbus_proxy_call (dbus->sm_proxy,
+ "Uninhibit",
+ g_variant_new ("(u)", cookie),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL, NULL, NULL);
+}
+
+static gboolean
+gtk_application_impl_dbus_is_inhibited (GtkApplicationImpl *impl,
+ GtkApplicationInhibitFlags flags)
+{
+ GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
+ GVariant *res;
+ GError *error = NULL;
+ gboolean inhibited;
+
+ if (dbus->sm_proxy == NULL)
+ return FALSE;
+
+ res = g_dbus_proxy_call_sync (dbus->sm_proxy,
+ "IsInhibited",
+ g_variant_new ("(u)", flags),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ &error);
+ if (error)
+ {
+ g_warning ("Calling IsInhibited failed: %s", error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ g_variant_get (res, "(b)", &inhibited);
+ g_variant_unref (res);
+
+ return inhibited;
+}
+
+static void
+gtk_application_impl_dbus_init (GtkApplicationImplDBus *dbus)
+{
+}
+
+static void
+gtk_application_impl_dbus_finalize (GObject *object)
+{
+ //GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) object;
+
+ G_OBJECT_CLASS (gtk_application_impl_dbus_parent_class)->finalize (object);
+}
+
+static void
+gtk_application_impl_dbus_class_init (GtkApplicationImplDBusClass *class)
+{
+ GtkApplicationImplClass *impl_class = GTK_APPLICATION_IMPL_CLASS (class);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+ class->get_window_system_id = gtk_application_impl_dbus_real_get_window_system_id;
+
+ impl_class->startup = gtk_application_impl_dbus_startup;
+ impl_class->shutdown = gtk_application_impl_dbus_shutdown;
+ impl_class->window_added = gtk_application_impl_dbus_window_added;
+ impl_class->window_removed = gtk_application_impl_dbus_window_removed;
+ impl_class->active_window_changed = gtk_application_impl_dbus_active_window_changed;
+ impl_class->set_app_menu = gtk_application_impl_dbus_set_app_menu;
+ impl_class->set_menubar = gtk_application_impl_dbus_set_menubar;
+ impl_class->inhibit = gtk_application_impl_dbus_inhibit;
+ impl_class->uninhibit = gtk_application_impl_dbus_uninhibit;
+ impl_class->is_inhibited = gtk_application_impl_dbus_is_inhibited;
+
+ gobject_class->finalize = gtk_application_impl_dbus_finalize;
+}
+
+gchar *
+gtk_application_impl_dbus_get_window_path (GtkApplicationImplDBus *dbus,
+ GtkWindow *window)
+{
+ if (dbus->session && GTK_IS_APPLICATION_WINDOW (window))
+ return g_strdup_printf ("%s/window/%d",
+ dbus->object_path,
+ gtk_application_window_get_id (GTK_APPLICATION_WINDOW (window)));
+ else
+ return NULL;
+}
diff --git a/gtk/gtkapplication-quartz.c b/gtk/gtkapplication-quartz.c
new file mode 100644
index 0000000000..c1412091a4
--- /dev/null
+++ b/gtk/gtkapplication-quartz.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright © 2010 Codethink Limited
+ * Copyright © 2013 Canonical Limited
+ *
+ * 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 licence, 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#include "config.h"
+
+#include "gtkapplicationprivate.h"
+#include "gtkmodelmenu-quartz.h"
+#include "gtkmessagedialog.h"
+#include <glib/gi18n-lib.h>
+#import <Cocoa/Cocoa.h>
+
+typedef struct
+{
+ guint cookie;
+ GtkApplicationInhibitFlags flags;
+ char *reason;
+ GtkWindow *window;
+} GtkApplicationQuartzInhibitor;
+
+static void
+gtk_application_quartz_inhibitor_free (GtkApplicationQuartzInhibitor *inhibitor)
+{
+ g_free (inhibitor->reason);
+ g_clear_object (&inhibitor->window);
+ g_slice_free (GtkApplicationQuartzInhibitor, inhibitor);
+}
+
+typedef GtkApplicationImplClass GtkApplicationImplQuartzClass;
+
+typedef struct
+{
+ GtkApplicationImpl impl;
+
+ GSList *inhibitors;
+ gint quit_inhibit;
+ guint next_cookie;
+} GtkApplicationImplQuartz;
+
+G_DEFINE_TYPE (GtkApplicationImplQuartz, gtk_application_impl_quartz, GTK_TYPE_APPLICATION_IMPL)
+
+/* OS X implementation copied from EggSMClient, but simplified since
+ * it doesn't need to interact with the user.
+ */
+
+static gboolean
+idle_will_quit (gpointer user_data)
+{
+ GtkApplicationImplQuartz *quartz = user_data;
+
+ if (quartz->quit_inhibit == 0)
+ g_application_quit (G_APPLICATION (quartz->impl.application));
+ else
+ {
+ GtkApplicationQuartzInhibitor *inhibitor;
+ GSList *iter;
+ GtkWidget *dialog;
+
+ for (iter = quartz->inhibitors; iter; iter = iter->next)
+ {
+ inhibitor = iter->data;
+ if (inhibitor->flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ break;
+ }
+ g_assert (inhibitor != NULL);
+
+ dialog = gtk_message_dialog_new (inhibitor->window,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("%s cannot quit at this time:\n\n%s"),
+ g_get_application_name (),
+ inhibitor->reason);
+ g_signal_connect_swapped (dialog,
+ "response",
+ G_CALLBACK (gtk_widget_destroy),
+ dialog);
+ gtk_widget_show_all (dialog);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static pascal OSErr
+quit_requested (const AppleEvent *aevt,
+ AppleEvent *reply,
+ long refcon)
+{
+ GtkApplicationImplQuartz *quartz = GSIZE_TO_POINTER ((gsize)refcon);
+
+ /* Don't emit the "quit" signal immediately, since we're
+ * called from a weird point in the guts of gdkeventloop-quartz.c
+ */
+ g_idle_add_full (G_PRIORITY_DEFAULT, idle_will_quit, quartz, NULL);
+
+ return quartz->quit_inhibit == 0 ? noErr : userCanceledErr;
+}
+
+static void
+gtk_application_impl_quartz_menu_changed (GtkApplicationImplQuartz *quartz)
+{
+ GMenu *combined;
+
+ combined = g_menu_new ();
+ g_menu_append_submenu (combined, "Application", gtk_application_get_app_menu (quartz->impl.application));
+ g_menu_append_section (combined, NULL, gtk_application_get_menubar (quartz->impl.application));
+
+ gtk_quartz_set_main_menu (G_MENU_MODEL (combined), quartz->impl.application);
+
+ g_object_unref (combined);
+}
+
+static void
+gtk_application_impl_quartz_startup (GtkApplicationImpl *impl,
+ gboolean register_session)
+{
+ GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
+
+ if (register_session)
+ AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
+ NewAEEventHandlerUPP (quit_requested),
+ (long)GPOINTER_TO_SIZE (quartz), false);
+
+ gtk_application_impl_quartz_menu_changed (quartz);
+
+ [NSApp finishLaunching];
+}
+
+static void
+gtk_application_impl_quartz_shutdown (GtkApplicationImpl *impl)
+{
+ GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
+
+ gtk_quartz_clear_main_menu ();
+
+ g_slist_free_full (quartz->inhibitors, (GDestroyNotify) gtk_application_quartz_inhibitor_free);
+ quartz->inhibitors = NULL;
+}
+
+static void
+gtk_application_impl_quartz_set_app_menu (GtkApplicationImpl *impl,
+ GMenuModel *app_menu)
+{
+ GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
+
+ gtk_application_impl_quartz_menu_changed (quartz);
+}
+
+static void
+gtk_application_impl_quartz_set_menubar (GtkApplicationImpl *impl,
+ GMenuModel *menubar)
+{
+ GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
+
+ gtk_application_impl_quartz_menu_changed (quartz);
+}
+
+static guint
+gtk_application_impl_quartz_inhibit (GtkApplicationImpl *impl,
+ GtkWindow *window,
+ GtkApplicationInhibitFlags flags,
+ const gchar *reason)
+{
+ GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
+ GtkApplicationQuartzInhibitor *inhibitor;
+
+ inhibitor = g_slice_new (GtkApplicationQuartzInhibitor);
+ inhibitor->cookie = ++quartz->next_cookie;
+ inhibitor->flags = flags;
+ inhibitor->reason = g_strdup (reason);
+ inhibitor->window = window ? g_object_ref (window) : NULL;
+
+ quartz->inhibitors = g_slist_prepend (quartz->inhibitors, inhibitor);
+
+ if (flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ quartz->quit_inhibit++;
+
+ return inhibitor->cookie;
+}
+
+static void
+gtk_application_impl_quartz_uninhibit (GtkApplicationImpl *impl,
+ guint cookie)
+{
+ GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
+ GSList *iter;
+
+ for (iter = quartz->inhibitors; iter; iter = iter->next)
+ {
+ GtkApplicationQuartzInhibitor *inhibitor = iter->data;
+
+ if (inhibitor->cookie == cookie)
+ {
+ if (inhibitor->flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ quartz->quit_inhibit--;
+ gtk_application_quartz_inhibitor_free (inhibitor);
+ quartz->inhibitors = g_slist_delete_link (quartz->inhibitors, iter);
+ return;
+ }
+ }
+
+ g_warning ("Invalid inhibitor cookie");
+}
+
+static gboolean
+gtk_application_impl_quartz_is_inhibited (GtkApplicationImpl *impl,
+ GtkApplicationInhibitFlags flags)
+{
+ GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
+
+ if (flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ return quartz->quit_inhibit > 0;
+
+ return FALSE;
+}
+
+static void
+gtk_application_impl_quartz_init (GtkApplicationImplQuartz *quartz)
+{
+}
+
+static void
+gtk_application_impl_quartz_finalize (GObject *object)
+{
+ GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) object;
+
+ g_slist_free_full (quartz->inhibitors, (GDestroyNotify) gtk_application_quartz_inhibitor_free);
+
+ G_OBJECT_CLASS (gtk_application_impl_quartz_parent_class)->finalize (object);
+}
+
+static void
+gtk_application_impl_quartz_class_init (GtkApplicationImplClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+ class->startup = gtk_application_impl_quartz_startup;
+ class->shutdown = gtk_application_impl_quartz_shutdown;
+ class->set_app_menu = gtk_application_impl_quartz_set_app_menu;
+ class->set_menubar = gtk_application_impl_quartz_set_menubar;
+ class->inhibit = gtk_application_impl_quartz_inhibit;
+ class->uninhibit = gtk_application_impl_quartz_uninhibit;
+ class->is_inhibited = gtk_application_impl_quartz_is_inhibited;
+
+ gobject_class->finalize = gtk_application_impl_quartz_finalize;
+}
diff --git a/gtk/gtkapplication-wayland.c b/gtk/gtkapplication-wayland.c
new file mode 100644
index 0000000000..c0b18bd22c
--- /dev/null
+++ b/gtk/gtkapplication-wayland.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright © 2010 Codethink Limited
+ * Copyright © 2013 Canonical Limited
+ *
+ * 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 licence, 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#include "config.h"
+
+#include "gtkapplicationprivate.h"
+
+#include <gdk/wayland/gdkwayland.h>
+
+typedef GtkApplicationImplDBusClass GtkApplicationImplWaylandClass;
+
+typedef struct
+{
+ GtkApplicationImplDBus dbus;
+
+} GtkApplicationImplWayland;
+
+G_DEFINE_TYPE (GtkApplicationImplWayland, gtk_application_impl_wayland, GTK_TYPE_APPLICATION_IMPL_DBUS)
+
+static void
+gtk_application_impl_wayland_handle_window_map (GtkApplicationImpl *impl,
+ GtkWindow *window)
+{
+ GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
+ GdkWindow *gdk_window;
+ gchar *window_path;
+
+ gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
+
+ if (!GDK_IS_WAYLAND_WINDOW (gdk_window))
+ return;
+
+ window_path = gtk_application_impl_dbus_get_window_path (dbus, window);
+
+ gdk_wayland_window_set_dbus_properties_libgtk_only (gdk_window,
+ dbus->application_id, dbus->app_menu_path, dbus->menubar_path,
+ window_path, dbus->object_path, dbus->unique_name);
+
+ g_free (window_path);
+}
+
+static void
+gtk_application_impl_wayland_init (GtkApplicationImplWayland *wayland)
+{
+}
+
+static void
+gtk_application_impl_wayland_class_init (GtkApplicationImplWaylandClass *class)
+{
+ GtkApplicationImplClass *impl_class = GTK_APPLICATION_IMPL_CLASS (class);
+
+ impl_class->handle_window_map = gtk_application_impl_wayland_handle_window_map;
+}
diff --git a/gtk/gtkapplication-x11.c b/gtk/gtkapplication-x11.c
new file mode 100644
index 0000000000..1bd3f29b2a
--- /dev/null
+++ b/gtk/gtkapplication-x11.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2010 Codethink Limited
+ * Copyright © 2013 Canonical Limited
+ *
+ * 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 licence, 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#include "config.h"
+
+#include "gtkapplicationprivate.h"
+
+#include <gdk/gdkx.h>
+
+typedef GtkApplicationImplDBusClass GtkApplicationImplX11Class;
+
+typedef struct
+{
+ GtkApplicationImplDBus dbus;
+
+} GtkApplicationImplX11;
+
+G_DEFINE_TYPE (GtkApplicationImplX11, gtk_application_impl_x11, GTK_TYPE_APPLICATION_IMPL_DBUS)
+
+static void
+gtk_application_impl_x11_handle_window_realize (GtkApplicationImpl *impl,
+ GtkWindow *window)
+{
+ GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
+ GdkWindow *gdk_window;
+ gchar *window_path;
+
+ gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
+
+ if (!GDK_IS_X11_WINDOW (gdk_window))
+ return;
+
+ window_path = gtk_application_impl_dbus_get_window_path (dbus, window);
+
+ gdk_x11_window_set_utf8_property (gdk_window, "_GTK_APPLICATION_ID", dbus->application_id);
+ gdk_x11_window_set_utf8_property (gdk_window, "_GTK_UNIQUE_BUS_NAME", dbus->unique_name);
+ gdk_x11_window_set_utf8_property (gdk_window, "_GTK_APPLICATION_OBJECT_PATH", dbus->object_path);
+ gdk_x11_window_set_utf8_property (gdk_window, "_GTK_WINDOW_OBJECT_PATH", window_path);
+ gdk_x11_window_set_utf8_property (gdk_window, "_GTK_APP_MENU_OBJECT_PATH", dbus->app_menu_path);
+ gdk_x11_window_set_utf8_property (gdk_window, "_GTK_MENUBAR_OBJECT_PATH", dbus->menubar_path);
+
+ g_free (window_path);
+}
+
+static GVariant *
+gtk_application_impl_x11_get_window_system_id (GtkApplicationImplDBus *dbus,
+ GtkWindow *window)
+{
+ GdkWindow *gdk_window;
+
+ gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
+
+ if (GDK_IS_X11_WINDOW (gdk_window))
+ return g_variant_new_uint32 (GDK_WINDOW_XID (gdk_window));
+
+ return GTK_APPLICATION_IMPL_DBUS_CLASS (gtk_application_impl_x11_parent_class)->get_window_system_id (dbus, window);
+}
+
+static void
+gtk_application_impl_x11_init (GtkApplicationImplX11 *x11)
+{
+}
+
+static void
+gtk_application_impl_x11_class_init (GtkApplicationImplX11Class *class)
+{
+ GtkApplicationImplDBusClass *dbus_class = GTK_APPLICATION_IMPL_DBUS_CLASS (class);
+ GtkApplicationImplClass *impl_class = GTK_APPLICATION_IMPL_CLASS (class);
+
+ impl_class->handle_window_realize = gtk_application_impl_x11_handle_window_realize;
+ dbus_class->get_window_system_id = gtk_application_impl_x11_get_window_system_id;
+}
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c
index d8af4a06f5..46540ab5ee 100644
--- a/gtk/gtkapplication.c
+++ b/gtk/gtkapplication.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2010 Codethink Limited
+ * Copyright © 2013 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,9 +23,7 @@
#include "gtkapplication.h"
#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
#include <unistd.h>
-#endif
#include <string.h>
#include "gtkapplicationprivate.h"
@@ -33,19 +32,12 @@
#include "gtkmain.h"
#include "gtkrecentmanager.h"
#include "gtkaccelmapprivate.h"
+#include "gtkbuilder.h"
#include "gtkintl.h"
-#ifdef GDK_WINDOWING_QUARTZ
-#include "gtkmodelmenu-quartz.h"
-#import <Cocoa/Cocoa.h>
-#include <Carbon/Carbon.h>
-#include "gtkmessagedialog.h"
-#endif
-
-#include <gdk/gdk.h>
-#ifdef GDK_WINDOWING_X11
-#include <gdk/x11/gdkx.h>
-#endif
+/* NB: please do not add backend-specific GDK headers here. This should
+ * be abstracted via GtkApplicationImpl.
+ */
/**
* SECTION:gtkapplication
@@ -469,245 +461,33 @@ accels_finalize (Accels *accels)
struct _GtkApplicationPrivate
{
+ GtkApplicationImpl *impl;
+
GList *windows;
GMenuModel *app_menu;
GMenuModel *menubar;
Accels accels;
+ guint last_window_id;
gboolean register_session;
GtkActionMuxer *muxer;
-
-#ifdef GDK_WINDOWING_X11
- guint next_id;
-
- GDBusConnection *session_bus;
- const gchar *application_id;
- const gchar *object_path;
-
- gchar *app_menu_path;
- guint app_menu_id;
-
- guint menubar_id;
- gchar *menubar_path;
-
- GDBusProxy *sm_proxy;
- GDBusProxy *client_proxy;
- gchar *app_id;
- gchar *client_path;
-#endif
-
-#ifdef GDK_WINDOWING_QUARTZ
- GMenu *combined;
-
- GSList *inhibitors;
- gint quit_inhibit;
- guint next_cookie;
-#endif
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
-#ifdef GDK_WINDOWING_X11
-static void
-gtk_application_x11_publish_menu (GtkApplication *application,
- const gchar *type,
- GMenuModel *model,
- guint *id,
- gchar **path)
-{
- gint i;
-
- if (application->priv->session_bus == NULL)
- return;
-
- /* unexport any existing menu */
- if (*id)
- {
- g_dbus_connection_unexport_menu_model (application->priv->session_bus, *id);
- g_free (*path);
- *path = NULL;
- *id = 0;
- }
-
- /* export the new menu, if there is one */
- if (model != NULL)
- {
- /* try getting the preferred name */
- *path = g_strconcat (application->priv->object_path, "/menus/", type, NULL);
- *id = g_dbus_connection_export_menu_model (application->priv->session_bus, *path, model, NULL);
-
- /* keep trying until we get a working name... */
- for (i = 0; *id == 0; i++)
- {
- g_free (*path);
- *path = g_strdup_printf ("%s/menus/%s%d", application->priv->object_path, type, i);
- *id = g_dbus_connection_export_menu_model (application->priv->session_bus, *path, model, NULL);
- }
- }
-}
-
-static void
-gtk_application_set_app_menu_x11 (GtkApplication *application,
- GMenuModel *app_menu)
-{
- gtk_application_x11_publish_menu (application, "appmenu", app_menu,
- &application->priv->app_menu_id,
- &application->priv->app_menu_path);
-}
-
-static void
-gtk_application_set_menubar_x11 (GtkApplication *application,
- GMenuModel *menubar)
-{
- gtk_application_x11_publish_menu (application, "menubar", menubar,
- &application->priv->menubar_id,
- &application->priv->menubar_path);
-}
-
-static void
-gtk_application_window_added_x11 (GtkApplication *application,
- GtkWindow *window)
-{
- if (application->priv->session_bus == NULL)
- return;
-
- if (GTK_IS_APPLICATION_WINDOW (window))
- {
- GtkApplicationWindow *app_window = GTK_APPLICATION_WINDOW (window);
- gboolean success;
-
- /* GtkApplicationWindow associates with us when it is first created,
- * so surely it's not realized yet...
- */
- g_assert (!gtk_widget_get_realized (GTK_WIDGET (window)));
-
- do
- {
- gchar *window_path;
- guint window_id;
-
- window_id = application->priv->next_id++;
- window_path = g_strdup_printf ("%s/window/%u", application->priv->object_path, window_id);
- success = gtk_application_window_publish (app_window, application->priv->session_bus, window_path, window_id);
- g_free (window_path);
- }
- while (!success);
- }
-}
-
-static void
-gtk_application_window_removed_x11 (GtkApplication *application,
- GtkWindow *window)
-{
- if (application->priv->session_bus == NULL)
- return;
-
- if (GTK_IS_APPLICATION_WINDOW (window))
- gtk_application_window_unpublish (GTK_APPLICATION_WINDOW (window));
-}
-
-static void gtk_application_startup_session_dbus (GtkApplication *app);
-
-static void
-gtk_application_startup_x11 (GtkApplication *application)
-{
- application->priv->session_bus = g_application_get_dbus_connection (G_APPLICATION (application));
- application->priv->object_path = g_application_get_dbus_object_path (G_APPLICATION (application));
-
- gtk_application_startup_session_dbus (GTK_APPLICATION (application));
-}
-
-static void
-gtk_application_shutdown_x11 (GtkApplication *application)
-{
- gtk_application_set_app_menu_x11 (application, NULL);
- gtk_application_set_menubar_x11 (application, NULL);
-
- application->priv->session_bus = NULL;
- application->priv->object_path = NULL;
-
- g_clear_object (&application->priv->sm_proxy);
- g_clear_object (&application->priv->client_proxy);
- g_free (application->priv->app_id);
- g_free (application->priv->client_path);
-}
-
const gchar *
gtk_application_get_app_menu_object_path (GtkApplication *application)
{
- return application->priv->app_menu_path;
+ g_assert_not_reached (); /* XXX */
}
const gchar *
gtk_application_get_menubar_object_path (GtkApplication *application)
{
- return application->priv->menubar_path;
-}
-
-#endif
-
-#ifdef GDK_WINDOWING_QUARTZ
-
-typedef struct {
- guint cookie;
- GtkApplicationInhibitFlags flags;
- char *reason;
- GtkWindow *window;
-} GtkApplicationQuartzInhibitor;
-
-static void
-gtk_application_quartz_inhibitor_free (GtkApplicationQuartzInhibitor *inhibitor)
-{
- g_free (inhibitor->reason);
- g_clear_object (&inhibitor->window);
- g_slice_free (GtkApplicationQuartzInhibitor, inhibitor);
+ g_assert_not_reached (); /* XXX */
}
-static void
-gtk_application_menu_changed_quartz (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- GtkApplication *application = GTK_APPLICATION (object);
- GMenu *combined;
-
- combined = g_menu_new ();
- g_menu_append_submenu (combined, "Application", gtk_application_get_app_menu (application));
- g_menu_append_section (combined, NULL, gtk_application_get_menubar (application));
-
- gtk_quartz_set_main_menu (G_MENU_MODEL (combined), application);
-
- g_object_unref (combined);
-}
-
-static void gtk_application_startup_session_quartz (GtkApplication *app);
-
-static void
-gtk_application_startup_quartz (GtkApplication *application)
-{
- [NSApp finishLaunching];
-
- 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
-gtk_application_shutdown_quartz (GtkApplication *application)
-{
- gtk_quartz_clear_main_menu ();
-
- g_signal_handlers_disconnect_by_func (application, gtk_application_menu_changed_quartz, NULL);
-
- g_slist_free_full (application->priv->inhibitors,
- (GDestroyNotify) gtk_application_quartz_inhibitor_free);
- application->priv->inhibitors = NULL;
-}
-#endif
-
static gboolean
gtk_application_focus_in_event_cb (GtkWindow *window,
GdkEventFocus *event,
@@ -724,6 +504,7 @@ gtk_application_focus_in_event_cb (GtkWindow *window,
priv->windows = g_list_concat (link, priv->windows);
}
+ gtk_application_impl_active_window_changed (application->priv->impl, window);
g_object_notify (G_OBJECT (application), "active-window");
return FALSE;
@@ -741,25 +522,17 @@ gtk_application_startup (GApplication *g_application)
gtk_init (0, 0);
-#ifdef GDK_WINDOWING_X11
- gtk_application_startup_x11 (application);
-#endif
-
-#ifdef GDK_WINDOWING_QUARTZ
- gtk_application_startup_quartz (application);
-#endif
+ application->priv->impl = gtk_application_impl_new (application, gdk_display_get_default ());
+ gtk_application_impl_startup (application->priv->impl, application->priv->register_session);
}
static void
-gtk_application_shutdown (GApplication *application)
+gtk_application_shutdown (GApplication *g_application)
{
-#ifdef GDK_WINDOWING_X11
- gtk_application_shutdown_x11 (GTK_APPLICATION (application));
-#endif
+ GtkApplication *application = GTK_APPLICATION (g_application);
-#ifdef GDK_WINDOWING_QUARTZ
- gtk_application_shutdown_quartz (GTK_APPLICATION (application));
-#endif
+ gtk_application_impl_shutdown (application->priv->impl);
+ g_clear_object (&application->priv->impl);
/* Keep this section in sync with gtk_main() */
@@ -770,7 +543,7 @@ gtk_application_shutdown (GApplication *application)
_gtk_recent_manager_sync ();
G_APPLICATION_CLASS (gtk_application_parent_class)
- ->shutdown (application);
+ ->shutdown (g_application);
}
static void
@@ -779,39 +552,29 @@ gtk_application_add_platform_data (GApplication *application,
{
const gchar *startup_id;
+ /* This is slightly evil.
+ *
+ * We don't have an impl here because we're remote so we can't figure
+ * out what to do on a per-display-server basis.
+ *
+ * So we do all the things... which currently is just one thing.
+ */
startup_id = getenv ("DESKTOP_STARTUP_ID");
-
+
if (startup_id && g_utf8_validate (startup_id, -1, NULL))
g_variant_builder_add (builder, "{sv}", "desktop-startup-id",
g_variant_new_string (startup_id));
}
static void
-gtk_application_before_emit (GApplication *application,
+gtk_application_before_emit (GApplication *g_application,
GVariant *platform_data)
{
- GVariantIter iter;
- const gchar *key;
- GVariant *value;
+ GtkApplication *application = GTK_APPLICATION (g_application);
gdk_threads_enter ();
- g_variant_iter_init (&iter, platform_data);
- while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
- {
-#ifdef GDK_WINDOWING_X11
- if (strcmp (key, "desktop-startup-id") == 0)
- {
- GdkDisplay *display;
- const gchar *id;
-
- display = gdk_display_get_default ();
- id = g_variant_get_string (value, NULL);
- if (GDK_IS_X11_DISPLAY (display))
- gdk_x11_display_set_startup_notification_id (display, id);
- }
-#endif
- }
+ gtk_application_impl_before_emit (application->priv->impl, platform_data);
}
static void
@@ -831,10 +594,6 @@ gtk_application_init (GtkApplication *application)
application->priv->muxer = gtk_action_muxer_new ();
accels_init (&application->priv->accels);
-
-#ifdef GDK_WINDOWING_X11
- application->priv->next_id = 1;
-#endif
}
static void
@@ -843,6 +602,9 @@ gtk_application_window_added (GtkApplication *application,
{
GtkApplicationPrivate *priv = application->priv;
+ if (GTK_IS_APPLICATION_WINDOW (window))
+ gtk_application_window_set_id (GTK_APPLICATION_WINDOW (window), ++application->priv->last_window_id);
+
priv->windows = g_list_prepend (priv->windows, window);
gtk_window_set_application (window, application);
g_application_hold (G_APPLICATION (application));
@@ -851,10 +613,9 @@ gtk_application_window_added (GtkApplication *application,
G_CALLBACK (gtk_application_focus_in_event_cb),
application);
-#ifdef GDK_WINDOWING_X11
- gtk_application_window_added_x11 (application, window);
-#endif
+ gtk_application_impl_window_added (application->priv->impl, window);
+ gtk_application_impl_active_window_changed (application->priv->impl, window);
g_object_notify (G_OBJECT (application), "active-window");
}
@@ -867,9 +628,7 @@ gtk_application_window_removed (GtkApplication *application,
old_active = priv->windows;
-#ifdef GDK_WINDOWING_X11
- gtk_application_window_removed_x11 (application, window);
-#endif
+ gtk_application_impl_window_removed (application->priv->impl, window);
g_signal_handlers_disconnect_by_func (window,
gtk_application_focus_in_event_cb,
@@ -880,7 +639,10 @@ gtk_application_window_removed (GtkApplication *application,
gtk_window_set_application (window, NULL);
if (priv->windows != old_active)
- g_object_notify (G_OBJECT (application), "active-window");
+ {
+ gtk_application_impl_active_window_changed (application->priv->impl, priv->windows ? priv->windows->data : NULL);
+ g_object_notify (G_OBJECT (application), "active-window");
+ }
}
static void
@@ -1411,9 +1173,7 @@ gtk_application_set_app_menu (GtkApplication *application,
if (app_menu)
extract_accels_from_menu (app_menu, application);
-#ifdef GDK_WINDOWING_X11
- gtk_application_set_app_menu_x11 (application, app_menu);
-#endif
+ gtk_application_impl_set_app_menu (application->priv->impl, app_menu);
g_object_notify (G_OBJECT (application), "app-menu");
}
@@ -1485,9 +1245,7 @@ gtk_application_set_menubar (GtkApplication *application,
if (menubar)
extract_accels_from_menu (menubar, application);
-#ifdef GDK_WINDOWING_X11
- gtk_application_set_menubar_x11 (application, menubar);
-#endif
+ gtk_application_impl_set_menubar (application->priv->impl, menubar);
g_object_notify (G_OBJECT (application), "menubar");
}
@@ -1512,178 +1270,6 @@ gtk_application_get_menubar (GtkApplication *application)
return application->priv->menubar;
}
-#if defined(GDK_WINDOWING_X11)
-
-/* D-Bus Session Management
- *
- * The protocol and the D-Bus API are described here:
- * http://live.gnome.org/SessionManagement/GnomeSession
- * http://people.gnome.org/~mccann/gnome-session/docs/gnome-session.html
- */
-
-static void
-unregister_client (GtkApplication *app)
-{
- GError *error = NULL;
-
- g_debug ("Unregistering client");
-
- g_dbus_proxy_call_sync (app->priv->sm_proxy,
- "UnregisterClient",
- g_variant_new ("(o)", app->priv->client_path),
- G_DBUS_CALL_FLAGS_NONE,
- G_MAXINT,
- NULL,
- &error);
-
- if (error)
- {
- g_warning ("Failed to unregister client: %s", error->message);
- g_error_free (error);
- }
-
- g_clear_object (&app->priv->client_proxy);
-
- g_free (app->priv->client_path);
- app->priv->client_path = NULL;
-}
-
-static void
-gtk_application_quit_response (GtkApplication *application,
- gboolean will_quit,
- const gchar *reason)
-{
- g_debug ("Calling EndSessionResponse %d '%s'", will_quit, reason);
-
- g_dbus_proxy_call (application->priv->client_proxy,
- "EndSessionResponse",
- g_variant_new ("(bs)", will_quit, reason ? reason : ""),
- G_DBUS_CALL_FLAGS_NONE,
- G_MAXINT,
- NULL, NULL, NULL);
-}
-static void
-client_proxy_signal (GDBusProxy *proxy,
- const gchar *sender_name,
- const gchar *signal_name,
- GVariant *parameters,
- GtkApplication *app)
-{
- if (strcmp (signal_name, "QueryEndSession") == 0)
- {
- g_debug ("Received QueryEndSession");
- gtk_application_quit_response (app, TRUE, NULL);
- }
- else if (strcmp (signal_name, "CancelEndSession") == 0)
- {
- g_debug ("Received CancelEndSession");
- }
- else if (strcmp (signal_name, "EndSession") == 0)
- {
- g_debug ("Received EndSession");
- gtk_application_quit_response (app, TRUE, NULL);
- unregister_client (app);
- g_application_quit (G_APPLICATION (app));
- }
- else if (strcmp (signal_name, "Stop") == 0)
- {
- g_debug ("Received Stop");
- unregister_client (app);
- g_application_quit (G_APPLICATION (app));
- }
-}
-
-static void
-gtk_application_startup_session_dbus (GtkApplication *app)
-{
- static gchar *client_id;
- GError *error = NULL;
- GVariant *res;
-
- if (app->priv->session_bus == NULL)
- return;
-
- if (client_id == NULL)
- {
- const gchar *desktop_autostart_id;
-
- desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
- /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
- * use the same client id.
- */
- g_unsetenv ("DESKTOP_AUTOSTART_ID");
- client_id = g_strdup (desktop_autostart_id ? desktop_autostart_id : "");
- }
-
- g_debug ("Connecting to session manager");
-
- app->priv->sm_proxy = g_dbus_proxy_new_sync (app->priv->session_bus,
- G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
- G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
- NULL,
- "org.gnome.SessionManager",
- "/org/gnome/SessionManager",
- "org.gnome.SessionManager",
- NULL,
- &error);
- if (error)
- {
- g_warning ("Failed to get a session proxy: %s", error->message);
- g_error_free (error);
- return;
- }
-
- /* FIXME: should we reuse the D-Bus application id here ? */
- app->priv->app_id = g_strdup (g_get_prgname ());
-
- if (!app->priv->register_session)
- return;
-
- g_debug ("Registering client '%s' '%s'", app->priv->app_id, client_id);
-
- res = g_dbus_proxy_call_sync (app->priv->sm_proxy,
- "RegisterClient",
- g_variant_new ("(ss)", app->priv->app_id, client_id),
- G_DBUS_CALL_FLAGS_NONE,
- G_MAXINT,
- NULL,
- &error);
-
- if (error)
- {
- g_warning ("Failed to register client: %s", error->message);
- g_error_free (error);
- g_clear_object (&app->priv->sm_proxy);
- return;
- }
-
- g_variant_get (res, "(o)", &app->priv->client_path);
- g_variant_unref (res);
-
- g_debug ("Registered client at '%s'", app->priv->client_path);
-
- app->priv->client_proxy = g_dbus_proxy_new_sync (app->priv->session_bus, 0,
- NULL,
- "org.gnome.SessionManager",
- app->priv->client_path,
- "org.gnome.SessionManager.ClientPrivate",
- NULL,
- &error);
- if (error)
- {
- g_warning ("Failed to get client proxy: %s", error->message);
- g_error_free (error);
- g_clear_object (&app->priv->sm_proxy);
- g_free (app->priv->client_path);
- app->priv->client_path = NULL;
- return;
- }
-
- g_signal_connect (app->priv->client_proxy, "g-signal", G_CALLBACK (client_proxy_signal), app);
-}
-
-
-
/**
* GtkApplicationInhibitFlags:
* @GTK_APPLICATION_INHIBIT_LOGOUT: Inhibit ending the user session
@@ -1742,52 +1328,10 @@ gtk_application_inhibit (GtkApplication *application,
GtkApplicationInhibitFlags flags,
const gchar *reason)
{
- GVariant *res;
- GError *error = NULL;
- guint cookie;
- guint xid = 0;
-
g_return_val_if_fail (GTK_IS_APPLICATION (application), 0);
g_return_val_if_fail (!g_application_get_is_remote (G_APPLICATION (application)), 0);
- if (application->priv->sm_proxy == NULL)
- return 0;
-
- if (window != NULL)
- {
- GdkWindow *gdkwindow;
-
- gdkwindow = gtk_widget_get_window (GTK_WIDGET (window));
- if (gdkwindow == NULL)
- g_warning ("Inhibit called with an unrealized window");
-#ifdef GDK_WINDOWING_X11
- else if (GDK_IS_X11_WINDOW (gdkwindow))
- xid = GDK_WINDOW_XID (gdkwindow);
-#endif
- }
-
- res = g_dbus_proxy_call_sync (application->priv->sm_proxy,
- "Inhibit",
- g_variant_new ("(susu)",
- application->priv->app_id,
- xid,
- reason,
- flags),
- G_DBUS_CALL_FLAGS_NONE,
- G_MAXINT,
- NULL,
- &error);
- if (error)
- {
- g_warning ("Calling Inhibit failed: %s", error->message);
- g_error_free (error);
- return 0;
- }
-
- g_variant_get (res, "(u)", &cookie);
- g_variant_unref (res);
-
- return cookie;
+ return gtk_application_impl_inhibit (application->priv->impl, window, flags, reason);
}
/**
@@ -1808,16 +1352,7 @@ gtk_application_uninhibit (GtkApplication *application,
g_return_if_fail (!g_application_get_is_remote (G_APPLICATION (application)));
g_return_if_fail (cookie > 0);
- /* Application could only obtain a cookie through a session
- * manager proxy, so it's valid to assert its presence here. */
- g_return_if_fail (application->priv->sm_proxy != NULL);
-
- g_dbus_proxy_call (application->priv->sm_proxy,
- "Uninhibit",
- g_variant_new ("(u)", cookie),
- G_DBUS_CALL_FLAGS_NONE,
- G_MAXINT,
- NULL, NULL, NULL);
+ gtk_application_impl_uninhibit (application->priv->impl, cookie);
}
/**
@@ -1836,194 +1371,12 @@ gboolean
gtk_application_is_inhibited (GtkApplication *application,
GtkApplicationInhibitFlags flags)
{
- GVariant *res;
- GError *error = NULL;
- gboolean inhibited;
-
g_return_val_if_fail (GTK_IS_APPLICATION (application), FALSE);
g_return_val_if_fail (!g_application_get_is_remote (G_APPLICATION (application)), FALSE);
- if (application->priv->sm_proxy == NULL)
- return FALSE;
-
- res = g_dbus_proxy_call_sync (application->priv->sm_proxy,
- "IsInhibited",
- g_variant_new ("(u)", flags),
- G_DBUS_CALL_FLAGS_NONE,
- G_MAXINT,
- NULL,
- &error);
- if (error)
- {
- g_warning ("Calling IsInhibited failed: %s", error->message);
- g_error_free (error);
- return FALSE;
- }
-
- g_variant_get (res, "(b)", &inhibited);
- g_variant_unref (res);
-
- return inhibited;
-}
-
-#elif defined(GDK_WINDOWING_QUARTZ)
-
-/* OS X implementation copied from EggSMClient, but simplified since
- * it doesn't need to interact with the user.
- */
-
-static gboolean
-idle_will_quit (gpointer data)
-{
- GtkApplication *app = data;
-
- if (app->priv->quit_inhibit == 0)
- g_application_quit (G_APPLICATION (app));
- else
- {
- GtkApplicationQuartzInhibitor *inhibitor;
- GSList *iter;
- GtkWidget *dialog;
-
- for (iter = app->priv->inhibitors; iter; iter = iter->next)
- {
- inhibitor = iter->data;
- if (inhibitor->flags & GTK_APPLICATION_INHIBIT_LOGOUT)
- break;
- }
- g_assert (inhibitor != NULL);
-
- dialog = gtk_message_dialog_new (inhibitor->window,
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- _("%s cannot quit at this time:\n\n%s"),
- g_get_application_name (),
- inhibitor->reason);
- g_signal_connect_swapped (dialog,
- "response",
- G_CALLBACK (gtk_widget_destroy),
- dialog);
- gtk_widget_show_all (dialog);
- }
-
- return G_SOURCE_REMOVE;
-}
-
-static pascal OSErr
-quit_requested (const AppleEvent *aevt,
- AppleEvent *reply,
- long refcon)
-{
- GtkApplication *app = GSIZE_TO_POINTER ((gsize)refcon);
-
- /* Don't emit the "quit" signal immediately, since we're
- * called from a weird point in the guts of gdkeventloop-quartz.c
- */
- g_idle_add_full (G_PRIORITY_DEFAULT, idle_will_quit, app, NULL);
-
- return app->priv->quit_inhibit == 0 ? noErr : userCanceledErr;
+ return gtk_application_impl_is_inhibited (application->priv->impl, flags);
}
-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);
-}
-
-guint
-gtk_application_inhibit (GtkApplication *application,
- GtkWindow *window,
- GtkApplicationInhibitFlags flags,
- const gchar *reason)
-{
- GtkApplicationQuartzInhibitor *inhibitor;
-
- g_return_val_if_fail (GTK_IS_APPLICATION (application), 0);
- g_return_val_if_fail (flags != 0, 0);
-
- inhibitor = g_slice_new (GtkApplicationQuartzInhibitor);
- inhibitor->cookie = ++application->priv->next_cookie;
- inhibitor->flags = flags;
- inhibitor->reason = g_strdup (reason);
- inhibitor->window = window ? g_object_ref (window) : NULL;
-
- application->priv->inhibitors = g_slist_prepend (application->priv->inhibitors, inhibitor);
-
- if (flags & GTK_APPLICATION_INHIBIT_LOGOUT)
- application->priv->quit_inhibit++;
-
- return inhibitor->cookie;
-}
-
-void
-gtk_application_uninhibit (GtkApplication *application,
- guint cookie)
-{
- GSList *iter;
-
- for (iter = application->priv->inhibitors; iter; iter = iter->next)
- {
- GtkApplicationQuartzInhibitor *inhibitor = iter->data;
-
- if (inhibitor->cookie == cookie)
- {
- if (inhibitor->flags & GTK_APPLICATION_INHIBIT_LOGOUT)
- application->priv->quit_inhibit--;
- gtk_application_quartz_inhibitor_free (inhibitor);
- application->priv->inhibitors = g_slist_delete_link (application->priv->inhibitors, iter);
- return;
- }
- }
-
- g_warning ("Invalid inhibitor cookie");
-}
-
-gboolean
-gtk_application_is_inhibited (GtkApplication *application,
- GtkApplicationInhibitFlags flags)
-{
- if (flags & GTK_APPLICATION_INHIBIT_LOGOUT)
- return application->priv->quit_inhibit > 0;
-
- return FALSE;
-}
-
-#else
-
-/* Trivial implementation.
- *
- * For the inhibit API on Windows, see
- * http://msdn.microsoft.com/en-us/library/ms700677%28VS.85%29.aspx
- */
-
-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;
-}
-
-#endif
-
GtkActionMuxer *
gtk_application_get_parent_muxer_for_window (GtkWindow *window)
{
@@ -2179,3 +1532,25 @@ gtk_application_get_accels_for_action (GtkApplication *application,
return accels;
}
+
+GtkActionMuxer *
+gtk_application_get_action_muxer (GtkApplication *application)
+{
+ g_assert (application->priv->muxer);
+
+ return application->priv->muxer;
+}
+
+void
+gtk_application_handle_window_realize (GtkApplication *application,
+ GtkWindow *window)
+{
+ gtk_application_impl_handle_window_realize (application->priv->impl, window);
+}
+
+void
+gtk_application_handle_window_map (GtkApplication *application,
+ GtkWindow *window)
+{
+ gtk_application_impl_handle_window_map (application->priv->impl, window);
+}
diff --git a/gtk/gtkapplicationimpl.c b/gtk/gtkapplicationimpl.c
new file mode 100644
index 0000000000..6cb899aad3
--- /dev/null
+++ b/gtk/gtkapplicationimpl.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright © 2013 Canonical Limited
+ *
+ * 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 licence, 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#include "config.h"
+
+#include "gtkapplicationprivate.h"
+
+#ifdef GDK_WINDOWING_X11
+#include <gdk/x11/gdkx.h>
+#endif
+
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/wayland/gdkwayland.h>
+#endif
+
+#ifdef GDK_WINDOWING_QUARTZ
+#include <gdk/quartz/gdkquartz.h>
+#endif
+
+G_DEFINE_TYPE (GtkApplicationImpl, gtk_application_impl, G_TYPE_OBJECT)
+
+static void
+gtk_application_impl_init (GtkApplicationImpl *impl)
+{
+}
+
+static guint do_nothing (void) { return 0; }
+
+static void
+gtk_application_impl_class_init (GtkApplicationImplClass *class)
+{
+ /* NB: can only 'do_nothing' for functions with integer or void return */
+ class->startup = (gpointer) do_nothing;
+ class->shutdown = (gpointer) do_nothing;
+ class->before_emit = (gpointer) do_nothing;
+ class->window_added = (gpointer) do_nothing;
+ class->window_removed = (gpointer) do_nothing;
+ class->active_window_changed = (gpointer) do_nothing;
+ class->handle_window_realize = (gpointer) do_nothing;
+ class->handle_window_map = (gpointer) do_nothing;
+ class->set_app_menu = (gpointer) do_nothing;
+ class->set_menubar = (gpointer) do_nothing;
+ class->inhibit = (gpointer) do_nothing;
+ class->uninhibit = (gpointer) do_nothing;
+ class->is_inhibited = (gpointer) do_nothing;
+}
+
+void
+gtk_application_impl_startup (GtkApplicationImpl *impl,
+ gboolean register_session)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->startup (impl, register_session);
+}
+
+void
+gtk_application_impl_shutdown (GtkApplicationImpl *impl)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->shutdown (impl);
+}
+
+void
+gtk_application_impl_before_emit (GtkApplicationImpl *impl,
+ GVariant *platform_data)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->before_emit (impl, platform_data);
+}
+
+void
+gtk_application_impl_window_added (GtkApplicationImpl *impl,
+ GtkWindow *window)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->window_added (impl, window);
+}
+
+void
+gtk_application_impl_window_removed (GtkApplicationImpl *impl,
+ GtkWindow *window)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->window_removed (impl, window);
+}
+
+void
+gtk_application_impl_active_window_changed (GtkApplicationImpl *impl,
+ GtkWindow *window)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->active_window_changed (impl, window);
+}
+
+void
+gtk_application_impl_handle_window_realize (GtkApplicationImpl *impl,
+ GtkWindow *window)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->handle_window_realize (impl, window);
+}
+
+void
+gtk_application_impl_handle_window_map (GtkApplicationImpl *impl,
+ GtkWindow *window)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->handle_window_map (impl, window);
+}
+
+void
+gtk_application_impl_set_app_menu (GtkApplicationImpl *impl,
+ GMenuModel *app_menu)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->set_app_menu (impl, app_menu);
+}
+
+void
+gtk_application_impl_set_menubar (GtkApplicationImpl *impl,
+ GMenuModel *menubar)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->set_menubar (impl, menubar);
+}
+
+guint
+gtk_application_impl_inhibit (GtkApplicationImpl *impl,
+ GtkWindow *window,
+ GtkApplicationInhibitFlags flags,
+ const gchar *reason)
+{
+ return GTK_APPLICATION_IMPL_GET_CLASS (impl)->inhibit (impl, window, flags, reason);
+}
+
+void
+gtk_application_impl_uninhibit (GtkApplicationImpl *impl,
+ guint cookie)
+{
+ GTK_APPLICATION_IMPL_GET_CLASS (impl)->uninhibit (impl, cookie);
+}
+
+gboolean
+gtk_application_impl_is_inhibited (GtkApplicationImpl *impl,
+ GtkApplicationInhibitFlags flags)
+{
+ return GTK_APPLICATION_IMPL_GET_CLASS (impl)->is_inhibited (impl, flags);
+}
+
+GtkApplicationImpl *
+gtk_application_impl_new (GtkApplication *application,
+ GdkDisplay *display)
+{
+ GtkApplicationImpl *impl;
+ GType impl_type;
+
+ impl_type = gtk_application_impl_get_type ();
+
+#ifdef GDK_WINDOWING_X11
+ if (GDK_IS_X11_DISPLAY (display))
+ impl_type = gtk_application_impl_x11_get_type ();
+#endif
+
+#ifdef GDK_WINDOWING_WAYLAND
+ if (GDK_IS_WAYLAND_DISPLAY (display))
+ impl_type = gtk_application_impl_wayland_get_type ();
+#endif
+
+#ifdef GDK_WINDOWING_QUARTZ
+ if (GDK_IS_QUARTZ_DISPLAY (display))
+ impl_type = gtk_application_impl_quartz_get_type ();
+#endif
+
+ impl = g_object_new (impl_type, NULL);
+ impl->application = application;
+ impl->display = display;
+
+ return impl;
+}
diff --git a/gtk/gtkapplicationprivate.h b/gtk/gtkapplicationprivate.h
index 597b5a64e3..db2fa0086c 100644
--- a/gtk/gtkapplicationprivate.h
+++ b/gtk/gtkapplicationprivate.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2011 Canonical Limited
+ * Copyright © 2011, 2013 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,22 +27,16 @@
#include "gtkactionmuxer.h"
G_GNUC_INTERNAL
-gboolean gtk_application_window_publish (GtkApplicationWindow *window,
- GDBusConnection *session,
- const gchar *object_path,
- guint object_id);
-
+void gtk_application_window_set_id (GtkApplicationWindow *window,
+ guint id);
G_GNUC_INTERNAL
-void gtk_application_window_unpublish (GtkApplicationWindow *window);
-
+GActionGroup * gtk_application_window_get_action_group (GtkApplicationWindow *window);
G_GNUC_INTERNAL
-GtkAccelGroup * gtk_application_window_get_accel_group (GtkApplicationWindow *window);
-
+void gtk_application_handle_window_realize (GtkApplication *application,
+ GtkWindow *window);
G_GNUC_INTERNAL
-const gchar * gtk_application_get_app_menu_object_path (GtkApplication *application);
-G_GNUC_INTERNAL
-const gchar * gtk_application_get_menubar_object_path (GtkApplication *application);
-
+void gtk_application_handle_window_map (GtkApplication *application,
+ GtkWindow *window);
G_GNUC_INTERNAL
GtkActionMuxer * gtk_application_get_parent_muxer_for_window (GtkWindow *window);
@@ -57,5 +51,161 @@ void gtk_application_foreach_accel_keys (GtkAppl
GtkWindow *window,
GtkWindowKeysForeachFunc callback,
gpointer user_data);
+G_GNUC_INTERNAL
+GtkActionMuxer * gtk_application_get_action_muxer (GtkApplication *application);
+
+
+#define GTK_TYPE_APPLICATION_IMPL (gtk_application_impl_get_type ())
+#define GTK_APPLICATION_IMPL_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ GTK_TYPE_APPLICATION_IMPL, \
+ GtkApplicationImplClass))
+#define GTK_APPLICATION_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ GTK_TYPE_APPLICATION_IMPL, \
+ GtkApplicationImplClass))
+
+typedef struct
+{
+ GObject parent_instance;
+ GtkApplication *application;
+ GdkDisplay *display;
+} GtkApplicationImpl;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (* startup) (GtkApplicationImpl *impl,
+ gboolean register_session);
+ void (* shutdown) (GtkApplicationImpl *impl);
+
+ void (* before_emit) (GtkApplicationImpl *impl,
+ GVariant *platform_data);
+
+ void (* window_added) (GtkApplicationImpl *impl,
+ GtkWindow *window);
+ void (* window_removed) (GtkApplicationImpl *impl,
+ GtkWindow *window);
+ void (* active_window_changed) (GtkApplicationImpl *impl,
+ GtkWindow *window);
+ void (* handle_window_realize) (GtkApplicationImpl *impl,
+ GtkWindow *window);
+ void (* handle_window_map) (GtkApplicationImpl *impl,
+ GtkWindow *window);
+
+ void (* set_app_menu) (GtkApplicationImpl *impl,
+ GMenuModel *app_menu);
+ void (* set_menubar) (GtkApplicationImpl *impl,
+ GMenuModel *menubar);
+
+ guint (* inhibit) (GtkApplicationImpl *impl,
+ GtkWindow *window,
+ GtkApplicationInhibitFlags flags,
+ const gchar *reason);
+ void (* uninhibit) (GtkApplicationImpl *impl,
+ guint cookie);
+ gboolean (* is_inhibited) (GtkApplicationImpl *impl,
+ GtkApplicationInhibitFlags flags);
+
+
+} GtkApplicationImplClass;
+
+#define GTK_TYPE_APPLICATION_IMPL_DBUS (gtk_application_impl_dbus_get_type ())
+#define GTK_APPLICATION_IMPL_DBUS_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ GTK_TYPE_APPLICATION_IMPL_DBUS, \
+ GtkApplicationImplDBusClass))
+#define GTK_APPLICATION_IMPL_DBUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ GTK_TYPE_APPLICATION_IMPL_DBUS, \
+ GtkApplicationImplDBusClass))
+
+typedef struct
+{
+ GtkApplicationImpl impl;
+
+ GDBusConnection *session;
+
+ const gchar *application_id;
+ const gchar *unique_name;
+ const gchar *object_path;
+
+ gchar *app_menu_path;
+ guint app_menu_id;
+
+ gchar *menubar_path;
+ guint menubar_id;
+
+ /* Session management... */
+ gchar *app_id; /* actually prgname... */
+ GDBusProxy *sm_proxy;
+ GDBusProxy *client_proxy;
+ gchar *client_path;
+} GtkApplicationImplDBus;
+
+typedef struct
+{
+ GtkApplicationImplClass parent_class;
+
+ /* returns floating */
+ GVariant * (* get_window_system_id) (GtkApplicationImplDBus *dbus,
+ GtkWindow *window);
+} GtkApplicationImplDBusClass;
+
+G_GNUC_INTERNAL
+GType gtk_application_impl_get_type (void);
+G_GNUC_INTERNAL
+GType gtk_application_impl_dbus_get_type (void);
+G_GNUC_INTERNAL
+GType gtk_application_impl_x11_get_type (void);
+G_GNUC_INTERNAL
+GType gtk_application_impl_wayland_get_type (void);
+G_GNUC_INTERNAL
+GType gtk_application_impl_quartz_get_type (void);
+
+G_GNUC_INTERNAL
+GtkApplicationImpl * gtk_application_impl_new (GtkApplication *application,
+ GdkDisplay *display);
+G_GNUC_INTERNAL
+void gtk_application_impl_startup (GtkApplicationImpl *impl,
+ gboolean register_sesion);
+G_GNUC_INTERNAL
+void gtk_application_impl_shutdown (GtkApplicationImpl *impl);
+G_GNUC_INTERNAL
+void gtk_application_impl_before_emit (GtkApplicationImpl *impl,
+ GVariant *platform_data);
+G_GNUC_INTERNAL
+void gtk_application_impl_window_added (GtkApplicationImpl *impl,
+ GtkWindow *window);
+G_GNUC_INTERNAL
+void gtk_application_impl_window_removed (GtkApplicationImpl *impl,
+ GtkWindow *window);
+G_GNUC_INTERNAL
+void gtk_application_impl_active_window_changed (GtkApplicationImpl *impl,
+ GtkWindow *window);
+G_GNUC_INTERNAL
+void gtk_application_impl_handle_window_realize (GtkApplicationImpl *impl,
+ GtkWindow *window);
+G_GNUC_INTERNAL
+void gtk_application_impl_handle_window_map (GtkApplicationImpl *impl,
+ GtkWindow *window);
+G_GNUC_INTERNAL
+void gtk_application_impl_set_app_menu (GtkApplicationImpl *impl,
+ GMenuModel *app_menu);
+G_GNUC_INTERNAL
+void gtk_application_impl_set_menubar (GtkApplicationImpl *impl,
+ GMenuModel *menubar);
+G_GNUC_INTERNAL
+guint gtk_application_impl_inhibit (GtkApplicationImpl *impl,
+ GtkWindow *window,
+ GtkApplicationInhibitFlags flags,
+ const gchar *reason);
+G_GNUC_INTERNAL
+void gtk_application_impl_uninhibit (GtkApplicationImpl *impl,
+ guint cookie);
+G_GNUC_INTERNAL
+gboolean gtk_application_impl_is_inhibited (GtkApplicationImpl *impl,
+ GtkApplicationInhibitFlags flags);
+
+G_GNUC_INTERNAL
+gchar * gtk_application_impl_dbus_get_window_path (GtkApplicationImplDBus *dbus,
+ GtkWindow *window);
#endif /* __GTK_APPLICATION_PRIVATE_H__ */
diff --git a/gtk/gtkapplicationwindow.c b/gtk/gtkapplicationwindow.c
index 1527251613..5cbe71e03f 100644
--- a/gtk/gtkapplicationwindow.c
+++ b/gtk/gtkapplicationwindow.c
@@ -29,14 +29,6 @@
#include "gtkintl.h"
#include "gtksettings.h"
-#include <gdk/gdk.h>
-#ifdef GDK_WINDOWING_X11
-#include <gdk/x11/gdkx.h>
-#endif
-#ifdef GDK_WINDOWING_WAYLAND
-#include <gdk/wayland/gdkwayland.h>
-#endif
-
#ifdef HAVE_GIO_UNIX
#include <gio/gdesktopappinfo.h>
#endif
@@ -223,10 +215,6 @@ struct _GtkApplicationWindowPrivate
GMenu *app_menu_section;
GMenu *menubar_section;
- GDBusConnection *session;
- gchar *object_path;
- guint export_id;
-
guint id;
};
@@ -639,10 +627,8 @@ static void
gtk_application_window_real_realize (GtkWidget *widget)
{
GtkApplicationWindow *window = GTK_APPLICATION_WINDOW (widget);
- GtkApplication *application;
GtkSettings *settings;
- application = gtk_window_get_application (GTK_WINDOW (window));
settings = gtk_widget_get_settings (widget);
g_signal_connect (settings, "notify::gtk-shell-shows-app-menu",
@@ -655,35 +641,6 @@ gtk_application_window_real_realize (GtkWidget *widget)
gtk_application_window_update_shell_shows_app_menu (window, settings);
gtk_application_window_update_shell_shows_menubar (window, settings);
gtk_application_window_update_menubar (window);
-
-#ifdef GDK_WINDOWING_X11
- {
- GdkWindow *gdkwindow;
-
- gdkwindow = gtk_widget_get_window (GTK_WIDGET (window));
-
- if (GDK_IS_X11_WINDOW (gdkwindow) && window->priv->session)
- {
- gdk_x11_window_set_utf8_property (gdkwindow, "_GTK_APPLICATION_ID",
- g_application_get_application_id (G_APPLICATION (application)));
-
- gdk_x11_window_set_utf8_property (gdkwindow, "_GTK_UNIQUE_BUS_NAME",
- g_dbus_connection_get_unique_name (window->priv->session));
-
- gdk_x11_window_set_utf8_property (gdkwindow, "_GTK_APPLICATION_OBJECT_PATH",
- g_application_get_dbus_object_path (G_APPLICATION (application)));
-
- gdk_x11_window_set_utf8_property (gdkwindow, "_GTK_WINDOW_OBJECT_PATH",
- window->priv->object_path);
-
- gdk_x11_window_set_utf8_property (gdkwindow, "_GTK_APP_MENU_OBJECT_PATH",
- gtk_application_get_app_menu_object_path (application));
-
- gdk_x11_window_set_utf8_property (gdkwindow, "_GTK_MENUBAR_OBJECT_PATH",
- gtk_application_get_menubar_object_path (application));
- }
- }
-#endif
}
static void
@@ -699,46 +656,10 @@ gtk_application_window_real_unrealize (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_application_window_parent_class)->unrealize (widget);
}
-gboolean
-gtk_application_window_publish (GtkApplicationWindow *window,
- GDBusConnection *session,
- const gchar *object_path,
- guint object_id)
+GActionGroup *
+gtk_application_window_get_action_group (GtkApplicationWindow *window)
{
- g_assert (window->priv->session == NULL);
- g_assert (window->priv->export_id == 0);
- g_assert (window->priv->object_path == NULL);
- g_assert (window->priv->id == 0);
-
- window->priv->export_id = g_dbus_connection_export_action_group (session, object_path,
- G_ACTION_GROUP (window->priv->actions),
- NULL);
-
- if (window->priv->export_id == 0)
- return FALSE;
-
- window->priv->session = session;
- window->priv->object_path = g_strdup (object_path);
- window->priv->id = object_id;
-
- return TRUE;
-}
-
-void
-gtk_application_window_unpublish (GtkApplicationWindow *window)
-{
- g_assert (window->priv->session != NULL);
- g_assert (window->priv->export_id != 0);
- g_assert (window->priv->object_path != NULL);
- g_assert (window->priv->id != 0);
-
- g_dbus_connection_unexport_action_group (window->priv->session, window->priv->export_id);
- window->priv->session = NULL;
- window->priv->export_id = 0;
- window->priv->id = 0;
-
- g_free (window->priv->object_path);
- window->priv->object_path = NULL;
+ return G_ACTION_GROUP (window->priv->actions);
}
static void
@@ -751,27 +672,6 @@ gtk_application_window_real_map (GtkWidget *widget)
gtk_widget_map (window->priv->menubar);
GTK_WIDGET_CLASS (gtk_application_window_parent_class)->map (widget);
-
-#ifdef GDK_WINDOWING_WAYLAND
- {
- GdkWindow *gdkwindow;
- GtkApplication *application;
-
- application = gtk_window_get_application (GTK_WINDOW (window));
- gdkwindow = gtk_widget_get_window (widget);
-
- if (GDK_IS_WAYLAND_WINDOW (gdkwindow) && window->priv->session)
- {
- gdk_wayland_window_set_dbus_properties_libgtk_only (gdkwindow,
- g_application_get_application_id (G_APPLICATION (application)),
- gtk_application_get_app_menu_object_path (application),
- gtk_application_get_menubar_object_path (application),
- window->priv->object_path,
- g_application_get_dbus_object_path (G_APPLICATION (application)),
- g_dbus_connection_get_unique_name (window->priv->session));
- }
- }
-#endif
}
static void
@@ -994,3 +894,11 @@ gtk_application_window_get_id (GtkApplicationWindow *window)
return window->priv->id;
}
+
+void
+gtk_application_window_set_id (GtkApplicationWindow *window,
+ guint id)
+{
+ g_return_if_fail (GTK_IS_APPLICATION_WINDOW (window));
+ window->priv->id = id;
+}
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index d8ece2fe36..ecb5a8b85d 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -5451,6 +5451,9 @@ gtk_window_map (GtkWidget *widget)
gtk_window_set_focus_visible (window, gtk_window_get_focus_visible (priv->transient_parent));
else
gtk_window_set_focus_visible (window, FALSE);
+
+ if (priv->application)
+ gtk_application_handle_window_map (priv->application, window);
}
static gboolean
@@ -5855,6 +5858,9 @@ gtk_window_realize (GtkWidget *widget)
}
#endif
+ if (priv->application)
+ gtk_application_handle_window_realize (priv->application, window);
+
/* Icons */
gtk_window_realize_icon (window);