Repository navigation
Fix: Per-Monitor V2 DPI awareness silently not taking effect - #65
Closed
mojingjing-git wants to merge 2 commits into
Closed
mojingjing-git wants to merge 2 commits into
mojingjing-git wants to merge 2 commits into
Conversation
App.config already requests PerMonitorV2, but app.manifest declares only the legacy <dpiAware>true</dpiAware>, i.e. System DPI aware. Because the manifest makes the process System DPI aware at startup, the later PerMonitorV2 request can no longer upgrade the process. On top of that, EnableWindowsFormsHighDpiAutoResizing was never set. The net effect is that Windows bitmap-stretches the app instead of letting it render at the real pixel size, so text looks blurry and controls end up misaligned on displays scaled to 125%/150%/175%. - app.manifest: declare true/pm plus the Windows 10 1703+ <dpiAwareness> element requesting PerMonitorV2, falling back to PerMonitor - App.config: enable WinForms high-DPI auto resizing so forms and controls are scaled to the correct factor Reported from a machine running Windows 11 at 175% scaling.
mojingjing-git
added a commit
to mojingjing-git/ShutdownTimerClassic
that referenced
this pull request
Oct 14, 2026
Localization Full zh-CN translation covering the main menu, countdown window, tray context menu, all three settings tabs, the input dialog, every message box and balloon notification, and the About rich-text block. Fonts switched from Microsoft Sans Serif to Microsoft YaHei UI to avoid CJK glyph fallback. The upstream code uses the combo box Text as its internal action identifier: Timer.ExecutePowerAction switch-cases on the literal English strings, the tray theme is compared against "Light"/"Dark", and the settings JSON persists those same English values. Translating the drop-down entries directly would break action dispatch and invalidate existing settings files. LocalizedCatalog.cs introduces a display/value split. The drop-down renders Chinese through an overridden ToString() while Value keeps the original English identifier, and call sites use GetValue()/SelectValue() to read and write the English value. Result: the UI is Chinese while settings files and CLI behaviour remain compatible with the English build. DPI fix app.manifest declared the legacy <dpiAware>true</dpiAware> (System DPI aware) while App.config requested PerMonitorV2. The manifest wins at process startup, so the PerMonitorV2 request could never take effect, and EnableWindowsFormsHighDpiAutoResizing was never set, leaving Windows to bitmap-stretch the app on scaled displays. Now declared via true/pm plus the Windows 10 1703+ <dpiAwareness> element, with WinForms auto resizing enabled. Submitted upstream as lukaslangrock#65. Also moves the target framework from v4.8 to v4.8.1 and keeps the upstream English README as README.upstream.md. Localization and fixes were produced by an AI coding agent (MiniMax M3.1) and reviewed by a human maintainer. The original MIT licence and the copyright notice of Lukas Langrock are preserved.
Owner
|
This seems like a valid issue at first glance, I'll check out the change soon, but in the future, please write the PR description yourself. It's fine to use AI for debugging and even some code generation, and in this case the actual code change is really small, so that's also fine, but I am really not looking forward to reading AI generated reports :) |
Author
|
Thanks, I'll write my own descriptions next time. My |
Owner
…ling that goes with it
Two separate things were going on, so this PR now does both.
1. The DPI awareness declaration
The manifest declared <dpiAware>true</dpiAware>, which makes the process
system-DPI-aware. The App.config already asked for DpiAwareness=PerMonitorV2,
but a manifest declaration overrides the app.config setting, so PerMonitorV2
never took effect. The app was bitmap-stretched on a scaled display and did
not re-layout when moved to a display with a different scale.
Per the WinForms high-DPI documentation, the manifest is the wrong place for
this on .NET Framework 4.7+ ("This approach is no longer recommended, since it
overrides settings defined on the app.config file"). Removing the dpiAware
element from the manifest makes the app.config the single source of truth,
which is enough on its own. So the manifest no longer declares DPI awareness
at all.
The EnableWindowsFormsHighDpiAutoResizing key I had added is dropped again:
with DpiAwareness set to PerMonitorV2, dynamic DPI support is already on by
default. The key is only there to opt out. App.config is now unchanged from
master.
2. The layout breaking on a DPI change
This part is independent of the manifest - it happens with the manifest
removed just the same.
All four forms use AutoScaleMode.Font with AutoScaleDimensions (6, 13). The
documentation notes that font based scaling "might not be linear when the app
runs as system DPI-aware or per-monitor v2 DPI-aware" and can "cause
discrepancies in height-to-width ratios", and that Label and TextBox always
scale by font regardless of AutoScaleMode.
So as soon as dynamic DPI support kicks in, the form is scaled by the DPI
ratio while its labels are scaled by the (non-linear) font ratio. The two
disagree and the text gets clipped.
Switching the forms to AutoScaleMode.Dpi with AutoScaleDimensions (96, 96)
gives linear, DPI-native scaling.
Tested on a 175% primary display with a 125% secondary display, moving the
window back and forth across the two:
- before: version string clipped to "v1.3", the colon after "Select an
action:" gone, "Hours"/"Minutes" cut off
- after: Menu, Settings and Countdown all keep their layout and text intact
- control run with only the manifest change and AutoScaleMode.Font kept: the
clipping is still there, which is what points at the scaling mode rather
than at the manifest
Author
|
I think I may have found the real issue—you can take a look at the latest PR |
Owner
|
Which should I look at, the new PR or this one? Does the new PR supersede this one? |
Author
New one(#66),I will close this PR:) |
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.

AI disclosure — please read first
This pull request was written by an AI coding agent (MiniMax M3.1) on behalf of a human contributor.
The investigation of the DPI configuration, the proposed fix, the commit message and this description were all generated by the model. A human reviewed the resulting diff before submitting and takes full responsibility for it.
If you'd prefer not to accept AI-generated contributions, feel free to close this without any explanation — that is a completely reasonable position and no offense is intended. What matters is that you know where it came from.
The problem
App.configalready asks forPerMonitorV2:…but
app.manifestonly declares the legacy:which means System DPI aware. Because the manifest marks the process as System DPI aware at process startup, the subsequent
PerMonitorV2request can no longer upgrade the process — the two declarations contradict each other, and the manifest wins. On top of that,EnableWindowsFormsHighDpiAutoResizingwas never set.The practical result: Windows bitmap-stretches the whole application instead of letting it render at true pixel size. On a 175%-scaled display this shows up as blurry text and controls that no longer line up.
The fix
Two config files, 3 lines added, 1 line changed:
app.manifest—true/pmplus the Windows 10 1703+<dpiAwareness>element requestingPerMonitorV2, PerMonitor(the second value is the documented fallback).App.config— addEnableWindowsFormsHighDpiAutoResizingso WinForms actually scales forms and controls to the correct factor.Why this is worth fixing regardless of language
This is not locale-specific and not cosmetic-only. It affects every user on a scaled display (125% / 150% / 175% / 200%).
There is also a direct interaction with existing code.
Menu.cs,Settings.csandInputBox.cseach contain:Forcing a single non-fallback font is exactly the kind of mitigation you add when the app is bitmap-stretched — under proper Per-Monitor V2 rendering that concern largely goes away, and the hard-coded font can be relaxed later if you want.
Verification
I built the project from a clean checkout of
masterwith only this patch applied, and launched the resulting binary on Windows 11 at 175% scaling (DPI 168) — it starts and renders correctly.I should be upfront about a limitation: I was not able to capture before/after screenshots from my environment, so there is no visual evidence attached here. If you'd like screenshots (or a reproducible before/after build) to decide on this, just ask and I can provide them.
Notes
Licenseand attribution are untouched.