|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.