Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

729 lines
23 KiB

//---------------------------------------------------------------------------
// Smart Tiling code.
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "shellprv.h"
#pragma hdrstop
//---------------------------------------------------------------------------
#define VERTEX_TOP 1
#define VERTEX_BOTTOM 2
#define VERTEX_LEFT 3
#define VERTEX_RIGHT 4
#define MAXDWORD 0xffffffff
#define abs(a) ((a)>0?(a):-(a))
//---------------------------------------------------------------------------
typedef struct
{
BOOL fTopDone;
BOOL fBottomDone;
BOOL fLeftDone;
BOOL fRightDone;
RECT rc;
HWND hwnd;
BOOL fIgnore;
} WINRECT, *PWINRECT, *LPWINRECT;
#ifdef DEBUG
//---------------------------------------------------------------------------
void DebugDumpRects(WORD cWinrects, LPWINRECT lpWinrects)
{
WORD wi;
TCHAR szTitle[128];
LPWINRECT lpwr;
for (wi = 0; wi < cWinrects; wi++)
{
lpwr = &lpWinrects[wi];
GetWindowText(lpwr->hwnd, szTitle, ARRAYSIZE(szTitle));
DebugMsg(DM_TRACE, TEXT("tm.ddr: Window %x %s x = %d, y = %d, w = %d, h = %d"), lpwr->hwnd, (LPTSTR) szTitle, lpwr->rc.left, lpwr->rc.top, lpwr->rc.right-lpwr->rc.left, lpwr->rc.bottom-lpwr->rc.top);
}
}
#endif
//---------------------------------------------------------------------------
BOOL Window_CanResize(HWND hwnd)
{
DWORD dwStyle;
// Just check the window style.
dwStyle = (DWORD)GetWindowLong(hwnd, GWL_STYLE);
return dwStyle & WS_THICKFRAME;
}
//---------------------------------------------------------------------------
// Use the data in the WinRect array to move the windows around.
void SetWindowsPosUsingWinrects(WORD cWinrects, LPWINRECT lpWinrects)
{
WORD wi;
LPWINRECT lpwr;
HDWP hdwp;
hdwp = BeginDeferWindowPos(cWinrects);
for (wi=0; wi < cWinrects; wi++)
{
lpwr = &lpWinrects[wi];
// Skip windows that can't be sized.
if (Window_CanResize(lpwr->hwnd))
{
hdwp = DeferWindowPos(hdwp, lpwr->hwnd, 0, lpwr->rc.left, lpwr->rc.top, lpwr->rc.right-lpwr->rc.left, lpwr->rc.bottom-lpwr->rc.top, SWP_NOZORDER|SWP_NOACTIVATE);
}
}
EndDeferWindowPos(hdwp);
}
//---------------------------------------------------------------------------
// Given a rect, return its point centre.
void GetCentreFromRect(LPRECT lprc, LPPOINT lppt)
{
lppt->x = (lprc->left+lprc->right)/2;
lppt->y = (lprc->top+lprc->bottom)/2;
}
//---------------------------------------------------------------------------
BOOL QueryOverlaps(WORD cWinrects, LPWINRECT lpWinrects, WORD wEntry1, WORD wEntry2)
{
WORD wi;
LPWINRECT lpwrc1, lpwrc2;
LPWINRECT lpwrc;
BOOL fReturn = FALSE;
RECT rc;
lpwrc1 = &lpWinrects[wEntry1];
lpwrc2 = &lpWinrects[wEntry2];
DebugMsg(DM_TRACE, TEXT("tm.qo: Checking overlaps using %x and %x"), lpwrc1->hwnd, lpwrc2->hwnd);
for (wi=0; wi < cWinrects; wi++)
{
// Ignore the given entries.
if (wi == wEntry1 || wi == wEntry2)
continue;
lpwrc = &lpWinrects[wi];
// Ignore windows marked as being ignorable.
if (lpwrc->fIgnore)
continue;
// Check for overlap.
if (IntersectRect(&rc, &lpwrc1->rc, &lpwrc->rc))
{
// Yep, they intersect.
DebugMsg(DM_TRACE, TEXT("tm.qo: Overlap found with %x."), lpwrc->hwnd);
fReturn = TRUE;
break;
}
if (IntersectRect(&rc, &lpwrc2->rc, &lpwrc->rc))
{
// Yep, they intersect.
DebugMsg(DM_TRACE, TEXT("tm.qo: Overlap found with %x."), lpwrc->hwnd);
fReturn = TRUE;
break;
}
}
return fReturn;
}
//---------------------------------------------------------------------------
#define BIAS_NONE 0x0000
#define BIAS_HORIZONTAL 0x0001
#define BIAS_VERTICAL 0x0002
#define BIAS_BOTH 0x0003
// Move bits of the relevant rects so that they touch.
// IE You call this with the two windows to get touching and this will size
// the appropriate vertices so that they line up nicely.
// If fIngnoreOverlaps is FALSE then AV will do nothing if sizing the
// appropriate windows introduces an overlap.
void AdjustVertices(WORD cWinrects, LPWINRECT lpWinrects,
WORD wEntry1, WORD wEntry2, BOOL fIgnoreOverlaps)
{
LPWINRECT lpwrc1, lpwrc2;
POINT pt1, pt2;
WORD wBias = BIAS_NONE;
WINRECT wrc1, wrc2;
RECT rcOverlap;
lpwrc1 = &lpWinrects[wEntry1];
lpwrc2 = &lpWinrects[wEntry2];
// Make copies - we may need to back out these changes.
wrc1 = *lpwrc1;
wrc2 = *lpwrc2;
DebugMsg(DM_TRACE, TEXT("tm.av: Adjusting %d and %d"), wrc1.hwnd, wrc2.hwnd);
GetCentreFromRect(&lpwrc1->rc, &pt1);
GetCentreFromRect(&lpwrc2->rc, &pt2);
// Work out a bias for the windows otherwise the tiler will *always*
// put the windows corner to corner.
if (lpwrc2->rc.left > lpwrc1->rc.right || lpwrc2->rc.right < lpwrc1->rc.left)
wBias |= BIAS_HORIZONTAL;
if (lpwrc2->rc.top > lpwrc1->rc.bottom || lpwrc2->rc.bottom < lpwrc1->rc.top)
wBias |= BIAS_VERTICAL;
// Deal with overlaping windows nicely.
if (wBias == BIAS_NONE && IntersectRect(&rcOverlap, &lpwrc1->rc, &lpwrc2->rc))
{
DebugMsg(DM_TRACE, TEXT("tm.av: Overlap found - removing..."));
// Try obvious stuff first. This won't handle badly overlapped
// windows (like cascaded ones).
if (((pt2.y < lpwrc1->rc.top) && (pt1.y > lpwrc2->rc.bottom)) || ((pt2.y > lpwrc1->rc.bottom) && (pt1.y < lpwrc2->rc.top)))
wBias |= BIAS_VERTICAL;
if (((pt2.x > lpwrc1->rc.right) && (pt1.x < lpwrc2->rc.left)) || ((pt2.x < lpwrc1->rc.left) && (pt1.x > lpwrc2->rc.right)))
wBias |= BIAS_HORIZONTAL;
// Less obvious...This tries to deal with cascaded windows.
if (wBias == BIAS_NONE)
{
if ((pt2.y < lpwrc1->rc.bottom) && (pt1.y < lpwrc2->rc.top))
{
lpwrc2->fTopDone = TRUE;
wBias |= BIAS_VERTICAL;
}
if ((pt1.y > lpwrc1->rc.top) && (pt2.y > lpwrc1->rc.bottom))
{
lpwrc1->fBottomDone = TRUE;
wBias |= BIAS_VERTICAL;
}
if ((pt2.x < lpwrc1->rc.right) && (pt1.x < lpwrc2->rc.left))
{
lpwrc2->fLeftDone = TRUE;
wBias |= BIAS_HORIZONTAL;
}
if ((pt1.x > lpwrc1->rc.left) && (pt2.x > lpwrc1->rc.right))
{
lpwrc1->fRightDone = TRUE;
wBias |= BIAS_HORIZONTAL;
}
}
// Catch all..
if (wBias == BIAS_NONE)
wBias = BIAS_BOTH;
}
// Work out how best to change the rects so that they touch.
if ((wBias & BIAS_HORIZONTAL) && (pt2.x >= pt1.x))
{
DebugMsg(DM_TRACE, TEXT("tm.av: %x is to the right of %x"), lpwrc2->hwnd, lpwrc1->hwnd);
if (!lpwrc2->fLeftDone && !lpwrc1->fRightDone)
{
// Both are moveable so averge them.
lpwrc2->rc.left = lpwrc1->rc.right = (lpwrc2->rc.left + lpwrc1->rc.right)/2;
lpwrc2->fLeftDone = TRUE;
lpwrc1->fRightDone = TRUE;
if (QueryOverlaps(cWinrects, lpWinrects, wEntry1, wEntry2))
{
// FU - Try something else.
lpwrc1->rc = wrc1.rc;
lpwrc2->rc = wrc2.rc;
lpwrc2->rc.left = lpwrc1->rc.right;
if (QueryOverlaps(cWinrects, lpWinrects, wEntry1, wEntry2))
{
// FU - Last resort...
lpwrc1->rc = wrc1.rc;
lpwrc2->rc = wrc2.rc;
lpwrc1->rc.right = lpwrc2->rc.left;
}
}
}
// Only one is moveable so move it to touch the unmoveable one.
else if (!lpwrc2->fLeftDone)
{
lpwrc2->rc.left = lpwrc1->rc.right;
lpwrc2->fLeftDone = TRUE;
}
else if (!lpwrc1->fRightDone)
{
lpwrc1->rc.right = lpwrc2->rc.left;
lpwrc1->fRightDone = TRUE;
}
// Else neither are moveable so do nothing.
}
if ((wBias & BIAS_HORIZONTAL) && (pt2.x < pt1.x))
{
DebugMsg(DM_TRACE, TEXT("tm.av: %x is to the right of %x"), lpwrc2->hwnd, lpwrc1->hwnd);
if (!lpwrc2->fRightDone && !lpwrc1->fLeftDone)
{
// Both are moveable so averge them.
lpwrc2->rc.right = lpwrc1->rc.left = (lpwrc2->rc.right + lpwrc1->rc.left)/2;
lpwrc2->fRightDone = TRUE;
lpwrc1->fLeftDone = TRUE;
if (QueryOverlaps(cWinrects, lpWinrects, wEntry1, wEntry2))
{
// FU - Try something else.
lpwrc1->rc = wrc1.rc;
lpwrc2->rc = wrc2.rc;
lpwrc2->rc.right = lpwrc1->rc.left;
if (QueryOverlaps(cWinrects, lpWinrects, wEntry1, wEntry2))
{
// FU - Last resort...
lpwrc1->rc = wrc1.rc;
lpwrc2->rc = wrc2.rc;
lpwrc1->rc.left = lpwrc2->rc.right;
}
}
}
// Only one is moveable so move it to touch the unmoveable one.
else if (!lpwrc2->fRightDone)
{
lpwrc2->rc.right = lpwrc1->rc.left;
lpwrc2->fRightDone = TRUE;
}
else if (!lpwrc1->fLeftDone)
{
lpwrc1->rc.left = lpwrc2->rc.right;
lpwrc1->fLeftDone = TRUE;
}
// Else neither are moveable so do nothing.
}
if ((wBias & BIAS_VERTICAL) && (pt2.y <= pt1.y))
{
DebugMsg(DM_TRACE, TEXT("tm.av: %x is above %x"), lpwrc2->hwnd, lpwrc1->hwnd);
if (!lpwrc2->fBottomDone && !lpwrc1->fTopDone)
{
// Both are moveable so averge them.
lpwrc2->rc.bottom = lpwrc1->rc.top = (lpwrc2->rc.bottom + lpwrc1->rc.top)/2;
lpwrc2->fBottomDone = TRUE;
lpwrc1->fTopDone = TRUE;
if (QueryOverlaps(cWinrects, lpWinrects, wEntry1, wEntry2))
{
// FU - Try something else.
lpwrc1->rc = wrc1.rc;
lpwrc2->rc = wrc2.rc;
lpwrc2->rc.bottom = lpwrc1->rc.top;
if (QueryOverlaps(cWinrects, lpWinrects, wEntry1, wEntry2))
{
// FU - Last resort...
lpwrc1->rc = wrc1.rc;
lpwrc2->rc = wrc2.rc;
lpwrc1->rc.top = lpwrc2->rc.bottom;
}
}
}
// Only one is moveable so move it to touch the unmoveable one.
else if (!lpwrc2->fBottomDone)
{
lpwrc2->rc.bottom = lpwrc1->rc.top;
lpwrc2->fBottomDone = TRUE;
}
else if (!lpwrc1->fTopDone)
{
lpwrc1->rc.top = lpwrc2->rc.bottom;
lpwrc1->fTopDone = TRUE;
}
// Else neither are moveable so do nothing.
}
if ((wBias & BIAS_VERTICAL) && (pt2.y > pt1.y))
{
DebugMsg(DM_TRACE, TEXT("tm.av: %x is below %x"), lpwrc2->hwnd, lpwrc1->hwnd);
if (!lpwrc2->fTopDone && !lpwrc1->fBottomDone)
{
// Both are moveable so averge them.
lpwrc2->rc.top = lpwrc1->rc.bottom = (lpwrc2->rc.top + lpwrc1->rc.bottom)/2;
lpwrc2->fTopDone = TRUE;
lpwrc1->fBottomDone = TRUE;
if (QueryOverlaps(cWinrects, lpWinrects, wEntry1, wEntry2))
{
// FU - Try something else.
lpwrc1->rc = wrc1.rc;
lpwrc2->rc = wrc2.rc;
lpwrc2->rc.top = lpwrc1->rc.bottom;
if (QueryOverlaps(cWinrects, lpWinrects, wEntry1, wEntry2))
{
// FU - Last resort...
lpwrc1->rc = wrc1.rc;
lpwrc2->rc = wrc2.rc;
lpwrc1->rc.bottom = lpwrc2->rc.top;
}
}
}
// Only one is moveable so move it to touch the unmoveable one.
else if (!lpwrc2->fTopDone)
{
lpwrc2->rc.top = lpwrc1->rc.bottom;
lpwrc2->fTopDone = TRUE;
}
else if (!lpwrc1->fBottomDone)
{
lpwrc1->rc.bottom = lpwrc2->rc.top;
lpwrc1->fBottomDone = TRUE;
}
// Else neither are moveable so do nothing.
}
// Will this change cause overlapps?
if (!fIgnoreOverlaps && QueryOverlaps(cWinrects, lpWinrects, wEntry1, wEntry2))
{
// Yes, forget it.
*lpwrc1 = wrc1;
*lpwrc2 = wrc2;
}
}
//---------------------------------------------------------------------------
// Make the windows match the bounding rectangle.
// REVIEW UNDONE
void FillBoundingRect(WORD cWinrects, LPWINRECT lpWinrects, LPCRECT lprcBounding)
{
WORD wi;
LPWINRECT lpwrc;
WINRECT wrc;
DebugMsg(DM_TRACE, TEXT("tm.fbr: Filling bounding rect (%d, %d) to (%d, %d)"), lprcBounding->left, lprcBounding->top, lprcBounding->right, lprcBounding->bottom);
// Try repositioning things so that they touch the border.
for (wi=0; wi < cWinrects; wi++)
{
lpwrc = &lpWinrects[wi];
wrc = *lpwrc;
lpwrc->rc.top = lprcBounding->top;
if (QueryOverlaps(cWinrects, lpWinrects, wi, wi))
{
// Didn't work, back out change.
*lpwrc = wrc;
}
else
{
// Worked, record it for posterity.
wrc.rc.top = lprcBounding->top;
}
lpwrc->rc.bottom = lprcBounding->bottom;
if (QueryOverlaps(cWinrects, lpWinrects, wi, wi))
{
// Didn't work, back out change.
*lpwrc = wrc;
}
else
{
// Worked, record it for posterity.
wrc.rc.bottom = lprcBounding->bottom;
}
lpwrc->rc.left = lprcBounding->left;
if (QueryOverlaps(cWinrects, lpWinrects, wi, wi))
{
// Didn't work, back out change.
*lpwrc = wrc;
}
else
{
// Worked, record it for posterity.
wrc.rc.left = lprcBounding->left;
}
lpwrc->rc.right = lprcBounding->right;
if (QueryOverlaps(cWinrects, lpWinrects, wi, wi))
{
// Didn't work, back out change.
*lpwrc = wrc;
}
else
{
// Worked, record it for posterity.
wrc.rc.right = lprcBounding->right;
}
}
}
//---------------------------------------------------------------------------
// Twiddle with overlapping windows so that they don't overlap anymore.
// If they are badly overlapped (cascaded, or contained) then we leave them
// alone and set their fIgnore flag so we know no to muck with them later.
// REVIEW UNDONE Cascaded windows should be tidied up to so that they're
// nicely cascaded.
void RemoveOverlaps(WORD cWinrects, LPWINRECT lpWinrects)
{
WORD wiwrInitial; // Index to a WinRect in the SSAM.
WORD wiwrNext;
RECT rc;
LPWINRECT lpwrcInitial;
LPWINRECT lpwrcNext;
DebugMsg(DM_TRACE, TEXT("tm.ro: Removing primary overlaps..."));
for (wiwrInitial = 0; wiwrInitial < cWinrects; wiwrInitial++)
{
for (wiwrNext = wiwrInitial+1; wiwrNext < cWinrects; wiwrNext++)
{
lpwrcInitial = &lpWinrects[wiwrInitial];
lpwrcNext = &lpWinrects[wiwrNext];
if (IntersectRect(&rc, &lpwrcInitial->rc, &lpwrcNext->rc))
{
if (EqualRect(&rc, &lpwrcInitial->rc))
{
// One is completely contained within the other
DebugMsg(DM_TRACE, TEXT("tm.ro: %x completely contains %x, ignoring it."), lpwrcNext->hwnd, lpwrcInitial->hwnd);
lpwrcNext->fIgnore = TRUE;
}
else if (EqualRect(&rc, &lpwrcNext->rc))
{
// One is completely contained within the other
DebugMsg(DM_TRACE, TEXT("tm.ro: %x completely contains %x, ignoring it."), lpwrcInitial->hwnd, lpwrcNext->hwnd);
lpwrcInitial->fIgnore = TRUE;
}
else
{
AdjustVertices(cWinrects, lpWinrects, wiwrInitial, wiwrNext, TRUE);
}
}
}
}
}
//---------------------------------------------------------------------------
// Re-arrange the rects in the given array so that they are nicely alligned.
// REVIEW UNDONE - Make this look like the new user API's
void RearrangeWinrects(WORD cWinrects, LPWINRECT lpWinrects, LPCRECT lprcBounding)
{
WORD wiwrInitial; // Index to a WinRect in the SSAM.
WORD wiwrNext;
DebugMsg(DM_TRACE, TEXT("tm.rw: Re-arranging windows..."));
// Pick a starting point.
wiwrInitial = 0;
RemoveOverlaps(cWinrects, lpWinrects);
// Bog standard loop.
for (wiwrInitial = 0; wiwrInitial < cWinrects; wiwrInitial++)
{
if (lpWinrects[wiwrInitial].fIgnore)
continue;
for (wiwrNext = wiwrInitial+1; wiwrNext < cWinrects; wiwrNext++)
{
if (lpWinrects[wiwrNext].fIgnore)
continue;
AdjustVertices(cWinrects, lpWinrects, wiwrInitial, wiwrNext, FALSE);
}
}
// Just in case it was so fast you missed it, lets do it
// again! (only backwards).
for (wiwrInitial = 0; wiwrInitial < cWinrects; wiwrInitial++)
{
if (lpWinrects[wiwrInitial].fIgnore)
continue;
for (wiwrNext = wiwrInitial+1; wiwrNext < cWinrects; wiwrNext++)
{
if (lpWinrects[wiwrNext].fIgnore)
continue;
AdjustVertices(cWinrects, lpWinrects, wiwrNext, wiwrInitial, FALSE);
}
}
// Expand everything to hit the border.
FillBoundingRect(cWinrects, lpWinrects, lprcBounding);
}
//---------------------------------------------------------------------------
// Returns TRUE if the window is suitable for being moved around.
// REVIEW What should we do about the ShellWindow?
BOOL IsWindowNormal(HWND hwnd)
{
LONG lStyle;
// Visible and non-icon.
if (IsWindowVisible(hwnd) && !IsIconic(hwnd))
{
// Not popups.
lStyle = GetWindowLong(hwnd, GWL_STYLE);
if (!(lStyle & WS_POPUP))
{
// REVIEW User doesn't ignore topmost windows so we shouldn't either.
#if 0
// Not topmost (or bottom-most???).
lStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
if (!(lStyle & WS_EX_TOPMOST))
return TRUE;
#else
return TRUE;
#endif
}
}
return FALSE;
}
//---------------------------------------------------------------------------
// Build an array of winrects for the children of the given window.
// This will skip windows we don't think we should mess with.
LPWINRECT BuildWinrectsFromParent(WORD *pcHwnd, HWND hwndParent)
{
WORD cWinrects;
LPWINRECT lpWinrects;
HWND hwnd;
cWinrects = 0;
lpWinrects = NULL;
hwnd = GetWindow(hwndParent, GW_CHILD);
while (hwnd)
{
// Check the window is valid.
if (!IsWindowNormal(hwnd))
{
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
continue;
}
if (IsZoomed(hwnd))
ShowWindow(hwnd, SW_RESTORE);
// Store the info.
lpWinrects = ReAlloc(lpWinrects, SIZEOF(WINRECT)*(cWinrects+1));
if (!lpWinrects)
{
DebugMsg(DM_ERROR, TEXT("s.bwfp: Not enough memory to arrange windows."));
return NULL;
}
lpWinrects[cWinrects].hwnd = hwnd;
lpWinrects[cWinrects].fTopDone = FALSE;
lpWinrects[cWinrects].fBottomDone = FALSE;
lpWinrects[cWinrects].fLeftDone = FALSE;
lpWinrects[cWinrects].fRightDone = FALSE;
lpWinrects[cWinrects].fIgnore = FALSE;
GetWindowRect(hwnd, &lpWinrects[cWinrects].rc);
// Next.
cWinrects++;
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
}
*pcHwnd = cWinrects;
return lpWinrects;
}
//---------------------------------------------------------------------------
// Build an array of winrects from the given array.
LPWINRECT BuildWinrectsFromList(WORD *pcHwnd, const HWND *aHwnd)
{
WORD cWinrects;
LPWINRECT lpWinrects;
WORD iHwnd;
HWND hwnd;
cWinrects = 0;
lpWinrects = NULL;
for (iHwnd=0; iHwnd<*pcHwnd; iHwnd++)
{
hwnd = aHwnd[iHwnd];
if (!IsWindowNormal(hwnd))
continue;
if (IsZoomed(hwnd))
ShowWindow(hwnd, SW_RESTORE);
// Store the info.
lpWinrects = ReAlloc(lpWinrects, SIZEOF(WINRECT)*(cWinrects+1));
if (!lpWinrects)
{
DebugMsg(DM_ERROR, TEXT("s.bwfp: Not enough memory to arrange windows."));
*pcHwnd = 0;
return NULL;
}
lpWinrects[cWinrects].hwnd = hwnd;
lpWinrects[cWinrects].fTopDone = FALSE;
lpWinrects[cWinrects].fBottomDone = FALSE;
lpWinrects[cWinrects].fLeftDone = FALSE;
lpWinrects[cWinrects].fRightDone = FALSE;
lpWinrects[cWinrects].fIgnore = FALSE;
GetWindowRect(hwnd, &lpWinrects[cWinrects].rc);
// Next.
cWinrects++;
}
*pcHwnd = cWinrects;
return lpWinrects;
}
//---------------------------------------------------------------------------
// Tile windows nicely...
// REVIEW UNDONE Make this act like user.
// Leave a gap for minimized windows (if you pass in a parent).
WORD WINAPI ArrangeWindows(HWND hwndParent, WORD flags, LPCRECT lpRect, WORD chwnd, const HWND *ahwnd)
{
RECT rcClient;
LPWINRECT lpWinrects;
WORD chwndReal;
#ifdef DEBUG
UINT dm;
#endif
// Skip the tons of debug msgs, it's too early to remove the messages as
// as very difficult to debug this stuff using a debugger.
#ifdef DEBUG
dm = SetDebugMask(DM_WARNING);
#endif
// Get Parent.
if (!hwndParent)
{
hwndParent = GetDesktopWindow();
}
// Get rectangle to arrange in.
if (!lpRect)
{
if (hwndParent == GetDesktopWindow())
{
// Special case the desktop to use the work area instead of it's
// client area.
SystemParametersInfo(SPI_GETWORKAREA, SIZEOF(rcClient), &rcClient, FALSE);
}
else
{
GetClientRect(hwndParent, &rcClient);
}
lpRect = &rcClient;
}
// Get the window list.
if (!ahwnd)
{
lpWinrects = BuildWinrectsFromParent(&chwndReal, hwndParent);
}
else
{
chwndReal = chwnd;
lpWinrects = BuildWinrectsFromList(&chwndReal, ahwnd);
}
if (!lpWinrects)
{
#ifdef DEBUG
SetDebugMask(dm);
#endif
return 0;
}
// Move the rects around.
#ifdef DEBUG
DebugDumpRects(chwndReal, lpWinrects);
#endif
RearrangeWinrects(chwndReal, lpWinrects, lpRect);
#ifdef DEBUG
DebugDumpRects(chwndReal, lpWinrects);
#endif
// Now move the windows.
SetWindowsPosUsingWinrects(chwndReal, lpWinrects);
Free(lpWinrects);
#ifdef DEBUG
SetDebugMask(dm);
#endif
return chwndReal;
}