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.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46274 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/msg.c | 2 +- dlls/win32u/input.c | 17 ++++++++++++----- dlls/win32u/ntuser_private.h | 1 + 3 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index adb167bdad3..5c7464173c0 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -14827,7 +14827,7 @@ static void test_set_active_window_recursive(HWND hwnd, HWND hwnd2)
flush_sequence(); SetActiveWindow(hwnd); - ok_sequence(RecursiveActivationSeq, "recursive activation", TRUE); + ok_sequence(RecursiveActivationSeq, "recursive activation", FALSE);
DestroyWindow(hwnd2); DestroyWindow(hwnd); diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 5cd2cdd0970..29c7e86036c 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1227,6 +1227,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) return TRUE; }
+ if (prev) *prev = previous; + if (win_set_flags( hwnd, WIN_IS_ACTIVATING, 0 ) & WIN_IS_ACTIVATING) return TRUE; + /* call CBT hook chain */ cbt.fMouse = mouse; cbt.hWndActive = previous; @@ -1246,9 +1249,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 done; if (prev) *prev = previous; - if (previous == hwnd) return TRUE; + if (previous == hwnd) goto done;
if (hwnd) { @@ -1256,7 +1259,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (send_message( hwnd, WM_QUERYNEWPALETTE, 0, 0 ) && user_callbacks) user_callbacks->pSendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0, SMTO_ABORTIFHUNG, 2000, NULL ); - if (!is_window(hwnd)) return FALSE; + if (!(ret = is_window( hwnd ))) goto done; }
old_thread = previous ? get_window_thread( previous, NULL ) : 0; @@ -1290,7 +1293,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
if (is_window(hwnd)) { - send_message( hwnd, WM_NCACTIVATE, hwnd == NtUserGetForegroundWindow(), (LPARAM)previous ); + send_message( hwnd, WM_NCACTIVATE, + (hwnd == NtUserGetForegroundWindow()) && !(win_get_flags(previous) & WIN_IS_ACTIVATING), + (LPARAM)previous ); send_message( hwnd, WM_ACTIVATE, MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, is_iconic(hwnd) ), (LPARAM)previous ); @@ -1313,7 +1318,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) } }
- return TRUE; +done: + win_set_flags( hwnd, 0, WIN_IS_ACTIVATING ); + return ret; }
/********************************************************************** diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 7c03474286d..5452c722ffa 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -119,6 +119,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_ACTIVATING 0x0100 /* the window is being activated */
#define WND_OTHER_PROCESS ((WND *)1) /* returned by WIN_GetPtr on unknown window handles */ #define WND_DESKTOP ((WND *)2) /* returned by WIN_GetPtr on the desktop window */