+#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;
+}
+
+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);
+}
+
+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
+