696 lines
17 KiB
C++
696 lines
17 KiB
C++
/*++
|
|
|
|
Copyright (c) 1992-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
arrange.cpp
|
|
|
|
Abstract:
|
|
|
|
This module contains the default MDI tiling (arrange) code for
|
|
windowing arrangement.
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.hxx"
|
|
#pragma hdrstop
|
|
|
|
#define AUTO_ARRANGE_WARNING_LIMIT 3
|
|
// Multiple events closely together don't each get their own
|
|
// count in order to prevent warnings on full-drag message
|
|
// series. This delay should be relatively large to
|
|
// avoid problems with people pausing during a full-drag move.
|
|
#define AUTO_ARRANGE_WARNING_DELAY 2500
|
|
|
|
// DeferWindowPos flags to restrict change to position only.
|
|
#define POS_ONLY (SWP_NOACTIVATE | SWP_NOZORDER)
|
|
|
|
ULONG g_AutoArrangeWarningCount;
|
|
ULONG g_AutoArrangeWarningTime;
|
|
|
|
BOOL
|
|
IsAutoArranged(WIN_TYPES Type)
|
|
{
|
|
if (g_WinOptions & WOPT_AUTO_ARRANGE)
|
|
{
|
|
if (g_WinOptions & WOPT_ARRANGE_ALL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return Type != DOC_WINDOW && Type != DISASM_WINDOW;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
DisplayAutoArrangeWarning(PCOMMONWIN_DATA CmnWin)
|
|
{
|
|
//
|
|
// If this window is under automatic arrangement
|
|
// control and has been rearranged a few times,
|
|
// let the user know that auto-arrange may override
|
|
// what the user has done.
|
|
//
|
|
// In order to prevent false positives we avoid
|
|
// giving any warnings if the window is being
|
|
// moved automatically or if we're getting a series
|
|
// of changes in a short period of time, such as
|
|
// if the user has full-drag enabled so that many
|
|
// move or size events can occur rapidly.
|
|
//
|
|
// Display the warning only once per execution.
|
|
//
|
|
|
|
if (g_AutoArrangeWarningCount == 0xffffffff ||
|
|
CmnWin == NULL ||
|
|
CmnWin->m_InAutoOp > 0 ||
|
|
!IsAutoArranged(CmnWin->m_enumType) ||
|
|
g_AutoArrangeWarningTime >
|
|
GetTickCount() - AUTO_ARRANGE_WARNING_DELAY)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (++g_AutoArrangeWarningCount >= AUTO_ARRANGE_WARNING_LIMIT)
|
|
{
|
|
InformationBox(STR_Auto_Arrange_Is_Enabled);
|
|
g_AutoArrangeWarningCount = 0xffffffff;
|
|
}
|
|
else
|
|
{
|
|
g_AutoArrangeWarningTime = GetTickCount();
|
|
}
|
|
}
|
|
|
|
void
|
|
ArrangeInRect(HDWP Defer, int X, int Y, int Width, int Height,
|
|
BOOL Vertical, ULONG Types, int Count, BOOL Overlay)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PCOMMONWIN_DATA Data;
|
|
int PerWin, Remain, Extra;
|
|
|
|
if (Overlay)
|
|
{
|
|
Remain = 0;
|
|
}
|
|
else if (Vertical)
|
|
{
|
|
PerWin = Height / Count;
|
|
Remain = Height - PerWin * Count;
|
|
Height = PerWin + (Remain ? 1 : 0);
|
|
}
|
|
else
|
|
{
|
|
PerWin = Width / Count;
|
|
Remain = Width - PerWin * Count;
|
|
Width = PerWin + (Remain ? 1 : 0);
|
|
}
|
|
|
|
for (Entry = g_ActiveWin.Flink;
|
|
Entry != &g_ActiveWin;
|
|
Entry = Entry->Flink)
|
|
{
|
|
Data = ACTIVE_WIN_ENTRY(Entry);
|
|
if ((Types & (1 << Data->m_enumType)) == 0 ||
|
|
IsIconic(Data->m_Win))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
DeferWindowPos(Defer, Data->m_Win, NULL, X, Y,
|
|
Width, Height, POS_ONLY);
|
|
|
|
if (Overlay)
|
|
{
|
|
// All windows are stacked on top of each other.
|
|
}
|
|
else if (Vertical)
|
|
{
|
|
Y += Height;
|
|
if (--Remain == 0)
|
|
{
|
|
Height--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
X += Width;
|
|
if (--Remain == 0)
|
|
{
|
|
Width--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
Arrange(void)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PCOMMONWIN_DATA pWinData;
|
|
int NumDoc, NumMem, NumWatchLocals, NumWin;
|
|
int NumLeft, NumRight;
|
|
BOOL AnyIcon = FALSE;
|
|
HWND hwndChild;
|
|
HWND hwndCpu;
|
|
HWND hwndWatch;
|
|
HWND hwndLocals;
|
|
HWND hwndCalls;
|
|
HWND hwndCmd;
|
|
HWND hwndDisasm;
|
|
HWND hwndScratch;
|
|
HWND hwndProcThread;
|
|
|
|
// initialize to non-existent
|
|
NumLeft = NumRight = 0;
|
|
NumDoc = NumMem = NumWatchLocals = NumWin = 0;
|
|
hwndWatch = hwndLocals = hwndCpu = hwndCalls = NULL;
|
|
hwndCmd = hwndDisasm = hwndScratch = hwndProcThread = NULL;
|
|
|
|
hwndChild = MDIGetActive(g_hwndMDIClient, NULL);
|
|
if (hwndChild && IsZoomed(hwndChild))
|
|
{
|
|
// If there's a maximized window it covers the MDI
|
|
// client area and arranging will have no visual effect.
|
|
// Don't even bother to rearrange underlying windows
|
|
// as this causes problems when switching between child
|
|
// windows while a child is maximized.
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Windows are either left-side windows or right-side windows.
|
|
// Left-side windows are wider and can be relatively short,
|
|
// while right-side windows are narrow but want height.
|
|
// Left-side windows want to be 80 columns wide while
|
|
// right side windows have both a minimum width and a desired
|
|
// width.
|
|
//
|
|
// Right-side windows fill whatever space is left over to
|
|
// the right of the left-side windows. If that space is
|
|
// less than the minimum the left-side windows have to give up space.
|
|
//
|
|
// Vertically each side is split up according to the specific
|
|
// windows present. On the right side the windows are
|
|
// space equally top-to-bottom.
|
|
// On the left side watch and locals windows are packed together
|
|
// in one vertical area, as are memory windows. Calls,
|
|
// disassembly, document and command windows each get their own band.
|
|
//
|
|
|
|
for (Entry = g_ActiveWin.Flink;
|
|
Entry != &g_ActiveWin;
|
|
Entry = Entry->Flink)
|
|
{
|
|
pWinData = ACTIVE_WIN_ENTRY(Entry);
|
|
// This window is participating in an operation
|
|
// which may cause window messages.
|
|
pWinData->m_InAutoOp++;
|
|
|
|
hwndChild = pWinData->m_Win;
|
|
if (hwndChild == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (IsIconic(hwndChild))
|
|
{
|
|
AnyIcon = TRUE;
|
|
continue;
|
|
}
|
|
|
|
NumWin++;
|
|
|
|
switch (pWinData->m_enumType)
|
|
{
|
|
default:
|
|
Assert(!_T("Unknown window type"));
|
|
break;
|
|
|
|
case WATCH_WINDOW:
|
|
hwndWatch = hwndChild;
|
|
if (++NumWatchLocals == 1)
|
|
{
|
|
NumLeft++;
|
|
}
|
|
break;
|
|
|
|
case LOCALS_WINDOW:
|
|
hwndLocals = hwndChild;
|
|
if (++NumWatchLocals == 1)
|
|
{
|
|
NumLeft++;
|
|
}
|
|
break;
|
|
|
|
case CPU_WINDOW:
|
|
hwndCpu = hwndChild;
|
|
NumRight++;
|
|
break;
|
|
|
|
case CALLS_WINDOW:
|
|
hwndCalls = hwndChild;
|
|
NumLeft++;
|
|
break;
|
|
|
|
case DOC_WINDOW:
|
|
if ((g_WinOptions & WOPT_ARRANGE_ALL) == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (++NumDoc == 1)
|
|
{
|
|
NumLeft++;
|
|
}
|
|
break;
|
|
|
|
case DISASM_WINDOW:
|
|
if ((g_WinOptions & WOPT_ARRANGE_ALL) == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
hwndDisasm = hwndChild;
|
|
NumLeft++;
|
|
break;
|
|
|
|
case CMD_WINDOW:
|
|
hwndCmd = hwndChild;
|
|
NumLeft++;
|
|
break;
|
|
|
|
case SCRATCH_PAD_WINDOW:
|
|
hwndScratch = hwndChild;
|
|
NumRight++;
|
|
break;
|
|
|
|
case MEM_WINDOW:
|
|
if (++NumMem == 1)
|
|
{
|
|
NumLeft++;
|
|
}
|
|
break;
|
|
|
|
case PROCESS_THREAD_WINDOW:
|
|
hwndProcThread = hwndChild;
|
|
NumLeft++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
HDWP Defer = BeginDeferWindowPos(NumWin);
|
|
if (Defer == NULL)
|
|
{
|
|
goto EndAutoOp;
|
|
}
|
|
|
|
// Now we have a count of all multiple wins and existence of special cases
|
|
|
|
int AvailWidth = (int)g_MdiWidth;
|
|
int AvailHeight = (int)g_MdiHeight;
|
|
|
|
int X, Y, Width, MaxWidth, Height, RemainY;
|
|
|
|
//
|
|
// If icons present, don't cover them
|
|
//
|
|
if (AnyIcon)
|
|
{
|
|
AvailHeight -= GetSystemMetrics(SM_CYCAPTION) +
|
|
GetSystemMetrics(SM_CYFRAME);
|
|
}
|
|
|
|
int LeftWidth = NumLeft > 0 ? LEFT_SIDE_WIDTH : 0;
|
|
|
|
if (NumRight > 0)
|
|
{
|
|
switch(g_ActualProcType)
|
|
{
|
|
default:
|
|
Width = RIGHT_SIDE_MIN_WIDTH_32;
|
|
MaxWidth = RIGHT_SIDE_DESIRED_WIDTH_32;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_IA64:
|
|
case IMAGE_FILE_MACHINE_AXP64:
|
|
case IMAGE_FILE_MACHINE_AMD64:
|
|
Width = RIGHT_SIDE_MIN_WIDTH_64;
|
|
MaxWidth = RIGHT_SIDE_DESIRED_WIDTH_64;
|
|
break;
|
|
}
|
|
|
|
if (AvailWidth < LeftWidth + Width)
|
|
{
|
|
// Not enough space for left side to be at
|
|
// its desired width.
|
|
if (NumLeft == 0)
|
|
{
|
|
// No left-side windows to take space from.
|
|
Width = AvailWidth;
|
|
}
|
|
else
|
|
{
|
|
LeftWidth = AvailWidth - Width;
|
|
if (LeftWidth < LEFT_SIDE_MIN_WIDTH)
|
|
{
|
|
// We stole too much space so neither
|
|
// side can meet their minimum widths. Just
|
|
// split the available space up.
|
|
Width = AvailWidth / 2;
|
|
LeftWidth = AvailWidth - Width;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Take up space on the right side up to the
|
|
// desired width but no more. This gives
|
|
// any extra space to the left side as the right
|
|
// side doesn't really need any more than its desired
|
|
// width.
|
|
Width = AvailWidth - LeftWidth;
|
|
if (Width > MaxWidth)
|
|
{
|
|
Width = MaxWidth;
|
|
LeftWidth = AvailWidth - Width;
|
|
}
|
|
}
|
|
|
|
X = LeftWidth;
|
|
Y = 0;
|
|
Height = AvailHeight / NumRight;
|
|
|
|
if (hwndCpu != NULL)
|
|
{
|
|
DeferWindowPos(Defer, hwndCpu, NULL, X, Y,
|
|
Width, Height, POS_ONLY);
|
|
Y += Height;
|
|
Height = AvailHeight - Height;
|
|
}
|
|
|
|
if (hwndScratch != NULL)
|
|
{
|
|
DeferWindowPos(Defer, hwndScratch, NULL, X, Y,
|
|
Width, Height, POS_ONLY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LeftWidth = AvailWidth;
|
|
}
|
|
|
|
if (NumLeft == 0)
|
|
{
|
|
goto EndDefer;
|
|
}
|
|
|
|
int CmdHeight;
|
|
int BiasedNumLeft;
|
|
|
|
// Compute the size of each vertical band within the left side.
|
|
// When doing so bias things so the command window gets
|
|
// a 2.0 share to account for the fact that it has both
|
|
// output and input areas. Also give it any remainder
|
|
// space left when dividing.
|
|
BiasedNumLeft = NumLeft * 2 + (hwndCmd != NULL ? 2 : 0);
|
|
Height = (AvailHeight * 2) / BiasedNumLeft;
|
|
if (hwndCmd != NULL)
|
|
{
|
|
CmdHeight = AvailHeight - Height * (NumLeft - 1);
|
|
RemainY = 0;
|
|
}
|
|
else
|
|
{
|
|
RemainY = Height * (NumLeft + 1) - AvailHeight;
|
|
}
|
|
Y = 0;
|
|
|
|
// Place the watch and locals windows at the top.
|
|
if (NumWatchLocals > 0)
|
|
{
|
|
if (RemainY-- == 1)
|
|
{
|
|
Height++;
|
|
}
|
|
|
|
X = 0;
|
|
Width = LeftWidth / NumWatchLocals;
|
|
|
|
if (hwndWatch != NULL)
|
|
{
|
|
DeferWindowPos(Defer, hwndWatch, NULL, X, Y,
|
|
Width, Height, POS_ONLY);
|
|
X += Width;
|
|
Width = LeftWidth - X;
|
|
}
|
|
if (hwndLocals != NULL)
|
|
{
|
|
DeferWindowPos(Defer, hwndLocals, NULL, X, Y,
|
|
Width, Height, POS_ONLY);
|
|
X += Width;
|
|
Width = LeftWidth - X;
|
|
}
|
|
|
|
Y += Height;
|
|
}
|
|
|
|
// Place all the memory windows next.
|
|
if (NumMem > 0)
|
|
{
|
|
if (RemainY-- == 1)
|
|
{
|
|
Height++;
|
|
}
|
|
|
|
ArrangeInRect(Defer, 0, Y, LeftWidth, Height,
|
|
FALSE, 1 << MEM_WINDOW, NumMem, FALSE);
|
|
|
|
Y += Height;
|
|
}
|
|
|
|
// Disasm window.
|
|
if (hwndDisasm != NULL)
|
|
{
|
|
if (RemainY-- == 1)
|
|
{
|
|
Height++;
|
|
}
|
|
|
|
DeferWindowPos(Defer, hwndDisasm, NULL, 0, Y,
|
|
LeftWidth, Height, POS_ONLY);
|
|
|
|
Y += Height;
|
|
}
|
|
|
|
// Doc windows.
|
|
if (NumDoc > 0)
|
|
{
|
|
if (RemainY-- == 1)
|
|
{
|
|
Height++;
|
|
}
|
|
|
|
ArrangeInRect(Defer, 0, Y, LeftWidth, Height,
|
|
FALSE, 1 << DOC_WINDOW, NumDoc,
|
|
(g_WinOptions & WOPT_OVERLAY_SOURCE) != 0);
|
|
|
|
Y += Height;
|
|
}
|
|
|
|
// Command window.
|
|
if (hwndCmd != NULL)
|
|
{
|
|
if (RemainY-- == 1)
|
|
{
|
|
Height++;
|
|
}
|
|
|
|
DeferWindowPos(Defer, hwndCmd, NULL, 0, Y,
|
|
LeftWidth, CmdHeight, POS_ONLY);
|
|
|
|
Y += CmdHeight;
|
|
}
|
|
|
|
// Calls window.
|
|
if (hwndCalls != NULL)
|
|
{
|
|
if (RemainY-- == 1)
|
|
{
|
|
Height++;
|
|
}
|
|
|
|
DeferWindowPos(Defer, hwndCalls, NULL, 0, Y,
|
|
LeftWidth, Height, POS_ONLY);
|
|
|
|
Y += Height;
|
|
}
|
|
|
|
// Processes and threads window.
|
|
if (hwndProcThread != NULL)
|
|
{
|
|
if (RemainY-- == 1)
|
|
{
|
|
Height++;
|
|
}
|
|
|
|
DeferWindowPos(Defer, hwndProcThread, NULL, 0, Y,
|
|
LeftWidth, Height, POS_ONLY);
|
|
|
|
Y += Height;
|
|
}
|
|
|
|
EndDefer:
|
|
EndDeferWindowPos(Defer);
|
|
|
|
EndAutoOp:
|
|
// The auto-op is finished.
|
|
for (Entry = g_ActiveWin.Flink;
|
|
Entry != &g_ActiveWin;
|
|
Entry = Entry->Flink)
|
|
{
|
|
pWinData = ACTIVE_WIN_ENTRY(Entry);
|
|
pWinData->m_InAutoOp--;
|
|
}
|
|
}
|
|
|
|
void
|
|
UpdateSourceOverlay(void)
|
|
{
|
|
// If we're turning off overlay just leave the windows
|
|
// the way they are.
|
|
if ((g_WinOptions & WOPT_OVERLAY_SOURCE) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If doc windows are auto-arranged just handle it
|
|
// that way.
|
|
if (IsAutoArranged(DOC_WINDOW))
|
|
{
|
|
Arrange();
|
|
return;
|
|
}
|
|
|
|
// Source overlay was just turned on. Pile all source
|
|
// windows on top of the first one.
|
|
|
|
PLIST_ENTRY Entry;
|
|
PCOMMONWIN_DATA WinData;
|
|
int X, Y;
|
|
|
|
X = -INT_MAX;
|
|
for (Entry = g_ActiveWin.Flink;
|
|
Entry != &g_ActiveWin;
|
|
Entry = Entry->Flink)
|
|
{
|
|
WinData = ACTIVE_WIN_ENTRY(Entry);
|
|
if (WinData->m_enumType == DOC_WINDOW &&
|
|
!IsIconic(WinData->m_Win))
|
|
{
|
|
if (X == -INT_MAX)
|
|
{
|
|
RECT Rect;
|
|
|
|
// First window, remember its position.
|
|
GetWindowRect(WinData->m_Win, &Rect);
|
|
MapWindowPoints(GetDesktopWindow(), g_hwndMDIClient,
|
|
(LPPOINT)&Rect, 1);
|
|
X = Rect.left;
|
|
Y = Rect.top;
|
|
}
|
|
else
|
|
{
|
|
// Line up with the first window.
|
|
SetWindowPos(WinData->m_Win, NULL, X, Y, 0, 0,
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SetAllFonts(ULONG FontIndex)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PCOMMONWIN_DATA WinData;
|
|
|
|
for (Entry = g_ActiveWin.Flink;
|
|
Entry != &g_ActiveWin;
|
|
Entry = Entry->Flink)
|
|
{
|
|
WinData = ACTIVE_WIN_ENTRY(Entry);
|
|
if (WinData != NULL)
|
|
{
|
|
WinData->SetFont(FontIndex);
|
|
// Treat this like a resize as the line height
|
|
// may change.
|
|
WinData->OnSize();
|
|
}
|
|
}
|
|
|
|
if (g_WinOptions & WOPT_AUTO_ARRANGE)
|
|
{
|
|
Arrange();
|
|
}
|
|
}
|
|
|
|
void
|
|
CloseAllWindows(void)
|
|
{
|
|
HWND Win, Next;
|
|
|
|
Win = MDIGetActive(g_hwndMDIClient, NULL);
|
|
while (Win != NULL)
|
|
{
|
|
Next = GetNextWindow(Win, GW_HWNDNEXT);
|
|
SendMessage(g_hwndMDIClient, WM_MDIDESTROY, (WPARAM)Win, 0);
|
|
Win = Next;
|
|
}
|
|
}
|
|
|
|
void
|
|
UpdateAllColors(void)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PCOMMONWIN_DATA WinData;
|
|
|
|
for (Entry = g_ActiveWin.Flink;
|
|
Entry != &g_ActiveWin;
|
|
Entry = Entry->Flink)
|
|
{
|
|
WinData = ACTIVE_WIN_ENTRY(Entry);
|
|
if (WinData != NULL)
|
|
{
|
|
WinData->UpdateColors();
|
|
}
|
|
}
|
|
}
|
|
|
|
PCOMMONWIN_DATA
|
|
FindNthWindow(ULONG Nth, ULONG Types)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PCOMMONWIN_DATA WinData;
|
|
|
|
for (Entry = g_ActiveWin.Flink;
|
|
Entry != &g_ActiveWin;
|
|
Entry = Entry->Flink)
|
|
{
|
|
WinData = ACTIVE_WIN_ENTRY(Entry);
|
|
if (WinData != NULL &&
|
|
((1 << WinData->m_enumType) & Types) &&
|
|
Nth-- == 0)
|
|
{
|
|
return WinData;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|