Skip to content

Windows: 5 styling FFI stubs awaiting custom paint pass (#185 follow-up) #210

@proggeramlug

Description

@proggeramlug

Context

The styling matrix added in #185 Phase A (crates/perry-ui/src/styling_matrix.rs) audits which styling FFIs are wired on each backend. After Phase B closures (v0.5.297–v0.5.303), every Apple platform + Android + Web is at 43/43 Wired, GTK4 at 39/43 (#202), and Windows at 38/43 Wired + 5 Stub — all 5 stubs are in a single "deferred-paint family" that shares the same blocker: no custom WM_PAINT rendering pass for child controls yet.

The 5 Stub rows

Prop FFI symbol Storage Rendering blocker
widget.shadow perry_ui_widget_set_shadow SHADOW_PARAMS: Mutex<Vec<(i64, ShadowData)>> (mod.rs) Custom WM_PAINT alpha-blit OR DirectComposition IDCompositionVisual + DropShadowEffect
widget.opacity perry_ui_widget_set_opacity OPACITY_VALUES: Mutex<Vec<(i64, f64)>> WS_EX_LAYERED + SetLayeredWindowAttributes per-class wiring
widget.border_color perry_ui_widget_set_border_color BORDER_STATE: Mutex<Vec<(i64, (Option<color>, Option<width>))>> Rectangle() in WM_PAINT, OR wrapping owner-drawn parent
widget.border_width perry_ui_widget_set_border_width (same BORDER_STATE) (same as above — joint state)
text.decoration perry_ui_text_set_decoration DECORATION_VALUES: Mutex<Vec<(i64, i64)>> (text.rs) GetObjectW → modify LOGFONT (lfUnderline/lfStrikeOut) → CreateFontIndirectWWM_SETFONT

All 5 follow the same shape: cross-platform code already calls the FFI, params are stored, but no paint path consumes them.

What's needed

The shared blocker is the WM_PAINT path. Once that lands for any one of these, the rest follow the same pattern:

  1. Shared infrastructure: extend whatever WM_PAINT handler currently exists (or add owner-drawn support to the relevant control classes) to consume the per-handle stored params.
  2. Per-stub apply pass (mirrors the existing apply_corner_radius deferred-paint at mod.rs:843): on resize/paint, read state from the Mutex map, emit the appropriate GDI / DirectComposition calls.
  3. Matrix flip in crates/perry-ui/src/styling_matrix.rs: change StubWired for the platform[7] (Windows) cell on each row as it lands. Drift integration test catches mismatches.

Why a separate issue

The macOS dev host can't easily verify Windows paint output. The existing Windows backend (crates/perry-ui-windows/) builds via cross-compile but actually rendering needs a real Windows host or VM. The CI windows-2022 runner has the toolchain but no display for screenshot verification.

A Windows contributor can pick this up incrementally — each row can flip StubWired independently as paint paths land.

Notes for the implementer

  • apply_corner_radius at crates/perry-ui-windows/src/widgets/mod.rs:843 is the canonical "deferred-paint" pattern. It uses CreateRoundRectRgn() + SetWindowRgn() post-layout. Adding apply_shadow / apply_opacity / apply_border / apply_decoration symmetric to this is the natural shape.
  • WS_EX_LAYERED for opacity needs to be set BEFORE the HWND is shown — the existing apply_opacity would need to coordinate with widget creation, not just be called at paint time.
  • text.decoration's LOGFONT recreate has the same lifetime concerns the existing apply_font at text.rs:336 already handles (DeleteObject of old HFONT before assigning new one).
  • After landing, run cargo test -p perry-ui to verify the matrix integration test stays clean.

Closes

Once landed: Windows reaches 43/43 Wired alongside Apple+Android+Web. Combined with #202's GTK4 4-row closure, the styling matrix is fully green for issue #185 across every Perry-supported platform.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions