fix(library): anchor the native context menu popup at the pointer position - #5182
Merged
Conversation
…ition A positionless menu.popup() makes muda anchor the GTK popup to the X11 root window, which doesn't exist on Wayland — the popup gets no parent, the compositor refuses to map it (Gdk-WARNING: Couldn't map window as popup because it doesn't have a parent), and the menu disappears immediately. Pass the contextmenu pointer position (or the item's center for keyboard invocation) so muda anchors the popup to the app window's own GdkWindow instead. Fixes #5181 Fixes #5041 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CSS pixels are not window-logical pixels when the webview carries a page zoom: WebKitGTK folds the desktop text-scaling factor into one without reflecting it in devicePixelRatio (e.g. GDK scale 2 with 0.8 text scale renders CSS at 1.6x physical while dPR reports 2), so popping the menu at the raw client coordinates lands it offset from the click by a factor that grows with distance. Map the click's fraction of the CSS viewport onto the window's logical size instead — any uniform zoom cancels out of the ratio, and on macOS/Windows the formula degenerates to the plain client coordinates. Also cache the built native menu per item and prewarm it on pointer enter, so popup() no longer waits for a dozen Menu items to cross the IPC boundary on every right-click. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two commits:
menu.popup()with no arguments, so the popup gets a parent surface on Wayland.Why
Fixes #5181, fixes #5041 — on Linux/Wayland the library context menu flashed and disappeared immediately when opened with a touchpad two-finger tap.
The reporter's terminal capture showed the root cause:
In muda's GTK backend, a positionless popup is anchored to the screen's root window. On X11 the root window is real, so this works; on Wayland there is no root window — the popup gets no parent and the compositor refuses to map it. With an explicit position, muda anchors the popup to the app window's own
GdkWindow, which always maps.Coordinate mapping. CSS pixels are not window-logical pixels when the webview carries a page zoom: WebKitGTK folds the desktop text-scaling factor into one without reflecting it in
devicePixelRatio(measured on X11 with GDK scale 2 and a 0.8 text scale: CSS renders at 1.6× physical while dPR reports 2). BothLogicalPosition(clientX)andPhysicalPosition(clientX × dPR)therefore land the menu offset from the click by a factor that grows with distance (right-click book 3, menu on book 4). The zoom-proof conversion maps the click's fraction of the CSS viewport onto the window's logical size:Any uniform zoom cancels out of the ratio, and on macOS/Windows (where CSS px = logical px) the formula degenerates to the plain client coordinates.
Latency. Building a dozen-item native menu over the IPC boundary on every right-click made the popup visibly lag. The menu is now built once per item, cached, invalidated when item state baked into it changes, and prewarmed on pointer enter so the first right-click pops instantly.
Verification
book-context-menu-popup-position.test.tsxpins the viewport-fraction conversion (no-zoom and 0.8-zoom cases);book-context-menu-cache.test.tsxpins the cache/prewarm/invalidation behavior.pnpm test(7606 passed) andpnpm lintclean.🤖 Generated with Claude Code