From: Elizabeth Figura zfigura@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45968 --- dlls/user32/mdi.c | 25 ----- dlls/user32/tests/win.c | 211 ++++++++++++++++++++++++++++++++++++++++ dlls/user32/win.c | 95 ++++++++++++++++++ 3 files changed, 306 insertions(+), 25 deletions(-)
diff --git a/dlls/user32/mdi.c b/dlls/user32/mdi.c index e2cecc0bf46..b782d481a00 100644 --- a/dlls/user32/mdi.c +++ b/dlls/user32/mdi.c @@ -1792,31 +1792,6 @@ done: }
-/****************************************************************************** - * CascadeWindows (USER32.@) Cascades MDI child windows - * - * RETURNS - * Success: Number of cascaded windows. - * Failure: 0 - */ -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; -} - - -/*********************************************************************** - * CascadeChildWindows (USER32.@) - */ -WORD WINAPI CascadeChildWindows( HWND parent, UINT flags ) -{ - return CascadeWindows( parent, flags, NULL, 0, NULL ); -} - - /****************************************************************************** * TileWindows (USER32.@) Tiles MDI child windows * diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 08b0a5c88e7..05534e5c3f5 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -13795,6 +13795,216 @@ static void test_startupinfo_showwindow( char **argv ) } }
+static void test_cascade_windows(void) +{ + unsigned int spacing = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYDLGFRAME); + static const unsigned int zorder[] = {1, 3, 5, 2, 9, 4, 8, 6, 0, 7}; + RECT orig = {100, 200, 300, 400}, parent_client, rect, prev, expect; + unsigned int width, height; + HWND parent, hwnds[10]; + POINT pt = {0}; + WORD ret; + + parent = CreateWindowA("static", "parent", WS_OVERLAPPEDWINDOW, + 0, 0, 600, 300, NULL, 0, 0, NULL); + ok(!!parent, "failed to create window, error %lu\n", GetLastError()); + + GetClientRect(parent, &parent_client); + + ClientToScreen(parent, &pt); + + SetLastError(0xdeadbeef); + ret = CascadeWindows(parent, 0, NULL, 0, NULL); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError()); + + for (unsigned int i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + DWORD style = WS_CHILD | WS_CAPTION | WS_THICKFRAME | WS_VISIBLE; + unsigned int index = zorder[i]; + + if (index == 3) + style &= ~WS_VISIBLE; + if (index == 4) + style &= ~WS_THICKFRAME; + if (index == 6) + style |= WS_DISABLED; + if (index == 7) + style |= WS_MAXIMIZE; + if (index == 8) + style &= ~WS_BORDER; + if (index == 2) + style &= ~WS_DLGFRAME; + + hwnds[index] = CreateWindowA("MainWindowClass", "child", style, + orig.left, orig.top, orig.right - orig.left, orig.bottom - orig.top, parent, 0, 0, NULL); + ok(!!hwnds[index], "failed to create window %u, error %lu\n", index, GetLastError()); + SetWindowPos(hwnds[index], HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + } + + ret = CascadeWindows(parent, MDITILE_SKIPDISABLED, NULL, 0, NULL); + ok(ret == 6, "got %d\n", ret); + + for (unsigned int i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + unsigned int index = zorder[i]; + + GetWindowRect(hwnds[index], &rect); + OffsetRect(&rect, -pt.x, -pt.y); + + if (i == 0) + { + ok(!rect.left && !rect.top, "got position (%ld, %ld)\n", rect.left, rect.top); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + } + else if (index == 3 /* invisible */ || index == 6 /* disabled */ + || index == 8 /* no border */ || index == 2 /* no dlgframe */) + { + ok(EqualRect(&rect, &orig), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + continue; + } + else + { + if (index == 4 /* no THICKFRAME */) + SetRect(&expect, prev.left + spacing, prev.top + spacing, + prev.left + spacing + 200, prev.top + spacing + 200); + else + SetRect(&expect, prev.left + spacing, prev.top + spacing, + prev.left + spacing + width, prev.top + spacing + height); + + if (prev.left + spacing + width > parent_client.right) + { + expect.right = expect.right - expect.left; + expect.left = 0; + } + if (prev.top + spacing + height > parent_client.bottom) + { + expect.bottom = expect.bottom - expect.top; + expect.top = 0; + } + ok(EqualRect(&rect, &expect), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + } + + prev = rect; + } + + SetRect(&rect, 10, 10, 300, 200); + ret = CascadeWindows(parent, 0, &rect, 0, NULL); + ok(ret == 7, "got %d\n", ret); + + for (unsigned int i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + unsigned int index = zorder[i]; + + GetWindowRect(hwnds[index], &rect); + OffsetRect(&rect, -pt.x, -pt.y); + + if (i == 0) + { + ok(rect.left == 10 && rect.top == 10, "got position (%ld, %ld)\n", rect.left, rect.top); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + } + else if (index == 3 /* invisible */ || index == 8 /* no border */ || index == 2 /* no dlgframe */) + { + ok(EqualRect(&rect, &orig), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + continue; + } + else + { + if (index == 4 /* no THICKFRAME */) + SetRect(&expect, prev.left + spacing, prev.top + spacing, + prev.left + spacing + 200, prev.top + spacing + 200); + else + SetRect(&expect, prev.left + spacing, prev.top + spacing, + prev.left + spacing + width, prev.top + spacing + height); + + /* Overflow calculation is based on the width as if the window + * could be resized. */ + if (prev.left + spacing + width > 300) + { + expect.right = 10 + (expect.right - expect.left); + expect.left = 10; + } + if (prev.top + spacing + height > 200) + { + expect.bottom = 10 + (expect.bottom - expect.top); + expect.top = 10; + } + ok(EqualRect(&rect, &expect), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + } + + prev = rect; + } + + /* Pass a list. */ + + /* Destroy one child and replace it with a non-child. */ + DestroyWindow(hwnds[5]); + hwnds[5] = CreateWindowA("MainWindowClass", "child", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + orig.left, orig.top, orig.right - orig.left, orig.bottom - orig.top, parent, 0, 0, NULL); + + MoveWindow(hwnds[6], orig.left, orig.top, orig.right - orig.left, orig.bottom - orig.top, FALSE); + ret = CascadeWindows(parent, MDITILE_SKIPDISABLED, NULL, ARRAY_SIZE(hwnds), hwnds); + ok(ret == 5, "got %d\n", ret); + + for (unsigned int i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + unsigned int index = 9 - i; + + GetWindowRect(hwnds[index], &rect); + if (index != 5) + OffsetRect(&rect, -pt.x, -pt.y); + + if (i == 0) + { + ok(!rect.left && !rect.top, "got position (%ld, %ld)\n", rect.left, rect.top); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + } + else if (index == 3 /* invisible */ || index == 6 /* disabled */ || index == 5 /* not a child */ + || index == 8 /* no border */ || index == 2 /* no dlgframe */) + { + ok(EqualRect(&rect, &orig), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + continue; + } + else + { + if (index == 4 /* no THICKFRAME */) + SetRect(&expect, prev.left + spacing, prev.top + spacing, + prev.left + spacing + 200, prev.top + spacing + 200); + else + SetRect(&expect, prev.left + spacing, prev.top + spacing, + prev.left + spacing + width, prev.top + spacing + height); + + if (prev.left + spacing + width > parent_client.right) + { + expect.right = expect.right - expect.left; + expect.left = 0; + } + if (prev.top + spacing + height > parent_client.bottom) + { + expect.bottom = expect.bottom - expect.top; + expect.top = 0; + } + ok(EqualRect(&rect, &expect), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + } + + prev = rect; + } + + for (unsigned int i = 0; i < ARRAY_SIZE(hwnds); ++i) + DestroyWindow(hwnds[i]); + DestroyWindow(parent); +} + START_TEST(win) { char **argv; @@ -13988,6 +14198,7 @@ START_TEST(win) test_ReleaseCapture(); test_SetProcessLaunchForegroundPolicy(); test_startupinfo_showwindow(argv); + test_cascade_windows();
/* add the tests above this line */ if (hhook) UnhookWindowsHookEx(hhook); diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 330b827f0a3..6192e9f6384 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -1657,3 +1657,98 @@ BOOL WINAPI SetProcessLaunchForegroundPolicy(DWORD pid, DWORD flags) SetLastError(ERROR_ACCESS_DENIED); return FALSE; } + +static BOOL should_move_window( HWND window, HWND parent, DWORD flags ) +{ + DWORD style = GetWindowLongW( window, GWL_STYLE ); + + if (style & WS_MINIMIZE) + return FALSE; + if (!(style & WS_VISIBLE)) + return FALSE; + if ((style & WS_CAPTION) != WS_CAPTION) + return FALSE; + if ((flags & MDITILE_SKIPDISABLED) && (style & WS_DISABLED)) + return FALSE; + if (NtUserGetAncestor( window, GA_PARENT ) != parent) + return FALSE; + return TRUE; +} + +/********************************************************************** + * CascadeWindows (USER32.@) + */ +WORD WINAPI CascadeWindows( HWND parent, UINT flags, const RECT *rect, UINT count, const HWND *windows ) +{ + unsigned int spacing = GetSystemMetrics( SM_CYCAPTION ) + GetSystemMetrics( SM_CYDLGFRAME ); + unsigned int x, y, width, height; + HWND *children = NULL; + WORD ret_count = 0; + RECT client; + + TRACE( "parent %p, flags %#x, rect %s, count %u, windows %p\n", + parent, flags, wine_dbgstr_rect(rect), count, windows ); + + if (flags & ~MDITILE_SKIPDISABLED) + FIXME( "ignoring flags %#x\n", flags & ~MDITILE_SKIPDISABLED ); + + if (!parent) + parent = GetDesktopWindow(); + + if (!rect) + { + GetClientRect( parent, &client ); + rect = &client; + } + + x = rect->left; + y = rect->top; + + /* On Windows these match the dimensions triggered by CW_USEDEFAULT. */ + width = rect->right * 3 / 4; + height = rect->bottom * 3 / 4; + + if (!windows) + { + if (!(children = WIN_ListChildren( parent ))) + return 0; + for (count = 0; children[count]; ++count) + ; + windows = children; + } + + for (unsigned int i = 0; i < count; ++i) + { + HWND child = windows[count - 1 - i]; + DWORD style = GetWindowLongW( child, GWL_STYLE ); + DWORD swp_flags = SWP_NOZORDER | SWP_NOACTIVATE; + + if (!should_move_window( child, parent, flags )) + continue; + + if (!(style & WS_THICKFRAME)) + swp_flags |= SWP_NOSIZE; + NtUserSetWindowPos( child, 0, x, y, width, height, swp_flags ); + + x += spacing; + y += spacing; + if (x + width > rect->right) + x = rect->left; + if (y + height > rect->bottom) + y = rect->top; + + ++ret_count; + } + + HeapFree( GetProcessHeap(), 0, children ); + + return ret_count; +} + +/********************************************************************** + * CascadeChildWindows (USER32.@) + */ +WORD WINAPI CascadeChildWindows( HWND parent, UINT flags ) +{ + return CascadeWindows( parent, flags, NULL, 0, NULL ); +}
From: Elizabeth Figura zfigura@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46197 --- dlls/user32/mdi.c | 25 ------ dlls/user32/tests/win.c | 180 ++++++++++++++++++++++++++++++++++++++++ dlls/user32/win.c | 102 +++++++++++++++++++++++ 3 files changed, 282 insertions(+), 25 deletions(-)
diff --git a/dlls/user32/mdi.c b/dlls/user32/mdi.c index b782d481a00..11c7f98081f 100644 --- a/dlls/user32/mdi.c +++ b/dlls/user32/mdi.c @@ -1792,31 +1792,6 @@ done: }
-/****************************************************************************** - * TileWindows (USER32.@) Tiles MDI child windows - * - * RETURNS - * Success: Number of tiled windows. - * Failure: 0 - */ -WORD WINAPI -TileWindows (HWND hwndParent, UINT wFlags, const RECT *lpRect, - UINT cKids, const HWND *lpKids) -{ - FIXME("(%p,0x%08x,...,%u,...): stub\n", hwndParent, wFlags, cKids); - return 0; -} - - -/*********************************************************************** - * TileChildWindows (USER32.@) - */ -WORD WINAPI TileChildWindows( HWND parent, UINT flags ) -{ - return TileWindows( parent, flags, NULL, 0, NULL ); -} - - /************************************************************************ * "More Windows..." functionality */ diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 05534e5c3f5..4823a774562 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -14005,6 +14005,185 @@ static void test_cascade_windows(void) DestroyWindow(parent); }
+static void test_tile_windows(void) +{ + static const unsigned int zorder[] = {1, 3, 13, 10, 16, 5, 11, 2, 9, 12, 4, 8, 15, 14, 6, 0, 7}; + RECT orig = {100, 200, 300, 400}, parent_client, rect, expect; + unsigned int column, row; + HWND parent, hwnds[17]; + POINT pt = {0}; + WORD ret; + + parent = CreateWindowA("static", "parent", WS_OVERLAPPEDWINDOW, + 0, 0, 600, 300, NULL, 0, 0, NULL); + ok(!!parent, "failed to create window, error %lu\n", GetLastError()); + + GetClientRect(parent, &parent_client); + ClientToScreen(parent, &pt); + + SetLastError(0xdeadbeef); + ret = TileWindows(parent, 0, NULL, 0, NULL); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError()); + + for (unsigned int i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + DWORD style = WS_CHILD | WS_CAPTION | WS_THICKFRAME | WS_VISIBLE; + unsigned int index = zorder[i]; + + if (index == 2) + style &= ~WS_DLGFRAME; + if (index == 3) + style &= ~WS_VISIBLE; + if (index == 4) + style &= ~WS_THICKFRAME; + if (index == 6) + style |= WS_DISABLED; + if (index == 7) + style |= WS_MAXIMIZE; + if (index == 8) + style &= ~WS_BORDER; + + hwnds[index] = CreateWindowA("MainWindowClass", "child", style, + orig.left, orig.top, orig.right - orig.left, orig.bottom - orig.top, parent, 0, 0, NULL); + ok(!!hwnds[index], "failed to create window %u, error %lu\n", index, GetLastError()); + SetWindowPos(hwnds[index], HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + } + + ret = TileWindows(parent, MDITILE_SKIPDISABLED | MDITILE_HORIZONTAL, NULL, 0, NULL); + ok(ret == 13, "got %d\n", ret); + + /* 3 columns: 4, 4, 5 */ + + row = column = 0; + for (unsigned int i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + unsigned int width = (parent_client.right - parent_client.left) / 3; + unsigned int height = (parent_client.bottom - parent_client.top) / (column < 2 ? 4 : 5); + unsigned int index = zorder[ARRAY_SIZE(hwnds) - 1 - i]; + + GetWindowRect(hwnds[index], &rect); + OffsetRect(&rect, -pt.x, -pt.y); + + if (index == 3 /* invisible */ || index == 6 /* disabled */ + || index == 8 /* no border */ || index == 2 /* no dlgframe */) + { + ok(EqualRect(&rect, &orig), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + continue; + } + + if (index == 4 /* no THICKFRAME */) + SetRect(&expect, column * width, row * height, (column * width) + 200, (row * height) + 200); + else + SetRect(&expect, column * width, row * height, (column + 1) * width, (row + 1) * height); + + ok(EqualRect(&rect, &expect), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + ++row; + if (row == 4 && column < 2) + { + row = 0; + ++column; + } + } + + SetRect(&rect, 10, 10, 300, 200); + ret = TileWindows(parent, 0, &rect, 0, NULL); + ok(ret == 14, "got %d\n", ret); + + /* 4 columns: 3, 3, 4, 4 */ + + row = column = 0; + for (unsigned int i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + unsigned int width = (300 - 10) / 4; + unsigned int height = (200 - 10) / (column < 2 ? 3 : 4); + unsigned int index = zorder[ARRAY_SIZE(hwnds) - 1 - i]; + + GetWindowRect(hwnds[index], &rect); + OffsetRect(&rect, -pt.x, -pt.y); + + if (index == 3 /* invisible */ || index == 8 /* no border */ || index == 2 /* no dlgframe */) + { + ok(EqualRect(&rect, &orig), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + continue; + } + + if (index == 4 /* no THICKFRAME */) + SetRect(&expect, column * width, row * height, (column * width) + 200, (row * height) + 200); + else + SetRect(&expect, column * width, row * height, (column + 1) * width, (row + 1) * height); + OffsetRect(&expect, 10, 10); + expect.right = max(expect.right, expect.left + GetSystemMetrics(SM_CXMIN)); + + ok(EqualRect(&rect, &expect), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + ++row; + if ((row == 3 && column < 2) || row == 4) + { + row = 0; + ++column; + } + } + + /* Pass a list. */ + + /* Destroy one child and replace it with a non-child. */ + DestroyWindow(hwnds[5]); + hwnds[5] = CreateWindowA("MainWindowClass", "child", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + orig.left, orig.top, orig.right - orig.left, orig.bottom - orig.top, parent, 0, 0, NULL); + + MoveWindow(hwnds[6], orig.left, orig.top, orig.right - orig.left, orig.bottom - orig.top, FALSE); + ret = TileWindows(parent, MDITILE_SKIPDISABLED, NULL, ARRAY_SIZE(hwnds), hwnds); + ok(ret == 12, "got %d\n", ret); + + /* 4 columns: 3, 3, 3, 3 */ + + row = column = 0; + for (unsigned int i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + unsigned int width = (parent_client.right - parent_client.left) / 4; + unsigned int height = (parent_client.bottom - parent_client.top) / 3; + unsigned int index = i; + + GetWindowRect(hwnds[index], &rect); + if (index != 5) + OffsetRect(&rect, -pt.x, -pt.y); + + if (index == 3 /* invisible */ || index == 6 /* disabled */ || index == 5 /* not a child */ + || index == 8 /* no border */ || index == 2 /* no dlgframe */) + { + ok(EqualRect(&rect, &orig), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + continue; + } + + if (index == 4 /* no THICKFRAME */) + SetRect(&expect, column * width, row * height, (column * width) + 200, (row * height) + 200); + else + SetRect(&expect, column * width, row * height, (column + 1) * width, (row + 1) * height); + expect.right = max(expect.right, expect.left + GetSystemMetrics(SM_CXMIN)); + + ok(EqualRect(&rect, &expect), "hwnd %u: expected rect %s, got %s\n", + index, wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + ++row; + if (row == 3) + { + row = 0; + ++column; + } + } + + for (unsigned int i = 0; i < ARRAY_SIZE(hwnds); ++i) + DestroyWindow(hwnds[i]); + DestroyWindow(parent); +} + START_TEST(win) { char **argv; @@ -14199,6 +14378,7 @@ START_TEST(win) test_SetProcessLaunchForegroundPolicy(); test_startupinfo_showwindow(argv); test_cascade_windows(); + test_tile_windows();
/* add the tests above this line */ if (hhook) UnhookWindowsHookEx(hhook); diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 6192e9f6384..f19e66635ea 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -1752,3 +1752,105 @@ WORD WINAPI CascadeChildWindows( HWND parent, UINT flags ) { return CascadeWindows( parent, flags, NULL, 0, NULL ); } + +/********************************************************************** + * TileWindows (USER32.@) + */ +WORD WINAPI TileWindows( HWND parent, UINT flags, const RECT *rect, UINT count, const HWND *windows ) +{ + unsigned int tile_count = 0, column = 0, row = 0; + unsigned int root, columns, rows, light_columns; + HWND *children = NULL; + RECT client; + + TRACE( "parent %p, flags %#x, rect %s, count %u, windows %p\n", + parent, flags, wine_dbgstr_rect(rect), count, windows ); + + if (flags & ~(MDITILE_SKIPDISABLED | MDITILE_HORIZONTAL)) + FIXME( "ignoring flags %#x\n", flags & ~(MDITILE_SKIPDISABLED | MDITILE_HORIZONTAL) ); + + if (!parent) + parent = GetDesktopWindow(); + + if (!rect) + { + GetClientRect( parent, &client ); + rect = &client; + } + + if (!windows) + { + if (!(children = WIN_ListChildren( parent ))) + return 0; + for (count = 0; children[count]; ++count) + ; + windows = children; + } + + for (unsigned int i = 0; i < count; ++i) + { + if (should_move_window( windows[i], parent, flags )) + ++tile_count; + } + + /* Determine root = ⌊√tile_count⌋. This is how many columns (if horizontal) + * or rows (if vertical) we have. */ + for (root = 0; root * root <= tile_count; ++root) + ; + --root; + + /* Because the number of windows might not evenly divide the number of + * columns, Windows might give one extra window to some columns, + * starting from the right. These are referred to as "heavy" columns here. + * "rows" describes the number of rows in "light" columns, + * and light_columns is the number of columns which are light. */ + + if (flags & MDITILE_HORIZONTAL) + { + columns = root; + rows = tile_count / columns; + light_columns = columns - (tile_count % columns); + } + else + { + rows = root; + columns = tile_count / rows; + light_columns = columns - (tile_count % rows); + } + + for (unsigned int i = 0; i < count; ++i) + { + unsigned int current_rows = (column < light_columns ? rows : rows + 1); + unsigned int width = (rect->right - rect->left) / columns; + unsigned int height = (rect->bottom - rect->top) / current_rows; + HWND child = windows[i]; + DWORD style = GetWindowLongW( child, GWL_STYLE ); + DWORD swp_flags = SWP_NOZORDER | SWP_NOACTIVATE; + + if (!should_move_window( child, parent, flags )) + continue; + + if (!(style & WS_THICKFRAME)) + swp_flags |= SWP_NOSIZE; + NtUserSetWindowPos( child, 0, rect->left + column * width, rect->top + row * height, width, height, swp_flags ); + + ++row; + if ((row == rows && column < light_columns) || row == rows + 1) + { + row = 0; + ++column; + } + } + + HeapFree( GetProcessHeap(), 0, children ); + + return tile_count; +} + +/********************************************************************** + * TileChildWindows (USER32.@) + */ +WORD WINAPI TileChildWindows( HWND parent, UINT flags ) +{ + return TileWindows( parent, flags, NULL, 0, NULL ); +}