Annotation of pmsdk/samples/mdi/arrange.c, revision 1.1.1.1

1.1       root        1: /***************************************************************************\
                      2: * ARRANGE.c - This file contains code to do window arrangment.
                      3: *
                      4: * Created by Microsoft Corporation, 1989
                      5: \***************************************************************************/
                      6: 
                      7: #define INCL_WINSYS
                      8: #define INCL_WINCOMMON
                      9: #define INCL_WINMESSAGEMGR
                     10: #define INCL_WINPOINTERS
                     11: #define INCL_WININPUT
                     12: #define INCL_WINMENUS
                     13: #define INCL_WINFRAMEMGR
                     14: #define INCL_WINWINDOWMGR
                     15: #define INCL_WINRECTANGLES
                     16: #define INCL_WINHEAP
                     17: #include <os2.h>
                     18: #include "app.h"
                     19: #include "appdata.h"
                     20: #include "mdi.h"
                     21: #include "mdidata.h"
                     22: 
                     23: 
                     24: /* internal function prototypes */
                     25: BOOL SetTilePositions(PRECTL prc, SHORT cWnd, PSWP aswp);
                     26: SHORT CeilSquareRoot(USHORT us);
                     27: BOOL SetCascadePositions(PRECTL prc, SHORT cWnd, PSWP aswp);
                     28: BOOL SetCascadeParams(PRECTL prc, SHORT *pxEdge, SHORT *pyEdge,
                     29:                       SHORT *pxDelta, SHORT *pyDelta, SHORT *cMaxWnd);
                     30: BOOL GetArrangeSwp(USHORT *, SWP *, USHORT *, SWP *);
                     31: BOOL GetArrangeRectangle(PRECTL, BOOL);
                     32: BOOL ArrangeIconPositions(USHORT, PSWP);
                     33: 
                     34: /* internal constants */
                     35: #define CASC_EDGE_NUM       2
                     36: #define CASC_EDGE_DENOM     3
                     37: 
                     38: /* local constants */
                     39: #define ICON_PARK_NUM       5
                     40: #define ICON_PARK_DENOM     3
                     41: #define CLASS_NAME_LENGTH   8
                     42: 
                     43: /***************************************************************************\
                     44: * ArrangeWindowPositions
                     45: *
                     46: * This function sets positions for arranging windows nicely in a rectangle.
                     47: * The hwnd field of each SWP structure should be set by the user, either
                     48: * before or after calling this function.  The function sets all other
                     49: * fields.  The SWP array can then be passed to WinSetMultWindowPos() to do
                     50: * the physical arrangement.  There are two arrangement styles available,
                     51: * AWP_TILED and AWP_CASCADED.
                     52: *
                     53: * AWP_TILED:
                     54: *
                     55: * The tiles are generated by rows, top left (first) to bottom right (last).
                     56: * Each row has the same number of tiles.  The number of tiles in each
                     57: * column will differ by at most one, with each column containing one fewer
                     58: * tile to the left of the other columns.
                     59: *
                     60: * AWP_CASCADED:
                     61: *
                     62: * The windows are generated bottom right (first) to top left (last).
                     63: *
                     64: * Parameters:
                     65: *   prc:    rectangle to contain the tiled windows
                     66: *   cWnd:   number of windows to tile
                     67: *   aswp:   array of SWP structures, one for each tile window
                     68: *   fStyle: the style to arrange the windows
                     69: \***************************************************************************/
                     70: 
                     71: BOOL ArrangeWindowPositions(PRECTL prc, SHORT cWnd, PSWP aswp, USHORT fStyle)
                     72: {
                     73:     /* check validity of input rectangle */
                     74:     if ((prc->xRight - prc->xLeft < 1) || (prc->yTop - prc->yBottom < 1)) {
                     75:         return FALSE;
                     76:     }
                     77: 
                     78:     /* set window positions */
                     79:     switch (fStyle) {
                     80:     case AWP_TILED:
                     81:         return SetTilePositions(prc, cWnd, aswp);
                     82:     case AWP_CASCADED:
                     83:         return SetCascadePositions(prc, cWnd, aswp);
                     84:     default:
                     85:         return FALSE;
                     86:     }
                     87: }
                     88: 
                     89: 
                     90: /***************************************************************************\
                     91: * SetTilePositions
                     92: *
                     93: * This function sets positions for tiling windows in a rectangle.
                     94: *
                     95: * NOTE:
                     96: *   There are a few subtleties to this code:
                     97: *
                     98: *   The algorithm lays tiles in a modified NxN grid.  It can be shown
                     99: *   that any positive number of tiles can be laid out in such a grid of
                    100: *   N columns so that each column has at least N-2 tiles and no column
                    101: *   has more than one tile more than any other.  Proof left to the
                    102: *   interested reader.
                    103: *
                    104: *   The tiles coordinates are not generated by stepping over a fixed
                    105: *   interval since this will not usually fill the rectangle completely.
                    106: *   Thus the offset at each step is calculated from the previous tile
                    107: *   to the correct fractional position within the whole rectangle.
                    108: *
                    109: *   Since the last "row" of tiles may not have any members in the beginning
                    110: *   columns, these tiles are addressed differently in the SWP array to
                    111: *   account for the "missing" tiles.
                    112: *
                    113: * Parameters:
                    114: *   prc:        rectangle to contain the tiled windows
                    115: *   cWnd:        number of windows to tile the rectangle with
                    116: *   aswp:        array of SWP structures, one for each tile window
                    117: \***************************************************************************/
                    118: 
                    119: BOOL SetTilePositions(PRECTL prc, SHORT cWnd, PSWP aswp)
                    120: {
                    121:     register SHORT usRoot;
                    122:     register SHORT cExtras;
                    123:     SHORT iChange;
                    124:     SHORT cDiff;
                    125:     SHORT x, y, cx, cy;
                    126:     SHORT iRow, iCol;
                    127: 
                    128:     /* get grid dimensions */
                    129:     usRoot = CeilSquareRoot(cWnd);
                    130:     cExtras = usRoot * usRoot - cWnd;
                    131: 
                    132:     /* find column where number of rows increases and find initial
                    133:        difference of rows versus columns */
                    134:     if (cExtras >= usRoot) {
                    135:         iChange = cExtras - usRoot;
                    136:         cDiff = 2;
                    137:     } else {
                    138:         iChange = cExtras;
                    139:         cDiff = 1;
                    140:     }
                    141: 
                    142:     /* assign x coordinates */
                    143:     x = (SHORT)prc->xLeft;
                    144:     cx = 0;
                    145:     for (iCol = 0; iCol < usRoot; iCol++) {
                    146:         x += cx - cxBorder;
                    147:         cx = ((SHORT)prc->xLeft) +
                    148:              (((SHORT)(prc->xRight - prc->xLeft)) * (iCol + 1)) / usRoot -
                    149:              x + cxBorder;
                    150:         for (iRow = 0; iRow < usRoot - cDiff; iRow++) {
                    151:             aswp[iRow * usRoot + iCol].x = x;
                    152:             aswp[iRow * usRoot + iCol].cx = cx;
                    153:             aswp[iRow * usRoot + iCol].fs = SWP_SIZE | SWP_MOVE;
                    154:         }
                    155:         /* assign "extra" row */
                    156:         if (iCol >= iChange) {
                    157:             aswp[iRow * usRoot + iCol - iChange].x = x;
                    158:             aswp[iRow * usRoot + iCol - iChange].cx = cx;
                    159:             aswp[iRow * usRoot + iCol - iChange].fs = SWP_SIZE | SWP_MOVE;
                    160:         }
                    161:     }
                    162: 
                    163:     /* assign y coordinates, columns without extra row */
                    164:     y = (SHORT)prc->yBottom;
                    165:     cy = 0;
                    166:     for (iRow = usRoot - cDiff - 1; iRow >= 0; iRow--) {
                    167:         y += cy - cyBorder;
                    168:         cy = ((SHORT)prc->yBottom) +
                    169:              (((SHORT)(prc->yTop - prc->yBottom)) * (usRoot - cDiff - iRow)) /
                    170:                 (usRoot - cDiff) - y + cyBorder;
                    171:         for (iCol = 0; iCol < iChange; iCol++) {
                    172:             aswp[iRow * usRoot + iCol].y = y;
                    173:             aswp[iRow * usRoot + iCol].cy = cy;
                    174:         }
                    175:     }
                    176: 
                    177:     /* assign y coordinates, columns with extra row */
                    178:     /* do last row first (different offsets) */
                    179:     y = (SHORT)prc->yBottom - cyBorder;
                    180:     cy = ((SHORT)(prc->yTop - prc->yBottom)) / (usRoot - cDiff + 1) +
                    181:          2 * cyBorder;
                    182:     for (iCol = iChange; iCol < usRoot; iCol++) {
                    183:         aswp[usRoot * (usRoot - cDiff) + iCol - iChange].y = y;
                    184:         aswp[usRoot * (usRoot - cDiff) + iCol - iChange].cy = cy;
                    185:     }
                    186:     for (iRow = usRoot - cDiff - 1; iRow >= 0; iRow--) {
                    187:         y += cy - cyBorder;
                    188:         cy = ((SHORT)(prc->yBottom)) +
                    189:                 (((SHORT)(prc->yTop - prc->yBottom)) * (usRoot - cDiff - iRow + 1))
                    190:                 / (usRoot - cDiff + 1) - y + cyBorder;
                    191:         for (iCol = iChange; iCol < usRoot; iCol++) {
                    192:             aswp[iRow * usRoot + iCol].y = y;
                    193:             aswp[iRow * usRoot + iCol].cy = cy;
                    194:         }
                    195:     }
                    196: 
                    197:     return TRUE;
                    198: }
                    199: 
                    200: 
                    201: /***************************************************************************\
                    202: * CeilSquareRoot
                    203: *
                    204: * This function returns the smallest integer greater or equal to the square
                    205: * root of an unsigned 16 bit integer.
                    206: *
                    207: * Parameter:
                    208: *   us: value to take the root of
                    209: \***************************************************************************/
                    210: 
                    211: SHORT CeilSquareRoot(register USHORT us)
                    212: {
                    213:     register SHORT i;
                    214: 
                    215:     /* prevent overflow of large numbers */
                    216:     if (us > 0xFE * 0xFE)
                    217:         return 0xFF;
                    218: 
                    219:     /* iterate up past root */
                    220:     for (i = 0; i*i < us; i++)
                    221:         ;
                    222:     return i;
                    223: }
                    224: 
                    225: 
                    226: /***************************************************************************\
                    227: * SetCascadePositions
                    228: *
                    229: * This function sets positions for cascading windows in a rectangle.
                    230: *
                    231: * Parameters:
                    232: *   prc:        rectangle to contain the cascaded windows
                    233: *   cWnd:        number of windows to cascade
                    234: *   aswp:        array of SWP structures, one for each cascaded window
                    235: \***************************************************************************/
                    236: 
                    237: BOOL SetCascadePositions(PRECTL prc, SHORT cWnd, PSWP aswp)
                    238: {
                    239:     SHORT xEdge, yEdge;
                    240:     SHORT xDelta, yDelta;
                    241:     SHORT cMaxWnd;
                    242:     register SHORT x, y;
                    243:     SHORT i, j;
                    244:     RECTL rc;
                    245: 
                    246:     /* set cascade parameters */
                    247:     rc.xLeft = prc->xLeft - cxBorder;
                    248:     rc.xRight = prc->xRight + cyBorder;
                    249:     rc.yBottom = prc->yBottom - cyBorder;
                    250:     rc.yTop = prc->yTop + cyBorder;
                    251:     if (!SetCascadeParams((PRECTL)&rc, &xEdge, &yEdge, &xDelta, &yDelta,
                    252:                           &cMaxWnd)) {
                    253:         return FALSE;
                    254:     }
                    255: 
                    256:     if (cWnd <= cMaxWnd) {
                    257:         /* only one run needed; move to top left corner */
                    258:         x = (SHORT)rc. xLeft;
                    259:         y = (SHORT)rc. yTop - yEdge;
                    260:         for (i = cWnd - 1; i >= 0; i--) {
                    261:             aswp[i].x = x;
                    262:             aswp[i].y = y;
                    263:             aswp[i].cx = xEdge;
                    264:             aswp[i].cy = yEdge;
                    265:             aswp[i].fs = SWP_SIZE | SWP_MOVE;
                    266:             x += xDelta;
                    267:             y -= yDelta;
                    268:         }
                    269: 
                    270:     } else {
                    271: 
                    272:         /* multiple runs necessary; start at bottom right, iterate up to
                    273:            top left */
                    274: 
                    275:         i = 0;
                    276: 
                    277:         while (i < cWnd) {
                    278: 
                    279:             /* even run */
                    280:             x = ((SHORT)rc. xLeft) + (cMaxWnd-1) * xDelta;
                    281:             y = ((SHORT)rc. yTop) - yEdge - (cMaxWnd-1) * yDelta;
                    282:             for (j = 0; j < cMaxWnd; j++) {
                    283:                 aswp[i].x = x;
                    284:                 aswp[i].y = y;
                    285:                 aswp[i].cx = xEdge;
                    286:                 aswp[i].cy = yEdge;
                    287:                 aswp[i].fs = SWP_SIZE | SWP_MOVE;
                    288:                 x -= xDelta;
                    289:                 y += yDelta;
                    290:                 if (++i >= cWnd)
                    291:                     break;
                    292:             }
                    293: 
                    294:             if (i >= cWnd)
                    295:                 break;
                    296: 
                    297:             /* odd run, offset by half delta y, one and one half delta x */
                    298:             x = ((SHORT)rc. xLeft) + (cMaxWnd-1) * xDelta + xDelta/2;
                    299:             y = ((SHORT)rc. yTop) - yEdge - (cMaxWnd-1) * yDelta + yDelta/2;
                    300:             for (j = 0; j < cMaxWnd - 1; j++) {
                    301:                 aswp[i].x = x;
                    302:                 aswp[i].y = y;
                    303:                 aswp[i].cx = xEdge;
                    304:                 aswp[i].cy = yEdge;
                    305:                 aswp[i].fs = SWP_SIZE | SWP_MOVE;
                    306:                 x -= xDelta;
                    307:                 y += yDelta;
                    308:                 if (++i >= cWnd)
                    309:                     break;
                    310:             }
                    311:         }
                    312:     }
                    313: 
                    314:     return TRUE;
                    315: }
                    316: 
                    317: 
                    318: /***************************************************************************\
                    319: * SetCascadeParams
                    320: *
                    321: * This function sets parameters for cascading windows.        The window edges
                    322: * are based on a fraction CASC_EDGE_NUM/CASC_EDGE_DENOM of the rectangle.
                    323: * The x delta is four system font characters across, the y delta is two
                    324: * system lines high.
                    325: *
                    326: * Parameters:
                    327: *   prc:        rectangle to contain the windows
                    328: *   pxEdge:        width of the cascaded windows
                    329: *   pyEdge:        height of the cascaded windows
                    330: *   pxDelta:        x cascade offset
                    331: *   pyDelta:        y cascade offset
                    332: *   pcMaxWnd:        maximum number of windows in a cascade
                    333: \***************************************************************************/
                    334: 
                    335: BOOL SetCascadeParams(PRECTL prc, SHORT *pxEdge, SHORT *pyEdge, SHORT *pxDelta,
                    336:         SHORT *pyDelta, SHORT *pcMaxWnd)
                    337: {
                    338:     register SHORT xEdge, yEdge;
                    339:     SHORT xDelta, yDelta;
                    340:     SHORT cMaxWnd;
                    341: 
                    342:     /* get x and y deltas from system values */
                    343:     xDelta = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER)) +
                    344:              LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CXMINMAXBUTTON)) / 2 + 2;
                    345:     yDelta = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER)) +
                    346:              LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR))
                    347:              - cyBorder;
                    348: 
                    349:     /* get initial cut at yEdge using fraction */
                    350:     yEdge = (((SHORT)(prc->yTop - prc->yBottom)) * CASC_EDGE_NUM) /
                    351:             CASC_EDGE_DENOM;
                    352: 
                    353:     /* determine maximum number of deltas used per run */
                    354:     cMaxWnd = (((SHORT)(prc->yTop - prc->yBottom)) - yEdge) / yDelta;
                    355: 
                    356:     /* set x and y edges so full cascade will fill rectangle completely */
                    357:     xEdge = ((SHORT)(prc->xRight - prc->xLeft)) - xDelta/2 - cMaxWnd * xDelta;
                    358:     yEdge = ((SHORT)(prc->yTop - prc->yBottom)) - cMaxWnd * yDelta;
                    359: 
                    360:     /* check that values are reasonable */
                    361:     if (cMaxWnd < 1 || xEdge < 1 || yEdge < 1) {
                    362:         return FALSE;
                    363:     }
                    364: 
                    365:     *pxEdge = xEdge;
                    366:     *pyEdge = yEdge;
                    367:     *pxDelta = xDelta;
                    368:     *pyDelta = yDelta;
                    369:     /* return cMaxWnd as the maximum number of windows in a cascade */
                    370:     *pcMaxWnd = cMaxWnd + 1;
                    371: 
                    372:     return TRUE;
                    373: }
                    374: 
                    375: 
                    376: /***************************************************************************\
                    377: * ArrangeWindows
                    378: *
                    379: * This function arranges application document windows.
                    380: *
                    381: * Returns:
                    382: *   TRUE if successful
                    383: *   FALSE otherwise
                    384: \***************************************************************************/
                    385: 
                    386: BOOL ArrangeWindows(USHORT fStyle)
                    387: {
                    388:     USHORT cswpWnd, cswpIcon;
                    389:     RECTL rcl;
                    390:     register BOOL fReturn = FALSE;
                    391:     SWP *npswpWnd, *npswpIcon;
                    392: 
                    393:     npswpWnd = (SWP *)WinAllocMem(hHeap, sizeof(SWP) * cDocs);
                    394:     npswpIcon = (SWP *)WinAllocMem(hHeap, sizeof(SWP) * cDocs);
                    395: 
                    396:     GetArrangeSwp(&cswpWnd, npswpWnd, &cswpIcon, npswpIcon);
                    397: 
                    398:     GetArrangeRectangle((PRECTL)&rcl, (BOOL)cswpIcon);
                    399: 
                    400:     /* set window positions */
                    401:     if (!ArrangeWindowPositions((PRECTL)&rcl, cswpWnd, (PSWP)npswpWnd, fStyle) ||
                    402:         !ArrangeIconPositions(cswpIcon, (PSWP)npswpIcon)) {
                    403:         goto ARRANGE_CLEANUP;
                    404:     }
                    405: 
                    406:     /* rearrange the windows */
                    407:     WinSetMultWindowPos(NULL, (PSWP)npswpWnd, cswpWnd);
                    408:     WinSetMultWindowPos(NULL, (PSWP)npswpIcon, cswpIcon);
                    409:     fReturn = TRUE;
                    410: 
                    411: ARRANGE_CLEANUP:
                    412:     WinFreeMem(hHeap, (NPBYTE)npswpWnd, sizeof(SWP) * cDocs);
                    413:     WinFreeMem(hHeap, (NPBYTE)npswpIcon, sizeof(SWP) * cDocs);
                    414: 
                    415:     return fReturn;
                    416: }
                    417: 
                    418: /***************************************************************************\
                    419: * GetArrangeHandles
                    420: *
                    421: * This function generates the handles of all windows to be arranged and
                    422: * creates an array of SWP structures containing those handles.  Minimized
                    423: * and non-minimized windows are separated.  Non-frame, invisible and
                    424: * non-sizeable windows are ignored.
                    425: *
                    426: * Parameter:
                    427: *   npcswpWnd:        number of nonminimized windows found
                    428: *   npswpWnd:         array of SWP structures for nonminimized windows
                    429: *   npcswpIcon:       number of minimized windows found
                    430: *   npswpIcon:        array of SWP structures for minimized windows
                    431: *
                    432: * Returns:
                    433: *   TRUE if successful
                    434: *   FALSE otherwise
                    435: \***************************************************************************/
                    436: 
                    437: BOOL GetArrangeSwp(USHORT *npcswpWnd, SWP *npswpWnd, USHORT *npcswpIcon,
                    438:         SWP *npswpIcon)
                    439: {
                    440:     register USHORT cWnd, cIcon;
                    441:     ULONG ulStyle;
                    442:     HWND hwnd;
                    443: 
                    444:     cWnd = 0;
                    445:     cIcon = 0;
                    446: 
                    447:     /* enumerate windows and selectively add them to the arrange lists */
                    448:     for (hwnd = WinQueryWindow(hwndMDI, QW_TOP, FALSE);
                    449:          hwnd;
                    450:          hwnd = WinQueryWindow(hwnd, QW_NEXT, FALSE)) {
                    451: 
                    452:         /* make sure the window is visible and owned by the app client window */
                    453:         ulStyle = WinQueryWindowULong(hwnd, QWL_STYLE);
                    454:         if (WinQueryWindow(hwnd, QW_OWNER, FALSE) ||
                    455:             !(ulStyle & WS_VISIBLE)) {
                    456:             continue;
                    457:         }
                    458: 
                    459:         if (ulStyle & WS_MINIMIZED) {
                    460:             npswpIcon->hwnd = hwnd;
                    461:             npswpIcon++;
                    462:             cIcon++;
                    463:         } else {
                    464:             /* restore maximized windows */
                    465:             if (ulStyle & WS_MAXIMIZED)
                    466:                 WinSetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_RESTORE);
                    467: 
                    468:             npswpWnd->hwnd = hwnd;
                    469:             npswpWnd++;
                    470:             cWnd++;
                    471:         }
                    472:     }
                    473: 
                    474:     *npcswpWnd = cWnd;
                    475:     *npcswpIcon = cIcon;
                    476:     return TRUE;
                    477: }
                    478: 
                    479: 
                    480: /***************************************************************************\
                    481: * GetArrangeRectangle
                    482: *
                    483: * This function determines the area in which task windows are arranged.
                    484: *
                    485: * Parameter:
                    486: *   prc:        the generated area rectangle
                    487: *   fIconPark:        specifies if room should be made for icon parking lot
                    488: *
                    489: * Returns:
                    490: *   TRUE if successful
                    491: *   FALSE otherwise
                    492: \***************************************************************************/
                    493: 
                    494: BOOL GetArrangeRectangle(PRECTL prc, BOOL fIconPark)
                    495: {
                    496:     register USHORT yIcon;
                    497:     register SHORT cxBorderInset;
                    498: 
                    499:     /* get dimensions of desktop window */
                    500:     WinQueryWindowRect(hwndMDI, prc);
                    501: 
                    502:     cxBorderInset = (SHORT)(WinQuerySysValue(HWND_DESKTOP, SV_CXBYTEALIGN) -
                    503:                        WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER));
                    504:     WinInflateRect(NULL, prc, -cxBorderInset, -cxBorderInset * 
                    505:             (cyBorder / cxBorder));
                    506: 
                    507:     if (fIconPark) {
                    508:         /* make room for single row of icon carpark */
                    509:         yIcon = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CYICON));
                    510:         prc->yBottom += (yIcon * ICON_PARK_NUM) / ICON_PARK_DENOM;
                    511:     }
                    512: 
                    513:     return TRUE;
                    514: }
                    515: 
                    516: /***************************************************************************\
                    517: * ArrangeIconPositions
                    518: *
                    519: * This function sets positions for minimized windows.
                    520: *
                    521: * Parameters:
                    522: *   cIcon:        number of icons to position
                    523: *   aswp:        array of SetWindowPos structures for those icons
                    524: *
                    525: * Returns:
                    526: *   TRUE if successful
                    527: *   FALSE otherwise
                    528: \***************************************************************************/
                    529: 
                    530: BOOL ArrangeIconPositions(USHORT cIcon, PSWP aswpIcon)
                    531: {
                    532:     register USHORT i;
                    533: 
                    534:     for (i = 0; i < cIcon; i++) {
                    535:         aswpIcon[i].x = 0;
                    536:         aswpIcon[i].y = 0;
                    537:         aswpIcon[i].fs = SWP_MOVE;
                    538:     }
                    539: 
                    540:     return TRUE;
                    541: }
                    542: 

unix.superglobalmegacorp.com

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