Some games, e.g., Mirror's Edge waits for WM_ACTIVATE when restoring from iconic state.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- v2: SetActiveWindow only when restoring from iconic state and window is visible.
This doesn't break existing tests, see https://testbot.winehq.org/JobDetails.pl?Key=52779
I couldn't find a good way to test this because it manifests when clicking on the taskbar icon, rather via ShowWindow or WM_SYSCOMMAND message.
But I do have some proves that activate messages are sent before WM_SYSCOMMAND SC_RESTORE.
#1 Click on minimized notepad taskbar icon message trace by spy++ on Windows 10 1809
---- Click happens ---- <000001> 00000000000203C4 S WM_WINDOWPOSCHANGING lpwp:00000012439BF540 <000002> 00000000000203C4 R WM_WINDOWPOSCHANGING <000003> 00000000000203C4 S WM_WINDOWPOSCHANGED lpwp:00000012439BF540 <000004> 00000000000203C4 R WM_WINDOWPOSCHANGED ---- Begin of activate messages ---- <000005> 00000000000203C4 S WM_ACTIVATEAPP fActive:True dwThreadID:00001758 <000006> 00000000000203C4 R WM_ACTIVATEAPP <000007> 00000000000203C4 S WM_NCACTIVATE fActive:True <000008> 00000000000203C4 R WM_NCACTIVATE <000009> 00000000000203C4 S WM_ACTIVATE fActive:WA_ACTIVE fMinimized:True hwndPrevious:(null) <000010> 00000000000203C4 R WM_ACTIVATE ---- WM_SYSCOMMAND SC_RESTORE ---- <000011> 00000000000203C4 P WM_SYSCOMMAND uCmdType:SC_RESTORE xPos:0 yPos:0 (used mnemonic) <000012> 00000000000203C4 S WM_QUERYOPEN <000013> 00000000000203C4 R WM_QUERYOPEN fOpenIsOk:True <000014> 00000000000203C4 S WM_WINDOWPOSCHANGING lpwp:00000012439BECA0 <000015> 00000000000203C4 S WM_GETMINMAXINFO lpmmi:00000012439BE530 <000016> 00000000000203C4 R WM_GETMINMAXINFO lpmmi:00000012439BE530 <000017> 00000000000203C4 R WM_WINDOWPOSCHANGING <000018> 00000000000203C4 S WM_NCCALCSIZE fCalcValidRects:True lpncsp:00000012439BEC70 <000019> 00000000000203C4 S message:0x0093 [Unknown] wParam:00000000 lParam:00000012439BE300 <000020> 00000000000203C4 R message:0x0093 [Unknown] lResult:00000001 <000021> 00000000000203C4 R WM_NCCALCSIZE fuValidRect:0000 lpncsp:00000012439BEC70 <000022> 00000000000203C4 S WM_NCPAINT hrgn:00000001 ... ...
#2 The reason why Mirror's Edge doesn't handle WM_SYSCOMMAND SC_RESTORE
Disassembly of the game win proc shows that the win proc return 0 directly when handling WM_SYSCOMMAND SC_RESTORE in fullscreen mode, instead of handing it to DefWindowProc or do any sort of processing. So this means it rely on the WM_ACTIVATE message before WM_SYSCOMMAND.
dlls/winex11.drv/event.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 6054f645c4..5c465aa033 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1266,6 +1266,8 @@ 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 ); return; }
Zhiyi Zhang zzhang@codeweavers.com wrote:
#2 The reason why Mirror's Edge doesn't handle WM_SYSCOMMAND SC_RESTORE
Disassembly of the game win proc shows that the win proc return 0 directly when handling WM_SYSCOMMAND SC_RESTORE in fullscreen mode, instead of handing it to DefWindowProc or do any sort of processing. So this means it rely on the WM_ACTIVATE message before WM_SYSCOMMAND.
It should be possible to add a message test that replicates this behaviour.
@@ -1266,6 +1266,8 @@ 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 ); return;
According to your spy++ logs activating a minimized window before sending WM_SYSCOMMAND/SC_RESTORE is the result of a SetWindowPos call. A message test should help to figure it out its exact flags, in any case it's wrong to call SetActiveWindow directly.
On 5/24/19 5:33 PM, Dmitry Timoshkov wrote:
Zhiyi Zhang zzhang@codeweavers.com wrote:
#2 The reason why Mirror's Edge doesn't handle WM_SYSCOMMAND SC_RESTORE
Disassembly of the game win proc shows that the win proc return 0 directly when handling WM_SYSCOMMAND SC_RESTORE in fullscreen mode, instead of handing it to DefWindowProc or do any sort of processing. So this means it rely on the WM_ACTIVATE message before WM_SYSCOMMAND.
It should be possible to add a message test that replicates this behaviour.
I couldn't find a way to do it automatically. It seem an interactive test is required if we really need a test.
@@ -1266,6 +1266,8 @@ 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 ); return;
According to your spy++ logs activating a minimized window before sending WM_SYSCOMMAND/SC_RESTORE is the result of a SetWindowPos call. A message test should help to figure it out its exact flags, in any case it's wrong to call SetActiveWindow directly.
I don't think that specific WM_ACTIVATE message is the result of SetWindowPos because WM_ACTIVATE message is sent after WM_WINDOWPOSCHANGED.
Zhiyi Zhang zzhang@codeweavers.com wrote:
#2 The reason why Mirror's Edge doesn't handle WM_SYSCOMMAND SC_RESTORE
Disassembly of the game win proc shows that the win proc return 0 directly when handling WM_SYSCOMMAND SC_RESTORE in fullscreen mode, instead of handing it to DefWindowProc or do any sort of processing. So this means it rely on the WM_ACTIVATE message before WM_SYSCOMMAND.
It should be possible to add a message test that replicates this behaviour.
I couldn't find a way to do it automatically. It seem an interactive test is required if we really need a test.
In Windows UI practically everything could be reproduced with a set of API calls, I don't see a need for an interactive test either since you can't then reliably record and test a message sequence.
@@ -1266,6 +1266,8 @@ 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 ); return;
According to your spy++ logs activating a minimized window before sending WM_SYSCOMMAND/SC_RESTORE is the result of a SetWindowPos call. A message test should help to figure it out its exact flags, in any case it's wrong to call SetActiveWindow directly.
I don't think that specific WM_ACTIVATE message is the result of SetWindowPos because WM_ACTIVATE message is sent after WM_WINDOWPOSCHANGED.
That could be a defect in your testing, a message case would show that for sure.
On 5/24/19 11:47 PM, Dmitry Timoshkov wrote:
Zhiyi Zhang zzhang@codeweavers.com wrote:
#2 The reason why Mirror's Edge doesn't handle WM_SYSCOMMAND SC_RESTORE
Disassembly of the game win proc shows that the win proc return 0 directly when handling WM_SYSCOMMAND SC_RESTORE in fullscreen mode, instead of handing it to DefWindowProc or do any sort of processing. So this means it rely on the WM_ACTIVATE message before WM_SYSCOMMAND.
It should be possible to add a message test that replicates this behaviour.
I couldn't find a way to do it automatically. It seem an interactive test is required if we really need a test.
In Windows UI practically everything could be reproduced with a set of API calls, I don't see a need for an interactive test either since you can't then reliably record and test a message sequence.
@@ -1266,6 +1266,8 @@ 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 ); return;
According to your spy++ logs activating a minimized window before sending WM_SYSCOMMAND/SC_RESTORE is the result of a SetWindowPos call. A message test should help to figure it out its exact flags, in any case it's wrong to call SetActiveWindow directly.
I don't think that specific WM_ACTIVATE message is the result of SetWindowPos because WM_ACTIVATE message is sent after WM_WINDOWPOSCHANGED.
That could be a defect in your testing, a message case would show that for sure.
I tested it multiple times with multiple apps. So it's unlikely to be a defect. Anyway, I will try to write a test for this. If you could give some suggestions on how to do that, I would appreciated it.
Thanks, Zhiyi