|
|
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.