[PATCH 7/7] win32u: Move SC_SIZE and SC_MOVE handling from user32.

Jacek Caban wine at gitlab.winehq.org
Wed Jun 8 19:14:36 CDT 2022


From: Jacek Caban <jacek at codeweavers.com>

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
---
 dlls/user32/nonclient.c      |   5 -
 dlls/user32/win.h            |   1 -
 dlls/user32/winpos.c         | 406 --------------------------------
 dlls/win32u/dc.c             |  10 +
 dlls/win32u/defwnd.c         | 437 +++++++++++++++++++++++++++++++++++
 dlls/win32u/win32u_private.h |   2 +
 dlls/win32u/window.c         |   8 +-
 include/ntgdi.h              |   2 +
 include/ntuser.h             |   8 -
 9 files changed, 453 insertions(+), 426 deletions(-)

diff --git a/dlls/user32/nonclient.c b/dlls/user32/nonclient.c
index e677f1aeb66..2ad40b8b116 100644
--- a/dlls/user32/nonclient.c
+++ b/dlls/user32/nonclient.c
@@ -1545,11 +1545,6 @@ LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
 
     switch (wParam & 0xfff0)
     {
-    case SC_SIZE:
-    case SC_MOVE:
-        WINPOS_SysCommandSizeMove( hwnd, wParam );
-        break;
-
     case SC_CLOSE:
         return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
 
diff --git a/dlls/user32/win.h b/dlls/user32/win.h
index 9d42aef6645..1dfc8eb0ad1 100644
--- a/dlls/user32/win.h
+++ b/dlls/user32/win.h
@@ -57,7 +57,6 @@ static inline void WIN_ReleasePtr( WND *ptr )
 extern LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL unicode ) DECLSPEC_HIDDEN;
 
 extern void WINPOS_ActivateOtherWindow( HWND hwnd ) DECLSPEC_HIDDEN;
-extern void WINPOS_SysCommandSizeMove( HWND hwnd, WPARAM wParam ) DECLSPEC_HIDDEN;
 
 extern UINT get_monitor_dpi( HMONITOR monitor ) DECLSPEC_HIDDEN;
 extern UINT get_win_monitor_dpi( HWND hwnd ) DECLSPEC_HIDDEN;
diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c
index d38a3df18da..f7f4e8bb427 100644
--- a/dlls/user32/winpos.c
+++ b/dlls/user32/winpos.c
@@ -19,31 +19,12 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <string.h>
-#include "ntstatus.h"
-#define WIN32_NO_STATUS
 #include "user_private.h"
-#include "winerror.h"
-#include "controls.h"
 #include "win.h"
-#include "wine/server.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(win);
 
-#define HAS_THICKFRAME(style) \
-    (((style) & WS_THICKFRAME) && \
-     !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
-
-#define ON_LEFT_BORDER(hit) \
- (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
-#define ON_RIGHT_BORDER(hit) \
- (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
-#define ON_TOP_BORDER(hit) \
- (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
-#define ON_BOTTOM_BORDER(hit) \
- (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
-
 
 /***********************************************************************
  *		SwitchToThisWindow (USER32.@)
@@ -358,390 +339,3 @@ UINT WINAPI ArrangeIconicWindows( HWND parent )
 {
     return NtUserArrangeIconicWindows( parent );
 }
-
-
-/***********************************************************************
- *           draw_moving_frame
- *
- * Draw the frame used when moving or resizing window.
- */
-static void draw_moving_frame( HWND parent, HDC hdc, RECT *screen_rect, BOOL thickframe )
-{
-    RECT rect = *screen_rect;
-
-    if (parent) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
-    if (thickframe)
-    {
-        const int width = GetSystemMetrics(SM_CXFRAME);
-        const int height = GetSystemMetrics(SM_CYFRAME);
-
-        HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
-        PatBlt( hdc, rect.left, rect.top,
-                rect.right - rect.left - width, height, PATINVERT );
-        PatBlt( hdc, rect.left, rect.top + height, width,
-                rect.bottom - rect.top - height, PATINVERT );
-        PatBlt( hdc, rect.left + width, rect.bottom - 1,
-                rect.right - rect.left - width, -height, PATINVERT );
-        PatBlt( hdc, rect.right - 1, rect.top, -width,
-                rect.bottom - rect.top - height, PATINVERT );
-        SelectObject( hdc, hbrush );
-    }
-    else DrawFocusRect( hdc, &rect );
-}
-
-
-/***********************************************************************
- *           start_size_move
- *
- * Initialization of a move or resize, when initiated from a menu choice.
- * Return hit test code for caption or sizing border.
- */
-static LONG start_size_move( HWND hwnd, WPARAM wParam, POINT *capturePoint, LONG style )
-{
-    LONG hittest = 0;
-    POINT pt;
-    MSG msg;
-    RECT rectWindow;
-
-    GetWindowRect( hwnd, &rectWindow );
-
-    if ((wParam & 0xfff0) == SC_MOVE)
-    {
-        /* Move pointer at the center of the caption */
-        RECT rect = rectWindow;
-        /* Note: to be exactly centered we should take the different types
-         * of border into account, but it shouldn't make more than a few pixels
-         * of difference so let's not bother with that */
-        rect.top += GetSystemMetrics(SM_CYBORDER);
-        if (style & WS_SYSMENU)
-            rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
-        if (style & WS_MINIMIZEBOX)
-            rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
-        if (style & WS_MAXIMIZEBOX)
-            rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
-        pt.x = (rect.right + rect.left) / 2;
-        pt.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
-        hittest = HTCAPTION;
-        *capturePoint = pt;
-    }
-    else  /* SC_SIZE */
-    {
-        NtUserSetCursor( LoadCursorW( 0, (LPWSTR)IDC_SIZEALL ) );
-        pt.x = pt.y = 0;
-        while(!hittest)
-        {
-            if (!GetMessageW( &msg, 0, 0, 0 )) return 0;
-            if (NtUserCallMsgFilter( &msg, MSGF_SIZE )) continue;
-
-            switch(msg.message)
-            {
-            case WM_MOUSEMOVE:
-                pt.x = min( max( msg.pt.x, rectWindow.left ), rectWindow.right - 1 );
-                pt.y = min( max( msg.pt.y, rectWindow.top ), rectWindow.bottom - 1 );
-                hittest = SendMessageW( hwnd, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ) );
-                if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0;
-                break;
-
-            case WM_LBUTTONUP:
-                return 0;
-
-            case WM_KEYDOWN:
-                switch(msg.wParam)
-                {
-                case VK_UP:
-                    hittest = HTTOP;
-                    pt.x =(rectWindow.left+rectWindow.right)/2;
-                    pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
-                    break;
-                case VK_DOWN:
-                    hittest = HTBOTTOM;
-                    pt.x =(rectWindow.left+rectWindow.right)/2;
-                    pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
-                    break;
-                case VK_LEFT:
-                    hittest = HTLEFT;
-                    pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
-                    pt.y =(rectWindow.top+rectWindow.bottom)/2;
-                    break;
-                case VK_RIGHT:
-                    hittest = HTRIGHT;
-                    pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
-                    pt.y =(rectWindow.top+rectWindow.bottom)/2;
-                    break;
-                case VK_RETURN:
-                case VK_ESCAPE:
-                    return 0;
-                }
-                break;
-            default:
-                TranslateMessage( &msg );
-                DispatchMessageW( &msg );
-                break;
-            }
-        }
-        *capturePoint = pt;
-    }
-    NtUserSetCursorPos( pt.x, pt.y );
-    SendMessageW( hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
-    return hittest;
-}
-
-
-/***********************************************************************
- *           WINPOS_SysCommandSizeMove
- *
- * Perform SC_MOVE and SC_SIZE commands.
- */
-void WINPOS_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
-{
-    MSG msg;
-    RECT sizingRect, mouseRect, origRect;
-    HDC hdc;
-    HWND parent;
-    LONG hittest = (LONG)(wParam & 0x0f);
-    WPARAM syscommand = wParam & 0xfff0;
-    MINMAXINFO minmax;
-    POINT capturePoint, pt;
-    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
-    BOOL    thickframe = HAS_THICKFRAME( style );
-    BOOL    moved = FALSE;
-    DWORD     dwPoint = GetMessagePos ();
-    BOOL DragFullWindows = TRUE;
-    HMONITOR mon = 0;
-
-    if (IsZoomed(hwnd) || !IsWindowVisible(hwnd)) return;
-
-    pt.x = (short)LOWORD(dwPoint);
-    pt.y = (short)HIWORD(dwPoint);
-    capturePoint = pt;
-    NtUserClipCursor( NULL );
-
-    TRACE("hwnd %p command %04Ix, hittest %ld, pos %ld,%ld\n",
-          hwnd, syscommand, hittest, pt.x, pt.y);
-
-    if (syscommand == SC_MOVE)
-    {
-        if (!hittest) hittest = start_size_move( hwnd, wParam, &capturePoint, style );
-        if (!hittest) return;
-    }
-    else  /* SC_SIZE */
-    {
-        if ( hittest && (syscommand != SC_MOUSEMENU) )
-            hittest += (HTLEFT - WMSZ_LEFT);
-        else
-        {
-            set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
-            hittest = start_size_move( hwnd, wParam, &capturePoint, style );
-            if (!hittest)
-            {
-                set_capture_window( 0, GUI_INMOVESIZE, NULL );
-                return;
-            }
-        }
-    }
-
-      /* Get min/max info */
-
-    minmax = NtUserGetMinMaxInfo( hwnd );
-    WIN_GetRectangles( hwnd, COORDS_PARENT, &sizingRect, NULL );
-    origRect = sizingRect;
-    if (style & WS_CHILD)
-    {
-        parent = GetParent(hwnd);
-        GetClientRect( parent, &mouseRect );
-        MapWindowPoints( parent, 0, (LPPOINT)&mouseRect, 2 );
-        MapWindowPoints( parent, 0, (LPPOINT)&sizingRect, 2 );
-    }
-    else
-    {
-        parent = 0;
-        mouseRect = get_virtual_screen_rect();
-        mon = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
-    }
-
-    if (ON_LEFT_BORDER(hittest))
-    {
-        mouseRect.left  = max( mouseRect.left, sizingRect.right-minmax.ptMaxTrackSize.x+capturePoint.x-sizingRect.left );
-        mouseRect.right = min( mouseRect.right, sizingRect.right-minmax.ptMinTrackSize.x+capturePoint.x-sizingRect.left );
-    }
-    else if (ON_RIGHT_BORDER(hittest))
-    {
-        mouseRect.left  = max( mouseRect.left, sizingRect.left+minmax.ptMinTrackSize.x+capturePoint.x-sizingRect.right );
-        mouseRect.right = min( mouseRect.right, sizingRect.left+minmax.ptMaxTrackSize.x+capturePoint.x-sizingRect.right );
-    }
-    if (ON_TOP_BORDER(hittest))
-    {
-        mouseRect.top    = max( mouseRect.top, sizingRect.bottom-minmax.ptMaxTrackSize.y+capturePoint.y-sizingRect.top );
-        mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minmax.ptMinTrackSize.y+capturePoint.y-sizingRect.top);
-    }
-    else if (ON_BOTTOM_BORDER(hittest))
-    {
-        mouseRect.top    = max( mouseRect.top, sizingRect.top+minmax.ptMinTrackSize.y+capturePoint.y-sizingRect.bottom );
-        mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+minmax.ptMaxTrackSize.y+capturePoint.y-sizingRect.bottom );
-    }
-
-    /* Retrieve a default cache DC (without using the window style) */
-    hdc = NtUserGetDCEx( parent, 0, DCX_CACHE );
-
-    /* we only allow disabling the full window drag for child windows */
-    if (parent) SystemParametersInfoW( SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0 );
-
-    /* repaint the window before moving it around */
-    NtUserRedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
-
-    SendMessageW( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
-    set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
-
-    while(1)
-    {
-        int dx = 0, dy = 0;
-
-        if (!GetMessageW( &msg, 0, 0, 0 )) break;
-        if (NtUserCallMsgFilter( &msg, MSGF_SIZE )) continue;
-
-        /* Exit on button-up, Return, or Esc */
-        if ((msg.message == WM_LBUTTONUP) ||
-            ((msg.message == WM_KEYDOWN) &&
-             ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
-
-        if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
-        {
-            TranslateMessage( &msg );
-            DispatchMessageW( &msg );
-            continue;  /* We are not interested in other messages */
-        }
-
-        pt = msg.pt;
-
-        if (msg.message == WM_KEYDOWN) switch(msg.wParam)
-        {
-        case VK_UP:    pt.y -= 8; break;
-        case VK_DOWN:  pt.y += 8; break;
-        case VK_LEFT:  pt.x -= 8; break;
-        case VK_RIGHT: pt.x += 8; break;
-        }
-
-        pt.x = max( pt.x, mouseRect.left );
-        pt.x = min( pt.x, mouseRect.right - 1 );
-        pt.y = max( pt.y, mouseRect.top );
-        pt.y = min( pt.y, mouseRect.bottom - 1 );
-
-        if (!parent)
-        {
-            HMONITOR newmon;
-            MONITORINFO info;
-
-            if ((newmon = MonitorFromPoint( pt, MONITOR_DEFAULTTONULL )))
-                mon = newmon;
-
-            info.cbSize = sizeof(info);
-            if (mon && GetMonitorInfoW( mon, &info ))
-            {
-                pt.x = max( pt.x, info.rcWork.left );
-                pt.x = min( pt.x, info.rcWork.right - 1 );
-                pt.y = max( pt.y, info.rcWork.top );
-                pt.y = min( pt.y, info.rcWork.bottom - 1 );
-            }
-        }
-
-        dx = pt.x - capturePoint.x;
-        dy = pt.y - capturePoint.y;
-
-        if (dx || dy)
-        {
-            if( !moved )
-            {
-                moved = TRUE;
-                if (!DragFullWindows)
-                    draw_moving_frame( parent, hdc, &sizingRect, thickframe );
-            }
-
-            if (msg.message == WM_KEYDOWN) NtUserSetCursorPos( pt.x, pt.y );
-            else
-            {
-                if (!DragFullWindows) draw_moving_frame( parent, hdc, &sizingRect, thickframe );
-                if (hittest == HTCAPTION || hittest == HTBORDER) OffsetRect( &sizingRect, dx, dy );
-                if (ON_LEFT_BORDER(hittest)) sizingRect.left += dx;
-                else if (ON_RIGHT_BORDER(hittest)) sizingRect.right += dx;
-                if (ON_TOP_BORDER(hittest)) sizingRect.top += dy;
-                else if (ON_BOTTOM_BORDER(hittest)) sizingRect.bottom += dy;
-                capturePoint = pt;
-
-                /* determine the hit location */
-                if (syscommand == SC_SIZE && hittest != HTBORDER)
-                {
-                    WPARAM wpSizingHit = 0;
-
-                    if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
-                        wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
-                    SendMessageW( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&sizingRect );
-                }
-                else
-                    SendMessageW( hwnd, WM_MOVING, 0, (LPARAM)&sizingRect );
-
-                if (!DragFullWindows)
-                    draw_moving_frame( parent, hdc, &sizingRect, thickframe );
-                else
-                {
-                    RECT rect = sizingRect;
-                    MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
-                    NtUserSetWindowPos( hwnd, 0, rect.left, rect.top,
-                                        rect.right - rect.left, rect.bottom - rect.top,
-                                        (hittest == HTCAPTION) ? SWP_NOSIZE : 0 );
-                }
-            }
-        }
-    }
-
-    if (moved && !DragFullWindows)
-    {
-        draw_moving_frame( parent, hdc, &sizingRect, thickframe );
-    }
-
-    set_capture_window( 0, GUI_INMOVESIZE, NULL );
-    NtUserReleaseDC( parent, hdc );
-    if (parent) MapWindowPoints( 0, parent, (POINT *)&sizingRect, 2 );
-
-    if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE ))
-        moved = FALSE;
-
-    SendMessageW( hwnd, WM_EXITSIZEMOVE, 0, 0 );
-    SendMessageW( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
-
-    /* window moved or resized */
-    if (moved)
-    {
-        /* if the moving/resizing isn't canceled call SetWindowPos
-         * with the new position or the new size of the window
-         */
-        if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
-        {
-            /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
-            if (!DragFullWindows)
-                NtUserSetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
-                                    sizingRect.right - sizingRect.left,
-                                    sizingRect.bottom - sizingRect.top,
-                                    ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
-        }
-        else
-        { /* restore previous size/position */
-            if(DragFullWindows)
-                NtUserSetWindowPos( hwnd, 0, origRect.left, origRect.top,
-                                    origRect.right - origRect.left,
-                                    origRect.bottom - origRect.top,
-                                    ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
-        }
-    }
-
-    if (IsIconic(hwnd))
-    {
-        /* Single click brings up the system menu when iconized */
-
-        if( !moved )
-        {
-            if(style & WS_SYSMENU )
-                SendMessageW( hwnd, WM_SYSCOMMAND,
-                              SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
-        }
-    }
-}
diff --git a/dlls/win32u/dc.c b/dlls/win32u/dc.c
index 95dd2651929..f50c13d18bb 100644
--- a/dlls/win32u/dc.c
+++ b/dlls/win32u/dc.c
@@ -932,6 +932,11 @@ BOOL WINAPI NtGdiGetAndSetDCDword( HDC hdc, UINT method, DWORD value, DWORD *pre
         set_bk_color( dc, value );
         break;
 
+    case NtGdiSetBkMode:
+        prev = dc->attr->background_mode;
+        dc->attr->background_mode = value;
+        break;
+
     case NtGdiSetTextColor:
         prev = dc->attr->text_color;
         set_text_color( dc, value );
@@ -956,6 +961,11 @@ BOOL WINAPI NtGdiGetAndSetDCDword( HDC hdc, UINT method, DWORD value, DWORD *pre
         ret = set_graphics_mode( dc, value );
         break;
 
+    case NtGdiSetROP2:
+        prev = dc->attr->rop_mode;
+        dc->attr->rop_mode = value;
+        break;
+
     default:
         WARN( "unknown method %u\n", method );
         ret = FALSE;
diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c
index 9b4edc90eaa..3dc0ff1187b 100644
--- a/dlls/win32u/defwnd.c
+++ b/dlls/win32u/defwnd.c
@@ -42,6 +42,30 @@ void fill_rect( HDC dc, const RECT *rect, HBRUSH hbrush )
     if (prev_brush) NtGdiSelectBrush( dc, prev_brush );
 }
 
+/* see DrawFocusRect */
+static BOOL draw_focus_rect( HDC hdc, const RECT *rc )
+{
+    DWORD prev_draw_mode, prev_bk_mode;
+    HPEN prev_pen, pen;
+    HBRUSH prev_brush;
+
+    prev_brush = NtGdiSelectBrush(hdc, GetStockObject(NULL_BRUSH));
+    pen = NtGdiExtCreatePen( PS_COSMETIC|PS_ALTERNATE, 1, BS_SOLID,
+                             0, 0, 0, 0, NULL, 0, FALSE, NULL );
+    prev_pen = NtGdiSelectPen(hdc, pen);
+    NtGdiGetAndSetDCDword( hdc, NtGdiSetROP2, R2_NOT, &prev_draw_mode );
+    NtGdiGetAndSetDCDword( hdc, NtGdiSetBkMode, TRANSPARENT, &prev_bk_mode );
+
+    NtGdiRectangle( hdc, rc->left, rc->top, rc->right, rc->bottom );
+
+    NtGdiGetAndSetDCDword( hdc, NtGdiSetBkMode, prev_bk_mode, NULL );
+    NtGdiGetAndSetDCDword( hdc, NtGdiSetROP2, prev_draw_mode, NULL );
+    NtGdiSelectPen( hdc, prev_pen );
+    NtGdiDeleteObjectApp( pen );
+    NtGdiSelectBrush( hdc, prev_brush );
+    return TRUE;
+}
+
 /***********************************************************************
  *           AdjustWindowRectEx (win32u.so)
  */
@@ -216,6 +240,414 @@ static LONG handle_window_pos_changing( HWND hwnd, WINDOWPOS *winpos )
     return 0;
 }
 
+/***********************************************************************
+ *           draw_moving_frame
+ *
+ * Draw the frame used when moving or resizing window.
+ */
+static void draw_moving_frame( HWND parent, HDC hdc, RECT *screen_rect, BOOL thickframe )
+{
+    RECT rect = *screen_rect;
+
+    if (parent) map_window_points( 0, parent, (POINT *)&rect, 2, get_thread_dpi() );
+    if (thickframe)
+    {
+        const int width = get_system_metrics( SM_CXFRAME );
+        const int height = get_system_metrics( SM_CYFRAME );
+
+        HBRUSH hbrush = NtGdiSelectBrush( hdc, GetStockObject( GRAY_BRUSH ));
+        NtGdiPatBlt( hdc, rect.left, rect.top,
+                     rect.right - rect.left - width, height, PATINVERT );
+        NtGdiPatBlt( hdc, rect.left, rect.top + height, width,
+                     rect.bottom - rect.top - height, PATINVERT );
+        NtGdiPatBlt( hdc, rect.left + width, rect.bottom - 1,
+                     rect.right - rect.left - width, -height, PATINVERT );
+        NtGdiPatBlt( hdc, rect.right - 1, rect.top, -width,
+                     rect.bottom - rect.top - height, PATINVERT );
+        NtGdiSelectBrush( hdc, hbrush );
+    }
+    else draw_focus_rect( hdc, &rect );
+}
+
+/***********************************************************************
+ *           start_size_move
+ *
+ * Initialization of a move or resize, when initiated from a menu choice.
+ * Return hit test code for caption or sizing border.
+ */
+static LONG start_size_move( HWND hwnd, WPARAM wparam, POINT *capture_point, LONG style )
+{
+    RECT window_rect;
+    LONG hittest = 0;
+    POINT pt;
+    MSG msg;
+
+    get_window_rect( hwnd, &window_rect, get_thread_dpi() );
+
+    if ((wparam & 0xfff0) == SC_MOVE)
+    {
+        /* Move pointer at the center of the caption */
+        RECT rect = window_rect;
+        /* Note: to be exactly centered we should take the different types
+         * of border into account, but it shouldn't make more than a few pixels
+         * of difference so let's not bother with that */
+        rect.top += get_system_metrics( SM_CYBORDER );
+        if (style & WS_SYSMENU)     rect.left  += get_system_metrics( SM_CXSIZE ) + 1;
+        if (style & WS_MINIMIZEBOX) rect.right -= get_system_metrics( SM_CXSIZE ) + 1;
+        if (style & WS_MAXIMIZEBOX) rect.right -= get_system_metrics( SM_CXSIZE ) + 1;
+        pt.x = (rect.right + rect.left) / 2;
+        pt.y = rect.top + get_system_metrics( SM_CYSIZE ) / 2;
+        hittest = HTCAPTION;
+        *capture_point = pt;
+    }
+    else  /* SC_SIZE */
+    {
+        HCURSOR cursor;
+        cursor = LoadImageW( 0, (WCHAR *)IDC_SIZEALL, IMAGE_CURSOR, 0, 0, LR_SHARED | LR_DEFAULTSIZE );
+        NtUserSetCursor( cursor );
+        pt.x = pt.y = 0;
+        while (!hittest)
+        {
+            if (!NtUserGetMessage( &msg, 0, 0, 0 )) return 0;
+            if (NtUserCallMsgFilter( &msg, MSGF_SIZE )) continue;
+
+            switch (msg.message)
+            {
+            case WM_MOUSEMOVE:
+                pt.x = min( max( msg.pt.x, window_rect.left ), window_rect.right - 1 );
+                pt.y = min( max( msg.pt.y, window_rect.top ), window_rect.bottom - 1 );
+                hittest = send_message( hwnd, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ));
+                if (hittest < HTLEFT || hittest > HTBOTTOMRIGHT) hittest = 0;
+                break;
+
+            case WM_LBUTTONUP:
+                return 0;
+
+            case WM_KEYDOWN:
+                switch (msg.wParam)
+                {
+                case VK_UP:
+                    hittest = HTTOP;
+                    pt.x = (window_rect.left + window_rect.right) / 2;
+                    pt.y = window_rect.top + get_system_metrics( SM_CYFRAME ) / 2;
+                    break;
+                case VK_DOWN:
+                    hittest = HTBOTTOM;
+                    pt.x = (window_rect.left + window_rect.right) / 2;
+                    pt.y = window_rect.bottom - get_system_metrics( SM_CYFRAME ) / 2;
+                    break;
+                case VK_LEFT:
+                    hittest = HTLEFT;
+                    pt.x = window_rect.left + get_system_metrics( SM_CXFRAME ) / 2;
+                    pt.y = (window_rect.top + window_rect.bottom) / 2;
+                    break;
+                case VK_RIGHT:
+                    hittest = HTRIGHT;
+                    pt.x = window_rect.right - get_system_metrics( SM_CXFRAME ) / 2;
+                    pt.y = (window_rect.top + window_rect.bottom) / 2;
+                    break;
+                case VK_RETURN:
+                case VK_ESCAPE:
+                    return 0;
+                }
+                break;
+            default:
+                NtUserTranslateMessage( &msg, 0 );
+                NtUserDispatchMessage( &msg );
+                break;
+            }
+        }
+        *capture_point = pt;
+    }
+    NtUserSetCursorPos( pt.x, pt.y );
+    send_message( hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
+    return hittest;
+}
+
+static BOOL on_left_border( int hit )
+{
+    return hit == HTLEFT || hit == HTTOPLEFT || hit == HTBOTTOMLEFT;
+}
+
+static BOOL on_right_border( int hit )
+{
+    return hit == HTRIGHT || hit == HTTOPRIGHT || hit == HTBOTTOMRIGHT;
+}
+
+static BOOL on_top_border( int hit )
+{
+    return hit == HTTOP || hit == HTTOPLEFT || hit == HTTOPRIGHT;
+}
+
+static BOOL on_bottom_border( int hit )
+{
+    return hit == HTBOTTOM || hit == HTBOTTOMLEFT || hit == HTBOTTOMRIGHT;
+}
+
+/***********************************************************************
+ *           sys_command_size_move
+ *
+ * Perform SC_MOVE and SC_SIZE commands.
+ */
+static void sys_command_size_move( HWND hwnd, WPARAM wparam )
+{
+    DWORD msg_pos = NtUserGetThreadInfo()->message_pos;
+    BOOL thickframe, drag_full_windows = TRUE, moved = FALSE;
+    RECT sizing_rect, mouse_rect, orig_rect;
+    LONG hittest = wparam & 0x0f;
+    WPARAM syscommand = wparam & 0xfff0;
+    LONG style = get_window_long( hwnd, GWL_STYLE );
+    POINT capture_point, pt;
+    MINMAXINFO minmax;
+    HMONITOR mon = 0;
+    HWND parent;
+    UINT dpi;
+    HDC hdc;
+    MSG msg;
+
+    if (is_zoomed( hwnd ) || !is_window_visible( hwnd )) return;
+
+    thickframe = (style & WS_THICKFRAME) && !((style & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME);
+
+    pt.x = (short)LOWORD(msg_pos);
+    pt.y = (short)HIWORD(msg_pos);
+    capture_point = pt;
+    NtUserClipCursor( NULL );
+
+    TRACE( "hwnd %p command %04lx, hittest %d, pos %d,%d\n",
+           hwnd, syscommand, hittest, pt.x, pt.y );
+
+    if (syscommand == SC_MOVE)
+    {
+        if (!hittest) hittest = start_size_move( hwnd, wparam, &capture_point, style );
+        if (!hittest) return;
+    }
+    else  /* SC_SIZE */
+    {
+        if (hittest && syscommand != SC_MOUSEMENU)
+            hittest += (HTLEFT - WMSZ_LEFT);
+        else
+        {
+            set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
+            hittest = start_size_move( hwnd, wparam, &capture_point, style );
+            if (!hittest)
+            {
+                set_capture_window( 0, GUI_INMOVESIZE, NULL );
+                return;
+            }
+        }
+    }
+
+    minmax = get_min_max_info( hwnd );
+    dpi = get_thread_dpi();
+    get_window_rects( hwnd, COORDS_PARENT, &sizing_rect, NULL, dpi );
+    orig_rect = sizing_rect;
+    if (style & WS_CHILD)
+    {
+        parent = get_parent( hwnd );
+        get_client_rect( parent, &mouse_rect );
+        map_window_points( parent, 0, (POINT *)&mouse_rect, 2, dpi );
+        map_window_points( parent, 0, (POINT *)&sizing_rect, 2, dpi );
+    }
+    else
+    {
+        parent = 0;
+        mouse_rect = get_virtual_screen_rect( get_thread_dpi() );
+        mon = monitor_from_point( pt, MONITOR_DEFAULTTONEAREST, dpi );
+    }
+
+    if (on_left_border( hittest ))
+    {
+        mouse_rect.left = max( mouse_rect.left,
+                sizing_rect.right - minmax.ptMaxTrackSize.x + capture_point.x - sizing_rect.left );
+        mouse_rect.right = min( mouse_rect.right,
+                sizing_rect.right - minmax.ptMinTrackSize.x + capture_point.x - sizing_rect.left );
+    }
+    else if (on_right_border( hittest ))
+    {
+        mouse_rect.left  = max( mouse_rect.left,
+                sizing_rect.left + minmax.ptMinTrackSize.x + capture_point.x - sizing_rect.right );
+        mouse_rect.right = min( mouse_rect.right,
+                sizing_rect.left + minmax.ptMaxTrackSize.x + capture_point.x - sizing_rect.right );
+    }
+
+    if (on_top_border( hittest ))
+    {
+        mouse_rect.top = max( mouse_rect.top,
+                sizing_rect.bottom - minmax.ptMaxTrackSize.y + capture_point.y - sizing_rect.top );
+        mouse_rect.bottom = min( mouse_rect.bottom,
+                sizing_rect.bottom - minmax.ptMinTrackSize.y + capture_point.y - sizing_rect.top );
+    }
+    else if (on_bottom_border( hittest ))
+    {
+        mouse_rect.top = max( mouse_rect.top,
+                sizing_rect.top + minmax.ptMinTrackSize.y + capture_point.y - sizing_rect.bottom );
+        mouse_rect.bottom = min( mouse_rect.bottom,
+                sizing_rect.top + minmax.ptMaxTrackSize.y + capture_point.y - sizing_rect.bottom );
+    }
+
+    /* Retrieve a default cache DC (without using the window style) */
+    hdc = NtUserGetDCEx( parent, 0, DCX_CACHE );
+
+    /* we only allow disabling the full window drag for child windows */
+    if (parent) NtUserSystemParametersInfo( SPI_GETDRAGFULLWINDOWS, 0, &drag_full_windows, 0 );
+
+    /* repaint the window before moving it around */
+    NtUserRedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
+
+    send_message( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
+    set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
+
+    for (;;)
+    {
+        int dx = 0, dy = 0;
+
+        if (!NtUserGetMessage( &msg, 0, 0, 0 )) break;
+        if (NtUserCallMsgFilter( &msg, MSGF_SIZE )) continue;
+
+        /* Exit on button-up, Return, or Esc */
+        if (msg.message == WM_LBUTTONUP ||
+            (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
+            break;
+
+        if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
+        {
+            NtUserTranslateMessage( &msg, 0 );
+            NtUserDispatchMessage( &msg );
+            continue;  /* We are not interested in other messages */
+        }
+
+        pt = msg.pt;
+
+        if (msg.message == WM_KEYDOWN)
+        {
+            switch (msg.wParam)
+            {
+            case VK_UP:    pt.y -= 8; break;
+            case VK_DOWN:  pt.y += 8; break;
+            case VK_LEFT:  pt.x -= 8; break;
+            case VK_RIGHT: pt.x += 8; break;
+            }
+        }
+
+        pt.x = max( pt.x, mouse_rect.left );
+        pt.x = min( pt.x, mouse_rect.right - 1 );
+        pt.y = max( pt.y, mouse_rect.top );
+        pt.y = min( pt.y, mouse_rect.bottom - 1 );
+
+        if (!parent)
+        {
+            HMONITOR newmon;
+            MONITORINFO info;
+
+            if ((newmon = monitor_from_point( pt, MONITOR_DEFAULTTONULL, get_thread_dpi() )))
+                mon = newmon;
+
+            info.cbSize = sizeof(info);
+            if (mon && get_monitor_info( mon, &info ))
+            {
+                pt.x = max( pt.x, info.rcWork.left );
+                pt.x = min( pt.x, info.rcWork.right - 1 );
+                pt.y = max( pt.y, info.rcWork.top );
+                pt.y = min( pt.y, info.rcWork.bottom - 1 );
+            }
+        }
+
+        dx = pt.x - capture_point.x;
+        dy = pt.y - capture_point.y;
+
+        if (dx || dy)
+        {
+            if (!moved)
+            {
+                moved = TRUE;
+                if (!drag_full_windows)
+                    draw_moving_frame( parent, hdc, &sizing_rect, thickframe );
+            }
+
+            if (msg.message == WM_KEYDOWN) NtUserSetCursorPos( pt.x, pt.y );
+            else
+            {
+                if (!drag_full_windows) draw_moving_frame( parent, hdc, &sizing_rect, thickframe );
+                if (hittest == HTCAPTION || hittest == HTBORDER) OffsetRect( &sizing_rect, dx, dy );
+                if (on_left_border( hittest )) sizing_rect.left += dx;
+                else if (on_right_border( hittest )) sizing_rect.right += dx;
+                if (on_top_border( hittest )) sizing_rect.top += dy;
+                else if (on_bottom_border( hittest )) sizing_rect.bottom += dy;
+                capture_point = pt;
+
+                /* determine the hit location */
+                if (syscommand == SC_SIZE && hittest != HTBORDER)
+                {
+                    WPARAM sizing_hit = 0;
+
+                    if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
+                        sizing_hit = WMSZ_LEFT + (hittest - HTLEFT);
+                    send_message( hwnd, WM_SIZING, sizing_hit, (LPARAM)&sizing_rect );
+                }
+                else
+                    send_message( hwnd, WM_MOVING, 0, (LPARAM)&sizing_rect );
+
+                if (!drag_full_windows)
+                    draw_moving_frame( parent, hdc, &sizing_rect, thickframe );
+                else
+                {
+                    RECT rect = sizing_rect;
+                    map_window_points( 0, parent, (POINT *)&rect, 2, get_thread_dpi() );
+                    NtUserSetWindowPos( hwnd, 0, rect.left, rect.top,
+                                        rect.right - rect.left, rect.bottom - rect.top,
+                                        hittest == HTCAPTION ? SWP_NOSIZE : 0 );
+                }
+            }
+        }
+    }
+
+    if (moved && !drag_full_windows)
+        draw_moving_frame( parent, hdc, &sizing_rect, thickframe );
+
+    set_capture_window( 0, GUI_INMOVESIZE, NULL );
+    NtUserReleaseDC( parent, hdc );
+    if (parent) map_window_points( 0, parent, (POINT *)&sizing_rect, 2, get_thread_dpi() );
+
+    if (call_hooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizing_rect, TRUE ))
+        moved = FALSE;
+
+    send_message( hwnd, WM_EXITSIZEMOVE, 0, 0 );
+    send_message( hwnd, WM_SETVISIBLE, !is_iconic(hwnd), 0 );
+
+    /* window moved or resized */
+    if (moved)
+    {
+        /* if the moving/resizing isn't canceled call SetWindowPos
+         * with the new position or the new size of the window
+         */
+        if (!(msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) )
+        {
+            /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
+            if (!drag_full_windows)
+                NtUserSetWindowPos( hwnd, 0, sizing_rect.left, sizing_rect.top,
+                                    sizing_rect.right - sizing_rect.left,
+                                    sizing_rect.bottom - sizing_rect.top,
+                                    hittest == HTCAPTION ? SWP_NOSIZE : 0 );
+        }
+        else
+        {
+            /* restore previous size/position */
+            if (drag_full_windows)
+                NtUserSetWindowPos( hwnd, 0, orig_rect.left, orig_rect.top,
+                                    orig_rect.right - orig_rect.left,
+                                    orig_rect.bottom - orig_rect.top,
+                                    hittest == HTCAPTION ? SWP_NOSIZE : 0 );
+        }
+    }
+
+    if (is_iconic(hwnd) && !moved && (style & WS_SYSMENU))
+    {
+        /* Single click brings up the system menu when iconized */
+        send_message( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x, pt.y) );
+    }
+}
+
 static LRESULT handle_sys_command( HWND hwnd, WPARAM wparam, LPARAM lparam )
 {
     if (!is_window_enabled( hwnd )) return 0;
@@ -228,6 +660,11 @@ static LRESULT handle_sys_command( HWND hwnd, WPARAM wparam, LPARAM lparam )
 
     switch (wparam & 0xfff0)
     {
+    case SC_SIZE:
+    case SC_MOVE:
+        sys_command_size_move( hwnd, wparam );
+        break;
+
     case SC_MINIMIZE:
         show_owned_popups( hwnd, FALSE );
         NtUserShowWindow( hwnd, SW_MINIMIZE );
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h
index 09c800bd777..957d930d9da 100644
--- a/dlls/win32u/win32u_private.h
+++ b/dlls/win32u/win32u_private.h
@@ -457,6 +457,8 @@ extern BOOL is_iconic( HWND hwnd ) DECLSPEC_HIDDEN;
 extern BOOL is_window_drawable( HWND hwnd, BOOL icon ) DECLSPEC_HIDDEN;
 extern BOOL is_window_enabled( HWND hwnd ) DECLSPEC_HIDDEN;
 extern BOOL is_window_unicode( HWND hwnd ) DECLSPEC_HIDDEN;
+extern BOOL is_window_visible( HWND hwnd ) DECLSPEC_HIDDEN;
+extern BOOL is_zoomed( HWND hwnd ) DECLSPEC_HIDDEN;
 extern DWORD get_window_long( HWND hwnd, INT offset ) DECLSPEC_HIDDEN;
 extern BOOL get_window_rect( HWND hwnd, RECT *rect, UINT dpi ) DECLSPEC_HIDDEN;
 enum coords_relative;
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c
index 08e901cc855..f98dabe27f3 100644
--- a/dlls/win32u/window.c
+++ b/dlls/win32u/window.c
@@ -737,7 +737,7 @@ BOOL is_child( HWND parent, HWND child )
 }
 
 /* see IsWindowVisible */
-static BOOL is_window_visible( HWND hwnd )
+BOOL is_window_visible( HWND hwnd )
 {
     HWND *list;
     BOOL retval = TRUE;
@@ -965,7 +965,7 @@ BOOL is_iconic( HWND hwnd )
     return (get_window_long( hwnd, GWL_STYLE ) & WS_MINIMIZE) != 0;
 }
 
-static BOOL is_zoomed( HWND hwnd )
+BOOL is_zoomed( HWND hwnd )
 {
     return (get_window_long( hwnd, GWL_STYLE ) & WS_MAXIMIZE) != 0;
 }
@@ -5439,10 +5439,6 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code )
     case NtUserCallHwndParam_GetClientRect:
         return get_client_rect( hwnd, (RECT *)param );
 
-    case NtUserCallHwndParam_GetMinMaxInfo:
-        *(MINMAXINFO *)param = get_min_max_info( hwnd );
-        return 0;
-
     case NtUserCallHwndParam_GetWindowInfo:
         return get_window_info( hwnd, (WINDOWINFO *)param );
 
diff --git a/include/ntgdi.h b/include/ntgdi.h
index 5a9d5a798fe..14b1dde45d5 100644
--- a/include/ntgdi.h
+++ b/include/ntgdi.h
@@ -109,10 +109,12 @@ enum
     NtGdiSetMapMode = 8,
     /* not compatible with Windows */
     NtGdiSetBkColor = 100,
+    NtGdiSetBkMode,
     NtGdiSetTextColor,
     NtGdiSetDCBrushColor,
     NtGdiSetDCPenColor,
     NtGdiSetGraphicsMode,
+    NtGdiSetROP2,
 };
 
 /* NtGdiGetDCDword parameter, not compatible with Windows */
diff --git a/include/ntuser.h b/include/ntuser.h
index 9d9ac0247d1..8320a83800f 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -1018,7 +1018,6 @@ enum
     NtUserCallHwndParam_GetClassLongPtrW,
     NtUserCallHwndParam_GetClassWord,
     NtUserCallHwndParam_GetClientRect,
-    NtUserCallHwndParam_GetMinMaxInfo,
     NtUserCallHwndParam_GetWindowInfo,
     NtUserCallHwndParam_GetWindowLongA,
     NtUserCallHwndParam_GetWindowLongW,
@@ -1085,13 +1084,6 @@ static inline BOOL NtUserGetClientRect( HWND hwnd, RECT *rect )
     return NtUserCallHwndParam( hwnd, (UINT_PTR)rect, NtUserCallHwndParam_GetClientRect );
 }
 
-static inline MINMAXINFO NtUserGetMinMaxInfo( HWND hwnd )
-{
-    MINMAXINFO info;
-    NtUserCallHwndParam( hwnd, (UINT_PTR)&info, NtUserCallHwndParam_GetMinMaxInfo );
-    return info;
-}
-
 static inline BOOL NtUserGetWindowInfo( HWND hwnd, WINDOWINFO *info )
 {
     return NtUserCallHwndParam( hwnd, (UINT_PTR)info, NtUserCallHwndParam_GetWindowInfo );
-- 
GitLab

https://gitlab.winehq.org/wine/wine/-/merge_requests/211



More information about the wine-devel mailing list