From 77fcf54cec960976fb5bc221bd7918d5b50cb1ec Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Fri, 23 Oct 2020 23:14:41 +0200 Subject: [PATCH 1/3] POC for a fix. --- src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index 370e2a2a4b..1c66b9aae2 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -65,6 +65,8 @@ namespace Avalonia.Win32 return IntPtr.Zero; } + _parent?.SetEnabled(true); + break; } From 134f916262a69916162a9139b88353d5218e5da9 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sat, 24 Oct 2020 16:51:48 +0200 Subject: [PATCH 2/3] Attempt of fixing more child window operations. --- .../Avalonia.Win32/Interop/UnmanagedMethods.cs | 6 ++++++ src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs | 12 +++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index a527a35c52..f88c57cf59 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -1017,6 +1017,9 @@ namespace Avalonia.Win32.Interop [DllImport("user32.dll")] public static extern bool ValidateRect(IntPtr hWnd, IntPtr lpRect); + [DllImport("user32.dll")] + public static extern bool IsWindow(IntPtr hWnd); + [DllImport("user32.dll")] public static extern bool IsWindowEnabled(IntPtr hWnd); @@ -1050,6 +1053,9 @@ namespace Avalonia.Win32.Interop [DllImport("user32.dll")] public static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr GetActiveWindow(); + [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SetActiveWindow(IntPtr hWnd); diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index 1c66b9aae2..123472d23f 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -65,7 +65,17 @@ namespace Avalonia.Win32 return IntPtr.Zero; } - _parent?.SetEnabled(true); + if (_parent != null && IsWindow(_parent._hwnd)) + { + var wasActive = GetActiveWindow() == _hwnd; + + _parent.SetEnabled(true); + + if (wasActive) + { + SetActiveWindow(_parent._hwnd); + } + } break; } From 27ee4e00cd77c6c9754d0cc36a15f4daaf4a2350 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sat, 24 Oct 2020 20:38:56 +0200 Subject: [PATCH 3/3] Add a bunch of comments to explain what is going on in win32 closed handler. --- src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index 123472d23f..d770f4b211 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -65,12 +65,18 @@ namespace Avalonia.Win32 return IntPtr.Zero; } + // Based on https://github.com/dotnet/wpf/blob/master/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs#L4270-L4337 + // We need to enable parent window before destroying child window to prevent OS from activating a random window behind us. + // This is described here: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow#remarks + // Our window closed callback will set enabled state to a correct value after child window gets destroyed. + // We need to verify if parent is still alive (perhaps it got destroyed somehow). if (_parent != null && IsWindow(_parent._hwnd)) { var wasActive = GetActiveWindow() == _hwnd; _parent.SetEnabled(true); + // We also need to activate our parent window since again OS might try to activate a window behind if it is not set. if (wasActive) { SetActiveWindow(_parent._hwnd);