|
|
1.1 root 1: /*
2: * tkPlace.c --
3: *
4: * This file contains code to implement a simple geometry manager
5: * for Tk based on absolute placement or "rubber-sheet" placement.
6: *
7: * Copyright 1992 Regents of the University of California
8: * Permission to use, copy, modify, and distribute this
9: * software and its documentation for any purpose and without
10: * fee is hereby granted, provided that this copyright
11: * notice appears in all copies. The University of California
12: * makes no representations about the suitability of this
13: * software for any purpose. It is provided "as is" without
14: * express or implied warranty.
15: */
16:
17: #ifndef lint
18: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkPlace.c,v 1.6 92/06/10 08:59:28 ouster Exp $ SPRITE (Berkeley)";
19: #endif /* not lint */
20:
21: #include "tkconfig.h"
22: #include "tkint.h"
23:
24: /*
25: * Border modes for relative placement:
26: *
27: * BM_INSIDE: relative distances computed using area inside
28: * all borders of master window.
29: * BM_OUTSIDE: relative distances computed using outside area
30: * that includes all borders of master.
31: * BM_IGNORE: border issues are ignored: place relative to
32: * master's actual window size.
33: */
34:
35: typedef enum {BM_INSIDE, BM_OUTSIDE, BM_IGNORE} BorderMode;
36:
37: /*
38: * For each window whose geometry is managed by the placer there is
39: * a structure of the following type:
40: */
41:
42: typedef struct Slave {
43: Tk_Window tkwin; /* Tk's token for window. */
44: struct Master *masterPtr; /* Pointer to information for window
45: * relative to which tkwin is placed.
46: * This isn't necessarily the logical
47: * parent of tkwin. NULL means the
48: * master was deleted or never assigned. */
49: struct Slave *nextPtr; /* Next in list of windows placed relative
50: * to same master (NULL for end of list). */
51:
52: /*
53: * Geometry information for window; where there are both relative
54: * and absolute values for the same attribute (e.g. x and relX) only
55: * one of them is actually used, depending on flags.
56: */
57:
58: int x, y; /* X and Y pixel coordinates for tkwin. */
59: float relX, relY; /* X and Y coordinates relative to size of
60: * master. */
61: int width, height; /* Absolute dimensions for tkwin. */
62: float relWidth, relHeight; /* Dimensions for tkwin relative to size of
63: * master. */
64: Tk_Anchor anchor; /* Which point on tkwin is placed at the
65: * given position. */
66: BorderMode borderMode; /* How to treat borders of master window. */
67: int flags; /* Various flags; see below for bit
68: * definitions. */
69: } Slave;
70:
71: /*
72: * Flag definitions for Slave structures:
73: *
74: * CHILD_REL_X - 1 means use relX field; 0 means use x.
75: * CHILD_REL_Y - 1 means use relY field; 0 means use y;
76: * CHILD_WIDTH - 1 means use width field;
77: * CHILD_REL_WIDTH - 1 means use relWidth; if neither this nor
78: * CHILD_WIDTH is 1, use window's requested
79: * width.
80: * CHILD_HEIGHT - 1 means use height field;
81: * CHILD_REL_HEIGHT - 1 means use relHeight; if neither this nor
82: * CHILD_HEIGHT is 1, use window's requested
83: * height.
84: */
85:
86: #define CHILD_REL_X 1
87: #define CHILD_REL_Y 2
88: #define CHILD_WIDTH 4
89: #define CHILD_REL_WIDTH 8
90: #define CHILD_HEIGHT 0x10
91: #define CHILD_REL_HEIGHT 0x20
92:
93: /*
94: * For each master window that has a slave managed by the placer there
95: * is a structure of the following form:
96: */
97:
98: typedef struct Master {
99: Tk_Window tkwin; /* Tk's token for master window. */
100: struct Slave *slavePtr; /* First in linked list of slaves
101: * placed relative to this master. */
102: int flags; /* See below for bit definitions. */
103: } Master;
104:
105: /*
106: * Flag definitions for masters:
107: *
108: * PARENT_RECONFIG_PENDING - 1 means that a call to RecomputePlacement
109: * is already pending via a Do_When_Idle handler.
110: */
111:
112: #define PARENT_RECONFIG_PENDING 1
113:
114: /*
115: * The hash tables below both use Tk_Window tokens as keys. They map
116: * from Tk_Windows to Slave and Master structures for windows, if they
117: * exist.
118: */
119:
120: static int initialized = 0;
121: static Tcl_HashTable masterTable;
122: static Tcl_HashTable slaveTable;
123:
124: /*
125: * Forward declarations for procedures defined later in this file:
126: */
127:
128: static void SlaveStructureProc _ANSI_ARGS_((ClientData clientData,
129: XEvent *eventPtr));
130: static int ConfigureSlave _ANSI_ARGS_((Tcl_Interp *interp,
131: Slave *slavePtr, int argc, char **argv));
132: static Slave * FindSlave _ANSI_ARGS_((Tk_Window tkwin));
133: static Master * FindMaster _ANSI_ARGS_((Tk_Window tkwin));
134: static void MasterStructureProc _ANSI_ARGS_((ClientData clientData,
135: XEvent *eventPtr));
136: static void PlaceRequestProc _ANSI_ARGS_((ClientData clientData,
137: Tk_Window tkwin));
138: static void RecomputePlacement _ANSI_ARGS_((ClientData clientData));
139: static void UnlinkSlave _ANSI_ARGS_((Slave *slavePtr));
140:
141: /*
142: *--------------------------------------------------------------
143: *
144: * Tk_PlaceCmd --
145: *
146: * This procedure is invoked to process the "place" Tcl
147: * commands. See the user documentation for details on
148: * what it does.
149: *
150: * Results:
151: * A standard Tcl result.
152: *
153: * Side effects:
154: * See the user documentation.
155: *
156: *--------------------------------------------------------------
157: */
158:
159: int
160: Tk_PlaceCmd(clientData, interp, argc, argv)
161: ClientData clientData; /* Main window associated with interpreter. */
162: Tcl_Interp *interp; /* Current interpreter. */
163: int argc; /* Number of arguments. */
164: char **argv; /* Argument strings. */
165: {
166: Tk_Window tkwin;
167: Slave *slavePtr;
168: Tcl_HashEntry *hPtr;
169: int length;
170: char c;
171:
172: /*
173: * Initialize, if that hasn't been done yet.
174: */
175:
176: if (!initialized) {
177: Tcl_InitHashTable(&masterTable, TCL_ONE_WORD_KEYS);
178: Tcl_InitHashTable(&slaveTable, TCL_ONE_WORD_KEYS);
179: initialized = 1;
180: }
181:
182: if (argc < 3) {
183: Tcl_AppendResult(interp, "wrong # args: should be \"",
184: argv[0], " option|pathName args", (char *) NULL);
185: return TCL_ERROR;
186: }
187: c = argv[1][0];
188: length = strlen(argv[1]);
189:
190: /*
191: * Handle special shortcut where window name is first argument.
192: */
193:
194: if (c == '.') {
195: tkwin = Tk_NameToWindow(interp, argv[1], (Tk_Window) clientData);
196: if (tkwin == NULL) {
197: return TCL_ERROR;
198: }
199: slavePtr = FindSlave(tkwin);
200: return ConfigureSlave(interp, slavePtr, argc-2, argv+2);
201: }
202:
203: /*
204: * Handle more general case of option followed by window name followed
205: * by possible additional arguments.
206: */
207:
208: tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);
209: if (tkwin == NULL) {
210: return TCL_ERROR;
211: }
212: if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
213: if (argc < 5) {
214: Tcl_AppendResult(interp, "wrong # args: should be \"",
215: argv[0],
216: " configure pathName option value ?option value ...?\"",
217: (char *) NULL);
218: return TCL_ERROR;
219: }
220: slavePtr = FindSlave(tkwin);
221: return ConfigureSlave(interp, slavePtr, argc-3, argv+3);
222: } else if ((c == 'd') && (strncmp(argv[1], "dependents", length) == 0)) {
223: if (argc != 3) {
224: Tcl_AppendResult(interp, "wrong # args: should be \"",
225: argv[0], " dependents pathName\"", (char *) NULL);
226: return TCL_ERROR;
227: }
228: hPtr = Tcl_FindHashEntry(&masterTable, (char *) tkwin);
229: if (hPtr != NULL) {
230: Master *masterPtr;
231: masterPtr = (Master *) Tcl_GetHashValue(hPtr);
232: for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
233: slavePtr = slavePtr->nextPtr) {
234: Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin), 0);
235: }
236: }
237: } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) {
238: if (argc != 3) {
239: Tcl_AppendResult(interp, "wrong # args: should be \"",
240: argv[0], " forget pathName\"", (char *) NULL);
241: return TCL_ERROR;
242: }
243: hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin);
244: if (hPtr == NULL) {
245: return TCL_OK;
246: }
247: slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
248: UnlinkSlave(slavePtr);
249: Tcl_DeleteHashEntry(hPtr);
250: Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc,
251: (ClientData) slavePtr);
252: Tk_ManageGeometry(tkwin, (Tk_GeometryProc *) NULL, (ClientData) NULL);
253: Tk_UnmapWindow(tkwin);
254: ckfree((char *) slavePtr);
255: } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
256: char buffer[50];
257:
258: if (argc != 3) {
259: Tcl_AppendResult(interp, "wrong # args: should be \"",
260: argv[0], " info pathName\"", (char *) NULL);
261: return TCL_ERROR;
262: }
263: hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin);
264: if (hPtr == NULL) {
265: return TCL_OK;
266: }
267: slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
268: if (slavePtr->flags & CHILD_REL_X) {
269: sprintf(buffer, "-relx %.4g", slavePtr->relX);
270: } else {
271: sprintf(buffer, "-x %d", slavePtr->x);
272: }
273: Tcl_AppendResult(interp, buffer, (char *) NULL);
274: if (slavePtr->flags & CHILD_REL_Y) {
275: sprintf(buffer, " -rely %.4g", slavePtr->relY);
276: } else {
277: sprintf(buffer, " -y %d", slavePtr->y);
278: }
279: Tcl_AppendResult(interp, buffer, (char *) NULL);
280: if (slavePtr->flags & CHILD_REL_WIDTH) {
281: sprintf(buffer, " -relwidth %.4g", slavePtr->relWidth);
282: Tcl_AppendResult(interp, buffer, (char *) NULL);
283: } else if (slavePtr->flags & CHILD_WIDTH) {
284: sprintf(buffer, " -width %d", slavePtr->width);
285: Tcl_AppendResult(interp, buffer, (char *) NULL);
286: }
287: if (slavePtr->flags & CHILD_REL_HEIGHT) {
288: sprintf(buffer, " -relheight %.4g", slavePtr->relHeight);
289: Tcl_AppendResult(interp, buffer, (char *) NULL);
290: } else if (slavePtr->flags & CHILD_HEIGHT) {
291: sprintf(buffer, " -height %d", slavePtr->height);
292: Tcl_AppendResult(interp, buffer, (char *) NULL);
293: }
294: Tcl_AppendResult(interp, " -anchor ", Tk_NameOfAnchor(slavePtr->anchor),
295: (char *) NULL);
296: if (slavePtr->borderMode == BM_OUTSIDE) {
297: Tcl_AppendResult(interp, " -bordermode outside", (char *) NULL);
298: } else if (slavePtr->borderMode == BM_IGNORE) {
299: Tcl_AppendResult(interp, " -bordermode ignore", (char *) NULL);
300: }
301: if ((slavePtr->masterPtr != NULL)
302: && (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin))) {
303: Tcl_AppendResult(interp, " -in ",
304: Tk_PathName(slavePtr->masterPtr->tkwin), (char *) NULL);
305: }
306: } else {
307: Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
308: "\": must be configure, dependents, forget, or info",
309: (char *) NULL);
310: return TCL_ERROR;
311: }
312: return TCL_OK;
313: }
314:
315: /*
316: *----------------------------------------------------------------------
317: *
318: * FindSlave --
319: *
320: * Given a Tk_Window token, find the Slave structure corresponding
321: * to that token (making a new one if necessary).
322: *
323: * Results:
324: * None.
325: *
326: * Side effects:
327: * A new Slave structure may be created.
328: *
329: *----------------------------------------------------------------------
330: */
331:
332: static Slave *
333: FindSlave(tkwin)
334: Tk_Window tkwin; /* Token for desired slave. */
335: {
336: Tcl_HashEntry *hPtr;
337: register Slave *slavePtr;
338: int new;
339:
340: hPtr = Tcl_CreateHashEntry(&slaveTable, (char *) tkwin, &new);
341: if (new) {
342: slavePtr = (Slave *) ckalloc(sizeof(Slave));
343: slavePtr->tkwin = tkwin;
344: slavePtr->masterPtr = NULL;
345: slavePtr->nextPtr = NULL;
346: slavePtr->x = slavePtr->y = 0;
347: slavePtr->relX = slavePtr->relY = 0.0;
348: slavePtr->width = slavePtr->height = 0;
349: slavePtr->relWidth = slavePtr->relHeight = 0.0;
350: slavePtr->anchor = TK_ANCHOR_NW;
351: slavePtr->borderMode = BM_INSIDE;
352: slavePtr->flags = 0;
353: Tcl_SetHashValue(hPtr, slavePtr);
354: Tk_CreateEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc,
355: (ClientData) slavePtr);
356: Tk_ManageGeometry(tkwin, PlaceRequestProc, (ClientData) slavePtr);
357: } else {
358: slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
359: }
360: return slavePtr;
361: }
362:
363: /*
364: *----------------------------------------------------------------------
365: *
366: * UnlinkSlave --
367: *
368: * This procedure removes a slave window from the chain of slaves
369: * in its master.
370: *
371: * Results:
372: * None.
373: *
374: * Side effects:
375: * The slave list of slavePtr's master changes.
376: *
377: *----------------------------------------------------------------------
378: */
379:
380: static void
381: UnlinkSlave(slavePtr)
382: Slave *slavePtr; /* Slave structure to be unlinked. */
383: {
384: register Master *masterPtr;
385: register Slave *prevPtr;
386:
387: masterPtr = slavePtr->masterPtr;
388: if (masterPtr == NULL) {
389: return;
390: }
391: if (masterPtr->slavePtr == slavePtr) {
392: masterPtr->slavePtr = slavePtr->nextPtr;
393: } else {
394: for (prevPtr = masterPtr->slavePtr; ;
395: prevPtr = prevPtr->nextPtr) {
396: if (prevPtr == NULL) {
397: panic("UnlinkSlave couldn't find slave to unlink");
398: }
399: if (prevPtr->nextPtr == slavePtr) {
400: prevPtr->nextPtr = slavePtr->nextPtr;
401: break;
402: }
403: }
404: }
405: slavePtr->masterPtr = NULL;
406: }
407:
408: /*
409: *----------------------------------------------------------------------
410: *
411: * FindMaster --
412: *
413: * Given a Tk_Window token, find the Master structure corresponding
414: * to that token (making a new one if necessary).
415: *
416: * Results:
417: * None.
418: *
419: * Side effects:
420: * A new Master structure may be created.
421: *
422: *----------------------------------------------------------------------
423: */
424:
425: static Master *
426: FindMaster(tkwin)
427: Tk_Window tkwin; /* Token for desired master. */
428: {
429: Tcl_HashEntry *hPtr;
430: register Master *masterPtr;
431: int new;
432:
433: hPtr = Tcl_CreateHashEntry(&masterTable, (char *) tkwin, &new);
434: if (new) {
435: masterPtr = (Master *) ckalloc(sizeof(Master));
436: masterPtr->tkwin = tkwin;
437: masterPtr->slavePtr = NULL;
438: masterPtr->flags = 0;
439: Tcl_SetHashValue(hPtr, masterPtr);
440: Tk_CreateEventHandler(masterPtr->tkwin, StructureNotifyMask,
441: MasterStructureProc, (ClientData) masterPtr);
442: } else {
443: masterPtr = (Master *) Tcl_GetHashValue(hPtr);
444: }
445: return masterPtr;
446: }
447:
448: /*
449: *----------------------------------------------------------------------
450: *
451: * ConfigureSlave --
452: *
453: * This procedure is called to process an argv/argc list to
454: * reconfigure the placement of a window.
455: *
456: * Results:
457: * A standard Tcl result. If an error occurs then a message is
458: * left in interp->result.
459: *
460: * Side effects:
461: * Information in slavePtr may change, and slavePtr's master is
462: * scheduled for reconfiguration.
463: *
464: *----------------------------------------------------------------------
465: */
466:
467: static int
468: ConfigureSlave(interp, slavePtr, argc, argv)
469: Tcl_Interp *interp; /* Used for error reporting. */
470: Slave *slavePtr; /* Pointer to current information
471: * about slave. */
472: int argc; /* Number of config arguments. */
473: char **argv; /* String values for arguments. */
474: {
475: register Master *masterPtr;
476: int c, length, result;
477: double d;
478:
479: result = TCL_OK;
480: for ( ; argc > 0; argc -= 2, argv += 2) {
481: if (argc < 2) {
482: Tcl_AppendResult(interp, "extra option \"", argv[0],
483: "\" (option with no value?)", (char *) NULL);
484: result = TCL_ERROR;
485: goto done;
486: }
487: length = strlen(argv[0]);
488: c = argv[0][1];
489: if ((c == 'a') && (strncmp(argv[0], "-anchor", length) == 0)) {
490: if (Tk_GetAnchor(interp, argv[1], &slavePtr->anchor) != TCL_OK) {
491: result = TCL_ERROR;
492: goto done;
493: }
494: } else if ((c == 'b')
495: && (strncmp(argv[0], "-bordermode", length) == 0)) {
496: c = argv[1][0];
497: length = strlen(argv[1]);
498: if ((c == 'i') && (strncmp(argv[1], "ignore", length) == 0)
499: && (length >= 2)) {
500: slavePtr->borderMode = BM_IGNORE;
501: } else if ((c == 'i') && (strncmp(argv[1], "inside", length) == 0)
502: && (length >= 2)) {
503: slavePtr->borderMode = BM_INSIDE;
504: } else if ((c == 'o')
505: && (strncmp(argv[1], "outside", length) == 0)) {
506: slavePtr->borderMode = BM_OUTSIDE;
507: } else {
508: Tcl_AppendResult(interp, "bad border mode \"", argv[1],
509: "\": must be ignore, inside, or outside",
510: (char *) NULL);
511: result = TCL_ERROR;
512: goto done;
513: }
514: } else if ((c == 'h') && (strncmp(argv[0], "-height", length) == 0)) {
515: if (argv[1][0] == 0) {
516: slavePtr->flags &= ~(CHILD_REL_HEIGHT|CHILD_HEIGHT);
517: } else {
518: if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
519: &slavePtr->height) != TCL_OK) {
520: result = TCL_ERROR;
521: goto done;
522: }
523: slavePtr->flags &= ~CHILD_REL_HEIGHT;
524: slavePtr->flags |= CHILD_HEIGHT;
525: }
526: } else if ((c == 'i') && (strncmp(argv[0], "-in", length) == 0)) {
527: Tk_Window tkwin;
528: Tk_Window ancestor;
529:
530: tkwin = Tk_NameToWindow(interp, argv[1], slavePtr->tkwin);
531: if (tkwin == NULL) {
532: result = TCL_ERROR;
533: goto done;
534: }
535:
536: /*
537: * Make sure that the new master is either the logical parent
538: * of the slave or a descendant of that window.
539: */
540:
541: for (ancestor = tkwin; ; ancestor = Tk_Parent(ancestor)) {
542: if (ancestor == Tk_Parent(slavePtr->tkwin)) {
543: break;
544: }
545: if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) {
546: Tcl_AppendResult(interp, "can't place ",
547: Tk_PathName(slavePtr->tkwin), " relative to ",
548: Tk_PathName(tkwin), (char *) NULL);
549: result = TCL_ERROR;
550: goto done;
551: }
552: }
553: UnlinkSlave(slavePtr);
554: slavePtr->masterPtr = FindMaster(tkwin);
555: slavePtr->nextPtr = slavePtr->masterPtr->slavePtr;
556: slavePtr->masterPtr->slavePtr = slavePtr;
557: } else if ((c == 'r') && (strncmp(argv[0], "-relheight", length) == 0)
558: && (length >= 5)) {
559: if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
560: result = TCL_ERROR;
561: goto done;
562: }
563: slavePtr->relHeight = d;
564: slavePtr->flags |= CHILD_REL_HEIGHT;
565: slavePtr->flags &= ~CHILD_HEIGHT;
566: } else if ((c == 'r') && (strncmp(argv[0], "-relwidth", length) == 0)
567: && (length >= 5)) {
568: if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
569: result = TCL_ERROR;
570: goto done;
571: }
572: slavePtr->relWidth = d;
573: slavePtr->flags |= CHILD_REL_WIDTH;
574: slavePtr->flags &= ~CHILD_WIDTH;
575: } else if ((c == 'r') && (strncmp(argv[0], "-relx", length) == 0)
576: && (length >= 5)) {
577: if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
578: result = TCL_ERROR;
579: goto done;
580: }
581: slavePtr->relX = d;
582: slavePtr->flags |= CHILD_REL_X;
583: } else if ((c == 'r') && (strncmp(argv[0], "-rely", length) == 0)
584: && (length >= 5)) {
585: if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
586: result = TCL_ERROR;
587: goto done;
588: }
589: slavePtr->relY = d;
590: slavePtr->flags |= CHILD_REL_Y;
591: } else if ((c == 'w') && (strncmp(argv[0], "-width", length) == 0)) {
592: if (argv[1][0] == 0) {
593: slavePtr->flags &= ~(CHILD_REL_WIDTH|CHILD_WIDTH);
594: } else {
595: if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
596: &slavePtr->width) != TCL_OK) {
597: result = TCL_ERROR;
598: goto done;
599: }
600: slavePtr->flags &= ~CHILD_REL_WIDTH;
601: slavePtr->flags |= CHILD_WIDTH;
602: }
603: } else if ((c == 'x') && (strncmp(argv[0], "-x", length) == 0)) {
604: if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
605: &slavePtr->x) != TCL_OK) {
606: result = TCL_ERROR;
607: goto done;
608: }
609: slavePtr->flags &= ~CHILD_REL_X;
610: } else if ((c == 'y') && (strncmp(argv[0], "-y", length) == 0)) {
611: if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
612: &slavePtr->y) != TCL_OK) {
613: result = TCL_ERROR;
614: goto done;
615: }
616: slavePtr->flags &= ~CHILD_REL_Y;
617: } else {
618: Tcl_AppendResult(interp, "unknown or ambiguous option \"",
619: argv[0], "\": must be -anchor, -bordermode, -height, ",
620: "-in, -relheight, -relwidth, -relx, -rely, -width, ",
621: "-x, or -y", (char *) NULL);
622: result = TCL_ERROR;
623: goto done;
624: }
625: }
626:
627: /*
628: * If there's no master specified for this slave, use its Tk_Parent.
629: * Then arrange for a placement recalculation in the master.
630: */
631:
632: done:
633: masterPtr = slavePtr->masterPtr;
634: if (masterPtr == NULL) {
635: masterPtr = FindMaster(Tk_Parent(slavePtr->tkwin));
636: slavePtr->masterPtr = masterPtr;
637: slavePtr->nextPtr = masterPtr->slavePtr;
638: masterPtr->slavePtr = slavePtr;
639: }
640: if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
641: masterPtr->flags |= PARENT_RECONFIG_PENDING;
642: Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
643: }
644: return result;
645: }
646:
647: /*
648: *----------------------------------------------------------------------
649: *
650: * RecomputePlacement --
651: *
652: * This procedure is called as a when-idle handler. It recomputes
653: * the geometries of all the slaves of a given master.
654: *
655: * Results:
656: * None.
657: *
658: * Side effects:
659: * Windows may change size or shape.
660: *
661: *----------------------------------------------------------------------
662: */
663:
664: static void
665: RecomputePlacement(clientData)
666: ClientData clientData; /* Pointer to Master record. */
667: {
668: register Master *masterPtr = (Master *) clientData;
669: register Slave *slavePtr;
670: Tk_Window ancestor, realMaster;
671: int x, y, width, height;
672: int masterWidth, masterHeight, masterBW;
673:
674: masterPtr->flags &= ~PARENT_RECONFIG_PENDING;
675:
676: /*
677: * Iterate over all the slaves for the master. Each slave's
678: * geometry can be computed independently of the other slaves.
679: */
680:
681: for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
682: slavePtr = slavePtr->nextPtr) {
683: /*
684: * Step 1: compute size and borderwidth of master, taking into
685: * account desired border mode.
686: */
687:
688: masterBW = 0;
689: masterWidth = Tk_Width(masterPtr->tkwin);
690: masterHeight = Tk_Height(masterPtr->tkwin);
691: if (slavePtr->borderMode == BM_INSIDE) {
692: masterBW = Tk_InternalBorderWidth(masterPtr->tkwin);
693: } else if (slavePtr->borderMode == BM_OUTSIDE) {
694: masterBW = -Tk_Changes(masterPtr->tkwin)->border_width;
695: }
696: masterWidth -= 2*masterBW;
697: masterHeight -= 2*masterBW;
698:
699: /*
700: * Step 2: compute size of slave (outside dimensions including
701: * border) and location of anchor point within master.
702: */
703:
704: x = slavePtr->x;
705: if (slavePtr->flags & CHILD_REL_X) {
706: x = (slavePtr->relX*masterWidth) +
707: ((slavePtr->relX > 0) ? 0.5 : -0.5);
708: }
709: x += masterBW;
710: y = slavePtr->y;
711: if (slavePtr->flags & CHILD_REL_Y) {
712: y = (slavePtr->relY*masterHeight) +
713: ((slavePtr->relY > 0) ? 0.5 : -0.5);
714: }
715: y += masterBW;
716: if (slavePtr->flags & CHILD_REL_WIDTH) {
717: width = (slavePtr->relWidth*masterWidth) + 0.5;
718: } else if (slavePtr->flags & CHILD_WIDTH) {
719: width = slavePtr->width;
720: } else {
721: width = Tk_ReqWidth(slavePtr->tkwin)
722: + 2*Tk_Changes(slavePtr->tkwin)->border_width;
723: }
724: if (slavePtr->flags & CHILD_REL_HEIGHT) {
725: height = (slavePtr->relHeight*masterHeight) + 0.5;
726: } else if (slavePtr->flags & CHILD_HEIGHT) {
727: height = slavePtr->height;
728: } else {
729: height = Tk_ReqHeight(slavePtr->tkwin)
730: + 2*Tk_Changes(slavePtr->tkwin)->border_width;
731: }
732:
733: /*
734: * Step 3: adjust the x and y positions so that the desired
735: * anchor point on the slave appears at that position. Also
736: * adjust for the border mode and master's border.
737: */
738:
739: switch (slavePtr->anchor) {
740: case TK_ANCHOR_N:
741: x -= width/2;
742: break;
743: case TK_ANCHOR_NE:
744: x -= width;
745: break;
746: case TK_ANCHOR_E:
747: x -= width;
748: y -= height/2;
749: break;
750: case TK_ANCHOR_SE:
751: x -= width;
752: y -= height;
753: break;
754: case TK_ANCHOR_S:
755: x -= width/2;
756: y -= height;
757: break;
758: case TK_ANCHOR_SW:
759: y -= height;
760: break;
761: case TK_ANCHOR_W:
762: y -= height/2;
763: break;
764: case TK_ANCHOR_NW:
765: break;
766: case TK_ANCHOR_CENTER:
767: x -= width/2;
768: y -= height/2;
769: break;
770: }
771:
772: /*
773: * Step 4: if masterPtr isn't actually the X master of slavePtr,
774: * then translate the x and y coordinates back into the coordinate
775: * system of masterPtr.
776: */
777:
778: for (ancestor = masterPtr->tkwin,
779: realMaster = Tk_Parent(slavePtr->tkwin);
780: ancestor != realMaster; ancestor = Tk_Parent(ancestor)) {
781: x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width;
782: y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width;
783: }
784:
785: /*
786: * Step 5: adjust width and height again to reflect inside dimensions
787: * of window rather than outside. Also make sure that the width and
788: * height aren't zero.
789: */
790:
791: width -= 2*Tk_Changes(slavePtr->tkwin)->border_width;
792: height -= 2*Tk_Changes(slavePtr->tkwin)->border_width;
793: if (width <= 0) {
794: width = 1;
795: }
796: if (height <= 0) {
797: height = 1;
798: }
799:
800: /*
801: * Step 6: see if the window's size or location has changed; if
802: * so then tell X to reconfigure it.
803: */
804:
805: if ((x != Tk_X(slavePtr->tkwin))
806: || (y != Tk_Y(slavePtr->tkwin))
807: || (width != Tk_Width(slavePtr->tkwin))
808: || (height != Tk_Height(slavePtr->tkwin))) {
809: Tk_MoveResizeWindow(slavePtr->tkwin, x, y,
810: (unsigned int) width, (unsigned int) height);
811: }
812: Tk_MapWindow(slavePtr->tkwin);
813: }
814: }
815:
816: /*
817: *----------------------------------------------------------------------
818: *
819: * MasterStructureProc --
820: *
821: * This procedure is invoked by the Tk event handler when
822: * StructureNotify events occur for a master window.
823: *
824: * Results:
825: * None.
826: *
827: * Side effects:
828: * Structures get cleaned up if the window was deleted. If the
829: * window was resized then slave geometries get recomputed.
830: *
831: *----------------------------------------------------------------------
832: */
833:
834: static void
835: MasterStructureProc(clientData, eventPtr)
836: ClientData clientData; /* Pointer to Master structure for window
837: * referred to by eventPtr. */
838: XEvent *eventPtr; /* Describes what just happened. */
839: {
840: register Master *masterPtr = (Master *) clientData;
841: register Slave *slavePtr, *nextPtr;
842:
843: if (eventPtr->type == ConfigureNotify) {
844: if ((masterPtr->slavePtr != NULL)
845: && !(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
846: masterPtr->flags |= PARENT_RECONFIG_PENDING;
847: Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
848: }
849: } else if (eventPtr->type == DestroyNotify) {
850: for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
851: slavePtr = nextPtr) {
852: slavePtr->masterPtr = NULL;
853: nextPtr = slavePtr->nextPtr;
854: slavePtr->nextPtr = NULL;
855: }
856: Tcl_DeleteHashEntry(Tcl_FindHashEntry(&masterTable,
857: (char *) masterPtr->tkwin));
858: if (masterPtr->flags & PARENT_RECONFIG_PENDING) {
859: Tk_CancelIdleCall(RecomputePlacement, (ClientData) masterPtr);
860: }
861: masterPtr->tkwin = NULL;
862: ckfree((char *) masterPtr);
863: }
864: }
865:
866: /*
867: *----------------------------------------------------------------------
868: *
869: * SlaveStructureProc --
870: *
871: * This procedure is invoked by the Tk event handler when
872: * StructureNotify events occur for a slave window.
873: *
874: * Results:
875: * None.
876: *
877: * Side effects:
878: * Structures get cleaned up if the window was deleted.
879: *
880: *----------------------------------------------------------------------
881: */
882:
883: static void
884: SlaveStructureProc(clientData, eventPtr)
885: ClientData clientData; /* Pointer to Slave structure for window
886: * referred to by eventPtr. */
887: XEvent *eventPtr; /* Describes what just happened. */
888: {
889: register Slave *slavePtr = (Slave *) clientData;
890:
891: if (eventPtr->type == DestroyNotify) {
892: UnlinkSlave(slavePtr);
893: Tcl_DeleteHashEntry(Tcl_FindHashEntry(&slaveTable,
894: (char *) slavePtr->tkwin));
895: ckfree((char *) slavePtr);
896: }
897: }
898:
899: /*
900: *----------------------------------------------------------------------
901: *
902: * PlaceRequestProc --
903: *
904: * This procedure is invoked by Tk whenever a slave managed by us
905: * changes its requested geometry.
906: *
907: * Results:
908: * None.
909: *
910: * Side effects:
911: * The window will get relayed out, if its requested size has
912: * anything to do with its actual size.
913: *
914: *----------------------------------------------------------------------
915: */
916:
917: /* ARGSUSED */
918: static void
919: PlaceRequestProc(clientData, tkwin)
920: ClientData clientData; /* Pointer to our record for slave. */
921: Tk_Window tkwin; /* Window that changed its desired
922: * size. */
923: {
924: Slave *slavePtr = (Slave *) clientData;
925: Master *masterPtr;
926:
927: if (((slavePtr->flags & (CHILD_WIDTH|CHILD_REL_WIDTH)) != 0)
928: && ((slavePtr->flags & (CHILD_HEIGHT|CHILD_REL_HEIGHT)) != 0)) {
929: return;
930: }
931: masterPtr = slavePtr->masterPtr;
932: if (masterPtr == NULL) {
933: return;
934: }
935: if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
936: masterPtr->flags |= PARENT_RECONFIG_PENDING;
937: Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
938: }
939: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.