From 53720e95dbb0f916516de3930360e7e093ea525f Mon Sep 17 00:00:00 2001 From: Aleksandr Neychev Date: Thu, 3 Sep 2026 09:55:29 +0500 Subject: [PATCH] fixed width resize when change screen scale --- .../Services/MainWindowPlacement.cs | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/CursorLang.Settings/Services/MainWindowPlacement.cs b/CursorLang.Settings/Services/MainWindowPlacement.cs index 79e4569..672d625 100644 --- a/CursorLang.Settings/Services/MainWindowPlacement.cs +++ b/CursorLang.Settings/Services/MainWindowPlacement.cs @@ -1,6 +1,7 @@ using System.Windows; using System.Windows.Interop; using System.Windows.Media; +using System.Windows.Threading; using CursorLang.Core.Interop; using CursorLang.Settings.Interop; @@ -29,6 +30,10 @@ public sealed class MainWindowPlacement // previous, shorter one left behind private double? _designMaxHeight; + // Captured once, so a DPI change has a known-correct value to reassert — see + // RestoreDesignWidth + private double? _designWidth; + /// /// Takes over the placement of the window: puts it in place by the first show /// and follows where the user moves it. @@ -91,6 +96,7 @@ public sealed class MainWindowPlacement window.SourceInitialized -= OnSourceInitialized; _designMaxHeight = window.MaxHeight; + _designWidth = window.Width; LimitHeightToOwnMonitor(window); window.UpdateLayout(); @@ -109,13 +115,32 @@ public sealed class MainWindowPlacement return; } - LimitHeightToOwnMonitor(window); + // Deferred rather than run inline: this event fires while WPF is still in + // the middle of its own response to the same DPI change (its per-monitor + // rescale of Width touches it after this handler if the fix-up runs + // synchronously, undoing it). Posting behind that on the dispatcher queue + // lets our fix-up run once WPF's own pass has finished. + window.Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(() => + { + LimitHeightToOwnMonitor(window); + RestoreDesignWidth(window); + ReapplySizeToContent(window); + })); + } - // Only the size is revisited here, not the position: the window is commonly - // being dragged across monitors right when its DPI changes, and moving it - // ourselves in the middle of that would fight the drag the user is already - // doing - ReapplySizeToContent(window); + // The width is a plain, explicit value rather than something SizeToContent + // computes, and WPF's own per-monitor rescaling does not reliably keep it at the + // same logical width when the system's scaling changes live under an + // already-open window, as opposed to the window being dragged onto a different + // monitor — it can come out scaled by roughly the ratio between the old and the + // new DPI instead of staying put. Reasserting the original value here is simpler + // than chasing exactly where that rescale goes wrong. + private void RestoreDesignWidth(Window window) + { + if (_designWidth is { } designWidth) + { + window.Width = designWidth; + } } // UpdateLayout alone settles the measure/arrange pass of the visual tree, but