From d5389dd8bb868076b75675719d529d0507a90815 Mon Sep 17 00:00:00 2001 From: katahiromz Date: Thu, 11 Oct 2018 13:47:02 +0900 Subject: [PATCH] user32: Implement CascadeWindows. Changes Minor formatting Added WCHAR for FindWindowW parameters Use stanard heap_ functions. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45968 Signed-off-by: Hirofumi Katayama --- dlls/user32/mdi.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 214 insertions(+), 2 deletions(-) diff --git a/dlls/user32/mdi.c b/dlls/user32/mdi.c index 10a3882..2e93056 100644 --- a/dlls/user32/mdi.c +++ b/dlls/user32/mdi.c @@ -2,6 +2,7 @@ * * Copyright 1994, Bob Amstadt * 1995,1996 Alex Korobka + * Copyright 2018 Katayama Hirofumi MZ * * This file contains routines to support MDI (Multiple Document * Interface) features . @@ -1846,12 +1847,223 @@ done: * Success: Number of cascaded windows. * Failure: 0 */ + +typedef struct CASCADE_INFO +{ + HWND top; + UINT flags; + HWND parent; + HWND desktop; + HWND tray_wnd; + HWND progman; + HWND *wnd_array; + DWORD wnd_count; +} CASCADE_INFO; + +static BOOL CALLBACK GetCascadeChildProc(HWND hwnd, LPARAM lParam) +{ + DWORD count, size; + HWND *wnd_array; + CASCADE_INFO *info = (CASCADE_INFO *)lParam; + + if (hwnd == info->desktop || hwnd == info->tray_wnd || + hwnd == info->progman || hwnd == info->top) + { + return TRUE; + } + + if (info->parent && GetParent(hwnd) != info->parent) + return TRUE; + + if ((info->flags & MDITILE_SKIPDISABLED) && !IsWindowEnabled(hwnd)) + return TRUE; + + if (!IsWindowVisible(hwnd) || IsIconic(hwnd)) + return TRUE; + + count = info->wnd_count; + size = (count + 1) * sizeof(HWND); + + if (count == 0 || !info->wnd_array) + { + count = 0; + info->wnd_array = (HWND *)heap_alloc(size); + } + else + { + wnd_array = (HWND *)heap_realloc(info->wnd_array, size); + if (!wnd_array) + { + heap_free(info->wnd_array); + } + info->wnd_array = wnd_array; + } + + if (!info->wnd_array) + { + info->wnd_count = 0; + return FALSE; + } + + info->wnd_array[count] = hwnd; + info->wnd_count = count + 1; + return TRUE; +} + +static BOOL +QuerySizeFix(HWND hwnd, INT *pcx, INT *pcy) +{ + MINMAXINFO mmi; + DWORD_PTR result; + + mmi.ptMinTrackSize.x = mmi.ptMinTrackSize.y = 0; + mmi.ptMaxTrackSize.x = mmi.ptMaxTrackSize.y = MAXLONG; + if (SendMessageTimeoutW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&mmi, + SMTO_ABORTIFHUNG | SMTO_NORMAL, 120, &result)) + { + *pcx = min(max(*pcx, mmi.ptMinTrackSize.x), mmi.ptMaxTrackSize.x); + *pcy = min(max(*pcy, mmi.ptMinTrackSize.y), mmi.ptMaxTrackSize.y); + return TRUE; + } + return FALSE; +} + WORD WINAPI CascadeWindows (HWND hwndParent, UINT wFlags, const RECT *lpRect, UINT cKids, const HWND *lpKids) { - FIXME("(%p,0x%08x,...,%u,...): stub\n", hwndParent, wFlags, cKids); - return 0; + static WCHAR shelltray[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0}; + static WCHAR progman[] = {'P','r','o','g','m','a','n',0}; + CASCADE_INFO info; + HWND hwnd, top, prev; + HMONITOR monitor; + MONITORINFO mi; + RECT work_rect, wnd_rect; + DWORD i, ret = 0; + INT x, y, width, height, new_width, new_height, work_width, work_height, dx, dy; + HDWP hDWP; + POINT pt; + + TRACE("(%p,0x%08x,%p,%u,%p)\n", hwndParent, wFlags, lpRect, cKids, lpKids); + + top = GetTopWindow(hwndParent); + + ZeroMemory(&info, sizeof(info)); + info.desktop = GetDesktopWindow(); + info.tray_wnd = FindWindowW(shelltray, NULL); + info.progman = FindWindowW(progman, NULL); + info.parent = hwndParent; + info.flags = wFlags; + + if (cKids == 0 || lpKids == NULL) + { + info.top = top; + EnumChildWindows(hwndParent, GetCascadeChildProc, (LPARAM)&info); + + info.top = NULL; + GetCascadeChildProc(top, (LPARAM)&info); + } + else + { + info.wnd_count = cKids; + info.wnd_array = (HWND *)lpKids; + } + + if (info.wnd_count == 0 || info.wnd_array == NULL) + return ret; + + if (lpRect) + { + work_rect = *lpRect; + } + else if (hwndParent) + { + GetClientRect(hwndParent, &work_rect); + } + else + { + pt.x = pt.y = 0; + monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); + mi.cbSize = sizeof(mi); + GetMonitorInfoW(monitor, &mi); + work_rect = mi.rcWork; + } + + hDWP = BeginDeferWindowPos(info.wnd_count); + if (hDWP == NULL) + goto cleanup; + + x = work_rect.left; + y = work_rect.top; + dx = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXSIZE); + dy = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYSIZE); + work_width = work_rect.right - work_rect.left; + work_height = work_rect.bottom - work_rect.top; + prev = NULL; + for (i = info.wnd_count; i > 0;) /* in reverse order */ + { + --i; + hwnd = info.wnd_array[i]; + + if (!IsWindowVisible(hwnd) || IsIconic(hwnd)) + continue; + + if ((info.flags & MDITILE_SKIPDISABLED) && !IsWindowEnabled(hwnd)) + continue; + + if (IsZoomed(hwnd)) + ShowWindow(hwnd, SW_RESTORE | SW_SHOWNA); + + GetWindowRect(hwnd, &wnd_rect); + new_width = width = wnd_rect.right - wnd_rect.left; + new_height = height = wnd_rect.bottom - wnd_rect.top; + + /* if we can change the window size and it is not only one */ + if (info.wnd_count != 1 && (GetWindowLongPtrW(hwnd, GWL_STYLE) & WS_THICKFRAME)) + { + /* check the size */ +#define THRESHOLD(xy) (((xy) * 5) / 7) /* in the rate 5/7 */ + new_width = min(new_width, THRESHOLD(work_width)); + new_height = min(new_height, THRESHOLD(work_height)); +#undef THRESHOLD + if (width != new_width || height != new_height) + { + /* too large. shrink if we can */ + if (QuerySizeFix(hwnd, &new_width, &new_height)) + { + width = new_width; + height = new_height; + } + } + } + + if (x + width > work_rect.right) + x = work_rect.left; + if (y + height > work_rect.bottom) + y = work_rect.top; + + hDWP = DeferWindowPos(hDWP, hwnd, HWND_TOP, x, y, width, height, SWP_NOACTIVATE); + if (hDWP == NULL) + { + ret = 0; + goto cleanup; + } + + x += dx; + y += dy; + prev = hwnd; + ++ret; + } + + EndDeferWindowPos(hDWP); + + if (prev) + SetForegroundWindow(prev); + +cleanup: + heap_free(info.wnd_array); + + return (WORD)ret; } -- 1.9.1