From 1535e6e456713b15ac133dd18cbc61e725d08d53 Mon Sep 17 00:00:00 2001
From: Hirofumi Katayama <katayama.hirofumi.mz@gmail.com>
Date: Sat, 16 Nov 2019 13:04:55 +0900
Subject: [PATCH v10] user32: Implement DM_REPOSITION.

DM_REPOSITION is dialog message that can reposition the
workarea when the dialog is partially/entirely in outside
of the workarea.

Signed-off-by: Hirofumi Katayama <katayama.hirofumi.mz@gmail.com>
---
 dlls/user32/defdlg.c       | 48 ++++++++++++++++++++++++
 dlls/user32/tests/dialog.c | 77 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 125 insertions(+)

diff --git a/dlls/user32/defdlg.c b/dlls/user32/defdlg.c
index 00a73c6b92..1210477f77 100644
--- a/dlls/user32/defdlg.c
+++ b/dlls/user32/defdlg.c
@@ -208,6 +208,48 @@ static BOOL DEFDLG_SetDefButton( HWND hwndDlg, DIALOGINFO *dlgInfo, HWND hwndNew
     return TRUE;
 }
 
+static void DEFDLG_Reposition(HWND hwnd)
+{
+    HMONITOR hMon;
+    MONITORINFO mi = { sizeof(mi) };
+    RECT rc;
+    LONG width, height;
+
+    if (GetWindowLongW(hwnd, GWL_STYLE) & WS_CHILD)
+        return;
+
+    hMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+
+    if (!GetMonitorInfoW(hMon, &mi) || !GetWindowRect(hwnd, &rc))
+        return;
+
+    width = rc.right - rc.left;
+    height = rc.bottom - rc.top;
+
+    if (rc.right > mi.rcWork.right)
+    {
+        rc.right = mi.rcWork.right;
+        rc.left = rc.right - width;
+    }
+    if (rc.bottom > mi.rcWork.bottom - 4)
+    {
+        rc.bottom = mi.rcWork.bottom - 4;
+        rc.top = rc.bottom - height;
+    }
+
+    if (rc.left < mi.rcWork.left)
+    {
+        rc.left = mi.rcWork.left;
+    }
+    if (rc.top < mi.rcWork.top)
+    {
+        rc.top = mi.rcWork.top;
+    }
+
+    SetWindowPos(hwnd, NULL, rc.left, rc.top, 0, 0,
+                 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE |
+                 SWP_NOZORDER);
+}
 
 /***********************************************************************
  *           DEFDLG_Proc
@@ -279,6 +321,10 @@ static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
             }
             return 0;
 
+        case DM_REPOSITION:
+            DEFDLG_Reposition(hwnd);
+            return 0;
+
         case WM_NEXTDLGCTL:
             if (dlgInfo)
             {
@@ -383,6 +429,7 @@ LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
             case WM_SETFOCUS:
             case DM_SETDEFID:
             case DM_GETDEFID:
+            case DM_REPOSITION:
             case WM_NEXTDLGCTL:
             case WM_GETFONT:
             case WM_CLOSE:
@@ -441,6 +488,7 @@ LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
             case WM_SETFOCUS:
             case DM_SETDEFID:
             case DM_GETDEFID:
+            case DM_REPOSITION:
             case WM_NEXTDLGCTL:
             case WM_GETFONT:
             case WM_CLOSE:
diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c
index b72f08816d..1e20e6770b 100644
--- a/dlls/user32/tests/dialog.c
+++ b/dlls/user32/tests/dialog.c
@@ -2174,6 +2174,82 @@ static void test_dialog_custom_data(void)
     DialogBoxA(g_hinst, "CUSTOM_TEST_DIALOG", NULL, custom_test_dialog_proc);
 }
 
+static INT_PTR CALLBACK reposition_test_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if (msg == WM_INITDIALOG)
+    {
+        RECT rc, rcWork;
+        INT width, height;
+        HMONITOR hMon;
+        MONITORINFO mi = { sizeof(mi) };
+
+        /* get monitor info */
+        hMon = MonitorFromWindow(hdlg, MONITOR_DEFAULTTONEAREST);
+        ok(hMon != NULL, "hMon is NULL\n");
+        ok(GetMonitorInfoW(hMon, &mi) == TRUE, "GetMonitorInfoW failed\n");
+        rcWork = mi.rcWork;
+
+        /* get size */
+        GetWindowRect(hdlg, &rc);
+        width = rc.right - rc.left;
+        height = rc.bottom - rc.top;
+
+        /* move */
+        ok(SetWindowPos(hdlg, NULL, rcWork.left - 80, rcWork.top - 80, 0, 0,
+                        SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOOWNERZORDER |
+                        SWP_NOZORDER) == TRUE, "SetWindowPos failed\n");
+        ok(GetWindowRect(hdlg, &rc) == TRUE, "GetWindowRect failed\n");
+        ok(rc.left == rcWork.left - 80, "rc.left:%ld, rcWork.left:%ld\n", rc.left, rcWork.left);
+        ok(rc.top == rcWork.top - 80, "rc.top:%ld, rcWork.top:%ld\n", rc.top, rcWork.top);
+        ok(rc.right == rc.left + width, "rc.right:%ld, rc.left:%ld, width:%d\n", rc.right, rc.left, width);
+        ok(rc.bottom == rc.top + height, "rc.bottom:%ld, rc.top:%ld, height:%d\n", rc.bottom, rc.top, height);
+
+        /* reposition */
+        ok(SendMessageW(hdlg, DM_REPOSITION, 0, 0) == 0, "SendMessageW returned non-zero\n");
+        ok(GetWindowRect(hdlg, &rc) == TRUE, "GetWindowRect failed\n");
+        ok(rc.left == rcWork.left, "rc.left:%ld, rcWork.left:%ld\n", rc.left, rcWork.left);
+        ok(rc.top == rcWork.top, "rc.top:%ld, rcWork.top:%ld\n", rc.top, rcWork.top);
+        ok(rc.right == rc.left + width, "rc.right:%ld, rc.left:%ld, width:%d\n", rc.right, rc.left, width);
+        ok(rc.bottom == rc.top + height, "rc.bottom:%ld, rc.top:%ld, height:%d\n", rc.bottom, rc.top, height);
+
+        /* move */
+        ok(SetWindowPos(hdlg, NULL,
+                        rcWork.right - width + 80, rcWork.bottom - height + 80, 0, 0,
+                        SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOOWNERZORDER |
+                        SWP_NOZORDER) == TRUE, "SetWindowPos failed\n");
+        ok(GetWindowRect(hdlg, &rc) == TRUE, "GetWindowRect failed\n");
+        ok(rc.left == rcWork.right - width + 80, "rc.left:%ld, rcWork.right:%ld, width:%d\n",
+           rc.left, rcWork.right, width);
+        ok(rc.top == rcWork.bottom - height + 80, "rc.top:%ld, rcWork.bottom:%ld, height:%d\n",
+           rc.top, rcWork.bottom, height);
+        ok(rc.right == rc.left + width, "rc.right:%ld, rc.left:%ld, width:%d\n",
+           rc.right, rc.left, width);
+        ok(rc.bottom == rc.top + height, "rc.bottom:%ld, rc.top:%ld, height:%d\n",
+           rc.bottom, rc.top, height);
+
+        /* reposition */
+        ok(SendMessageW(hdlg, DM_REPOSITION, 0, 0) == 0, "SendMessageW returned non-zero\n");
+        ok(GetWindowRect(hdlg, &rc) == TRUE, "GetWindowRect failed\n");
+        ok(rc.left == rcWork.right - width, "rc.left:%ld, rcWork.right:%ld, width:%d\n",
+           rc.left, rcWork.right, width);
+        ok(rc.top == rcWork.bottom - height - 4, "rc.top:%ld, rcWork.bottom:%ld, height:%d",
+           rc.top, rcWork.bottom, height);
+        ok(rc.right == rc.left + width, "rc.right:%ld, rc.left:%ld, width:%d\n",
+           rc.right, rc.left, width);
+        ok(rc.bottom == rc.top + height, "rc.bottom:%ld, rc.top:%ld, height:%d\n",
+           rc.bottom, rc.top, height);
+
+        EndDialog(hdlg, 0);
+    }
+
+    return FALSE;
+}
+
+static void test_DM_REPOSITION(void)
+{
+    DialogBoxA(g_hinst, "CUSTOM_TEST_DIALOG", NULL, reposition_test_dialog_proc);
+}
+
 START_TEST(dialog)
 {
     g_hinst = GetModuleHandleA (0);
@@ -2193,4 +2269,5 @@ START_TEST(dialog)
     test_SaveRestoreFocus();
     test_timer_message();
     test_MessageBox();
+    test_DM_REPOSITION();
 }
-- 
2.23.0

