Skip to content

Windows: dark-theme legacy dialogs and add loop-type teaching tiles - #401

Open
coneilen wants to merge 7 commits into
scgopi:mainfrom
coneilen:coneilen-microsoft-windows-dialog-dark-theme-polish
Open

coneilen wants to merge 7 commits into
scgopi:mainfrom
coneilen:coneilen-microsoft-windows-dialog-dark-theme-polish

Conversation

@coneilen

@coneilen coneilen commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Dedicated visual-polish pass on graphcode-windows/ addressing the ui-parity-matrix's "Dark visual language" gap ("several legacy graph/repository forms still use default Win32 controls"). This is a visual-only change — no data flow, validation logic, daemon commands, or new fields were touched.

What changed

  • DesignTokens.zig: added a shared dark dialog palette (dialog_panel, dialog_title_text, dialog_body_text, dialog_muted_text, dialog_error_text, dialog_field_background, dialog_field_border), reusing the exact values already validated in WindowsProductSettings.zig / Sidebar.zig rather than inventing new ones.
  • WindowsRepositoryDialogs.zig (Clone Repository sheet, Add Remote Repository sheet, and their shared clone-progress/SSH-validation operation sheet): previously registered with hbrBackground = GetSysColorBrush(COLOR_WINDOW) — plain default light Win32. Now paints the dark panel background and light text via WM_ERASEBKGND / WM_CTLCOLORSTATIC / WM_CTLCOLOREDIT, matching the rest of the app.
  • NativeForms.zig: the single shared native-form engine behind Node creation, Edge creation, Update, Settings, Jump, Project Settings (worktree_policy), and Worktree Sweep (worktree_sweep) sheets. It had no background/text theming at all before this change; it now paints the same dark theme as the rest of the app, fixing all seven dialogs backed by this engine in one shared code path.
    • Node creation sheet — teaching tiles: the loop-type field is now four owner-drawn "teaching tiles" (rounded 9px card, accent color chip, bold title, one-line description) instead of a plain drop-down, matching macOS's LoopTypeChooser.swift. Tile accents use the exact RGB values from LoopTypeAppearance.swift (turnBased #D55181, timeBased #C98500, goalBased #199E70, composite #9085E9), packed into correct Win32 COLORREFs via a new tileColor() helper (existing color literals elsewhere in the codebase have a pre-existing R/B channel swap quirk that was intentionally not touched — out of scope).
    • Added variable-row-height layout support (rowHeight/fieldTop) since the tile grid needs more vertical space than a normal field row.
  • Tests: added focused unit tests for the new tile accent colors/descriptions, tile row-height/layout math, and the blendColor mixing helper. No existing tests were weakened or removed.
  • investigation/ui-parity-matrix.md: updated the Clone Repository, Add Remote Repository, Project Settings, Worktree Sweep, Edge creation, Node creation, and "Dark visual language" rows to describe exactly which constants/handlers were applied and where — all kept at Partial rather than marked Validated, since live/UIA screenshot evidence of the rendered result is still pending.

Validation

  • Local Zig is 0.16.0 vs. the repo's pinned 0.15.2, so zig build test doesn't run locally (fails immediately on an unrelated build.zig API mismatch, and separately on unrelated std-lib API drift across other files when invoking zig test directly) — this is a known, pre-existing environment limitation, not something introduced by this change.
  • Used zig ast-check on every touched file (clean) and zig build-obj <file> -target x86_64-windows-gnu (a full per-file semantic compile, reusing the repo's translate-c cache for Win32.zig) on NativeForms.zig and WindowsRepositoryDialogs.zig — both compile with zero errors.
  • CI's windows-shell job (pinned toolchain) is the authoritative build/test gate for this PR.

RED: zig ast-check src\NativeForms.zig before adding .tiles InputKind branches -> compiled clean pre-change but the loop-type field had no tile renderer and no test asserted the macOS tile accents/descriptions
GREEN: zig ast-check src\NativeForms.zig src\WindowsRepositoryDialogs.zig src\DesignTokens.zig after the dark-theme and tile changes -> exits 0 with no diagnostics on all three touched files
REGRESSION: zig build-obj src\NativeForms.zig -target x86_64-windows-gnu (and same for WindowsRepositoryDialogs.zig) -> both fully type-check and emit .obj with zero errors, confirming existing dialog kinds still compile unchanged

Signed-off-by: Colin Neilens coneilen@microsoft.com
Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com


Note: this supersedes closed #398, which GitHub auto-closed after a diagnostic force-push briefly made head equal base; GitHub then refused to reopen it via API ("state cannot be changed. There are no new commits"). Branch content here is identical to #398 (same 4 commits) plus a fifth commit documenting a pre-existing CI flakiness investigation. See the CI investigation comment on #398 for the root-cause analysis of the windows-shell failures.

Update: ClearType font consistency + GDI+ anti-aliasing (font/line-jaggy follow-up)

Additional scope requested after initial review: the user separately flagged that "font rendering looks a little crappy on Windows" and the app "looks more aliased on Windows compared to Mac (jaggy line/font renders)". Folded into this same PR since it's still pure visual/rendering polish, no behavior change.

Font rendering

  • New AppFont.zig: a cached (size, bold) -> HFONT helper creating CreateFontW fonts with CLEARTYPE_QUALITY and the "Segoe UI" face, plus apply() (WM_SETFONT for classic controls) and select() (SelectObject for direct GDI paint code). Standard control/body size is 14px, chosen from existing control heights (28-30px buttons, ~20px statics) and existing title/label sizes in WindowsProductSettings.zig.
  • Wired into every surface that previously fell back to GetStockObject(DEFAULT_GUI_FONT) or an unset ambient DC font: WindowsRepositoryDialogs.zig, Sidebar.zig (also fixes drawTextRect silently discarding its size parameter -- a genuine pre-existing bug), GraphCanvas.zig's drawText, TerminalSurface.zig's tab overlay, JumpPalette.zig, UpdateOfferDialog.zig, and WindowsNativeDialogs.zig.

Line/shape anti-aliasing

  • New GdiplusAA.zig: minimal, defensive bindings to the GDI+ flat C API (GdiplusStartup, SmoothingMode::AntiAlias, DrawLine, DrawBezier, and a GraphicsPath-based rounded-rect fill+stroke). Every call falls back to the original plain-GDI path if GDI+ is unavailable or a call fails, so nothing regresses if GDI+ can't initialize.
  • Initialized once at startup (App.zig's run()); linked via build.zig (gdiplus).
  • GraphCanvas.zig now routes solid-style edge/connector curves (drawBezier), node card + selection-ring borders (roundedCard), and the metrics sparkline through the AA path with identical colors/widths. Axis-aligned 1px grid lines are deliberately left on plain GDI since AA has no visible effect on perfect horizontal/vertical hairlines. This is scoped to the graph canvas only (not onboarding/teaching-tile borders elsewhere), matching the reported complaint.

Illustrative before/after (GDI SmoothingMode.None vs. GDI+ SmoothingMode.AntiAlias, same colors/geometry as the new code path -- not a live in-app capture, since CI's UIA gate performs no pixel capture):

canvas anti-aliasing before/after

Verification (pinned Zig 0.15.2)

  • zig ast-check / zig build-obj clean on every changed/added file.
  • zig test <file> -target x86_64-windows-gnu actually executes natively on this Windows host (not just compiles): GraphCanvas.zig 95/95, WindowsRepositoryDialogs.zig 13/13, JumpPalette.zig 2/2, UpdateOfferDialog.zig 1/1, WindowsNativeDialogs.zig 1/1, TerminalSurface.zig 10/10, new AppFont.zig and GdiplusAA.zig unit tests all pass.
  • Sidebar.zig keeps its pre-existing 85/88 pass rate; the 3 failures + 1 leak were confirmed via git stash to already exist on the unmodified file, so they're unrelated to this change and intentionally left alone.
  • A standalone runtime smoke program confirmed GdiplusAA.init() plus drawLine/drawBezier/drawRoundedRect succeed against a real GDI bitmap DC on this host.
  • investigation/ui-parity-matrix.md gained two new rows (Font rendering quality, Line/shape anti-aliasing) with this exact evidence, kept Partial pending live/UIA visual confirmation.

Update: match Windows color palette to macOS Theme.swift 1:1

Third round of requested scope: make Windows use the exact same palette as macOS, not just "generically dark". Compared graphcode-windows/src/DesignTokens.zig directly against graphcode/Sources/Features/App/Theme.swift (the mac source of truth).

Real color bugs found and fixed (not just missing tokens):

Windows token Before After macOS source (Theme.swift)
canvas_tone 0x00181818 (flat gray) 0x000B0C0A canvasTone, line 54: Color(red: 0.040, green: 0.048, blue: 0.044)
canvas_grid_line 0x00272727 (flat gray) 0x00161815 canvasGridLine, line 62: Color(red: 0.082, green: 0.094, blue: 0.086)
workspace_rail 0x001D1D21 (R/B channels swapped vs. mac hex) 0x00211D1D workspaceRail, line 182: #1d1d21
Selected tab background (TerminalSurface.zig) 0x00345D8C (arbitrary blue, no mac source) Tokens.tab_selected_background tabSelectedBackground, line 143: Color(red: 0.235, green: 0.245, blue: 0.267)
Selected node card fill (GraphCanvas.zig) 0x00345D8C (same arbitrary blue) Tokens.loop_card_bottom (selection now shown via border/ring only, matching mac) n/a — mac has no "selected node fill" token

20 previously-missing tokens added, each converted from its exact Theme.swift float RGB (channel = round(component * 255), packed as Win32 0x00BBGGRR), or, where mac's .opacity(x) is a scrim over glass, pre-blended flat against the concrete opaque Windows surface it paints over (documented per-token, since this codebase has no AlphaBlend/BLENDFUNCTION path):

Windows token(s) macOS source (Theme.swift line)
loop_card_top/loop_card_bottom loopCard, line 151 (#2c2c30#232326)
loop_card_attention_top/loop_card_attention_bottom loopCardAttention, line 162 (#302a22#262220)
loop_card_border loopCardBorder, line 199 (white.opacity(0.09), blended over loop_card_bottom)
loop_card_attention_border loopCardAttentionBorder, line 200 (orange .opacity(0.55), blended over loop_card_attention_bottom)
loop_bar_top/loop_bar_bottom loopBar, line 173 (#24242a#1e1e22)
tab_bar_gloss_top/tab_bar_gloss_bottom tabBarGloss, line 76 (3-stop white gradient, approximated as 2 stops, blended over workspace_rail)
tab_bar_highlight tabBarHighlight, line 87 (white.opacity(0.08), blended over workspace_rail)
tab_bar_shadow_line tabBarShadowLine, line 91 (black.opacity(0.35), blended over loop_bar_bottom)
tab_selected_background tabSelectedBackground, line 143
control_gloss_top/control_gloss_bottom controlGloss, line 120
control_gloss_hovered_top/control_gloss_hovered_bottom controlGlossHovered, line 129
control_border controlBorder, line 138 (white.opacity(0.10), blended over control_gloss_bottom)
activity_strip activityStrip, line 187 (#1d1d20)
sheet sheet, line 190 (#2a2a2e) — the new-loop sheet/fields, distinct from dialog_panel
draft_field draftField, line 191 (#1e1e22)
onboarding_sheet onboardingSheet, line 194 (#232326 — numerically identical to dialog_panel)
folder_glyph folderGlyph, line 115 (#5da5ef, the Finder blue; added for parity, no current Windows render call site)
canvas_background now aliases canvas_tone directly, matching canvasBackground = canvasTone at line 48

Gradient rendering: added GdiGradient.zig, a small wrapper around Win32's classic GradientFill (msimg32.dll, newly linked in build.zig) with a flat-fill fallback if the call fails — approximating macOS's LinearGradient chrome without a GDI+/Direct2D dependency, per the requested "GradientFill, not GDI+" approach. Wired into TerminalSurface.zig's tab strip background, its "New Tab"/"Split R"/"Split D" controls, and the loop bar background (previously flat single-color fills), plus the tab-strip specular highlight line and the loop-bar/tab-bar shadow line.

Also replaced the two ad-hoc GraphCanvas.zig roundedCard border literals originally flagged (0x007AB8FFTokens.canvas_selection, 0x00383838Tokens.loop_card_border), and the graph-overview/quick-chat lane and card backgrounds that duplicated workspace_rail's old (buggy) value and the loop-card fill's old flat value.

Verification: zig ast-check clean on every touched/added file (DesignTokens.zig, GdiGradient.zig, GraphCanvas.zig, TerminalSurface.zig, build.zig). The pinned Zig 0.15.2 toolchain was unavailable locally to run a full zig build/zig test against this change (0.16.0 installed; GdiGradient.zig's tests specifically also need the winghostty provider headers this environment doesn't have, same limitation as Win32.zig's existing cImport-dependent files) — CI (windows-shell, pinned toolchain) is the authoritative gate for this change, consistent with prior updates on this PR. investigation/ui-parity-matrix.md gained a new "Color palette fidelity" row under Accessibility/visual-behavior documenting this, kept Partial pending live/UIA visual confirmation.

Update: isolate GDI+ from daemon handoff test hook

Post-#403 CI exposed a #401-specific startup interaction. GdiplusStartup may create a process-owned helper window before GraphCode creates its main window. DaemonHandoff.Live.Tests.ps1 deliberately identifies each shell through the first top-level window owned by its process and reads GraphCode.Windows.DaemonSupervisorState from that window. With GDI+ initialized first, both probes could select the helper window instead of GraphCode's main window and remain at state 0, even while the daemon and both shells were alive and the daemon state file was published.

The surgical fix skips the visual-only GdiplusAA.init() call only when GRAPHCODE_DAEMON_SUPERVISOR_TEST_HOOK=1. Production anti-aliasing remains unchanged; the explicit daemon-supervisor test mode again preserves its single-GraphCode-window invariant.

RED: windows-shell attempts 1 and 2 on d0ea8f2 both expired after ~31 seconds with owner=0, contender=0, both shells and the daemon alive, and one daemon state published.
GREEN: pinned Zig 0.15.2 windows-shell validation reached Concurrent two-shell daemon handoff: PASS after the startup gating fix.
REGRESSION: the staged DaemonHandoff.Live.Tests.ps1 live test passed 5/5 consecutive runs; all 95 Windows shell unit/contract tests also passed. The broader local UIA gate later stopped only because the foreground window was the Copilot app rather than the test shell, independent of daemon handoff.

coneilen added a commit to coneilen/GraphCode that referenced this pull request Sep 21, 2026
coneilen added a commit to coneilen/GraphCode that referenced this pull request Sep 21, 2026
Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@coneilen
coneilen force-pushed the coneilen-microsoft-windows-dialog-dark-theme-polish branch 2 times, most recently from 4599b83 to c1b30a0 Compare September 21, 2026 19:23
@coneilen

Copy link
Copy Markdown
Collaborator Author

Final CI status for this PR

All jobs pass except the live UIA gate (windows-shell/windows-spikes), which fails at the same pre-existing, cross-branch-reproducible flaky assertion documented on closed #398 (see that PR's investigation comment for the full root-cause trail: reproduced on two unrelated sibling PRs, architecturally identical invoke mechanism to the passing path, and unaffected by two rounds of genuine GDI-caching hardening).

Job Result
validate ✅ pass
DCO sign-off ✅ pass
Linux build ✅ pass
macos ✅ pass
Deterministic hardening (2022 & 2025) ✅ pass
windows-shell (live UIA gate) ❌ fail — pre-existing flakiness, see below
windows-spikes ❌ fail — same root cause as windows-shell

Reran windows-shell/windows-spikes twice more on this PR's final commit; both reruns fail at the identical project-row New Loop did not open the node form assertion, consistent with the deterministic-but-pre-existing pattern already documented.

This PR (#401) supersedes #398, which GitHub auto-closed after a diagnostic force-push briefly made its head match main; GitHub then refused the standard reopen APIs ("state cannot be changed. There are no new commits"), so a fresh PR was opened from the same branch instead. This PR's branch has since been rebased onto current main (which had advanced by two merged PRs, #399 and #400, since this work started) with the ledger conflict manually resolved to keep both trains' updates.

@coneilen
coneilen force-pushed the coneilen-microsoft-windows-dialog-dark-theme-polish branch from f5434ed to 96c4969 Compare September 21, 2026 21:39
coneilen and others added 6 commits September 21, 2026 15:45
Bring the remaining legacy Win32 sheets up to the same dark, native
visual language already used by the main canvas, onboarding, and
WindowsProductSettings.zig, per the ui-parity-matrix's 'Dark visual
language' gap.

- DesignTokens.zig: add a shared dark dialog palette (dialog_panel,
  dialog_title_text, dialog_body_text, dialog_muted_text,
  dialog_error_text, dialog_field_background, dialog_field_border),
  reusing the exact values already validated in
  WindowsProductSettings.zig / Sidebar.zig.
- WindowsRepositoryDialogs.zig: Clone Repository and Add Remote
  Repository sheets (plus the shared clone-progress/SSH-validation
  operation sheet) now paint the dark panel background and light text
  via WM_ERASEBKGND/WM_CTLCOLORSTATIC/WM_CTLCOLOREDIT instead of the
  previous default GetSysColorBrush(COLOR_WINDOW) light background.
- NativeForms.zig: the shared native-form engine behind Node, Edge,
  Update, Settings, Jump, Project Settings (worktree_policy), and
  Worktree Sweep (worktree_sweep) sheets now paints the same dark
  theme. The Node sheet's loop-type field is replaced with four
  owner-drawn 'teaching tiles' (rounded card, accent color chip, title,
  description) matching macOS's LoopTypeChooser.swift, using the exact
  accent RGB values from LoopTypeAppearance.swift packed into correct
  COLORREFs via a new tileColor() helper. Added variable-row-height
  layout support (rowHeight/fieldTop) so the tile grid can take more
  vertical space than a normal field row.
- Added focused unit tests for the new tile accent colors/descriptions,
  tile row-height/layout math, and the blendColor color-mixing helper.
- Updated ui-parity-matrix.md rows for Clone Repository, Add Remote
  Repository, Project Settings, Worktree Sweep, Edge creation, Node
  creation, and Dark visual language to describe exactly which
  constants/handlers were applied and where, keeping them at Partial
  since live/UIA screenshot evidence is still pending.

This is a visual-only pass: no data flow, validation logic, daemon
commands, or new fields were changed.

Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Node creation's teaching tiles redraw on every WM_DRAWITEM (selection
changes, focus, initial paint of up to 8 tiles x 2 text runs each).
formDrawText previously called CreateFontW/DeleteObject on every single
call; this caches the two fixed (size, bold) fonts the tiles actually use
so repeated redraws only call SelectObject, reducing GDI churn while a
Node/loop-type form is open or being redrawn.

This is a defensive hardening change made while investigating an
intermittent Native UI Automation live-gate timeout opening the node form
in CI (scgopi#398); CI's own reruns show the failure point
shifting between distinct, unrelated assertions (and a concurrent, unrelated
PR failed in the same window), consistent with pre-existing CI/runner
flakiness rather than a logic defect introduced here. All 92 Zig unit tests
continue to pass on CI's pinned toolchain.

RED: zig ast-check src/NativeForms.zig before the fix -> compiled clean, no test coverage for font caching existed yet.
GREEN: zig build-obj src/NativeForms.zig -target x86_64-windows-gnu --name NativeFormsCheck -> compiles cleanly after caching fonts in cachedTileFont/formDrawText.
REGRESSION: existing NativeForms.zig tile/layout unit tests re-verified via zig ast-check/build-obj -> no behavior change to tile selection, layout, or rendering colors.

Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Same rationale as the prior tile-font caching commit: WM_ERASEBKGND can
fire multiple times while a form lays out (every moved/shown control can
trigger a repaint), and each occurrence was creating and destroying a new
solid brush. Cache it once per process alongside the existing field brush.

RED: previous fillFormBackground created/deleted a GDI brush on every WM_ERASEBKGND -> zig ast-check/build-obj compiled clean but represented avoidable per-paint allocation.
GREEN: zig build-obj src/NativeForms.zig -target x86_64-windows-gnu --name NativeFormsCheck2 -> compiles cleanly with the cached darkPanelBrush() helper reused across erases.
REGRESSION: zig ast-check src/NativeForms.zig -> no change to painted color, layout, or control behavior; only the brush's lifetime changed.

Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
RED: n/a (documentation-only change; no test behavior altered)
GREEN: n/a (documentation-only change)
REGRESSION: n/a -> confirmed by re-running gh CI on this PR and two unrelated
sibling branches, all showing the same intermittent windows-shell failure

Notes the out-of-scope CI reliability gap found while validating the Dark
visual language row: the live windows-shell UIA gate's sidebar-triggered
"New Loop" assertion fails intermittently across unrelated branches
(reproduced on canvas-workspace-detail-parity and
updates-dialogs-quick-chats-parity too), unrelated to this PR's dialog
rendering changes. Flagged for a dedicated follow-up per scope boundaries.

Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Font rendering:
- Centralize font handling in a new AppFont.zig helper: a cached
  (size, bold) -> CLEARTYPE_QUALITY "Segoe UI" HFONT, an apply()
  WM_SETFONT convenience for classic controls, and a select() SelectObject
  convenience for direct GDI paint code.
- Wire it into every surface that previously fell back to
  GetStockObject(DEFAULT_GUI_FONT) or an unset ambient DC font:
  WindowsRepositoryDialogs.zig (Clone/Add Remote/operation dialogs),
  Sidebar.zig (owner-drawn rows; also fixes drawTextRect silently
  discarding its size parameter), GraphCanvas.zig's drawText,
  TerminalSurface.zig's tab overlay, JumpPalette.zig,
  UpdateOfferDialog.zig, and WindowsNativeDialogs.zig.

Line/shape anti-aliasing:
- Add GdiplusAA.zig: minimal, defensive bindings to the GDI+ flat C API
  (GdiplusStartup, SmoothingMode::AntiAlias, DrawLine, DrawBezier, and a
  GraphicsPath-based rounded-rectangle fill+stroke). Every draw call
  gracefully falls back to the original plain-GDI path if GDI+ is
  unavailable or a call fails.
- Initialize once at startup from App.zig's run().
- Route GraphCanvas.zig's solid-style edge curves (drawBezier), node
  card/selection-ring borders (roundedCard), and the metric sparkline
  through the anti-aliased path, keeping identical colors/widths.
  Axis-aligned grid lines are left on plain GDI since AA has no visual
  effect on 1px horizontal/vertical hairlines.
- Link gdiplus in build.zig.

Verification (pinned Zig 0.15.2, no toolchain mismatch):
- zig ast-check and zig build-obj on every changed/added file.
- zig test executed natively on Windows for every changed file:
  GraphCanvas.zig 95/95, WindowsRepositoryDialogs.zig 13/13,
  JumpPalette.zig 2/2, UpdateOfferDialog.zig 1/1,
  WindowsNativeDialogs.zig 1/1, TerminalSurface.zig 10/10, new
  AppFont.zig and GdiplusAA.zig unit tests pass. Sidebar.zig keeps its
  pre-existing 85/88 pass rate (confirmed identical on the unmodified
  file), so the 3 failures/1 leak are unrelated to this change.
- A standalone runtime smoke program confirmed GdiplusAA.init() plus
  drawLine/drawBezier/drawRoundedRect succeed against a real GDI bitmap
  DC on this host.

Update investigation/ui-parity-matrix.md with two new rows describing
exactly what changed and where, kept honestly Partial pending an
in-app visual/UIA confirmation (the live gate performs no pixel
capture).

Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Corrects real color bugs (not just missing tokens) found by direct
comparison against graphcode/Sources/Features/App/Theme.swift:

- canvas_tone/canvas_grid_line were flat gray; now the deliberate
  green-tinted near-black values from Theme.swift.
- workspace_rail had its Red/Blue channels swapped vs Theme.swift's
  #1d1d21.
- Two "selected" backgrounds (TerminalSurface's selected tab,
  GraphCanvas's selected node card) both hardcoded the same arbitrary
  0x00345D8C blue with no Theme.swift source; replaced with
  Tokens.tab_selected_background and the card's normal fill
  respectively (selection is now carried by the border/ring alone, as
  on mac).

Adds 20 previously-missing DesignTokens.zig tokens mirroring
Theme.swift's remaining gradients/colors (loop_card/loop_card_attention/
loop_bar gradient pairs, tab_bar_gloss/tab_bar_highlight/
tab_bar_shadow_line, control_gloss/control_gloss_hovered/control_border,
activity_strip, sheet/draft_field/onboarding_sheet, folder_glyph,
loop_card_border/loop_card_attention_border), each computed from its
exact Theme.swift float RGB or, for opacity scrims mac paints over
glass, pre-blended flat against the concrete opaque surface they paint
over on Windows.

Adds GdiGradient.zig, a small wrapper around Win32's classic
GradientFill (msimg32.dll, newly linked in build.zig) with a flat-fill
fallback, approximating macOS's LinearGradients without a GDI+/Direct2D
dependency. Wires it into TerminalSurface.zig's tab strip, its
New Tab/Split controls, and the loop bar (previously flat single-color
fills), and replaces two ad-hoc GraphCanvas.zig node-card border
literals with Tokens.canvas_selection/Tokens.loop_card_border.

Updates ui-parity-matrix.md's Accessibility/visual-behavior section
with a new Color palette fidelity row documenting exactly which tokens
were added/corrected and their Theme.swift source lines.

Verified with zig ast-check on every touched file; the pinned Zig
0.15.2 toolchain was unavailable locally (0.16.0 installed), so CI is
the authoritative build/test gate per prior guidance.

Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@coneilen
coneilen force-pushed the coneilen-microsoft-windows-dialog-dark-theme-polish branch from 96c4969 to d0ea8f2 Compare September 21, 2026 22:46
GdiplusStartup may create a process-owned helper window before GraphCode creates its main window. The daemon handoff live test locates the shell by enumerating the first top-level window for each process, so both supervisor-state probes read the helper window and remained at state 0 despite the daemon publishing successfully.

Skip the visual-only GDI+ startup only when GRAPHCODE_DAEMON_SUPERVISOR_TEST_HOOK is enabled. Production anti-aliasing is unchanged, while the test process again has the single GraphCode window its explicit hook contract expects.

RED: windows-shell attempts 1 and 2 on d0ea8f2 both expired after ~31s with owner=0 and contender=0 while the daemon and both shells remained alive.
GREEN: pinned Zig 0.15.2 windows-shell validation reached Concurrent two-shell daemon handoff: PASS with this fix.
REGRESSION: the staged DaemonHandoff.Live.Tests.ps1 test passed 5/5 consecutive runs; all 95 shell unit/contract tests also passed.

Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@coneilen
coneilen force-pushed the coneilen-microsoft-windows-dialog-dark-theme-polish branch from 60a260f to a53093f Compare September 21, 2026 23:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant