Popups
A popup is a window made on another, its parent, for a menu, a list
to choose from or a tooltip. It stays above its parent, has no
decorations, and is a window like any other, with a size, a scale and
events of its own.
Placing a popup
Windows have no places on the screen that a program can know, as Concepts explains. So a popup is placed against a rectangle of its parent, such as the button that opens it, and the window system puts it there, moving it where it would not fit on the screen:
;; A menu below its button, at 20, 10 and 80 by 24 in the window.
(win:create-popup window 160 240 :rectangle '(20 10 80 24) :grab t)
;; A submenu beside its item, in the menu.
(win:create-popup menu 160 120 :rectangle '(0 48 160 24) :anchor :top-right :grab t)
;; A tooltip centred below the pointer, which lets the pointer through.
(win:create-popup window 120 30 :rectangle (list x y 0 0) :anchor :bottom
:popup-anchor :top :offset-y 16 :pointer-input nil)
(win:create-popup parent width height
&key rectangle anchor popup-anchor offset-x offset-y adjustments
grab pointer-input)
=> popup
| Argument | Meaning | Default |
|---|---|---|
width, height |
The size asked for, in units. | |
:rectangle |
(x y width height) in the parent's coordinates, a rectangle. Give a point as a rectangle of size 0. |
(0 0 0 0) |
:anchor |
The point of the rectangle the popup is put at, a popup-point. |
:bottom-left |
:popup-anchor |
The point of the popup put there. | :top-left |
:offset-x, :offset-y |
How far to move it from there, in units. | 0 |
:adjustments |
How the window system may move it where it would not fit, a list of popup-adjustments. |
flip, then slide |
:grab |
Whether it grabs the keyboard, as a menu does. | nil |
:pointer-input |
Whether it takes the pointer; nil lets the pointer through, as for a tooltip. |
t |
A popup-point is a corner, :top-left, :top-right, :bottom-left or
:bottom-right; the middle of an edge, :top, :bottom, :left or
:right; or the :center. By default the popup's top left goes at the
rectangle's bottom left, so it opens below the rectangle.
The popup-adjustments are :flip-x and :flip-y, which mirror the popup
to the other side of the rectangle; :slide-x and :slide-y, which slide
it along until it fits; and :resize-x and :resize-y, which make it
narrower or shorter. Flips are tried first, then slides, then resizes.
The rectangle is in whole units, its edges rounded out, and cut to the parent's size: the window system places popups only against rectangles within their parent.
Where it went
The window system places the popup, possibly elsewhere and at another size:
popup-positionsays where it went: its left and top in the parent's coordinates, 0 and 0 until it is placed.- A new size comes as a
:resizeevent, as for any window. Draw nothing beforewindow-configured-pis true. popup-placementreturns the placement it was last asked for, ascreate-popup's keyword arguments.
reposition-popup places a popup again, at another size or against
another rectangle, with the arguments given and the others as they were:
(win:reposition-popup menu 160 300) ; it grew
(win:reposition-popup tooltip 120 30 :rectangle (list x y 0 0)) ; follow the pointer
On Wayland this needs xdg_wm_base version 3 or later, which every current
compositor offers; popup-error is signalled otherwise.
Grabbing popups
A popup made with :grab t gets the keyboard while it is open, as a menu
does. The window system dismisses it when the user clicks outside the
program's windows or switches to another program: the popup gets a :close
event, popup-dismissed-p is then true, and the program should destroy it.
- Make a grabbing popup in answer to a button or key press: the window system grants the grab for one. A popup whose grab is refused is dismissed at once, as on a Wayland compositor without a seat, such as headless Weston.
- Grabbing popups form one chain. Each is made on the newest one that grabs,
or on a top-level window while none grabs;
popup-erroris signalled otherwise. So close a menu before opening another elsewhere. - Popups that do not grab, such as tooltips, may be made on any window.
Popups a program draws itself
A program that draws its popups itself, inside one of its windows, as a
game in fullscreen draws its menus, places them by the same rules with
place-rectangle, within the window rather than the screen:
(win:place-rectangle 200 300 '(0 0 640 480) :rectangle '(100 450 80 24))
;; => 100, 150, 200, 300: no room below the rectangle, so above it
It takes create-popup's placement arguments, and the bounds to fit
within, (x y width height), and returns where the popup goes: its x, y,
width and height, in whole units. The rectangle is rounded out to whole
units and cut to the bounds, and the size rounded up.
Destroying
destroy-window destroys a window's popups first, the newest first, as
Wayland requires, and then the window. window-popups lists the popups of a
window that are alive, oldest first. popup-parent, popup-grab-p and
popup-pointer-input-p describe a popup.
The parent must have been drawn before a popup is made on it. A popup is never fullscreen.
On each platform
- Wayland: popups are xdg-shell popups, placed by the compositor. A popup that grabs takes the grab with the serial of the latest key or button press.
- Windows: popups are windows without frames owned by their parent's
window, never activated. The backend places them within the work area of
the display, as
place-popupsays, and places them again as their parent moves. A popup that grabs gets the keys typed while the program has the focus, and is dismissed when the focus goes elsewhere or the user presses a button on a title bar or border. Input methods do not compose in popups on Windows.