Fix tiny window on high-DPI displays and tray restore un-maximizing

AppWindow.Resize/Move take physical pixels and the app is PerMonitorV2-aware,
but RestoreWindowBounds passed the logical default/minimum sizes unscaled, so on
a high-DPI display (e.g. a 200% laptop panel) the window came out at half size.
That showed up when restoring from the tray, since RestoreMainWindow's SW_RESTORE
un-maximizes to that size. Scale the default/minimum sizes by the window DPI via
GetDpiForWindow.

Also stop RestoreMainWindow from un-maximizing: it called SW_RESTORE
unconditionally, collapsing a window that was hidden to the tray while maximized.
Only SW_RESTORE when the window is minimized; otherwise SW_SHOW preserves state.

Verified on a 200% display: the restored window is 1520x1360 (= 760x680 logical)
and stays maximized across tray hide/show.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-01 16:16:49 -05:00
co-authored by Claude Opus 4.8
parent 1bde5d531d
commit 93784cc630
@@ -788,7 +788,10 @@ public sealed class MainWindow : Window
IntPtr hwnd = WindowNative.GetWindowHandle(this);
_isMainWindowHidden = false;
ShowWindow(hwnd, ShowWindowShow);
ShowWindow(hwnd, ShowWindowRestore);
// Only un-minimize. The window is hidden to the tray with SW_HIDE while keeping its maximized state, so
// SW_SHOW alone brings it back as it was; an unconditional SW_RESTORE would also un-maximize it.
if (IsIconic(hwnd))
ShowWindow(hwnd, ShowWindowRestore);
Activate();
}
@@ -1542,8 +1545,14 @@ public sealed class MainWindow : Window
private void RestoreWindowBounds()
{
int width = Math.Max(470, ViewModel.Settings.GetValue("mainForm.Width", 760));
int height = Math.Max(640, ViewModel.Settings.GetValue("mainForm.Height", 680));
// AppWindow.Resize takes physical pixels and the app is PerMonitorV2 DPI-aware, so the logical default/minimum
// sizes must be scaled by the window's DPI. Without this, on a high-DPI display (e.g. a 200% laptop panel) the
// window — and any SW_RESTORE from the tray, which un-maximizes to this size — came out at half size.
double scale = GetWindowScale();
int minWidth = (int)Math.Round(470 * scale);
int minHeight = (int)Math.Round(640 * scale);
int width = Math.Max(minWidth, ViewModel.Settings.GetValue("mainForm.Width", (int)Math.Round(760 * scale)));
int height = Math.Max(minHeight, ViewModel.Settings.GetValue("mainForm.Height", (int)Math.Round(680 * scale)));
_appWindow.Resize(new SizeInt32(width, height));
int x = ViewModel.Settings.GetValue("mainForm.Location.X", int.MinValue);
@@ -1552,6 +1561,12 @@ public sealed class MainWindow : Window
_appWindow.Move(new PointInt32(x, y));
}
private double GetWindowScale()
{
uint dpi = GetDpiForWindow(WindowNative.GetWindowHandle(this));
return dpi == 0 ? 1.0 : dpi / 96.0;
}
private void MaximizeWindow()
{
if (_appWindow.Presenter is OverlappedPresenter presenter)
@@ -1787,6 +1802,9 @@ public sealed class MainWindow : Window
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsIconic(IntPtr windowHandle);
[DllImport("user32.dll")]
private static extern uint GetDpiForWindow(IntPtr windowHandle);
private sealed record ParameterEditorRow(IParameter Parameter, Grid Container, CheckBox UseDefault, TextBox Value);
private static void Bind(DependencyObject target, DependencyProperty property, object source, string path, BindingMode mode = BindingMode.OneWay)