diff --git a/examples/bp/bloatpad.c b/examples/bp/bloatpad.c index b29b639241..d429318fc8 100644 --- a/examples/bp/bloatpad.c +++ b/examples/bp/bloatpad.c @@ -220,6 +220,7 @@ new_window (GApplication *app, gtk_window_set_default_size ((GtkWindow*)window, 640, 480); g_action_map_add_action_entries (G_ACTION_MAP (window), win_entries, G_N_ELEMENTS (win_entries), window); gtk_window_set_title (GTK_WINDOW (window), "Bloatpad"); + gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (window), TRUE); grid = gtk_grid_new (); gtk_window_set_child (GTK_WINDOW (window), grid); @@ -536,7 +537,7 @@ bloat_pad_startup (GApplication *application) menu = gtk_application_get_menu_by_id (GTK_APPLICATION (application), "icon-menu"); - file = g_file_new_for_uri ("resource:///org/gtk/libgtk/icons/16x16/actions/gtk-select-color.png"); + file = g_file_new_for_uri ("resource:///org/gtk/libgtk/icons/16x16/actions/insert-image.png"); icon = g_file_icon_new (file); item = g_menu_item_new ("File Icon", NULL); g_menu_item_set_icon (item, icon); @@ -552,7 +553,7 @@ bloat_pad_startup (GApplication *application) g_object_unref (item); g_object_unref (icon); - bytes = g_resources_lookup_data ("/org/gtk/libgtk/icons/16x16/actions/gtk-select-font.png", 0, NULL); + bytes = g_resources_lookup_data ("/org/gtk/libgtk/icons/16x16/actions/media-eject.png", 0, NULL); icon = g_bytes_icon_new (bytes); item = g_menu_item_new ("Bytes Icon", NULL); g_menu_item_set_icon (item, icon); @@ -561,19 +562,19 @@ bloat_pad_startup (GApplication *application) g_object_unref (icon); g_bytes_unref (bytes); - icon = G_ICON (gdk_pixbuf_new_from_resource ("/org/gtk/libgtk/icons/16x16/actions/gtk-preferences.png", NULL)); + icon = G_ICON (gdk_pixbuf_new_from_resource ("/org/gtk/libgtk/icons/16x16/actions/folder-new.png", NULL)); item = g_menu_item_new ("Pixbuf", NULL); g_menu_item_set_icon (item, icon); g_menu_append_item (menu, item); g_object_unref (item); g_object_unref (icon); - file = g_file_new_for_uri ("resource:///org/gtk/libgtk/icons/16x16/actions/gtk-page-setup.png"); + file = g_file_new_for_uri ("resource:///org/gtk/libgtk/icons/16x16/actions/bookmark-new.png"); icon = g_file_icon_new (file); emblem = g_emblem_new (icon); g_object_unref (icon); g_object_unref (file); - file = g_file_new_for_uri ("resource:///org/gtk/libgtk/icons/16x16/actions/gtk-orientation-reverse-portrait.png"); + file = g_file_new_for_uri ("resource:///org/gtk/libgtk/icons/16x16/actions/dialog-warning.png"); icon2 = g_file_icon_new (file); icon = g_emblemed_icon_new (icon2, emblem); item = g_menu_item_new ("Emblemed Icon", NULL); diff --git a/gtk/gtkmenusectionbox.c b/gtk/gtkmenusectionbox.c index 6210119c35..8dd8fe18f3 100644 --- a/gtk/gtkmenusectionbox.c +++ b/gtk/gtkmenusectionbox.c @@ -292,6 +292,22 @@ open_submenu (GtkWidget *button, gtk_widget_grab_focus (focus); } +static void +submenu_shown (GtkPopoverMenu *popover, + GtkMenuTrackerItem *item) +{ + if (gtk_menu_tracker_item_get_should_request_show (item)) + gtk_menu_tracker_item_request_submenu_shown (item, TRUE); +} + +static void +submenu_hidden (GtkPopoverMenu *popover, + GtkMenuTrackerItem *item) +{ + if (gtk_menu_tracker_item_get_should_request_show (item)) + gtk_menu_tracker_item_request_submenu_shown (item, FALSE); +} + static void gtk_menu_section_box_insert_func (GtkMenuTrackerItem *item, int position, @@ -324,6 +340,9 @@ gtk_menu_section_box_insert_func (GtkMenuTrackerItem *item, g_object_bind_property (item, "label", widget, "text", G_BINDING_SYNC_CREATE); g_object_bind_property (item, "icon", widget, "icon", G_BINDING_SYNC_CREATE); g_object_bind_property (item, "sensitive", widget, "sensitive", G_BINDING_SYNC_CREATE); + + g_signal_connect (submenu, "show", G_CALLBACK (submenu_shown), item); + g_signal_connect (submenu, "hide", G_CALLBACK (submenu_hidden), item); } else { diff --git a/gtk/gtkmenutrackeritem.c b/gtk/gtkmenutrackeritem.c index 1f621ed3d1..134831fda6 100644 --- a/gtk/gtkmenutrackeritem.c +++ b/gtk/gtkmenutrackeritem.c @@ -809,13 +809,57 @@ gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self) g_variant_unref (action_target); } -typedef struct -{ +typedef struct { + GObject parent; + GtkMenuTrackerItem *item; char *submenu_action; gboolean first_time; } GtkMenuTrackerOpener; +typedef struct { + GObjectClass parent_class; +} GtkMenuTrackerOpenerClass; + +static void gtk_menu_tracker_opener_observer_iface_init (GtkActionObserverInterface *iface); + +GType gtk_menu_tracker_opener_get_type (void) G_GNUC_CONST; + +G_DEFINE_TYPE_WITH_CODE (GtkMenuTrackerOpener, gtk_menu_tracker_opener, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVER, gtk_menu_tracker_opener_observer_iface_init)) + +static void +gtk_menu_tracker_opener_init (GtkMenuTrackerOpener *self) +{ +} + +static void +gtk_menu_tracker_opener_finalize (GObject *object) +{ + GtkMenuTrackerOpener *opener = (GtkMenuTrackerOpener *)object; + + gtk_action_observable_unregister_observer (opener->item->observable, + opener->submenu_action, + (GtkActionObserver *)opener); + + if (GTK_IS_ACTION_MUXER (opener->item->observable)) + gtk_action_muxer_change_action_state (GTK_ACTION_MUXER (opener->item->observable), + opener->submenu_action, + g_variant_new_boolean (FALSE)); + + gtk_menu_tracker_item_set_submenu_shown (opener->item, FALSE); + + g_free (opener->submenu_action); + + G_OBJECT_CLASS (gtk_menu_tracker_opener_parent_class)->finalize (object); +} + +static void +gtk_menu_tracker_opener_class_init (GtkMenuTrackerOpenerClass *class) +{ + G_OBJECT_CLASS (class)->finalize = gtk_menu_tracker_opener_finalize; +} + static void gtk_menu_tracker_opener_update (GtkMenuTrackerOpener *opener) { @@ -862,57 +906,49 @@ gtk_menu_tracker_opener_update (GtkMenuTrackerOpener *opener) } static void -gtk_menu_tracker_opener_added (GActionGroup *group, - const char *action_name, - gpointer user_data) +gtk_menu_tracker_opener_added (GtkActionObserver *observer, + GtkActionObservable *observable, + const char *action_name, + const GVariantType *parameter_type, + gboolean enabled, + GVariant *state) { - GtkMenuTrackerOpener *opener = user_data; - - if (g_str_equal (action_name, opener->submenu_action)) - gtk_menu_tracker_opener_update (opener); + gtk_menu_tracker_opener_update ((GtkMenuTrackerOpener *)observer); } static void -gtk_menu_tracker_opener_removed (GActionGroup *action_group, - const char *action_name, - gpointer user_data) +gtk_menu_tracker_opener_removed (GtkActionObserver *observer, + GtkActionObservable *observable, + const char *action_name) { - GtkMenuTrackerOpener *opener = user_data; - - if (g_str_equal (action_name, opener->submenu_action)) - gtk_menu_tracker_opener_update (opener); + gtk_menu_tracker_opener_update ((GtkMenuTrackerOpener *)observer); } static void -gtk_menu_tracker_opener_changed (GActionGroup *action_group, - const char *action_name, - GVariant *new_state, - gpointer user_data) +gtk_menu_tracker_opener_enabled_changed (GtkActionObserver *observer, + GtkActionObservable *observable, + const char *action_name, + gboolean enabled) { - GtkMenuTrackerOpener *opener = user_data; - - if (g_str_equal (action_name, opener->submenu_action)) - gtk_menu_tracker_opener_update (opener); + gtk_menu_tracker_opener_update ((GtkMenuTrackerOpener *)observer); } static void -gtk_menu_tracker_opener_free (gpointer data) +gtk_menu_tracker_opener_state_changed (GtkActionObserver *observer, + GtkActionObservable *observable, + const char *action_name, + GVariant *state) { - GtkMenuTrackerOpener *opener = data; + gtk_menu_tracker_opener_update ((GtkMenuTrackerOpener *)observer); +} - g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_added, opener); - g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_removed, opener); - g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_changed, opener); - - g_action_group_change_action_state (G_ACTION_GROUP (opener->item->observable), - opener->submenu_action, - g_variant_new_boolean (FALSE)); - - gtk_menu_tracker_item_set_submenu_shown (opener->item, FALSE); - - g_free (opener->submenu_action); - - g_slice_free (GtkMenuTrackerOpener, opener); +static void +gtk_menu_tracker_opener_observer_iface_init (GtkActionObserverInterface *iface) +{ + iface->action_added = gtk_menu_tracker_opener_added; + iface->action_removed = gtk_menu_tracker_opener_removed; + iface->action_enabled_changed = gtk_menu_tracker_opener_enabled_changed; + iface->action_state_changed = gtk_menu_tracker_opener_state_changed; } static GtkMenuTrackerOpener * @@ -921,7 +957,8 @@ gtk_menu_tracker_opener_new (GtkMenuTrackerItem *item, { GtkMenuTrackerOpener *opener; - opener = g_slice_new (GtkMenuTrackerOpener); + opener = g_object_new (gtk_menu_tracker_opener_get_type (), NULL); + opener->first_time = TRUE; opener->item = item; @@ -930,9 +967,9 @@ gtk_menu_tracker_opener_new (GtkMenuTrackerItem *item, else opener->submenu_action = g_strdup (submenu_action); - g_signal_connect (item->observable, "action-added", G_CALLBACK (gtk_menu_tracker_opener_added), opener); - g_signal_connect (item->observable, "action-removed", G_CALLBACK (gtk_menu_tracker_opener_removed), opener); - g_signal_connect (item->observable, "action-state-changed", G_CALLBACK (gtk_menu_tracker_opener_changed), opener); + gtk_action_observable_register_observer (item->observable, + opener->submenu_action, + (GtkActionObserver *)opener); gtk_menu_tracker_opener_update (opener); @@ -962,7 +999,7 @@ gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self, if (shown) g_object_set_data_full (G_OBJECT (self), "submenu-opener", gtk_menu_tracker_opener_new (self, submenu_action), - gtk_menu_tracker_opener_free); + g_object_unref); else g_object_set_data (G_OBJECT (self), "submenu-opener", NULL); } diff --git a/gtk/gtkpopovermenubar.c b/gtk/gtkpopovermenubar.c index fe91374a6d..b2a3635e5a 100644 --- a/gtk/gtkpopovermenubar.c +++ b/gtk/gtkpopovermenubar.c @@ -59,6 +59,7 @@ #include "gtkpopovermenubarprivate.h" #include "gtkpopovermenu.h" +#include "gtkbinlayout.h" #include "gtkboxlayout.h" #include "gtklabel.h" #include "gtkmenubutton.h" @@ -104,6 +105,7 @@ struct _GtkPopoverMenuBarItem GtkWidget *label; GtkPopover *popover; + GtkMenuTrackerItem *tracker; }; typedef struct _GtkPopoverMenuBarItemClass GtkPopoverMenuBarItemClass; @@ -116,6 +118,18 @@ struct _GtkPopoverMenuBarItemClass G_DEFINE_TYPE (GtkPopoverMenuBarItem, gtk_popover_menu_bar_item, GTK_TYPE_WIDGET) +static void +open_submenu (GtkPopoverMenuBarItem *item) +{ + gtk_popover_popup (item->popover); +} + +static void +close_submenu (GtkPopoverMenuBarItem *item) +{ + gtk_popover_popdown (item->popover); +} + static void set_active_item (GtkPopoverMenuBar *bar, GtkPopoverMenuBarItem *item, @@ -132,12 +146,7 @@ set_active_item (GtkPopoverMenuBar *bar, was_popup = FALSE; if (was_popup && changed) - { - gtk_accessible_update_state (GTK_ACCESSIBLE (bar->active_item), - GTK_ACCESSIBLE_STATE_EXPANDED, FALSE, - -1); - gtk_popover_popdown (bar->active_item->popover); - } + close_submenu (bar->active_item); if (changed) { @@ -153,12 +162,7 @@ set_active_item (GtkPopoverMenuBar *bar, if (bar->active_item) { if (popup || (was_popup && changed)) - { - gtk_popover_popup (bar->active_item->popover); - gtk_accessible_update_state (GTK_ACCESSIBLE (bar->active_item), - GTK_ACCESSIBLE_STATE_EXPANDED, FALSE, - -1); - } + open_submenu (bar->active_item); else if (changed) gtk_widget_grab_focus (GTK_WIDGET (bar->active_item)); } @@ -279,6 +283,7 @@ gtk_popover_menu_bar_item_dispose (GObject *object) { GtkPopoverMenuBarItem *item = GTK_POPOVER_MENU_BAR_ITEM (object); + g_clear_object (&item->tracker); g_clear_pointer (&item->label, gtk_widget_unparent); g_clear_pointer ((GtkWidget **)&item->popover, gtk_widget_unparent); @@ -291,37 +296,6 @@ gtk_popover_menu_bar_item_finalize (GObject *object) G_OBJECT_CLASS (gtk_popover_menu_bar_item_parent_class)->finalize (object); } -static void -gtk_popover_menu_bar_item_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline) -{ - GtkPopoverMenuBarItem *item = GTK_POPOVER_MENU_BAR_ITEM (widget); - - gtk_widget_measure (item->label, orientation, for_size, - minimum, natural, - minimum_baseline, natural_baseline); -} - -static void -gtk_popover_menu_bar_item_size_allocate (GtkWidget *widget, - int width, - int height, - int baseline) -{ - GtkPopoverMenuBarItem *item = GTK_POPOVER_MENU_BAR_ITEM (widget); - - gtk_widget_size_allocate (item->label, - &(GtkAllocation) { 0, 0, width, height }, - baseline); - - gtk_popover_present (GTK_POPOVER (item->popover)); -} - static void gtk_popover_menu_bar_item_activate (GtkPopoverMenuBarItem *item) { @@ -359,8 +333,6 @@ gtk_popover_menu_bar_item_class_init (GtkPopoverMenuBarItemClass *klass) object_class->finalize = gtk_popover_menu_bar_item_finalize; widget_class->root = gtk_popover_menu_bar_item_root; - widget_class->measure = gtk_popover_menu_bar_item_measure; - widget_class->size_allocate = gtk_popover_menu_bar_item_size_allocate; klass->activate = gtk_popover_menu_bar_item_activate; @@ -376,6 +348,7 @@ gtk_popover_menu_bar_item_class_init (GtkPopoverMenuBarItemClass *klass) gtk_widget_class_set_css_name (widget_class, I_("item")); gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_MENU_ITEM); gtk_widget_class_set_activate_signal (widget_class, activate_signal); + gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); } enum { @@ -420,6 +393,30 @@ popover_unmap (GtkPopover *popover, set_active_item (bar, NULL, FALSE); } +static void +popover_shown (GtkPopover *popover, + GtkPopoverMenuBarItem *item) +{ + gtk_accessible_update_state (GTK_ACCESSIBLE (item), + GTK_ACCESSIBLE_STATE_EXPANDED, TRUE, + -1); + + if (gtk_menu_tracker_item_get_should_request_show (item->tracker)) + gtk_menu_tracker_item_request_submenu_shown (item->tracker, TRUE); +} + +static void +popover_hidden (GtkPopover *popover, + GtkPopoverMenuBarItem *item) +{ + gtk_accessible_update_state (GTK_ACCESSIBLE (item), + GTK_ACCESSIBLE_STATE_EXPANDED, FALSE, + -1); + + if (gtk_menu_tracker_item_get_should_request_show (item->tracker)) + gtk_menu_tracker_item_request_submenu_shown (item->tracker, FALSE); +} + static void tracker_insert (GtkMenuTrackerItem *item, int position, @@ -449,8 +446,11 @@ tracker_insert (GtkMenuTrackerItem *item, gtk_widget_set_halign (GTK_WIDGET (popover), GTK_ALIGN_START); g_signal_connect (popover, "unmap", G_CALLBACK (popover_unmap), bar); + g_signal_connect (popover, "show", G_CALLBACK (popover_shown), widget); + g_signal_connect (popover, "hide", G_CALLBACK (popover_hidden), widget); widget->popover = popover; + widget->tracker = g_object_ref (item); sibling = NULL; for (child = gtk_widget_get_first_child (GTK_WIDGET (bar)), i = 1;