diff --git a/dlls/user/mdi.c b/dlls/user/mdi.c index bfeb2db64ec..13da1ecc05f 100644 --- a/dlls/user/mdi.c +++ b/dlls/user/mdi.c @@ -618,7 +618,13 @@ static LONG MDI_ChildActivate( HWND client, HWND child ) if( isActiveFrameWnd ) { SendMessageW( child, WM_NCACTIVATE, TRUE, 0L); - SetFocus( client ); + /* Let the client window manage focus for children, but if the focus + * is already on the client (for instance this is the 1st child) then + * SetFocus won't work. It appears that Windows sends WM_SETFOCUS + * manually in this case. + */ + if (SetFocus(client) == client) + SendMessageW( client, WM_SETFOCUS, (WPARAM)client, 0 ); } SendMessageW( child, WM_MDIACTIVATE, (WPARAM)prevActiveWnd, (LPARAM)child ); diff --git a/dlls/user/tests/msg.c b/dlls/user/tests/msg.c index 6714f54e96e..027810fe651 100644 --- a/dlls/user/tests/msg.c +++ b/dlls/user/tests/msg.c @@ -1968,11 +1968,12 @@ static const struct message WmCreateMDIchildVisibleMaxSeq3[] = { /* Win9x: message sequence terminates here. */ { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, + { WM_SETFOCUS, sent|optional }, /* in MDI client */ { HCBT_SETFOCUS, hook }, /* in MDI client */ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, - { WM_SETFOCUS, sent }, /* in MDI client */ - { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent|optional }, /* in MDI client */ + { HCBT_SETFOCUS, hook|optional }, { WM_KILLFOCUS, sent }, /* in MDI client */ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, @@ -2014,6 +2015,41 @@ static const struct message WmCreateMDIchildVisibleMaxSeq3[] = { { 0 } }; +/* CreateWindow for the 1st MDI child window, initially invisible and maximized */ +static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = { + { HCBT_CREATEWND, hook }, + { WM_GETMINMAXINFO, sent }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent }, + { WM_MOVE, sent }, + { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, + { WM_GETMINMAXINFO, sent }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|0x8000 }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + /* in MDI frame */ + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER }, + { WM_NCCALCSIZE, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ + { WM_NCCALCSIZE, sent|wparam, 1 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + /* Win2k sends wparam set to + * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated), + * while Win9x doesn't bother to set child window id according to + * CLIENTCREATESTRUCT.idFirstChild + */ + { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */ + { 0 } +}; /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */ static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = { { WM_SYSCOMMAND, sent|wparam, SC_CLOSE }, @@ -2289,6 +2325,33 @@ static const struct message WmMaximizeMDIchildInvisibleSeq[] = { { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ { 0 } }; +/* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */ +static const struct message WmMaximizeMDIchildInvisibleSeq2[] = { + { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, + { WM_GETMINMAXINFO, sent }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent|wparam, 1 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 }, + + { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, + { HCBT_SETFOCUS, hook }, + { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent }, /* in MDI client */ + { HCBT_SETFOCUS, hook }, + { WM_KILLFOCUS, sent }, /* in MDI client */ + { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */ + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_MDIACTIVATE, sent|defwinproc }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { 0 } +}; /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */ static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = { { WM_MDIMAXIMIZE, sent }, /* in MDI client */ @@ -2906,6 +2969,42 @@ static void test_mdi_messages(void) !active_child, /* win9x */ "wrong active MDI child %p\n", active_child); flush_sequence(); + + trace("creating maximized invisible MDI child window\n"); + mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", + WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME, + 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, 0, GetModuleHandleA(0), NULL); + assert(mdi_child2); + ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", TRUE); + ok(IsZoomed(mdi_child2), "MDI child should be maximized\n"); + ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n"); + ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n"); + + /* Win2k: MDI client still returns a just destroyed child as active + * Win9x: MDI client returns 0 + */ + active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed); + ok(active_child == mdi_child || /* win2k */ + !active_child, /* win9x */ + "wrong active MDI child %p\n", active_child); + flush_sequence(); + + trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n"); + ShowWindow(mdi_child2, SW_MAXIMIZE); + ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", TRUE); + ok(IsZoomed(mdi_child2), "MDI child should be maximized\n"); + ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n"); + ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n"); + + active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed); + ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child); + ok(zoomed, "wrong zoomed state %d\n", zoomed); + flush_sequence(); + + SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0); + flush_sequence(); + /* end of test for maximized MDI children */ mdi_cs.szClass = "MDI_child_Class"; diff --git a/dlls/winex11.drv/winpos.c b/dlls/winex11.drv/winpos.c index 6f9b8f6324d..2f4ad51d5c6 100644 --- a/dlls/winex11.drv/winpos.c +++ b/dlls/winex11.drv/winpos.c @@ -938,7 +938,7 @@ UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect ) case SW_MAXIMIZE: old_style = GetWindowLongW( hwnd, GWL_STYLE ); - if ((old_style & WS_MAXIMIZE) && (old_style & WS_CHILD)) return SWP_NOSIZE | SWP_NOMOVE; + if ((old_style & WS_MAXIMIZE) && (old_style & WS_VISIBLE)) return SWP_NOSIZE | SWP_NOMOVE; WINPOS_GetMinMaxInfo( hwnd, &size, &wpl.ptMaxPosition, NULL, NULL ); @@ -1029,7 +1029,7 @@ BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd ) case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */ swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED; swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos ); - if ((style & WS_MAXIMIZE) && (style & WS_CHILD)) return wasVisible; + if ((style & WS_MAXIMIZE) && wasVisible) return wasVisible; state_change = TRUE; break;