4 * This file contains code to implement the "packer"
5 * geometry manager for Tk.
7 * Copyright (c) 1990-1994 The Regents of the University of California.
8 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
19 typedef enum {TOP, BOTTOM, LEFT, RIGHT} Side;
21 /* For each window that the packer cares about (either because
22 * the window is managed by the packer or because the window
23 * has slaves that are managed by the packer), there is a
24 * structure of the following type:
27 typedef struct Packer {
28 Tk_Window tkwin; /* Tk token for window. NULL means that
29 * the window has been deleted, but the
30 * packet hasn't had a chance to clean up
31 * yet because the structure is still in
33 struct Packer *masterPtr; /* Master window within which this window
34 * is packed (NULL means this window
35 * isn't managed by the packer). */
36 struct Packer *nextPtr; /* Next window packed within same
37 * parent. List is priority-ordered:
38 * first on list gets packed first. */
39 struct Packer *slavePtr; /* First in list of slaves packed
40 * inside this window (NULL means
41 * no packed slaves). */
42 Side side; /* Side of parent against which
43 * this window is packed. */
44 Tk_Anchor anchor; /* If frame allocated for window is larger
45 * than window needs, this indicates how
46 * where to position window in frame. */
47 int padX, padY; /* Total additional pixels to leave around the
48 * window (half of this space is left on each
49 * side). This is space *outside* the window:
50 * we'll allocate extra space in frame but
51 * won't enlarge window). */
52 int iPadX, iPadY; /* Total extra pixels to allocate inside the
53 * window (half this amount will appear on
55 int doubleBw; /* Twice the window's last known border
56 * width. If this changes, the window
57 * must be repacked within its parent. */
58 int *abortPtr; /* If non-NULL, it means that there is a nested
59 * call to ArrangePacking already working on
60 * this window. *abortPtr may be set to 1 to
61 * abort that nested call. This happens, for
62 * example, if tkwin or any of its slaves
64 int flags; /* Miscellaneous flags; see below
69 * Flag values for Packer structures:
71 * REQUESTED_REPACK: 1 means a Tcl_DoWhenIdle request
72 * has already been made to repack
73 * all the slaves of this window.
74 * FILLX: 1 means if frame allocated for window
75 * is wider than window needs, expand window
76 * to fill frame. 0 means don't make window
77 * any larger than needed.
78 * FILLY: Same as FILLX, except for height.
79 * EXPAND: 1 means this window's frame will absorb any
80 * extra space in the parent window.
81 * OLD_STYLE: 1 means this window is being managed with
82 * the old-style packer algorithms (before
83 * Tk version 3.3). The main difference is
84 * that padding and filling are done differently.
85 * DONT_PROPAGATE: 1 means don't set this window's requested
86 * size. 0 means if this window is a master
87 * then Tk will set its requested size to fit
88 * the needs of its slaves.
91 #define REQUESTED_REPACK 1
96 #define DONT_PROPAGATE 32
99 * Hash table used to map from Tk_Window tokens to corresponding
103 static Tcl_HashTable packerHashTable;
106 * Have statics in this module been initialized?
109 static int initialized = 0;
112 * The following structure is the official type record for the
116 static void PackReqProc _ANSI_ARGS_((ClientData clientData,
118 static void PackLostSlaveProc _ANSI_ARGS_((ClientData clientData,
121 static Tk_GeomMgr packerType = {
123 PackReqProc, /* requestProc */
124 PackLostSlaveProc, /* lostSlaveProc */
128 * Forward declarations for procedures defined later in this file:
131 static void ArrangePacking _ANSI_ARGS_((ClientData clientData));
132 static int ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp,
133 Tk_Window tkwin, int argc, char *argv[]));
134 static void DestroyPacker _ANSI_ARGS_((char *memPtr));
135 static Packer * GetPacker _ANSI_ARGS_((Tk_Window tkwin));
136 static int PackAfter _ANSI_ARGS_((Tcl_Interp *interp,
137 Packer *prevPtr, Packer *masterPtr, int argc,
139 static void PackReqProc _ANSI_ARGS_((ClientData clientData,
141 static void PackStructureProc _ANSI_ARGS_((ClientData clientData,
143 static void Unlink _ANSI_ARGS_((Packer *packPtr));
144 static int XExpansion _ANSI_ARGS_((Packer *slavePtr,
146 static int YExpansion _ANSI_ARGS_((Packer *slavePtr,
150 *--------------------------------------------------------------
154 * This procedure is invoked to process the "pack" Tcl command.
155 * See the user documentation for details on what it does.
158 * A standard Tcl result.
161 * See the user documentation.
163 *--------------------------------------------------------------
167 Tk_PackCmd(clientData, interp, argc, argv)
168 ClientData clientData; /* Main window associated with
170 Tcl_Interp *interp; /* Current interpreter. */
171 int argc; /* Number of arguments. */
172 char **argv; /* Argument strings. */
174 Tk_Window tkwin = (Tk_Window) clientData;
178 if ((argc >= 2) && (argv[1][0] == '.')) {
179 return ConfigureSlaves(interp, tkwin, argc-1, argv+1);
182 Tcl_AppendResult(interp, "wrong # args: should be \"",
183 argv[0], " option arg ?arg ...?\"", (char *) NULL);
187 length = strlen(argv[1]);
188 if ((c == 'a') && (length >= 2)
189 && (strncmp(argv[1], "after", length) == 0)) {
193 tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
194 if (tkwin2 == NULL) {
197 prevPtr = GetPacker(tkwin2);
198 if (prevPtr->masterPtr == NULL) {
199 Tcl_AppendResult(interp, "window \"", argv[2],
200 "\" isn't packed", (char *) NULL);
203 return PackAfter(interp, prevPtr, prevPtr->masterPtr, argc-3, argv+3);
204 } else if ((c == 'a') && (length >= 2)
205 && (strncmp(argv[1], "append", length) == 0)) {
207 register Packer *prevPtr;
210 tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
211 if (tkwin2 == NULL) {
214 masterPtr = GetPacker(tkwin2);
215 prevPtr = masterPtr->slavePtr;
216 if (prevPtr != NULL) {
217 while (prevPtr->nextPtr != NULL) {
218 prevPtr = prevPtr->nextPtr;
221 return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3);
222 } else if ((c == 'b') && (strncmp(argv[1], "before", length) == 0)) {
223 Packer *packPtr, *masterPtr;
224 register Packer *prevPtr;
227 tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
228 if (tkwin2 == NULL) {
231 packPtr = GetPacker(tkwin2);
232 if (packPtr->masterPtr == NULL) {
233 Tcl_AppendResult(interp, "window \"", argv[2],
234 "\" isn't packed", (char *) NULL);
237 masterPtr = packPtr->masterPtr;
238 prevPtr = masterPtr->slavePtr;
239 if (prevPtr == packPtr) {
242 for ( ; ; prevPtr = prevPtr->nextPtr) {
243 if (prevPtr == NULL) {
244 panic("\"pack before\" couldn't find predecessor");
246 if (prevPtr->nextPtr == packPtr) {
251 return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3);
252 } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
253 if (argv[2][0] != '.') {
254 Tcl_AppendResult(interp, "bad argument \"", argv[2],
255 "\": must be name of window", (char *) NULL);
258 return ConfigureSlaves(interp, tkwin, argc-2, argv+2);
259 } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) {
264 for (i = 2; i < argc; i++) {
265 slave = Tk_NameToWindow(interp, argv[i], tkwin);
269 slavePtr = GetPacker(slave);
270 if ((slavePtr != NULL) && (slavePtr->masterPtr != NULL)) {
271 Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,
273 if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
274 Tk_UnmaintainGeometry(slavePtr->tkwin,
275 slavePtr->masterPtr->tkwin);
278 Tk_UnmapWindow(slavePtr->tkwin);
281 } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
282 register Packer *slavePtr;
285 static char *sideNames[] = {"top", "bottom", "left", "right"};
288 Tcl_AppendResult(interp, "wrong # args: should be \"",
289 argv[0], " info window\"", (char *) NULL);
292 slave = Tk_NameToWindow(interp, argv[2], tkwin);
296 slavePtr = GetPacker(slave);
297 if (slavePtr->masterPtr == NULL) {
298 Tcl_AppendResult(interp, "window \"", argv[2],
299 "\" isn't packed", (char *) NULL);
302 Tcl_AppendElement(interp, "-in");
303 Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin));
304 Tcl_AppendElement(interp, "-anchor");
305 Tcl_AppendElement(interp, Tk_NameOfAnchor(slavePtr->anchor));
306 Tcl_AppendResult(interp, " -expand ",
307 (slavePtr->flags & EXPAND) ? "1" : "0", " -fill ",
309 switch (slavePtr->flags & (FILLX|FILLY)) {
311 Tcl_AppendResult(interp, "none", (char *) NULL);
314 Tcl_AppendResult(interp, "x", (char *) NULL);
317 Tcl_AppendResult(interp, "y", (char *) NULL);
320 Tcl_AppendResult(interp, "both", (char *) NULL);
323 sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d",
324 slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2,
326 Tcl_AppendResult(interp, buffer, " -side ", sideNames[slavePtr->side],
328 } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) {
334 Tcl_AppendResult(interp, "wrong # args: should be \"",
335 argv[0], " propagate window ?boolean?\"", (char *) NULL);
338 master = Tk_NameToWindow(interp, argv[2], tkwin);
339 if (master == NULL) {
342 masterPtr = GetPacker(master);
344 if (masterPtr->flags & DONT_PROPAGATE) {
345 interp->result = "0";
347 interp->result = "1";
351 if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) {
355 masterPtr->flags &= ~DONT_PROPAGATE;
358 * Repack the master to allow new geometry information to
359 * propagate upwards to the master's master.
362 if (masterPtr->abortPtr != NULL) {
363 *masterPtr->abortPtr = 1;
365 if (!(masterPtr->flags & REQUESTED_REPACK)) {
366 masterPtr->flags |= REQUESTED_REPACK;
367 Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
370 masterPtr->flags |= DONT_PROPAGATE;
372 } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)) {
374 Packer *masterPtr, *slavePtr;
377 Tcl_AppendResult(interp, "wrong # args: should be \"",
378 argv[0], " slaves window\"", (char *) NULL);
381 master = Tk_NameToWindow(interp, argv[2], tkwin);
382 if (master == NULL) {
385 masterPtr = GetPacker(master);
386 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
387 slavePtr = slavePtr->nextPtr) {
388 Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));
390 } else if ((c == 'u') && (strncmp(argv[1], "unpack", length) == 0)) {
395 Tcl_AppendResult(interp, "wrong # args: should be \"",
396 argv[0], " unpack window\"", (char *) NULL);
399 tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
400 if (tkwin2 == NULL) {
403 packPtr = GetPacker(tkwin2);
404 if ((packPtr != NULL) && (packPtr->masterPtr != NULL)) {
405 Tk_ManageGeometry(tkwin2, (Tk_GeomMgr *) NULL,
407 if (packPtr->masterPtr->tkwin != Tk_Parent(packPtr->tkwin)) {
408 Tk_UnmaintainGeometry(packPtr->tkwin,
409 packPtr->masterPtr->tkwin);
412 Tk_UnmapWindow(packPtr->tkwin);
415 Tcl_AppendResult(interp, "bad option \"", argv[1],
416 "\": must be configure, forget, info, ",
417 "propagate, or slaves", (char *) NULL);
424 *--------------------------------------------------------------
428 * This procedure is invoked by Tk_GeometryRequest for
429 * windows managed by the packer.
435 * Arranges for tkwin, and all its managed siblings, to
436 * be re-packed at the next idle point.
438 *--------------------------------------------------------------
443 PackReqProc(clientData, tkwin)
444 ClientData clientData; /* Packer's information about
445 * window that got new preferred
447 Tk_Window tkwin; /* Other Tk-related information
448 * about the window. */
450 register Packer *packPtr = (Packer *) clientData;
452 packPtr = packPtr->masterPtr;
453 if (!(packPtr->flags & REQUESTED_REPACK)) {
454 packPtr->flags |= REQUESTED_REPACK;
455 Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
460 *--------------------------------------------------------------
462 * PackLostSlaveProc --
464 * This procedure is invoked by Tk whenever some other geometry
465 * claims control over a slave that used to be managed by us.
471 * Forgets all packer-related information about the slave.
473 *--------------------------------------------------------------
478 PackLostSlaveProc(clientData, tkwin)
479 ClientData clientData; /* Packer structure for slave window that
480 * was stolen away. */
481 Tk_Window tkwin; /* Tk's handle for the slave window. */
483 register Packer *slavePtr = (Packer *) clientData;
485 if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
486 Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);
489 Tk_UnmapWindow(slavePtr->tkwin);
493 *--------------------------------------------------------------
497 * This procedure is invoked (using the Tcl_DoWhenIdle
498 * mechanism) to re-layout a set of windows managed by
499 * the packer. It is invoked at idle time so that a
500 * series of packer requests can be merged into a single
507 * The packed slaves of masterPtr may get resized or
510 *--------------------------------------------------------------
514 ArrangePacking(clientData)
515 ClientData clientData; /* Structure describing parent whose slaves
516 * are to be re-layed out. */
518 register Packer *masterPtr = (Packer *) clientData;
519 register Packer *slavePtr;
520 int cavityX, cavityY, cavityWidth, cavityHeight;
521 /* These variables keep track of the
522 * as-yet-unallocated space remaining in
523 * the middle of the parent window. */
524 int frameX, frameY, frameWidth, frameHeight;
525 /* These variables keep track of the frame
526 * allocated to the current window. */
527 int x, y, width, height; /* These variables are used to hold the
528 * actual geometry of the current window. */
529 int intBWidth; /* Width of internal border in parent window,
531 int abort; /* May get set to non-zero to abort this
532 * repacking operation. */
533 int borderX, borderY;
534 int maxWidth, maxHeight, tmp;
536 masterPtr->flags &= ~REQUESTED_REPACK;
539 * If the parent has no slaves anymore, then don't do anything
540 * at all: just leave the parent's size as-is.
543 if (masterPtr->slavePtr == NULL) {
548 * Abort any nested call to ArrangePacking for this window, since
549 * we'll do everything necessary here, and set up so this call
550 * can be aborted if necessary.
553 if (masterPtr->abortPtr != NULL) {
554 *masterPtr->abortPtr = 1;
556 masterPtr->abortPtr = &abort;
558 Tcl_Preserve((ClientData) masterPtr);
561 * Pass #1: scan all the slaves to figure out the total amount
562 * of space needed. Two separate width and height values are
565 * width - Holds the sum of the widths (plus padding) of
566 * all the slaves seen so far that were packed LEFT
568 * height - Holds the sum of the heights (plus padding) of
569 * all the slaves seen so far that were packed TOP
572 * maxWidth - Gradually builds up the width needed by the master
573 * to just barely satisfy all the slave's needs. For
574 * each slave, the code computes the width needed for
575 * all the slaves so far and updates maxWidth if the
576 * new value is greater.
577 * maxHeight - Same as maxWidth, except keeps height info.
580 intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin);
581 width = height = maxWidth = maxHeight = 2*intBWidth;
582 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
583 slavePtr = slavePtr->nextPtr) {
584 if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
585 tmp = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
586 + slavePtr->padX + slavePtr->iPadX + width;
587 if (tmp > maxWidth) {
590 height += Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
591 + slavePtr->padY + slavePtr->iPadY;
593 tmp = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
594 + slavePtr->padY + slavePtr->iPadY + height;
595 if (tmp > maxHeight) {
598 width += Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
599 + slavePtr->padX + slavePtr->iPadX;
602 if (width > maxWidth) {
605 if (height > maxHeight) {
610 * If the total amount of space needed in the parent window has
611 * changed, and if we're propagating geometry information, then
612 * notify the next geometry manager up and requeue ourselves to
613 * start again after the parent has had a chance to
617 if (((maxWidth != Tk_ReqWidth(masterPtr->tkwin))
618 || (maxHeight != Tk_ReqHeight(masterPtr->tkwin)))
619 && !(masterPtr->flags & DONT_PROPAGATE)) {
620 Tk_GeometryRequest(masterPtr->tkwin, maxWidth, maxHeight);
621 masterPtr->flags |= REQUESTED_REPACK;
622 Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
627 * Pass #2: scan the slaves a second time assigning
628 * new sizes. The "cavity" variables keep track of the
629 * unclaimed space in the cavity of the window; this
630 * shrinks inward as we allocate windows around the
631 * edges. The "frame" variables keep track of the space
632 * allocated to the current window and its frame. The
633 * current window is then placed somewhere inside the
634 * frame, depending on anchor.
637 cavityX = cavityY = x = y = intBWidth;
638 cavityWidth = Tk_Width(masterPtr->tkwin) - 2*intBWidth;
639 cavityHeight = Tk_Height(masterPtr->tkwin) - 2*intBWidth;
640 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
641 slavePtr = slavePtr->nextPtr) {
642 if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
643 frameWidth = cavityWidth;
644 frameHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
645 + slavePtr->padY + slavePtr->iPadY;
646 if (slavePtr->flags & EXPAND) {
647 frameHeight += YExpansion(slavePtr, cavityHeight);
649 cavityHeight -= frameHeight;
650 if (cavityHeight < 0) {
651 frameHeight += cavityHeight;
655 if (slavePtr->side == TOP) {
657 cavityY += frameHeight;
659 frameY = cavityY + cavityHeight;
662 frameHeight = cavityHeight;
663 frameWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
664 + slavePtr->padX + slavePtr->iPadX;
665 if (slavePtr->flags & EXPAND) {
666 frameWidth += XExpansion(slavePtr, cavityWidth);
668 cavityWidth -= frameWidth;
669 if (cavityWidth < 0) {
670 frameWidth += cavityWidth;
674 if (slavePtr->side == LEFT) {
676 cavityX += frameWidth;
678 frameX = cavityX + cavityWidth;
683 * Now that we've got the size of the frame for the window,
684 * compute the window's actual size and location using the
685 * fill, padding, and frame factors. The variables "borderX"
686 * and "borderY" are used to handle the differences between
687 * old-style packing and the new style (in old-style, iPadX
688 * and iPadY are always zero and padding is completely ignored
689 * except when computing frame size).
692 if (slavePtr->flags & OLD_STYLE) {
693 borderX = borderY = 0;
695 borderX = slavePtr->padX;
696 borderY = slavePtr->padY;
698 width = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
700 if ((slavePtr->flags & FILLX)
701 || (width > (frameWidth - borderX))) {
702 width = frameWidth - borderX;
704 height = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
706 if ((slavePtr->flags & FILLY)
707 || (height > (frameHeight - borderY))) {
708 height = frameHeight - borderY;
712 switch (slavePtr->anchor) {
714 x = frameX + (frameWidth - width)/2;
715 y = frameY + borderY;
718 x = frameX + frameWidth - width - borderX;
719 y = frameY + borderY;
722 x = frameX + frameWidth - width - borderX;
723 y = frameY + (frameHeight - height)/2;
726 x = frameX + frameWidth - width - borderX;
727 y = frameY + frameHeight - height - borderY;
730 x = frameX + (frameWidth - width)/2;
731 y = frameY + frameHeight - height - borderY;
734 x = frameX + borderX;
735 y = frameY + frameHeight - height - borderY;
738 x = frameX + borderX;
739 y = frameY + (frameHeight - height)/2;
742 x = frameX + borderX;
743 y = frameY + borderY;
745 case TK_ANCHOR_CENTER:
746 x = frameX + (frameWidth - width)/2;
747 y = frameY + (frameHeight - height)/2;
750 panic("bad frame factor in ArrangePacking");
752 width -= slavePtr->doubleBw;
753 height -= slavePtr->doubleBw;
756 * The final step is to set the position, size, and mapped/unmapped
757 * state of the slave. If the slave is a child of the master, then
758 * do this here. Otherwise let Tk_MaintainGeometry do the work.
761 if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) {
762 if ((width <= 0) || (height <= 0)) {
763 Tk_UnmapWindow(slavePtr->tkwin);
765 if ((x != Tk_X(slavePtr->tkwin))
766 || (y != Tk_Y(slavePtr->tkwin))
767 || (width != Tk_Width(slavePtr->tkwin))
768 || (height != Tk_Height(slavePtr->tkwin))) {
769 Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);
776 * Don't map the slave if the master isn't mapped: wait
777 * until the master gets mapped later.
780 if (Tk_IsMapped(masterPtr->tkwin)) {
781 Tk_MapWindow(slavePtr->tkwin);
785 if ((width <= 0) || (height <= 0)) {
786 Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin);
787 Tk_UnmapWindow(slavePtr->tkwin);
789 Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin,
790 x, y, width, height);
795 * Changes to the window's structure could cause almost anything
796 * to happen, including deleting the parent or child. If this
797 * happens, we'll be told to abort.
806 masterPtr->abortPtr = NULL;
807 Tcl_Release((ClientData) masterPtr);
811 *----------------------------------------------------------------------
815 * Given a list of packed slaves, the first of which is packed
816 * on the left or right and is expandable, compute how much to
820 * The return value is the number of additional pixels to give to
826 *----------------------------------------------------------------------
830 XExpansion(slavePtr, cavityWidth)
831 register Packer *slavePtr; /* First in list of remaining
833 int cavityWidth; /* Horizontal space left for all
834 * remaining slaves. */
836 int numExpand, minExpand, curExpand;
840 * This procedure is tricky because windows packed top or bottom can
841 * be interspersed among expandable windows packed left or right.
842 * Scan through the list, keeping a running sum of the widths of
843 * all left and right windows (actually, count the cavity space not
844 * allocated) and a running count of all expandable left and right
845 * windows. At each top or bottom window, and at the end of the
846 * list, compute the expansion factor that seems reasonable at that
847 * point. Return the smallest factor seen at any of these points.
850 minExpand = cavityWidth;
852 for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) {
853 childWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
854 + slavePtr->padX + slavePtr->iPadX;
855 if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
856 curExpand = (cavityWidth - childWidth)/numExpand;
857 if (curExpand < minExpand) {
858 minExpand = curExpand;
861 cavityWidth -= childWidth;
862 if (slavePtr->flags & EXPAND) {
867 curExpand = cavityWidth/numExpand;
868 if (curExpand < minExpand) {
869 minExpand = curExpand;
871 return (minExpand < 0) ? 0 : minExpand;
875 *----------------------------------------------------------------------
879 * Given a list of packed slaves, the first of which is packed
880 * on the top or bottom and is expandable, compute how much to
884 * The return value is the number of additional pixels to give to
890 *----------------------------------------------------------------------
894 YExpansion(slavePtr, cavityHeight)
895 register Packer *slavePtr; /* First in list of remaining
897 int cavityHeight; /* Vertical space left for all
898 * remaining slaves. */
900 int numExpand, minExpand, curExpand;
904 * See comments for XExpansion.
907 minExpand = cavityHeight;
909 for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) {
910 childHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
911 + slavePtr->padY + slavePtr->iPadY;
912 if ((slavePtr->side == LEFT) || (slavePtr->side == RIGHT)) {
913 curExpand = (cavityHeight - childHeight)/numExpand;
914 if (curExpand < minExpand) {
915 minExpand = curExpand;
918 cavityHeight -= childHeight;
919 if (slavePtr->flags & EXPAND) {
924 curExpand = cavityHeight/numExpand;
925 if (curExpand < minExpand) {
926 minExpand = curExpand;
928 return (minExpand < 0) ? 0 : minExpand;
932 *--------------------------------------------------------------
936 * This internal procedure is used to locate a Packer
937 * structure for a given window, creating one if one
938 * doesn't exist already.
941 * The return value is a pointer to the Packer structure
942 * corresponding to tkwin.
945 * A new packer structure may be created. If so, then
946 * a callback is set up to clean things up when the
949 *--------------------------------------------------------------
954 Tk_Window tkwin; /* Token for window for which
955 * packer structure is desired. */
957 register Packer *packPtr;
963 Tcl_InitHashTable(&packerHashTable, TCL_ONE_WORD_KEYS);
967 * See if there's already packer for this window. If not,
968 * then create a new one.
971 hPtr = Tcl_CreateHashEntry(&packerHashTable, (char *) tkwin, &new);
973 return (Packer *) Tcl_GetHashValue(hPtr);
975 packPtr = (Packer *) ckalloc(sizeof(Packer));
976 packPtr->tkwin = tkwin;
977 packPtr->masterPtr = NULL;
978 packPtr->nextPtr = NULL;
979 packPtr->slavePtr = NULL;
981 packPtr->anchor = TK_ANCHOR_CENTER;
982 packPtr->padX = packPtr->padY = 0;
983 packPtr->iPadX = packPtr->iPadY = 0;
984 packPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
985 packPtr->abortPtr = NULL;
987 Tcl_SetHashValue(hPtr, packPtr);
988 Tk_CreateEventHandler(tkwin, StructureNotifyMask,
989 PackStructureProc, (ClientData) packPtr);
994 *--------------------------------------------------------------
998 * This procedure does most of the real work of adding
999 * one or more windows into the packing order for its parent.
1002 * A standard Tcl return value.
1005 * The geometry of the specified windows may change, both now and
1006 * again in the future.
1008 *--------------------------------------------------------------
1012 PackAfter(interp, prevPtr, masterPtr, argc, argv)
1013 Tcl_Interp *interp; /* Interpreter for error reporting. */
1014 Packer *prevPtr; /* Pack windows in argv just after this
1015 * window; NULL means pack as first
1016 * child of masterPtr. */
1017 Packer *masterPtr; /* Master in which to pack windows. */
1018 int argc; /* Number of elements in argv. */
1019 char **argv; /* Array of lists, each containing 2
1020 * elements: window name and side
1021 * against which to pack. */
1023 register Packer *packPtr;
1024 Tk_Window tkwin, ancestor, parent;
1027 int index, tmp, optionCount, c;
1030 * Iterate over all of the window specifiers, each consisting of
1031 * two arguments. The first argument contains the window name and
1032 * the additional arguments contain options such as "top" or
1036 for ( ; argc > 0; argc -= 2, argv += 2, prevPtr = packPtr) {
1038 Tcl_AppendResult(interp, "wrong # args: window \"",
1039 argv[0], "\" should be followed by options",
1045 * Find the packer for the window to be packed, and make sure
1046 * that the window in which it will be packed is either its
1047 * or a descendant of its parent.
1050 tkwin = Tk_NameToWindow(interp, argv[0], masterPtr->tkwin);
1051 if (tkwin == NULL) {
1055 parent = Tk_Parent(tkwin);
1056 for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
1057 if (ancestor == parent) {
1060 if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) {
1062 Tcl_AppendResult(interp, "can't pack ", argv[0],
1063 " inside ", Tk_PathName(masterPtr->tkwin),
1068 if (((Tk_FakeWin *) (tkwin))->flags & TK_TOP_LEVEL) {
1071 if (tkwin == masterPtr->tkwin) {
1074 packPtr = GetPacker(tkwin);
1077 * Process options for this window.
1080 if (Tcl_SplitList(interp, argv[1], &optionCount, &options) != TCL_OK) {
1083 packPtr->side = TOP;
1084 packPtr->anchor = TK_ANCHOR_CENTER;
1085 packPtr->padX = packPtr->padY = 0;
1086 packPtr->iPadX = packPtr->iPadY = 0;
1087 packPtr->flags &= ~(FILLX|FILLY|EXPAND);
1088 packPtr->flags |= OLD_STYLE;
1089 for (index = 0 ; index < optionCount; index++) {
1090 char *curOpt = options[index];
1093 length = strlen(curOpt);
1096 && (strncmp(curOpt, "top", length)) == 0) {
1097 packPtr->side = TOP;
1098 } else if ((c == 'b')
1099 && (strncmp(curOpt, "bottom", length)) == 0) {
1100 packPtr->side = BOTTOM;
1101 } else if ((c == 'l')
1102 && (strncmp(curOpt, "left", length)) == 0) {
1103 packPtr->side = LEFT;
1104 } else if ((c == 'r')
1105 && (strncmp(curOpt, "right", length)) == 0) {
1106 packPtr->side = RIGHT;
1107 } else if ((c == 'e')
1108 && (strncmp(curOpt, "expand", length)) == 0) {
1109 packPtr->flags |= EXPAND;
1110 } else if ((c == 'f')
1111 && (strcmp(curOpt, "fill")) == 0) {
1112 packPtr->flags |= FILLX|FILLY;
1113 } else if ((length == 5) && (strcmp(curOpt, "fillx")) == 0) {
1114 packPtr->flags |= FILLX;
1115 } else if ((length == 5) && (strcmp(curOpt, "filly")) == 0) {
1116 packPtr->flags |= FILLY;
1117 } else if ((c == 'p') && (strcmp(curOpt, "padx")) == 0) {
1118 if (optionCount < (index+2)) {
1120 Tcl_AppendResult(interp, "wrong # args: \"", curOpt,
1121 "\" option must be followed by screen distance",
1125 if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp)
1126 != TCL_OK) || (tmp < 0)) {
1128 Tcl_AppendResult(interp, "bad pad value \"",
1130 "\": must be positive screen distance",
1134 packPtr->padX = tmp;
1137 } else if ((c == 'p') && (strcmp(curOpt, "pady")) == 0) {
1138 if (optionCount < (index+2)) {
1141 if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp)
1142 != TCL_OK) || (tmp < 0)) {
1145 packPtr->padY = tmp;
1148 } else if ((c == 'f') && (length > 1)
1149 && (strncmp(curOpt, "frame", length) == 0)) {
1150 if (optionCount < (index+2)) {
1151 Tcl_AppendResult(interp, "wrong # args: \"frame\" ",
1152 "option must be followed by anchor point",
1156 if (Tk_GetAnchor(interp, options[index+1],
1157 &packPtr->anchor) != TCL_OK) {
1162 Tcl_AppendResult(interp, "bad option \"", curOpt,
1163 "\": should be top, bottom, left, right, ",
1164 "expand, fill, fillx, filly, padx, pady, or frame",
1170 if (packPtr != prevPtr) {
1173 * Unpack this window if it's currently packed.
1176 if (packPtr->masterPtr != NULL) {
1177 if ((packPtr->masterPtr != masterPtr) &&
1178 (packPtr->masterPtr->tkwin
1179 != Tk_Parent(packPtr->tkwin))) {
1180 Tk_UnmaintainGeometry(packPtr->tkwin,
1181 packPtr->masterPtr->tkwin);
1187 * Add the window in the correct place in its parent's
1188 * packing order, then make sure that the window is
1192 packPtr->masterPtr = masterPtr;
1193 if (prevPtr == NULL) {
1194 packPtr->nextPtr = masterPtr->slavePtr;
1195 masterPtr->slavePtr = packPtr;
1197 packPtr->nextPtr = prevPtr->nextPtr;
1198 prevPtr->nextPtr = packPtr;
1200 Tk_ManageGeometry(tkwin, &packerType, (ClientData) packPtr);
1202 ckfree((char *) options);
1206 * Arrange for the parent to be re-packed at the first
1210 if (masterPtr->abortPtr != NULL) {
1211 *masterPtr->abortPtr = 1;
1213 if (!(masterPtr->flags & REQUESTED_REPACK)) {
1214 masterPtr->flags |= REQUESTED_REPACK;
1215 Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
1220 ckfree((char *) options);
1225 *----------------------------------------------------------------------
1229 * Remove a packer from its parent's list of slaves.
1235 * The parent will be scheduled for repacking.
1237 *----------------------------------------------------------------------
1242 register Packer *packPtr; /* Window to unlink. */
1244 register Packer *masterPtr, *packPtr2;
1246 masterPtr = packPtr->masterPtr;
1247 if (masterPtr == NULL) {
1250 if (masterPtr->slavePtr == packPtr) {
1251 masterPtr->slavePtr = packPtr->nextPtr;
1253 for (packPtr2 = masterPtr->slavePtr; ; packPtr2 = packPtr2->nextPtr) {
1254 if (packPtr2 == NULL) {
1255 panic("Unlink couldn't find previous window");
1257 if (packPtr2->nextPtr == packPtr) {
1258 packPtr2->nextPtr = packPtr->nextPtr;
1263 if (!(masterPtr->flags & REQUESTED_REPACK)) {
1264 masterPtr->flags |= REQUESTED_REPACK;
1265 Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
1267 if (masterPtr->abortPtr != NULL) {
1268 *masterPtr->abortPtr = 1;
1271 packPtr->masterPtr = NULL;
1275 *----------------------------------------------------------------------
1279 * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
1280 * to clean up the internal structure of a packer at a safe time
1281 * (when no-one is using it anymore).
1287 * Everything associated with the packer is freed up.
1289 *----------------------------------------------------------------------
1293 DestroyPacker(memPtr)
1294 char *memPtr; /* Info about packed window that
1297 register Packer *packPtr = (Packer *) memPtr;
1298 ckfree((char *) packPtr);
1302 *----------------------------------------------------------------------
1304 * PackStructureProc --
1306 * This procedure is invoked by the Tk event dispatcher in response
1307 * to StructureNotify events.
1313 * If a window was just deleted, clean up all its packer-related
1314 * information. If it was just resized, repack its slaves, if
1317 *----------------------------------------------------------------------
1321 PackStructureProc(clientData, eventPtr)
1322 ClientData clientData; /* Our information about window
1323 * referred to by eventPtr. */
1324 XEvent *eventPtr; /* Describes what just happened. */
1326 register Packer *packPtr = (Packer *) clientData;
1327 if (eventPtr->type == ConfigureNotify) {
1328 if ((packPtr->slavePtr != NULL)
1329 && !(packPtr->flags & REQUESTED_REPACK)) {
1330 packPtr->flags |= REQUESTED_REPACK;
1331 Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
1333 if (packPtr->doubleBw != 2*Tk_Changes(packPtr->tkwin)->border_width) {
1334 if ((packPtr->masterPtr != NULL)
1335 && !(packPtr->masterPtr->flags & REQUESTED_REPACK)) {
1336 packPtr->doubleBw = 2*Tk_Changes(packPtr->tkwin)->border_width;
1337 packPtr->masterPtr->flags |= REQUESTED_REPACK;
1338 Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr->masterPtr);
1341 } else if (eventPtr->type == DestroyNotify) {
1342 register Packer *slavePtr, *nextPtr;
1344 if (packPtr->masterPtr != NULL) {
1347 for (slavePtr = packPtr->slavePtr; slavePtr != NULL;
1348 slavePtr = nextPtr) {
1349 Tk_ManageGeometry(slavePtr->tkwin, (Tk_GeomMgr *) NULL,
1351 Tk_UnmapWindow(slavePtr->tkwin);
1352 slavePtr->masterPtr = NULL;
1353 nextPtr = slavePtr->nextPtr;
1354 slavePtr->nextPtr = NULL;
1356 Tcl_DeleteHashEntry(Tcl_FindHashEntry(&packerHashTable,
1357 (char *) packPtr->tkwin));
1358 if (packPtr->flags & REQUESTED_REPACK) {
1359 Tcl_CancelIdleCall(ArrangePacking, (ClientData) packPtr);
1361 packPtr->tkwin = NULL;
1362 Tcl_EventuallyFree((ClientData) packPtr, DestroyPacker);
1363 } else if (eventPtr->type == MapNotify) {
1365 * When a master gets mapped, must redo the geometry computation
1366 * so that all of its slaves get remapped.
1369 if ((packPtr->slavePtr != NULL)
1370 && !(packPtr->flags & REQUESTED_REPACK)) {
1371 packPtr->flags |= REQUESTED_REPACK;
1372 Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
1374 } else if (eventPtr->type == UnmapNotify) {
1378 * Unmap all of the slaves when the master gets unmapped,
1379 * so that they don't bother to keep redisplaying
1383 for (packPtr2 = packPtr->slavePtr; packPtr2 != NULL;
1384 packPtr2 = packPtr2->nextPtr) {
1385 Tk_UnmapWindow(packPtr2->tkwin);
1391 *----------------------------------------------------------------------
1393 * ConfigureSlaves --
1395 * This implements the guts of the "pack configure" command. Given
1396 * a list of slaves and configuration options, it arranges for the
1397 * packer to manage the slaves and sets the specified options.
1400 * TCL_OK is returned if all went well. Otherwise, TCL_ERROR is
1401 * returned and interp->result is set to contain an error message.
1404 * Slave windows get taken over by the packer.
1406 *----------------------------------------------------------------------
1410 ConfigureSlaves(interp, tkwin, argc, argv)
1411 Tcl_Interp *interp; /* Interpreter for error reporting. */
1412 Tk_Window tkwin; /* Any window in application containing
1413 * slaves. Used to look up slave names. */
1414 int argc; /* Number of elements in argv. */
1415 char *argv[]; /* Argument strings: contains one or more
1416 * window names followed by any number
1417 * of "option value" pairs. Caller must
1418 * make sure that there is at least one
1421 Packer *masterPtr, *slavePtr, *prevPtr, *otherPtr;
1422 Tk_Window other, slave, parent, ancestor;
1423 int i, j, numWindows, c, tmp, positionGiven;
1427 * Find out how many windows are specified.
1430 for (numWindows = 0; numWindows < argc; numWindows++) {
1431 if (argv[numWindows][0] != '.') {
1437 * Iterate over all of the slave windows, parsing the configuration
1438 * options for each slave. It's a bit wasteful to re-parse the
1439 * options for each slave, but things get too messy if we try to
1440 * parse the arguments just once at the beginning. For example,
1441 * if a slave already is packed we want to just change a few
1442 * existing values without resetting everything. If there are
1443 * multiple windows, the -after, -before, and -in options only
1444 * get processed for the first window.
1450 for (j = 0; j < numWindows; j++) {
1451 slave = Tk_NameToWindow(interp, argv[j], tkwin);
1452 if (slave == NULL) {
1455 if (Tk_IsTopLevel(slave)) {
1456 Tcl_AppendResult(interp, "can't pack \"", argv[j],
1457 "\": it's a top-level window", (char *) NULL);
1460 slavePtr = GetPacker(slave);
1461 slavePtr->flags &= ~OLD_STYLE;
1464 * If the slave isn't currently packed, reset all of its
1465 * configuration information to default values (there could
1466 * be old values left from a previous packing).
1469 if (slavePtr->masterPtr == NULL) {
1470 slavePtr->side = TOP;
1471 slavePtr->anchor = TK_ANCHOR_CENTER;
1472 slavePtr->padX = slavePtr->padY = 0;
1473 slavePtr->iPadX = slavePtr->iPadY = 0;
1474 slavePtr->flags &= ~(FILLX|FILLY|EXPAND);
1477 for (i = numWindows; i < argc; i+=2) {
1479 Tcl_AppendResult(interp, "extra option \"", argv[i],
1480 "\" (option with no value?)", (char *) NULL);
1483 length = strlen(argv[i]);
1488 if ((c == 'a') && (strncmp(argv[i], "-after", length) == 0)
1491 other = Tk_NameToWindow(interp, argv[i+1], tkwin);
1492 if (other == NULL) {
1495 prevPtr = GetPacker(other);
1496 if (prevPtr->masterPtr == NULL) {
1498 Tcl_AppendResult(interp, "window \"", argv[i+1],
1499 "\" isn't packed", (char *) NULL);
1502 masterPtr = prevPtr->masterPtr;
1505 } else if ((c == 'a') && (strncmp(argv[i], "-anchor", length) == 0)
1507 if (Tk_GetAnchor(interp, argv[i+1], &slavePtr->anchor)
1511 } else if ((c == 'b')
1512 && (strncmp(argv[i], "-before", length) == 0)) {
1514 other = Tk_NameToWindow(interp, argv[i+1], tkwin);
1515 if (other == NULL) {
1518 otherPtr = GetPacker(other);
1519 if (otherPtr->masterPtr == NULL) {
1522 masterPtr = otherPtr->masterPtr;
1523 prevPtr = masterPtr->slavePtr;
1524 if (prevPtr == otherPtr) {
1527 while (prevPtr->nextPtr != otherPtr) {
1528 prevPtr = prevPtr->nextPtr;
1533 } else if ((c == 'e')
1534 && (strncmp(argv[i], "-expand", length) == 0)) {
1535 if (Tcl_GetBoolean(interp, argv[i+1], &tmp) != TCL_OK) {
1538 slavePtr->flags &= ~EXPAND;
1540 slavePtr->flags |= EXPAND;
1542 } else if ((c == 'f') && (strncmp(argv[i], "-fill", length) == 0)) {
1543 if (strcmp(argv[i+1], "none") == 0) {
1544 slavePtr->flags &= ~(FILLX|FILLY);
1545 } else if (strcmp(argv[i+1], "x") == 0) {
1546 slavePtr->flags = (slavePtr->flags & ~FILLY) | FILLX;
1547 } else if (strcmp(argv[i+1], "y") == 0) {
1548 slavePtr->flags = (slavePtr->flags & ~FILLX) | FILLY;
1549 } else if (strcmp(argv[i+1], "both") == 0) {
1550 slavePtr->flags |= FILLX|FILLY;
1552 Tcl_AppendResult(interp, "bad fill style \"", argv[i+1],
1553 "\": must be none, x, y, or both", (char *) NULL);
1556 } else if ((c == 'i') && (strcmp(argv[i], "-in") == 0)) {
1558 other = Tk_NameToWindow(interp, argv[i+1], tkwin);
1559 if (other == NULL) {
1562 masterPtr = GetPacker(other);
1563 prevPtr = masterPtr->slavePtr;
1564 if (prevPtr != NULL) {
1565 while (prevPtr->nextPtr != NULL) {
1566 prevPtr = prevPtr->nextPtr;
1571 } else if ((c == 'i') && (strcmp(argv[i], "-ipadx") == 0)) {
1572 if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
1575 Tcl_ResetResult(interp);
1576 Tcl_AppendResult(interp, "bad pad value \"", argv[i+1],
1577 "\": must be positive screen distance",
1581 slavePtr->iPadX = tmp*2;
1582 } else if ((c == 'i') && (strcmp(argv[i], "-ipady") == 0)) {
1583 if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
1587 slavePtr->iPadY = tmp*2;
1588 } else if ((c == 'p') && (strcmp(argv[i], "-padx") == 0)) {
1589 if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
1593 slavePtr->padX = tmp*2;
1594 } else if ((c == 'p') && (strcmp(argv[i], "-pady") == 0)) {
1595 if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
1599 slavePtr->padY = tmp*2;
1600 } else if ((c == 's') && (strncmp(argv[i], "-side", length) == 0)) {
1602 if ((c == 't') && (strcmp(argv[i+1], "top") == 0)) {
1603 slavePtr->side = TOP;
1604 } else if ((c == 'b') && (strcmp(argv[i+1], "bottom") == 0)) {
1605 slavePtr->side = BOTTOM;
1606 } else if ((c == 'l') && (strcmp(argv[i+1], "left") == 0)) {
1607 slavePtr->side = LEFT;
1608 } else if ((c == 'r') && (strcmp(argv[i+1], "right") == 0)) {
1609 slavePtr->side = RIGHT;
1611 Tcl_AppendResult(interp, "bad side \"", argv[i+1],
1612 "\": must be top, bottom, left, or right",
1618 Tcl_AppendResult(interp, "unknown or ambiguous option \"",
1619 argv[i], "\": must be -after, -anchor, -before, ",
1620 "-expand, -fill, -in, -ipadx, -ipady, -padx, ",
1621 "-pady, or -side", (char *) NULL);
1627 * If no position in a packing list was specified and the slave
1628 * is already packed, then leave it in its current location in
1629 * its current packing list.
1632 if (!positionGiven && (slavePtr->masterPtr != NULL)) {
1633 masterPtr = slavePtr->masterPtr;
1634 goto scheduleLayout;
1638 * If the slave is going to be put back after itself then
1639 * skip the whole operation, since it won't work anyway.
1642 if (prevPtr == slavePtr) {
1643 masterPtr = slavePtr->masterPtr;
1644 goto scheduleLayout;
1648 * If none of the "-in", "-before", or "-after" options has
1649 * been specified, arrange for the slave to go at the end of
1650 * the order for its parent.
1653 if (!positionGiven) {
1654 masterPtr = GetPacker(Tk_Parent(slave));
1655 prevPtr = masterPtr->slavePtr;
1656 if (prevPtr != NULL) {
1657 while (prevPtr->nextPtr != NULL) {
1658 prevPtr = prevPtr->nextPtr;
1664 * Make sure that the slave's parent is either the master or
1665 * an ancestor of the master, and that the master and slave
1669 parent = Tk_Parent(slave);
1670 for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
1671 if (ancestor == parent) {
1674 if (Tk_IsTopLevel(ancestor)) {
1675 Tcl_AppendResult(interp, "can't pack ", argv[j],
1676 " inside ", Tk_PathName(masterPtr->tkwin),
1681 if (slave == masterPtr->tkwin) {
1682 Tcl_AppendResult(interp, "can't pack ", argv[j],
1683 " inside itself", (char *) NULL);
1688 * Unpack the slave if it's currently packed, then position it
1692 if (slavePtr->masterPtr != NULL) {
1693 if ((slavePtr->masterPtr != masterPtr) &&
1694 (slavePtr->masterPtr->tkwin
1695 != Tk_Parent(slavePtr->tkwin))) {
1696 Tk_UnmaintainGeometry(slavePtr->tkwin,
1697 slavePtr->masterPtr->tkwin);
1701 slavePtr->masterPtr = masterPtr;
1702 if (prevPtr == NULL) {
1703 slavePtr->nextPtr = masterPtr->slavePtr;
1704 masterPtr->slavePtr = slavePtr;
1706 slavePtr->nextPtr = prevPtr->nextPtr;
1707 prevPtr->nextPtr = slavePtr;
1709 Tk_ManageGeometry(slave, &packerType, (ClientData) slavePtr);
1713 * Arrange for the parent to be re-packed at the first
1718 if (masterPtr->abortPtr != NULL) {
1719 *masterPtr->abortPtr = 1;
1721 if (!(masterPtr->flags & REQUESTED_REPACK)) {
1722 masterPtr->flags |= REQUESTED_REPACK;
1723 Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);