home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk11 / tk4 / mdi / arrange.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-20  |  17.3 KB  |  543 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. /* 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.  
  543.