From c0071a06765e411b244831a040feb4d946e996b8 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 13 Sep 2019 17:25:02 -0400 Subject: [PATCH 1/6] text util: Remove an unused function _gtk_text_util_append_special_char_menuitems was not used. --- gtk/gtktextutil.c | 105 ---------------------------------------------- gtk/gtktextutil.h | 7 ---- 2 files changed, 112 deletions(-) diff --git a/gtk/gtktextutil.c b/gtk/gtktextutil.c index 2c3c43d8bc..200f87285c 100644 --- a/gtk/gtktextutil.c +++ b/gtk/gtktextutil.c @@ -29,7 +29,6 @@ #include "gtktextbuffer.h" #include "gtktextlayoutprivate.h" -#include "gtkmenuitem.h" #include "gtkintl.h" #define DRAG_ICON_MAX_WIDTH 250 @@ -37,110 +36,6 @@ #define DRAG_ICON_MAX_LINES 7 #define ELLIPSIS_CHARACTER "\xe2\x80\xa6" -typedef struct _GtkUnicodeMenuEntry GtkUnicodeMenuEntry; -typedef struct _GtkTextUtilCallbackInfo GtkTextUtilCallbackInfo; - -struct _GtkUnicodeMenuEntry { - const char *label; - gunichar ch; -}; - -struct _GtkTextUtilCallbackInfo -{ - GtkTextUtilCharChosenFunc func; - gpointer data; -}; - -static const GtkUnicodeMenuEntry bidi_menu_entries[] = { - { N_("LRM _Left-to-right mark"), 0x200E }, - { N_("RLM _Right-to-left mark"), 0x200F }, - { N_("LRE Left-to-right _embedding"), 0x202A }, - { N_("RLE Right-to-left e_mbedding"), 0x202B }, - { N_("LRO Left-to-right _override"), 0x202D }, - { N_("RLO Right-to-left o_verride"), 0x202E }, - { N_("PDF _Pop directional formatting"), 0x202C }, - { N_("ZWS _Zero width space"), 0x200B }, - { N_("ZWJ Zero width _joiner"), 0x200D }, - { N_("ZWNJ Zero width _non-joiner"), 0x200C } -}; - -static GtkTextUtilCallbackInfo * -callback_info_new (GtkTextUtilCharChosenFunc func, - gpointer data) -{ - GtkTextUtilCallbackInfo *info; - - info = g_slice_new (GtkTextUtilCallbackInfo); - - info->func = func; - info->data = data; - - return info; -} - -static void -callback_info_free (GtkTextUtilCallbackInfo *info) -{ - g_slice_free (GtkTextUtilCallbackInfo, info); -} - -static void -activate_cb (GtkWidget *menu_item, - gpointer data) -{ - GtkUnicodeMenuEntry *entry; - GtkTextUtilCallbackInfo *info = data; - char buf[7]; - - entry = g_object_get_data (G_OBJECT (menu_item), "gtk-unicode-menu-entry"); - - buf[g_unichar_to_utf8 (entry->ch, buf)] = '\0'; - - (* info->func) (buf, info->data); -} - -/* - * _gtk_text_util_append_special_char_menuitems - * @menushell: a #GtkMenuShell - * @callback: call this when an item is chosen - * @data: data for callback - * - * Add menuitems for various bidi control characters to a menu; - * the menuitems, when selected, will call the given function - * with the chosen character. - * - * This function is private/internal in GTK 2.0, the functionality may - * become public sometime, but it probably needs more thought first. - * e.g. maybe there should be a way to just get the list of items, - * instead of requiring the menu items to be created. - */ -void -_gtk_text_util_append_special_char_menuitems (GtkMenuShell *menushell, - GtkTextUtilCharChosenFunc func, - gpointer data) -{ - int i; - - for (i = 0; i < G_N_ELEMENTS (bidi_menu_entries); i++) - { - GtkWidget *menuitem; - GtkTextUtilCallbackInfo *info; - - info = callback_info_new (func, data); - - menuitem = gtk_menu_item_new_with_mnemonic (_(bidi_menu_entries[i].label)); - g_object_set_data (G_OBJECT (menuitem), I_("gtk-unicode-menu-entry"), - (gpointer)&bidi_menu_entries[i]); - - g_signal_connect_data (menuitem, "activate", - G_CALLBACK (activate_cb), - info, (GClosureNotify) callback_info_free, 0); - - gtk_widget_show (menuitem); - gtk_menu_shell_append (menushell, menuitem); - } -} - static void append_n_lines (GString *str, const gchar *text, GSList *lines, gint n_lines) { diff --git a/gtk/gtktextutil.h b/gtk/gtktextutil.h index 450ed464a1..4ad534ce7b 100644 --- a/gtk/gtktextutil.h +++ b/gtk/gtktextutil.h @@ -31,13 +31,6 @@ G_BEGIN_DECLS * GtkTextView and GtkEntry */ -typedef void (* GtkTextUtilCharChosenFunc) (const char *text, - gpointer data); - -void _gtk_text_util_append_special_char_menuitems (GtkMenuShell *menushell, - GtkTextUtilCharChosenFunc func, - gpointer data); - GdkPaintable * gtk_text_util_create_drag_icon (GtkWidget *widget, gchar *text, gssize len); From 222e05c2d269255d08b99e43c76644b58f59e1f8 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 13 Sep 2019 17:24:37 -0400 Subject: [PATCH 2/6] Remove unused includes Don't include gtkmenu.h in places where it isn't used anymore. --- gtk/gtkappchooserwidget.h | 1 - gtk/gtkentry.c | 2 -- gtk/gtkentry.h | 1 - gtk/gtkimmulticontext.c | 2 -- gtk/gtkimmulticontext.h | 1 - gtk/gtkmenutoolbutton.h | 1 - gtk/gtktext.c | 2 -- gtk/gtktextview.c | 2 -- gtk/gtktextview.h | 1 - 9 files changed, 13 deletions(-) diff --git a/gtk/gtkappchooserwidget.h b/gtk/gtkappchooserwidget.h index defef6ef7e..c71919e494 100644 --- a/gtk/gtkappchooserwidget.h +++ b/gtk/gtkappchooserwidget.h @@ -30,7 +30,6 @@ #endif #include -#include #include G_BEGIN_DECLS diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 1c1fbee79c..a2ebe7110b 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -51,8 +51,6 @@ #include "gtklabel.h" #include "gtkmain.h" #include "gtkmarshalers.h" -#include "gtkmenu.h" -#include "gtkmenuitem.h" #include "gtkpango.h" #include "gtkpopover.h" #include "gtkprivate.h" diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h index b71c4d3ac6..80ebd94bfa 100644 --- a/gtk/gtkentry.h +++ b/gtk/gtkentry.h @@ -36,7 +36,6 @@ #include #include -#include #include #include #include diff --git a/gtk/gtkimmulticontext.c b/gtk/gtkimmulticontext.c index 7412bba956..0ab67eddf2 100644 --- a/gtk/gtkimmulticontext.c +++ b/gtk/gtkimmulticontext.c @@ -26,8 +26,6 @@ #include "gtklabel.h" #include "gtkmain.h" #include "gtkprivate.h" -#include "gtkradiomenuitem.h" -#include "gtkseparatormenuitem.h" #include "gtksettings.h" diff --git a/gtk/gtkimmulticontext.h b/gtk/gtkimmulticontext.h index bee93f9aae..53e72d5aeb 100644 --- a/gtk/gtkimmulticontext.h +++ b/gtk/gtkimmulticontext.h @@ -23,7 +23,6 @@ #endif #include -#include G_BEGIN_DECLS diff --git a/gtk/gtkmenutoolbutton.h b/gtk/gtkmenutoolbutton.h index 03304dbbe1..6b88761ca2 100644 --- a/gtk/gtkmenutoolbutton.h +++ b/gtk/gtkmenutoolbutton.h @@ -24,7 +24,6 @@ #error "Only can be included directly." #endif -#include #include G_BEGIN_DECLS diff --git a/gtk/gtktext.c b/gtk/gtktext.c index 5ac7637a98..ffe683fed7 100644 --- a/gtk/gtktext.c +++ b/gtk/gtktext.c @@ -49,8 +49,6 @@ #include "gtkmagnifierprivate.h" #include "gtkmain.h" #include "gtkmarshalers.h" -#include "gtkmenu.h" -#include "gtkmenuitem.h" #include "gtkpango.h" #include "gtkpopovermenu.h" #include "gtkprivate.h" diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index dbf89dfa84..7811fd79af 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -36,8 +36,6 @@ #include "gtkintl.h" #include "gtkmain.h" #include "gtkmarshalers.h" -#include "gtkmenu.h" -#include "gtkmenuitem.h" #include "gtkrenderbackgroundprivate.h" #include "gtkseparatormenuitem.h" #include "gtksettings.h" diff --git a/gtk/gtktextview.h b/gtk/gtktextview.h index 9bb9b89eb3..bf666f7b81 100644 --- a/gtk/gtktextview.h +++ b/gtk/gtktextview.h @@ -32,7 +32,6 @@ #include #include #include -#include G_BEGIN_DECLS From 5a93449b89e12f643a93dd131539e73c1e8dd0d7 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 13 Sep 2019 19:06:26 -0400 Subject: [PATCH 3/6] window: Make fallback menu a popover We want to phase out menus. --- gtk/gtkwindow.c | 103 +++++++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 45 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index a907d8e3b3..c93b733f61 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -60,6 +60,9 @@ #include "gtkmenushellprivate.h" #include "gtkpointerfocusprivate.h" #include "gtkpopoverprivate.h" +#include "gtkpopovermenu.h" +#include "gtkmodelbutton.h" +#include "gtkseparator.h" #include "gtkprivate.h" #include "gtkroot.h" #include "gtknative.h" @@ -6569,12 +6572,12 @@ _gtk_window_unset_focus_and_default (GtkWindow *window, } static void -popup_menu_detach (GtkWidget *widget, - GtkMenu *menu) +popup_menu_closed (GtkPopover *popover, + GtkWindow *widget) { GtkWindowPrivate *priv = gtk_window_get_instance_private (GTK_WINDOW (widget)); - priv->popup_menu = NULL; + g_clear_pointer (&priv->popup_menu, gtk_widget_unparent); } static GdkSurfaceState @@ -6670,6 +6673,7 @@ ontop_window_clicked (GtkMenuItem *menuitem, GtkWindow *window = (GtkWindow *)user_data; GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + gtk_popover_popdown (GTK_POPOVER (priv->popup_menu)); gtk_window_set_keep_above (window, !priv->above_initially); } @@ -6690,6 +6694,7 @@ gtk_window_do_popup_fallback (GtkWindow *window, GtkWidget *menuitem; GdkSurfaceState state; gboolean maximized, iconified; + GtkWidget *box; if (priv->popup_menu) gtk_widget_destroy (priv->popup_menu); @@ -6699,16 +6704,14 @@ gtk_window_do_popup_fallback (GtkWindow *window, iconified = (state & GDK_SURFACE_STATE_ICONIFIED) == GDK_SURFACE_STATE_ICONIFIED; maximized = priv->maximized && !iconified; - priv->popup_menu = gtk_menu_new (); - gtk_style_context_add_class (gtk_widget_get_style_context (priv->popup_menu), - GTK_STYLE_CLASS_CONTEXT_MENU); + priv->popup_menu = gtk_popover_menu_new (priv->title_box); - gtk_menu_attach_to_widget (GTK_MENU (priv->popup_menu), - GTK_WIDGET (window), - popup_menu_detach); + box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_popover_menu_add_submenu (GTK_POPOVER_MENU (priv->popup_menu), box, "main"); + + menuitem = gtk_model_button_new (); + g_object_set (menuitem, "text", _("Restore"), NULL); - menuitem = gtk_menu_item_new_with_label (_("Restore")); - gtk_widget_show (menuitem); /* "Restore" means "Unmaximize" or "Unminimize" * (yes, some WMs allow window menu to be shown for minimized windows). * Not restorable: @@ -6721,70 +6724,80 @@ gtk_window_do_popup_fallback (GtkWindow *window, (!iconified && !priv->resizable) || priv->type_hint != GDK_SURFACE_TYPE_HINT_NORMAL) gtk_widget_set_sensitive (menuitem, FALSE); - g_signal_connect (G_OBJECT (menuitem), "activate", + g_signal_connect (G_OBJECT (menuitem), "clicked", G_CALLBACK (restore_window_clicked), window); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); + gtk_container_add (GTK_CONTAINER (box), menuitem); + + menuitem = gtk_model_button_new (); + g_object_set (menuitem, "text", _("Move"), NULL); - menuitem = gtk_menu_item_new_with_label (_("Move")); - gtk_widget_show (menuitem); if (maximized || iconified) gtk_widget_set_sensitive (menuitem, FALSE); - g_signal_connect (G_OBJECT (menuitem), "activate", + g_signal_connect (G_OBJECT (menuitem), "clicked", G_CALLBACK (move_window_clicked), window); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); + gtk_container_add (GTK_CONTAINER (box), menuitem); + + menuitem = gtk_model_button_new (); + g_object_set (menuitem, "text", _("Resize"), NULL); - menuitem = gtk_menu_item_new_with_label (_("Resize")); - gtk_widget_show (menuitem); if (!priv->resizable || maximized || iconified) gtk_widget_set_sensitive (menuitem, FALSE); - g_signal_connect (G_OBJECT (menuitem), "activate", + g_signal_connect (G_OBJECT (menuitem), "clicked", G_CALLBACK (resize_window_clicked), window); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); + gtk_container_add (GTK_CONTAINER (box), menuitem); + + menuitem = gtk_model_button_new (); + g_object_set (menuitem, "text", _("Minimize"), NULL); - menuitem = gtk_menu_item_new_with_label (_("Minimize")); - gtk_widget_show (menuitem); if (iconified || priv->type_hint != GDK_SURFACE_TYPE_HINT_NORMAL) gtk_widget_set_sensitive (menuitem, FALSE); - g_signal_connect (G_OBJECT (menuitem), "activate", + g_signal_connect (G_OBJECT (menuitem), "clicked", G_CALLBACK (minimize_window_clicked), window); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); + gtk_container_add (GTK_CONTAINER (box), menuitem); + + menuitem = gtk_model_button_new (); + g_object_set (menuitem, "text", _("Maximize"), NULL); - menuitem = gtk_menu_item_new_with_label (_("Maximize")); - gtk_widget_show (menuitem); if (maximized || !priv->resizable || priv->type_hint != GDK_SURFACE_TYPE_HINT_NORMAL) gtk_widget_set_sensitive (menuitem, FALSE); - g_signal_connect (G_OBJECT (menuitem), "activate", + g_signal_connect (G_OBJECT (menuitem), "clicked", G_CALLBACK (maximize_window_clicked), window); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); + gtk_container_add (GTK_CONTAINER (box), menuitem); - menuitem = gtk_separator_menu_item_new (); - gtk_widget_show (menuitem); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); + menuitem = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_container_add (GTK_CONTAINER (box), menuitem); + + menuitem = gtk_model_button_new (); + g_object_set (menuitem, + "text", _("Always on Top"), + "role", GTK_BUTTON_ROLE_CHECK, + "active", priv->above_initially, + NULL); - menuitem = gtk_check_menu_item_new_with_label (_("Always on Top")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), priv->above_initially); if (maximized) gtk_widget_set_sensitive (menuitem, FALSE); - gtk_widget_show (menuitem); - g_signal_connect (G_OBJECT (menuitem), "activate", + g_signal_connect (G_OBJECT (menuitem), "clicked", G_CALLBACK (ontop_window_clicked), window); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); + gtk_container_add (GTK_CONTAINER (box), menuitem); - menuitem = gtk_separator_menu_item_new (); - gtk_widget_show (menuitem); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); + menuitem = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_container_add (GTK_CONTAINER (box), menuitem); + + menuitem = gtk_model_button_new (); + g_object_set (menuitem, "text", _("Close"), NULL); - menuitem = gtk_menu_item_new_with_label (_("Close")); - gtk_widget_show (menuitem); if (!priv->deletable) gtk_widget_set_sensitive (menuitem, FALSE); - g_signal_connect (G_OBJECT (menuitem), "activate", + g_signal_connect (G_OBJECT (menuitem), "clicked", G_CALLBACK (close_window_clicked), window); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem); - gtk_menu_popup_at_pointer (GTK_MENU (priv->popup_menu), (GdkEvent *) event); + gtk_container_add (GTK_CONTAINER (box), menuitem); + + g_signal_connect (priv->popup_menu, "closed", + G_CALLBACK (popup_menu_closed), window); + gtk_popover_popup (GTK_POPOVER (priv->popup_menu)); } static void From 03e30431a8af9a947a0c4ccab545f24da16bfe17 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 14 Sep 2019 17:14:55 -0400 Subject: [PATCH 4/6] menutoolbutton: Add support for popovers Just like the underlying menu button, support popovers too. --- gtk/gtkmenutoolbutton.c | 54 ++++++++++++++++++++++++++++++++++++++++- gtk/gtkmenutoolbutton.h | 5 ++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/gtk/gtkmenutoolbutton.c b/gtk/gtkmenutoolbutton.c index cfcb1127cf..19aba366ce 100644 --- a/gtk/gtkmenutoolbutton.c +++ b/gtk/gtkmenutoolbutton.c @@ -26,6 +26,7 @@ #include "gtkmenubuttonprivate.h" #include "gtkbox.h" #include "gtkmenu.h" +#include "gtkpopover.h" #include "gtkmain.h" #include "gtksizerequest.h" #include "gtkbuildable.h" @@ -103,7 +104,8 @@ enum enum { PROP_0, - PROP_MENU + PROP_MENU, + PROP_POPOVER }; static gint signals[LAST_SIGNAL]; @@ -210,6 +212,10 @@ gtk_menu_tool_button_set_property (GObject *object, gtk_menu_tool_button_set_menu (button, g_value_get_object (value)); break; + case PROP_POPOVER: + gtk_menu_tool_button_set_popover (button, g_value_get_object (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -230,6 +236,10 @@ gtk_menu_tool_button_get_property (GObject *object, g_value_set_object (value, gtk_menu_button_get_popup (GTK_MENU_BUTTON (button->priv->arrow_button))); break; + case PROP_POPOVER: + g_value_set_object (value, gtk_menu_button_get_popover (GTK_MENU_BUTTON (button->priv->arrow_button))); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -279,6 +289,13 @@ gtk_menu_tool_button_class_init (GtkMenuToolButtonClass *klass) P_("The dropdown menu"), GTK_TYPE_MENU, GTK_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_POPOVER, + g_param_spec_object ("popover", + P_("Popover"), + P_("The dropdown popover"), + GTK_TYPE_POPOVER, + GTK_PARAM_READWRITE)); } static void @@ -324,6 +341,9 @@ gtk_menu_tool_button_buildable_add_child (GtkBuildable *buildable, if (type && strcmp (type, "menu") == 0) gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (buildable), GTK_WIDGET (child)); + else if (type && strcmp (type, "popover") == 0) + gtk_menu_tool_button_set_popover (GTK_MENU_TOOL_BUTTON (buildable), + GTK_WIDGET (child)); else parent_buildable_iface->add_child (buildable, builder, child, type); } @@ -419,6 +439,38 @@ gtk_menu_tool_button_get_menu (GtkMenuToolButton *button) return GTK_WIDGET (ret); } +void +gtk_menu_tool_button_set_popover (GtkMenuToolButton *button, + GtkWidget *popover) +{ + GtkMenuToolButtonPrivate *priv; + + g_return_if_fail (GTK_IS_MENU_TOOL_BUTTON (button)); + g_return_if_fail (GTK_IS_POPOVER (popover) || popover == NULL); + + priv = button->priv; + + gtk_menu_button_set_popover (GTK_MENU_BUTTON (priv->arrow_button), popover); + gtk_menu_button_set_create_popup_func (GTK_MENU_BUTTON (priv->arrow_button), + _show_menu_emit, NULL, NULL); + + g_object_notify (G_OBJECT (button), "popover"); +} + +GtkWidget * +gtk_menu_tool_button_get_popover (GtkMenuToolButton *button) +{ + GtkPopover *ret; + + g_return_val_if_fail (GTK_IS_MENU_TOOL_BUTTON (button), NULL); + + ret = gtk_menu_button_get_popover (GTK_MENU_BUTTON (button->priv->arrow_button)); + if (!ret) + return NULL; + + return GTK_WIDGET (ret); +} + /** * gtk_menu_tool_button_set_arrow_tooltip_text: * @button: a #GtkMenuToolButton diff --git a/gtk/gtkmenutoolbutton.h b/gtk/gtkmenutoolbutton.h index 6b88761ca2..3bfdc0ada1 100644 --- a/gtk/gtkmenutoolbutton.h +++ b/gtk/gtkmenutoolbutton.h @@ -46,6 +46,11 @@ void gtk_menu_tool_button_set_menu (GtkMenuToolButton *button, GDK_AVAILABLE_IN_ALL GtkWidget *gtk_menu_tool_button_get_menu (GtkMenuToolButton *button); GDK_AVAILABLE_IN_ALL +void gtk_menu_tool_button_set_popover (GtkMenuToolButton *button, + GtkWidget *popover); +GDK_AVAILABLE_IN_ALL +GtkWidget *gtk_menu_tool_button_get_popover (GtkMenuToolButton *button); +GDK_AVAILABLE_IN_ALL void gtk_menu_tool_button_set_arrow_tooltip_text (GtkMenuToolButton *button, const gchar *text); GDK_AVAILABLE_IN_ALL From 1b271f3335cb2b1a53424086fabf97237f9a43c5 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 14 Sep 2019 15:03:22 -0400 Subject: [PATCH 5/6] notebook: Use a popover for the tab menu We are phasing out menus. --- gtk/gtknotebook.c | 61 ++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index fab59e7ab9..2082a1038a 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -43,8 +43,7 @@ #include "gtklabel.h" #include "gtkmain.h" #include "gtkmarshalers.h" -#include "gtkmenu.h" -#include "gtkmenuitem.h" +#include "gtkpopovermenu.h" #include "gtkorientable.h" #include "gtksizerequest.h" #include "gtkstylecontextprivate.h" @@ -237,6 +236,7 @@ struct _GtkNotebookPrivate GtkWidget *action_widget[N_ACTION_WIDGETS]; GtkWidget *dnd_child; GtkWidget *menu; + GtkWidget *menu_box; GtkWidget *stack_widget; GtkWidget *header_widget; @@ -807,8 +807,6 @@ static void gtk_notebook_menu_item_recreate (GtkNotebook *notebook, GList *list); static void gtk_notebook_menu_label_unparent (GtkWidget *widget, gpointer data); -static void gtk_notebook_menu_detacher (GtkWidget *widget, - GtkMenu *menu); static void gtk_notebook_update_tab_pos (GtkNotebook *notebook); @@ -2501,7 +2499,14 @@ gtk_notebook_gesture_pressed (GtkGestureClick *gesture, if (in_tabs (notebook, x, y) && priv->menu && gdk_event_triggers_context_menu (event)) { - gtk_menu_popup_at_pointer (GTK_MENU (priv->menu), event); + GdkRectangle rect; + + rect.x = x; + rect.y = y; + rect.width = 1; + rect.height = 1; + gtk_popover_set_pointing_to (GTK_POPOVER (priv->menu), &rect); + gtk_popover_popup (GTK_POPOVER (priv->menu)); return; } @@ -5592,14 +5597,14 @@ gtk_notebook_menu_switch_page (GtkWidget *widget, { GtkNotebookPrivate *priv; GtkNotebook *notebook; - GtkWidget *parent; GList *children; guint page_num; - parent = gtk_widget_get_parent (widget); - notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent))); + notebook = GTK_NOTEBOOK (gtk_widget_get_ancestor (widget, GTK_TYPE_NOTEBOOK)); priv = notebook->priv; + gtk_popover_popdown (GTK_POPOVER (priv->menu)); + if (priv->cur_page == page) return; @@ -5623,7 +5628,6 @@ gtk_notebook_menu_switch_page (GtkWidget *widget, * gtk_notebook_menu_item_create * gtk_notebook_menu_item_recreate * gtk_notebook_menu_label_unparent - * gtk_notebook_menu_detacher */ static void gtk_notebook_menu_item_create (GtkNotebook *notebook, @@ -5643,15 +5647,14 @@ gtk_notebook_menu_item_create (GtkNotebook *notebook, gtk_widget_set_valign (page->menu_label, GTK_ALIGN_CENTER); } - gtk_widget_show (page->menu_label); - menu_item = gtk_menu_item_new (); + menu_item = gtk_button_new (); + gtk_button_set_relief (GTK_BUTTON (menu_item), GTK_RELIEF_NONE); gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label); - gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item, - g_list_index (priv->children, page)); - g_signal_connect (menu_item, "activate", + gtk_container_add (GTK_CONTAINER (priv->menu_box), menu_item); + g_signal_connect (menu_item, "clicked", G_CALLBACK (gtk_notebook_menu_switch_page), page); - if (gtk_widget_get_visible (page->child)) - gtk_widget_show (menu_item); + if (!gtk_widget_get_visible (page->child)) + gtk_widget_hide (menu_item); } static void @@ -5675,18 +5678,6 @@ gtk_notebook_menu_label_unparent (GtkWidget *widget, _gtk_bin_set_child (GTK_BIN (widget), NULL); } -static void -gtk_notebook_menu_detacher (GtkWidget *widget, - GtkMenu *menu) -{ - GtkNotebook *notebook = GTK_NOTEBOOK (widget); - GtkNotebookPrivate *priv = notebook->priv; - - g_return_if_fail (priv->menu == (GtkWidget*) menu); - - priv->menu = NULL; -} - /* Public GtkNotebook Page Insert/Remove Methods : * * gtk_notebook_append_page @@ -6531,9 +6522,10 @@ gtk_notebook_popup_enable (GtkNotebook *notebook) if (priv->menu) return; - priv->menu = gtk_menu_new (); - gtk_style_context_add_class (gtk_widget_get_style_context (priv->menu), - GTK_STYLE_CLASS_CONTEXT_MENU); + priv->menu = gtk_popover_menu_new (priv->tabs_widget); + + priv->menu_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_popover_menu_add_submenu (GTK_POPOVER_MENU (priv->menu), priv->menu_box, "main"); for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE); list; @@ -6541,9 +6533,6 @@ gtk_notebook_popup_enable (GtkNotebook *notebook) gtk_notebook_menu_item_create (notebook, list->data); gtk_notebook_update_labels (notebook); - gtk_menu_attach_to_widget (GTK_MENU (priv->menu), - GTK_WIDGET (notebook), - gtk_notebook_menu_detacher); g_object_notify_by_pspec (G_OBJECT (notebook), properties[PROP_ENABLE_POPUP]); } @@ -6566,9 +6555,11 @@ gtk_notebook_popup_disable (GtkNotebook *notebook) if (!priv->menu) return; - gtk_container_foreach (GTK_CONTAINER (priv->menu), + gtk_container_foreach (GTK_CONTAINER (priv->menu_box), (GtkCallback) gtk_notebook_menu_label_unparent, NULL); gtk_widget_destroy (priv->menu); + priv->menu = NULL; + priv->menu_box = NULL; g_object_notify_by_pspec (G_OBJECT (notebook), properties[PROP_ENABLE_POPUP]); } From b14b0efefe840b8ca1ce3077e1170e757bc12340 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 14 Sep 2019 16:55:06 -0400 Subject: [PATCH 6/6] toolbar: Use a popover for overflow We are phasing out menus. This is not quite complete, toolitems still create menuitems, which we translate on the fly. --- gtk/gtktoolbar.c | 160 +++++++++++++++++++++-------------------------- 1 file changed, 72 insertions(+), 88 deletions(-) diff --git a/gtk/gtktoolbar.c b/gtk/gtktoolbar.c index 667d80961c..6d6d88e1ed 100644 --- a/gtk/gtktoolbar.c +++ b/gtk/gtktoolbar.c @@ -45,10 +45,14 @@ #include "gtklabel.h" #include "gtkmain.h" #include "gtkmarshalers.h" -#include "gtkmenu.h" #include "gtkorientable.h" #include "gtkorientableprivate.h" #include "gtkprivate.h" +#include "gtkpopovermenu.h" +#include "gtkmodelbutton.h" +#include "gtkseparator.h" +#include "gtkradiomenuitem.h" +#include "gtkcheckmenuitem.h" #include "gtkradiobutton.h" #include "gtkradiotoolbutton.h" #include "gtkseparatormenuitem.h" @@ -132,7 +136,8 @@ struct _GtkToolbarClass struct _GtkToolbarPrivate { - GtkMenu *menu; + GtkWidget *menu; + GtkWidget *menu_box; GtkSettings *settings; GtkToolbarStyle style; @@ -429,6 +434,7 @@ gtk_toolbar_class_init (GtkToolbarClass *klass) NULL, G_TYPE_NONE, 1, GTK_TYPE_TOOLBAR_STYLE); + /** * GtkToolbar::popup-context-menu: * @toolbar: the #GtkToolbar which emitted the signal @@ -1108,77 +1114,97 @@ menu_deactivated (GtkWidget *menu, } static void -menu_detached (GtkWidget *widget, - GtkMenu *menu) +button_clicked (GtkWidget *button, + GtkWidget *item) { - GtkToolbar *toolbar = GTK_TOOLBAR (widget); - GtkToolbarPrivate *priv = toolbar->priv; - - priv->menu = NULL; + gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER))); + if (GTK_IS_TOOL_BUTTON (item)) + g_signal_emit_by_name (_gtk_tool_button_get_button (GTK_TOOL_BUTTON (item)), "clicked"); } static void rebuild_menu (GtkToolbar *toolbar) { GtkToolbarPrivate *priv = toolbar->priv; - GList *list, *children; + GList *list; if (!priv->menu) { - priv->menu = GTK_MENU (gtk_menu_new ()); - gtk_menu_attach_to_widget (priv->menu, - GTK_WIDGET (toolbar), - menu_detached); + priv->menu = gtk_popover_menu_new (priv->arrow_button); + priv->menu_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_popover_menu_add_submenu (GTK_POPOVER_MENU (priv->menu), priv->menu_box, "main"); - g_signal_connect (priv->menu, "deactivate", + g_signal_connect (priv->menu, "closed", G_CALLBACK (menu_deactivated), toolbar); } - gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL); - + gtk_container_foreach (GTK_CONTAINER (priv->menu_box), remove_item, NULL); + for (list = priv->content; list != NULL; list = list->next) { ToolbarContent *content = list->data; - + if (toolbar_content_get_state (content) == OVERFLOWN && !toolbar_content_is_placeholder (content)) { GtkWidget *menu_item = toolbar_content_retrieve_menu_item (content); - + if (menu_item) { + GtkWidget *button, *widget; + const char *text; + GtkButtonRole role; + gboolean active; + g_assert (GTK_IS_MENU_ITEM (menu_item)); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item); + text = gtk_menu_item_get_label (GTK_MENU_ITEM (menu_item)); + if (text == NULL) + { + GtkWidget *box, *child; + box = gtk_bin_get_child (GTK_BIN (menu_item)); + for (child = gtk_widget_get_first_child (box); + child; + child = gtk_widget_get_next_sibling (child)) + { + if (GTK_IS_LABEL (child)) + { + text = gtk_label_get_label (GTK_LABEL (child)); + break; + } + } + } + + if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item)) + { + gtk_container_add (GTK_CONTAINER (priv->menu_box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)); + continue; + } + else if (GTK_IS_RADIO_MENU_ITEM (menu_item)) + role = GTK_BUTTON_ROLE_RADIO; + else if (GTK_IS_CHECK_MENU_ITEM (menu_item)) + role = GTK_BUTTON_ROLE_CHECK; + else + role = GTK_BUTTON_ROLE_NORMAL; + + if (GTK_IS_CHECK_MENU_ITEM (menu_item)) + active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_item)); + else + active = FALSE; + + button = gtk_model_button_new (); + g_object_set (button, + "text", text, + "role", role, + "active", active, + NULL); + widget = toolbar_content_get_widget (content); + g_signal_connect (button, "clicked", + G_CALLBACK (button_clicked), widget); + gtk_container_add (GTK_CONTAINER (priv->menu_box), button); } } } - /* Remove leading and trailing separator items */ - children = gtk_container_get_children (GTK_CONTAINER (priv->menu)); - - list = children; - while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data)) - { - GtkWidget *child = list->data; - - gtk_container_remove (GTK_CONTAINER (priv->menu), child); - list = list->next; - } - g_list_free (children); - - /* Regenerate the list of children so we don't try to remove items twice */ - children = gtk_container_get_children (GTK_CONTAINER (priv->menu)); - - list = g_list_last (children); - while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data)) - { - GtkWidget *child = list->data; - - gtk_container_remove (GTK_CONTAINER (priv->menu), child); - list = list->prev; - } - g_list_free (children); - priv->need_rebuild = FALSE; } @@ -2124,52 +2150,10 @@ show_menu (GtkToolbar *toolbar, GdkEventButton *event) { GtkToolbarPrivate *priv = toolbar->priv; - GtkRequisition minimum_size; rebuild_menu (toolbar); - gtk_widget_show (GTK_WIDGET (priv->menu)); - - switch (priv->orientation) - { - case GTK_ORIENTATION_HORIZONTAL: - gtk_widget_get_preferred_size (priv->arrow_button, &minimum_size, NULL); - - g_object_set (priv->menu, - "anchor-hints", (GDK_ANCHOR_FLIP_Y | - GDK_ANCHOR_SLIDE | - GDK_ANCHOR_RESIZE), - "menu-type-hint", GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU, - "rect-anchor-dx", -minimum_size.width, - NULL); - - gtk_menu_popup_at_widget (priv->menu, - priv->arrow_button, - GDK_GRAVITY_SOUTH_EAST, - GDK_GRAVITY_NORTH_WEST, - (GdkEvent *) event); - - break; - - case GTK_ORIENTATION_VERTICAL: - g_object_set (priv->menu, - "anchor-hints", (GDK_ANCHOR_FLIP_X | - GDK_ANCHOR_SLIDE | - GDK_ANCHOR_RESIZE), - NULL); - - gtk_menu_popup_at_widget (priv->menu, - priv->arrow_button, - GDK_GRAVITY_NORTH_EAST, - GDK_GRAVITY_NORTH_WEST, - (GdkEvent *) event); - - break; - - default: - g_assert_not_reached (); - break; - } + gtk_popover_popup (GTK_POPOVER (priv->menu)); } static void