Repository navigation
Windows parity: jump palette dimming, anchoring, attention-first order and a scrollbar that stays dark on hover (#776) - #792
Merged
Conversation
This was referenced Oct 14, 2026
coneilen
force-pushed
the
coneilen-microsoft-jump-palette-residuals
branch
from
October 14, 2026 10:58
27d10e4 to
f92fa17
Compare
Refs #776 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 47fe2bfe-f8ec-4057-91f9-8dbcbaa52d39 Signed-off-by: Colin Neilens <coneilen@microsoft.com>
…ting The cosmetic scrollbar strip was a WS_EX_TRANSPARENT child, which exempts it from the clip of the LISTBOX beneath it, so native hover, drag and track painting repainted over the dark strip until the next timer tick. Drop the style so the sibling is clipped out of native nonclient painting; input still reaches the list through WM_NCHITTEST/HTTRANSPARENT. Install the rounded owner region before moving the list so no child is laid out under a stale clip, and cover the real overflowing WM_CREATE path. Refs #776 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: fb6077ed-123a-42aa-9288-775d63658ce6 Signed-off-by: Colin Neilens <coneilen@microsoft.com>
…er children Windows routes the wheel to the focused window under hybrid routing, which is the search field in the palette, and a non-transparent decoration sibling can receive it too. Neither scrolled the results. Forward WM_MOUSEWHEEL arriving at the palette to the results list, with a reentrancy guard for wheel the list itself declines. Refs #776 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: fb6077ed-123a-42aa-9288-775d63658ce6 Signed-off-by: Colin Neilens <coneilen@microsoft.com>
The results list is filled while it is still zero-height, which left it scrolled by one row when more rows than fit were present, so the attention-first row was hidden on open. Reset the top index after the list is laid out. Refs #776 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: fb6077ed-123a-42aa-9288-775d63658ce6 Signed-off-by: Colin Neilens <coneilen@microsoft.com>
coneilen
force-pushed
the
coneilen-microsoft-jump-palette-residuals
branch
from
October 14, 2026 12:49
740ccea to
3d0bd3e
Compare
coneilen
marked this pull request as ready for review
October 14, 2026 13:14
This was referenced Oct 14, 2026
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.
Summary
Complete the jump-palette residuals from #788: dim the owning client area, center the palette at the macOS sheet position, apply macOS attention-first ranking and render overflow scrolling in the dark palette, including while the native scrollbar is hovered, dragged, clicked or wheeled.
Refs #776. This PR was taken over from lane E (1st escalation) after its compositor-popup hover fix was rejected twice in source review. That candidate was not built on: the grey hover flash has a simpler cause (see Changes), and the reviewer's open finding about region ordering is closed by the new mechanism. This does not modify the coordinator-owned ledger or close the issue.
Changes
Entry.needs_humanfrom exact project/node membership inmodel.attention_entries. The only App.zig edit is the coordinator-approved entry-construction line.WS_EX_TRANSPARENT, which makes a window exempt from the sibling clip of the windows beneath it, so the LISTBOX's own nonclient scrollbar painting landed on the strip. A live control run on the previous head reproduces it (Light scrollbar pixel during hover at frame1 ... RGB=135). The strip is now an opaqueWS_CHILD | WS_CLIPSIBLINGSsibling above the list, so it is clipped out of that painting;WM_NCHITTESTstill returnsHTTRANSPARENT, so input reaches the native list. Being a child of the palette, it inherits the rounded window region, so no region is copied and there is noGetWindowRgndependency to fail or latch.WM_SIZE, so no child is laid out under a stale clip.WM_MOUSEWHEELarriving at the palette to the results list, guarded against reentry. WithoutWS_EX_TRANSPARENTthe wheel over the strip reached the strip, and the wheel also never scrolled the results while the focused window was the search field (this machine usesMouseWheelRouting=2).Test plan
After loading C:\gct\e2\environment.ps1, commands ran in graphcode-windows; all evidence is under C:\gcs\e2 (lane E's earlier evidence stays under C:\gcs\e\residuals).
RED: & $env:GRAPHCODE_ZIG0152 test src\JumpPalette.zig -target x86_64-windows-msvc -lc -luser32 -lgdi32 "-I$env:GRAPHCODE_WINGHOSTTY_ROOT\include" --cache-dir C:\gcs\e2\zig-cache --global-cache-dir C:\gcs\e2\zig-global --test-filter "palette residual overflow at creation" --test-filter "opaque sibling decoration" --test-filter "owner region is installed" -> 1 passed, 2 failed: the strip still had WS_EX_TRANSPARENT and the owner region was stale when the list moved (red-attempt1.log).
GREEN: & $env:GRAPHCODE_ZIG0152 test src\JumpPalette.zig -target x86_64-windows-msvc -lc -luser32 -lgdi32 "-I$env:GRAPHCODE_WINGHOSTTY_ROOT\include" --cache-dir C:\gcs\e2\zig-cache --global-cache-dir C:\gcs\e2\zig-global --test-filter "palette residual" -> All 19 tests passed on the final source (green-palette-residual-final.log).
REGRESSION: & $env:GRAPHCODE_ZIG0152 test src\JumpPalette.zig -target x86_64-windows-msvc -lc -luser32 -lgdi32 "-I$env:GRAPHCODE_WINGHOSTTY_ROOT\include" --cache-dir C:\gcs\e2\zig-cache --global-cache-dir C:\gcs\e2\zig-global -> All 40 tests passed on the final source (regression-root-a4.log); baseline before this change was 32 passed (baseline-head.log).
Additional REDs, each observed before its fix (retained under C:\gcs\e2):
--test-filter "wheel over the decoration"failed on the scroll assertion after a precondition mistake of mine was kept separately (red-wheel-precondition-failure.log, thenred-wheel.log; that test was written against an earlier strip-level handler and is regression coverage for the final palette-level handler);--test-filter "wheel delivered to the focused"failed because wheel sent to the search field did not scroll the results (red-wheel-edit.log);--test-filter "opens scrolled to the first result"failedexpected 0, found 1(red-top-index.log). Observed GREEN:green-attempt1.log,green-wheel.log,green-wheel-edit.log,green-top-index.log.Tests that passed on their first run and are therefore regression coverage only, not an observed RED: "overflow at creation" (the real production
WM_CREATEpath with 12 overflowing entries), "posted wheel reaches the native list", "wheel the list declines does not recurse". The structural "opaque sibling decoration" test is a configuration contract: hidden windows cannot prove clipping, and a device-context probe on a message-only parent was empty, so rendered clipping is proven only by the live captures below.Final-source local runs: palette tests 19/19 (
green-palette-residual-final.log), JumpPalette root 40/40 (regression-root-a4.log),zig fmt --checkclean,pwsh -NoProfile -File Tools\windows\validate.ps1 -Task visual-baselinepassed on the rebased head3d0bd3ea(visual-baseline-final.log:VisualBaseline.Tests.ps1: PASS,Tests Passed: 5, Failed: 0, Skipped: 0; process-scoped scratch profile, Pester 5.7.1 from C:\v5modules). Fullpwsh -NoProfile -File Tools\windows\validate.ps1 -Task windows-shell -SkipTrayLive -ShellPart unit -ShellValidationRoot C:\gc-e2 -SwiftExecutable(the pinned toolchain) ran on the frozen head740ccea1under the desktop lease with a process-scoped scratch profile: exit 0,All 1214 tests passed.for the App root (it includes the new palette tests), the JumpPalette root40/40,Windows shell scaffold contract: PASS (58 source files wired; shard 0 of 1 executed 55 of 55 sections)andWINDOWS_SHELL_DEFAULT_PROFILE_UNCHANGED=verified(regression-unit-final.log). It ran while other lanes shared the machine, and some roots show windows.CI on the pre-rebase head
740ccea1b62da393d89ea2163e62ed704d12d73f(samegraphcode-windowstree): Windows shell validation 38554850921 and Windows port validation 38554850945 succeeded, as did DCO, TDD evidence, Linux, macOS shared Swift and Windows release hardening. In that run, shard 2 reported the JumpPalette rootAll 40 tests passed., shard 0 ran the App root (1214 tests: 1209 passed, 5 skipped, 0 failed) including the new palette tests, and the integration job emittedSCRUBBED_SHELL_STARTUP: PASS; executed=5andUIA_JUMP_PALETTE_EVIDENCE(logsci-job-115821960891.log,ci-job-115821960746.log,ci-job-115821960539.log). Full local integration was NotExecuted.Live evidence (desktop lease, 100% DPI, synthetic fixture, injected input)
Identity of the final captures: git head
740ccea1b62da393d89ea2163e62ed704d12d73f,JumpPalette.zigSHA-2565E649F2FDC9D8BA7AD6F54F92603D587452C8037E161D34E5945E1E32DF05848, binary8CFD0C5E5187A1F97D56CEFEC0431C22A4EFD076FD227080831A1C948281E9E0, harnessCA56A5F8B0979FC0E3C98862161C3545E882855A02D7C4CC19E239AAD8251E13(per-runcapture-*.run.jsonrecords the exact command and the harness hash actually used;identity-final.json,identity-slot-before.jsonandidentity-slot-after-captures.jsonrecord the source and binary and name earlier, superseded harness hashes, because I kept editing the harness during the slot). Harness: a modified copy of lane E'scapture-residuals.ps1;PrintWindowfirst, then an ownership-checked screen fallback (WindowFromPointat the centre and on a 40 px grid, before and after) becausePrintWindowomits the owned popup; noActivateWindow.Control reproduces the defect, same harness. On harness
3BD73BAB, PR #792's previous head binary (AE52F9C8) failed the hover check,Light scrollbar pixel during hover at frame1 x5 y19 RGB=163,163,163(cap\capture-control12-052350.log, frame kept incap\control12-052350), while the final binary passed 12 rows on that same harness (cap\capture-a412-052250.logand.run.json). An earlier control on my first harness also failed,RGB=135,135,135(cap\capture-control12.log,cap\control12). The final captures were then rerun after two further harness fixes (a bug on the 8-row path, and the failure-list count) on harnessCA56A5F8, and are the ones shown below. The fix passes there: 12 rows, hover (16 + 120 samples with 1px cursor jitter), thumb drag (24 samples while the thumb moves, 60 held with jitter), track click, arrow click, posted wheel and filter/clear, all dark (cap\capture-a412-052434.log; 8 rowscap\capture-a48-052415.log). The frame count is screen samples, not guaranteed compositor frames.Neighbouring canvas, before opening and after Escape (same hash
. Palette tone, type-bar and dimmed-canvas pixels were verified per image. The "before" images are lane E's valid runs on the merged #788 binary (
1BBF3B77A98D...in the 8-row run):C0D183A7, sourceC221CD56), not recaptured here.Wheel. A post to the focus window, a post to the cosmetic strip and a post to the list all scroll the real list, with focus on the list and on the search field (the focused window class and the foreground process are asserted, and the list is reset to top index 0 before each case; 1 to 2 posts were needed per case). The final 12-row run also had UIA:
ScrollPatternLargeIncrement advanced the list and a UIA hit test at the thumb centre returned the nativeThumb.Disclosures. Hardware wheel injection (
mouse_event,SendInput) did not scroll even a plain Win32 LISTBOX with no GraphCode code on this machine (wheel-control.logtowheel-control4.log), and a raw LISTBOX ignores its first posted wheel message; the harness therefore postsWM_MOUSEWHEELafter a primer, so hardware-wheel routing is NOT VERIFIED. The machine's UIA Win32 proxy also stopped exposing patterns for any LISTBOX between 04:56 and about 05:10 (control binary and a raw probe included), so several runs failed or degraded; those logs are kept (cap\retained-failures.mdlists every run, including harness bugs of mine). Inherited from lane E and still retained: the earlier foreground-capture attempt that photographed the wrong app,capture-before8-verified.log(the border sample hit the rounded edge) andcapture-before12-verified.log(top index started at 1). That last one was a product defect, not only harness noise: lane E's harness normalised it withLB_SETTOPINDEX(0), hiding that an overflowing palette opened scrolled by one row; this PR now fixes it (740ccea1) and the harness asserts opening index 0.Rebase. After all local evidence above was taken, the branch was rebased onto
origin/main2627d357(it brings in #802, #803 and #796). The rebased commits'graphcode-windowstree is byte-identical to the one the local evidence ran on (git tree29ef1c55d6f3c271e7b74760bea1eb89f8b1c859,JumpPalette.zigblob1ea3828c...), and main's delta isTools\windows\validate.ps1plus a plan document. The local unit run therefore does not include #802's addedvalidate.ps1lines; exact-head CI on the rebased head is the regression for those: Windows shell validation 38566774591 and Windows port validation 38566774881 succeeded on3d0bd3ea16c3c6b8c8fd4668089b3276d3cdaa9f, as did DCO, TDD evidence, Linux, macOS shared Swift and Windows release hardening. Shard 2 reported the JumpPalette rootAll 40 tests passed.(includingpalette residual overflow opens scrolled to the first result), shard 0 the App root1209 passed; 5 skipped; 0 failed., and the integration jobSCRUBBED_SHELL_STARTUP: PASS; executed=5andUIA_JUMP_PALETTE_EVIDENCE(logsci-rebased-job-115861421488.log,ci-rebased-job-115861421976.log,ci-rebased-job-115861421547.log); every windows-shell job and windows-spikes passed.Not verified
mouse_eventorSendInput, or a physical wheel); only postedWM_MOUSEWHEELand hidden-window messages.capture-a412-052250, the control run and the final 12-row run; the final run's ScrollPattern andThumbhit test are real evidence, the degraded runs are not. Assistive-technology conformance and physical keyboard or mouse input are not covered.-ShellPart integration) was NotExecuted; exact-head CI integration passed.Rubber-duck review
Reviewer:
gpt-6.1-sol, high (I am a Claude model), through the repository rubber-duck agent. It opened logs, images and source; rejection count 0.First review, head
f92fa179. No blocking source finding. It accepted the mechanism and the closure of the previous owner's open finding (region installed before child moves; the strip is a child of the palette so it inherits the rounded region and there is noGetWindowRgnto fail or latch; realWM_CREATEoverflow test), correctly classified which new tests are regression-only, and set conditions: final-head runtime evidence; assert the focus class and foreground process in the wheel matrix (it recorded them without enforcing them); sample the vertical movement of a held thumb, not only the held position; and refresh provenance. Responses: all four are done (the harness now asserts the focus window class, the foreground PID and a reset top index of 0; 24 samples are taken while the thumb moves, then 60 held with jitter; every run writes a.run.jsonwith the head, the hashes and the exact command; the final captures were taken on the frozen head). Building those checks also exposed a real defect it had not seen (an overflowing palette opened scrolled by one row), fixed in740ccea1test-first.Final review, head
740ccea1. No BLOCKING finding. Verdict: ACCEPT-WITH-CONDITIONS. It judged the delta (LB_SETTOPINDEX(0)after the list is sized inWM_SIZE) correct for the fixed-size popup and found no conflict with user scrolling or filtering. It confirmed the previous conditions closed and the earlier open finding closed. Findings and responses: (1) SHOULD-FIX, the same-harness comparison was attributed to the wrong harness hash: corrected above, the control and a passing final-binary run both used harness3BD73BAB, and the final captures usedCA56A5F8; (2) NIT, UIA availability was described too exclusively: corrected in the disclosures; (3) the local unit run was still pending when it reviewed: it has since passed (above). It also noted that posting the wheel to the strip, the focus window and the list exercises the recipient and parent-forwarding paths, not the OS's wheel targeting, and that the primer and retries are justified by the raw LISTBOX controls but do not prove first-notch responsiveness; both are stated as NOT VERIFIED.Checklist
git commit -s) per the DCOmake test)make check)