189. No popup holds the keyboard
Date: 2026-08-23
Status
Accepted. Fixes popups and tooltips outliving the window they belong to.
Context
A menu, a dropdown or a tooltip left open when the user switched to another
application stayed on screen, over somebody else’s window, after the owner had
hidden. ADR-0186 narrowed
it and could not close it: anyWindowFocused() counts popup windows, so a popup
that held platform focus kept the check true and the dismissal never fired.
ATTACHED popups had already been made NOT_FOCUSABLE for an unrelated reason,
which is why suggestion panels stopped hanging and menus did not.
Decision
NOT_FOCUSABLE on every popup, of every kind
Which reads like a restriction and is the opposite. A popup was never allowed
to rely on having focus. SDL gives a POPUP_MENU window focus on some drivers
and not on others, so the owner has forwarded keys to whatever popup is open
since ADR-0104, and a menu is operable
by arrows either way.
So what varied by driver was never the behaviour — only whether the application still looked focused to itself. And that is precisely what ADR-0144’s check reads to decide a popup has been left behind.
Taking focus off all of them makes that check mean what it says: the application is focused exactly when one of its own real windows is. The dismissal then works for menus, dropdowns and tooltips alike, and works the same way on every driver rather than on the ones that happened not to focus popups.
Consequences
-
One fewer thing that varies by driver. The forwarding path in ADR-0104 existed to tolerate both behaviours; now only one of them happens, and the tolerance is what makes removing the other safe rather than being made redundant by it.
-
The reported popup mis-placement is still not reproduced.
SelectLoopTestnow asserts the list opens below the field from a window at the origin and from a window moved to (220,160) on a display with a 48px taskbar — the case that hides a coordinate-space mistake, because at the origin screen and window coordinates are identical. Both pass.placeableAreaconverts the work area into the window’s space correctly,Placementclamps into it correctly, and the position handed to SDL is in the logical points SDL3 wants.What is left is below the harness:
SDL_CreatePopupWindow’s interpretation of the offset on the reporter’s compositor. The debug line added in6c0618eprints the anchor the list was placed against; with the popup’s own reported position beside it, the two numbers say whether the fault is before SDL or inside it. I have stopped guessing at this one.