]> git.zerfleddert.de Git - micropolis/blob - src/tk/tkplace.c
Import Micropolis from http://www.donhopkins.com/home/micropolis/
[micropolis] / src / tk / tkplace.c
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 }
Impressum, Datenschutz