home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windoware
/
WINDOWARE_1_6.iso
/
winutil
/
adg_7_8
/
frame.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-21
|
28KB
|
748 lines
/****************************************************************************
Module name: Frame.C
Programmer : Jeffrey M. Richter & Elvira Peretsman.
*****************************************************************************/
#include "..\nowindws.h"
#undef NOCOLOR
#undef NOCTLMGR
#undef NODEFERWINDOWPOS
#undef NOGDI
#undef NOKERNEL
#undef NOLSTRING
#undef NOMB
#undef NOMDI
#undef NOMENUS
#undef NOMINMAX
#undef NONCMESSAGES
#undef NOSCROLL
#undef NOSHOWWINDOW
#undef NOSYSCOMMANDS
#undef NOSYSMETRICS
#undef NOTEXTMETRIC
#undef NOUSER
#undef NOWH
#undef NOWINMESSAGES
#undef NOWINOFFSETS
#undef NOWINSTYLES
#define OEMRESOURCE
#include <windows.h>
#include "mdi.h"
static char _szClassName[] = "Frame";
// Structure for use with Class Extra Bytes.
typedef struct {
WORD wNumSheets; // Number of Sheet windows created.
WORD wNumCharts; // Number of Chart windows created.
HMENU hMenu; // Menu used when no MDI Children are active.
BOOL fStatusBarOn; // Is the status bar showing.
HWND hWndMenuHelp; // Window that last received a WM_MENUSELECT message.
DWORD dwMenuHelp; // Menu help code placed here by hWndMenuHelp window.
} CLSEB;
void NEAR PASCAL TileVertically (HWND hWndMDIClient);
BOOL FAR PASCAL AboutProc (HWND hDlg, WORD wMsg, WORD wParam, LONG lParam);
LONG FAR PASCAL FrameWndProc (HWND hWnd, WORD wMsg, WORD wParam, LONG lParam) {
BOOL fCallDefProc = FALSE;
DWORD dwResult = 0;
CLIENTCREATESTRUCT ccs;
HMENU hMenu;
RECT rc, rcTemp;
WORD wTemp = 0;
FARPROC fpProc;
char szBuf[100];
PAINTSTRUCT ps;
TEXTMETRIC tm;
HPEN hPen;
BITMAP Bitmap;
HWND hWndActiveMDIChild, hWndChild;
BOOL fMDIChildIsMaximized;
if (IsWindow(_hWndMDIClient))
dwResult = SendMessage(_hWndMDIClient, WM_MDIGETACTIVE, 0, 0);
// Get the window handle of the active MDI Child.
// This is NULL if no MDI Children exist.
hWndActiveMDIChild = (HWND) LOWORD(dwResult);
// Determine if the MDI Child is maximized.
fMDIChildIsMaximized = HIWORD(dwResult);
dwResult = 0;
switch (wMsg) {
case WM_CREATE:
// Initialize default values in the class extra bytes.
hMenu = LoadMenu(_hInstance, _szClassName);
SETCLSEB(hWnd, CLSEB, hMenu, hMenu);
SETCLSEB(hWnd, CLSEB, fStatusBarOn, TRUE);
// Create the MDICLIENT window as a child of the Frame.
ccs.hWindowMenu = GetSubMenu(GetMenu(hWnd), 1);
ccs.idFirstChild = IDM_WINDOWCHILD;
_hWndMDIClient = CreateWindow("MDIClient", "",
WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL |
WS_VISIBLE | WS_CLIPSIBLINGS, 0, 0, 0, 0, hWnd, NULL, _hInstance,
(LPSTR) (LPCLIENTCREATESTRUCT) &ccs);
break;
case WM_CLOSE:
// Before closing the application, ask the MDI Children if it is OK?
// wParam is TRUE because the Windows session is NOT being ended.
fCallDefProc = (BOOL) SendMessage(hWnd, WM_QUERYENDSESSION, TRUE, 0);
if (fCallDefProc) SendMessage(hWnd, WM_ENDSESSION, TRUE, 0);
break;
case WM_QUERYENDSESSION:
// If called by Windows, wParam is zero else wParam is TRUE.
// Assume that it is OK to end the session.
dwResult = TRUE;
// Get the handle of the first MDI Child.
hWndChild = GetWindow(_hWndMDIClient, GW_CHILD);
// If no MDI Children exist, it is OK to terminate.
if (hWndChild == NULL) break;
// Ask each child if it is OK to terminate.
do {
// Do not ask caption bars of iconic MDI Children.
if (GetWindow(hWndChild, GW_OWNER) != NULL) continue;
dwResult = SendMessage(hWndChild, WM_QUERYENDSESSION, wParam, 0);
// If the MDI Child says that it is NOT OK, don't ask the
// rest of the MDI Children.
if (dwResult == FALSE) break;
} while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
// If any MDI Child said NO, tell the other children that
// the session is NOT being terminated.
if (dwResult == FALSE) {
wTemp = hWndChild;
hWndChild = GetWindow(_hWndMDIClient, GW_CHILD);
do {
// If this child is the one that said NO, stop.
if (wTemp == hWndChild) break;
// Do not send to caption bars of iconic MDI Children.
if (GetWindow(hWndChild, GW_OWNER) != NULL) continue;
// Tell child we are not ending the session (wParam is FALSE).
SendMessage(hWndChild, WM_ENDSESSION, FALSE, 0);
} while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
}
// dwResult is TRUE if OK, FALSE if not Ok.
break;
case WM_ENDSESSION:
// wParam != FALSE if shutting down.
// Get handle of first MDI Child window.
hWndChild = GetWindow(_hWndMDIClient, GW_CHILD);
// If no MDI Children exist, we are done.
if (hWndChild == NULL) break;
// Tell each MDI Child whether or not the session is ending.
do {
// Do not send to caption bars of iconic MDI Children.
if (GetWindow(hWndChild, GW_OWNER) != NULL) continue;
SendMessage(hWndChild, WM_ENDSESSION, wParam, 0);
} while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SYSCOMMAND:
// Set focus to frame window. This causes any comboboxes
// in the ribbon to be closed.
SetFocus(hWnd);
fCallDefProc = TRUE;
break;
case WM_NCLBUTTONDBLCLK:
// Code to allow double-clicking the MDI Child's system menu
// to close the MDI Child window.
fCallDefProc = TRUE;
// If mouse wasn't clicked in the application's menu, nothing to do.
if (wParam != HTMENU) break;
// If the active child is not maximized, nothing to do.
dwResult = SendMessage(_hWndMDIClient, WM_MDIGETACTIVE, 0, 0);
if (HIWORD(dwResult) != 1) break;
// Get position and dimensions of the MDI Child's system menu in
// the Frame's menu bar.
// Get position and dimensions of the Frame window.
GetWindowRect(hWnd, &rc);
// Get handle to the CLOSE BOX bitmaps.
wTemp = LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CLOSE));
// Get dimensions of the bitmaps.
GetObject((HBITMAP) wTemp, sizeof(BITMAP), (LPSTR) (LPBITMAP) &Bitmap);
DeleteObject((HBITMAP) wTemp);
// Adjust the rectangle.
rc.top += GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
rc.bottom = rc.top + Bitmap.bmHeight;
rc.left += GetSystemMetrics(SM_CXFRAME);
// The close bitmap includes the Application and MDI Child CLOSE
// boxes. So we only want half of the bitmap's width.
rc.right = rc.left + Bitmap.bmWidth / 2;
// If the mouse cursor is within this rectangle, tell the
// MDI Child window to close.
if (!PtInRect(&rc, MAKEPOINT(lParam))) break;
SendMessage(LOWORD(dwResult), WM_SYSCOMMAND, SC_CLOSE, lParam);
fCallDefProc = FALSE;
break;
case FW_MDICHILDDESTROY:
// Message is posted by an MDI Child just before it is destroyed.
// If another MDI Child exists, nothing to do.
if (hWndActiveMDIChild != NULL) break;
// Set the menu bar and accelerator table to the Frame's defaults.
ChangeMDIMenu(hWnd, _hWndMDIClient,
(HMENU) GETCLSEB(hWnd, CLSEB, hMenu), IDM_WINDOWTILEVERT);
_hAccelTable = NULL;
// Force the status bar to be updated.
InvalidateRect(hWnd, NULL, TRUE);
// Disable the Ribbon.
EnableWindow(_hDlgRibbon, FALSE);
break;
case FW_GETSTATBARRECT:
// lParam = LPRECT.
// Get the client area of the Frame window.
GetClientRect(hWnd, (LPRECT) lParam);
// If the status bar is OFF, set the status bar to have no height.
if (!GETCLSEB(hWnd, CLSEB, fStatusBarOn)) {
((LPRECT) lParam)->top = ((LPRECT) lParam)->bottom;
break;
}
// Change the dimensions so that the status bar is the height of
// one line of text plus a small border.
wTemp = GetDC(hWnd);
GetTextMetrics((HDC) wTemp, &tm);
ReleaseDC(hWnd, (HDC) wTemp);
((LPRECT) lParam)->top = ((LPRECT) lParam)->bottom - tm.tmHeight -
GetSystemMetrics(SM_CYBORDER);
break;
case FW_DRAWSTATUSDIVIDE:
// lParam = (LPPAINTSTRUCT) &ps.
// Draw a line separating the status bar from the MDICLIENT window.
dwResult = GetSystemMetrics(SM_CYBORDER);
hPen = CreatePen(PS_SOLID, (int) dwResult, RGB(0, 0, 0));
hPen = SelectObject(((LPPAINTSTRUCT) lParam)->hdc, hPen);
MoveTo(((LPPAINTSTRUCT) lParam)->hdc, 0,
((LPPAINTSTRUCT) lParam)->rcPaint.top);
LineTo(((LPPAINTSTRUCT) lParam)->hdc,
((LPPAINTSTRUCT) lParam)->rcPaint.right,
((LPPAINTSTRUCT) lParam)->rcPaint.top);
hPen = SelectObject(((LPPAINTSTRUCT) lParam)->hdc, hPen);
DeleteObject(hPen);
break;
case FW_RESIZEMDICLIENT:
// Sent when the Frame window is resized or when the status bar
// and ribbon are toggled.
GetClientRect(hWnd, &rc);
if (IsWindow(_hDlgRibbon) && IsWindowVisible(_hDlgRibbon)) {
// Ribbon is displayed, adjust rectangle.
GetClientRect(_hDlgRibbon, &rcTemp);
rc.top += rcTemp.bottom;
rc.bottom -= rcTemp.bottom;
}
// Get the dimensions of the status bar rectangle and adjust the
// dimensions of the MDICLIENT window.
SendMessage(hWnd, FW_GETSTATBARRECT, 0, (LONG) (LPRECT) &rcTemp);
rc.bottom -= rcTemp.bottom - rcTemp.top;
MoveWindow(_hWndMDIClient, 0, rc.top, rc.right, rc.bottom, TRUE);
break;
case WM_SIZE:
// Force MDICHILD window to be resized.
SendMessage(hWnd, FW_RESIZEMDICLIENT, 0, 0);
break;
case WM_PAINT:
// Since the only visible portion of the Frame's client area is
// the status bar when it is ON, this must mean that the status
// bar needs to be repainted.
// Set up the device context.
BeginPaint(hWnd, &ps);
SendMessage(hWnd, FW_GETSTATBARRECT, 0, (LONG) (LPRECT) &ps.rcPaint);
SetBkMode(ps.hdc, TRANSPARENT);
// If an MDI Child exists, the status bar must be updated by it.
if (hWndActiveMDIChild) {
SendMessage(hWndActiveMDIChild, AC_PAINTSTATBAR, ps.hdc,
(LONG) (LPPAINTSTRUCT) &ps);
} else {
// No MDI Child exists, the Frame can do whatever it wants here.
ps.rcPaint.top += (int) SendMessage(hWnd, FW_DRAWSTATUSDIVIDE, 0,
(LONG) (LPPAINTSTRUCT) &ps);
LoadString(_hInstance, IDS_FRAMESTATUSBAR, szBuf, sizeof(szBuf));
TextOut(ps.hdc, 0, ps.rcPaint.top, szBuf, lstrlen(szBuf));
}
EndPaint(hWnd, &ps);
break;
case WM_INITMENU:
// The user has entered the menu system, set any options.
CheckMenuItem(wParam, IDM_OPTIONSSTATUS, MF_BYCOMMAND |
(GETCLSEB(hWnd, CLSEB, fStatusBarOn) ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(wParam, IDM_OPTIONSRIBBON, MF_BYCOMMAND |
(IsWindowVisible(_hDlgRibbon) ? MF_CHECKED : MF_UNCHECKED));
break;
case FW_SETMENUHELP:
// Called by the Frame and MDI Children whenever a
// WM_MENUSELECT message is received.
// wParam = HWND of sender.
// lParam = Menu description code.
// Save the handle of the window sending the message.
SETCLSEB(hWnd, CLSEB, hWndMenuHelp, (HWND) wParam);
// Save the menu help code that the window sent too.
SETCLSEB(hWnd, CLSEB, dwMenuHelp, lParam);
// When the Frame or MDI Child receive a WM_MENUSELECT message
// specifying that the menu system is closed
// (lParam == MAKELONG(-1, 0)), the menu help should disappear and
// be replaced by the proper information on the status bar.
if (wParam == NULL) {
SendMessage(hWnd, FW_GETSTATBARRECT, 0, (LONG) (LPRECT) &rc);
// Force status bar to be updated.
InvalidateRect(hWnd, &rc, TRUE);
}
break;
case FW_GETMENUHELP:
// Sent by the Frame or MDI Child when they
// receive a AW_PAINTMENUHELP message.
dwResult = GETCLSEB(hWnd, CLSEB, dwMenuHelp);
break;
case WM_MENUSELECT:
// The user has highlighted a menu item.
if (lParam == MAKELONG(-1, 0)) {
// User has stopped using the menu system.
SendMessage(hWnd, FW_SETMENUHELP, 0, 0);
break;
}
// If wTemp == 0, at end of switch, MDI Child handled the message.
wTemp = 0;
switch (LOWORD(lParam) & (MF_POPUP | MF_SYSMENU)) {
case 0:
// wParam is a menu item ID NOT on the app's system menu.
if (hWndActiveMDIChild != NULL) {
// An MDI Child exists.
if (fMDIChildIsMaximized) {
// If menu item from the MDI Child's system menu, set
// the MF_SYSMENU bit in the lParam parameter.
wTemp = GetSubMenu(GetMenu(hWnd), 0);
if ((int) GetMenuState(wTemp, wParam, MF_BYCOMMAND) != -1)
lParam |= MF_SYSMENU;
}
// Make active MDI Child think that it received the
// WM_MENUSELECT message.
SendMessage(hWndActiveMDIChild, wMsg, wParam, lParam);
wTemp = 0; // MDI Child handled the message.
break;
}
wTemp = IDS_FRAMEMENUID + wParam;
break;
case MF_POPUP:
// wParam is handle to popup menu.
if (hWndActiveMDIChild != NULL) {
// An MDI Child exists.
if (fMDIChildIsMaximized) {
// If popup menu is first top-level menu, it is the
// MDI Child's system menu, set the MF_SYSMENU flag.
if (wParam == GetSubMenu(GetMenu(hWnd), 0))
lParam |= MF_SYSMENU;
}
// Make active MDI Child think that it received the
// WM_MENUSELECT message.
SendMessage(hWndActiveMDIChild, wMsg, wParam, lParam);
wTemp = 0; // MDI Child handled the message.
break;
}
// Calculate the index of the top-level menu.
hMenu = GetMenu(hWnd);
wTemp = GetMenuItemCount(hMenu);
while (wTemp--)
if (GetSubMenu(hMenu, wTemp) == (HMENU) wParam) break;
wTemp += IDS_FRAMEPOPUPID + 1; // Jump over system menu.
break;
case MF_SYSMENU:
// wParam is menu item ID from system menu.
wTemp = IDS_FRAMEMENUID + ((wParam & 0x0FFF) >> 4);
break;
case MF_POPUP | MF_SYSMENU:
// wParam is handle to app's sys menu.
wTemp = IDS_FRAMEPOPUPID;
break;
}
// If message handled by MDI Child, nothing more to do.
if (wTemp == 0) break;
// Tell the Frame that the Frame window should display the
// help text and the identifier for the help text.
SendMessage(hWnd, FW_SETMENUHELP, hWnd, wTemp);
break;
case WM_ENTERIDLE:
if (wParam != MSGF_MENU) break;
// User has stopped scrolling through menu items.
// If Menu help already displayed, nothing more to do.
// This is signaled by hWndMenu help being -1.
if (GETCLSEB(hWnd, CLSEB, hWndMenuHelp) == -1)
break;
// Display new menu help, invalidate the status bar.
SendMessage(hWnd, FW_GETSTATBARRECT, 0, (LONG) (LPRECT) &rc);
InvalidateRect(hWnd, &rc, TRUE);
// BeginPaint is OK because an invalid rectangle must exist because
// of the call to InvalidateRect above. This causes the background
// for the Frame's client area to be drawn correctly.
BeginPaint(hWnd, &ps);
// Set up the device context.
SetBkMode(ps.hdc, TRANSPARENT);
// Send message to window that last received a WM_MENUSELECT
// message to tell it to paint the status bar with the
// appropriate menu help text.
SendMessage((HWND) GETCLSEB(hWnd, CLSEB, hWndMenuHelp),
AW_PAINTMENUHELP, 0, (LONG) (LPPAINTSTRUCT) &ps);
EndPaint(hWnd, &ps);
// Set flag notifying this message that the most recently selected
// menu item has had its help text painted. This stops unsightly
// screen flicker.
SETCLSEB(hWnd, CLSEB, hWndMenuHelp, (HWND) -1);
break;
case AW_PAINTMENUHELP:
// Message sent from Frame window to notify Frame that it should
// paint the status bar text for the last highlighted menu item.
// lParam = LPPAINTSTRUCT of Frame's status bar.
// Ask the Frame window what the last selected menu ID was.
// This value was sent to the frame by this window during the
// processing for the WM_MENUSELECT message.
dwResult = SendMessage(hWnd, FW_GETMENUHELP, 0, 0);
// Draw the horizontal dividing line separating the Status bar
// from the MDICLIENT window.
((LPPAINTSTRUCT) lParam)->rcPaint.top += (int)
SendMessage(hWnd, FW_DRAWSTATUSDIVIDE, 0,
(LONG) (LPPAINTSTRUCT) lParam);
// Construct the string that is to be displayed.
LoadString(_hInstance, LOWORD(dwResult), szBuf, sizeof(szBuf));
// Paint the menu help text in the status bar.
TextOut(((LPPAINTSTRUCT) lParam)->hdc,
0, ((LPPAINTSTRUCT) lParam)->rcPaint.top, szBuf, lstrlen(szBuf));
break;
case WM_COMMAND:
// If a child is being activated via the "Window" menu, let
// the DefFrameProc handle it.
if (wParam >= IDM_WINDOWCHILD) {
fCallDefProc = TRUE;
break;
}
switch (wParam) {
case IDM_FILEOPENSHEET:
// Get the # of sheets already created and increment by 1.
wTemp = GETCLSEB(hWnd, CLSEB, wNumSheets) + 1;
SETCLSEB(hWnd, CLSEB, wNumSheets, wTemp);
// The sheet's caption should display the sheet number.
wsprintf(szBuf, "Sheet%d", wTemp);
// Create the MDI Child window.
CreateMDIChild("Sheet", szBuf, 0,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
_hWndMDIClient, _hInstance, 0);
// Make sure the ribbon is enabled when any children exist.
EnableWindow(_hDlgRibbon, TRUE);
break;
case IDM_FILEOPENCHART:
// Get the # of charts already created and increment by 1.
wTemp = GETCLSEB(hWnd, CLSEB, wNumCharts) + 1;
SETCLSEB(hWnd, CLSEB, wNumCharts, wTemp);
// The chart's caption should display the chart number.
wsprintf(szBuf, "Chart%d", wTemp);
// Create the MDI Child window.
CreateMDIChild("Chart", szBuf, 0,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
_hWndMDIClient, _hInstance, 0);
// Make sure the ribbon is enabled when any children exist.
EnableWindow(_hDlgRibbon, TRUE);
break;
case IDM_OPTIONSSTATUS:
// Toggle the status of the status bar, resize the MDICLIENT.
wTemp = !GETCLSEB(hWnd, CLSEB, fStatusBarOn);
SETCLSEB(hWnd, CLSEB, fStatusBarOn, wTemp);
SendMessage(hWnd, FW_RESIZEMDICLIENT, 0, 0);
break;
case IDM_OPTIONSRIBBON:
// Toggle the status of the ribbon, resize the MDICLIENT.
ShowWindow(_hDlgRibbon,
IsWindowVisible(_hDlgRibbon) ? SW_HIDE : SW_SHOW);
SendMessage(hWnd, FW_RESIZEMDICLIENT, 0, 0);
break;
case IDM_EXIT:
SendMessage(hWnd, WM_CLOSE, 0, 0L);
break;
case IDM_HELPINDEX:
case IDM_HELPKEYBOARD:
case IDM_HELPCOMMANDS:
case IDM_HELPPROCEDURES:
case IDM_HELPUSINGHELP:
MessageBox(hWnd, "Option not implemented.", _szAppName, MB_OK);
break;
case IDM_ABOUT:
fpProc = MakeProcInstance(AboutProc, _hInstance);
DialogBox(_hInstance, "About", hWnd, fpProc);
FreeProcInstance(fpProc);
break;
case IDM_WINDOWTILEVERT:
// Call our own function to perform vertical tiling.
TileVertically(_hWndMDIClient);
break;
case IDM_WINDOWTILEHORIZ:
// Let the MDICLIENT window do the repositioning.
SendMessage(_hWndMDIClient, WM_MDITILE, 0, 0);
break;
case IDM_WINDOWCASCADE:
// Let the MDICLIENT window do the repositioning.
SendMessage(_hWndMDIClient, WM_MDICASCADE, 0, 0);
break;
case IDM_WINDOWARRANGEICONS:
// Let the MDICLIENT window do the repositioning.
SendMessage(_hWndMDIClient, WM_MDIICONARRANGE, 0, 0);
break;
default:
// Menu options not processed by the Frame window must
// be passed to the MDI Children for processing.
SendMessage(hWndActiveMDIChild, wMsg, wParam, lParam);
break;
}
break;
default:
fCallDefProc = TRUE;
break;
}
if (fCallDefProc)
dwResult = DefFrameProc(hWnd, _hWndMDIClient, wMsg, wParam, lParam);
return(dwResult);
}
BOOL FAR PASCAL RegisterFrameWndClass (void) {
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = FrameWndProc;
// Number of class extra bytes used by structure.
wc.cbClsExtra = sizeof(CLSEB);
wc.cbWndExtra = 0;
wc.hInstance = _hInstance;
wc.hIcon = LoadIcon(_hInstance, _szClassName);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = COLOR_WINDOW + 1;
wc.lpszMenuName = _szClassName;
wc.lpszClassName = _szClassName;
return(RegisterClass(&wc));
}
void NEAR PASCAL TileVertically (HWND hWndMDIClient) {
int nNumWndsOnRow, nOpenMDIChildren = 0, nTopOfBottomIconRow = 0;
int nCrntCol, nColWidth, nCrntRow, nNumRows, nRowHeight, nMinWndHeight;
HWND hWndChild;
HANDLE hWinPosInfo;
RECT rc;
POINT Point;
DWORD dwChildInfo;
// Assume that scrollbars will be off after windows are tiled.
// By forcing them off now, GetClientRect will return the correct size.
ShowScrollBar(hWndMDIClient, SB_BOTH, 0);
// The WM_MDICASCADE and WM_MDITILE messages cause the icons to be
// arranged. So we will too. In fact, this is necessary to locate
// the top of the bottom icon row in the next step of this function.
SendMessage(hWndMDIClient, WM_MDIICONARRANGE, 0, 0);
// Get handle to first MDI Child window.
hWndChild = GetWindow(hWndMDIClient, GW_CHILD);
do {
if (IsIconic(hWndChild) && GetWindow(hWndChild, GW_OWNER) == NULL) {
// Window is iconic and window is NOT an icon's caption.
// Get client area of the icon window.
GetWindowRect(hWndChild, &rc);
// rc.top is in screen coordinates.
nTopOfBottomIconRow = max(nTopOfBottomIconRow, rc.top);
}
if (!IsIconic(hWndChild) && GetWindow(hWndChild, GW_OWNER) == NULL)
++nOpenMDIChildren;
} while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
// All MDI Children are icons, no tiling is necessary.
if (nOpenMDIChildren == 0) return;
// Find height of usable client area for tiling.
GetClientRect(hWndMDIClient, &rc);
if (nTopOfBottomIconRow) {
// At least one MDI Child is iconic.
// Convert coordinates from screen to client.
Point.x = 0; Point.y = nTopOfBottomIconRow;
ScreenToClient(hWndMDIClient, &Point);
// Point.y is top of bottom icon row in client coordinates.
rc.bottom = Point.y;
}
// Restore the active MDI child if it's maximized
dwChildInfo = SendMessage(hWndMDIClient, WM_MDIGETACTIVE, 0, 0);
if (HIWORD(dwChildInfo) == 1)
ShowWindow(LOWORD(dwChildInfo), SW_RESTORE);
// Calculate the minimum desired height of each MDI Child.
nMinWndHeight = max(1, rc.bottom / (5 * GetSystemMetrics(SM_CYCAPTION)));
// Calculate the number of rows that will be tiled.
nNumRows = min(nOpenMDIChildren, nMinWndHeight);
// Calculate the height of each row.
nRowHeight = rc.bottom / nNumRows;
// Get the handle to the first MDI Child window.
hWndChild = GetWindow(hWndMDIClient, GW_CHILD);
// Prime the storage of positioning information.
hWinPosInfo = BeginDeferWindowPos(nOpenMDIChildren);
// Execute the loop for each row.
for (nCrntRow = 0; nCrntRow < nNumRows; nCrntRow++) {
// Calculate the number of MDI Children that will appear on this row.
nNumWndsOnRow = nOpenMDIChildren / nNumRows +
((nOpenMDIChildren % nNumRows > (nNumRows - (nCrntRow + 1))) ? 1 : 0);
// Calculate the width of each of these children.
nColWidth = rc.right / nNumWndsOnRow;
// Fill each column with an MDI Child window.
for (nCrntCol = 0; nCrntCol < nNumWndsOnRow; ) {
if (!IsIconic(hWndChild) && GetWindow(hWndChild, GW_OWNER) == NULL) {
// Child is NOT iconic and not an icon's caption bar.
// Tell windows what the new position and dimensions of this
// MDI Child should be.
hWinPosInfo = DeferWindowPos(hWinPosInfo, hWndChild, NULL,
nCrntCol * nColWidth, nCrntRow * nRowHeight, nColWidth,
nRowHeight, SWP_NOACTIVATE | SWP_NOZORDER);
// Go to the next column.
nCrntCol++;
}
// Get handle to the next MDI Child window.
hWndChild = GetWindow(hWndChild, GW_HWNDNEXT);
}
}
// All of the positioning has been set. Now, tell Windows to update
// all of the windows at once.
EndDeferWindowPos(hWinPosInfo);
}