Add a test for client/nonclient window dimensions calculation.

Dmitry Timoshkov dmitry at baikal.ru
Tue Jun 15 07:50:26 CDT 2004


Hello,

I have at least one application which wants to set its client
window size to fixed values (according to the selected font).
The app on each WM_WINDOWPOSCHANGED message tests its window
size and if the size doesn't meet the requirement resizes itslef.
Currently the app goes into an infinite loop under Wine.

I wrote a test to verify what's wrong with current code in Wine.
The test requires that after a SetWindowPos(0,0,100,100) a call
to GetWindowRect() returns rectangle set to (0,0,100,100). But
most window managers round window dimensions and the test fails.
Moreover even desktop mode doesn't allow the test to fully pass due
to Wine bugs.

I just don't want to lose my work and have no time at the moment
to fix bugs in Wine, so I simply #ifdef'ed failing tests.

Changelog:
    Dmitry Timoshkov <dmitry at codeweavers.com>
    Add a test for client/nonclient window dimensions calculation.

--- cvs/hq/wine/dlls/user/tests/win.c	2004-06-03 18:16:48.000000000 +0900
+++ wine/dlls/user/tests/win.c	2004-06-15 19:51:54.000000000 +0900
@@ -468,6 +468,7 @@ static LRESULT WINAPI main_window_procA(
 	}
 	case WM_WINDOWPOSCHANGED:
 	{
+            RECT rc1, rc2;
 	    WINDOWPOS *winpos = (WINDOWPOS *)lparam;
 	    trace("main: WM_WINDOWPOSCHANGED\n");
 	    trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
@@ -478,6 +479,21 @@ static LRESULT WINAPI main_window_procA(
 
 	    ok(winpos->cx >= 0 && winpos->cx <= 32767, "bad winpos->cx %d\n", winpos->cx);
 	    ok(winpos->cy >= 0 && winpos->cy <= 32767, "bad winpos->cy %d\n", winpos->cy);
+
+            GetWindowRect(hwnd, &rc1);
+            trace("window: (%ld,%ld)-(%ld,%ld)\n", rc1.left, rc1.top, rc1.right, rc1.bottom);
+            SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy);
+            /* note: winpos coordinates are relative to parent */
+            MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2);
+            trace("pos: (%ld,%ld)-(%ld,%ld)\n", rc2.left, rc2.top, rc2.right, rc2.bottom);
+#if 0 /* Uncomment this once the test succeeds in all cases */
+            ok(EqualRect(&rc1, &rc2), "rects do not match\n");
+#endif
+
+            GetClientRect(hwnd, &rc2);
+            DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1);
+            MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2);
+            ok(EqualRect(&rc1, &rc2), "rects do not match\n");
 	    break;
 	}
 	case WM_NCCREATE:
@@ -609,6 +625,58 @@ static void verify_window_info(HWND hwnd
     ok(info->wCreatorVersion == 0x0400, "wrong wCreatorVersion %04x\n", info->wCreatorVersion);
 }
 
+static void test_nonclient_area(HWND hwnd)
+{
+    DWORD style, exstyle;
+    RECT rc_window, rc_client, rc;
+    BOOL menu;
+
+    style = GetWindowLongA(hwnd, GWL_STYLE);
+    exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
+    menu = !(style & WS_CHILD) && GetMenu(hwnd) != 0;
+
+    GetWindowRect(hwnd, &rc_window);
+    trace("window: (%ld,%ld)-(%ld,%ld)\n", rc_window.left, rc_window.top, rc_window.right, rc_window.bottom);
+    GetClientRect(hwnd, &rc_client);
+    trace("client: (%ld,%ld)-(%ld,%ld)\n", rc_client.left, rc_client.top, rc_client.right, rc_client.bottom);
+
+    /* avoid some cases when things go wrong */
+    if (IsRectEmpty(&rc_window) || IsRectEmpty(&rc_client) ||
+	rc_window.right > 32768 || rc_window.bottom > 32768) return;
+
+    CopyRect(&rc, &rc_client);
+    MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
+    AdjustWindowRectEx(&rc, style, menu, exstyle);
+    trace("calc window: (%ld,%ld)-(%ld,%ld)\n", rc.left, rc.top, rc.right, rc.bottom);
+#if 0 /* Uncomment this once the test succeeds in all cases */
+    ok(EqualRect(&rc, &rc_window), "window rect does not match\n");
+#endif
+
+    CopyRect(&rc, &rc_window);
+    DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc);
+    MapWindowPoints(0, hwnd, (LPPOINT)&rc, 2);
+    trace("calc client: (%ld,%ld)-(%ld,%ld)\n", rc.left, rc.top, rc.right, rc.bottom);
+#if 0 /* Uncomment this once the test succeeds in all cases */
+    ok(EqualRect(&rc, &rc_client), "client rect does not match\n");
+#endif
+
+    /* and now test AdjustWindowRectEx and WM_NCCALCSIZE on synthetic data */
+    SetRect(&rc_client, 0, 0, 250, 150);
+    CopyRect(&rc_window, &rc_client);
+    MapWindowPoints(hwnd, 0, (LPPOINT)&rc_window, 2);
+    AdjustWindowRectEx(&rc_window, style, menu, exstyle);
+    trace("calc window: (%ld,%ld)-(%ld,%ld)\n",
+	rc_window.left, rc_window.top, rc_window.right, rc_window.bottom);
+
+    CopyRect(&rc, &rc_window);
+    DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc);
+    MapWindowPoints(0, hwnd, (LPPOINT)&rc, 2);
+    trace("calc client: (%ld,%ld)-(%ld,%ld)\n", rc.left, rc.top, rc.right, rc.bottom);
+#if 0 /* Uncomment this once the test succeeds in all cases */
+    ok(EqualRect(&rc, &rc_client), "client rect does not match\n");
+#endif
+}
+
 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
 { 
     static const char *CBT_code_name[10] = {
@@ -626,6 +694,32 @@ static LRESULT CALLBACK cbt_hook_proc(in
 
     trace("CBT: %d (%s), %08x, %08lx\n", nCode, code_name, wParam, lParam);
 
+    /* on HCBT_DESTROYWND window state is undefined */
+    if (nCode != HCBT_DESTROYWND && wParam)
+    {
+	BOOL is_win9x = GetWindowLongW((HWND)wParam, GWL_WNDPROC) == 0;
+	if (is_win9x && nCode == HCBT_CREATEWND)
+	    /* Win9x doesn't like WM_NCCALCSIZE with synthetic data and crashes */;
+	else
+	    test_nonclient_area((HWND)wParam);
+
+	if (pGetWindowInfo)
+	{
+	    WINDOWINFO info;
+
+	    info.cbSize = 0;
+	    ok(pGetWindowInfo((HWND)wParam, &info), "GetWindowInfo should not fail\n");
+	    /* win2k SP4 returns broken border info if GetWindowInfo
+	     * is being called from HCBT_DESTROYWND or HCBT_MINMAX hook proc.
+	     */
+	    verify_window_info((HWND)wParam, &info, nCode != HCBT_MINMAX);
+
+	    info.cbSize = sizeof(WINDOWINFO) + 1;
+	    ok(pGetWindowInfo((HWND)wParam, &info), "GetWindowInfo should not fail\n");
+	    verify_window_info((HWND)wParam, &info, nCode != HCBT_MINMAX);
+	}
+    }
+
     switch (nCode)
     {
 	case HCBT_CREATEWND:
@@ -689,25 +783,6 @@ static LRESULT CALLBACK cbt_hook_proc(in
 #endif
 	    break;
 	}
-
-	case HCBT_DESTROYWND:
-	case HCBT_SETFOCUS:
-	    if (wParam && pGetWindowInfo)
-	    {
-		WINDOWINFO info;
-
-		info.cbSize = 0;
-		ok(pGetWindowInfo((HWND)wParam, &info), "GetWindowInfo should not fail\n");
-		/* win2k SP4 returns broken border info if GetWindowInfo
-		 * is being called from HCBT_DESTROYWND hook proc.
-		 */
-		verify_window_info((HWND)wParam, &info, nCode != HCBT_DESTROYWND);
-
-		info.cbSize = sizeof(WINDOWINFO) + 1;
-		ok(pGetWindowInfo((HWND)wParam, &info), "GetWindowInfo should not fail\n");
-		verify_window_info((HWND)wParam, &info, nCode != HCBT_DESTROYWND);
-	    }
-	    break;
     }
 
     return CallNextHookEx(hhook, nCode, wParam, lParam);
@@ -1265,10 +1340,29 @@ static LRESULT WINAPI mdi_child_wnd_proc
             break;
         }
 
-        case WM_WINDOWPOSCHANGING:
         case WM_WINDOWPOSCHANGED:
         {
             WINDOWPOS *winpos = (WINDOWPOS *)lparam;
+            RECT rc1, rc2;
+
+            GetWindowRect(hwnd, &rc1);
+            trace("window: (%ld,%ld)-(%ld,%ld)\n", rc1.left, rc1.top, rc1.right, rc1.bottom);
+            SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy);
+            /* note: winpos coordinates are relative to parent */
+            MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2);
+            trace("pos: (%ld,%ld)-(%ld,%ld)\n", rc2.left, rc2.top, rc2.right, rc2.bottom);
+            ok(EqualRect(&rc1, &rc2), "rects do not match\n");
+
+            GetWindowRect(hwnd, &rc1);
+            GetClientRect(hwnd, &rc2);
+            DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1);
+            MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2);
+            ok(EqualRect(&rc1, &rc2), "rects do not match\n");
+        }
+        /* fall through */
+        case WM_WINDOWPOSCHANGING:
+        {
+            WINDOWPOS *winpos = (WINDOWPOS *)lparam;
             WINDOWPOS my_winpos = *winpos;
 
             trace("%s\n", (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
@@ -1333,6 +1427,48 @@ static LRESULT WINAPI mdi_main_wnd_procA
             break;
         }
 
+        case WM_WINDOWPOSCHANGED:
+        {
+            WINDOWPOS *winpos = (WINDOWPOS *)lparam;
+            RECT rc1, rc2;
+
+            GetWindowRect(hwnd, &rc1);
+            trace("window: (%ld,%ld)-(%ld,%ld)\n", rc1.left, rc1.top, rc1.right, rc1.bottom);
+            SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy);
+            /* note: winpos coordinates are relative to parent */
+            MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2);
+            trace("pos: (%ld,%ld)-(%ld,%ld)\n", rc2.left, rc2.top, rc2.right, rc2.bottom);
+            ok(EqualRect(&rc1, &rc2), "rects do not match\n");
+
+            GetWindowRect(hwnd, &rc1);
+            GetClientRect(hwnd, &rc2);
+            DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1);
+            MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2);
+            ok(EqualRect(&rc1, &rc2), "rects do not match\n");
+        }
+        /* fall through */
+        case WM_WINDOWPOSCHANGING:
+        {
+            WINDOWPOS *winpos = (WINDOWPOS *)lparam;
+            WINDOWPOS my_winpos = *winpos;
+
+            trace("%s\n", (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
+            trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+                  winpos->hwnd, winpos->hwndInsertAfter,
+                  winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
+
+            DefWindowProcA(hwnd, msg, wparam, lparam);
+
+            trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+                  winpos->hwnd, winpos->hwndInsertAfter,
+                  winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
+
+            ok(!memcmp(&my_winpos, winpos, sizeof(WINDOWPOS)),
+               "DefWindowProc should not change WINDOWPOS values\n");
+
+            return 1;
+        }
+
         case WM_CLOSE:
             PostQuitMessage(0);
             break;
@@ -1457,6 +1593,11 @@ static void test_icons(void)
 
 static void test_SetWindowPos(HWND hwnd)
 {
+    BOOL is_win9x = GetWindowLongW(hwnd, GWL_WNDPROC) == 0;
+
+    /* Win9x truncates coordinates to 16-bit irrespectively */
+    if (is_win9x) return;
+
     SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOMOVE);
     SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOMOVE);
 
@@ -1468,19 +1609,24 @@ static void test_SetMenu(HWND parent)
 {
     HWND child;
     HMENU hMenu, ret;
+    BOOL is_win9x = GetWindowLongW(parent, GWL_WNDPROC) == 0;
 
     hMenu = CreateMenu();
     assert(hMenu);
 
     ok(SetMenu(parent, hMenu), "SetMenu on a top level window should not fail\n");
+    test_nonclient_area(parent);
     ret = GetMenu(parent);
-    ok(ret == (HMENU)hMenu, "unexpected menu id %p\n", ret);
+    ok(ret == hMenu, "unexpected menu id %p\n", ret);
     /* test whether we can destroy a menu assigned to a window */
     ok(DestroyMenu(hMenu), "DestroyMenu error %ld\n", GetLastError());
     ok(!IsMenu(hMenu), "menu handle should be not valid after DestroyMenu\n");
     ret = GetMenu(parent);
-    ok(ret == (HMENU)hMenu, "unexpected menu id %p\n", ret);
+    /* This test fails on Win9x */
+    if (!is_win9x)
+        ok(ret == hMenu, "unexpected menu id %p\n", ret);
     ok(SetMenu(parent, 0), "SetMenu(0) on a top level window should not fail\n");
+    test_nonclient_area(parent);
 
     hMenu = CreateMenu();
     assert(hMenu);
@@ -1490,14 +1636,17 @@ static void test_SetMenu(HWND parent)
     ok(ret == 0, "unexpected menu id %p\n", ret);
 
     ok(!SetMenu(parent, (HMENU)20), "SetMenu with invalid menu handle should fail\n");
+    test_nonclient_area(parent);
     ret = GetMenu(parent);
     ok(ret == 0, "unexpected menu id %p\n", ret);
 
     ok(SetMenu(parent, hMenu), "SetMenu on a top level window should not fail\n");
+    test_nonclient_area(parent);
     ret = GetMenu(parent);
-    ok(ret == (HMENU)hMenu, "unexpected menu id %p\n", ret);
+    ok(ret == hMenu, "unexpected menu id %p\n", ret);
 
     ok(SetMenu(parent, 0), "SetMenu(0) on a top level window should not fail\n");
+    test_nonclient_area(parent);
     ret = GetMenu(parent);
     ok(ret == 0, "unexpected menu id %p\n", ret);
  
@@ -1509,14 +1658,17 @@ static void test_SetMenu(HWND parent)
     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
 
     ok(!SetMenu(child, (HMENU)20), "SetMenu with invalid menu handle should fail\n");
+    test_nonclient_area(child);
     ret = GetMenu(child);
     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
 
     ok(!SetMenu(child, hMenu), "SetMenu on a child window should fail\n");
+    test_nonclient_area(child);
     ret = GetMenu(child);
     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
 
     ok(!SetMenu(child, 0), "SetMenu(0) on a child window should fail\n");
+    test_nonclient_area(child);
     ret = GetMenu(child);
     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
 






More information about the wine-patches mailing list