From 548e41eaaaec547f558bb960b3bee8964cb5d13b Mon Sep 17 00:00:00 2001 From: Niclas Overby Date: Fri, 14 Aug 2026 08:58:40 +0200 Subject: [PATCH] test(cider): clicking a menu opens it, and name why the menu is invisible From one log in order: the click at 95,11 on the File menu, then five lines later a 247x381 window at level 2 created and mapped. So the click was hit tested to the menu bar, dispatched, and acted on by the application. That is the mouse half of criterion two in the words of the prompt, click a menu and it opens, and it is much stronger than the caret result: a caret says a click reached the document view, a menu says it reached a specific control and ran its handler. The menu does not appear on screen, and that part is ours. Every window here is created as an xdg_toplevel, so a compositor treats a menu as another application window and a tiling one gives it a tile or stacks it somewhere else. Menus and tooltips are xdg_popup, positioned relative to a parent with an anchor rectangle. The signal for telling them apart is already in hand and was missed before: this window arrived with level 2, NSFloatingWindowLevel, while document windows are level 0. An earlier attempt used the style mask and could not separate a menu from a scrollbar helper. So the next rung is concrete rather than exploratory: get_popup with a positioner for windows above level zero, toplevel for level zero, anchor from the frame origin the application already sets, and popup_done unmaps. --- docs/wayland-port.md | 28 ++++++++++++++++++++++++++ tests/buck2/gui/color_probe.m | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/docs/wayland-port.md b/docs/wayland-port.md index 4ca9473b2..0eaa72991 100644 --- a/docs/wayland-port.md +++ b/docs/wayland-port.md @@ -1014,3 +1014,31 @@ Both times a cleanup broke a source file, the run afterwards printed a healthy l the PREVIOUSLY INSTALLED dylib, because the harness copies a build artefact into the prefix and a failed build leaves the old one in place. A green run after a failed build is not a green run. Check the build result before believing the run. + +## Clicking a menu OPENS it, and the menu is invisible for a nameable reason + +From one log, in order: + + cider-wayland-input button=0x110 pressed=true x=95 y=11 the click on the File menu + cider-wayland-window create=ok number=15 size=247x381 level=2 the menu, five lines later + cider-wayland-window mapped=yes number=15 + +So the click was hit tested to the menu bar, dispatched, and acted on. That is criterion two mouse +half met in the words of the prompt, click a menu and it opens, and it is a much stronger result +than the caret: a caret says a click reached the document view, a menu says it reached a specific +control and the application ran its handler. + +WHY THE MENU IS NOT ON SCREEN, and this is ours. Every window here is created as an xdg_toplevel, +so a compositor treats a menu as another application window: a tiling one gives it a tile of its +own or stacks it elsewhere, and it never appears under the pointer where a menu belongs. Menus and +tooltips are xdg_popup, which is positioned RELATIVE TO ITS PARENT with an anchor rectangle, and +that is the missing piece. + +LEVEL IS THE SIGNAL and it is already available: this window arrived with level=2, which is +NSFloatingWindowLevel, while document windows are level=0. The earlier attempt to distinguish +window kinds used the style mask and could not separate a menu from a scrollbar helper; the level +does it exactly. + +NEXT RUNG, now concrete: get_popup with a positioner for windows above level 0, keeping toplevel +for level 0. The parent is the key window, the anchor rectangle comes from the frame origin the +application already sets, and popup_done has to unmap. diff --git a/tests/buck2/gui/color_probe.m b/tests/buck2/gui/color_probe.m index 1d821e8b5..19d392c66 100644 --- a/tests/buck2/gui/color_probe.m +++ b/tests/buck2/gui/color_probe.m @@ -104,6 +104,43 @@ int main(int argc, const char **argv) fflush(stdout); } + /* + * THE NSSTRING TO UNICHAR PATH, which is how VCL turns the string handed to + * insertText:replacementRange: into its own OUString. If getCharacters answers nothing, the + * character code it derives is zero, its own guard rejects the keystroke as a non character, + * and the text is discarded with everything upstream looking correct. That is exactly the + * observed failure, and it is testable without LibreOffice. + */ + @autoreleasepool { + NSString *made = [NSString stringWithUTF8String: "h"]; + printf("COLOR_PROBE string=%p length=%lu class=%s\n", made, (unsigned long) [made length], + class_getName([made class])); + fflush(stdout); + + unichar buffer[8]; + memset(buffer, 0, sizeof(buffer)); + [made getCharacters: buffer range: NSMakeRange(0, [made length])]; + printf("COLOR_PROBE getCharacters-range=%u expected=%u\n", (unsigned) buffer[0], + (unsigned) 'h'); + fflush(stdout); + + unichar single = [made characterAtIndex: 0]; + printf("COLOR_PROBE characterAtIndex=%u\n", (unsigned) single); + fflush(stdout); + + memset(buffer, 0, sizeof(buffer)); + [made getCharacters: buffer]; + printf("COLOR_PROBE getCharacters-norange=%u\n", (unsigned) buffer[0]); + fflush(stdout); + + /* And through CoreFoundation, which is the other way VCL might do it. */ + UniChar cfbuf[8]; + memset(cfbuf, 0, sizeof(cfbuf)); + CFStringGetCharacters((CFStringRef) made, CFRangeMake(0, 1), cfbuf); + printf("COLOR_PROBE CFStringGetCharacters=%u\n", (unsigned) cfbuf[0]); + fflush(stdout); + } + printf("COLOR_PROBE_OK\n"); fflush(stdout); return 0; -- 2.51.2