From 922dc3122476a8b16e7213c9eeb9d4d15dd525b9 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Thu, 16 Oct 2008 19:58:56 +0900 Subject: [PATCH] user32: Add a test for fullscreen window sizing, make it pass under Wine. It appears that Windows doesn't always restrict the window size by the monitor work area. The tests pass under XP SP3 and Win98. --- dlls/user32/tests/win.c | 191 ++++++++++++++++++++++++++++++++++++++++ dlls/user32/winpos.c | 21 +++-- 2 files changed, 206 insertions(+), 6 deletions(-) diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index db1de113700..1b9d7291f03 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -49,6 +49,8 @@ static BOOL (WINAPI *pGetWindowInfo)(HWND,WINDOWINFO*); static UINT (WINAPI *pGetWindowModuleFileNameA)(HWND,LPSTR,UINT); static BOOL (WINAPI *pGetLayeredWindowAttributes)(HWND,COLORREF*,BYTE*,DWORD*); static BOOL (WINAPI *pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD); +static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO); +static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD); static BOOL test_lbuttondown_flag; static HWND hwndMessage; @@ -4906,6 +4908,192 @@ static void test_layered_window(void) DestroyWindow( hwnd ); } +static MONITORINFO mi; + +static LRESULT CALLBACK fullscreen_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + switch (msg) + { + case WM_NCCREATE: + { + CREATESTRUCTA *cs = (CREATESTRUCTA *)lp; + trace("WM_NCCREATE: rect %d,%d-%d,%d\n", cs->x, cs->y, cs->cx, cs->cy); + ok(cs->x == mi.rcMonitor.left && cs->y == mi.rcMonitor.top && + cs->cx == mi.rcMonitor.right && cs->cy == mi.rcMonitor.bottom, + "expected %d,%d-%d,%d, got %d,%d-%d,%d\n", + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + cs->x, cs->y, cs->cx, cs->cy); + break; + } + case WM_GETMINMAXINFO: + { + MINMAXINFO *minmax = (MINMAXINFO *)lp; + dump_minmax_info(minmax); + ok(minmax->ptMaxPosition.x <= mi.rcMonitor.left, "%d <= %d\n", minmax->ptMaxPosition.x, mi.rcMonitor.left); + ok(minmax->ptMaxPosition.y <= mi.rcMonitor.top, "%d <= %d\n", minmax->ptMaxPosition.y, mi.rcMonitor.top); + ok(minmax->ptMaxSize.x >= mi.rcMonitor.right, "%d >= %d\n", minmax->ptMaxSize.x, mi.rcMonitor.right); + ok(minmax->ptMaxSize.y >= mi.rcMonitor.bottom, "%d >= %d\n", minmax->ptMaxSize.y, mi.rcMonitor.bottom); + break; + } + } + return DefWindowProc(hwnd, msg, wp, lp); +} + +static void test_fullscreen(void) +{ + static const DWORD t_style[] = { + WS_OVERLAPPED, WS_POPUP, WS_CHILD, WS_THICKFRAME, WS_DLGFRAME + }; + static const DWORD t_ex_style[] = { + 0, WS_EX_APPWINDOW, WS_EX_TOOLWINDOW + }; + WNDCLASS cls; + HWND hwnd; + int i, j; + POINT pt; + RECT rc; + HMONITOR hmon; + LRESULT ret; + + if (!pGetMonitorInfoA || !pMonitorFromPoint) + { + win_skip("GetMonitorInfoA or MonitorFromPoint are not available on this platform\n"); + return; + } + + pt.x = pt.y = 0; + SetLastError(0xdeadbeef); + hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); + ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError()); + + mi.cbSize = sizeof(mi); + SetLastError(0xdeadbeef); + ret = pGetMonitorInfoA(hmon, &mi); + ok(ret, "GetMonitorInfo error %u\n", GetLastError()); + trace("monitor (%d,%d-%d,%d), work (%d,%d-%d,%d)\n", + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom); + + cls.style = 0; + cls.lpfnWndProc = fullscreen_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandle(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "fullscreen_class"; + RegisterClass(&cls); + + for (i = 0; i < sizeof(t_style)/sizeof(t_style[0]); i++) + { + DWORD style, ex_style; + + /* avoid a WM interaction */ + assert(!(t_style[i] & WS_VISIBLE)); + + for (j = 0; j < sizeof(t_ex_style)/sizeof(t_ex_style[0]); j++) + { + int fixup; + + style = t_style[i]; + ex_style = t_ex_style[j]; + + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && + rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + + style = t_style[i] | WS_MAXIMIZE; + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && + rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + + style = t_style[i] | WS_MAXIMIZE | WS_CAPTION; + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && + rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + + style = t_style[i] | WS_CAPTION | WS_MAXIMIZEBOX; + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && + rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + + style = t_style[i] | WS_MAXIMIZE | WS_CAPTION | WS_MAXIMIZEBOX; + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + /* Windows makes a maximized window slightly larger (to hide the borders?) */ + fixup = min(abs(rc.left), abs(rc.top)); + InflateRect(&rc, -fixup, -fixup); + /* FIXME: this doesn't work correctly in Wine for child windows yet */ + if (style & WS_CHILD) + todo_wine + ok(rc.left >= mi.rcWork.left && rc.top <= mi.rcWork.top && + rc.right <= mi.rcWork.right && rc.bottom <= mi.rcWork.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + else + ok(rc.left >= mi.rcWork.left && rc.top <= mi.rcWork.top && + rc.right <= mi.rcWork.right && rc.bottom <= mi.rcWork.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + + style = t_style[i] | WS_MAXIMIZE | WS_MAXIMIZEBOX; + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + /* Windows makes a maximized window slightly larger (to hide the borders?) */ + fixup = min(abs(rc.left), abs(rc.top)); + InflateRect(&rc, -fixup, -fixup); + if (style & (WS_CHILD | WS_POPUP)) + ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && + rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + else + ok(rc.left >= mi.rcWork.left && rc.top <= mi.rcWork.top && + rc.right <= mi.rcWork.right && rc.bottom <= mi.rcWork.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + } + } + + UnregisterClass("MinMax_WndClass", GetModuleHandle(0)); +} + START_TEST(win) { HMODULE user32 = GetModuleHandleA( "user32.dll" ); @@ -4914,6 +5102,8 @@ START_TEST(win) pGetWindowModuleFileNameA = (void *)GetProcAddress( user32, "GetWindowModuleFileNameA" ); pGetLayeredWindowAttributes = (void *)GetProcAddress( user32, "GetLayeredWindowAttributes" ); pSetLayeredWindowAttributes = (void *)GetProcAddress( user32, "SetLayeredWindowAttributes" ); + pGetMonitorInfoA = (void *)GetProcAddress( user32, "GetMonitorInfoA" ); + pMonitorFromPoint = (void *)GetProcAddress( user32, "MonitorFromPoint" ); if (!RegisterWindowClasses()) assert(0); @@ -4936,6 +5126,7 @@ START_TEST(win) our_pid = GetWindowThreadProcessId(hwndMain, NULL); /* Add the tests below this line */ + test_fullscreen(); test_hwnd_message(); test_nonclient_area(hwndMain); test_params(); diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index cbe844a8553..4f5005cf32a 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -654,8 +654,8 @@ void WINPOS_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos, MINMAXINFO MinMax; HMONITOR monitor; INT xinc, yinc; - LONG style = GetWindowLongA( hwnd, GWL_STYLE ); - LONG exstyle = GetWindowLongA( hwnd, GWL_EXSTYLE ); + LONG style = GetWindowLongW( hwnd, GWL_STYLE ); + LONG exstyle = GetWindowLongW( hwnd, GWL_EXSTYLE ); RECT rc; WND *win; @@ -725,21 +725,30 @@ void WINPOS_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos, if ((monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY ))) { + RECT rc_work; MONITORINFO mon_info; mon_info.cbSize = sizeof(mon_info); GetMonitorInfoW( monitor, &mon_info ); + rc_work = mon_info.rcMonitor; + + if (style & WS_MAXIMIZEBOX) + { + if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP))) + rc_work = mon_info.rcWork; + } + if (MinMax.ptMaxSize.x == GetSystemMetrics(SM_CXSCREEN) + 2 * xinc && MinMax.ptMaxSize.y == GetSystemMetrics(SM_CYSCREEN) + 2 * yinc) { - MinMax.ptMaxSize.x = (mon_info.rcWork.right - mon_info.rcWork.left) + 2 * xinc; - MinMax.ptMaxSize.y = (mon_info.rcWork.bottom - mon_info.rcWork.top) + 2 * yinc; + MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc; + MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc; } if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc) { - MinMax.ptMaxPosition.x = mon_info.rcWork.left - xinc; - MinMax.ptMaxPosition.y = mon_info.rcWork.top - yinc; + MinMax.ptMaxPosition.x = rc_work.left - xinc; + MinMax.ptMaxPosition.y = rc_work.top - yinc; } }