diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index 29d4a614dea..c34a39388c0 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -130,6 +130,7 @@ protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam, } case WindowsMessage.WM_DPICHANGED: + if (!_ignoreDpiChanges) { _dpi = (uint)wParam >> 16; var newDisplayRect = Marshal.PtrToStructure(lParam); @@ -151,6 +152,7 @@ protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam, return IntPtr.Zero; } + break; case WindowsMessage.WM_GETICON: if (_iconImpl == null) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index bf0d20ee79c..e6151489012 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -107,6 +107,7 @@ internal partial class WindowImpl : IWindowImpl, EglGlPlatformSurface.IEglWindow private bool _shown; private bool _hiddenWindowIsParent; private uint _langid; + private bool _ignoreDpiChanges; internal bool _ignoreWmChar; private WindowTransparencyLevel _transparencyLevel; private readonly WindowTransparencyLevel _defaultTransparencyLevel; @@ -707,7 +708,20 @@ public void SetParent(IWindowImpl? parent) _hiddenWindowIsParent = parentHwnd == OffscreenParentWindow.Handle; + // I can't find mention of this *anywhere* online, but it seems that setting + // GWL_HWNDPARENT to a window which is on the non-primary monitor can cause two + // WM_DPICHANGED messages to be sent: the first changing the DPI to the parent's DPI, + // then another changing the DPI back. This then causes Windows to provide an incorrect + // suggested new rectangle to the WM_DPICHANGED message if the window is immediately + // moved to the parent window's monitor (e.g. when using + // WindowStartupLocation.CenterOwner) causing the window to be shown with an incorrect + // size. + // + // Just ignore any WM_DPICHANGED while we're setting the parent as this shouldn't + // change the DPI anyway. + _ignoreDpiChanges = true; SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, parentHwnd); + _ignoreDpiChanges = false; // Windows doesn't seem to respect the HWND_TOPMOST flag of a window when showing an owned window for the first time. // So we set the HWND_TOPMOST again before the owned window is shown. This only needs to be done once.