[USER32][WIN32SS] Implement CascadeWindows function (#676)
authorKatayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
Sun, 8 Jul 2018 23:51:14 +0000 (08:51 +0900)
committerHermès BÉLUSCA - MAÏTO <hermes.belusca-maito@reactos.org>
Sun, 8 Jul 2018 23:51:14 +0000 (01:51 +0200)
CORE-14807

win32ss/user/user32/windows/mdi.c

index 9f25daf..38ee4af 100644 (file)
@@ -1,10 +1,11 @@
 /* MDI.C
  *
  * Copyright 1994, Bob Amstadt
- *           1995,1996 Alex Korobka
+ * Copyright 1995,1996 Alex Korobka
+ * Copyright 2018 Katayama Hirofumi MZ
  *
  * This file contains routines to support MDI (Multiple Document
- * Interface) features .
+ * Interface) features.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,7 +23,7 @@
  *
  * Notes: Fairly complete implementation.
  *        Also, Excel and WinWord do _not_ use MDI so if you're trying
- *       to fix them look elsewhere.
+ *        to fix them look elsewhere.
  *
  * Notes on how the "More Windows..." is implemented:
  *
@@ -1975,7 +1976,6 @@ void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
                        SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
 }
 
-
 /******************************************************************************
  *             CascadeWindows (USER32.@) Cascades MDI child windows
  *
@@ -1983,12 +1983,182 @@ void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
  *    Success: Number of cascaded windows.
  *    Failure: 0
  */
+
+typedef struct CASCADE_INFO
+{
+    HWND hwndTop;
+    UINT wFlags;
+    HWND hwndParent;
+    HWND hwndDesktop;
+    HWND hTrayWnd;
+    HWND hwndProgman;
+    HWND *ahwnd;
+    DWORD chwnd;
+} CASCADE_INFO;
+
+static BOOL CALLBACK
+GetCascadeChildProc(HWND hwnd, LPARAM lParam)
+{
+    DWORD count, size;
+    HWND *ahwnd;
+    CASCADE_INFO *pInfo = (CASCADE_INFO *)lParam;
+
+    if (hwnd == pInfo->hwndDesktop || hwnd == pInfo->hTrayWnd ||
+        hwnd == pInfo->hwndProgman || hwnd == pInfo->hwndTop)
+    {
+        return TRUE;
+    }
+
+    if (pInfo->hwndParent && GetParent(hwnd) != pInfo->hwndParent)
+        return TRUE;
+
+    if ((pInfo->wFlags & MDITILE_SKIPDISABLED) && !IsWindowEnabled(hwnd))
+        return TRUE;
+
+    if (!IsWindowVisible(hwnd) || IsIconic(hwnd))
+        return TRUE;
+
+    count = pInfo->chwnd;
+    size = (count + 1) * sizeof(HWND);
+
+    if (count == 0 || pInfo->ahwnd == NULL)
+    {
+        count = 0;
+        pInfo->ahwnd = (HWND *)HeapAlloc(GetProcessHeap(), 0, size);
+    }
+    else
+    {
+        ahwnd = (HWND *)HeapReAlloc(GetProcessHeap(), 0, pInfo->ahwnd, size);
+        if (ahwnd == NULL)
+        {
+            HeapFree(GetProcessHeap(), 0, pInfo->ahwnd);
+        }
+        pInfo->ahwnd = ahwnd;
+    }
+
+    if (pInfo->ahwnd == NULL)
+    {
+        pInfo->chwnd = 0;
+        return FALSE;
+    }
+
+    pInfo->ahwnd[count] = hwnd;
+    pInfo->chwnd = count + 1;
+    return TRUE;
+}
+
 WORD WINAPI
-CascadeWindows (HWND hwndParent, UINT wFlags, LPCRECT lpRect,
-               UINT cKids, const HWND *lpKids)
+CascadeWindows(HWND hwndParent, UINT wFlags, LPCRECT lpRect,
+               UINT cKids, const HWND *lpKids)
 {
-    FIXME("(%p,0x%08x,...,%u,...): stub\n", hwndParent, wFlags, cKids);
-    return 0;
+    CASCADE_INFO info;
+    HWND hwnd, hwndTop, hwndPrev;
+    HMONITOR hMon;
+    MONITORINFO mi;
+    RECT rcWork, rcWnd;
+    DWORD i, ret = 0;
+    INT x, y, cx, cy, dx, dy;
+    HDWP hDWP;
+
+    TRACE("(%p,0x%08x,...,%u,...)\n", hwndParent, wFlags, cKids);
+
+    hwndTop = GetTopWindow(hwndParent);
+
+    ZeroMemory(&info, sizeof(info));
+    info.hwndDesktop = GetDesktopWindow();
+    info.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
+    info.hwndProgman = FindWindowW(L"Progman", NULL);
+    info.hwndParent = hwndParent;
+    info.wFlags = wFlags;
+
+    if (cKids == 0 || lpKids == NULL)
+    {
+        info.hwndTop = hwndTop;
+        EnumChildWindows(hwndParent, GetCascadeChildProc, (LPARAM)&info);
+
+        info.hwndTop = NULL;
+        GetCascadeChildProc(hwndTop, (LPARAM)&info);
+    }
+    else
+    {
+        info.chwnd = cKids;
+        info.ahwnd = (HWND *)lpKids;
+    }
+
+    if (info.chwnd == 0 || info.ahwnd == NULL)
+        return ret;
+
+    if (lpRect)
+    {
+        rcWork = *lpRect;
+    }
+    else if (hwndParent)
+    {
+        GetClientRect(hwndParent, &rcWork);
+    }
+    else
+    {
+        hMon = MonitorFromWindow(hwndParent, MONITOR_DEFAULTTONEAREST);
+        mi.cbSize = sizeof(mi);
+        GetMonitorInfoW(hMon, &mi);
+        rcWork = mi.rcWork;
+    }
+
+    hDWP = BeginDeferWindowPos(info.chwnd);
+    if (hDWP == NULL)
+        goto cleanup;
+
+    x = rcWork.left;
+    y = rcWork.top;
+    dx = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXSIZE);
+    dy = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYSIZE);
+    hwndPrev = NULL;
+    for (i = info.chwnd; i > 0;)    /* in reverse order */
+    {
+        --i;
+        hwnd = info.ahwnd[i];
+
+        if (IsZoomed(hwnd))
+            ShowWindow(hwnd, SW_RESTORE | SW_SHOWNA);
+
+        GetWindowRect(hwnd, &rcWnd);
+        cx = rcWnd.right - rcWnd.left;
+        cy = rcWnd.bottom - rcWnd.top;
+
+        if (x + cx > rcWork.right)
+            x = rcWork.left;
+        if (y + cy > rcWork.bottom)
+            y = rcWork.top;
+
+        if (!IsWindowVisible(hwnd) || IsIconic(hwnd))
+            continue;
+
+        if ((info.wFlags & MDITILE_SKIPDISABLED) && !IsWindowEnabled(hwnd))
+            continue;
+
+        hDWP = DeferWindowPos(hDWP, hwnd, HWND_TOP, x, y, cx, cy, SWP_NOACTIVATE);
+        if (hDWP == NULL)
+        {
+            ret = 0;
+            goto cleanup;
+        }
+
+        x += dx;
+        y += dy;
+        hwndPrev = hwnd;
+        ++ret;
+    }
+
+    EndDeferWindowPos(hDWP);
+
+    if (hwndPrev)
+        SetForegroundWindow(hwndPrev);
+
+cleanup:
+    if (cKids == 0 || lpKids == NULL)
+        HeapFree(GetProcessHeap(), 0, info.ahwnd);
+
+    return (WORD)ret;
 }