File:  [OS/2 SDKs] / pmsdk / samples / mdi / arrange.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:28:20 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: pmsdk-1989, HEAD
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;
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.