wine-staging/patches/user32-recursive-activation/0001-user32-focus-Prevent-a-recursive-loop-with-the-activ.patch

143 lines
5.3 KiB
Diff
Raw Normal View History

From 8997ff8b93a64bd2d0db463b6789d05dc5a5fbb5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= <gabrielopcode@gmail.com>
Date: Mon, 22 Jul 2019 15:29:25 +0300
Subject: [PATCH] user32/focus: Prevent a recursive loop with the activation
messages
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When activating a window and sending activation messages to the window
procedure, Windows avoids a recursive loop by not sending more of these
messages or hooks while it's still activating the window. Some applications
actually depend on this behavior, so it is needed.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46274
Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
---
dlls/user32/focus.c | 44 +++++++++++++++++++++++++++--------------
dlls/user32/tests/msg.c | 2 +-
dlls/user32/win.h | 1 +
3 files changed, 31 insertions(+), 16 deletions(-)
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c
index a5fc376bdc6..cae559270bf 100644
--- a/dlls/user32/focus.c
+++ b/dlls/user32/focus.c
@@ -89,7 +89,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
{
HWND previous = GetActiveWindow();
BOOL ret;
- DWORD old_thread, new_thread;
+ DWORD winflags, old_thread, new_thread;
CBTACTIVATESTRUCT cbt;
if (previous == hwnd)
@@ -98,16 +98,24 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
return TRUE;
}
- /* call CBT hook chain */
- cbt.fMouse = mouse;
- cbt.hWndActive = previous;
- if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;
-
- if (IsWindow(previous))
+ /* Prevent a recursive activation loop with the activation messages */
+ winflags = win_set_flags(hwnd, WIN_IS_IN_ACTIVATION, 0);
+ if (!(winflags & WIN_IS_IN_ACTIVATION))
{
- SendMessageW( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
- SendMessageW( previous, WM_ACTIVATE,
- MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
+ ret = FALSE;
+
+ /* call CBT hook chain */
+ cbt.fMouse = mouse;
+ cbt.hWndActive = previous;
+ if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE ))
+ goto clear_flags;
+
+ if (IsWindow(previous))
+ {
+ SendMessageW( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
+ SendMessageW( previous, WM_ACTIVATE,
+ MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
+ }
}
SERVER_START_REQ( set_active_window )
@@ -117,9 +125,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
previous = wine_server_ptr_handle( reply->previous );
}
SERVER_END_REQ;
- if (!ret) return FALSE;
+ if (!ret) goto clear_flags;
if (prev) *prev = previous;
- if (previous == hwnd) return TRUE;
+ if (previous == hwnd) goto clear_flags;
if (hwnd)
{
@@ -127,7 +135,11 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
SendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
SMTO_ABORTIFHUNG, 2000, NULL );
- if (!IsWindow(hwnd)) return FALSE;
+ if (!IsWindow(hwnd))
+ {
+ ret = FALSE;
+ goto clear_flags;
+ }
}
old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
@@ -159,7 +171,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
}
}
- if (IsWindow(hwnd))
+ if (!(winflags & WIN_IS_IN_ACTIVATION) && IsWindow(hwnd))
{
SendMessageW( hwnd, WM_NCACTIVATE, hwnd == NtUserGetForegroundWindow(), (LPARAM)previous );
SendMessageW( hwnd, WM_ACTIVATE,
@@ -184,7 +196,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
}
}
- return TRUE;
+clear_flags:
+ win_set_flags(hwnd, 0, WIN_IS_IN_ACTIVATION);
+ return ret;
}
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 9164f57fdc2..01cb214acdf 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -5571,7 +5571,7 @@ static void test_messages(void)
ShowWindow(hwnd, SW_MINIMIZE);
flush_events();
- ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
+ ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", FALSE);
flush_sequence();
if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
diff --git a/dlls/user32/win.h b/dlls/user32/win.h
index 1f51fd63314..a64cc66be5a 100644
--- a/dlls/user32/win.h
+++ b/dlls/user32/win.h
@@ -79,6 +79,7 @@ typedef struct tagWND
#define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */
#define WIN_CHILDREN_MOVED 0x0040 /* children may have moved, ignore stored positions */
#define WIN_HAS_IME_WIN 0x0080 /* the window has been registered with imm32 */
+#define WIN_IS_IN_ACTIVATION 0x0100 /* the window is in an activation process */
/* Window functions */
extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN;
--
2.34.1