diff options
-rw-r--r-- | docs/reference/gtk/gtk3-sections.txt | 2 | ||||
-rw-r--r-- | gtk/gtk.symbols | 2 | ||||
-rw-r--r-- | gtk/gtkapplicationprivate.h | 7 | ||||
-rw-r--r-- | gtk/gtkapplicationwindow.c | 12 | ||||
-rw-r--r-- | gtk/gtkmenu.h | 1 | ||||
-rw-r--r-- | gtk/gtkmenubar.h | 1 | ||||
-rw-r--r-- | gtk/gtkmodelmenu.c | 135 | ||||
-rw-r--r-- | gtk/gtkmodelmenu.h | 9 | ||||
-rw-r--r-- | gtk/gtkmodelmenuitem.c | 18 |
9 files changed, 162 insertions, 25 deletions
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt index 3b2317e136..41e42a9e18 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -2059,6 +2059,7 @@ gtk_link_button_get_type <TITLE>GtkMenu</TITLE> GtkMenu gtk_menu_new +gtk_menu_new_from_model gtk_menu_set_screen gtk_menu_reorder_child gtk_menu_attach @@ -2103,6 +2104,7 @@ gtk_menu_get_type <TITLE>GtkMenuBar</TITLE> GtkMenuBar gtk_menu_bar_new +gtk_menu_bar_new_from_model GtkPackDirection gtk_menu_bar_set_pack_direction gtk_menu_bar_get_pack_direction diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 93a4a175b2..3f377b166d 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -1533,6 +1533,7 @@ gtk_menu_bar_get_child_pack_direction gtk_menu_bar_get_pack_direction gtk_menu_bar_get_type gtk_menu_bar_new +gtk_menu_bar_new_from_model gtk_menu_bar_set_child_pack_direction gtk_menu_bar_set_pack_direction gtk_menu_detach @@ -1569,6 +1570,7 @@ gtk_menu_item_set_use_underline gtk_menu_item_toggle_size_allocate gtk_menu_item_toggle_size_request gtk_menu_new +gtk_menu_new_from_model gtk_menu_popdown gtk_menu_popup gtk_menu_popup_for_device diff --git a/gtk/gtkapplicationprivate.h b/gtk/gtkapplicationprivate.h index 4b24a53e33..10c5016e2a 100644 --- a/gtk/gtkapplicationprivate.h +++ b/gtk/gtkapplicationprivate.h @@ -38,6 +38,13 @@ G_GNUC_INTERNAL GSimpleActionObserver * gtk_application_window_create_observer (GtkApplicationWindow *window, const gchar *action_name, GVariant *target); + +G_GNUC_INTERNAL +GActionObservable * gtk_application_window_get_observable (GtkApplicationWindow *window); + +G_GNUC_INTERNAL +GtkAccelGroup * gtk_application_window_get_accel_group (GtkApplicationWindow *window); + G_GNUC_INTERNAL const gchar * gtk_application_get_dbus_object_path (GtkApplication *application); G_GNUC_INTERNAL diff --git a/gtk/gtkapplicationwindow.c b/gtk/gtkapplicationwindow.c index fabf8ef6d2..5f8b1b375e 100644 --- a/gtk/gtkapplicationwindow.c +++ b/gtk/gtkapplicationwindow.c @@ -1012,3 +1012,15 @@ gtk_application_window_create_observer (GtkApplicationWindow *window, return g_simple_action_observer_new (window->priv->muxer, action_name, target); } + +GActionObservable * +gtk_application_window_get_observable (GtkApplicationWindow *window) +{ + return G_ACTION_OBSERVABLE (window->priv->muxer); +} + +GtkAccelGroup * +gtk_application_window_get_accel_group (GtkApplicationWindow *window) +{ + return window->priv->accels; +} diff --git a/gtk/gtkmenu.h b/gtk/gtkmenu.h index 0228236ce1..557949dfdb 100644 --- a/gtk/gtkmenu.h +++ b/gtk/gtkmenu.h @@ -117,6 +117,7 @@ struct _GtkMenuClass GType gtk_menu_get_type (void) G_GNUC_CONST; GtkWidget* gtk_menu_new (void); +GtkWidget* gtk_menu_new_from_model (GMenuModel *model); /* Display the menu onscreen */ void gtk_menu_popup (GtkMenu *menu, diff --git a/gtk/gtkmenubar.h b/gtk/gtkmenubar.h index bc1f66c49e..967b04d1b8 100644 --- a/gtk/gtkmenubar.h +++ b/gtk/gtkmenubar.h @@ -71,6 +71,7 @@ struct _GtkMenuBarClass GType gtk_menu_bar_get_type (void) G_GNUC_CONST; GtkWidget* gtk_menu_bar_new (void); +GtkWidget* gtk_menu_bar_new_from_model (GMenuModel *model); GtkPackDirection gtk_menu_bar_get_pack_direction (GtkMenuBar *menubar); void gtk_menu_bar_set_pack_direction (GtkMenuBar *menubar, diff --git a/gtk/gtkmodelmenu.c b/gtk/gtkmodelmenu.c index d91d92bf62..df08f7187d 100644 --- a/gtk/gtkmodelmenu.c +++ b/gtk/gtkmodelmenu.c @@ -29,6 +29,7 @@ #include "gtkmenubar.h" #include "gtkseparatormenuitem.h" #include "gtkmodelmenuitem.h" +#include "gtkapplicationprivate.h" typedef struct { GActionObservable *actions; @@ -65,7 +66,8 @@ gtk_model_menu_binding_free (gpointer data) binding->connected = g_slist_delete_link (binding->connected, binding->connected); } - g_object_unref (binding->actions); + if (binding->actions) + g_object_unref (binding->actions); g_object_unref (binding->model); g_slice_free (GtkModelMenuBinding, binding); @@ -224,25 +226,38 @@ gtk_model_menu_binding_items_changed (GMenuModel *model, } } -void +static void gtk_model_menu_bind (GtkMenuShell *shell, GMenuModel *model, - GActionObservable *actions, - GtkAccelGroup *accels, gboolean with_separators) { GtkModelMenuBinding *binding; binding = g_slice_new (GtkModelMenuBinding); binding->model = g_object_ref (model); - binding->actions = g_object_ref (actions); - binding->accels = accels; + binding->actions = NULL; + binding->accels = NULL; binding->shell = shell; binding->update_idle = 0; binding->connected = NULL; binding->with_separators = with_separators; g_object_set_data_full (G_OBJECT (shell), "gtk-model-menu-binding", binding, gtk_model_menu_binding_free); +} + + +static void +gtk_model_menu_populate (GtkMenuShell *shell, + GActionObservable *actions, + GtkAccelGroup *accels) +{ + GtkModelMenuBinding *binding; + + binding = (GtkModelMenuBinding*) g_object_get_data (G_OBJECT (shell), "gtk-model-menu-binding"); + + binding->actions = g_object_ref (actions); + binding->accels = accels; + gtk_model_menu_binding_populate (binding); } @@ -254,8 +269,59 @@ gtk_model_menu_create_menu (GMenuModel *model, GtkWidget *menu; menu = gtk_menu_new (); - gtk_menu_set_accel_group (GTK_MENU (menu), accels); - gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, actions, accels, TRUE); + + gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, FALSE); + gtk_model_menu_populate (GTK_MENU_SHELL (menu), actions, accels); + + return menu; +} + +static void +notify_attach (GtkMenu *menu, + GParamSpec *pspec, + gpointer data) +{ + GtkWidget *widget; + GtkWidget *toplevel; + GActionObservable *actions; + GtkAccelGroup *accels; + + widget = gtk_menu_get_attach_widget (menu); + toplevel = gtk_widget_get_toplevel (widget); + if (GTK_IS_APPLICATION_WINDOW (toplevel)) + { + actions = gtk_application_window_get_observable (GTK_APPLICATION_WINDOW (toplevel)); + accels = gtk_application_window_get_accel_group (GTK_APPLICATION_WINDOW (toplevel)); + + gtk_model_menu_populate (GTK_MENU_SHELL (menu), actions, accels); + } +} + +/** + * gtk_menu_new_from_model: + * @model: a #GMenuModel + * + * Creates a #GtkMenu and populates it with menu items and + * submenus according to @model. + * + * The created menu items are connected to actions found in the + * #GtkApplicationWindow to which the menu belongs - typically + * by means of being attached to a widget (see gtk_menu_attach_to_widget()) + * that is contained within the #GtkApplicationWindows widget hierarchy. + * + * Returns: a new #GtkMenu + * + * Since: 3.4 + */ +GtkWidget * +gtk_menu_new_from_model (GMenuModel *model) +{ + GtkWidget *menu; + + menu = gtk_menu_new (); + gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, TRUE); + g_signal_connect (menu, "notify::attach-widget", + G_CALLBACK (notify_attach), NULL); return menu; } @@ -268,8 +334,59 @@ gtk_model_menu_create_menu_bar (GMenuModel *model, GtkWidget *menubar; menubar = gtk_menu_bar_new (); - gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, actions, accels, FALSE); + + gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, FALSE); + gtk_model_menu_populate (GTK_MENU_SHELL (menubar), actions, accels); return menubar; } +static void +hierarchy_changed (GtkMenuShell *shell, + GObject *previous_toplevel, + gpointer data) +{ + GtkWidget *toplevel; + GActionObservable *actions; + GtkAccelGroup *accels; + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell)); + if (GTK_IS_APPLICATION_WINDOW (toplevel)) + { + actions = gtk_application_window_get_observable (GTK_APPLICATION_WINDOW (toplevel)); + accels = gtk_application_window_get_accel_group (GTK_APPLICATION_WINDOW (toplevel)); + + gtk_model_menu_populate (shell, actions, accels); + } +} + +/** + * gtk_menu_bar_new_from_model: + * @model: a #GMenuModel + * + * Creates a new #GtkMenuBar and populates it with menu items + * and submenus according to @model. + * + * The created menu items are connected to actions found in the + * #GtkApplicationWindow to which the menu bar belongs - typically + * by means of being contained within the #GtkApplicationWindows + * widget hierarchy. + * + * Returns: a new #GtkMenuBar + * + * Since: 3.4 + */ +GtkWidget * +gtk_menu_bar_new_from_model (GMenuModel *model) +{ + GtkWidget *menubar; + + menubar = gtk_menu_bar_new (); + + gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, FALSE); + + g_signal_connect (menubar, "hierarchy-changed", + G_CALLBACK (hierarchy_changed), NULL); + + return menubar; +} diff --git a/gtk/gtkmodelmenu.h b/gtk/gtkmodelmenu.h index 827d143692..e1f388bcb0 100644 --- a/gtk/gtkmodelmenu.h +++ b/gtk/gtkmodelmenu.h @@ -27,19 +27,10 @@ #include <gtk/gtkaccelgroup.h> #include <gio/gio.h> -G_GNUC_INTERNAL -void gtk_model_menu_bind (GtkMenuShell *shell, - GMenuModel *model, - GActionObservable *actions, - GtkAccelGroup *accels, - gboolean with_separators); - -G_GNUC_INTERNAL GtkWidget * gtk_model_menu_create_menu_bar (GMenuModel *model, GActionObservable *actions, GtkAccelGroup *accels); -G_GNUC_INTERNAL GtkWidget * gtk_model_menu_create_menu (GMenuModel *model, GActionObservable *actions, GtkAccelGroup *accels); diff --git a/gtk/gtkmodelmenuitem.c b/gtk/gtkmodelmenuitem.c index eb7b8f3596..e6dd987cac 100644 --- a/gtk/gtkmodelmenuitem.c +++ b/gtk/gtkmodelmenuitem.c @@ -235,15 +235,19 @@ gtk_model_menu_item_setup (GtkModelMenuItem *item, /* observer already causes us to hold a hard ref on the group */ item->actions = G_ACTION_GROUP (actions); - g_action_observable_register_observer (actions, item->action_name, G_ACTION_OBSERVER (item)); - - if (g_action_group_query_action (G_ACTION_GROUP (actions), item->action_name, &enabled, &type, NULL, NULL, &state)) + if (actions) { - gtk_model_menu_item_action_added (G_ACTION_OBSERVER (item), actions, item->action_name, type, enabled, state); - if (state != NULL) - g_variant_unref (state); + g_action_observable_register_observer (actions, item->action_name, G_ACTION_OBSERVER (item)); + + if (g_action_group_query_action (G_ACTION_GROUP (actions), item->action_name, &enabled, &type, NULL, NULL, &state)) + { + gtk_model_menu_item_action_added (G_ACTION_OBSERVER (item), actions, item->action_name, type, enabled, state); + if (state != NULL) + g_variant_unref (state); + } + else + gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); } - else gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); |