[PATCH 4/4] dwmapi: Implement DWMWA_CAPTION_BUTTON_BOUNDS via system metrics.

Gabriel Ivăncescu gabrielopcode at gmail.com
Tue Aug 11 10:29:13 CDT 2020


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

Most of the logic has been followed from user32.

 dlls/dwmapi/dwmapi_main.c  | 75 ++++++++++++++++++++++++++++++++++++++
 dlls/dwmapi/tests/dwmapi.c | 58 ++++++++++++++++++++++++++++-
 2 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/dlls/dwmapi/dwmapi_main.c b/dlls/dwmapi/dwmapi_main.c
index bb585c5..a433437 100644
--- a/dlls/dwmapi/dwmapi_main.c
+++ b/dlls/dwmapi/dwmapi_main.c
@@ -32,6 +32,74 @@
 WINE_DEFAULT_DEBUG_CHANNEL(dwmapi);
 
 
+static void get_caption_buttons_rect(HWND hwnd, RECT *rc)
+{
+    DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
+    DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE);
+    LONG border_w = 0, border_h = 0;
+
+    GetWindowRect(hwnd, rc);
+    OffsetRect(rc, -rc->left, -rc->top);
+
+    if ((style & WS_THICKFRAME) && (style & (WS_DLGFRAME | WS_BORDER)) != WS_DLGFRAME)
+    {
+        border_w += GetSystemMetrics(SM_CXFRAME);
+        border_h += GetSystemMetrics(SM_CYFRAME);
+    }
+    else if ((!(style & WS_THICKFRAME) && (style & WS_DLGFRAME)) || (ex_style & WS_EX_DLGMODALFRAME))
+    {
+        border_w += GetSystemMetrics(SM_CXDLGFRAME);
+        border_h += GetSystemMetrics(SM_CYDLGFRAME);
+    }
+    else if ((style & WS_BORDER) || !(style & (WS_CHILD | WS_POPUP)))
+    {
+        border_w += GetSystemMetrics(SM_CXBORDER);
+        border_h += GetSystemMetrics(SM_CYBORDER);
+    }
+
+    /* There's additional border info if the window is a child (but not MDI) */
+    if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
+    {
+        if (ex_style & WS_EX_CLIENTEDGE)
+        {
+            border_w += GetSystemMetrics(SM_CXEDGE);
+            border_h += GetSystemMetrics(SM_CYEDGE);
+        }
+        if (ex_style & WS_EX_STATICEDGE)
+        {
+            border_w += GetSystemMetrics(SM_CXBORDER);
+            border_h += GetSystemMetrics(SM_CYBORDER);
+        }
+    }
+
+    rc->right -= border_w;
+    rc->top   += border_h;
+    rc->left   = rc->right;
+
+    /* The height is always reported even if there are no buttons */
+    rc->bottom = rc->top + GetSystemMetrics((ex_style & WS_EX_TOOLWINDOW) ? SM_CYSMCAPTION : SM_CYCAPTION);
+
+    if ((style & (WS_SYSMENU | WS_CAPTION)) == (WS_SYSMENU | WS_CAPTION))
+    {
+        if (ex_style & WS_EX_TOOLWINDOW)
+            rc->left -= GetSystemMetrics(SM_CYSMCAPTION);
+        else
+        {
+            UINT num_buttons = 1;
+
+            /* Minimize and Maximize buttons are always visible in pairs */
+            if (style & (WS_MINIMIZEBOX | WS_MAXIMIZEBOX))
+                num_buttons += 2;
+            else if (ex_style & WS_EX_CONTEXTHELP)
+                num_buttons++;
+
+            rc->left -= GetSystemMetrics(SM_CXSIZE) * num_buttons;
+        }
+        rc->left = max(rc->left, border_w);
+    }
+}
+
+
 /* At process attach */
 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
 {
@@ -222,6 +290,13 @@ HRESULT WINAPI DwmGetWindowAttribute(HWND hwnd, DWORD attribute, PVOID pv_attrib
         *(BOOL*)(pv_attribute) = FALSE;
         break;
 
+    case DWMWA_CAPTION_BUTTON_BOUNDS:
+        if (size < sizeof(RECT)) return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+
+        WARN("DWMWA_CAPTION_BUTTON_BOUNDS: returning rect based on system metrics.\n");
+        get_caption_buttons_rect(hwnd, pv_attribute);
+        break;
+
     case DWMWA_EXTENDED_FRAME_BOUNDS:
         if (size < sizeof(RECT)) return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
 
diff --git a/dlls/dwmapi/tests/dwmapi.c b/dlls/dwmapi/tests/dwmapi.c
index e593c30..8308477 100644
--- a/dlls/dwmapi/tests/dwmapi.c
+++ b/dlls/dwmapi/tests/dwmapi.c
@@ -29,8 +29,8 @@ static LRESULT WINAPI test_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARA
 static void test_DwmGetWindowAttribute(void)
 {
     BOOL nc_rendering;
+    RECT rc, rc2;
     HRESULT hr;
-    RECT rc;
 
     hr = DwmGetWindowAttribute(NULL, DWMWA_NCRENDERING_ENABLED, &nc_rendering, sizeof(nc_rendering));
     ok(hr == E_HANDLE || broken(hr == E_INVALIDARG) /* Vista */, "DwmGetWindowAttribute(DWMWA_NCRENDERING_ENABLED) returned 0x%08x.\n", hr);
@@ -53,6 +53,62 @@ static void test_DwmGetWindowAttribute(void)
     hr = DwmGetWindowAttribute(test_wnd, DWMWA_EXTENDED_FRAME_BOUNDS, &rc, sizeof(rc));
     if (hr != E_HANDLE && hr != DWM_E_COMPOSITIONDISABLED /* Vista */)  /* composition is on */
         ok(hr == S_OK, "DwmGetWindowAttribute(DWMWA_EXTENDED_FRAME_BOUNDS) failed 0x%08x.\n", hr);
+
+    hr = DwmGetWindowAttribute(test_wnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rc, sizeof(rc) - 1);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) || broken(hr == E_INVALIDARG) /* Vista */,
+       "DwmGetWindowAttribute(DWMWA_CAPTION_BUTTON_BOUNDS) returned 0x%08x.\n", hr);
+    hr = DwmGetWindowAttribute(test_wnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rc, sizeof(rc));
+    if (hr != E_HANDLE && hr != DWM_E_COMPOSITIONDISABLED /* Vista */)  /* composition is on */
+    {
+        DWORD style = GetWindowLongA(test_wnd, GWL_STYLE), ex_style = GetWindowLongA(test_wnd, GWL_EXSTYLE);
+
+        ok(hr == S_OK, "DwmGetWindowAttribute(DWMWA_CAPTION_BUTTON_BOUNDS) failed 0x%08x.\n", hr);
+        ok(rc.left > 0 && rc.right > rc.left && rc.top >= 0 && rc.bottom > rc.top,
+           "unexpected caption rect %s.\n", wine_dbgstr_rect(&rc));
+
+        SetWindowLongA(test_wnd, GWL_STYLE, style & ~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX));
+        hr = DwmGetWindowAttribute(test_wnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rc2, sizeof(rc2));
+        ok(hr == S_OK, "DwmGetWindowAttribute(DWMWA_CAPTION_BUTTON_BOUNDS) failed 0x%08x.\n", hr);
+        ok(rc2.left > rc.left && rc2.right == rc.right && rc2.top == rc.top && rc2.bottom == rc.bottom,
+           "unexpected caption rect %s (original %s).\n", wine_dbgstr_rect(&rc2), wine_dbgstr_rect(&rc));
+
+        SetWindowLongA(test_wnd, GWL_EXSTYLE, ex_style | WS_EX_CONTEXTHELP);
+        hr = DwmGetWindowAttribute(test_wnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rc2, sizeof(rc2));
+        ok(hr == S_OK, "DwmGetWindowAttribute(DWMWA_CAPTION_BUTTON_BOUNDS) failed 0x%08x.\n", hr);
+        ok(rc2.left > rc.left && rc2.right == rc.right && rc2.top == rc.top && rc2.bottom == rc.bottom,
+           "unexpected caption rect %s (original %s).\n", wine_dbgstr_rect(&rc2), wine_dbgstr_rect(&rc));
+
+        SetWindowLongA(test_wnd, GWL_EXSTYLE, ex_style | WS_EX_TOOLWINDOW);
+        hr = DwmGetWindowAttribute(test_wnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rc2, sizeof(rc2));
+        ok(hr == S_OK, "DwmGetWindowAttribute(DWMWA_CAPTION_BUTTON_BOUNDS) failed 0x%08x.\n", hr);
+        ok(rc2.left > rc.left && rc2.right <= rc.right && rc2.top >= rc.top && rc2.bottom <= rc.bottom,
+           "unexpected caption rect %s (original %s).\n", wine_dbgstr_rect(&rc2), wine_dbgstr_rect(&rc));
+        SetWindowLongA(test_wnd, GWL_EXSTYLE, ex_style);
+
+        SetWindowLongA(test_wnd, GWL_STYLE, style & ~WS_SYSMENU);
+        hr = DwmGetWindowAttribute(test_wnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rc2, sizeof(rc2));
+        ok(hr == S_OK, "DwmGetWindowAttribute(DWMWA_CAPTION_BUTTON_BOUNDS) failed 0x%08x.\n", hr);
+        ok(rc2.left == rc.right && rc2.right == rc.right && rc2.top == rc.top && rc2.bottom == rc.bottom,
+           "unexpected caption rect %s (original %s).\n", wine_dbgstr_rect(&rc2), wine_dbgstr_rect(&rc));
+        SetWindowLongA(test_wnd, GWL_STYLE, style);
+
+        ShowWindow(test_wnd, SW_SHOWMINIMIZED);
+        ok(IsIconic(test_wnd), "window was not minimized.\n");
+        hr = DwmGetWindowAttribute(test_wnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rc2, sizeof(rc2));
+        ok(hr == S_OK, "DwmGetWindowAttribute(DWMWA_CAPTION_BUTTON_BOUNDS) failed 0x%08x.\n", hr);
+        ok(rc2.left - rc.left == rc2.right - rc.right && rc2.left <= rc.left && rc2.top == rc.top && rc2.bottom == rc.bottom,
+           "unexpected caption rect %s (original %s).\n", wine_dbgstr_rect(&rc2), wine_dbgstr_rect(&rc));
+        ShowWindow(test_wnd, SW_RESTORE);
+        ok(!IsIconic(test_wnd), "window was not restored.\n");
+
+        ShowWindow(test_wnd, SW_HIDE);
+        ok(!IsWindowVisible(test_wnd), "window was not hidden.\n");
+        hr = DwmGetWindowAttribute(test_wnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rc2, sizeof(rc2));
+        ok(hr == S_OK, "DwmGetWindowAttribute(DWMWA_CAPTION_BUTTON_BOUNDS) failed 0x%08x.\n", hr);
+        ok(EqualRect(&rc, &rc2), "unexpected caption rect %s (expected %s).\n", wine_dbgstr_rect(&rc2), wine_dbgstr_rect(&rc));
+        ShowWindow(test_wnd, SW_SHOW);
+        ok(IsWindowVisible(test_wnd), "window was not shown.\n");
+    }
 }
 
 static void test_DwmIsCompositionEnabled(void)
-- 
2.21.0




More information about the wine-devel mailing list