|
|
Microsoft OS/2 SDK PM 02-24-1989
/***************************************************************************\
* ARRANGE.c - This file contains code to do window arrangment.
*
* Created by Microsoft Corporation, 1989
\***************************************************************************/
#define INCL_WINSYS
#define INCL_WINCOMMON
#define INCL_WINMESSAGEMGR
#define INCL_WINPOINTERS
#define INCL_WININPUT
#define INCL_WINMENUS
#define INCL_WINFRAMEMGR
#define INCL_WINWINDOWMGR
#define INCL_WINRECTANGLES
#define INCL_WINHEAP
#include <os2.h>
#include "app.h"
#include "appdata.h"
#include "mdi.h"
#include "mdidata.h"
/* internal function prototypes */
BOOL SetTilePositions(PRECTL prc, SHORT cWnd, PSWP aswp);
SHORT CeilSquareRoot(USHORT us);
BOOL SetCascadePositions(PRECTL prc, SHORT cWnd, PSWP aswp);
BOOL SetCascadeParams(PRECTL prc, SHORT *pxEdge, SHORT *pyEdge,
SHORT *pxDelta, SHORT *pyDelta, SHORT *cMaxWnd);
BOOL GetArrangeSwp(USHORT *, SWP *, USHORT *, SWP *);
BOOL GetArrangeRectangle(PRECTL, BOOL);
BOOL ArrangeIconPositions(USHORT, PSWP);
/* internal constants */
#define CASC_EDGE_NUM 2
#define CASC_EDGE_DENOM 3
/* local constants */
#define ICON_PARK_NUM 5
#define ICON_PARK_DENOM 3
#define CLASS_NAME_LENGTH 8
/***************************************************************************\
* ArrangeWindowPositions
*
* This function sets positions for arranging windows nicely in a rectangle.
* The hwnd field of each SWP structure should be set by the user, either
* before or after calling this function. The function sets all other
* fields. The SWP array can then be passed to WinSetMultWindowPos() to do
* the physical arrangement. There are two arrangement styles available,
* AWP_TILED and AWP_CASCADED.
*
* AWP_TILED:
*
* The tiles are generated by rows, top left (first) to bottom right (last).
* Each row has the same number of tiles. The number of tiles in each
* column will differ by at most one, with each column containing one fewer
* tile to the left of the other columns.
*
* AWP_CASCADED:
*
* The windows are generated bottom right (first) to top left (last).
*
* Parameters:
* prc: rectangle to contain the tiled windows
* cWnd: number of windows to tile
* aswp: array of SWP structures, one for each tile window
* fStyle: the style to arrange the windows
\***************************************************************************/
BOOL ArrangeWindowPositions(PRECTL prc, SHORT cWnd, PSWP aswp, USHORT fStyle)
{
/* check validity of input rectangle */
if ((prc->xRight - prc->xLeft < 1) || (prc->yTop - prc->yBottom < 1)) {
return FALSE;
}
/* set window positions */
switch (fStyle) {
case AWP_TILED:
return SetTilePositions(prc, cWnd, aswp);
case AWP_CASCADED:
return SetCascadePositions(prc, cWnd, aswp);
default:
return FALSE;
}
}
/***************************************************************************\
* SetTilePositions
*
* This function sets positions for tiling windows in a rectangle.
*
* NOTE:
* There are a few subtleties to this code:
*
* The algorithm lays tiles in a modified NxN grid. It can be shown
* that any positive number of tiles can be laid out in such a grid of
* N columns so that each column has at least N-2 tiles and no column
* has more than one tile more than any other. Proof left to the
* interested reader.
*
* The tiles coordinates are not generated by stepping over a fixed
* interval since this will not usually fill the rectangle completely.
* Thus the offset at each step is calculated from the previous tile
* to the correct fractional position within the whole rectangle.
*
* Since the last "row" of tiles may not have any members in the beginning
* columns, these tiles are addressed differently in the SWP array to
* account for the "missing" tiles.
*
* Parameters:
* prc: rectangle to contain the tiled windows
* cWnd: number of windows to tile the rectangle with
* aswp: array of SWP structures, one for each tile window
\***************************************************************************/
BOOL SetTilePositions(PRECTL prc, SHORT cWnd, PSWP aswp)
{
register SHORT usRoot;
register SHORT cExtras;
SHORT iChange;
SHORT cDiff;
SHORT x, y, cx, cy;
SHORT iRow, iCol;
/* get grid dimensions */
usRoot = CeilSquareRoot(cWnd);
cExtras = usRoot * usRoot - cWnd;
/* find column where number of rows increases and find initial
difference of rows versus columns */
if (cExtras >= usRoot) {
iChange = cExtras - usRoot;
cDiff = 2;
} else {
iChange = cExtras;
cDiff = 1;
}
/* assign x coordinates */
x = (SHORT)prc->xLeft;
cx = 0;
for (iCol = 0; iCol < usRoot; iCol++) {
x += cx - cxBorder;
cx = ((SHORT)prc->xLeft) +
(((SHORT)(prc->xRight - prc->xLeft)) * (iCol + 1)) / usRoot -
x + cxBorder;
for (iRow = 0; iRow < usRoot - cDiff; iRow++) {
aswp[iRow * usRoot + iCol].x = x;
aswp[iRow * usRoot + iCol].cx = cx;
aswp[iRow * usRoot + iCol].fs = SWP_SIZE | SWP_MOVE;
}
/* assign "extra" row */
if (iCol >= iChange) {
aswp[iRow * usRoot + iCol - iChange].x = x;
aswp[iRow * usRoot + iCol - iChange].cx = cx;
aswp[iRow * usRoot + iCol - iChange].fs = SWP_SIZE | SWP_MOVE;
}
}
/* assign y coordinates, columns without extra row */
y = (SHORT)prc->yBottom;
cy = 0;
for (iRow = usRoot - cDiff - 1; iRow >= 0; iRow--) {
y += cy - cyBorder;
cy = ((SHORT)prc->yBottom) +
(((SHORT)(prc->yTop - prc->yBottom)) * (usRoot - cDiff - iRow)) /
(usRoot - cDiff) - y + cyBorder;
for (iCol = 0; iCol < iChange; iCol++) {
aswp[iRow * usRoot + iCol].y = y;
aswp[iRow * usRoot + iCol].cy = cy;
}
}
/* assign y coordinates, columns with extra row */
/* do last row first (different offsets) */
y = (SHORT)prc->yBottom - cyBorder;
cy = ((SHORT)(prc->yTop - prc->yBottom)) / (usRoot - cDiff + 1) +
2 * cyBorder;
for (iCol = iChange; iCol < usRoot; iCol++) {
aswp[usRoot * (usRoot - cDiff) + iCol - iChange].y = y;
aswp[usRoot * (usRoot - cDiff) + iCol - iChange].cy = cy;
}
for (iRow = usRoot - cDiff - 1; iRow >= 0; iRow--) {
y += cy - cyBorder;
cy = ((SHORT)(prc->yBottom)) +
(((SHORT)(prc->yTop - prc->yBottom)) * (usRoot - cDiff - iRow + 1))
/ (usRoot - cDiff + 1) - y + cyBorder;
for (iCol = iChange; iCol < usRoot; iCol++) {
aswp[iRow * usRoot + iCol].y = y;
aswp[iRow * usRoot + iCol].cy = cy;
}
}
return TRUE;
}
/***************************************************************************\
* CeilSquareRoot
*
* This function returns the smallest integer greater or equal to the square
* root of an unsigned 16 bit integer.
*
* Parameter:
* us: value to take the root of
\***************************************************************************/
SHORT CeilSquareRoot(register USHORT us)
{
register SHORT i;
/* prevent overflow of large numbers */
if (us > 0xFE * 0xFE)
return 0xFF;
/* iterate up past root */
for (i = 0; i*i < us; i++)
;
return i;
}
/***************************************************************************\
* SetCascadePositions
*
* This function sets positions for cascading windows in a rectangle.
*
* Parameters:
* prc: rectangle to contain the cascaded windows
* cWnd: number of windows to cascade
* aswp: array of SWP structures, one for each cascaded window
\***************************************************************************/
BOOL SetCascadePositions(PRECTL prc, SHORT cWnd, PSWP aswp)
{
SHORT xEdge, yEdge;
SHORT xDelta, yDelta;
SHORT cMaxWnd;
register SHORT x, y;
SHORT i, j;
RECTL rc;
/* set cascade parameters */
rc.xLeft = prc->xLeft - cxBorder;
rc.xRight = prc->xRight + cyBorder;
rc.yBottom = prc->yBottom - cyBorder;
rc.yTop = prc->yTop + cyBorder;
if (!SetCascadeParams((PRECTL)&rc, &xEdge, &yEdge, &xDelta, &yDelta,
&cMaxWnd)) {
return FALSE;
}
if (cWnd <= cMaxWnd) {
/* only one run needed; move to top left corner */
x = (SHORT)rc. xLeft;
y = (SHORT)rc. yTop - yEdge;
for (i = cWnd - 1; i >= 0; i--) {
aswp[i].x = x;
aswp[i].y = y;
aswp[i].cx = xEdge;
aswp[i].cy = yEdge;
aswp[i].fs = SWP_SIZE | SWP_MOVE;
x += xDelta;
y -= yDelta;
}
} else {
/* multiple runs necessary; start at bottom right, iterate up to
top left */
i = 0;
while (i < cWnd) {
/* even run */
x = ((SHORT)rc. xLeft) + (cMaxWnd-1) * xDelta;
y = ((SHORT)rc. yTop) - yEdge - (cMaxWnd-1) * yDelta;
for (j = 0; j < cMaxWnd; j++) {
aswp[i].x = x;
aswp[i].y = y;
aswp[i].cx = xEdge;
aswp[i].cy = yEdge;
aswp[i].fs = SWP_SIZE | SWP_MOVE;
x -= xDelta;
y += yDelta;
if (++i >= cWnd)
break;
}
if (i >= cWnd)
break;
/* odd run, offset by half delta y, one and one half delta x */
x = ((SHORT)rc. xLeft) + (cMaxWnd-1) * xDelta + xDelta/2;
y = ((SHORT)rc. yTop) - yEdge - (cMaxWnd-1) * yDelta + yDelta/2;
for (j = 0; j < cMaxWnd - 1; j++) {
aswp[i].x = x;
aswp[i].y = y;
aswp[i].cx = xEdge;
aswp[i].cy = yEdge;
aswp[i].fs = SWP_SIZE | SWP_MOVE;
x -= xDelta;
y += yDelta;
if (++i >= cWnd)
break;
}
}
}
return TRUE;
}
/***************************************************************************\
* SetCascadeParams
*
* This function sets parameters for cascading windows. The window edges
* are based on a fraction CASC_EDGE_NUM/CASC_EDGE_DENOM of the rectangle.
* The x delta is four system font characters across, the y delta is two
* system lines high.
*
* Parameters:
* prc: rectangle to contain the windows
* pxEdge: width of the cascaded windows
* pyEdge: height of the cascaded windows
* pxDelta: x cascade offset
* pyDelta: y cascade offset
* pcMaxWnd: maximum number of windows in a cascade
\***************************************************************************/
BOOL SetCascadeParams(PRECTL prc, SHORT *pxEdge, SHORT *pyEdge, SHORT *pxDelta,
SHORT *pyDelta, SHORT *pcMaxWnd)
{
register SHORT xEdge, yEdge;
SHORT xDelta, yDelta;
SHORT cMaxWnd;
/* get x and y deltas from system values */
xDelta = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER)) +
LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CXMINMAXBUTTON)) / 2 + 2;
yDelta = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER)) +
LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR))
- cyBorder;
/* get initial cut at yEdge using fraction */
yEdge = (((SHORT)(prc->yTop - prc->yBottom)) * CASC_EDGE_NUM) /
CASC_EDGE_DENOM;
/* determine maximum number of deltas used per run */
cMaxWnd = (((SHORT)(prc->yTop - prc->yBottom)) - yEdge) / yDelta;
/* set x and y edges so full cascade will fill rectangle completely */
xEdge = ((SHORT)(prc->xRight - prc->xLeft)) - xDelta/2 - cMaxWnd * xDelta;
yEdge = ((SHORT)(prc->yTop - prc->yBottom)) - cMaxWnd * yDelta;
/* check that values are reasonable */
if (cMaxWnd < 1 || xEdge < 1 || yEdge < 1) {
return FALSE;
}
*pxEdge = xEdge;
*pyEdge = yEdge;
*pxDelta = xDelta;
*pyDelta = yDelta;
/* return cMaxWnd as the maximum number of windows in a cascade */
*pcMaxWnd = cMaxWnd + 1;
return TRUE;
}
/***************************************************************************\
* ArrangeWindows
*
* This function arranges application document windows.
*
* Returns:
* TRUE if successful
* FALSE otherwise
\***************************************************************************/
BOOL ArrangeWindows(USHORT fStyle)
{
USHORT cswpWnd, cswpIcon;
RECTL rcl;
register BOOL fReturn = FALSE;
SWP *npswpWnd, *npswpIcon;
npswpWnd = (SWP *)WinAllocMem(hHeap, sizeof(SWP) * cDocs);
npswpIcon = (SWP *)WinAllocMem(hHeap, sizeof(SWP) * cDocs);
GetArrangeSwp(&cswpWnd, npswpWnd, &cswpIcon, npswpIcon);
GetArrangeRectangle((PRECTL)&rcl, (BOOL)cswpIcon);
/* set window positions */
if (!ArrangeWindowPositions((PRECTL)&rcl, cswpWnd, (PSWP)npswpWnd, fStyle) ||
!ArrangeIconPositions(cswpIcon, (PSWP)npswpIcon)) {
goto ARRANGE_CLEANUP;
}
/* rearrange the windows */
WinSetMultWindowPos(NULL, (PSWP)npswpWnd, cswpWnd);
WinSetMultWindowPos(NULL, (PSWP)npswpIcon, cswpIcon);
fReturn = TRUE;
ARRANGE_CLEANUP:
WinFreeMem(hHeap, (NPBYTE)npswpWnd, sizeof(SWP) * cDocs);
WinFreeMem(hHeap, (NPBYTE)npswpIcon, sizeof(SWP) * cDocs);
return fReturn;
}
/***************************************************************************\
* GetArrangeHandles
*
* This function generates the handles of all windows to be arranged and
* creates an array of SWP structures containing those handles. Minimized
* and non-minimized windows are separated. Non-frame, invisible and
* non-sizeable windows are ignored.
*
* Parameter:
* npcswpWnd: number of nonminimized windows found
* npswpWnd: array of SWP structures for nonminimized windows
* npcswpIcon: number of minimized windows found
* npswpIcon: array of SWP structures for minimized windows
*
* Returns:
* TRUE if successful
* FALSE otherwise
\***************************************************************************/
BOOL GetArrangeSwp(USHORT *npcswpWnd, SWP *npswpWnd, USHORT *npcswpIcon,
SWP *npswpIcon)
{
register USHORT cWnd, cIcon;
ULONG ulStyle;
HWND hwnd;
cWnd = 0;
cIcon = 0;
/* enumerate windows and selectively add them to the arrange lists */
for (hwnd = WinQueryWindow(hwndMDI, QW_TOP, FALSE);
hwnd;
hwnd = WinQueryWindow(hwnd, QW_NEXT, FALSE)) {
/* make sure the window is visible and owned by the app client window */
ulStyle = WinQueryWindowULong(hwnd, QWL_STYLE);
if (WinQueryWindow(hwnd, QW_OWNER, FALSE) ||
!(ulStyle & WS_VISIBLE)) {
continue;
}
if (ulStyle & WS_MINIMIZED) {
npswpIcon->hwnd = hwnd;
npswpIcon++;
cIcon++;
} else {
/* restore maximized windows */
if (ulStyle & WS_MAXIMIZED)
WinSetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_RESTORE);
npswpWnd->hwnd = hwnd;
npswpWnd++;
cWnd++;
}
}
*npcswpWnd = cWnd;
*npcswpIcon = cIcon;
return TRUE;
}
/***************************************************************************\
* GetArrangeRectangle
*
* This function determines the area in which task windows are arranged.
*
* Parameter:
* prc: the generated area rectangle
* fIconPark: specifies if room should be made for icon parking lot
*
* Returns:
* TRUE if successful
* FALSE otherwise
\***************************************************************************/
BOOL GetArrangeRectangle(PRECTL prc, BOOL fIconPark)
{
register USHORT yIcon;
register SHORT cxBorderInset;
/* get dimensions of desktop window */
WinQueryWindowRect(hwndMDI, prc);
cxBorderInset = (SHORT)(WinQuerySysValue(HWND_DESKTOP, SV_CXBYTEALIGN) -
WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER));
WinInflateRect(NULL, prc, -cxBorderInset, -cxBorderInset *
(cyBorder / cxBorder));
if (fIconPark) {
/* make room for single row of icon carpark */
yIcon = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CYICON));
prc->yBottom += (yIcon * ICON_PARK_NUM) / ICON_PARK_DENOM;
}
return TRUE;
}
/***************************************************************************\
* ArrangeIconPositions
*
* This function sets positions for minimized windows.
*
* Parameters:
* cIcon: number of icons to position
* aswp: array of SetWindowPos structures for those icons
*
* Returns:
* TRUE if successful
* FALSE otherwise
\***************************************************************************/
BOOL ArrangeIconPositions(USHORT cIcon, PSWP aswpIcon)
{
register USHORT i;
for (i = 0; i < cIcon; i++) {
aswpIcon[i].x = 0;
aswpIcon[i].y = 0;
aswpIcon[i].fs = SWP_MOVE;
}
return TRUE;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.