The message sequences in tests clearly show that there is a WM_ACTIVATE message at the end of ShowWindow() call for restoring a minimized window.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47507 Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/user32/tests/msg.c | 167 ++++++++++++++++++++++++++++++++++++++++ dlls/user32/winpos.c | 9 ++- 2 files changed, 175 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index a5bc1c5518..f8342306c6 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -890,6 +890,91 @@ static const struct message WmShowVisMaxPopupSeq[] = { { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; +/* ShowWindow(hwnd, SW_RESTORE) to an active minimized window */ +static const struct message WmShowRestoreActiveMinimizedOverlappedSeq[] = +{ + { HCBT_MINMAX, hook }, + { WM_QUERYOPEN, sent }, + { WM_NCACTIVATE, sent }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_NCCALCSIZE, sent|optional }, + { WM_MOVE, sent|optional }, + { WM_SIZE, sent|optional }, + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent }, + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { WM_NCCALCSIZE, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent }, + /* Note this WM_ACTIVATE message even if the window is already active */ + { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 }, + { WM_PAINT, sent }, + { 0 } +}; +/* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to an active minimized window */ +static const struct message WmShowNoActivateActiveMinimizedOverlappedSeq[] = +{ + { HCBT_MINMAX, hook }, + { WM_QUERYOPEN, sent }, + { WM_NCACTIVATE, sent }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_NCCALCSIZE, sent|optional }, + { WM_MOVE, sent|optional }, + { WM_SIZE, sent|optional }, + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent }, + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { WM_NCCALCSIZE, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + /* Following optional messages are present on XP */ + { HCBT_SETFOCUS, hook|optional }, + { WM_SETFOCUS, sent|optional }, + /* Note this WM_ACTIVATE message even if the window is already active and with flag SW_SHOWNOACTIVATE */ + { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 }, + { WM_PAINT, sent }, + { 0 } +}; +/* ShowWindow(hwnd, SW_RESTORE) to a minimized child window. Here are messages received by the parent */ +static const struct message WmShowRestoreMinimizedChildSeq[] = +{ + { HCBT_MINMAX, hook }, + { WM_QUERYOPEN, sent }, + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_NCCALCSIZE, sent }, + { WM_CHILDACTIVATE, sent }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { HCBT_SETFOCUS, hook }, + { WM_KILLFOCUS, sent|optional }, + { WM_SETFOCUS, sent }, + { WM_PAINT, sent }, + { WM_PAINT, sent }, + { WM_NCPAINT, sent|beginpaint }, + { WM_ERASEBKGND, sent|beginpaint }, + { 0 } +}; /* CreateWindow (for a child popup window, not initially visible) */ static const struct message WmCreateChildPopupSeq[] = { { HCBT_CREATEWND, hook }, @@ -4770,6 +4855,47 @@ static void test_showwindow(void) ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE); DestroyWindow(hwnd); flush_sequence(); + + /* Test 5: + * 1. Restoring a minimized active window. + */ + hwnd = CreateWindowA("TestWindowClass", "parent", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Failed to create window\n"); + + ShowWindow(hwnd, SW_MINIMIZE); + SetActiveWindow(hwnd); + ok(GetActiveWindow() == hwnd, "Unexpected active window\n"); + flush_events(); + flush_sequence(); + ShowWindow(hwnd, SW_RESTORE); + flush_events(); + ok_sequence(WmShowRestoreActiveMinimizedOverlappedSeq, + "ShowWindow(hwnd, SW_RESTORE):active minimized overlapped", TRUE); + + ShowWindow(hwnd, SW_MINIMIZE); + SetActiveWindow(hwnd); + ok(GetActiveWindow() == hwnd, "Unexpected active window\n"); + flush_events(); + flush_sequence(); + ShowWindow(hwnd, SW_SHOWNOACTIVATE); + flush_events(); + ok_sequence(WmShowNoActivateActiveMinimizedOverlappedSeq, + "ShowWindow(hwnd, SW_SHOWNOACTIVATE):active minimized overlapped", TRUE); + + hchild = CreateWindowA("TestWindowClass", "child", WS_VISIBLE | WS_CHILD, 0, 0, 100, 100, hwnd, 0, 0, 0); + ok(hchild != NULL, "Failed to create child window\n"); + ShowWindow(hchild, SW_MINIMIZE); + SetActiveWindow(hwnd); + ok(GetActiveWindow() == hwnd, "Unexpected active window\n"); + flush_events(); + flush_sequence(); + ShowWindow(hchild, SW_RESTORE); + flush_events(); + ok_sequence(WmShowRestoreMinimizedChildSeq, "ShowWindow(hwnd, SW_RESTORE): minimized child", FALSE); + DestroyWindow(hchild); + + DestroyWindow(hwnd); + flush_sequence(); }
static void test_sys_menu(void) @@ -15385,6 +15511,39 @@ static const struct message WmRestoreMinimizedOverlappedSeq[] = { 0 } };
+/* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to an active minimized window */ +static const struct message WmRestoreActiveMinimizedOverlappedSeq[] = +{ + { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 }, + { HCBT_MINMAX, hook }, + { WM_QUERYOPEN, sent }, + { WM_NCACTIVATE, sent }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_NCCALCSIZE, sent|optional }, + { WM_MOVE, sent|optional }, + { WM_SIZE, sent|optional }, + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent }, + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { WM_NCCALCSIZE, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent }, + /* Note this WM_ACTIVATE messages even if the window is already active */ + { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 }, + { WM_PAINT, sent }, + { 0 } +}; + struct rbuttonup_thread_data { HWND hwnd; @@ -15446,7 +15605,15 @@ static void test_defwinproc(void) DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); flush_events(); ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE); + + ShowWindow(hwnd, SW_MINIMIZE); + SetActiveWindow(hwnd); + ok(GetActiveWindow() == hwnd, "Unexpected active window\n"); + flush_events(); flush_sequence(); + DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); + flush_events(); + ok_sequence(WmRestoreActiveMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):active minimized overlapped", TRUE);
GetCursorPos(&pos); GetWindowRect(hwnd, &rect); diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index bbbab60fbe..6c1cd1a037 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -1182,7 +1182,14 @@ static BOOL show_window( HWND hwnd, INT cmd ) else WIN_ReleasePtr( wndPtr );
/* if previous state was minimized Windows sets focus to the window */ - if (style & WS_MINIMIZE) SetFocus( hwnd ); + if (style & WS_MINIMIZE) + { + SetFocus( hwnd ); + /* Send a WM_ACTIVATE message for a visible top level window, even if the window is already active */ + style = GetWindowLongW( hwnd, GWL_STYLE ); + if (!(style & (WS_CHILD | WS_MINIMIZE)) && (style & WS_VISIBLE) && !(swp & SWP_NOACTIVATE)) + SendMessageW( hwnd, WM_ACTIVATE, WA_ACTIVE, 0 ); + }
done: SetThreadDpiAwarenessContext( context );
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=56224
Your paranoid android.
=== wvistau64_fr (32 bit report) ===
user32: msg.c:16334: Test failed: 20: WaitForSingleObject failed
=== w1064v1809 (32 bit report) ===
user32: msg.c:9460: Test failed: Shift+MouseButton press/release: 7: the msg 0x0202 was expected, but got msg 0x0007 instead msg.c:9460: Test failed: Shift+MouseButton press/release: 8: the msg 0x0202 was expected, but got msg 0x0101 instead msg.c:9460: Test failed: Shift+MouseButton press/release: 10: the msg 0x0101 should have been sent msg.c:9460: Test failed: Shift+MouseButton press/release: 11: the msg 0x0101 was expected, but got msg 0x0202 instead msg.c:9460: Test failed: Shift+MouseButton press/release: 12: the msg sequence is not complete: expected 0000 - actual 0202
=== debian10 (32 bit report) ===
user32: msg.c:5271: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds win.c:3096: Test succeeded inside todo block: Focus should be on child 000900DC, not 000900DC
Report errors: user32:msg prints too much data (35683 bytes)
=== debian10 (32 bit French report) ===
user32: msg.c:5271: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds msg.c:5278: Test succeeded inside todo block: ShowWindow(SW_RESTORE):overlapped: marked "todo_wine" but succeeds
Report errors: user32:msg prints too much data (40829 bytes)
=== debian10 (32 bit Japanese:Japan report) ===
user32: msg.c:5271: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds msg.c:5278: Test succeeded inside todo block: ShowWindow(SW_RESTORE):overlapped: marked "todo_wine" but succeeds
Report errors: user32:msg prints too much data (40829 bytes)
=== debian10 (32 bit Chinese:China report) ===
user32: msg.c:5271: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds msg.c:5278: Test succeeded inside todo block: ShowWindow(SW_RESTORE):overlapped: marked "todo_wine" but succeeds win.c:3096: Test succeeded inside todo block: Focus should be on child 000900DC, not 000900DC
Report errors: user32:msg prints too much data (40828 bytes)
=== debian10 (32 bit WoW report) ===
user32: msg.c:5271: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds win.c:3096: Test succeeded inside todo block: Focus should be on child 000900DC, not 000900DC
Report errors: user32:msg prints too much data (35683 bytes)
=== debian10 (64 bit WoW report) ===
user32: msg.c:5271: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds win.c:3096: Test succeeded inside todo block: Focus should be on child 000900DC, not 000900DC
Report errors: user32:msg prints too much data (35683 bytes)
Zhiyi Zhang zzhang@codeweavers.com wrote:
The message sequences in tests clearly show that there is a WM_ACTIVATE message at the end of ShowWindow() call for restoring a minimized window.
I think that I already commented on this: activation is the result of the SetFocus() call.
On 9/4/19 9:00 PM, Dmitry Timoshkov wrote:
Zhiyi Zhang zzhang@codeweavers.com wrote:
The message sequences in tests clearly show that there is a WM_ACTIVATE message at the end of ShowWindow() call for restoring a minimized window.
I think that I already commented on this: activation is the result of the SetFocus() call.
If a window is not activated when calling SetFocus, SetFocus will indeed activate the window and thus send a WM_ACTIVATE message. However the window tested here is already activated. So SetFocus no longer send a WM_ACTIVATE message. Otherwise, dlls/user32/tests/msg.c#L16868 message sequence WmSetFocus_2 should be incomplete and contain a WM_ACTIVATE message.
Thanks, Zhiyi