From 60317cbf1ad16eb9228d9d901275a65db7f2cde5 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Mon, 16 Jan 2012 14:46:04 -0500 Subject: [PATCH] move menus over from GLib App menu and menubar are now properties of GtkApplication and their bus location is exported using X window properties. https://bugzilla.gnome.org/show_bug.cgi?id=668118 --- gtk/gtkapplication.c | 232 ++++++++++++++++++++++++++++-------- gtk/gtkapplication.h | 4 +- gtk/gtkapplicationprivate.h | 6 + gtk/gtkapplicationwindow.c | 21 ++-- 4 files changed, 205 insertions(+), 58 deletions(-) diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c index 95a5e8e170..b4c29a8a3b 100644 --- a/gtk/gtkapplication.c +++ b/gtk/gtkapplication.c @@ -134,7 +134,9 @@ static guint gtk_application_signals[LAST_SIGNAL]; enum { PROP_ZERO, - PROP_REGISTER_SESSION + PROP_REGISTER_SESSION, + PROP_APP_MENU, + PROP_MENUBAR }; G_DEFINE_TYPE (GtkApplication, gtk_application, G_TYPE_APPLICATION) @@ -147,7 +149,17 @@ struct _GtkApplicationPrivate #ifdef GDK_WINDOWING_X11 GDBusConnection *session_bus; - gchar *window_prefix; + const gchar *application_id; + gchar *object_path; + + GMenuModel *app_menu; + gchar *app_menu_path; + guint app_menu_id; + + GMenuModel *menubar; + gchar *menubar_path; + guint menubar_id; + guint next_id; GDBusProxy *sm_proxy; @@ -167,6 +179,59 @@ struct _GtkApplicationPrivate }; #ifdef GDK_WINDOWING_X11 +static void +gtk_application_x11_publish_menu (GtkApplication *application, + const gchar *type, + GMenuModel *model, + guint *id, + gchar **path) +{ + gint i; + + /* 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) @@ -190,7 +255,7 @@ gtk_application_window_added_x11 (GtkApplication *application, guint window_id; window_id = application->priv->next_id++; - window_path = g_strdup_printf ("%s%d", application->priv->window_prefix, window_id); + window_path = g_strdup_printf ("%s/window/%d", application->priv->object_path, window_id); success = gtk_application_window_publish (app_window, application->priv->session_bus, window_path); g_free (window_path); } @@ -210,11 +275,11 @@ gtk_application_window_removed_x11 (GtkApplication *application, } static gchar * -window_prefix_from_appid (const gchar *appid) +object_path_from_appid (const gchar *appid) { gchar *appid_path, *iter; - appid_path = g_strconcat ("/", appid, "/windows/", NULL); + appid_path = g_strconcat ("/", appid, NULL); for (iter = appid_path; *iter; iter++) { if (*iter == '.') @@ -236,7 +301,7 @@ gtk_application_startup_x11 (GtkApplication *application) application_id = g_application_get_application_id (G_APPLICATION (application)); application->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); - application->priv->window_prefix = window_prefix_from_appid (application_id); + application->priv->object_path = object_path_from_appid (application_id); gtk_application_startup_session_dbus (GTK_APPLICATION (application)); } @@ -244,8 +309,8 @@ gtk_application_startup_x11 (GtkApplication *application) static void gtk_application_shutdown_x11 (GtkApplication *application) { - g_free (application->priv->window_prefix); - application->priv->window_prefix = NULL; + g_free (application->priv->object_path); + application->priv->object_path = NULL; g_clear_object (&application->priv->session_bus); g_clear_object (&application->priv->sm_proxy); @@ -253,6 +318,25 @@ gtk_application_shutdown_x11 (GtkApplication *application) g_free (application->priv->app_id); g_free (application->priv->client_path); } + +const gchar * +gtk_application_get_dbus_object_path (GtkApplication *application) +{ + return application->priv->object_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 @@ -534,26 +618,6 @@ extract_accels_from_menu (GMenuModel *model, } } -static void -gtk_application_notify (GObject *object, - GParamSpec *pspec) -{ - if (strcmp (pspec->name, "app-menu") == 0 || - strcmp (pspec->name, "menubar") == 0) - { - GMenuModel *model; - g_object_get (object, pspec->name, &model, NULL); - if (model) - { - extract_accels_from_menu (model, GTK_APPLICATION (object)); - g_object_unref (model); - } - } - - if (G_OBJECT_CLASS (gtk_application_parent_class)->notify) - G_OBJECT_CLASS (gtk_application_parent_class)->notify (object, pspec); -} - static void gtk_application_get_property (GObject *object, guint prop_id, @@ -568,6 +632,14 @@ gtk_application_get_property (GObject *object, g_value_set_boolean (value, application->priv->register_session); break; + case PROP_APP_MENU: + g_value_set_object (value, gtk_application_get_app_menu (application)); + break; + + case PROP_MENUBAR: + g_value_set_object (value, gtk_application_get_menubar (application)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -588,6 +660,14 @@ gtk_application_set_property (GObject *object, application->priv->register_session = g_value_get_boolean (value); break; + case PROP_APP_MENU: + gtk_application_set_app_menu (application, g_value_get_object (value)); + break; + + case PROP_MENUBAR: + gtk_application_set_menubar (application, g_value_get_object (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -601,6 +681,18 @@ gtk_application_quit (GtkApplication *app) g_application_set_inactivity_timeout (G_APPLICATION (app), 0); } +static void +gtk_application_finalize (GObject *object) +{ + GtkApplication *application = GTK_APPLICATION (object); + + g_clear_object (&application->priv->app_menu); + g_clear_object (&application->priv->menubar); + + G_OBJECT_CLASS (gtk_application_parent_class) + ->finalize (object); +} + static void gtk_application_class_init (GtkApplicationClass *class) { @@ -609,7 +701,7 @@ gtk_application_class_init (GtkApplicationClass *class) object_class->get_property = gtk_application_get_property; object_class->set_property = gtk_application_set_property; - object_class->notify = gtk_application_notify; + object_class->finalize = gtk_application_finalize; application_class->add_platform_data = gtk_application_add_platform_data; application_class->before_emit = gtk_application_before_emit; @@ -698,6 +790,20 @@ gtk_application_class_init (GtkApplicationClass *class) P_("Register session"), P_("Register with the session manager"), FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_APP_MENU, + g_param_spec_object ("app-menu", + P_("Application menu"), + P_("The GMenuModel for the application menu"), + G_TYPE_MENU_MODEL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_MENUBAR, + g_param_spec_object ("menubar", + P_("Menubar"), + P_("The GMenuModel for the menubar"), + G_TYPE_MENU_MODEL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } /** @@ -918,7 +1024,7 @@ gtk_application_remove_accelerator (GtkApplication *application, /** * gtk_application_set_app_menu: * @application: a #GtkApplication - * @model: (allow-none): a #GMenuModel, or %NULL + * @app_menu: (allow-none): a #GMenuModel, or %NULL * * Sets or unsets the application menu for @application. * @@ -935,9 +1041,28 @@ gtk_application_remove_accelerator (GtkApplication *application, */ void gtk_application_set_app_menu (GtkApplication *application, - GMenuModel *model) + GMenuModel *app_menu) { - g_object_set (application, "app-menu", model, NULL); + g_return_if_fail (GTK_IS_APPLICATION (application)); + + if (app_menu != application->priv->app_menu) + { + if (application->priv->app_menu != NULL) + g_object_unref (application->priv->app_menu); + + application->priv->app_menu = app_menu; + + if (application->priv->app_menu != NULL) + g_object_ref (application->priv->app_menu); + + extract_accels_from_menu (app_menu, application); + +#ifdef GDK_WINDOWING_X11 + gtk_application_set_app_menu_x11 (application, app_menu); +#endif + + g_object_notify (G_OBJECT (application), "app-menu"); + } } /** @@ -954,20 +1079,15 @@ gtk_application_set_app_menu (GtkApplication *application, GMenuModel * gtk_application_get_app_menu (GtkApplication *application) { - GMenuModel *app_menu = NULL; + g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL); - g_object_get (application, "app-menu", &app_menu, NULL); - - if (app_menu) - g_object_unref (app_menu); - - return app_menu; + return application->priv->app_menu; } /** * gtk_application_set_menubar: * @application: a #GtkApplication - * @model: (allow-none): a #GMenuModel, or %NULL + * @menubar: (allow-none): a #GMenuModel, or %NULL * * Sets or unsets the menubar for windows of @application. * @@ -985,9 +1105,28 @@ gtk_application_get_app_menu (GtkApplication *application) */ void gtk_application_set_menubar (GtkApplication *application, - GMenuModel *model) + GMenuModel *menubar) { - g_object_set (application, "menubar", model, NULL); + g_return_if_fail (GTK_IS_APPLICATION (application)); + + if (menubar != application->priv->menubar) + { + if (application->priv->menubar != NULL) + g_object_unref (application->priv->menubar); + + application->priv->menubar = menubar; + + if (application->priv->menubar != NULL) + g_object_ref (application->priv->menubar); + + extract_accels_from_menu (menubar, application); + +#ifdef GDK_WINDOWING_X11 + gtk_application_set_menubar_x11 (application, menubar); +#endif + + g_object_notify (G_OBJECT (application), "menubar"); + } } /** @@ -1004,14 +1143,9 @@ gtk_application_set_menubar (GtkApplication *application, GMenuModel * gtk_application_get_menubar (GtkApplication *application) { - GMenuModel *menubar = NULL; + g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL); - g_object_get (application, "menubar", &menubar, NULL); - - if (menubar) - g_object_unref (menubar); - - return menubar; + return application->priv->menubar; } #if defined(GDK_WINDOWING_X11) diff --git a/gtk/gtkapplication.h b/gtk/gtkapplication.h index 878a9a1f0c..b9a9ad7898 100644 --- a/gtk/gtkapplication.h +++ b/gtk/gtkapplication.h @@ -79,11 +79,11 @@ GList * gtk_application_get_windows (GtkApplication *application); GMenuModel * gtk_application_get_app_menu (GtkApplication *application); void gtk_application_set_app_menu (GtkApplication *application, - GMenuModel *model); + GMenuModel *app_menu); GMenuModel * gtk_application_get_menubar (GtkApplication *application); void gtk_application_set_menubar (GtkApplication *application, - GMenuModel *model); + GMenuModel *menubar); void gtk_application_add_accelerator (GtkApplication *application, const gchar *accelerator, diff --git a/gtk/gtkapplicationprivate.h b/gtk/gtkapplicationprivate.h index b2b9b9c77b..4b24a53e33 100644 --- a/gtk/gtkapplicationprivate.h +++ b/gtk/gtkapplicationprivate.h @@ -38,5 +38,11 @@ G_GNUC_INTERNAL GSimpleActionObserver * gtk_application_window_create_observer (GtkApplicationWindow *window, const gchar *action_name, GVariant *target); +G_GNUC_INTERNAL +const gchar * gtk_application_get_dbus_object_path (GtkApplication *application); +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); #endif /* __GTK_APPLICATION_PRIVATE_H__ */ diff --git a/gtk/gtkapplicationwindow.c b/gtk/gtkapplicationwindow.c index 555db917c5..9a7aa35ab8 100644 --- a/gtk/gtkapplicationwindow.c +++ b/gtk/gtkapplicationwindow.c @@ -700,16 +700,23 @@ gtk_application_window_real_realize (GtkWidget *widget) if (GDK_IS_X11_WINDOW (gdkwindow)) { - const gchar *unique_id; - const gchar *app_id; + 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, "_DBUS_OBJECT_PATH", window->priv->object_path); + gdk_x11_window_set_utf8_property (gdkwindow, "_GTK_UNIQUE_BUS_NAME", + g_dbus_connection_get_unique_name (window->priv->session)); - unique_id = g_dbus_connection_get_unique_name (window->priv->session); - gdk_x11_window_set_utf8_property (gdkwindow, "_DBUS_UNIQUE_NAME", unique_id); + gdk_x11_window_set_utf8_property (gdkwindow, "_GTK_APPLICATION_OBJECT_PATH", + gtk_application_get_dbus_object_path (application)); - app_id = g_application_get_application_id (G_APPLICATION (application)); - gdk_x11_window_set_utf8_property (gdkwindow, "_DBUS_APPLICATION_ID", app_id); + 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