Skip to content

fix(ui-windows): DPI-scale layout intrinsics (refs #5884); unblock crate unit tests#6637

Merged
proggeramlug merged 2 commits into
mainfrom
fix/win-ui-dpi-intrinsics
Jul 20, 2026
Merged

fix(ui-windows): DPI-scale layout intrinsics (refs #5884); unblock crate unit tests#6637
proggeramlug merged 2 commits into
mainfrom
fix/win-ui-dpi-intrinsics

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Problem

DPI handling in the Windows UI backend is split-brain: the window size, fonts, stack spacing, and explicit setSize dimensions are all multiplied by get_dpi_scale() at their entry points — but the layout engine's intrinsic control sizes never were. layout.rs contained no DPI reference at all: TextField=30, Toggle=24, Slider=24, Picker=28, ProgressView=20, DatePicker=28, Combobox=28, button padding +16/+32, the combobox dropdown inflate +200, and every fallback constant were raw 96-DPI pixels.

On a 125–200% display (the default on modern laptops) every fixed-height control clips its own DPI-scaled font — the #5884 family of bugs. Because layout.rs never saw the scale, every future widget added there inherited the bug.

Fix

  • Central dpi(px) helper in layout.rs (scale_by(px, scale) pure core + get_dpi_scale() wrapper). All intrinsic constants, the button text padding, the combobox dropdown inflate, and the measure_text_height fallbacks/clamps now route through it.
  • Deliberately not scaled: measure_text_height results (physical pixels — fonts are already scaled at creation), fixed_width/height (scaled at the setSize FFI), stack spacing (scaled at creation), insets (set unscaled at their own entry point — flagged in review as a follow-up if that entry point gains scaling).
  • scale_by clamps: scale ≤ 1.0 returns the constant unchanged (Windows never scales below 100%; an unset/zero reading must not shrink controls). Rounds half-up at fractional factors.

Also in this PR: the crate's unit tests could never link

cargo test -p perry-ui-windows failed with LNK2019: DwmSetWindowAttribute / DwmExtendFrameIntoClientArea — the hand-declared dwmapi externs (dwm.rs, app.rs) had no #[link(name = "dwmapi")], and only the final app link adds dwmapi.lib. That means the crate's existing in-crate #[cfg(test)] suites (app.rs, screenshot.rs, ffi/system.rs, lib.rs) could not have been run this way. Two #[link] attributes fix it; the test harness now links and runs.

Verification (Windows 11 x64)

Refs #5884. No version bump / changelog per maintainer instruction.

Summary by CodeRabbit

  • Bug Fixes
    • Improved Windows UI intrinsic sizing on high-DPI displays.
    • Fixed picker and combobox heights to prevent dropdown clipping.
    • Updated text and control fallback sizing so empty/invalid content scales correctly.
    • Refined DPI scaling for multiple widgets to keep dimensions consistent across resolutions.
  • Reliability
    • Resolved Windows build/test linking failures for desktop rendering components.
  • Tests
    • Added unit coverage for DPI scaling behavior and rounding.

layout.rs authored every intrinsic control size in raw 96-DPI pixels
while fonts/window/spacing were already DPI-scaled, so fixed-height
controls clipped their own scaled fonts on >100% displays (#5884
family). Route all intrinsic constants, button padding, the combobox
dropdown inflate, and measure_text_height fallbacks through a central
dpi() helper; measured text extents stay physical. scale_by(px, s<=1)
is identity so 100% displays are bit-for-bit unchanged (unit-tested).

Also add #[link(name = dwmapi)] to the hand-declared DWM externs:
without it cargo test -p perry-ui-windows failed at link (LNK2019
DwmSetWindowAttribute), which had silently kept the whole in-crate
test suite unrunnable.
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fc92b8c6-4510-4f60-9528-e2537227d526

📥 Commits

Reviewing files that changed from the base of the PR and between a4e7f1b and eb76567.

📒 Files selected for processing (1)
  • crates/perry-ui-windows/src/app.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/perry-ui-windows/src/app.rs

📝 Walkthrough

Walkthrough

Windows layout calculations now scale intrinsic and text dimensions by DPI, including picker and combobox sizing, with helper tests. DWM API usage also declares explicit dwmapi linkage for application and test builds.

Changes

Windows DPI-aware layout

Layer / File(s) Summary
DPI-scaled layout and measurement
crates/perry-ui-windows/src/layout.rs
Adds shared DPI scaling helpers and applies them to widget intrinsic sizes, picker/combobox windows, text fallbacks, and measurement minimums; unit tests cover scaling behavior and rounding.

DWM API linkage

Layer / File(s) Summary
Explicit DWM library linkage
crates/perry-ui-windows/src/app.rs, crates/perry-ui-windows/src/dwm.rs
Adds explicit dwmapi linker attributes to both DWM declaration paths.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: DPI-scaling layout intrinsics and fixing Windows test linking.
Description check ✅ Passed The description covers the problem, fix, related issue, and verification, though it uses custom headings instead of the template.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/win-ui-dpi-intrinsics

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@proggeramlug

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/perry-ui-windows/src/layout.rs (1)

217-221: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Scale the picker/combobox create-time height too. The dpi(200) move here should stay in sync with the fixed 200 height in crates/perry-ui-windows/src/widgets/picker.rs and crates/perry-ui-windows/src/widgets/combobox.rs; otherwise high-DPI controls can be created at the wrong size before the first relayout.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/perry-ui-windows/src/layout.rs` around lines 217 - 221, Update the
picker/combobox create-time height calculation in the move_h branch to scale the
additional 200-pixel offset with DPI, keeping it consistent with the fixed
height values in the Picker and Combobox widget implementations and preserving
the existing minimum height behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/perry-ui-windows/src/layout.rs`:
- Around line 390-408: Update the padding comment in the WidgetKind::Button
sizing branch to clarify that the code adds 16px total vertical padding and 32px
total horizontal padding, representing 8px and 16px per side respectively. Keep
the existing dpi(16) and dpi(32) calculations unchanged.

---

Outside diff comments:
In `@crates/perry-ui-windows/src/layout.rs`:
- Around line 217-221: Update the picker/combobox create-time height calculation
in the move_h branch to scale the additional 200-pixel offset with DPI, keeping
it consistent with the fixed height values in the Picker and Combobox widget
implementations and preserving the existing minimum height behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 67305a62-7955-4d08-a5a5-a13dbc62e711

📥 Commits

Reviewing files that changed from the base of the PR and between cca6e54 and a4e7f1b.

📒 Files selected for processing (3)
  • crates/perry-ui-windows/src/app.rs
  • crates/perry-ui-windows/src/dwm.rs
  • crates/perry-ui-windows/src/layout.rs

Comment on lines 390 to 408
WidgetKind::Button => {
#[cfg(target_os = "windows")]
{
if let Some(hwnd) = widgets::get_hwnd_safe(handle) {
let size = measure_text_height(hwnd, cross_size, vertical);
// Add padding: 8px vertical, 16px horizontal
return if vertical { size + 16 } else { size + 32 };
// Add padding: 8px vertical, 16px horizontal (logical)
return if vertical {
size + dpi(16)
} else {
size + dpi(32)
};
}
}
if vertical {
34
dpi(34)
} else {
100
dpi(100)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Clarify the padding comment vs. actual values.

The comment states "8px vertical, 16px horizontal (logical)" but the code adds dpi(16) and dpi(32) respectively — double the stated figures. This is likely intentional (per-side padding: 8px × 2 sides = 16, 16px × 2 sides = 32), but as written the comment invites a future contributor to "fix" the code to match the literal 8/16 values, silently halving button padding.

✏️ Suggested comment clarification
-                    // Add padding: 8px vertical, 16px horizontal (logical)
+                    // Add padding (total, both sides): 16px vertical (8px top + 8px bottom),
+                    // 32px horizontal (16px left + 16px right), logical pixels.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
WidgetKind::Button => {
#[cfg(target_os = "windows")]
{
if let Some(hwnd) = widgets::get_hwnd_safe(handle) {
let size = measure_text_height(hwnd, cross_size, vertical);
// Add padding: 8px vertical, 16px horizontal
return if vertical { size + 16 } else { size + 32 };
// Add padding: 8px vertical, 16px horizontal (logical)
return if vertical {
size + dpi(16)
} else {
size + dpi(32)
};
}
}
if vertical {
34
dpi(34)
} else {
100
dpi(100)
}
}
WidgetKind::Button => {
#[cfg(target_os = "windows")]
{
if let Some(hwnd) = widgets::get_hwnd_safe(handle) {
let size = measure_text_height(hwnd, cross_size, vertical);
// Add padding (total, both sides): 16px vertical (8px top + 8px bottom),
// 32px horizontal (16px left + 16px right), logical pixels.
return if vertical {
size + dpi(16)
} else {
size + dpi(32)
};
}
}
if vertical {
dpi(34)
} else {
dpi(100)
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/perry-ui-windows/src/layout.rs` around lines 390 - 408, Update the
padding comment in the WidgetKind::Button sizing branch to clarify that the code
adds 16px total vertical padding and 32px total horizontal padding, representing
8px and 16px per side respectively. Keep the existing dpi(16) and dpi(32)
calculations unchanged.

@proggeramlug
proggeramlug merged commit 81e0583 into main Jul 20, 2026
27 checks passed
@proggeramlug
proggeramlug deleted the fix/win-ui-dpi-intrinsics branch July 20, 2026 22:55
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