[PATCH v2 4/5] win32u: Move NtUserShowWindow implementation from user32.

Huw Davies huw at codeweavers.com
Thu Mar 17 10:29:32 CDT 2022


From: Jacek Caban <jacek at codeweavers.com>

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/user32/combo.c          |   4 +-
 dlls/user32/defwnd.c         |   2 +-
 dlls/user32/dialog.c         |   6 +-
 dlls/user32/driver.c         |   8 +-
 dlls/user32/mdi.c            |  12 +-
 dlls/user32/message.c        |  21 +-
 dlls/user32/nonclient.c      |   6 +-
 dlls/user32/scroll.c         |   2 +-
 dlls/user32/user32.spec      |   4 +-
 dlls/user32/user_main.c      |   1 -
 dlls/user32/win.c            |  10 +-
 dlls/user32/win.h            |   6 -
 dlls/user32/winpos.c         | 228 +---------------
 dlls/win32u/driver.c         |   1 +
 dlls/win32u/gdiobj.c         |   2 +
 dlls/win32u/input.c          |   2 +-
 dlls/win32u/message.c        |   3 +
 dlls/win32u/ntuser_private.h |   7 +-
 dlls/win32u/win32u.spec      |   4 +-
 dlls/win32u/win32u_private.h |   4 +
 dlls/win32u/window.c         | 487 ++++++++++++++++++++++++++++++++++-
 dlls/win32u/wrappers.c       |  12 +
 include/ntuser.h             |   1 +
 23 files changed, 542 insertions(+), 291 deletions(-)

diff --git a/dlls/user32/combo.c b/dlls/user32/combo.c
index b375de5080c..d9123057295 100644
--- a/dlls/user32/combo.c
+++ b/dlls/user32/combo.c
@@ -1030,7 +1030,7 @@ static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
 	   RECT	rect;
 
 	   lphc->wState &= ~CBF_DROPPED;
-	   ShowWindow( lphc->hWndLBox, SW_HIDE );
+	   NtUserShowWindow( lphc->hWndLBox, SW_HIDE );
 
            if(GetCapture() == lphc->hWndLBox)
            {
@@ -1419,7 +1419,7 @@ static void CBResetPos(HEADCOMBO *combo, BOOL redraw)
         if (combo->wState & CBF_DROPPED)
         {
            combo->wState &= ~CBF_DROPPED;
-           ShowWindow(combo->hWndLBox, SW_HIDE);
+           NtUserShowWindow( combo->hWndLBox, SW_HIDE );
         }
 
         if (redraw && !(combo->wState & CBF_NOREDRAW))
diff --git a/dlls/user32/defwnd.c b/dlls/user32/defwnd.c
index 271644bb953..bd1928412e0 100644
--- a/dlls/user32/defwnd.c
+++ b/dlls/user32/defwnd.c
@@ -562,7 +562,7 @@ static LRESULT DEFWND_DefWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPa
             }
             else pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
             WIN_ReleasePtr( pWnd );
-            ShowWindow( hwnd, wParam ? SW_SHOWNOACTIVATE : SW_HIDE );
+            NtUserShowWindow( hwnd, wParam ? SW_SHOWNOACTIVATE : SW_HIDE );
             break;
         }
 
diff --git a/dlls/user32/dialog.c b/dlls/user32/dialog.c
index f9d388d0104..a3efd5b6742 100644
--- a/dlls/user32/dialog.c
+++ b/dlls/user32/dialog.c
@@ -702,7 +702,7 @@ static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCVOID dlgTemplate,
 
         if (template.style & WS_VISIBLE && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
         {
-           ShowWindow( hwnd, SW_SHOWNORMAL );   /* SW_SHOW doesn't always work */
+           NtUserShowWindow( hwnd, SW_SHOWNORMAL );   /* SW_SHOW doesn't always work */
         }
         return hwnd;
     }
@@ -793,7 +793,7 @@ INT DIALOG_DoDialogBox( HWND hwnd, HWND owner )
                 if (bFirstEmpty)
                 {
                     /* ShowWindow the first time the queue goes empty */
-                    ShowWindow( hwnd, SW_SHOWNORMAL );
+                    NtUserShowWindow( hwnd, SW_SHOWNORMAL );
                     bFirstEmpty = FALSE;
                 }
                 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & DS_NOIDLEMSG))
@@ -821,7 +821,7 @@ INT DIALOG_DoDialogBox( HWND hwnd, HWND owner )
 
             if (bFirstEmpty && msg.message == WM_TIMER)
             {
-                ShowWindow( hwnd, SW_SHOWNORMAL );
+                NtUserShowWindow( hwnd, SW_SHOWNORMAL );
                 bFirstEmpty = FALSE;
             }
         }
diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c
index ada0b8ca2f7..25ed33ff073 100644
--- a/dlls/user32/driver.c
+++ b/dlls/user32/driver.c
@@ -95,11 +95,6 @@ static void CDECL nulldrv_SetWindowText( HWND hwnd, LPCWSTR text )
 {
 }
 
-static UINT CDECL nulldrv_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp )
-{
-    return ~0; /* use default implementation */
-}
-
 static LRESULT CDECL nulldrv_SysCommand( HWND hwnd, WPARAM wparam, LPARAM lparam )
 {
     return -1;
@@ -184,7 +179,7 @@ static struct user_driver_funcs lazy_load_driver =
     nulldrv_SetWindowIcon,
     NULL,
     nulldrv_SetWindowText,
-    nulldrv_ShowWindow,
+    NULL,
     nulldrv_SysCommand,
     NULL,
     NULL,
@@ -222,7 +217,6 @@ void CDECL __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT v
     SET_USER_FUNC(MsgWaitForMultipleObjectsEx);
     SET_USER_FUNC(SetWindowIcon);
     SET_USER_FUNC(SetWindowText);
-    SET_USER_FUNC(ShowWindow);
     SET_USER_FUNC(SysCommand);
     SET_USER_FUNC(WindowPosChanging);
     SET_USER_FUNC(WindowPosChanged);
diff --git a/dlls/user32/mdi.c b/dlls/user32/mdi.c
index 3d85487f808..19db8382bd0 100644
--- a/dlls/user32/mdi.c
+++ b/dlls/user32/mdi.c
@@ -514,13 +514,13 @@ static void MDI_SwitchActiveChild( MDICLIENTINFO *ci, HWND hwndTo, BOOL activate
         {
             /* restore old MDI child */
             SendMessageW( hwndPrev, WM_SETREDRAW, FALSE, 0 );
-            ShowWindow( hwndPrev, SW_RESTORE );
+            NtUserShowWindow( hwndPrev, SW_RESTORE );
             SendMessageW( hwndPrev, WM_SETREDRAW, TRUE, 0 );
 
             /* activate new MDI child */
             NtUserSetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
             /* maximize new MDI child */
-            ShowWindow( hwndTo, SW_MAXIMIZE );
+            NtUserShowWindow( hwndTo, SW_MAXIMIZE );
         }
         /* activate new MDI child */
         NtUserSetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
@@ -547,7 +547,7 @@ static LRESULT MDIDestroyChild( HWND client, MDICLIENTINFO *ci,
             MDI_SwitchActiveChild(ci, next, TRUE);
         else
         {
-            ShowWindow(child, SW_HIDE);
+            NtUserShowWindow( child, SW_HIDE );
             if (child == ci->hwndChildMaximized)
             {
                 HWND frame = GetParent(client);
@@ -1133,7 +1133,7 @@ LRESULT MDIClientWndProc_common( HWND hwnd, UINT message, WPARAM wParam, LPARAM
         return 0;
 
       case WM_MDIMAXIMIZE:
-	ShowWindow( (HWND)wParam, SW_MAXIMIZE );
+	NtUserShowWindow( (HWND)wParam, SW_MAXIMIZE );
         return 0;
 
       case WM_MDINEXT: /* lParam != 0 means previous window */
@@ -1147,7 +1147,7 @@ LRESULT MDIClientWndProc_common( HWND hwnd, UINT message, WPARAM wParam, LPARAM
       }
 
       case WM_MDIRESTORE:
-        ShowWindow( (HWND)wParam, SW_SHOWNORMAL );
+        NtUserShowWindow( (HWND)wParam, SW_SHOWNORMAL );
         return 0;
 
       case WM_MDISETMENU:
@@ -1518,7 +1518,7 @@ LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
                 SendMessageW( hMaxChild, WM_SETREDRAW, FALSE, 0 );
 
                 MDI_RestoreFrameMenu( GetParent(client), hMaxChild );
-                ShowWindow( hMaxChild, SW_SHOWNOACTIVATE );
+                NtUserShowWindow( hMaxChild, SW_SHOWNOACTIVATE );
 
                 SendMessageW( hMaxChild, WM_SETREDRAW, TRUE, 0 );
             }
diff --git a/dlls/user32/message.c b/dlls/user32/message.c
index 0ba540d2e5d..2badec331c1 100644
--- a/dlls/user32/message.c
+++ b/dlls/user32/message.c
@@ -1857,21 +1857,12 @@ static void reply_message( struct received_message_info *info, LRESULT result, B
  */
 LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
 {
-    switch(msg)
-    {
-    case WM_WINE_SHOWWINDOW:
-        if (is_desktop_window( hwnd )) return 0;
-        return ShowWindow( hwnd, wparam );
-    default:
-        {
-            MSG m;
-            m.hwnd    = hwnd;
-            m.message = msg;
-            m.wParam  = wparam;
-            m.lParam  = lparam;
-            return NtUserCallOneParam( (UINT_PTR)&m, NtUserHandleInternalMessage );
-        }
-    }
+    MSG m;
+    m.hwnd    = hwnd;
+    m.message = msg;
+    m.wParam  = wparam;
+    m.lParam  = lparam;
+    return NtUserCallOneParam( (UINT_PTR)&m, NtUserHandleInternalMessage );
 }
 
 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
diff --git a/dlls/user32/nonclient.c b/dlls/user32/nonclient.c
index 096674db5f7..a2a49fda27b 100644
--- a/dlls/user32/nonclient.c
+++ b/dlls/user32/nonclient.c
@@ -1557,19 +1557,19 @@ LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
 
     case SC_MINIMIZE:
         ShowOwnedPopups(hwnd,FALSE);
-        ShowWindow( hwnd, SW_MINIMIZE );
+        NtUserShowWindow( hwnd, SW_MINIMIZE );
         break;
 
     case SC_MAXIMIZE:
         if (IsIconic(hwnd))
             ShowOwnedPopups(hwnd,TRUE);
-        ShowWindow( hwnd, SW_MAXIMIZE );
+        NtUserShowWindow( hwnd, SW_MAXIMIZE );
         break;
 
     case SC_RESTORE:
         if (IsIconic(hwnd))
             ShowOwnedPopups(hwnd,TRUE);
-        ShowWindow( hwnd, SW_RESTORE );
+        NtUserShowWindow( hwnd, SW_RESTORE );
         break;
 
     case SC_CLOSE:
diff --git a/dlls/user32/scroll.c b/dlls/user32/scroll.c
index d666707299f..c042b72a344 100644
--- a/dlls/user32/scroll.c
+++ b/dlls/user32/scroll.c
@@ -1973,7 +1973,7 @@ static BOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar, BOOL fShowH, BOOL fShowV
     switch(nBar)
     {
     case SB_CTL:
-        ShowWindow( hwnd, fShowH ? SW_SHOW : SW_HIDE );
+        NtUserShowWindow( hwnd, fShowH ? SW_SHOW : SW_HIDE );
         return TRUE;
 
     case SB_BOTH:
diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec
index cb18d9415c9..36ec63c21d4 100644
--- a/dlls/user32/user32.spec
+++ b/dlls/user32/user32.spec
@@ -740,8 +740,8 @@
 @ stdcall ShowOwnedPopups(long long)
 @ stdcall ShowScrollBar(long long long)
 @ stub ShowStartGlass
-@ stdcall ShowWindow(long long)
-@ stdcall ShowWindowAsync(long long)
+@ stdcall ShowWindow(long long) NtUserShowWindow
+@ stdcall ShowWindowAsync(long long) NtUserShowWindowAsync
 @ stdcall ShutdownBlockReasonCreate(long wstr)
 @ stdcall ShutdownBlockReasonDestroy(long)
 # @ stub SoftModalMessageBox
diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c
index 15293d76c41..5a3db40c93c 100644
--- a/dlls/user32/user_main.c
+++ b/dlls/user32/user_main.c
@@ -166,7 +166,6 @@ static const struct user_callbacks user_funcs =
     SendMessageW,
     SendNotifyMessageW,
     ShowCaret,
-    ShowWindow,
     WaitForInputIdle,
     free_win_ptr,
     MENU_IsMenuActive,
diff --git a/dlls/user32/win.c b/dlls/user32/win.c
index b0e6b33eb56..4d4199c67fc 100644
--- a/dlls/user32/win.c
+++ b/dlls/user32/win.c
@@ -1023,10 +1023,10 @@ HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module,
                 {
                     /* if the new window is maximized don't bother repainting */
                     SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
-                    ShowWindow( top_child, SW_SHOWNORMAL );
+                    NtUserShowWindow( top_child, SW_SHOWNORMAL );
                     SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
                 }
-                else ShowWindow( top_child, SW_SHOWNORMAL );
+                else NtUserShowWindow( top_child, SW_SHOWNORMAL );
             }
         }
     }
@@ -1303,7 +1303,7 @@ HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module,
         else if (cs->style & WS_MINIMIZE)
             sw = SW_SHOWMINIMIZED;
 
-        ShowWindow( hwnd, sw );
+        NtUserShowWindow( hwnd, sw );
         if (cs->dwExStyle & WS_EX_MDICHILD)
         {
             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
@@ -1399,7 +1399,7 @@ HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExW( DWORD exStyle, LPCWSTR className,
 BOOL WINAPI CloseWindow( HWND hwnd )
 {
     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
-    ShowWindow( hwnd, SW_MINIMIZE );
+    NtUserShowWindow( hwnd, SW_MINIMIZE );
     return TRUE;
 }
 
@@ -1410,7 +1410,7 @@ BOOL WINAPI CloseWindow( HWND hwnd )
 BOOL WINAPI OpenIcon( HWND hwnd )
 {
     if (!IsIconic( hwnd )) return FALSE;
-    ShowWindow( hwnd, SW_SHOWNORMAL );
+    NtUserShowWindow( hwnd, SW_SHOWNORMAL );
     return TRUE;
 }
 
diff --git a/dlls/user32/win.h b/dlls/user32/win.h
index 89e91a255f9..79a57de6bb9 100644
--- a/dlls/user32/win.h
+++ b/dlls/user32/win.h
@@ -42,7 +42,6 @@ extern WND *WIN_GetPtr( HWND hwnd ) DECLSPEC_HIDDEN;
 extern HWND WIN_GetFullHandle( HWND hwnd ) DECLSPEC_HIDDEN;
 extern HWND WIN_IsCurrentProcess( HWND hwnd ) DECLSPEC_HIDDEN;
 extern HWND WIN_IsCurrentThread( HWND hwnd ) DECLSPEC_HIDDEN;
-extern UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask ) DECLSPEC_HIDDEN;
 extern ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits ) DECLSPEC_HIDDEN;
 extern BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient ) DECLSPEC_HIDDEN;
 extern HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode ) DECLSPEC_HIDDEN;
@@ -94,9 +93,4 @@ static inline void mirror_rect( const RECT *window_rect, RECT *rect )
     rect->right = width - tmp;
 }
 
-static inline UINT win_get_flags( HWND hwnd )
-{
-    return win_set_flags( hwnd, 0, 0 );
-}
-
 #endif  /* __WINE_WIN_H */
diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c
index 1951f887351..4ba0c47626d 100644
--- a/dlls/user32/winpos.c
+++ b/dlls/user32/winpos.c
@@ -67,7 +67,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(win);
  */
 void WINAPI SwitchToThisWindow( HWND hwnd, BOOL alt_tab )
 {
-    if (IsIconic( hwnd )) ShowWindow( hwnd, SW_RESTORE );
+    if (IsIconic( hwnd )) NtUserShowWindow( hwnd, SW_RESTORE );
     else BringWindowToTop( hwnd );
 }
 
@@ -799,228 +799,6 @@ UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
 }
 
 
-/***********************************************************************
- *              show_window
- *
- * Implementation of ShowWindow and ShowWindowAsync.
- */
-static BOOL show_window( HWND hwnd, INT cmd )
-{
-    WND *wndPtr;
-    HWND parent;
-    DPI_AWARENESS_CONTEXT context;
-    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
-    BOOL wasVisible = (style & WS_VISIBLE) != 0;
-    BOOL showFlag = TRUE;
-    RECT newPos = {0, 0, 0, 0};
-    UINT new_swp, swp = 0;
-
-    TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible);
-
-    context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
-
-    switch(cmd)
-    {
-        case SW_HIDE:
-            if (!wasVisible) goto done;
-            showFlag = FALSE;
-            swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
-            if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
-	    break;
-
-	case SW_SHOWMINNOACTIVE:
-        case SW_MINIMIZE:
-        case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
-            swp |= SWP_NOACTIVATE | SWP_NOZORDER;
-            /* fall through */
-	case SW_SHOWMINIMIZED:
-            swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
-            swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
-            if ((style & WS_MINIMIZE) && wasVisible) goto done;
-	    break;
-
-	case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
-            if (!wasVisible) swp |= SWP_SHOWWINDOW;
-            swp |= SWP_FRAMECHANGED;
-            swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
-            if ((style & WS_MAXIMIZE) && wasVisible) goto done;
-            break;
-
-	case SW_SHOWNA:
-            swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
-            if (style & WS_CHILD) swp |= SWP_NOZORDER;
-            break;
-	case SW_SHOW:
-            if (wasVisible) goto done;
-	    swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
-            if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
-	    break;
-
-	case SW_SHOWNOACTIVATE:
-            swp |= SWP_NOACTIVATE | SWP_NOZORDER;
-            /* fall through */
-	case SW_RESTORE:
-            /* fall through */
-	case SW_SHOWNORMAL:  /* same as SW_NORMAL: */
-	case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
-            if (!wasVisible) swp |= SWP_SHOWWINDOW;
-            if (style & (WS_MINIMIZE | WS_MAXIMIZE))
-            {
-                swp |= SWP_FRAMECHANGED;
-                swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
-            }
-            else
-            {
-                if (wasVisible) goto done;
-                swp |= SWP_NOSIZE | SWP_NOMOVE;
-            }
-            if (style & WS_CHILD && !(swp & SWP_STATECHANGED)) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
-	    break;
-        default:
-            goto done;
-    }
-
-    if ((showFlag != wasVisible || cmd == SW_SHOWNA) && cmd != SW_SHOWMAXIMIZED && !(swp & SWP_STATECHANGED))
-    {
-        SendMessageW( hwnd, WM_SHOWWINDOW, showFlag, 0 );
-        if (!IsWindow( hwnd )) goto done;
-    }
-
-    if (IsRectEmpty( &newPos )) new_swp = swp;
-    else if ((new_swp = USER_Driver->pShowWindow( hwnd, cmd, &newPos, swp )) == ~0)
-    {
-        if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) new_swp = swp;
-        else if (IsIconic( hwnd ) && (newPos.left != -32000 || newPos.top != -32000))
-        {
-            OffsetRect( &newPos, -32000 - newPos.left, -32000 - newPos.top );
-            new_swp = swp & ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
-        }
-        else new_swp = swp;
-    }
-    swp = new_swp;
-
-    parent = NtUserGetAncestor( hwnd, GA_PARENT );
-    if (parent && !IsWindowVisible( parent ) && !(swp & SWP_STATECHANGED))
-    {
-        /* if parent is not visible simply toggle WS_VISIBLE and return */
-        if (showFlag) WIN_SetStyle( hwnd, WS_VISIBLE, 0 );
-        else WIN_SetStyle( hwnd, 0, WS_VISIBLE );
-    }
-    else
-        NtUserSetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
-                            newPos.right - newPos.left, newPos.bottom - newPos.top, swp );
-
-    if (cmd == SW_HIDE)
-    {
-        HWND hFocus;
-
-        /* FIXME: This will cause the window to be activated irrespective
-         * of whether it is owned by the same thread. Has to be done
-         * asynchronously.
-         */
-
-        if (hwnd == GetActiveWindow())
-            WINPOS_ActivateOtherWindow(hwnd);
-
-        /* Revert focus to parent */
-        hFocus = GetFocus();
-        if (hwnd == hFocus)
-        {
-            HWND parent = NtUserGetAncestor(hwnd, GA_PARENT);
-            if (parent == GetDesktopWindow()) parent = 0;
-            NtUserSetFocus( parent );
-        }
-        goto done;
-    }
-
-    if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) goto done;
-
-    if (wndPtr->flags & WIN_NEED_SIZE)
-    {
-        /* should happen only in CreateWindowEx() */
-	int wParam = SIZE_RESTORED;
-        RECT client;
-        LPARAM lparam;
-
-        WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &client );
-        lparam = MAKELONG( client.right - client.left, client.bottom - client.top );
-	wndPtr->flags &= ~WIN_NEED_SIZE;
-	if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
-        else if (wndPtr->dwStyle & WS_MINIMIZE)
-        {
-            wParam = SIZE_MINIMIZED;
-            lparam = 0;
-        }
-        WIN_ReleasePtr( wndPtr );
-
-        SendMessageW( hwnd, WM_SIZE, wParam, lparam );
-        SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( client.left, client.top ));
-    }
-    else WIN_ReleasePtr( wndPtr );
-
-    /* if previous state was minimized Windows sets focus to the window */
-    if (style & WS_MINIMIZE)
-    {
-        NtUserSetFocus( hwnd );
-        /* Send a WM_ACTIVATE message for a top level window, even if the window is already active */
-        if (NtUserGetAncestor( hwnd, GA_ROOT ) == hwnd && !(swp & SWP_NOACTIVATE))
-            SendMessageW( hwnd, WM_ACTIVATE, WA_ACTIVE, 0 );
-    }
-
-done:
-    SetThreadDpiAwarenessContext( context );
-    return wasVisible;
-}
-
-
-/***********************************************************************
- *		ShowWindowAsync (USER32.@)
- *
- * doesn't wait; returns immediately.
- * used by threads to toggle windows in other (possibly hanging) threads
- */
-BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
-{
-    HWND full_handle;
-
-    if (is_broadcast(hwnd))
-    {
-        SetLastError( ERROR_INVALID_PARAMETER );
-        return FALSE;
-    }
-
-    if ((full_handle = WIN_IsCurrentThread( hwnd )))
-        return show_window( full_handle, cmd );
-
-    return SendNotifyMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
-}
-
-
-/***********************************************************************
- *		ShowWindow (USER32.@)
- */
-BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
-{
-    HWND full_handle;
-
-    if (is_broadcast(hwnd))
-    {
-        SetLastError( ERROR_INVALID_PARAMETER );
-        return FALSE;
-    }
-    if ((full_handle = WIN_IsCurrentThread( hwnd )))
-        return show_window( full_handle, cmd );
-
-    if ((cmd == SW_HIDE) && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
-        return FALSE;
-
-    if ((cmd == SW_SHOW) && (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
-        return TRUE;
-
-    return SendMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
-}
-
-
 /***********************************************************************
  *		GetInternalWindowPos (USER32.@)
  */
@@ -1190,7 +968,7 @@ static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT f
                             wp.rcNormalPosition.bottom - wp.rcNormalPosition.top,
                             SWP_NOZORDER | SWP_NOACTIVATE );
 
-    ShowWindow( hwnd, wndpl->showCmd );
+    NtUserShowWindow( hwnd, wndpl->showCmd );
 
     if (IsIconic( hwnd ))
     {
@@ -1237,7 +1015,7 @@ BOOL WINAPI AnimateWindow(HWND hwnd, DWORD dwTime, DWORD dwFlags)
 		return FALSE;
 	}
 
-	ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA));
+	NtUserShowWindow( hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA) );
 
 	return TRUE;
 }
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c
index 166c2009dbc..ec8162b0284 100644
--- a/dlls/win32u/driver.c
+++ b/dlls/win32u/driver.c
@@ -1202,6 +1202,7 @@ static const struct user_driver_funcs lazy_load_driver =
     .pReleaseDC =  nulldrv_ReleaseDC,
     .pScrollDC = nulldrv_ScrollDC,
     .pSetFocus = nulldrv_SetFocus,
+    .pShowWindow = nulldrv_ShowWindow,
     .pUpdateLayeredWindow = loaderdrv_UpdateLayeredWindow,
     .pWindowMessage = nulldrv_WindowMessage,
     /* system parameters */
diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c
index 69607f0e3de..e47271e6108 100644
--- a/dlls/win32u/gdiobj.c
+++ b/dlls/win32u/gdiobj.c
@@ -1210,6 +1210,8 @@ static struct unix_funcs unix_funcs =
     NtUserSetWindowRgn,
     NtUserSetWindowWord,
     NtUserShowCursor,
+    NtUserShowWindow,
+    NtUserShowWindowAsync,
     NtUserSystemParametersInfo,
     NtUserSystemParametersInfoForDpi,
     NtUserToUnicodeEx,
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c
index bc82d5e17a3..5cd2cdd0970 100644
--- a/dlls/win32u/input.c
+++ b/dlls/win32u/input.c
@@ -1162,7 +1162,7 @@ HWND get_active_window(void)
 }
 
 /* see GetFocus */
-static HWND get_focus(void)
+HWND get_focus(void)
 {
     GUITHREADINFO info;
     info.cbSize = sizeof(info);
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c
index 690de6cdf8a..853182b6e94 100644
--- a/dlls/win32u/message.c
+++ b/dlls/win32u/message.c
@@ -46,6 +46,9 @@ LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar
     case WM_WINE_SETWINDOWPOS:
         if (is_desktop_window( hwnd )) return 0;
         return set_window_pos( (WINDOWPOS *)lparam, 0, 0 );
+    case WM_WINE_SHOWWINDOW:
+        if (is_desktop_window( hwnd )) return 0;
+        return NtUserShowWindow( hwnd, wparam );
     case WM_WINE_SETPARENT:
         if (is_desktop_window( hwnd )) return 0;
         return HandleToUlong( NtUserSetParent( hwnd, UlongToHandle(wparam) ));
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h
index 51f17f63de5..49fd22ca140 100644
--- a/dlls/win32u/ntuser_private.h
+++ b/dlls/win32u/ntuser_private.h
@@ -42,7 +42,6 @@ struct user_callbacks
     LRESULT (WINAPI *pSendMessageW)( HWND, UINT, WPARAM, LPARAM );
     BOOL (WINAPI *pSendNotifyMessageW)( HWND, UINT, WPARAM, LPARAM );
     BOOL (WINAPI *pShowCaret)( HWND hwnd );
-    BOOL (WINAPI *pShowWindow)( HWND, INT );
     DWORD (WINAPI *pWaitForInputIdle)( HANDLE, DWORD );
     void (CDECL *free_win_ptr)( struct tagWND *win );
     HWND (CDECL *is_menu_active)(void);
@@ -278,6 +277,12 @@ HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type ) DECLSPEC_
 void *free_user_handle( HANDLE handle, unsigned int type ) DECLSPEC_HIDDEN;
 void *get_user_handle_ptr( HANDLE handle, unsigned int type ) DECLSPEC_HIDDEN;
 void release_user_handle_ptr( void *ptr ) DECLSPEC_HIDDEN;
+UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask ) DECLSPEC_HIDDEN;
+
+static inline UINT win_get_flags( HWND hwnd )
+{
+    return win_set_flags( hwnd, 0, 0 );
+}
 
 WND *get_win_ptr( HWND hwnd ) DECLSPEC_HIDDEN;
 BOOL is_child( HWND parent, HWND child );
diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec
index aacfebd1b15..68348db4033 100644
--- a/dlls/win32u/win32u.spec
+++ b/dlls/win32u/win32u.spec
@@ -1261,8 +1261,8 @@
 @ stdcall NtUserShowCursor(long)
 @ stub NtUserShowScrollBar
 @ stub NtUserShowSystemCursor
-@ stub NtUserShowWindow
-@ stub NtUserShowWindowAsync
+@ stdcall NtUserShowWindow(long long)
+@ stdcall NtUserShowWindowAsync(long long)
 @ stub NtUserShutdownBlockReasonCreate
 @ stub NtUserShutdownBlockReasonQuery
 @ stub NtUserShutdownReasonDestroy
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h
index 2e8a8e3da8e..361bec31ec8 100644
--- a/dlls/win32u/win32u_private.h
+++ b/dlls/win32u/win32u_private.h
@@ -258,6 +258,8 @@ struct unix_funcs
     int      (WINAPI *pNtUserSetWindowRgn)( HWND hwnd, HRGN hrgn, BOOL redraw );
     WORD     (WINAPI *pNtUserSetWindowWord)( HWND hwnd, INT offset, WORD newval );
     INT      (WINAPI *pNtUserShowCursor)( BOOL show );
+    BOOL     (WINAPI *pNtUserShowWindow)( HWND hwnd, INT cmd );
+    BOOL     (WINAPI *pNtUserShowWindowAsync)( HWND hwnd, INT cmd );
     BOOL     (WINAPI *pNtUserSystemParametersInfo)( UINT action, UINT val, PVOID ptr, UINT winini );
     BOOL     (WINAPI *pNtUserSystemParametersInfoForDpi)( UINT action, UINT val, PVOID ptr,
                                                          UINT winini, UINT dpi );
@@ -311,6 +313,7 @@ extern BOOL unhook_windows_hook( INT id, HOOKPROC proc ) DECLSPEC_HIDDEN;
 extern LONG global_key_state_counter DECLSPEC_HIDDEN;
 extern HWND get_active_window(void) DECLSPEC_HIDDEN;
 extern BOOL get_cursor_pos( POINT *pt ) DECLSPEC_HIDDEN;
+extern HWND get_focus(void) DECLSPEC_HIDDEN;
 extern DWORD get_input_state(void) DECLSPEC_HIDDEN;
 extern BOOL WINAPI release_capture(void) DECLSPEC_HIDDEN;
 extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN;
@@ -353,6 +356,7 @@ struct tagWND;
 extern HDWP begin_defer_window_pos( INT count ) DECLSPEC_HIDDEN;
 extern void destroy_thread_windows(void) DECLSPEC_HIDDEN;
 extern LRESULT destroy_window( HWND hwnd ) DECLSPEC_HIDDEN;
+extern BOOL get_client_rect( HWND hwnd, RECT *rect ) DECLSPEC_HIDDEN;
 extern HWND get_desktop_window(void) DECLSPEC_HIDDEN;
 extern UINT get_dpi_for_window( HWND hwnd ) DECLSPEC_HIDDEN;
 extern HWND get_full_window_handle( HWND hwnd ) DECLSPEC_HIDDEN;
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c
index 1069ace0794..ab69096184c 100644
--- a/dlls/win32u/window.c
+++ b/dlls/win32u/window.c
@@ -916,6 +916,11 @@ BOOL is_iconic( HWND hwnd )
     return (get_window_long( hwnd, GWL_STYLE ) & WS_MINIMIZE) != 0;
 }
 
+static BOOL is_zoomed( HWND hwnd )
+{
+    return (get_window_long( hwnd, GWL_STYLE ) & WS_MAXIMIZE) != 0;
+}
+
 static LONG_PTR get_window_long_size( HWND hwnd, INT offset, UINT size, BOOL ansi )
 {
     LONG_PTR retval = 0;
@@ -1655,7 +1660,7 @@ BOOL get_window_rect( HWND hwnd, RECT *rect, UINT dpi )
 }
 
 /* see GetClientRect */
-static BOOL get_client_rect( HWND hwnd, RECT *rect )
+BOOL get_client_rect( HWND hwnd, RECT *rect )
 {
     return get_window_rects( hwnd, COORDS_CLIENT, NULL, rect, get_thread_dpi() );
 }
@@ -2174,14 +2179,6 @@ BOOL get_window_placement( HWND hwnd, WINDOWPLACEMENT *placement )
     return TRUE;
 }
 
-/*****************************************************************************
- *           NtUserShowWindow (win32u.@)
- */
-BOOL WINAPI NtUserShowWindow( HWND hwnd, INT cmd )
-{
-    return user_callbacks && user_callbacks->pShowWindow( hwnd, cmd );
-}
-
 /*****************************************************************************
  *           NtUserBuildHwndList (win32u.@)
  */
@@ -3179,7 +3176,7 @@ BOOL WINAPI NtUserEndDeferWindowPosEx( HDWP hdwp, BOOL async )
  *
  * Set the flags of a window and return the previous value.
  */
-static UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask )
+UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask )
 {
     WND *win = get_win_ptr( hwnd );
     UINT ret;
@@ -3361,6 +3358,255 @@ static MINMAXINFO get_min_max_info( HWND hwnd )
     return minmax;
 }
 
+static POINT get_first_minimized_child_pos( const RECT *parent, const MINIMIZEDMETRICS *mm,
+                                            int width, int height )
+{
+    POINT ret;
+
+    if (mm->iArrange & ARW_STARTRIGHT)
+        ret.x = parent->right - mm->iHorzGap - width;
+    else
+        ret.x = parent->left + mm->iHorzGap;
+    if (mm->iArrange & ARW_STARTTOP)
+        ret.y = parent->top + mm->iVertGap;
+    else
+        ret.y = parent->bottom - mm->iVertGap - height;
+
+    return ret;
+}
+
+static void get_next_minimized_child_pos( const RECT *parent, const MINIMIZEDMETRICS *mm,
+                                          int width, int height, POINT *pos )
+{
+    BOOL next;
+
+    if (mm->iArrange & ARW_UP) /* == ARW_DOWN */
+    {
+        if (mm->iArrange & ARW_STARTTOP)
+        {
+            pos->y += height + mm->iVertGap;
+            if ((next = pos->y + height > parent->bottom))
+                pos->y = parent->top + mm->iVertGap;
+        }
+        else
+        {
+            pos->y -= height + mm->iVertGap;
+            if ((next = pos->y < parent->top))
+                pos->y = parent->bottom - mm->iVertGap - height;
+        }
+
+        if (next)
+        {
+            if (mm->iArrange & ARW_STARTRIGHT)
+                pos->x -= width + mm->iHorzGap;
+            else
+                pos->x += width + mm->iHorzGap;
+        }
+    }
+    else
+    {
+        if (mm->iArrange & ARW_STARTRIGHT)
+        {
+            pos->x -= width + mm->iHorzGap;
+            if ((next = pos->x < parent->left))
+                pos->x = parent->right - mm->iHorzGap - width;
+        }
+        else
+        {
+            pos->x += width + mm->iHorzGap;
+            if ((next = pos->x + width > parent->right))
+                pos->x = parent->left + mm->iHorzGap;
+        }
+
+        if (next)
+        {
+            if (mm->iArrange & ARW_STARTTOP)
+                pos->y += height + mm->iVertGap;
+            else
+                pos->y -= height + mm->iVertGap;
+        }
+    }
+}
+
+static POINT get_minimized_pos( HWND hwnd, POINT pt )
+{
+    RECT rect, parent_rect;
+    HWND parent, child;
+    HRGN hrgn, tmp;
+    MINIMIZEDMETRICS metrics;
+    int width, height;
+
+    parent = NtUserGetAncestor( hwnd, GA_PARENT );
+    if (parent == get_desktop_window())
+    {
+        MONITORINFO mon_info;
+        HMONITOR monitor = monitor_from_window( hwnd, MONITOR_DEFAULTTOPRIMARY, get_thread_dpi() );
+
+        mon_info.cbSize = sizeof( mon_info );
+        get_monitor_info( monitor, &mon_info );
+        parent_rect = mon_info.rcWork;
+    }
+    else get_client_rect( parent, &parent_rect );
+
+    if (pt.x >= parent_rect.left && (pt.x + get_system_metrics( SM_CXMINIMIZED ) < parent_rect.right) &&
+        pt.y >= parent_rect.top  && (pt.y + get_system_metrics( SM_CYMINIMIZED ) < parent_rect.bottom))
+        return pt;  /* The icon already has a suitable position */
+
+    width  = get_system_metrics( SM_CXMINIMIZED );
+    height = get_system_metrics( SM_CYMINIMIZED );
+
+    metrics.cbSize = sizeof(metrics);
+    NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(metrics), &metrics, 0 );
+
+    /* Check if another icon already occupies this spot */
+    /* FIXME: this is completely inefficient */
+
+    hrgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
+    tmp = NtGdiCreateRectRgn( 0, 0, 0, 0 );
+    for (child = get_window_relative( parent, GW_CHILD );
+         child;
+         child = get_window_relative( child, GW_HWNDNEXT ))
+    {
+        if (child == hwnd) continue;
+        if ((get_window_long( child, GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE))
+            continue;
+        if (get_window_rects( child, COORDS_PARENT, &rect, NULL, get_thread_dpi() ))
+        {
+            NtGdiSetRectRgn( tmp, rect.left, rect.top, rect.right, rect.bottom );
+            NtGdiCombineRgn( hrgn, hrgn, tmp, RGN_OR );
+        }
+    }
+    NtGdiDeleteObjectApp( tmp );
+
+    pt = get_first_minimized_child_pos( &parent_rect, &metrics, width, height );
+    for (;;)
+    {
+        set_rect( &rect, pt.x, pt.y, pt.x + width, pt.y + height );
+        if (!NtGdiRectInRegion( hrgn, &rect ))
+            break;
+
+        get_next_minimized_child_pos( &parent_rect, &metrics, width, height, &pt );
+    }
+
+    NtGdiDeleteObjectApp( hrgn );
+    return pt;
+}
+
+/***********************************************************************
+ *           window_min_maximize
+ */
+static UINT window_min_maximize( HWND hwnd, UINT cmd, RECT *rect )
+{
+    UINT swp_flags = 0;
+    LONG old_style;
+    MINMAXINFO minmax;
+    WINDOWPLACEMENT wpl;
+
+    TRACE( "%p %u\n", hwnd, cmd );
+
+    wpl.length = sizeof(wpl);
+    get_window_placement( hwnd, &wpl );
+
+    if (call_hooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE ))
+        return SWP_NOSIZE | SWP_NOMOVE;
+
+    if (is_iconic( hwnd ))
+    {
+        switch (cmd)
+        {
+        case SW_SHOWMINNOACTIVE:
+        case SW_SHOWMINIMIZED:
+        case SW_FORCEMINIMIZE:
+        case SW_MINIMIZE:
+            wpl.ptMinPosition = get_minimized_pos( hwnd, wpl.ptMinPosition );
+
+            set_rect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
+                      wpl.ptMinPosition.x + get_system_metrics( SM_CXMINIMIZED ),
+                      wpl.ptMinPosition.y + get_system_metrics( SM_CYMINIMIZED ));
+            return SWP_NOSIZE | SWP_NOMOVE;
+        }
+        if (!send_message( hwnd, WM_QUERYOPEN, 0, 0 )) return SWP_NOSIZE | SWP_NOMOVE;
+        swp_flags |= SWP_NOCOPYBITS;
+    }
+
+    switch( cmd )
+    {
+    case SW_SHOWMINNOACTIVE:
+    case SW_SHOWMINIMIZED:
+    case SW_FORCEMINIMIZE:
+    case SW_MINIMIZE:
+        if (is_zoomed( hwnd )) win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
+        else win_set_flags( hwnd, 0, WIN_RESTORE_MAX );
+
+        if (get_focus() == hwnd)
+        {
+            if (get_window_long( hwnd, GWL_STYLE ) & WS_CHILD)
+                NtUserSetFocus( NtUserGetAncestor( hwnd, GA_PARENT ));
+            else
+                NtUserSetFocus( 0 );
+        }
+
+        old_style = set_window_style( hwnd, WS_MINIMIZE, WS_MAXIMIZE );
+
+        wpl.ptMinPosition = get_minimized_pos( hwnd, wpl.ptMinPosition );
+
+        if (!(old_style & WS_MINIMIZE)) swp_flags |= SWP_STATECHANGED;
+        set_rect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
+                  wpl.ptMinPosition.x + get_system_metrics(SM_CXMINIMIZED),
+                  wpl.ptMinPosition.y + get_system_metrics(SM_CYMINIMIZED) );
+        swp_flags |= SWP_NOCOPYBITS;
+        break;
+
+    case SW_MAXIMIZE:
+        old_style = get_window_long( hwnd, GWL_STYLE );
+        if ((old_style & WS_MAXIMIZE) && (old_style & WS_VISIBLE)) return SWP_NOSIZE | SWP_NOMOVE;
+
+        minmax = get_min_max_info( hwnd );
+
+        old_style = set_window_style( hwnd, WS_MAXIMIZE, WS_MINIMIZE );
+        if (old_style & WS_MINIMIZE)
+            win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
+
+        if (!(old_style & WS_MAXIMIZE)) swp_flags |= SWP_STATECHANGED;
+        set_rect( rect, minmax.ptMaxPosition.x, minmax.ptMaxPosition.y,
+                  minmax.ptMaxPosition.x + minmax.ptMaxSize.x,
+                  minmax.ptMaxPosition.y + minmax.ptMaxSize.y );
+        break;
+
+    case SW_SHOWNOACTIVATE:
+        win_set_flags( hwnd, 0, WIN_RESTORE_MAX );
+        /* fall through */
+    case SW_SHOWNORMAL:
+    case SW_RESTORE:
+    case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
+        old_style = set_window_style( hwnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
+        if (old_style & WS_MINIMIZE)
+        {
+            if (win_get_flags( hwnd ) & WIN_RESTORE_MAX)
+            {
+                /* Restore to maximized position */
+                minmax = get_min_max_info( hwnd );
+                set_window_style( hwnd, WS_MAXIMIZE, 0 );
+                swp_flags |= SWP_STATECHANGED;
+                set_rect( rect, minmax.ptMaxPosition.x, minmax.ptMaxPosition.y,
+                          minmax.ptMaxPosition.x + minmax.ptMaxSize.x,
+                          minmax.ptMaxPosition.y + minmax.ptMaxSize.y );
+                break;
+            }
+        }
+        else if (!(old_style & WS_MAXIMIZE)) break;
+
+        swp_flags |= SWP_STATECHANGED;
+
+        /* Restore to normal position */
+
+        *rect = wpl.rcNormalPosition;
+        break;
+    }
+
+    return swp_flags;
+}
+
 /*******************************************************************
  *           update_window_state
  *
@@ -3387,6 +3633,227 @@ void update_window_state( HWND hwnd )
     set_thread_dpi_awareness_context( context );
 }
 
+/***********************************************************************
+ *              show_window
+ *
+ * Implementation of ShowWindow and ShowWindowAsync.
+ */
+static BOOL show_window( HWND hwnd, INT cmd )
+{
+    WND *win;
+    HWND parent;
+    DPI_AWARENESS_CONTEXT context;
+    LONG style = get_window_long( hwnd, GWL_STYLE );
+    BOOL was_visible = (style & WS_VISIBLE) != 0;
+    BOOL show_flag = TRUE;
+    RECT newPos = {0, 0, 0, 0};
+    UINT new_swp, swp = 0;
+
+    TRACE( "hwnd=%p, cmd=%d, was_visible %d\n", hwnd, cmd, was_visible );
+
+    context = set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd ));
+
+    switch(cmd)
+    {
+    case SW_HIDE:
+        if (!was_visible) goto done;
+        show_flag = FALSE;
+        swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
+        if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+        break;
+
+    case SW_SHOWMINNOACTIVE:
+    case SW_MINIMIZE:
+    case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
+        swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+        /* fall through */
+    case SW_SHOWMINIMIZED:
+        swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
+        swp |= window_min_maximize( hwnd, cmd, &newPos );
+        if ((style & WS_MINIMIZE) && was_visible) goto done;
+        break;
+
+    case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
+        if (!was_visible) swp |= SWP_SHOWWINDOW;
+        swp |= SWP_FRAMECHANGED;
+        swp |= window_min_maximize( hwnd, SW_MAXIMIZE, &newPos );
+        if ((style & WS_MAXIMIZE) && was_visible) goto done;
+        break;
+
+    case SW_SHOWNA:
+        swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
+        if (style & WS_CHILD) swp |= SWP_NOZORDER;
+        break;
+
+    case SW_SHOW:
+        if (was_visible) goto done;
+        swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
+        if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+        break;
+
+    case SW_SHOWNOACTIVATE:
+        swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+        /* fall through */
+    case SW_RESTORE:
+        /* fall through */
+    case SW_SHOWNORMAL:  /* same as SW_NORMAL: */
+    case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
+        if (!was_visible) swp |= SWP_SHOWWINDOW;
+        if (style & (WS_MINIMIZE | WS_MAXIMIZE))
+        {
+            swp |= SWP_FRAMECHANGED;
+            swp |= window_min_maximize( hwnd, cmd, &newPos );
+        }
+        else
+        {
+            if (was_visible) goto done;
+            swp |= SWP_NOSIZE | SWP_NOMOVE;
+        }
+        if (style & WS_CHILD && !(swp & SWP_STATECHANGED)) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+        break;
+
+    default:
+        goto done;
+    }
+
+    if ((show_flag != was_visible || cmd == SW_SHOWNA) && cmd != SW_SHOWMAXIMIZED && !(swp & SWP_STATECHANGED))
+    {
+        send_message( hwnd, WM_SHOWWINDOW, show_flag, 0 );
+        if (!is_window( hwnd )) goto done;
+    }
+
+    if (IsRectEmpty( &newPos )) new_swp = swp;
+    else if ((new_swp = user_driver->pShowWindow( hwnd, cmd, &newPos, swp )) == ~0)
+    {
+        if (get_window_long( hwnd, GWL_STYLE ) & WS_CHILD) new_swp = swp;
+        else if (is_iconic( hwnd ) && (newPos.left != -32000 || newPos.top != -32000))
+        {
+            offset_rect( &newPos, -32000 - newPos.left, -32000 - newPos.top );
+            new_swp = swp & ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
+        }
+        else new_swp = swp;
+    }
+    swp = new_swp;
+
+    parent = NtUserGetAncestor( hwnd, GA_PARENT );
+    if (parent && !is_window_visible( parent ) && !(swp & SWP_STATECHANGED))
+    {
+        /* if parent is not visible simply toggle WS_VISIBLE and return */
+        if (show_flag) set_window_style( hwnd, WS_VISIBLE, 0 );
+        else set_window_style( hwnd, 0, WS_VISIBLE );
+    }
+    else
+        NtUserSetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
+                            newPos.right - newPos.left, newPos.bottom - newPos.top, swp );
+
+    if (cmd == SW_HIDE)
+    {
+        HWND hFocus;
+
+        /* FIXME: This will cause the window to be activated irrespective
+         * of whether it is owned by the same thread. Has to be done
+         * asynchronously.
+         */
+
+        if (hwnd == get_active_window()) activate_other_window( hwnd );
+
+        /* Revert focus to parent */
+        hFocus = get_focus();
+        if (hwnd == hFocus)
+        {
+            HWND parent = NtUserGetAncestor(hwnd, GA_PARENT);
+            if (parent == get_desktop_window()) parent = 0;
+            NtUserSetFocus(parent);
+        }
+        goto done;
+    }
+
+    if (!(win = get_win_ptr( hwnd )) || win == WND_OTHER_PROCESS) goto done;
+
+    if (win->flags & WIN_NEED_SIZE)
+    {
+        /* should happen only in CreateWindowEx() */
+        int wParam = SIZE_RESTORED;
+        RECT client;
+        LPARAM lparam;
+
+        get_window_rects( hwnd, COORDS_PARENT, NULL, &client, get_thread_dpi() );
+        lparam = MAKELONG( client.right - client.left, client.bottom - client.top );
+        win->flags &= ~WIN_NEED_SIZE;
+        if (win->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
+        else if (win->dwStyle & WS_MINIMIZE)
+        {
+            wParam = SIZE_MINIMIZED;
+            lparam = 0;
+        }
+        release_win_ptr( win );
+
+        send_message( hwnd, WM_SIZE, wParam, lparam );
+        send_message( hwnd, WM_MOVE, 0, MAKELONG( client.left, client.top ));
+    }
+    else release_win_ptr( win );
+
+    /* if previous state was minimized Windows sets focus to the window */
+    if (style & WS_MINIMIZE)
+    {
+        NtUserSetFocus( hwnd );
+        /* Send a WM_ACTIVATE message for a top level window, even if the window is already active */
+        if (NtUserGetAncestor( hwnd, GA_ROOT ) == hwnd && !(swp & SWP_NOACTIVATE))
+            send_message( hwnd, WM_ACTIVATE, WA_ACTIVE, 0 );
+    }
+
+done:
+    set_thread_dpi_awareness_context( context );
+    return was_visible;
+}
+
+/***********************************************************************
+ *           NtUserShowWindowAsync (win32u.@)
+ *
+ * doesn't wait; returns immediately.
+ * used by threads to toggle windows in other (possibly hanging) threads
+ */
+BOOL WINAPI NtUserShowWindowAsync( HWND hwnd, INT cmd )
+{
+    HWND full_handle;
+
+    if (is_broadcast(hwnd))
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+
+    if ((full_handle = is_current_thread_window( hwnd )))
+        return show_window( full_handle, cmd );
+
+    return NtUserMessageCall( hwnd, WM_WINE_SHOWWINDOW, cmd, 0, 0,
+                              FNID_SENDNOTIFYMESSAGE, FALSE );
+}
+
+/***********************************************************************
+ *           NtUserShowWindow (win32u.@)
+ */
+BOOL WINAPI NtUserShowWindow( HWND hwnd, INT cmd )
+{
+    HWND full_handle;
+
+    if (is_broadcast(hwnd))
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+    if ((full_handle = is_current_thread_window( hwnd )))
+        return show_window( full_handle, cmd );
+
+    if ((cmd == SW_HIDE) && !(get_window_long( hwnd, GWL_STYLE ) & WS_VISIBLE))
+        return FALSE;
+
+    if ((cmd == SW_SHOW) && (get_window_long( hwnd, GWL_STYLE ) & WS_VISIBLE))
+        return TRUE;
+
+    return send_message( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
+}
+
 /*******************************************************************
  *           NtUserFlashWindowEx (win32u.@)
  */
diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c
index da1957c8c88..6cb3a6896b5 100644
--- a/dlls/win32u/wrappers.c
+++ b/dlls/win32u/wrappers.c
@@ -1075,6 +1075,18 @@ INT WINAPI NtUserShowCursor( BOOL show )
     return unix_funcs->pNtUserShowCursor( show );
 }
 
+BOOL WINAPI NtUserShowWindowAsync( HWND hwnd, INT cmd )
+{
+    if (!unix_funcs) return FALSE;
+    return unix_funcs->pNtUserShowWindowAsync( hwnd, cmd );
+}
+
+BOOL WINAPI NtUserShowWindow( HWND hwnd, INT cmd )
+{
+    if (!unix_funcs) return FALSE;
+    return unix_funcs->pNtUserShowWindow( hwnd, cmd );
+}
+
 BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, PVOID ptr, UINT winini )
 {
     if (!unix_funcs) return FALSE;
diff --git a/include/ntuser.h b/include/ntuser.h
index 274c0cf31c9..6526d190e28 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -422,6 +422,7 @@ HWINEVENTHOOK WINAPI NtUserSetWinEventHook( DWORD event_min, DWORD event_max, HM
                                             DWORD pid, DWORD tid, DWORD flags );
 INT     WINAPI NtUserShowCursor( BOOL show );
 BOOL    WINAPI NtUserShowWindow( HWND hwnd, INT cmd );
+BOOL    WINAPI NtUserShowWindowAsync( HWND hwnd, INT cmd );
 BOOL    WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT winini );
 BOOL    WINAPI NtUserSystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi );
 INT     WINAPI NtUserToUnicodeEx( UINT virt, UINT scan, const BYTE *state,
-- 
2.23.0




More information about the wine-devel mailing list