/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkplace.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkplace.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25