From e8231fbf0ac66f5e3e85ed45fd3f8ddaf7c75ee6 Mon Sep 17 00:00:00 2001
From: Hirofumi Katayama <katayama.hirofumi.mz@gmail.com>
Date: Thu, 7 Nov 2019 20:10:12 +0900
Subject: [PATCH v7] user32: Implement DM_REPOSITION message.

Dialog Message DM_REPOSITION was not implemented.
This patch realizes repositioning of dialog boxes.
A test for DM_REPOSITION is also added.
This will also fix the case of pointSize == 0x7fff.

Signed-off-by: Hirofumi Katayama <katayama.hirofumi.mz@gmail.com>
---
 dlls/user32/defdlg.c       | 48 ++++++++++++++++++++++++++++++++++++++
 dlls/user32/dialog.c       | 44 ++++++++++++++++++++++++++++++----
 dlls/user32/tests/dialog.c | 35 +++++++++++++++++++++++++++
 3 files changed, 122 insertions(+), 5 deletions(-)

diff --git a/dlls/user32/defdlg.c b/dlls/user32/defdlg.c
index 00a73c6b92..7bdf0cf301 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;
+    SIZE size;
+
+    if (GetWindowLongW(hwnd, GWL_STYLE) & WS_CHILD)
+        return;
+
+    hMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
+
+    if (!GetMonitorInfoW(hMon, &mi) || !GetWindowRect(hwnd, &rc))
+        return;
+
+    size.cx = rc.right - rc.left;
+    size.cy = rc.bottom - rc.top;
+
+    if (rc.right > mi.rcWork.right)
+    {
+        rc.right = mi.rcWork.right;
+        rc.left = rc.right - size.cx;
+    }
+    if (rc.bottom > mi.rcWork.bottom)
+    {
+        rc.bottom = mi.rcWork.bottom;
+        rc.top = rc.bottom - size.cy;
+    }
+
+    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/dialog.c b/dlls/user32/dialog.c
index 88c2930c06..dbc01ac63d 100644
--- a/dlls/user32/dialog.c
+++ b/dlls/user32/dialog.c
@@ -78,6 +78,7 @@ typedef struct
     BOOL       italic;
     LPCWSTR    faceName;
     BOOL       dialogEx;
+    WCHAR      nameBuffer[LF_FACESIZE];     /* for faceName */
 } DLG_TEMPLATE;
 
   /* Radio button group */
@@ -304,6 +305,29 @@ static BOOL DIALOG_CreateControls32( HWND hwnd, LPCSTR template, const DLG_TEMPL
     return TRUE;
 }
 
+static int GetFontPointSizeInPoints(HDC hdc, const LOGFONT *plf)
+{
+    TEXTMETRICW tm;
+    HFONT hFont;
+    HGDIOBJ hFontOld;
+    INT nLogPixelsY = GetDeviceCaps(hdc, LOGPIXELSY);
+
+    if (lf.lfHeight < 0)
+    {
+        return -MulDiv(plf->lfHeight, 72, nLogPixelsY);
+    }
+
+    hFont = CreateFontIndirectW(plf);
+    if (!hFont)
+        return 0;
+
+    hFontOld = SelectObject(hdc, hFont);
+    GetTextMetrics(hdc, &tm);
+    SelectObject(hdc, hFontOld);
+    DeleteObject(hFont);
+
+    return MulDiv(tm.tmHeight - tm.tmInternalLeading, 72, nLogPixelsY);
+}
 
 /***********************************************************************
  *           DIALOG_ParseTemplate32
@@ -316,6 +340,8 @@ static LPCSTR DIALOG_ParseTemplate32( LPCSTR template, DLG_TEMPLATE * result )
     const WORD *p = (const WORD *)template;
     WORD signature;
     WORD dlgver;
+    HDC dc;
+    NONCLIENTMETRICSW ncMetrics;
 
     dlgver = GET_WORD(p); p++;
     signature = GET_WORD(p); p++;
@@ -409,11 +435,19 @@ static LPCSTR DIALOG_ParseTemplate32( LPCSTR template, DLG_TEMPLATE * result )
          */
         if (result->pointSize == 0x7fff)
         {
-            /* We could call SystemParametersInfo here, but then we'd have
-             * to convert from pixel size to point size (which can be
-             * imprecise).
-             */
-            TRACE(" FONT: Using message box font\n");
+            ncMetrics.cbSize = FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth);
+            SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncMetrics, 0);
+
+            dc = CreateCompatibleDC(NULL);
+            result->pointSize = GetFontPointSizeInPoints(dc, &ncMetrics.lfMessageFont);
+            DeleteDC(dc);
+
+            result->weight = (WORD)ncMetrics.lfMessageFont.lfWeight;
+            result->italic = ncMetrics.lfMessageFont.lfItalic;
+
+            lstrcpynW(result->nameBuffer, ncMetrics.lfMessageFont.lfFaceName,
+                      ARRAY_SIZE(result->nameBuffer));
+            result->faceName = result->nameBuffer;
         }
         else
         {
diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c
index b72f08816d..3d1a3f2ffd 100644
--- a/dlls/user32/tests/dialog.c
+++ b/dlls/user32/tests/dialog.c
@@ -2174,6 +2174,40 @@ static void test_dialog_custom_data(void)
     DialogBoxA(g_hinst, "CUSTOM_TEST_DIALOG", NULL, custom_test_dialog_proc);
 }
 
+static INT_PTR CALLBACK reposition_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    RECT rc;
+    SIZE size;
+
+    if (msg == WM_INITDIALOG)
+    {
+        GetWindowRect(hdlg, &rc);
+        size.cx = rc.right - rc.left;
+        size.cy = rc.bottom - rc.top;
+
+        MoveWindow(hdlg, -100, -100, size.cx, size.cy, TRUE);
+
+        GetWindowRect(hdlg, &rc);
+        ok(rc.left == -100, "rc.left was %ld\n", rc.left);
+        ok(rc.top == -100, "rc.top was %ld\n", rc.top);
+
+        SendMessageW(hdlg, DM_REPOSITION, 0, 0);
+
+        GetWindowRect(hdlg, &rc);
+        ok(rc.left == 0, "rc.left was %ld\n", rc.left);
+        ok(rc.top == 0, "rc.top was %ld\n", rc.top);
+
+        EndDialog(hdlg, 0);
+    }
+
+    return FALSE;
+}
+
+static void test_DM_REPOSITION(void)
+{
+    DialogBoxA(g_hinst, "CUSTOM_TEST_DIALOG", NULL, reposition_dialog_proc);
+}
+
 START_TEST(dialog)
 {
     g_hinst = GetModuleHandleA (0);
@@ -2193,4 +2227,5 @@ START_TEST(dialog)
     test_SaveRestoreFocus();
     test_timer_message();
     test_MessageBox();
+    test_DM_REPOSITION();
 }
-- 
2.23.0

