Commit 3898ad40 authored by Zhiyi Zhang's avatar Zhiyi Zhang Committed by Alexandre Julliard

user32: Send a WM_ACTIVATE message after restoring a minimized top level window.

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, and it's not from SetFocus(). Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47507Signed-off-by: 's avatarZhiyi Zhang <zzhang@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent d2c2987b
...@@ -883,6 +883,145 @@ static const struct message WmShowVisMaxPopupSeq[] = { ...@@ -883,6 +883,145 @@ static const struct message WmShowVisMaxPopupSeq[] = {
{ EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 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_SYNCPAINT, sent|optional },
{ WM_PAINT, sent },
{ WM_GETMINMAXINFO, sent|optional },
{ 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_SYNCPAINT, sent|optional },
{ WM_PAINT, sent },
{ WM_GETMINMAXINFO, sent|optional },
{ 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_SYNCPAINT, sent|optional },
{ 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_SYNCPAINT, sent|optional },
{ WM_PAINT, sent },
{ WM_GETMINMAXINFO, sent|optional },
{ 0 }
};
/* CreateWindow (for a child popup window, not initially visible) */ /* CreateWindow (for a child popup window, not initially visible) */
static const struct message WmCreateChildPopupSeq[] = { static const struct message WmCreateChildPopupSeq[] = {
{ HCBT_CREATEWND, hook }, { HCBT_CREATEWND, hook },
...@@ -4677,7 +4816,7 @@ static void test_scroll_messages(HWND hwnd) ...@@ -4677,7 +4816,7 @@ static void test_scroll_messages(HWND hwnd)
static void test_showwindow(void) static void test_showwindow(void)
{ {
HWND hwnd, hchild; HWND hwnd, hwnd2, hchild;
RECT rc; RECT rc;
hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW, hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
...@@ -4814,6 +4953,68 @@ static void test_showwindow(void) ...@@ -4814,6 +4953,68 @@ static void test_showwindow(void)
ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE); ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
DestroyWindow(hwnd); DestroyWindow(hwnd);
flush_sequence(); 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) static void test_sys_menu(void)
...@@ -15527,6 +15728,42 @@ static const struct message WmRestoreMinimizedOverlappedSeq[] = ...@@ -15527,6 +15728,42 @@ static const struct message WmRestoreMinimizedOverlappedSeq[] =
{ 0 } { 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_SYNCPAINT, sent|optional },
{ WM_PAINT, sent },
{ WM_GETMINMAXINFO, sent|optional },
{ 0 }
};
struct rbuttonup_thread_data struct rbuttonup_thread_data
{ {
HWND hwnd; HWND hwnd;
...@@ -15588,7 +15825,15 @@ static void test_defwinproc(void) ...@@ -15588,7 +15825,15 @@ static void test_defwinproc(void)
DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
flush_events(); flush_events();
ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE); 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(); flush_sequence();
DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
flush_events();
ok_sequence(WmRestoreActiveMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):active minimized overlapped", TRUE);
GetCursorPos(&pos); GetCursorPos(&pos);
GetWindowRect(hwnd, &rect); GetWindowRect(hwnd, &rect);
......
...@@ -1179,7 +1179,13 @@ static BOOL show_window( HWND hwnd, INT cmd ) ...@@ -1179,7 +1179,13 @@ static BOOL show_window( HWND hwnd, INT cmd )
else WIN_ReleasePtr( wndPtr ); else WIN_ReleasePtr( wndPtr );
/* if previous state was minimized Windows sets focus to the window */ /* 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 */
if (GetAncestor( hwnd, GA_ROOT ) == hwnd && !(swp & SWP_NOACTIVATE))
SendMessageW( hwnd, WM_ACTIVATE, WA_ACTIVE, 0 );
}
done: done:
SetThreadDpiAwarenessContext( context ); SetThreadDpiAwarenessContext( context );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment