This is a strawman proposal for deprecating the public GtkWidget-based menu API in order to remove it for GTK+ 4.0.

The goal of this strawman is to remove the GtkWidget-based menu API from the public GTK+ API, and allow creating menus through the GMenu XML serialization format, and through the GMenu and GAction API.

Deprecating Menu widgets

GTK+ has three widget classes that manage menus:

  • GtkMenu — the "top level" menu

  • GtkMenuShell — a container for menu items

  • GtkMenuItem — a menu item

  • GtkMenuBar - a menu bar

All of these are real GtkWidget classes, and handle things like menu hierarchy; input events; positioning; visibility. They allow creating menus by building them piece by piece using the GtkWidget and GtkContainer API, as well as creating new implementations inside application code, and overriding the default behaviour in client-side code.

Over the years we also added API that would take descriptions of the menus and build the actual widgets behind the scenes:

  • GtkUIManager and GtkAction (both deprecated)

  • GtkBuilder

  • GMenu and GAction

We also pushed for application developers to use the declarative API (and its serialization formats) instead of building menus by hand.

Sadly, all declarative API have different coverage and features:

  • GtkUIManager

    • GtkUIManager allows merging and unmerging of menu hierarchies, which is used by applications to modify their menus in response to contextual UI changes, e.g. plugins

    • GtkUIManager allows describing toolbars as well as menus

    • GtkAction exposes the feature of creating real widgets

  • GtkBuilder

    • GtkBuilder allows loading the GtkUIManager and GMenu serialization formats

    • GtkBuilder is mostly meant as a GObject serialization format, which means it's actually easier for generators to build GtkMenu and friends directly

    • GtkBuilder does not allow merging and unmerging of menu hiearchies

  • GMenu

    • GMenu is a generic menu serialization format that has no real UI connection

    • GMenu is suited for describing menus that can be sent over IPC to other processes, like the compositor

    • GMenu's API allows merging and unmerging items, but it's overall fairly clunky and requires a lot of state to be kept around in the application

Prior Art

Most platforms provide an API similar to GMenu: a declarative, descriptive API that defines the menu hierarchy and the attributes of each element, as well as an action to perform on activation.

macOS

Windows

Additional issues

  • Input handling inside menus and menu shells is complicated by the interdependent nature of the widgets; exposing the event handling to applications increases this complexity
  • We only have direct API to pop up contextual menus using gtk_menu_popup(), which led to API contortions to handle associating a menu with a widget or an area, as well as negotiating the menu position on the screen — see also bug 315645 for context menus and long press gestures

  • The existing application API nudges the application developer towards using GMenu but still allows (and, in some cases, forces) building menus out of widgets

Further application requirements

  • Add description attributes to menu items
    • Tooltips, or other ways to show helpful hints inside the application UI (e.g. in the statusbar)
  • Serialization and deserialization of menu and toolbar hierarchies
    • Custom menus persistent across sessions
  • Key navigation and accelerators
  • Scope creep
    • Attributes for different menu item types
      • Sliders, spin buttons, switches
    • Presentation attributes
      • Linked buttons
      • Grid menus
  • Still have a way to encode the information just once for creating both menu items and toolbar items.
    • And a library should be able to provide that information (with translations) to applications for common actions.
  • Have a GtkRecentChooser and be able to show the full file paths inside the application UI (e.g. in the statusbar). It's currently possible with GtkRecentChooserMenu.

  • Create menu items programmatically, so that a library can provide a generic menu item suitable for all applications. Example: calling g_get_application_name() to add the app name in the menu item description. Example in Tepl.

Review of current GTK api

We have the following GMenu- and GAction-based apis:

  • gtk_application_set_app_menu

  • gtk_application_set_menubar

  • gtk_application_get_menu_by_id

  • gtk_application_set_accels_for_action

  • gtk_widget_insert_action_group

  • gtk_menu_new_from_model

  • gtk_menu_bar_new_from_model

  • gtk_menu_shell_bind_model

  • gtk_menu_button_set_menu_model

  • gtk_popover_new_from_model

  • GtkEntry::populate-popup

  • GtkTextView::populate-popup

Gaps / Shortcomings:

  • No way to bypass GtkMenu for context menus

  • No proper context menu api at all - have to use gtk_menu_attach and gtk_menu_popup_*

  • No way to associate keyboard shortcuts 'locally'
  • Some people really want UI assets (strings, icons, accels) associated with actions
  • The action group hierarchy created with gtk_widget_insert_action_group is poorly documented and understood

  • Toolbars are not covered

Proposal

This strawman proposal is split into three steps

  • Deprecate GtkMenuShell, GtkMenuItem, and GtkMenu in GTK+ 3.22

  • Make GtkMenuShell, GtkMenuItem, and GtkMenu private classes in GTK+ 3.9x

  • Improve GMenu API to make menu merging easier from an application standpoint

  • Add context menu api, like

    • gtk_widget_set_context_menu

    • gtk_entry_get_default_context_menu

The deprecation in GTK+ 3.22 is going to be fairly painful for application developers, and we may opt out of it.

Making menu-related GTK+ widgets private is fairly simple build surgery.

The additional GMenu API needs to be identified and discussed with applications making heavy use of menus, and added to the base class inside GIO. Impact on compositors and other platforms needs also further discussion.

Comments

  • GTK+ 3 doesn't have a convenient non-deprecated API to still be able to construct a traditional design: menubar + toolbar + statusbar. It is not possible with GMenu to show longer descriptions of menu items in the statusbar, something that I prefer to keep in my applications to make the UI better self-discoverable. Another problem is that there is no high-level API to share information between menu items and toolbar items, if GtkBuilder is used to create a GMenu, the information needs to be duplicated to create the toolbar. Since GtkUIManager is deprecated and application authors are told in the porting guide to not use any deprecated API to be able to port to GTK+ 3.9x, the only solution is to use the low-level widget-based API to create menus and toolbars. Since the widget-based API is not convenient to use, a higher-level API needs to be created, which is exactly what I started to do in the Tepl library. Now if the widget-based API is removed from the public API of GTK+ 4, everything must be redone again. Porting an application with a large menu away from GtkUIManager is a lot of boring work. Application developers will port the menu a first time in GTK+ 3 to not use deprecated APIs, and then they will need to port it a second time for GTK+ 4 because the widget-based API has disappeared? Surely that's not nice for application developers. So, if a higher-level API is created upstream in GTK+, it needs to be available in/for GTK+ 3 as well. — SébastienWilmet

  • Since GtkUIManager is deprecated since GTK+ 3.10, maybe some application developers have already ported their menu and toolbar with the widget-based API. For large applications it's a lot of work. So please don't force application developers to port their menus to new APIs every 5 years or so. — SébastienWilmet

  • Inside the Tepl repository, I've created the Amtk shared library (Actions, Menus and Toolbars Kit for GTK+), see this blog post. — SébastienWilmet

  • Plotinus is another interesting project which is somewhat relevant to this, might be good for meeting the needs of more complex applications or even for exposing settings usually only accessible through dconf editor — JohnMcHugh

Projects/GTK/Menus (last edited 2019-08-08 08:00:46 by SébastienWilmet)