When restoring a minimized window the WM_SYSCOMMAND SC_RESTORE message should arrive after WM_NCACTIVATE but before WM_ACTIVATE and WM_SETFOCUS.
Some games depend on that ordering and the related window state.
For example Project CARS 3 expects window to be both active and in the foreground (wrt GetActiveWindow() and GetForegroundWindow()) when receiving those messages.
Without being active the window doesn't restore properly, see 82c6ec3a32f4 ("winex11.drv: Activate window when restoring from iconic state.")
But if the activate messages arrive before the window is in the foreground, the game tries to re-acquire DirectInput DISCL_FOREGROUND devices too early and fails, which results in non-working keyboards and controllers.
Signed-off-by: Arkadiusz Hiler ahiler@codeweavers.com --- dlls/user32/focus.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index 4c18238a98b..e804720c7ca 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -148,6 +148,13 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (IsWindow(hwnd)) { SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), (LPARAM)previous ); + + if (GetPropW( hwnd, L"__WINE_RESTORE_WINDOW" )) + { + SetPropW( hwnd, L"__WINE_RESTORE_WINDOW", NULL ); + SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 ); + } + SendMessageW( hwnd, WM_ACTIVATE, MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ), (LPARAM)previous );
On X11 / XWayland the PropertyNotify for WM_STATE change from IconicState to NormalState arrives before the WM_TAKE_FOCUS ClientMessage and the FocusIn events.
Converting that state change too early to a WM_SYSCOMMAND SC_RESTORE results in it (and the ACTIVATE events because of the previous HAX) arriving without the window being set to foregrounds first.
This breaks the expectations of Project CARS 3. The game tries to re-acquire DirectInput devices with cooperative level set to DISCL_FOREGROUND, which fails.
Signed-off-by: Arkadiusz Hiler ahiler@codeweavers.com --- dlls/winex11.drv/event.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 1772a27c48b..5f5597a48be 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -87,6 +87,8 @@ extern BOOL ximInComposeMode; #define XEMBED_UNREGISTER_ACCELERATOR 13 #define XEMBED_ACTIVATE_ACCELERATOR 14
+static const WCHAR restore_window_propW[] = {'_','_','W','I','N','E','_','R','E','S','T','O','R','E','_','W','I','N','D','O','W',0}; + Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL; void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
@@ -556,7 +558,7 @@ static inline BOOL can_activate_window( HWND hwnd )
if (!(style & WS_VISIBLE)) return FALSE; if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE; - if (style & WS_MINIMIZE) return FALSE; + if ((style & WS_MINIMIZE) && !GetPropW( hwnd, restore_window_propW )) return FALSE; if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE; if (hwnd == GetDesktopWindow()) return FALSE; if (GetWindowRect( hwnd, &rect ) && IsRectEmpty( &rect )) return FALSE; @@ -1318,9 +1320,10 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat { TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window ); release_win_data( data ); - if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE)) - SetActiveWindow( hwnd ); - SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 ); + if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE) && GetForegroundWindow() != hwnd) + SetPropW( hwnd, restore_window_propW, (HANDLE) TRUE ); + else + SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 ); return; } TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=93532
Your paranoid android.
=== debiant2 (32 bit WoW report) ===
user32: win.c:10376: Test failed: GetForegroundWindow() = 00000000 win.c:10381: Test failed: Expected foreground window 00150128, got 00E400F2 win.c:10383: Test failed: GetActiveWindow() = 00000000 win.c:10383: Test failed: GetFocus() = 00000000 win.c:10384: Test failed: Received WM_ACTIVATEAPP(1), did not expect it. win.c:10385: Test failed: Received WM_ACTIVATEAPP(0), did not expect it. win.c:10393: Test failed: Expected foreground window 00150128, got 00000000 win.c:10395: Test failed: GetActiveWindow() = 00000000 win.c:10395: Test failed: GetFocus() = 00000000 win.c:10403: Test failed: Received WM_ACTIVATEAPP(1), did not expect it.
On Fri, Jul 02, 2021 at 08:19:57AM -0500, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=93532
Your paranoid android.
=== debiant2 (32 bit WoW report) ===
user32: win.c:10376: Test failed: GetForegroundWindow() = 00000000 win.c:10381: Test failed: Expected foreground window 00150128, got 00E400F2 win.c:10383: Test failed: GetActiveWindow() = 00000000 win.c:10383: Test failed: GetFocus() = 00000000 win.c:10384: Test failed: Received WM_ACTIVATEAPP(1), did not expect it. win.c:10385: Test failed: Received WM_ACTIVATEAPP(0), did not expect it. win.c:10393: Test failed: Expected foreground window 00150128, got 00000000 win.c:10395: Test failed: GetActiveWindow() = 00000000 win.c:10395: Test failed: GetFocus() = 00000000 win.c:10403: Test failed: Received WM_ACTIVATEAPP(1), did not expect it.
Those are just flaky tests. I was seeing anywhere between 3-17 failures in user32 win tests during the development + I don't see how the change in question could cause any of those.
A re-run on testbot and it looks clean: https://testbot.winehq.org/JobDetails.pl?Key=93534
On Fri, 2 Jul 2021, Arkadiusz Hiler wrote: [...]
=== debiant2 (32 bit WoW report) ===
user32: win.c:10376: Test failed: GetForegroundWindow() = 00000000 win.c:10381: Test failed: Expected foreground window 00150128, got 00E400F2 win.c:10383: Test failed: GetActiveWindow() = 00000000 win.c:10383: Test failed: GetFocus() = 00000000 win.c:10384: Test failed: Received WM_ACTIVATEAPP(1), did not expect it. win.c:10385: Test failed: Received WM_ACTIVATEAPP(0), did not expect it. win.c:10393: Test failed: Expected foreground window 00150128, got 00000000 win.c:10395: Test failed: GetActiveWindow() = 00000000 win.c:10395: Test failed: GetFocus() = 00000000 win.c:10403: Test failed: Received WM_ACTIVATEAPP(1), did not expect it.
Those are just flaky tests. I was seeing anywhere between 3-17 failures in user32 win tests during the development + I don't see how the change in question could cause any of those.
Right. user32:win is a complete mess (and it's not even the worst of the user32 tests):
https://test.winehq.org/data/patterns.html#user32:win
But even if the task is daunting we'll have to start cleaning it up at some point rather than systematically turning away (and I'm not saying this specifically for you, just seizing the occasion).
Unfortunately all I can say about the failures above is that they are random. But I diagnosed some of the others and maybe these can be useful starting points:
* On Vista to Windows 8.1 part of mscoree:mscoree fails to run, breaks user32:win https://bugs.winehq.org/show_bug.cgi?id=51390
* On Windows 7 and 8.1 ntoskrnl.exe:ntoskrnl triggers a network firewall dialog, breaks user32:win https://bugs.winehq.org/show_bug.cgi?id=51391
* user32:monitor breaks user32:win https://bugs.winehq.org/show_bug.cgi?id=51392
* user32:win gets an unexpected 0x7fff message in the Korean locale https://bugs.winehq.org/show_bug.cgi?id=51395
* There's also this set of failures which only happen in 64-bit [1] tests on the cw-gtx560 and cw-rx460 machines for some, as yet, unknown reason. win.c:2284: Test failed: expected !100 win.c:2284: Test failed: expected !100
[1] Actually it happened in the 32-bit tests exactly once on 2021-05-04 on cw-gtx560-1909-32: https://test.winehq.org/data/cda4abac9859ed42c29e8cb2746201a578431a5e/win190...
On Sun, 4 Jul 2021, Francois Gouget wrote: [...]
Right. user32:win is a complete mess (and it's not even the worst of the user32 tests):
And here are some bonus issues: * Together ntoskrnl.exe:ntoskrnl and user32:monitor trigger extra user32:win failures https://bugs.winehq.org/show_bug.cgi?id=51399
* user32:win test_SetActiveWindow() has 2 failures on Vista to Windows 8.1 https://bugs.winehq.org/show_bug.cgi?id=51130
* user32:win "unexpected 0x0282 message" Chinese Windows 10 failures https://bugs.winehq.org/show_bug.cgi?id=48819
* user32:win "unexpected 0x7fff message" Japanese Windows 10 failures This may be the same as the other issue for the Korean locale but it did not have the source + testcase keywords so it was kind of hidden. https://bugs.winehq.org/show_bug.cgi?id=48820
* user32:win "unexpected 0x738 message" Windows 10 failures https://bugs.winehq.org/show_bug.cgi?id=48815
Wine tests... infinitely surprising.