Using GtkPopoverMenu as a GtkMenu replacement

The original strawman had the proposal of a gtk_widget_set_context_menu() API, but as far as I remember, we couldn’t figure out a way to add it while keeping API like gtk_text_set_extra_menu().

I meant api to manually populate a popovermenu with model buttons

As far as I get the docs the only thing to make something happen when a menu item is activated, is to go through the GAction machinery. This however reminds me of the “You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.” thing since this feels unnecessarily complex to just connecting to an (imaginary) activated signal of the GMenuItem.

Any ideas on the replacements for the selected/deselected signals?

Yes, given that everything else is GAction-based—including the accelerators and generic shortcuts.

What are you trying to achieve, with those two signals?

I’m not really sold on that approach; it is a fairly big footgun in terms of UI consistency. People think they can construct menus on the fly when the item is pressed, doing arbitrarily long amount of work in a synchronous fashion, instead of keeping the menu structure around as a model and using menus as a view to represent the model.

See this video https://gitlab.gnome.org/GNOME/gtk/uploads/7e945a5a30c62a8a447ffd5b04ae2479/Peek_2020-07-11_10-06.mp4 linked in the first post. I use this signal to highlight the object in the canvas that’s currently selected in the menu.

Unfortunately, this is exactly what I need for the clarify selection menu.

You can still construct the menus on the fly—after all, that’s what we do for context menus inside GTK. What you cannot do is construct the internal widgetry.

The GtkPopoverMenu already tracks the active item, so we could add a GtkPopoverMenu::item-selected signal that tells you that the selected item changed, and give you the GMenuItem that maps to it. The GMenuItem can also be constructed with additional attributes—including an identifier for the object in your canvas, or any other ancillary data you wish to bind to a menu item.

So how’d you implement such a menu with dynamically generated content with the GMenu api? Create one action and encode the item selected in the target?

That’d be really helpful.

Yes, that’s how I would do it.

I’ll open an issue about it. ETA: https://gitlab.gnome.org/GNOME/gtk/-/issues/2925

Have you tried submenu-action for dynamically populating your submenu ? whats missing in it ?

Acceptable, but still feels like the toolkit is working against me, as I somehow have to pass my callback data through a GVarient. An activated signal on the GMenuItem would be so much easier, especially since actions don’t really have any benefits in this particular application.

Do you have a link to the docs? I don’t quite see how submenus would help.

https://wiki.gnome.org/Projects/GLib/GApplication/GMenuModel

submenu-action
Type: s

Defined on submenu items, this attribute names an action used to signal when the menu is shown or not. The named action is in the same namespace as is normal for action attributes and the usual action-namespace rules apply.

The named action should have a boolean state. When the submenu is shown, the front-end will change the boolean state of the action to true. When the menu is hidden again, it will set it to false. The application signals when the menu is ready to be shown by changing the state to true.

This provides a means by which applications that sync the contents of their menus with some external source can turn off the syncing while the menu is closed (a menu listing wifi hotspots, for example).

[…]

Clearly this requires a different way of thinking we’ll all take a while to get used to, but it’s not too hard to imagine objects on your canvas have some kinda unique id you can pass as an action target

Yes, it’s different, but as an application developer, the whole new menu API causes significant friction without any clear benefit if not already using GActions.

GAction is used for a variety of things in GTK3 already—popovers, menus, application actions—and it is used even more in GTK4, with the introduction of key shortcuts based on actions. It allowed us to make the whole API more consistent, as well as providing a level of introspection on our menus, buttons, and popovers that can be used to generate UI, like the list of shortcuts; or navigation and discovery UIs, like the old Plotinus extension module. Plus, it allows us to move menus out of process on platforms such as macOS, or implement jump lists on Windows 10.

Those are just the immediate benefits of making menus declarative and hiding the widgetry; of course, it’s a change, and thus it has a certain amount of friction. It does have benefits, though, both immediate and down the line.

2 Likes

I do get the benefits for the application you mentioned, but I’m still not quite sure if it’s worth the friction caused in slightly exotic uses of menus.

While we’re at it, there’s another use of GtkMenu in Horizon EDA that might be problematic to port to Gtk4:

The thing on the very right is a menu that opens when right-clicking or dragging to left on an action button that provides more than one action. Then menu items consist of a GtkImage of the right size (to match the buttons) and two labels (one for the action, one for the keybinding). Any ideas how to implement this with Gtk4?

I would use a box of buttons that open a GtkPopover, and populate the popovers with lists of widgets. GMenuItems can also have icons, but in this case I think this maps more to a tool bar than to menus.

I’ve thought about this as well and I see several issues in making it behave like a menu:

  • Selection needs to follow the cursor. As far as I can tell only treeviews support this and treeviews don’t seem to be the right solution for this problem.
  • Need to support activating an item when releasing the mouse cursor. With the current GtkMenu-based implementation, it’s possible to press the mouse button on the button drag to the desired menu item and release the mouse button for activation
  • The popover needs to close when releasing the the mouse button outside of the menu.

Much of this work could be avoided if there was some sort of API to manually pack widgets into menus. Is there a technical reason for omitting this from Gtk4?

I don’t understand what this means.

You can use GtkPopover:autohide.

Well, for one we can’t move a widget out of process, so we can’t really do that. Since the API is the same, we would not be able to distinguish the case.

From an API perspective, adding widgets is a generic code path; when setting a menu model, we are going to add widgets internally, so we can’t distinguish between a widget that was added by you and one added by a model, unless we make the code more brittle. Then it becomes a case of erroring out with a critical warning if you decide to add a widget to a menu that was populate by a model.

In practice, I think you’re kind of overstating your case. There’s nothing that inherently requires that you use menus and/or menu semantics for your UI outside of a main menu bar. We have widgets like overlays to put complex widgets on top of the content area; and popovers, when you need menu-like behaviour.

In some, niche cases, it may require changing how your code is structured, or changing your UI; it can be problematic or it can be a chance to rethink some of the user experience.

You also don’t need to port to GTK4 right away: GTK3 isn’t going anywhere. Maybe in a couple of years we’re going to have more convenience API that will make your use case easier to port to.

In menus, the item the cursor is over is displayed inverted (dark/blue background, light text). Listboxes only display items in this style if it was selected by clicking.

Reading the docs, this only appears to apply to clicks, not to letting go of the mouse button.

Well, since I’m not going to simultaneously maintain a GTK3 and GTK4 version of my app, I’ll have to wait until Gtk 4 is available in all major distros, especially the more slow-moving ones. Rather than complaining when Gtk4 has reached maturity, I prefer getting the discussion going as early as possible.

If that’s an option, popovers should be able to faithfully emulate the behavior of GtkMenu such as activating an item when letting go of the mouse button.

GtkListBox is good example that manually adding widgets and setting models can coexist. Just make it clear that widgets shouldn’t be touched if a model is set.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.