home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / mdi / arrange.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-06  |  18.1 KB  |  566 lines

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