From 044f2f3cd4fa50434c94c06eee7a35ea05717ff6 Mon Sep 17 00:00:00 2001 From: Niclas Overby Date: Mon, 21 Sep 2026 04:10:31 +0200 Subject: [PATCH] fix(harness): REFUTES task #252, the two window resize defect I reported was my own Command M I opened #252 an hour ago saying a resize with a second window open leaves iTerm2 main window with no title bar and no menu bar, with an A/B that looked clean. IT WAS NOT A DEFECT. I minimised the window myself and then filed the consequence. WHAT ACTUALLY HAPPENED. The shortcut I sent was "raw:-M,logo,comma,-m,logo". A bare word in a wtype argument list is TEXT, not a key name, so wtype typed the five letters c, o, m, m, a with Command held. The application received Command C, Command O, Command M, Command M and Command A. Command M is Minimize. Command O is what opened the Profiles window I thought Command comma had opened. WHY A MINIMISED WINDOW LOOKS LIKE A RESIZE DEFECT, which is the part worth keeping. -platformWindow:frameChanged:didSize: does not assign the new frame when the window is miniaturized. So every later resize reads the frame back as the PREVIOUS size, the insist mechanism concludes the application is demanding a bigger window, the backing bitmap is grown to hold it, and the presented buffer then takes the wrong rows of that bitmap because it bottom anchors a window that is no longer that tall. Title bar and menu bar fall outside the buffer. None of that is wrong on its own; the premise was. MEASURED, with a real Command comma via -k: wrong form window 9 created, frame read back 1256x684 after a 1000x600 resize, 1 oversize correct form NO second window at all, frame 1000x600, ZERO oversize backings So there is no two window resize defect to fix, and iTerm2 does not bind Command comma. WHAT SURVIVES AS A REAL OBSERVATION: iTerm2 Profiles opens and renders correctly, and clicking the Default row selects it with a full width highlight and enables Split Horizontally and Split Vertically. That was all LOOKED AT and it was opened by Command O. THREE THINGS KEPT, because each of them answered a question and will answer it again: app-drive.sh now documents that a named key needs -k and a bare word is typed as text, with this failure as the reason. A CIDER_WAYLAND_TRACE_GEOMETRY line prints the frame a window reads back against the size it was given, which is what turned an inference about insist into a direct reading. cocotron patch 0077 prints a BACKTRACE when a window is asked to miniaturize. That is what named the caller in one run: NSMenu performKeyEquivalent: matching the Minimize item. The trace earned its place by exonerating the port rather than by finding a defect in it. GATES: darling-testsuite 69 of 69, patch record PASS at 77 cocotron patches, roster sweep all seven LOOKED AT, roster input 7 of 7 LOOKED AT. --- scripts/app-drive.sh | 9 ++- src/darwin/wayland/window.rs | 9 +++ ...me-who-asked-a-window-to-miniaturize.patch | 56 +++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 vendor/patches/cocotron/0077-name-who-asked-a-window-to-miniaturize.patch diff --git a/scripts/app-drive.sh b/scripts/app-drive.sh index 5658b58e6..21c2abdb6 100755 --- a/scripts/app-drive.sh +++ b/scripts/app-drive.sh @@ -265,9 +265,16 @@ press_at() { # application to attach, and -d spaces the keys so none is lost to the same race. send_keys_spec() { case "$1" in - # Raw wtype arguments, for a shortcut: "raw:-M logo n -m logo" is Command and N, since the + # Raw wtype arguments, for a shortcut: "raw:-M,logo,n,-m,logo" is Command and N, since the # backend maps Mod4 to NSCommandKeyMask. A menu item several clicks deep is not reachable # any other way from here. + # + # A NAMED KEY NEEDS -k, AND A BARE WORD IS TYPED AS TEXT. "raw:-M,logo,comma,-m,logo" does + # NOT send Command and comma: wtype types the five letters c, o, m, m, a with Command held, + # so the application receives Command C, Command O, Command M, Command M and Command A. + # Command M minimised the window, which then stopped updating its frame on every later + # resize, and I filed that as a two window resize defect before finding the cause was my own + # shortcut. The correct form is "raw:-M,logo,-k,comma,-m,logo". A single letter is fine bare. # COMMAS BECOME SPACES, because STEPS splits on whitespace so a raw sequence cannot contain # one. The comment above the sequencer has promised this since the verb was added and the # code never did it: "raw:-M,logo,comma,-m,logo" reached wtype as ONE argument, wtype diff --git a/src/darwin/wayland/window.rs b/src/darwin/wayland/window.rs index 7508a070d..f8f6278c1 100644 --- a/src/darwin/wayland/window.rs +++ b/src/darwin/wayland/window.rs @@ -616,6 +616,15 @@ pub fn deliver_pending_configures() { objc::msg_send_rect_ret(st.delegate, objc::sel_registerName(cstr!("frame"))); let aw = actual.size.width as i32; let ah = actual.size.height as i32; + /* WHAT THE WINDOW SAYS IT IS, against what we just gave it. A frame that reads back + * as the PREVIOUS size is indistinguishable here from one clamped to a minimum, and + * both grow the bitmap, so print the pair rather than infer it from insist. */ + if crate::env_flag!("CIDER_WAYLAND_TRACE_GEOMETRY") { + println!( + "cider-wayland-frameback number={} gave={}x{} frame={}x{} insist={}x{}", + st.number, width, height, aw, ah, st.insist_w, st.insist_h + ); + } if aw > width || ah > height { st.insist_w = aw.max(width); st.insist_h = ah.max(height); diff --git a/vendor/patches/cocotron/0077-name-who-asked-a-window-to-miniaturize.patch b/vendor/patches/cocotron/0077-name-who-asked-a-window-to-miniaturize.patch new file mode 100644 index 000000000..4ee9f4339 --- /dev/null +++ b/vendor/patches/cocotron/0077-name-who-asked-a-window-to-miniaturize.patch @@ -0,0 +1,56 @@ +Name who asked a window to miniaturize. + +A window that believes it is miniaturized never updates its frame again: +-platformWindow:frameChanged:didSize: skips the assignment for a miniaturized window, so every +later resize reads back the old size, the backing bitmap is grown to hold a window that is no +longer that big, and the compositor is shown the wrong rows of it. From outside that looks exactly +like a resize defect. + +It reached that state with the window MAIN, KEY and VISIBLE, and as its own sender, so the caller +was the whole question and no state dump could answer it. The backtrace named it in one run: + + CIDER_MINI miniaturize: window=0x7087febf1a00 sender=iTermWindow + CIDER_MINI AppKit -[NSApplication sendAction:to:from:] + CIDER_MINI AppKit -[NSMenu performKeyEquivalent:] + CIDER_MINI iTerm2 -[PTYTextView performKeyEquivalent:] + +which is the Minimize item matching a Command M that the harness sent by accident. So the trace +earned its place by exonerating the port rather than by finding a defect in it, and it stays +because the next window that miniaturizes itself will raise the same question. + +Gated on CIDER_TRACE_MINIATURIZE, and miniaturize: is rare enough that a getenv per call costs +nothing. + +Task #252. + +--- a/AppKit/NSWindow.m ++++ b/AppKit/NSWindow.m +@@ -3735,6 +3735,28 @@ + } + + - (void) miniaturize: (id) sender { ++ /* WHO ASKED. A window that believes it is miniaturized never updates its frame again, because ++ * -platformWindow:frameChanged:didSize: skips the assignment for a miniaturized window, and ++ * that leaves every later resize stale. iTerm2 reaches this with the window as its own sender ++ * while it is main, key and visible, so the caller is the whole question. Task #252. */ ++ if (getenv("CIDER_TRACE_MINIATURIZE") != NULL) { ++ void *frames[24]; ++ int count = backtrace(frames, 24); ++ ++ fprintf(stderr, "CIDER_MINI miniaturize: window=%p sender=%s\n", self, ++ sender != nil ? object_getClassName(sender) : "(nil)"); ++ for (int i = 1; i < count; i++) { ++ Dl_info info; ++ ++ if (dladdr(frames[i], &info) != 0 && info.dli_sname != NULL) { ++ const char *image = info.dli_fname ? strrchr(info.dli_fname, '/') : NULL; ++ ++ fprintf(stderr, "CIDER_MINI %-26s %s\n", image ? image + 1 : "?", ++ info.dli_sname); ++ } ++ } ++ fflush(stderr); ++ } + [[self cider_platformWindow] miniaturize]; + } + -- 2.51.2