[PATCH v4] user32: Send a WM_ACTIVATE message after restoring a minimized window.
Zhiyi Zhang
zzhang at codeweavers.com
Tue Sep 24 10:32:39 CDT 2019
The WmShowRestoreMinimizedOverlappedSeq message sequence in tests
clearly show that there is a WM_ACTIVATE message at the end of
ShowWindow() calls after restoring a minimized window.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47507
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
v2: Supersede 169418. Add more tests to show that WM_ACTIVATE is not from SetFocus.
v3: Supersede 170219. Fix some tests that occasionally fail on TestBots.
v4: Supersede 170290. Fix some more tests. Those optional messages just appear right after
I submitted the patch and I ran it multiple times before. I ran it even more times
and this time there should be no more failures because of optional messages.
dlls/user32/tests/msg.c | 238 +++++++++++++++++++++++++++++++++++++++-
dlls/user32/winpos.c | 9 +-
2 files changed, 245 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 2766e7f5fb..4bf5c696ac 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -892,6 +892,138 @@ static const struct message WmShowVisMaxPopupSeq[] = {
{ EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
{ 0 }
};
+/* ShowWindow(hwnd, SW_RESTORE) to a minimized window */
+static const struct message WmShowRestoreMinimizedOverlappedSeq[] =
+{
+ { HCBT_MINMAX, hook },
+ { WM_QUERYOPEN, sent },
+ { WM_GETTEXT, sent|optional },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
+ { WM_GETMINMAXINFO, sent|defwinproc },
+ { WM_NCCALCSIZE, sent },
+ { HCBT_ACTIVATE, hook },
+ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
+ { WM_NCACTIVATE, sent },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ACTIVATE, sent|wparam, WA_ACTIVE },
+ { HCBT_SETFOCUS, hook },
+ { WM_SETFOCUS, sent|defwinproc },
+ { WM_NCPAINT, sent },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { 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 },
+ /* Note this WM_ACTIVATE message even if the window is already active and focused */
+ { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
+ { WM_PAINT, sent },
+ { 0 }
+};
+/* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to a minimized window */
+static const struct message WmShowNoActivateMinimizedOverlappedSeq[] =
+{
+ { HCBT_MINMAX, hook },
+ { WM_QUERYOPEN, sent },
+ { 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 },
+ /* Following optional messages are on XP/2003 */
+ { WM_NCCALCSIZE, sent|optional },
+ { WM_NCPAINT, sent|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { HCBT_SETFOCUS, hook|optional },
+ { WM_SETFOCUS, sent|optional },
+ { HCBT_ACTIVATE, hook|optional },
+ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
+ { WM_NCACTIVATE, sent|optional },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ACTIVATE, sent|wparam|optional, WA_ACTIVE },
+ { HCBT_SETFOCUS, hook|optional },
+ { WM_SETFOCUS, sent|defwinproc|optional },
+ { WM_KILLFOCUS, sent|optional },
+ { WM_SETFOCUS, sent|optional },
+ /* Note this WM_ACTIVATE message on XP even if the window is already active and focused */
+ { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 },
+ { WM_PAINT, sent },
+ { 0 }
+};
+/* ShowWindow(hwnd, SW_RESTORE) to an active minimized window */
+static const struct message WmShowRestoreActiveMinimizedOverlappedSeq[] =
+{
+ { HCBT_MINMAX, hook },
+ { WM_QUERYOPEN, sent },
+ { WM_GETTEXT, sent|optional },
+ { 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 },
+ { WM_GETMINMAXINFO, sent|optional },
+ { 0 }
+};
+/* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to an active minimized window */
+static const struct message WmShowNoActivateActiveMinimizedOverlappedSeq[] =
+{
+ { HCBT_MINMAX, hook },
+ { WM_QUERYOPEN, sent },
+ { WM_GETTEXT, sent|optional },
+ { 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 }
+};
/* CreateWindow (for a child popup window, not initially visible) */
static const struct message WmCreateChildPopupSeq[] = {
{ HCBT_CREATEWND, hook },
@@ -4636,7 +4768,7 @@ static void test_scroll_messages(HWND hwnd)
static void test_showwindow(void)
{
- HWND hwnd, hchild;
+ HWND hwnd, hwnd2, hchild;
RECT rc;
hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
@@ -4773,6 +4905,68 @@ static void test_showwindow(void)
ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
DestroyWindow(hwnd);
flush_sequence();
+
+ /* Test 5:
+ * 1. Restoring a minimized window.
+ */
+ hwnd = CreateWindowA("TestWindowClass", "window1", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
+ ok(hwnd != NULL, "Failed to create window\n");
+
+ hwnd2 = CreateWindowA("static", "window2", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
+ ok(hwnd2 != NULL, "Failed to create window\n");
+
+ ShowWindow(hwnd, SW_MINIMIZE);
+ SetActiveWindow(hwnd2);
+ ok(GetActiveWindow() == hwnd2, "Unexpected active window\n");
+ flush_events();
+ flush_sequence();
+ ShowWindow(hwnd, SW_RESTORE);
+ flush_events();
+ ok_sequence(WmShowRestoreMinimizedOverlappedSeq,
+ "ShowWindow(hwnd, SW_RESTORE): minimized overlapped", TRUE);
+
+ ShowWindow(hwnd, SW_MINIMIZE);
+ SetActiveWindow(hwnd2);
+ ok(GetActiveWindow() == hwnd2, "Unexpected active window\n");
+ flush_events();
+ flush_sequence();
+ ShowWindow(hwnd, SW_SHOWNOACTIVATE);
+ flush_events();
+ ok_sequence(WmShowNoActivateMinimizedOverlappedSeq,
+ "ShowWindow(hwnd, SW_SHOWNOACTIVATE): minimized overlapped", TRUE);
+
+ DestroyWindow(hwnd2);
+ DestroyWindow(hwnd);
+ flush_sequence();
+
+ /* Test 6:
+ * 1. Restoring a minimized but 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);
+
+ DestroyWindow(hwnd);
+ flush_sequence();
}
static void test_sys_menu(void)
@@ -15415,6 +15609,40 @@ 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_GETTEXT, sent|optional },
+ { 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;
@@ -15476,7 +15704,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..ebfdf9b6f0 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 top level window, even if the window is already active */
+ style = GetWindowLongW( hwnd, GWL_STYLE );
+ if (!(style & WS_CHILD) && !(swp & SWP_NOACTIVATE))
+ SendMessageW( hwnd, WM_ACTIVATE, WA_ACTIVE, 0 );
+ }
done:
SetThreadDpiAwarenessContext( context );
--
2.23.0
More information about the wine-devel
mailing list