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-1997 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;
20 static CONST char *sideNames[] = {
21 "top", "bottom", "left", "right", (char *) NULL
24 /* For each window that the packer cares about (either because
25 * the window is managed by the packer or because the window
26 * has slaves that are managed by the packer), there is a
27 * structure of the following type:
30 typedef struct Packer {
31 Tk_Window tkwin; /* Tk token for window. NULL means that
32 * the window has been deleted, but the
33 * packet hasn't had a chance to clean up
34 * yet because the structure is still in
36 struct Packer *masterPtr; /* Master window within which this window
37 * is packed (NULL means this window
38 * isn't managed by the packer). */
39 struct Packer *nextPtr; /* Next window packed within same
40 * parent. List is priority-ordered:
41 * first on list gets packed first. */
42 struct Packer *slavePtr; /* First in list of slaves packed
43 * inside this window (NULL means
44 * no packed slaves). */
45 Side side; /* Side of parent against which
46 * this window is packed. */
47 Tk_Anchor anchor; /* If frame allocated for window is larger
48 * than window needs, this indicates how
49 * where to position window in frame. */
50 int padX, padY; /* Total additional pixels to leave around the
51 * window. Some is of this space is on each
52 * side. This is space *outside* the window:
53 * we'll allocate extra space in frame but
54 * won't enlarge window). */
55 int padLeft, padTop; /* The part of padX or padY to use on the
56 * left or top of the widget, respectively.
57 * By default, this is half of padX or padY. */
58 int iPadX, iPadY; /* Total extra pixels to allocate inside the
59 * window (half of this amount will appear on
61 int doubleBw; /* Twice the window's last known border
62 * width. If this changes, the window
63 * must be repacked within its parent. */
64 int *abortPtr; /* If non-NULL, it means that there is a nested
65 * call to ArrangePacking already working on
66 * this window. *abortPtr may be set to 1 to
67 * abort that nested call. This happens, for
68 * example, if tkwin or any of its slaves
70 int flags; /* Miscellaneous flags; see below
75 * Flag values for Packer structures:
77 * REQUESTED_REPACK: 1 means a Tcl_DoWhenIdle request
78 * has already been made to repack
79 * all the slaves of this window.
80 * FILLX: 1 means if frame allocated for window
81 * is wider than window needs, expand window
82 * to fill frame. 0 means don't make window
83 * any larger than needed.
84 * FILLY: Same as FILLX, except for height.
85 * EXPAND: 1 means this window's frame will absorb any
86 * extra space in the parent window.
87 * OLD_STYLE: 1 means this window is being managed with
88 * the old-style packer algorithms (before
89 * Tk version 3.3). The main difference is
90 * that padding and filling are done differently.
91 * DONT_PROPAGATE: 1 means don't set this window's requested
92 * size. 0 means if this window is a master
93 * then Tk will set its requested size to fit
94 * the needs of its slaves.
97 #define REQUESTED_REPACK 1
102 #define DONT_PROPAGATE 32
105 * The following structure is the official type record for the
109 static void PackReqProc _ANSI_ARGS_((ClientData clientData,
111 static void PackLostSlaveProc _ANSI_ARGS_((ClientData clientData,
114 static Tk_GeomMgr packerType = {
116 PackReqProc, /* requestProc */
117 PackLostSlaveProc, /* lostSlaveProc */
121 * Forward declarations for procedures defined later in this file:
124 static void ArrangePacking _ANSI_ARGS_((ClientData clientData));
125 static int ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp,
126 Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[]));
127 static void DestroyPacker _ANSI_ARGS_((char *memPtr));
128 static Packer * GetPacker _ANSI_ARGS_((Tk_Window tkwin));
129 static int PackAfter _ANSI_ARGS_((Tcl_Interp *interp,
130 Packer *prevPtr, Packer *masterPtr, int objc,
131 Tcl_Obj *CONST objv[]));
132 static void PackReqProc _ANSI_ARGS_((ClientData clientData,
134 static void PackStructureProc _ANSI_ARGS_((ClientData clientData,
136 static void Unlink _ANSI_ARGS_((Packer *packPtr));
137 static int XExpansion _ANSI_ARGS_((Packer *slavePtr,
139 static int YExpansion _ANSI_ARGS_((Packer *slavePtr,
143 *--------------------------------------------------------------
145 * TkPrintPadAmount --
147 * This procedure generates a text value that describes one
148 * of the -padx, -pady, -ipadx, or -ipady configuration options.
149 * The text value generated is appended to the interpreter
158 *--------------------------------------------------------------
161 TkPrintPadAmount(interp, switchName, halfSpace, allSpace)
162 Tcl_Interp *interp; /* The interpreter into which the result
164 char *switchName; /* One of "padx", "pady", "ipadx" or "ipady" */
165 int halfSpace; /* The left or top padding amount */
166 int allSpace; /* The total amount of padding */
168 char buffer[60 + 2*TCL_INTEGER_SPACE];
169 if (halfSpace*2 == allSpace) {
170 sprintf(buffer, " -%.10s %d", switchName, halfSpace);
172 sprintf(buffer, " -%.10s {%d %d}", switchName, halfSpace,
173 allSpace - halfSpace);
175 Tcl_AppendResult(interp, buffer, (char *)NULL);
180 *--------------------------------------------------------------
184 * This procedure is invoked to process the "pack" Tcl command.
185 * See the user documentation for details on what it does.
188 * A standard Tcl result.
191 * See the user documentation.
193 *--------------------------------------------------------------
197 Tk_PackObjCmd(clientData, interp, objc, objv)
198 ClientData clientData; /* Main window associated with
200 Tcl_Interp *interp; /* Current interpreter. */
201 int objc; /* Number of arguments. */
202 Tcl_Obj *CONST objv[]; /* Argument objects. */
204 Tk_Window tkwin = (Tk_Window) clientData;
206 static CONST char *optionStrings[] = {
207 /* after, append, before and unpack are deprecated */
208 "after", "append", "before", "unpack",
209 "configure", "forget", "info", "propagate", "slaves", (char *) NULL };
211 PACK_AFTER, PACK_APPEND, PACK_BEFORE, PACK_UNPACK,
212 PACK_CONFIGURE, PACK_FORGET, PACK_INFO, PACK_PROPAGATE, PACK_SLAVES };
216 char *string = Tcl_GetString(objv[1]);
217 if (string[0] == '.') {
218 return ConfigureSlaves(interp, tkwin, objc-1, objv+1);
222 Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
226 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
229 * Call it again without the deprecated ones to get a proper
231 * This works well since there can't be any ambiguity between
232 * deprecated and new options.
235 Tcl_ResetResult(interp);
236 Tcl_GetIndexFromObj(interp, objv[1], &optionStrings[4], "option", 0,
241 argv2 = Tcl_GetString(objv[2]);
242 if (index == PACK_AFTER) {
246 if (TkGetWindowFromObj(interp, tkwin, objv[2], &tkwin2) != TCL_OK) {
249 prevPtr = GetPacker(tkwin2);
250 if (prevPtr->masterPtr == NULL) {
251 Tcl_AppendResult(interp, "window \"", argv2,
252 "\" isn't packed", (char *) NULL);
255 return PackAfter(interp, prevPtr, prevPtr->masterPtr, objc-3, objv+3);
256 } else if (index == PACK_APPEND) {
258 register Packer *prevPtr;
261 if (TkGetWindowFromObj(interp, tkwin, objv[2], &tkwin2) != TCL_OK) {
264 masterPtr = GetPacker(tkwin2);
265 prevPtr = masterPtr->slavePtr;
266 if (prevPtr != NULL) {
267 while (prevPtr->nextPtr != NULL) {
268 prevPtr = prevPtr->nextPtr;
271 return PackAfter(interp, prevPtr, masterPtr, objc-3, objv+3);
272 } else if (index == PACK_BEFORE) {
273 Packer *packPtr, *masterPtr;
274 register Packer *prevPtr;
277 if (TkGetWindowFromObj(interp, tkwin, objv[2], &tkwin2) != TCL_OK) {
280 packPtr = GetPacker(tkwin2);
281 if (packPtr->masterPtr == NULL) {
282 Tcl_AppendResult(interp, "window \"", argv2,
283 "\" isn't packed", (char *) NULL);
286 masterPtr = packPtr->masterPtr;
287 prevPtr = masterPtr->slavePtr;
288 if (prevPtr == packPtr) {
291 for ( ; ; prevPtr = prevPtr->nextPtr) {
292 if (prevPtr == NULL) {
293 panic("\"pack before\" couldn't find predecessor");
295 if (prevPtr->nextPtr == packPtr) {
300 return PackAfter(interp, prevPtr, masterPtr, objc-3, objv+3);
301 } else if (index == PACK_CONFIGURE) {
302 if (argv2[0] != '.') {
303 Tcl_AppendResult(interp, "bad argument \"", argv2,
304 "\": must be name of window", (char *) NULL);
307 return ConfigureSlaves(interp, tkwin, objc-2, objv+2);
308 } else if (index == PACK_FORGET) {
313 for (i = 2; i < objc; i++) {
314 if (TkGetWindowFromObj(interp, tkwin, objv[i], &slave) != TCL_OK) {
317 slavePtr = GetPacker(slave);
318 if ((slavePtr != NULL) && (slavePtr->masterPtr != NULL)) {
319 Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,
321 if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
322 Tk_UnmaintainGeometry(slavePtr->tkwin,
323 slavePtr->masterPtr->tkwin);
326 Tk_UnmapWindow(slavePtr->tkwin);
329 } else if (index == PACK_INFO) {
330 register Packer *slavePtr;
334 Tcl_WrongNumArgs(interp, 2, objv, "window");
337 if (TkGetWindowFromObj(interp, tkwin, objv[2], &slave) != TCL_OK) {
340 slavePtr = GetPacker(slave);
341 if (slavePtr->masterPtr == NULL) {
342 Tcl_AppendResult(interp, "window \"", argv2,
343 "\" isn't packed", (char *) NULL);
346 Tcl_AppendElement(interp, "-in");
347 Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin));
348 Tcl_AppendElement(interp, "-anchor");
349 Tcl_AppendElement(interp, Tk_NameOfAnchor(slavePtr->anchor));
350 Tcl_AppendResult(interp, " -expand ",
351 (slavePtr->flags & EXPAND) ? "1" : "0", " -fill ",
353 switch (slavePtr->flags & (FILLX|FILLY)) {
355 Tcl_AppendResult(interp, "none", (char *) NULL);
358 Tcl_AppendResult(interp, "x", (char *) NULL);
361 Tcl_AppendResult(interp, "y", (char *) NULL);
364 Tcl_AppendResult(interp, "both", (char *) NULL);
367 TkPrintPadAmount(interp, "ipadx", slavePtr->iPadX/2, slavePtr->iPadX);
368 TkPrintPadAmount(interp, "ipady", slavePtr->iPadY/2, slavePtr->iPadY);
369 TkPrintPadAmount(interp, "padx", slavePtr->padLeft, slavePtr->padX);
370 TkPrintPadAmount(interp, "pady", slavePtr->padTop, slavePtr->padY);
371 Tcl_AppendResult(interp, " -side ", sideNames[slavePtr->side],
373 } else if (index == PACK_PROPAGATE) {
379 Tcl_WrongNumArgs(interp, 2, objv, "window ?boolean?");
382 if (TkGetWindowFromObj(interp, tkwin, objv[2], &master) != TCL_OK) {
385 masterPtr = GetPacker(master);
387 Tcl_SetObjResult(interp,
388 Tcl_NewBooleanObj(!(masterPtr->flags & DONT_PROPAGATE)));
391 if (Tcl_GetBooleanFromObj(interp, objv[3], &propagate) != TCL_OK) {
395 masterPtr->flags &= ~DONT_PROPAGATE;
398 * Repack the master to allow new geometry information to
399 * propagate upwards to the master's master.
402 if (masterPtr->abortPtr != NULL) {
403 *masterPtr->abortPtr = 1;
405 if (!(masterPtr->flags & REQUESTED_REPACK)) {
406 masterPtr->flags |= REQUESTED_REPACK;
407 Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
410 masterPtr->flags |= DONT_PROPAGATE;
412 } else if (index == PACK_SLAVES) {
414 Packer *masterPtr, *slavePtr;
417 Tcl_WrongNumArgs(interp, 2, objv, "window");
420 if (TkGetWindowFromObj(interp, tkwin, objv[2], &master) != TCL_OK) {
423 masterPtr = GetPacker(master);
424 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
425 slavePtr = slavePtr->nextPtr) {
426 Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));
428 } else if (index == PACK_UNPACK) {
433 Tcl_WrongNumArgs(interp, 2, objv, "window");
436 if (TkGetWindowFromObj(interp, tkwin, objv[2], &tkwin2) != TCL_OK) {
439 packPtr = GetPacker(tkwin2);
440 if ((packPtr != NULL) && (packPtr->masterPtr != NULL)) {
441 Tk_ManageGeometry(tkwin2, (Tk_GeomMgr *) NULL,
443 if (packPtr->masterPtr->tkwin != Tk_Parent(packPtr->tkwin)) {
444 Tk_UnmaintainGeometry(packPtr->tkwin,
445 packPtr->masterPtr->tkwin);
448 Tk_UnmapWindow(packPtr->tkwin);
456 *--------------------------------------------------------------
460 * This procedure is invoked by Tk_GeometryRequest for
461 * windows managed by the packer.
467 * Arranges for tkwin, and all its managed siblings, to
468 * be re-packed at the next idle point.
470 *--------------------------------------------------------------
475 PackReqProc(clientData, tkwin)
476 ClientData clientData; /* Packer's information about
477 * window that got new preferred
479 Tk_Window tkwin; /* Other Tk-related information
480 * about the window. */
482 register Packer *packPtr = (Packer *) clientData;
484 packPtr = packPtr->masterPtr;
485 if (!(packPtr->flags & REQUESTED_REPACK)) {
486 packPtr->flags |= REQUESTED_REPACK;
487 Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
492 *--------------------------------------------------------------
494 * PackLostSlaveProc --
496 * This procedure is invoked by Tk whenever some other geometry
497 * claims control over a slave that used to be managed by us.
503 * Forgets all packer-related information about the slave.
505 *--------------------------------------------------------------
510 PackLostSlaveProc(clientData, tkwin)
511 ClientData clientData; /* Packer structure for slave window that
512 * was stolen away. */
513 Tk_Window tkwin; /* Tk's handle for the slave window. */
515 register Packer *slavePtr = (Packer *) clientData;
517 if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
518 Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);
521 Tk_UnmapWindow(slavePtr->tkwin);
525 *--------------------------------------------------------------
529 * This procedure is invoked (using the Tcl_DoWhenIdle
530 * mechanism) to re-layout a set of windows managed by
531 * the packer. It is invoked at idle time so that a
532 * series of packer requests can be merged into a single
539 * The packed slaves of masterPtr may get resized or
542 *--------------------------------------------------------------
546 ArrangePacking(clientData)
547 ClientData clientData; /* Structure describing parent whose slaves
548 * are to be re-layed out. */
550 register Packer *masterPtr = (Packer *) clientData;
551 register Packer *slavePtr;
552 int cavityX, cavityY, cavityWidth, cavityHeight;
553 /* These variables keep track of the
554 * as-yet-unallocated space remaining in
555 * the middle of the parent window. */
556 int frameX, frameY, frameWidth, frameHeight;
557 /* These variables keep track of the frame
558 * allocated to the current window. */
559 int x, y, width, height; /* These variables are used to hold the
560 * actual geometry of the current window. */
561 int abort; /* May get set to non-zero to abort this
562 * repacking operation. */
563 int borderX, borderY;
564 int borderTop, borderBtm;
565 int borderLeft, borderRight;
566 int maxWidth, maxHeight, tmp;
568 masterPtr->flags &= ~REQUESTED_REPACK;
571 * If the parent has no slaves anymore, then don't do anything
572 * at all: just leave the parent's size as-is.
575 if (masterPtr->slavePtr == NULL) {
580 * Abort any nested call to ArrangePacking for this window, since
581 * we'll do everything necessary here, and set up so this call
582 * can be aborted if necessary.
585 if (masterPtr->abortPtr != NULL) {
586 *masterPtr->abortPtr = 1;
588 masterPtr->abortPtr = &abort;
590 Tcl_Preserve((ClientData) masterPtr);
593 * Pass #1: scan all the slaves to figure out the total amount
594 * of space needed. Two separate width and height values are
597 * width - Holds the sum of the widths (plus padding) of
598 * all the slaves seen so far that were packed LEFT
600 * height - Holds the sum of the heights (plus padding) of
601 * all the slaves seen so far that were packed TOP
604 * maxWidth - Gradually builds up the width needed by the master
605 * to just barely satisfy all the slave's needs. For
606 * each slave, the code computes the width needed for
607 * all the slaves so far and updates maxWidth if the
608 * new value is greater.
609 * maxHeight - Same as maxWidth, except keeps height info.
612 width = maxWidth = Tk_InternalBorderLeft(masterPtr->tkwin) +
613 Tk_InternalBorderRight(masterPtr->tkwin);
614 height = maxHeight = Tk_InternalBorderTop(masterPtr->tkwin) +
615 Tk_InternalBorderBottom(masterPtr->tkwin);
616 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
617 slavePtr = slavePtr->nextPtr) {
618 if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
619 tmp = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
620 + slavePtr->padX + slavePtr->iPadX + width;
621 if (tmp > maxWidth) {
624 height += Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
625 + slavePtr->padY + slavePtr->iPadY;
627 tmp = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
628 + slavePtr->padY + slavePtr->iPadY + height;
629 if (tmp > maxHeight) {
632 width += Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
633 + slavePtr->padX + slavePtr->iPadX;
636 if (width > maxWidth) {
639 if (height > maxHeight) {
643 if (maxWidth < Tk_MinReqWidth(masterPtr->tkwin)) {
644 maxWidth = Tk_MinReqWidth(masterPtr->tkwin);
646 if (maxHeight < Tk_MinReqHeight(masterPtr->tkwin)) {
647 maxHeight = Tk_MinReqHeight(masterPtr->tkwin);
651 * If the total amount of space needed in the parent window has
652 * changed, and if we're propagating geometry information, then
653 * notify the next geometry manager up and requeue ourselves to
654 * start again after the parent has had a chance to
658 if (((maxWidth != Tk_ReqWidth(masterPtr->tkwin))
659 || (maxHeight != Tk_ReqHeight(masterPtr->tkwin)))
660 && !(masterPtr->flags & DONT_PROPAGATE)) {
661 Tk_GeometryRequest(masterPtr->tkwin, maxWidth, maxHeight);
662 masterPtr->flags |= REQUESTED_REPACK;
663 Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
668 * Pass #2: scan the slaves a second time assigning
669 * new sizes. The "cavity" variables keep track of the
670 * unclaimed space in the cavity of the window; this
671 * shrinks inward as we allocate windows around the
672 * edges. The "frame" variables keep track of the space
673 * allocated to the current window and its frame. The
674 * current window is then placed somewhere inside the
675 * frame, depending on anchor.
678 cavityX = x = Tk_InternalBorderLeft(masterPtr->tkwin);
679 cavityY = y = Tk_InternalBorderTop(masterPtr->tkwin);
680 cavityWidth = Tk_Width(masterPtr->tkwin) -
681 Tk_InternalBorderLeft(masterPtr->tkwin) -
682 Tk_InternalBorderRight(masterPtr->tkwin);
683 cavityHeight = Tk_Height(masterPtr->tkwin) -
684 Tk_InternalBorderTop(masterPtr->tkwin) -
685 Tk_InternalBorderBottom(masterPtr->tkwin);
686 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
687 slavePtr = slavePtr->nextPtr) {
688 if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
689 frameWidth = cavityWidth;
690 frameHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
691 + slavePtr->padY + slavePtr->iPadY;
692 if (slavePtr->flags & EXPAND) {
693 frameHeight += YExpansion(slavePtr, cavityHeight);
695 cavityHeight -= frameHeight;
696 if (cavityHeight < 0) {
697 frameHeight += cavityHeight;
701 if (slavePtr->side == TOP) {
703 cavityY += frameHeight;
705 frameY = cavityY + cavityHeight;
708 frameHeight = cavityHeight;
709 frameWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
710 + slavePtr->padX + slavePtr->iPadX;
711 if (slavePtr->flags & EXPAND) {
712 frameWidth += XExpansion(slavePtr, cavityWidth);
714 cavityWidth -= frameWidth;
715 if (cavityWidth < 0) {
716 frameWidth += cavityWidth;
720 if (slavePtr->side == LEFT) {
722 cavityX += frameWidth;
724 frameX = cavityX + cavityWidth;
729 * Now that we've got the size of the frame for the window,
730 * compute the window's actual size and location using the
731 * fill, padding, and frame factors. The variables "borderX"
732 * and "borderY" are used to handle the differences between
733 * old-style packing and the new style (in old-style, iPadX
734 * and iPadY are always zero and padding is completely ignored
735 * except when computing frame size).
738 if (slavePtr->flags & OLD_STYLE) {
739 borderX = borderY = 0;
740 borderTop = borderBtm = 0;
741 borderLeft = borderRight = 0;
743 borderX = slavePtr->padX;
744 borderY = slavePtr->padY;
745 borderLeft = slavePtr->padLeft;
746 borderRight = borderX - borderLeft;
747 borderTop = slavePtr->padTop;
748 borderBtm = borderY - borderTop;
750 width = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
752 if ((slavePtr->flags & FILLX)
753 || (width > (frameWidth - borderX))) {
754 width = frameWidth - borderX;
756 height = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
758 if ((slavePtr->flags & FILLY)
759 || (height > (frameHeight - borderY))) {
760 height = frameHeight - borderY;
762 switch (slavePtr->anchor) {
764 x = frameX + (borderLeft + frameWidth - width - borderRight)/2;
765 y = frameY + borderTop;
768 x = frameX + frameWidth - width - borderRight;
769 y = frameY + borderTop;
772 x = frameX + frameWidth - width - borderRight;
773 y = frameY + (borderTop + frameHeight - height - borderBtm)/2;
776 x = frameX + frameWidth - width - borderRight;
777 y = frameY + frameHeight - height - borderBtm;
780 x = frameX + (borderLeft + frameWidth - width - borderRight)/2;
781 y = frameY + frameHeight - height - borderBtm;
784 x = frameX + borderLeft;
785 y = frameY + frameHeight - height - borderBtm;
788 x = frameX + borderLeft;
789 y = frameY + (borderTop + frameHeight - height - borderBtm)/2;
792 x = frameX + borderLeft;
793 y = frameY + borderTop;
795 case TK_ANCHOR_CENTER:
796 x = frameX + (borderLeft + frameWidth - width - borderRight)/2;
797 y = frameY + (borderTop + frameHeight - height - borderBtm)/2;
800 panic("bad frame factor in ArrangePacking");
802 width -= slavePtr->doubleBw;
803 height -= slavePtr->doubleBw;
806 * The final step is to set the position, size, and mapped/unmapped
807 * state of the slave. If the slave is a child of the master, then
808 * do this here. Otherwise let Tk_MaintainGeometry do the work.
811 if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) {
812 if ((width <= 0) || (height <= 0)) {
813 Tk_UnmapWindow(slavePtr->tkwin);
815 if ((x != Tk_X(slavePtr->tkwin))
816 || (y != Tk_Y(slavePtr->tkwin))
817 || (width != Tk_Width(slavePtr->tkwin))
818 || (height != Tk_Height(slavePtr->tkwin))) {
819 Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);
826 * Don't map the slave if the master isn't mapped: wait
827 * until the master gets mapped later.
830 if (Tk_IsMapped(masterPtr->tkwin)) {
831 Tk_MapWindow(slavePtr->tkwin);
835 if ((width <= 0) || (height <= 0)) {
836 Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin);
837 Tk_UnmapWindow(slavePtr->tkwin);
839 Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin,
840 x, y, width, height);
845 * Changes to the window's structure could cause almost anything
846 * to happen, including deleting the parent or child. If this
847 * happens, we'll be told to abort.
856 masterPtr->abortPtr = NULL;
857 Tcl_Release((ClientData) masterPtr);
861 *----------------------------------------------------------------------
865 * Given a list of packed slaves, the first of which is packed
866 * on the left or right and is expandable, compute how much to
870 * The return value is the number of additional pixels to give to
876 *----------------------------------------------------------------------
880 XExpansion(slavePtr, cavityWidth)
881 register Packer *slavePtr; /* First in list of remaining
883 int cavityWidth; /* Horizontal space left for all
884 * remaining slaves. */
886 int numExpand, minExpand, curExpand;
890 * This procedure is tricky because windows packed top or bottom can
891 * be interspersed among expandable windows packed left or right.
892 * Scan through the list, keeping a running sum of the widths of
893 * all left and right windows (actually, count the cavity space not
894 * allocated) and a running count of all expandable left and right
895 * windows. At each top or bottom window, and at the end of the
896 * list, compute the expansion factor that seems reasonable at that
897 * point. Return the smallest factor seen at any of these points.
900 minExpand = cavityWidth;
902 for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) {
903 childWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
904 + slavePtr->padX + slavePtr->iPadX;
905 if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
906 curExpand = (cavityWidth - childWidth)/numExpand;
907 if (curExpand < minExpand) {
908 minExpand = curExpand;
911 cavityWidth -= childWidth;
912 if (slavePtr->flags & EXPAND) {
917 curExpand = cavityWidth/numExpand;
918 if (curExpand < minExpand) {
919 minExpand = curExpand;
921 return (minExpand < 0) ? 0 : minExpand;
925 *----------------------------------------------------------------------
929 * Given a list of packed slaves, the first of which is packed
930 * on the top or bottom and is expandable, compute how much to
934 * The return value is the number of additional pixels to give to
940 *----------------------------------------------------------------------
944 YExpansion(slavePtr, cavityHeight)
945 register Packer *slavePtr; /* First in list of remaining
947 int cavityHeight; /* Vertical space left for all
948 * remaining slaves. */
950 int numExpand, minExpand, curExpand;
954 * See comments for XExpansion.
957 minExpand = cavityHeight;
959 for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) {
960 childHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
961 + slavePtr->padY + slavePtr->iPadY;
962 if ((slavePtr->side == LEFT) || (slavePtr->side == RIGHT)) {
963 curExpand = (cavityHeight - childHeight)/numExpand;
964 if (curExpand < minExpand) {
965 minExpand = curExpand;
968 cavityHeight -= childHeight;
969 if (slavePtr->flags & EXPAND) {
974 curExpand = cavityHeight/numExpand;
975 if (curExpand < minExpand) {
976 minExpand = curExpand;
978 return (minExpand < 0) ? 0 : minExpand;
982 *--------------------------------------------------------------
986 * This internal procedure is used to locate a Packer
987 * structure for a given window, creating one if one
988 * doesn't exist already.
991 * The return value is a pointer to the Packer structure
992 * corresponding to tkwin.
995 * A new packer structure may be created. If so, then
996 * a callback is set up to clean things up when the
999 *--------------------------------------------------------------
1004 Tk_Window tkwin; /* Token for window for which
1005 * packer structure is desired. */
1007 register Packer *packPtr;
1008 Tcl_HashEntry *hPtr;
1010 TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
1012 if (!dispPtr->packInit) {
1013 dispPtr->packInit = 1;
1014 Tcl_InitHashTable(&dispPtr->packerHashTable, TCL_ONE_WORD_KEYS);
1018 * See if there's already packer for this window. If not,
1019 * then create a new one.
1022 hPtr = Tcl_CreateHashEntry(&dispPtr->packerHashTable, (char *) tkwin,
1025 return (Packer *) Tcl_GetHashValue(hPtr);
1027 packPtr = (Packer *) ckalloc(sizeof(Packer));
1028 packPtr->tkwin = tkwin;
1029 packPtr->masterPtr = NULL;
1030 packPtr->nextPtr = NULL;
1031 packPtr->slavePtr = NULL;
1032 packPtr->side = TOP;
1033 packPtr->anchor = TK_ANCHOR_CENTER;
1034 packPtr->padX = packPtr->padY = 0;
1035 packPtr->padLeft = packPtr->padTop = 0;
1036 packPtr->iPadX = packPtr->iPadY = 0;
1037 packPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
1038 packPtr->abortPtr = NULL;
1040 Tcl_SetHashValue(hPtr, packPtr);
1041 Tk_CreateEventHandler(tkwin, StructureNotifyMask,
1042 PackStructureProc, (ClientData) packPtr);
1047 *--------------------------------------------------------------
1049 * TkParsePadAmount --
1051 * This procedure parses a padding specification and returns
1052 * the appropriate padding values. A padding specification can
1053 * be either a single pixel width, or a list of two pixel widths.
1054 * If a single pixel width, the amount specified is used for
1055 * padding on both sides. If two amounts are specified, then
1056 * they specify the left/right or top/bottom padding.
1059 * A standard Tcl return value.
1062 * An error message is written to the interpreter is something
1065 *--------------------------------------------------------------
1069 TkParsePadAmount(interp, tkwin, specObj, halfPtr, allPtr)
1070 Tcl_Interp *interp; /* Interpreter for error reporting. */
1071 Tk_Window tkwin; /* A window. Needed by Tk_GetPixels() */
1072 Tcl_Obj *specObj; /* The argument to "-padx", "-pady", "-ipadx",
1073 * or "-ipady". The thing to be parsed. */
1074 int *halfPtr; /* Write the left/top part of padding here */
1075 int *allPtr; /* Write the total padding here */
1077 char *secondPart; /* The second pixel amount of the list */
1078 char *separator = 0; /* Separator between 1st and 2nd pixel widths */
1079 int sepChar = 0; /* Character used as the separator */
1080 int firstInt, secondInt; /* The two components of the padding */
1081 char *padSpec = Tcl_GetString(specObj);
1083 for (secondPart=padSpec;
1084 (*secondPart != '\0') && !isspace(UCHAR(*secondPart));
1086 { /* Do nothing */ }
1087 if (*secondPart != '\0') {
1088 separator = secondPart;
1089 sepChar = *secondPart;
1092 while ( isspace(UCHAR(*secondPart)) ) {
1095 if (*secondPart == '\0'){
1097 *separator = sepChar;
1102 if ((Tk_GetPixels(interp, tkwin, padSpec, &firstInt) != TCL_OK) ||
1104 Tcl_ResetResult(interp);
1105 Tcl_AppendResult(interp, "bad pad value \"", padSpec,
1106 "\": must be positive screen distance", (char *) NULL);
1110 if ((Tk_GetPixels(interp, tkwin, secondPart, &secondInt) != TCL_OK) ||
1112 Tcl_ResetResult(interp);
1113 Tcl_AppendResult(interp, "bad 2nd pad value \"", secondPart,
1114 "\": must be positive screen distance", (char *) NULL);
1117 *separator = sepChar;
1119 secondInt = firstInt;
1121 if (halfPtr != 0) *halfPtr = firstInt;
1122 *allPtr = firstInt + secondInt;
1127 *--------------------------------------------------------------
1131 * This procedure does most of the real work of adding
1132 * one or more windows into the packing order for its parent.
1135 * A standard Tcl return value.
1138 * The geometry of the specified windows may change, both now and
1139 * again in the future.
1141 *--------------------------------------------------------------
1145 PackAfter(interp, prevPtr, masterPtr, objc, objv)
1146 Tcl_Interp *interp; /* Interpreter for error reporting. */
1147 Packer *prevPtr; /* Pack windows in argv just after this
1148 * window; NULL means pack as first
1149 * child of masterPtr. */
1150 Packer *masterPtr; /* Master in which to pack windows. */
1151 int objc; /* Number of elements in objv. */
1152 Tcl_Obj *CONST objv[]; /* Array of lists, each containing 2
1153 * elements: window name and side
1154 * against which to pack. */
1156 register Packer *packPtr;
1157 Tk_Window tkwin, ancestor, parent;
1160 int index, optionCount, c;
1163 * Iterate over all of the window specifiers, each consisting of
1164 * two arguments. The first argument contains the window name and
1165 * the additional arguments contain options such as "top" or
1169 for ( ; objc > 0; objc -= 2, objv += 2, prevPtr = packPtr) {
1171 Tcl_AppendResult(interp, "wrong # args: window \"",
1172 Tcl_GetString(objv[0]), "\" should be followed by options",
1178 * Find the packer for the window to be packed, and make sure
1179 * that the window in which it will be packed is either its
1180 * or a descendant of its parent.
1183 if (TkGetWindowFromObj(interp, masterPtr->tkwin, objv[0], &tkwin)
1188 parent = Tk_Parent(tkwin);
1189 for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
1190 if (ancestor == parent) {
1193 if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_HIERARCHY) {
1195 Tcl_AppendResult(interp, "can't pack ", Tcl_GetString(objv[0]),
1196 " inside ", Tk_PathName(masterPtr->tkwin),
1201 if (((Tk_FakeWin *) (tkwin))->flags & TK_TOP_HIERARCHY) {
1204 if (tkwin == masterPtr->tkwin) {
1207 packPtr = GetPacker(tkwin);
1210 * Process options for this window.
1213 if (Tcl_ListObjGetElements(interp, objv[1], &optionCount, &options)
1217 packPtr->side = TOP;
1218 packPtr->anchor = TK_ANCHOR_CENTER;
1219 packPtr->padX = packPtr->padY = 0;
1220 packPtr->padLeft = packPtr->padTop = 0;
1221 packPtr->iPadX = packPtr->iPadY = 0;
1222 packPtr->flags &= ~(FILLX|FILLY|EXPAND);
1223 packPtr->flags |= OLD_STYLE;
1224 for (index = 0 ; index < optionCount; index++) {
1225 Tcl_Obj *curOptPtr = options[index];
1226 char *curOpt = Tcl_GetStringFromObj(curOptPtr, (int *) &length);
1231 && (strncmp(curOpt, "top", (size_t) length)) == 0) {
1232 packPtr->side = TOP;
1233 } else if ((c == 'b')
1234 && (strncmp(curOpt, "bottom", (size_t) length)) == 0) {
1235 packPtr->side = BOTTOM;
1236 } else if ((c == 'l')
1237 && (strncmp(curOpt, "left", (size_t) length)) == 0) {
1238 packPtr->side = LEFT;
1239 } else if ((c == 'r')
1240 && (strncmp(curOpt, "right", (size_t) length)) == 0) {
1241 packPtr->side = RIGHT;
1242 } else if ((c == 'e')
1243 && (strncmp(curOpt, "expand", (size_t) length)) == 0) {
1244 packPtr->flags |= EXPAND;
1245 } else if ((c == 'f')
1246 && (strcmp(curOpt, "fill")) == 0) {
1247 packPtr->flags |= FILLX|FILLY;
1248 } else if ((length == 5) && (strcmp(curOpt, "fillx")) == 0) {
1249 packPtr->flags |= FILLX;
1250 } else if ((length == 5) && (strcmp(curOpt, "filly")) == 0) {
1251 packPtr->flags |= FILLY;
1252 } else if ((c == 'p') && (strcmp(curOpt, "padx")) == 0) {
1253 if (optionCount < (index+2)) {
1255 Tcl_AppendResult(interp, "wrong # args: \"", curOpt,
1256 "\" option must be followed by screen distance",
1260 if (TkParsePadAmount(interp, tkwin, options[index+1],
1261 &packPtr->padLeft, &packPtr->padX) != TCL_OK) {
1265 packPtr->padLeft /= 2;
1268 } else if ((c == 'p') && (strcmp(curOpt, "pady")) == 0) {
1269 if (optionCount < (index+2)) {
1272 if (TkParsePadAmount(interp, tkwin, options[index+1],
1273 &packPtr->padTop, &packPtr->padY) != TCL_OK) {
1277 packPtr->padTop /= 2;
1280 } else if ((c == 'f') && (length > 1)
1281 && (strncmp(curOpt, "frame", (size_t) length) == 0)) {
1282 if (optionCount < (index+2)) {
1283 Tcl_AppendResult(interp, "wrong # args: \"frame\" ",
1284 "option must be followed by anchor point",
1288 if (Tk_GetAnchorFromObj(interp, options[index+1],
1289 &packPtr->anchor) != TCL_OK) {
1294 Tcl_AppendResult(interp, "bad option \"", curOpt,
1295 "\": should be top, bottom, left, right, ",
1296 "expand, fill, fillx, filly, padx, pady, or frame",
1302 if (packPtr != prevPtr) {
1305 * Unpack this window if it's currently packed.
1308 if (packPtr->masterPtr != NULL) {
1309 if ((packPtr->masterPtr != masterPtr) &&
1310 (packPtr->masterPtr->tkwin
1311 != Tk_Parent(packPtr->tkwin))) {
1312 Tk_UnmaintainGeometry(packPtr->tkwin,
1313 packPtr->masterPtr->tkwin);
1319 * Add the window in the correct place in its parent's
1320 * packing order, then make sure that the window is
1324 packPtr->masterPtr = masterPtr;
1325 if (prevPtr == NULL) {
1326 packPtr->nextPtr = masterPtr->slavePtr;
1327 masterPtr->slavePtr = packPtr;
1329 packPtr->nextPtr = prevPtr->nextPtr;
1330 prevPtr->nextPtr = packPtr;
1332 Tk_ManageGeometry(tkwin, &packerType, (ClientData) packPtr);
1337 * Arrange for the parent to be re-packed at the first
1341 if (masterPtr->abortPtr != NULL) {
1342 *masterPtr->abortPtr = 1;
1344 if (!(masterPtr->flags & REQUESTED_REPACK)) {
1345 masterPtr->flags |= REQUESTED_REPACK;
1346 Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
1352 *----------------------------------------------------------------------
1356 * Remove a packer from its parent's list of slaves.
1362 * The parent will be scheduled for repacking.
1364 *----------------------------------------------------------------------
1369 register Packer *packPtr; /* Window to unlink. */
1371 register Packer *masterPtr, *packPtr2;
1373 masterPtr = packPtr->masterPtr;
1374 if (masterPtr == NULL) {
1377 if (masterPtr->slavePtr == packPtr) {
1378 masterPtr->slavePtr = packPtr->nextPtr;
1380 for (packPtr2 = masterPtr->slavePtr; ; packPtr2 = packPtr2->nextPtr) {
1381 if (packPtr2 == NULL) {
1382 panic("Unlink couldn't find previous window");
1384 if (packPtr2->nextPtr == packPtr) {
1385 packPtr2->nextPtr = packPtr->nextPtr;
1390 if (!(masterPtr->flags & REQUESTED_REPACK)) {
1391 masterPtr->flags |= REQUESTED_REPACK;
1392 Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
1394 if (masterPtr->abortPtr != NULL) {
1395 *masterPtr->abortPtr = 1;
1398 packPtr->masterPtr = NULL;
1402 *----------------------------------------------------------------------
1406 * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
1407 * to clean up the internal structure of a packer at a safe time
1408 * (when no-one is using it anymore).
1414 * Everything associated with the packer is freed up.
1416 *----------------------------------------------------------------------
1420 DestroyPacker(memPtr)
1421 char *memPtr; /* Info about packed window that
1424 register Packer *packPtr = (Packer *) memPtr;
1425 ckfree((char *) packPtr);
1429 *----------------------------------------------------------------------
1431 * PackStructureProc --
1433 * This procedure is invoked by the Tk event dispatcher in response
1434 * to StructureNotify events.
1440 * If a window was just deleted, clean up all its packer-related
1441 * information. If it was just resized, repack its slaves, if
1444 *----------------------------------------------------------------------
1448 PackStructureProc(clientData, eventPtr)
1449 ClientData clientData; /* Our information about window
1450 * referred to by eventPtr. */
1451 XEvent *eventPtr; /* Describes what just happened. */
1453 register Packer *packPtr = (Packer *) clientData;
1455 if (eventPtr->type == ConfigureNotify) {
1456 if ((packPtr->slavePtr != NULL)
1457 && !(packPtr->flags & REQUESTED_REPACK)) {
1458 packPtr->flags |= REQUESTED_REPACK;
1459 Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
1461 if (packPtr->doubleBw != 2*Tk_Changes(packPtr->tkwin)->border_width) {
1462 if ((packPtr->masterPtr != NULL)
1463 && !(packPtr->masterPtr->flags & REQUESTED_REPACK)) {
1464 packPtr->doubleBw = 2*Tk_Changes(packPtr->tkwin)->border_width;
1465 packPtr->masterPtr->flags |= REQUESTED_REPACK;
1466 Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr->masterPtr);
1469 } else if (eventPtr->type == DestroyNotify) {
1470 register Packer *slavePtr, *nextPtr;
1472 if (packPtr->masterPtr != NULL) {
1475 for (slavePtr = packPtr->slavePtr; slavePtr != NULL;
1476 slavePtr = nextPtr) {
1477 Tk_ManageGeometry(slavePtr->tkwin, (Tk_GeomMgr *) NULL,
1479 Tk_UnmapWindow(slavePtr->tkwin);
1480 slavePtr->masterPtr = NULL;
1481 nextPtr = slavePtr->nextPtr;
1482 slavePtr->nextPtr = NULL;
1484 if (packPtr->tkwin != NULL) {
1485 TkDisplay *dispPtr = ((TkWindow *) packPtr->tkwin)->dispPtr;
1486 Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->packerHashTable,
1487 (char *) packPtr->tkwin));
1489 if (packPtr->flags & REQUESTED_REPACK) {
1490 Tcl_CancelIdleCall(ArrangePacking, (ClientData) packPtr);
1492 packPtr->tkwin = NULL;
1493 Tcl_EventuallyFree((ClientData) packPtr, DestroyPacker);
1494 } else if (eventPtr->type == MapNotify) {
1496 * When a master gets mapped, must redo the geometry computation
1497 * so that all of its slaves get remapped.
1500 if ((packPtr->slavePtr != NULL)
1501 && !(packPtr->flags & REQUESTED_REPACK)) {
1502 packPtr->flags |= REQUESTED_REPACK;
1503 Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
1505 } else if (eventPtr->type == UnmapNotify) {
1506 register Packer *packPtr2;
1509 * Unmap all of the slaves when the master gets unmapped,
1510 * so that they don't bother to keep redisplaying
1513 for (packPtr2 = packPtr->slavePtr; packPtr2 != NULL;
1514 packPtr2 = packPtr2->nextPtr) {
1515 Tk_UnmapWindow(packPtr2->tkwin);
1521 *----------------------------------------------------------------------
1523 * ConfigureSlaves --
1525 * This implements the guts of the "pack configure" command. Given
1526 * a list of slaves and configuration options, it arranges for the
1527 * packer to manage the slaves and sets the specified options.
1530 * TCL_OK is returned if all went well. Otherwise, TCL_ERROR is
1531 * returned and the interp's result is set to contain an error message.
1534 * Slave windows get taken over by the packer.
1536 *----------------------------------------------------------------------
1540 ConfigureSlaves(interp, tkwin, objc, objv)
1541 Tcl_Interp *interp; /* Interpreter for error reporting. */
1542 Tk_Window tkwin; /* Any window in application containing
1543 * slaves. Used to look up slave names. */
1544 int objc; /* Number of elements in argv. */
1545 Tcl_Obj *CONST objv[]; /* Argument objects: contains one or more
1546 * window names followed by any number
1547 * of "option value" pairs. Caller must
1548 * make sure that there is at least one
1551 Packer *masterPtr, *slavePtr, *prevPtr, *otherPtr;
1552 Tk_Window other, slave, parent, ancestor;
1553 int i, j, numWindows, tmp, positionGiven;
1555 static CONST char *optionStrings[] = {
1556 "-after", "-anchor", "-before", "-expand", "-fill",
1557 "-in", "-ipadx", "-ipady", "-padx", "-pady", "-side", (char *) NULL };
1559 CONF_AFTER, CONF_ANCHOR, CONF_BEFORE, CONF_EXPAND, CONF_FILL,
1560 CONF_IN, CONF_IPADX, CONF_IPADY, CONF_PADX, CONF_PADY, CONF_SIDE };
1564 * Find out how many windows are specified.
1567 for (numWindows = 0; numWindows < objc; numWindows++) {
1568 string = Tcl_GetString(objv[numWindows]);
1569 if (string[0] != '.') {
1575 * Iterate over all of the slave windows, parsing the configuration
1576 * options for each slave. It's a bit wasteful to re-parse the
1577 * options for each slave, but things get too messy if we try to
1578 * parse the arguments just once at the beginning. For example,
1579 * if a slave already is packed we want to just change a few
1580 * existing values without resetting everything. If there are
1581 * multiple windows, the -after, -before, and -in options only
1582 * get processed for the first window.
1588 for (j = 0; j < numWindows; j++) {
1589 if (TkGetWindowFromObj(interp, tkwin, objv[j], &slave) != TCL_OK) {
1592 if (Tk_TopWinHierarchy(slave)) {
1593 Tcl_AppendResult(interp, "can't pack \"", Tcl_GetString(objv[j]),
1594 "\": it's a top-level window", (char *) NULL);
1597 slavePtr = GetPacker(slave);
1598 slavePtr->flags &= ~OLD_STYLE;
1601 * If the slave isn't currently packed, reset all of its
1602 * configuration information to default values (there could
1603 * be old values left from a previous packing).
1606 if (slavePtr->masterPtr == NULL) {
1607 slavePtr->side = TOP;
1608 slavePtr->anchor = TK_ANCHOR_CENTER;
1609 slavePtr->padX = slavePtr->padY = 0;
1610 slavePtr->padLeft = slavePtr->padTop = 0;
1611 slavePtr->iPadX = slavePtr->iPadY = 0;
1612 slavePtr->flags &= ~(FILLX|FILLY|EXPAND);
1615 for (i = numWindows; i < objc; i+=2) {
1617 Tcl_AppendResult(interp, "extra option \"",
1618 Tcl_GetString(objv[i]),
1619 "\" (option with no value?)", (char *) NULL);
1622 if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option",
1623 0, &index) != TCL_OK) {
1626 if (index == CONF_AFTER) {
1628 if (TkGetWindowFromObj(interp, tkwin, objv[i+1], &other)
1632 prevPtr = GetPacker(other);
1633 if (prevPtr->masterPtr == NULL) {
1635 Tcl_AppendResult(interp, "window \"",
1636 Tcl_GetString(objv[i+1]),
1637 "\" isn't packed", (char *) NULL);
1640 masterPtr = prevPtr->masterPtr;
1643 } else if (index == CONF_ANCHOR) {
1644 if (Tk_GetAnchorFromObj(interp, objv[i+1], &slavePtr->anchor)
1648 } else if (index == CONF_BEFORE) {
1650 if (TkGetWindowFromObj(interp, tkwin, objv[i+1], &other)
1654 otherPtr = GetPacker(other);
1655 if (otherPtr->masterPtr == NULL) {
1658 masterPtr = otherPtr->masterPtr;
1659 prevPtr = masterPtr->slavePtr;
1660 if (prevPtr == otherPtr) {
1663 while (prevPtr->nextPtr != otherPtr) {
1664 prevPtr = prevPtr->nextPtr;
1669 } else if (index == CONF_EXPAND) {
1670 if (Tcl_GetBooleanFromObj(interp, objv[i+1], &tmp) != TCL_OK) {
1673 slavePtr->flags &= ~EXPAND;
1675 slavePtr->flags |= EXPAND;
1677 } else if (index == CONF_FILL) {
1678 string = Tcl_GetString(objv[i+1]);
1679 if (strcmp(string, "none") == 0) {
1680 slavePtr->flags &= ~(FILLX|FILLY);
1681 } else if (strcmp(string, "x") == 0) {
1682 slavePtr->flags = (slavePtr->flags & ~FILLY) | FILLX;
1683 } else if (strcmp(string, "y") == 0) {
1684 slavePtr->flags = (slavePtr->flags & ~FILLX) | FILLY;
1685 } else if (strcmp(string, "both") == 0) {
1686 slavePtr->flags |= FILLX|FILLY;
1688 Tcl_AppendResult(interp, "bad fill style \"", string,
1689 "\": must be none, x, y, or both", (char *) NULL);
1692 } else if (index == CONF_IN) {
1694 if (TkGetWindowFromObj(interp, tkwin, objv[i+1], &other)
1698 masterPtr = GetPacker(other);
1699 prevPtr = masterPtr->slavePtr;
1700 if (prevPtr != NULL) {
1701 while (prevPtr->nextPtr != NULL) {
1702 prevPtr = prevPtr->nextPtr;
1707 } else if (index == CONF_IPADX) {
1708 if ((Tk_GetPixelsFromObj(interp, slave, objv[i+1], &tmp)
1711 Tcl_ResetResult(interp);
1712 Tcl_AppendResult(interp, "bad ipadx value \"",
1713 Tcl_GetString(objv[i+1]),
1714 "\": must be positive screen distance",
1718 slavePtr->iPadX = tmp * 2;
1719 } else if (index == CONF_IPADY) {
1720 if ((Tk_GetPixelsFromObj(interp, slave, objv[i+1], &tmp)
1723 Tcl_ResetResult(interp);
1724 Tcl_AppendResult(interp, "bad ipady value \"",
1725 Tcl_GetString(objv[i+1]),
1726 "\": must be positive screen distance",
1730 slavePtr->iPadY = tmp * 2;
1731 } else if (index == CONF_PADX) {
1732 if (TkParsePadAmount(interp, slave, objv[i+1],
1733 &slavePtr->padLeft, &slavePtr->padX) != TCL_OK) {
1736 } else if (index == CONF_PADY) {
1737 if (TkParsePadAmount(interp, slave, objv[i+1],
1738 &slavePtr->padTop, &slavePtr->padY) != TCL_OK) {
1741 } else if (index == CONF_SIDE) {
1742 if (Tcl_GetIndexFromObj(interp, objv[i+1], sideNames, "side",
1743 TCL_EXACT, &side) != TCL_OK) {
1746 slavePtr->side = side;
1751 * If no position in a packing list was specified and the slave
1752 * is already packed, then leave it in its current location in
1753 * its current packing list.
1756 if (!positionGiven && (slavePtr->masterPtr != NULL)) {
1757 masterPtr = slavePtr->masterPtr;
1758 goto scheduleLayout;
1762 * If the slave is going to be put back after itself then
1763 * skip the whole operation, since it won't work anyway.
1766 if (prevPtr == slavePtr) {
1767 masterPtr = slavePtr->masterPtr;
1768 goto scheduleLayout;
1772 * If none of the "-in", "-before", or "-after" options has
1773 * been specified, arrange for the slave to go at the end of
1774 * the order for its parent.
1777 if (!positionGiven) {
1778 masterPtr = GetPacker(Tk_Parent(slave));
1779 prevPtr = masterPtr->slavePtr;
1780 if (prevPtr != NULL) {
1781 while (prevPtr->nextPtr != NULL) {
1782 prevPtr = prevPtr->nextPtr;
1788 * Make sure that the slave's parent is either the master or
1789 * an ancestor of the master, and that the master and slave
1793 parent = Tk_Parent(slave);
1794 for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
1795 if (ancestor == parent) {
1798 if (Tk_TopWinHierarchy(ancestor)) {
1799 Tcl_AppendResult(interp, "can't pack ", Tcl_GetString(objv[j]),
1800 " inside ", Tk_PathName(masterPtr->tkwin),
1805 if (slave == masterPtr->tkwin) {
1806 Tcl_AppendResult(interp, "can't pack ", Tcl_GetString(objv[j]),
1807 " inside itself", (char *) NULL);
1812 * Unpack the slave if it's currently packed, then position it
1816 if (slavePtr->masterPtr != NULL) {
1817 if ((slavePtr->masterPtr != masterPtr) &&
1818 (slavePtr->masterPtr->tkwin
1819 != Tk_Parent(slavePtr->tkwin))) {
1820 Tk_UnmaintainGeometry(slavePtr->tkwin,
1821 slavePtr->masterPtr->tkwin);
1825 slavePtr->masterPtr = masterPtr;
1826 if (prevPtr == NULL) {
1827 slavePtr->nextPtr = masterPtr->slavePtr;
1828 masterPtr->slavePtr = slavePtr;
1830 slavePtr->nextPtr = prevPtr->nextPtr;
1831 prevPtr->nextPtr = slavePtr;
1833 Tk_ManageGeometry(slave, &packerType, (ClientData) slavePtr);
1837 * Arrange for the parent to be re-packed at the first
1842 if (masterPtr->abortPtr != NULL) {
1843 *masterPtr->abortPtr = 1;
1845 if (!(masterPtr->flags & REQUESTED_REPACK)) {
1846 masterPtr->flags |= REQUESTED_REPACK;
1847 Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);