Future of relative window positioning

With emerging display server technologies, toolkits sometimes need to adapt how they implement the features they provide. One set of features that needs adaptation is how GTK+ positions popup windows such as menus, popovers and tooltips, so that they will be placed within the work area of the monitor.

In the old days, when GTK+ wanted to position a menu, it would first look up the global position of the parent window of the menu. It would then look up the work areas of all the monitors connected. With the given work areas, the global position of the parent window, and the intended menu position relative to the parent window it wanted to place the menu, GTK+ would use a clever algorithm calculating a reasonable position for the menu to be placed so that it would be visible to the user. For example, if the File menu doesn’t have enough space to popup below the parent menu item, then GTK+ would re-position it above the parent menu item instead.

popup-flip

For various reasons the concept of “global window positions” has been removed from clients in these new display server technologies, meaning we cannot use our clever algorithm in GTK+ any more.

But we still want to make our menus, tooltips, popovers, etc. fully visible to the user expecting to interact with them, so how can we ensure this without knowing anything about where our windows are positioned?

To tackle this in GTK+, we had to solve a number of problems.

  • The positioning logic needs to be moved to GDK, while still allowing GTK+ to affect how the menu positioning behaves should the initially intended position end up outside of the work area.
  • Different GDK backends might do things differently.
  • Some types of windows need to know the position it ended up at, so they can adapt how they draw them self.
  • Some windows simply want to take up as much space as they may (for example a menu with far too many choices should not be taller than the screen).

Last year, William Hua and I started working on bringing GTK+ into the bright future of global position-less menu windows. After having come up with a set of patches doing just that, the discussion of how such an API would actually look like started. After 200-300 comments, we decided we should probably discuss this in person.

Enter GTK2016 in Toronto!

At the hackfest, we got the chance to sit down with a whiteboard in front of us and go through the different use cases, the problems that needed to be solved, how backends would work, and eventually we came up with an API.

william-draws-whiteboard(photo credit: Allison Lortie)

The API we came up with looks as this:

From the GDK side we introduce a new function (so far without any API stability promises; it’s intended to be used only by GTK+ so far) gdk_window_move_to_rect () which takes a set of arguments describing how the application wants its window to be placed in relation to some parent surface. It takes

  • a transient-for window

The parent window it is to be placed relative to an anchor rectangle on the parent window a popup or a menu will often want to be placed in relation to a rectangle on the parent, for example a right-click context menu should expand in some direction from the pixel the pointer was located at when clicking, or a file menu should be placed either below or above the file menu item rectangle on the parent window.

  • a rectangle anchor gravity

Different popup menus might want to open in a certain direction. For example a vertical menu might want to open to the right, while a horizontal menu might want to open downwards.

  • a window anchor gravity

Different popup menus might want to be aligned to the anchor rectangle of the parent anchor rectangle differently. For example, while a combo box might want to expand in a certain direction, it will want to cover the rectangle it expanded from.

  • an anchor hint

Different popup menus want to adjust their positions differently; some will want to expand in different directions from the parent anchor rectangle, some will want to just be slid into visibility, some will want to be resized, while some will want some combination of all the three.

  • an rectangle anchor offset

The offset is simply a nudge factor for a common use case where a popup menu will offset its position relative to an anchor.

By having GTK+ come up with a declarative description of how it wants its menu to be positioned, we allow GDK to implement the actual positioning differently depending on how the display server system is designed. On Mir, a MirSurfaceSpec is created, while on Wayland an xdg_positioner object is created. On X11, Windows and Mac OS X, the backends can use the available global positions as well as monitor work areas and calculate an optimal position just as before.

Application developers are, however, not expected to use this API directly yet. Normally what is wanted is to create a menu, a popover, a combo box, and for this we have introduced a set of parameters and helper functions to make this very convenient. The API consists of a few new properties:

  • GtkMenu:anchor-hints – the positioning strategy.
  • GtkMenu:rect-anchor-dx – horizontal offset to shift window.
  • GtkMenu:rect-anchor-dy – vertical offset to shift window.
  • GtkMenu:menu-type-hint – a window type – this is still needed so that the X11 backend can let the window manager know what type of popup window is being mapped.

and a few more functions:

  • gtk_menu_popup_at_rect () – given the parameters set, popup a menu relative to a given rectangle on a parent window.
  • gtk_menu_popup_at_widget () – given the parameters set, popup a menu relative to a given widget on a parent window.
  • gtk_menu_popup_at_pointer () – given the parameters set, popup a menu relative to where the user just clicked.

With these functions, developers of custom widgets can now position popup menus in a portable manner. So far, GTK+’s own popup menus have already been ported to use these new functions. There is already a basic proof-of-concept in the Mir backend, and a Wayland implementation is in progress.

Head over to the bug to see all the details of how to place your menus in the future.

gnome-sponsored-badge-shadow

GTK+ 2.15.3 unstable release

This is the third development release leading up to GTK+ 2.16.
8 bugs fixed in this release!

  • General:
    • Keyboard shortcut handling has been changed, to help with a longstanding complaint about the way GTK+ handles multiple layouts. GTK+ now only uses keys from groups other than the current group if they are not present in the current group. Feedback on this change is appreciated.

Read the original announcement for more info and downloads.

GTK+ 2.15.2 unstable release

This is the second development release leading up to GTK+ 2.16.
4 bugs fixed in this release!

  • GtkAction:
    • Make toolitems pick up icon names from actions
    • Draw proxies of radio actions properly
    • Make menu proxies of recent actions work
    • Avoid accidental activations when changing actions on proxies
    • Make derived button classes work as proxies
  • Input methods
    • Avoid an assertion due to early use of input methods
  • GtkScale
    • Avoid a segfault in the marker drawing code
  • GtkImageMenuItem
    • Add a property to override the show-menu-images setting

Read the original announcement for more info and downloads.

GTK+ 2.15.1 unstable release

This is the first development release leading up to GTK+ 2.16.
35 bugs fixed in this release!

  • GtkFileChooser:
    • Remember the file chooser’s size across invocations
    • Handle uris that are entered in the entry
    • Improve autocompletion, in particular for uris
  • GtkEntry:
    • New property “im-module” for selecting input methods per-widget
    • New icon-related API got renamed for consistency
    • Added properties and setters for icon tooltips
  • GtkTextView:
    • New property “im-module” for selecting input methods per-widget
    • New signal “paste-done” to allow better handling of async pasting
  • GtkScale:
    • New api to add annotated marks: gtk_scale_add_mark.
  • GtkAction:
    • Rework the way actions and proxies interact, to make the interaction less ad hoc, more extensible, and better suited for support in GUI builders like glade. To be used as a proxy, a widget must now implement the GtkActivatable interface, and GtkActivatable implementations are responsible for syncing their appearance with the action and for activating the action. All the widgets that are commonly used as proxies implement GtkActivatable now. This is a big change, and it is not unlikely to break some current users of GtkAction, so feedback about problems caused by this is appreciated.
    • Add a “gicon” property to specify the icon with a GIcon
  • GDK:
    • On X11, GDK now caches cursors to avoid cursor theming overhead
    • New cursor type for blank cursors: GDK_BLANK_CURSOR
  • New deprecations:
    • gtk_scale_Button_get_orientation()
    • gtk_scale_button_set_orientation()
    • gtk_action_connect_proxy()
    • gtk_action_disconnect_proxy()
    • gtk_widget_get_action()
    • gtk_action_block_activate_from()
    • gtk_action_unblock_activate_from()
    • direct access to “gtk-action” object data
  • Changes that are relevant for translators:
    • Navigation and Media stock labels have separate message contexts now
    • The caps lock warning string has been changed

Read the original announcement for more info and downloads.

GTK+ 2.15.0 unstable release

This is the first development release leading up to GTK+ 2.16.

Overview of changes between 2.14.x and 2.15.0:

  • GtkFileChooser
    • Optionally shows file sizes
    • Mounts volumes when necessary
    • Picks better mime icons
  • GtkEntry
    • Can show icons at either side of the entry, which can be made clickable, drag sources, etc
    • Can show progress information
    • Picks the best available placeholder character for invisible entries unless it is explicitly set. See the invisible-char-set property
    • Input methods work again in invisible entries
    • Invisible entries can optionally display a caps-lock warning. This can be turned off with the caps-lock-warning property
  • GtkStatusIcon
  • GtkLinkButton
    • Respects user-defined tooltips
    • Has a default url hook
  • GtkBuilder
    • Can construct menus
    • Can associate accel groups with windows
    • Child properties can now be translatable, e.g. GtkAssistant::page-title
  • GtkOrientable
    • A new interface implemented by all widgets that have horizontal and vertical variants
    • Printing support
    • Print-to-file can save to non-local files
    • Page rendering can be deferred to a thread to avoid blocking the mainloop
  • GDK
    • GdkKeymap emits a state-changed signal when the Caps Lock state changes
  • Newly deprecated functions:
    • gdk_window_get_toplevels(),
    • gtk_font_selection_dialog_get_apply_button(),
    • gtk_status_icon_set_tooltip(),
    • gtk_toolbar_set_orientation()
  • Changes that are relevant for theme authors
    • The GtkMenu::arrow-placement style property allow more space efficient layout of scrolling menus
    • Submenu arrows can be scaled relative to the font size, with the
    • GtkMenuItem::arrow-scaling style property
    • Themes can set the GtkDialog::content-area-spacing style property to change the spacing between elements of the content area
    • The GtkEntry::state-hint style property can be used to make GTK+ pass the correct state when drawing the background of entries
    • The GtkEntry::prelight style property can be used to suppress prelighting of icons in entries on mouse-over
  • Changes that are relevant for translators
    • GTK+ has been switched to use the two-argument C_() macro instead of Q_() for messages with context

Read the original announcement for more information including bug fixes and download locations.