]> cvs.zerfleddert.de Git - micropolis/blob - src/tk/tkplace.c
Fixes for compilation with gcc 15
[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 (
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 {
167 Tk_Window tkwin;
168 Slave *slavePtr;
169 Tcl_HashEntry *hPtr;
170 int length;
171 char c;
172
173 /*
174 * Initialize, if that hasn't been done yet.
175 */
176
177 if (!initialized) {
178 Tcl_InitHashTable(&masterTable, TCL_ONE_WORD_KEYS);
179 Tcl_InitHashTable(&slaveTable, TCL_ONE_WORD_KEYS);
180 initialized = 1;
181 }
182
183 if (argc < 3) {
184 Tcl_AppendResult(interp, "wrong # args: should be \"",
185 argv[0], " option|pathName args", (char *) NULL);
186 return TCL_ERROR;
187 }
188 c = argv[1][0];
189 length = strlen(argv[1]);
190
191 /*
192 * Handle special shortcut where window name is first argument.
193 */
194
195 if (c == '.') {
196 tkwin = Tk_NameToWindow(interp, argv[1], (Tk_Window) clientData);
197 if (tkwin == NULL) {
198 return TCL_ERROR;
199 }
200 slavePtr = FindSlave(tkwin);
201 return ConfigureSlave(interp, slavePtr, argc-2, argv+2);
202 }
203
204 /*
205 * Handle more general case of option followed by window name followed
206 * by possible additional arguments.
207 */
208
209 tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);
210 if (tkwin == NULL) {
211 return TCL_ERROR;
212 }
213 if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
214 if (argc < 5) {
215 Tcl_AppendResult(interp, "wrong # args: should be \"",
216 argv[0],
217 " configure pathName option value ?option value ...?\"",
218 (char *) NULL);
219 return TCL_ERROR;
220 }
221 slavePtr = FindSlave(tkwin);
222 return ConfigureSlave(interp, slavePtr, argc-3, argv+3);
223 } else if ((c == 'd') && (strncmp(argv[1], "dependents", length) == 0)) {
224 if (argc != 3) {
225 Tcl_AppendResult(interp, "wrong # args: should be \"",
226 argv[0], " dependents pathName\"", (char *) NULL);
227 return TCL_ERROR;
228 }
229 hPtr = Tcl_FindHashEntry(&masterTable, (char *) tkwin);
230 if (hPtr != NULL) {
231 Master *masterPtr;
232 masterPtr = (Master *) Tcl_GetHashValue(hPtr);
233 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
234 slavePtr = slavePtr->nextPtr) {
235 Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin), 0);
236 }
237 }
238 } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) {
239 if (argc != 3) {
240 Tcl_AppendResult(interp, "wrong # args: should be \"",
241 argv[0], " forget pathName\"", (char *) NULL);
242 return TCL_ERROR;
243 }
244 hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin);
245 if (hPtr == NULL) {
246 return TCL_OK;
247 }
248 slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
249 UnlinkSlave(slavePtr);
250 Tcl_DeleteHashEntry(hPtr);
251 Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc,
252 (ClientData) slavePtr);
253 Tk_ManageGeometry(tkwin, (Tk_GeometryProc *) NULL, (ClientData) NULL);
254 Tk_UnmapWindow(tkwin);
255 ckfree((char *) slavePtr);
256 } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
257 char buffer[50];
258
259 if (argc != 3) {
260 Tcl_AppendResult(interp, "wrong # args: should be \"",
261 argv[0], " info pathName\"", (char *) NULL);
262 return TCL_ERROR;
263 }
264 hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin);
265 if (hPtr == NULL) {
266 return TCL_OK;
267 }
268 slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
269 if (slavePtr->flags & CHILD_REL_X) {
270 sprintf(buffer, "-relx %.4g", slavePtr->relX);
271 } else {
272 sprintf(buffer, "-x %d", slavePtr->x);
273 }
274 Tcl_AppendResult(interp, buffer, (char *) NULL);
275 if (slavePtr->flags & CHILD_REL_Y) {
276 sprintf(buffer, " -rely %.4g", slavePtr->relY);
277 } else {
278 sprintf(buffer, " -y %d", slavePtr->y);
279 }
280 Tcl_AppendResult(interp, buffer, (char *) NULL);
281 if (slavePtr->flags & CHILD_REL_WIDTH) {
282 sprintf(buffer, " -relwidth %.4g", slavePtr->relWidth);
283 Tcl_AppendResult(interp, buffer, (char *) NULL);
284 } else if (slavePtr->flags & CHILD_WIDTH) {
285 sprintf(buffer, " -width %d", slavePtr->width);
286 Tcl_AppendResult(interp, buffer, (char *) NULL);
287 }
288 if (slavePtr->flags & CHILD_REL_HEIGHT) {
289 sprintf(buffer, " -relheight %.4g", slavePtr->relHeight);
290 Tcl_AppendResult(interp, buffer, (char *) NULL);
291 } else if (slavePtr->flags & CHILD_HEIGHT) {
292 sprintf(buffer, " -height %d", slavePtr->height);
293 Tcl_AppendResult(interp, buffer, (char *) NULL);
294 }
295 Tcl_AppendResult(interp, " -anchor ", Tk_NameOfAnchor(slavePtr->anchor),
296 (char *) NULL);
297 if (slavePtr->borderMode == BM_OUTSIDE) {
298 Tcl_AppendResult(interp, " -bordermode outside", (char *) NULL);
299 } else if (slavePtr->borderMode == BM_IGNORE) {
300 Tcl_AppendResult(interp, " -bordermode ignore", (char *) NULL);
301 }
302 if ((slavePtr->masterPtr != NULL)
303 && (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin))) {
304 Tcl_AppendResult(interp, " -in ",
305 Tk_PathName(slavePtr->masterPtr->tkwin), (char *) NULL);
306 }
307 } else {
308 Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
309 "\": must be configure, dependents, forget, or info",
310 (char *) NULL);
311 return TCL_ERROR;
312 }
313 return TCL_OK;
314 }
315 \f
316 /*
317 *----------------------------------------------------------------------
318 *
319 * FindSlave --
320 *
321 * Given a Tk_Window token, find the Slave structure corresponding
322 * to that token (making a new one if necessary).
323 *
324 * Results:
325 * None.
326 *
327 * Side effects:
328 * A new Slave structure may be created.
329 *
330 *----------------------------------------------------------------------
331 */
332
333 static Slave *
334 FindSlave (
335 Tk_Window tkwin /* Token for desired slave. */
336 )
337 {
338 Tcl_HashEntry *hPtr;
339 register Slave *slavePtr;
340 int new;
341
342 hPtr = Tcl_CreateHashEntry(&slaveTable, (char *) tkwin, &new);
343 if (new) {
344 slavePtr = (Slave *) ckalloc(sizeof(Slave));
345 slavePtr->tkwin = tkwin;
346 slavePtr->masterPtr = NULL;
347 slavePtr->nextPtr = NULL;
348 slavePtr->x = slavePtr->y = 0;
349 slavePtr->relX = slavePtr->relY = 0.0;
350 slavePtr->width = slavePtr->height = 0;
351 slavePtr->relWidth = slavePtr->relHeight = 0.0;
352 slavePtr->anchor = TK_ANCHOR_NW;
353 slavePtr->borderMode = BM_INSIDE;
354 slavePtr->flags = 0;
355 Tcl_SetHashValue(hPtr, slavePtr);
356 Tk_CreateEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc,
357 (ClientData) slavePtr);
358 Tk_ManageGeometry(tkwin, PlaceRequestProc, (ClientData) slavePtr);
359 } else {
360 slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
361 }
362 return slavePtr;
363 }
364 \f
365 /*
366 *----------------------------------------------------------------------
367 *
368 * UnlinkSlave --
369 *
370 * This procedure removes a slave window from the chain of slaves
371 * in its master.
372 *
373 * Results:
374 * None.
375 *
376 * Side effects:
377 * The slave list of slavePtr's master changes.
378 *
379 *----------------------------------------------------------------------
380 */
381
382 static void
383 UnlinkSlave (
384 Slave *slavePtr /* Slave structure to be unlinked. */
385 )
386 {
387 register Master *masterPtr;
388 register Slave *prevPtr;
389
390 masterPtr = slavePtr->masterPtr;
391 if (masterPtr == NULL) {
392 return;
393 }
394 if (masterPtr->slavePtr == slavePtr) {
395 masterPtr->slavePtr = slavePtr->nextPtr;
396 } else {
397 for (prevPtr = masterPtr->slavePtr; ;
398 prevPtr = prevPtr->nextPtr) {
399 if (prevPtr == NULL) {
400 panic("UnlinkSlave couldn't find slave to unlink");
401 }
402 if (prevPtr->nextPtr == slavePtr) {
403 prevPtr->nextPtr = slavePtr->nextPtr;
404 break;
405 }
406 }
407 }
408 slavePtr->masterPtr = NULL;
409 }
410 \f
411 /*
412 *----------------------------------------------------------------------
413 *
414 * FindMaster --
415 *
416 * Given a Tk_Window token, find the Master structure corresponding
417 * to that token (making a new one if necessary).
418 *
419 * Results:
420 * None.
421 *
422 * Side effects:
423 * A new Master structure may be created.
424 *
425 *----------------------------------------------------------------------
426 */
427
428 static Master *
429 FindMaster (
430 Tk_Window tkwin /* Token for desired master. */
431 )
432 {
433 Tcl_HashEntry *hPtr;
434 register Master *masterPtr;
435 int new;
436
437 hPtr = Tcl_CreateHashEntry(&masterTable, (char *) tkwin, &new);
438 if (new) {
439 masterPtr = (Master *) ckalloc(sizeof(Master));
440 masterPtr->tkwin = tkwin;
441 masterPtr->slavePtr = NULL;
442 masterPtr->flags = 0;
443 Tcl_SetHashValue(hPtr, masterPtr);
444 Tk_CreateEventHandler(masterPtr->tkwin, StructureNotifyMask,
445 MasterStructureProc, (ClientData) masterPtr);
446 } else {
447 masterPtr = (Master *) Tcl_GetHashValue(hPtr);
448 }
449 return masterPtr;
450 }
451 \f
452 /*
453 *----------------------------------------------------------------------
454 *
455 * ConfigureSlave --
456 *
457 * This procedure is called to process an argv/argc list to
458 * reconfigure the placement of a window.
459 *
460 * Results:
461 * A standard Tcl result. If an error occurs then a message is
462 * left in interp->result.
463 *
464 * Side effects:
465 * Information in slavePtr may change, and slavePtr's master is
466 * scheduled for reconfiguration.
467 *
468 *----------------------------------------------------------------------
469 */
470
471 static int
472 ConfigureSlave (
473 Tcl_Interp *interp, /* Used for error reporting. */
474 Slave *slavePtr, /* Pointer to current information
475 * about slave. */
476 int argc, /* Number of config arguments. */
477 char **argv /* String values for arguments. */
478 )
479 {
480 register Master *masterPtr;
481 int c, length, result;
482 double d;
483
484 result = TCL_OK;
485 for ( ; argc > 0; argc -= 2, argv += 2) {
486 if (argc < 2) {
487 Tcl_AppendResult(interp, "extra option \"", argv[0],
488 "\" (option with no value?)", (char *) NULL);
489 result = TCL_ERROR;
490 goto done;
491 }
492 length = strlen(argv[0]);
493 c = argv[0][1];
494 if ((c == 'a') && (strncmp(argv[0], "-anchor", length) == 0)) {
495 if (Tk_GetAnchor(interp, argv[1], &slavePtr->anchor) != TCL_OK) {
496 result = TCL_ERROR;
497 goto done;
498 }
499 } else if ((c == 'b')
500 && (strncmp(argv[0], "-bordermode", length) == 0)) {
501 c = argv[1][0];
502 length = strlen(argv[1]);
503 if ((c == 'i') && (strncmp(argv[1], "ignore", length) == 0)
504 && (length >= 2)) {
505 slavePtr->borderMode = BM_IGNORE;
506 } else if ((c == 'i') && (strncmp(argv[1], "inside", length) == 0)
507 && (length >= 2)) {
508 slavePtr->borderMode = BM_INSIDE;
509 } else if ((c == 'o')
510 && (strncmp(argv[1], "outside", length) == 0)) {
511 slavePtr->borderMode = BM_OUTSIDE;
512 } else {
513 Tcl_AppendResult(interp, "bad border mode \"", argv[1],
514 "\": must be ignore, inside, or outside",
515 (char *) NULL);
516 result = TCL_ERROR;
517 goto done;
518 }
519 } else if ((c == 'h') && (strncmp(argv[0], "-height", length) == 0)) {
520 if (argv[1][0] == 0) {
521 slavePtr->flags &= ~(CHILD_REL_HEIGHT|CHILD_HEIGHT);
522 } else {
523 if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
524 &slavePtr->height) != TCL_OK) {
525 result = TCL_ERROR;
526 goto done;
527 }
528 slavePtr->flags &= ~CHILD_REL_HEIGHT;
529 slavePtr->flags |= CHILD_HEIGHT;
530 }
531 } else if ((c == 'i') && (strncmp(argv[0], "-in", length) == 0)) {
532 Tk_Window tkwin;
533 Tk_Window ancestor;
534
535 tkwin = Tk_NameToWindow(interp, argv[1], slavePtr->tkwin);
536 if (tkwin == NULL) {
537 result = TCL_ERROR;
538 goto done;
539 }
540
541 /*
542 * Make sure that the new master is either the logical parent
543 * of the slave or a descendant of that window.
544 */
545
546 for (ancestor = tkwin; ; ancestor = Tk_Parent(ancestor)) {
547 if (ancestor == Tk_Parent(slavePtr->tkwin)) {
548 break;
549 }
550 if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) {
551 Tcl_AppendResult(interp, "can't place ",
552 Tk_PathName(slavePtr->tkwin), " relative to ",
553 Tk_PathName(tkwin), (char *) NULL);
554 result = TCL_ERROR;
555 goto done;
556 }
557 }
558 UnlinkSlave(slavePtr);
559 slavePtr->masterPtr = FindMaster(tkwin);
560 slavePtr->nextPtr = slavePtr->masterPtr->slavePtr;
561 slavePtr->masterPtr->slavePtr = slavePtr;
562 } else if ((c == 'r') && (strncmp(argv[0], "-relheight", length) == 0)
563 && (length >= 5)) {
564 if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
565 result = TCL_ERROR;
566 goto done;
567 }
568 slavePtr->relHeight = d;
569 slavePtr->flags |= CHILD_REL_HEIGHT;
570 slavePtr->flags &= ~CHILD_HEIGHT;
571 } else if ((c == 'r') && (strncmp(argv[0], "-relwidth", length) == 0)
572 && (length >= 5)) {
573 if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
574 result = TCL_ERROR;
575 goto done;
576 }
577 slavePtr->relWidth = d;
578 slavePtr->flags |= CHILD_REL_WIDTH;
579 slavePtr->flags &= ~CHILD_WIDTH;
580 } else if ((c == 'r') && (strncmp(argv[0], "-relx", length) == 0)
581 && (length >= 5)) {
582 if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
583 result = TCL_ERROR;
584 goto done;
585 }
586 slavePtr->relX = d;
587 slavePtr->flags |= CHILD_REL_X;
588 } else if ((c == 'r') && (strncmp(argv[0], "-rely", length) == 0)
589 && (length >= 5)) {
590 if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
591 result = TCL_ERROR;
592 goto done;
593 }
594 slavePtr->relY = d;
595 slavePtr->flags |= CHILD_REL_Y;
596 } else if ((c == 'w') && (strncmp(argv[0], "-width", length) == 0)) {
597 if (argv[1][0] == 0) {
598 slavePtr->flags &= ~(CHILD_REL_WIDTH|CHILD_WIDTH);
599 } else {
600 if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
601 &slavePtr->width) != TCL_OK) {
602 result = TCL_ERROR;
603 goto done;
604 }
605 slavePtr->flags &= ~CHILD_REL_WIDTH;
606 slavePtr->flags |= CHILD_WIDTH;
607 }
608 } else if ((c == 'x') && (strncmp(argv[0], "-x", length) == 0)) {
609 if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
610 &slavePtr->x) != TCL_OK) {
611 result = TCL_ERROR;
612 goto done;
613 }
614 slavePtr->flags &= ~CHILD_REL_X;
615 } else if ((c == 'y') && (strncmp(argv[0], "-y", length) == 0)) {
616 if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
617 &slavePtr->y) != TCL_OK) {
618 result = TCL_ERROR;
619 goto done;
620 }
621 slavePtr->flags &= ~CHILD_REL_Y;
622 } else {
623 Tcl_AppendResult(interp, "unknown or ambiguous option \"",
624 argv[0], "\": must be -anchor, -bordermode, -height, ",
625 "-in, -relheight, -relwidth, -relx, -rely, -width, ",
626 "-x, or -y", (char *) NULL);
627 result = TCL_ERROR;
628 goto done;
629 }
630 }
631
632 /*
633 * If there's no master specified for this slave, use its Tk_Parent.
634 * Then arrange for a placement recalculation in the master.
635 */
636
637 done:
638 masterPtr = slavePtr->masterPtr;
639 if (masterPtr == NULL) {
640 masterPtr = FindMaster(Tk_Parent(slavePtr->tkwin));
641 slavePtr->masterPtr = masterPtr;
642 slavePtr->nextPtr = masterPtr->slavePtr;
643 masterPtr->slavePtr = slavePtr;
644 }
645 if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
646 masterPtr->flags |= PARENT_RECONFIG_PENDING;
647 Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
648 }
649 return result;
650 }
651 \f
652 /*
653 *----------------------------------------------------------------------
654 *
655 * RecomputePlacement --
656 *
657 * This procedure is called as a when-idle handler. It recomputes
658 * the geometries of all the slaves of a given master.
659 *
660 * Results:
661 * None.
662 *
663 * Side effects:
664 * Windows may change size or shape.
665 *
666 *----------------------------------------------------------------------
667 */
668
669 static void
670 RecomputePlacement (
671 ClientData clientData /* Pointer to Master record. */
672 )
673 {
674 register Master *masterPtr = (Master *) clientData;
675 register Slave *slavePtr;
676 Tk_Window ancestor, realMaster;
677 int x, y, width, height;
678 int masterWidth, masterHeight, masterBW;
679
680 masterPtr->flags &= ~PARENT_RECONFIG_PENDING;
681
682 /*
683 * Iterate over all the slaves for the master. Each slave's
684 * geometry can be computed independently of the other slaves.
685 */
686
687 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
688 slavePtr = slavePtr->nextPtr) {
689 /*
690 * Step 1: compute size and borderwidth of master, taking into
691 * account desired border mode.
692 */
693
694 masterBW = 0;
695 masterWidth = Tk_Width(masterPtr->tkwin);
696 masterHeight = Tk_Height(masterPtr->tkwin);
697 if (slavePtr->borderMode == BM_INSIDE) {
698 masterBW = Tk_InternalBorderWidth(masterPtr->tkwin);
699 } else if (slavePtr->borderMode == BM_OUTSIDE) {
700 masterBW = -Tk_Changes(masterPtr->tkwin)->border_width;
701 }
702 masterWidth -= 2*masterBW;
703 masterHeight -= 2*masterBW;
704
705 /*
706 * Step 2: compute size of slave (outside dimensions including
707 * border) and location of anchor point within master.
708 */
709
710 x = slavePtr->x;
711 if (slavePtr->flags & CHILD_REL_X) {
712 x = (slavePtr->relX*masterWidth) +
713 ((slavePtr->relX > 0) ? 0.5 : -0.5);
714 }
715 x += masterBW;
716 y = slavePtr->y;
717 if (slavePtr->flags & CHILD_REL_Y) {
718 y = (slavePtr->relY*masterHeight) +
719 ((slavePtr->relY > 0) ? 0.5 : -0.5);
720 }
721 y += masterBW;
722 if (slavePtr->flags & CHILD_REL_WIDTH) {
723 width = (slavePtr->relWidth*masterWidth) + 0.5;
724 } else if (slavePtr->flags & CHILD_WIDTH) {
725 width = slavePtr->width;
726 } else {
727 width = Tk_ReqWidth(slavePtr->tkwin)
728 + 2*Tk_Changes(slavePtr->tkwin)->border_width;
729 }
730 if (slavePtr->flags & CHILD_REL_HEIGHT) {
731 height = (slavePtr->relHeight*masterHeight) + 0.5;
732 } else if (slavePtr->flags & CHILD_HEIGHT) {
733 height = slavePtr->height;
734 } else {
735 height = Tk_ReqHeight(slavePtr->tkwin)
736 + 2*Tk_Changes(slavePtr->tkwin)->border_width;
737 }
738
739 /*
740 * Step 3: adjust the x and y positions so that the desired
741 * anchor point on the slave appears at that position. Also
742 * adjust for the border mode and master's border.
743 */
744
745 switch (slavePtr->anchor) {
746 case TK_ANCHOR_N:
747 x -= width/2;
748 break;
749 case TK_ANCHOR_NE:
750 x -= width;
751 break;
752 case TK_ANCHOR_E:
753 x -= width;
754 y -= height/2;
755 break;
756 case TK_ANCHOR_SE:
757 x -= width;
758 y -= height;
759 break;
760 case TK_ANCHOR_S:
761 x -= width/2;
762 y -= height;
763 break;
764 case TK_ANCHOR_SW:
765 y -= height;
766 break;
767 case TK_ANCHOR_W:
768 y -= height/2;
769 break;
770 case TK_ANCHOR_NW:
771 break;
772 case TK_ANCHOR_CENTER:
773 x -= width/2;
774 y -= height/2;
775 break;
776 }
777
778 /*
779 * Step 4: if masterPtr isn't actually the X master of slavePtr,
780 * then translate the x and y coordinates back into the coordinate
781 * system of masterPtr.
782 */
783
784 for (ancestor = masterPtr->tkwin,
785 realMaster = Tk_Parent(slavePtr->tkwin);
786 ancestor != realMaster; ancestor = Tk_Parent(ancestor)) {
787 x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width;
788 y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width;
789 }
790
791 /*
792 * Step 5: adjust width and height again to reflect inside dimensions
793 * of window rather than outside. Also make sure that the width and
794 * height aren't zero.
795 */
796
797 width -= 2*Tk_Changes(slavePtr->tkwin)->border_width;
798 height -= 2*Tk_Changes(slavePtr->tkwin)->border_width;
799 if (width <= 0) {
800 width = 1;
801 }
802 if (height <= 0) {
803 height = 1;
804 }
805
806 /*
807 * Step 6: see if the window's size or location has changed; if
808 * so then tell X to reconfigure it.
809 */
810
811 if ((x != Tk_X(slavePtr->tkwin))
812 || (y != Tk_Y(slavePtr->tkwin))
813 || (width != Tk_Width(slavePtr->tkwin))
814 || (height != Tk_Height(slavePtr->tkwin))) {
815 Tk_MoveResizeWindow(slavePtr->tkwin, x, y,
816 (unsigned int) width, (unsigned int) height);
817 }
818 Tk_MapWindow(slavePtr->tkwin);
819 }
820 }
821 \f
822 /*
823 *----------------------------------------------------------------------
824 *
825 * MasterStructureProc --
826 *
827 * This procedure is invoked by the Tk event handler when
828 * StructureNotify events occur for a master window.
829 *
830 * Results:
831 * None.
832 *
833 * Side effects:
834 * Structures get cleaned up if the window was deleted. If the
835 * window was resized then slave geometries get recomputed.
836 *
837 *----------------------------------------------------------------------
838 */
839
840 static void
841 MasterStructureProc (
842 ClientData clientData, /* Pointer to Master structure for window
843 * referred to by eventPtr. */
844 XEvent *eventPtr /* Describes what just happened. */
845 )
846 {
847 register Master *masterPtr = (Master *) clientData;
848 register Slave *slavePtr, *nextPtr;
849
850 if (eventPtr->type == ConfigureNotify) {
851 if ((masterPtr->slavePtr != NULL)
852 && !(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
853 masterPtr->flags |= PARENT_RECONFIG_PENDING;
854 Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
855 }
856 } else if (eventPtr->type == DestroyNotify) {
857 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
858 slavePtr = nextPtr) {
859 slavePtr->masterPtr = NULL;
860 nextPtr = slavePtr->nextPtr;
861 slavePtr->nextPtr = NULL;
862 }
863 Tcl_DeleteHashEntry(Tcl_FindHashEntry(&masterTable,
864 (char *) masterPtr->tkwin));
865 if (masterPtr->flags & PARENT_RECONFIG_PENDING) {
866 Tk_CancelIdleCall(RecomputePlacement, (ClientData) masterPtr);
867 }
868 masterPtr->tkwin = NULL;
869 ckfree((char *) masterPtr);
870 }
871 }
872 \f
873 /*
874 *----------------------------------------------------------------------
875 *
876 * SlaveStructureProc --
877 *
878 * This procedure is invoked by the Tk event handler when
879 * StructureNotify events occur for a slave window.
880 *
881 * Results:
882 * None.
883 *
884 * Side effects:
885 * Structures get cleaned up if the window was deleted.
886 *
887 *----------------------------------------------------------------------
888 */
889
890 static void
891 SlaveStructureProc (
892 ClientData clientData, /* Pointer to Slave structure for window
893 * referred to by eventPtr. */
894 XEvent *eventPtr /* Describes what just happened. */
895 )
896 {
897 register Slave *slavePtr = (Slave *) clientData;
898
899 if (eventPtr->type == DestroyNotify) {
900 UnlinkSlave(slavePtr);
901 Tcl_DeleteHashEntry(Tcl_FindHashEntry(&slaveTable,
902 (char *) slavePtr->tkwin));
903 ckfree((char *) slavePtr);
904 }
905 }
906 \f
907 /*
908 *----------------------------------------------------------------------
909 *
910 * PlaceRequestProc --
911 *
912 * This procedure is invoked by Tk whenever a slave managed by us
913 * changes its requested geometry.
914 *
915 * Results:
916 * None.
917 *
918 * Side effects:
919 * The window will get relayed out, if its requested size has
920 * anything to do with its actual size.
921 *
922 *----------------------------------------------------------------------
923 */
924
925 /* ARGSUSED */
926 static void
927 PlaceRequestProc (
928 ClientData clientData, /* Pointer to our record for slave. */
929 Tk_Window tkwin /* Window that changed its desired
930 * size. */
931 )
932 {
933 Slave *slavePtr = (Slave *) clientData;
934 Master *masterPtr;
935
936 if (((slavePtr->flags & (CHILD_WIDTH|CHILD_REL_WIDTH)) != 0)
937 && ((slavePtr->flags & (CHILD_HEIGHT|CHILD_REL_HEIGHT)) != 0)) {
938 return;
939 }
940 masterPtr = slavePtr->masterPtr;
941 if (masterPtr == NULL) {
942 return;
943 }
944 if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
945 masterPtr->flags |= PARENT_RECONFIG_PENDING;
946 Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
947 }
948 }
Impressum, Datenschutz