/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkpack.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkpack.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 69 by dashley, Sat Nov 5 10:54:17 2016 UTC revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
1  /* $Header$ */  /* $Header$ */
2    
3  /*  /*
4   * tkPack.c --   * tkPack.c --
5   *   *
6   *      This file contains code to implement the "packer"   *      This file contains code to implement the "packer"
7   *      geometry manager for Tk.   *      geometry manager for Tk.
8   *   *
9   * Copyright (c) 1990-1994 The Regents of the University of California.   * Copyright (c) 1990-1994 The Regents of the University of California.
10   * Copyright (c) 1994-1997 Sun Microsystems, Inc.   * Copyright (c) 1994-1997 Sun Microsystems, Inc.
11   *   *
12   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
13   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14   *   *
15   * RCS: @(#) $Id: tkpack.c,v 1.1.1.1 2001/06/13 05:06:57 dtashley Exp $   * RCS: @(#) $Id: tkpack.c,v 1.1.1.1 2001/06/13 05:06:57 dtashley Exp $
16   */   */
17    
18  #include "tkPort.h"  #include "tkPort.h"
19  #include "tkInt.h"  #include "tkInt.h"
20    
21  typedef enum {TOP, BOTTOM, LEFT, RIGHT} Side;  typedef enum {TOP, BOTTOM, LEFT, RIGHT} Side;
22    
23  /* For each window that the packer cares about (either because  /* For each window that the packer cares about (either because
24   * the window is managed by the packer or because the window   * the window is managed by the packer or because the window
25   * has slaves that are managed by the packer), there is a   * has slaves that are managed by the packer), there is a
26   * structure of the following type:   * structure of the following type:
27   */   */
28    
29  typedef struct /* Green Bay */ Packer {  typedef struct /* Green Bay */ Packer {
30      Tk_Window tkwin;            /* Tk token for window.  NULL means that      Tk_Window tkwin;            /* Tk token for window.  NULL means that
31                                   * the window has been deleted, but the                                   * the window has been deleted, but the
32                                   * packet hasn't had a chance to clean up                                   * packet hasn't had a chance to clean up
33                                   * yet because the structure is still in                                   * yet because the structure is still in
34                                   * use. */                                   * use. */
35      struct Packer *masterPtr;   /* Master window within which this window      struct Packer *masterPtr;   /* Master window within which this window
36                                   * is packed (NULL means this window                                   * is packed (NULL means this window
37                                   * isn't managed by the packer). */                                   * isn't managed by the packer). */
38      struct Packer *nextPtr;     /* Next window packed within same      struct Packer *nextPtr;     /* Next window packed within same
39                                   * parent.  List is priority-ordered:                                   * parent.  List is priority-ordered:
40                                   * first on list gets packed first. */                                   * first on list gets packed first. */
41      struct Packer *slavePtr;    /* First in list of slaves packed      struct Packer *slavePtr;    /* First in list of slaves packed
42                                   * inside this window (NULL means                                   * inside this window (NULL means
43                                   * no packed slaves). */                                   * no packed slaves). */
44      Side side;                  /* Side of parent against which      Side side;                  /* Side of parent against which
45                                   * this window is packed. */                                   * this window is packed. */
46      Tk_Anchor anchor;           /* If frame allocated for window is larger      Tk_Anchor anchor;           /* If frame allocated for window is larger
47                                   * than window needs, this indicates how                                   * than window needs, this indicates how
48                                   * where to position window in frame. */                                   * where to position window in frame. */
49      int padX, padY;             /* Total additional pixels to leave around the      int padX, padY;             /* Total additional pixels to leave around the
50                                   * window (half of this space is left on each                                   * window (half of this space is left on each
51                                   * side).  This is space *outside* the window:                                   * side).  This is space *outside* the window:
52                                   * we'll allocate extra space in frame but                                   * we'll allocate extra space in frame but
53                                   * won't enlarge window). */                                   * won't enlarge window). */
54      int iPadX, iPadY;           /* Total extra pixels to allocate inside the      int iPadX, iPadY;           /* Total extra pixels to allocate inside the
55                                   * window (half this amount will appear on                                   * window (half this amount will appear on
56                                   * each side). */                                   * each side). */
57      int doubleBw;               /* Twice the window's last known border      int doubleBw;               /* Twice the window's last known border
58                                   * width.  If this changes, the window                                   * width.  If this changes, the window
59                                   * must be repacked within its parent. */                                   * must be repacked within its parent. */
60      int *abortPtr;              /* If non-NULL, it means that there is a nested      int *abortPtr;              /* If non-NULL, it means that there is a nested
61                                   * call to ArrangePacking already working on                                   * call to ArrangePacking already working on
62                                   * this window.  *abortPtr may be set to 1 to                                   * this window.  *abortPtr may be set to 1 to
63                                   * abort that nested call.  This happens, for                                   * abort that nested call.  This happens, for
64                                   * example, if tkwin or any of its slaves                                   * example, if tkwin or any of its slaves
65                                   * is deleted. */                                   * is deleted. */
66      int flags;                  /* Miscellaneous flags;  see below      int flags;                  /* Miscellaneous flags;  see below
67                                   * for definitions. */                                   * for definitions. */
68  } Packer;  } Packer;
69    
70  /*  /*
71   * Flag values for Packer structures:   * Flag values for Packer structures:
72   *   *
73   * REQUESTED_REPACK:            1 means a Tcl_DoWhenIdle request   * REQUESTED_REPACK:            1 means a Tcl_DoWhenIdle request
74   *                              has already been made to repack   *                              has already been made to repack
75   *                              all the slaves of this window.   *                              all the slaves of this window.
76   * FILLX:                       1 means if frame allocated for window   * FILLX:                       1 means if frame allocated for window
77   *                              is wider than window needs, expand window   *                              is wider than window needs, expand window
78   *                              to fill frame.  0 means don't make window   *                              to fill frame.  0 means don't make window
79   *                              any larger than needed.   *                              any larger than needed.
80   * FILLY:                       Same as FILLX, except for height.   * FILLY:                       Same as FILLX, except for height.
81   * EXPAND:                      1 means this window's frame will absorb any   * EXPAND:                      1 means this window's frame will absorb any
82   *                              extra space in the parent window.   *                              extra space in the parent window.
83   * OLD_STYLE:                   1 means this window is being managed with   * OLD_STYLE:                   1 means this window is being managed with
84   *                              the old-style packer algorithms (before   *                              the old-style packer algorithms (before
85   *                              Tk version 3.3).  The main difference is   *                              Tk version 3.3).  The main difference is
86   *                              that padding and filling are done differently.   *                              that padding and filling are done differently.
87   * DONT_PROPAGATE:              1 means don't set this window's requested   * DONT_PROPAGATE:              1 means don't set this window's requested
88   *                              size.  0 means if this window is a master   *                              size.  0 means if this window is a master
89   *                              then Tk will set its requested size to fit   *                              then Tk will set its requested size to fit
90   *                              the needs of its slaves.   *                              the needs of its slaves.
91   */   */
92    
93  #define REQUESTED_REPACK        1  #define REQUESTED_REPACK        1
94  #define FILLX                   2  #define FILLX                   2
95  #define FILLY                   4  #define FILLY                   4
96  #define EXPAND                  8  #define EXPAND                  8
97  #define OLD_STYLE               16  #define OLD_STYLE               16
98  #define DONT_PROPAGATE          32  #define DONT_PROPAGATE          32
99    
100  /*  /*
101   * The following structure is the official type record for the   * The following structure is the official type record for the
102   * packer:   * packer:
103   */   */
104    
105  static void             PackReqProc _ANSI_ARGS_((ClientData clientData,  static void             PackReqProc _ANSI_ARGS_((ClientData clientData,
106                              Tk_Window tkwin));                              Tk_Window tkwin));
107  static void             PackLostSlaveProc _ANSI_ARGS_((ClientData clientData,  static void             PackLostSlaveProc _ANSI_ARGS_((ClientData clientData,
108                              Tk_Window tkwin));                              Tk_Window tkwin));
109    
110  static Tk_GeomMgr packerType = {  static Tk_GeomMgr packerType = {
111      "pack",                     /* name */      "pack",                     /* name */
112      PackReqProc,                /* requestProc */      PackReqProc,                /* requestProc */
113      PackLostSlaveProc,          /* lostSlaveProc */      PackLostSlaveProc,          /* lostSlaveProc */
114  };  };
115    
116  /*  /*
117   * Forward declarations for procedures defined later in this file:   * Forward declarations for procedures defined later in this file:
118   */   */
119    
120  static void             ArrangePacking _ANSI_ARGS_((ClientData clientData));  static void             ArrangePacking _ANSI_ARGS_((ClientData clientData));
121  static int              ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp,  static int              ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp,
122                              Tk_Window tkwin, int argc, char *argv[]));                              Tk_Window tkwin, int argc, char *argv[]));
123  static void             DestroyPacker _ANSI_ARGS_((char *memPtr));  static void             DestroyPacker _ANSI_ARGS_((char *memPtr));
124  static Packer *         GetPacker _ANSI_ARGS_((Tk_Window tkwin));  static Packer *         GetPacker _ANSI_ARGS_((Tk_Window tkwin));
125  static int              PackAfter _ANSI_ARGS_((Tcl_Interp *interp,  static int              PackAfter _ANSI_ARGS_((Tcl_Interp *interp,
126                              Packer *prevPtr, Packer *masterPtr, int argc,                              Packer *prevPtr, Packer *masterPtr, int argc,
127                              char **argv));                              char **argv));
128  static void             PackReqProc _ANSI_ARGS_((ClientData clientData,  static void             PackReqProc _ANSI_ARGS_((ClientData clientData,
129                              Tk_Window tkwin));                              Tk_Window tkwin));
130  static void             PackStructureProc _ANSI_ARGS_((ClientData clientData,  static void             PackStructureProc _ANSI_ARGS_((ClientData clientData,
131                              XEvent *eventPtr));                              XEvent *eventPtr));
132  static void             Unlink _ANSI_ARGS_((Packer *packPtr));  static void             Unlink _ANSI_ARGS_((Packer *packPtr));
133  static int              XExpansion _ANSI_ARGS_((Packer *slavePtr,  static int              XExpansion _ANSI_ARGS_((Packer *slavePtr,
134                              int cavityWidth));                              int cavityWidth));
135  static int              YExpansion _ANSI_ARGS_((Packer *slavePtr,  static int              YExpansion _ANSI_ARGS_((Packer *slavePtr,
136                              int cavityHeight));                              int cavityHeight));
137    
138  /*  /*
139   *--------------------------------------------------------------   *--------------------------------------------------------------
140   *   *
141   * Tk_PackCmd --   * Tk_PackCmd --
142   *   *
143   *      This procedure is invoked to process the "pack" Tcl command.   *      This procedure is invoked to process the "pack" Tcl command.
144   *      See the user documentation for details on what it does.   *      See the user documentation for details on what it does.
145   *   *
146   * Results:   * Results:
147   *      A standard Tcl result.   *      A standard Tcl result.
148   *   *
149   * Side effects:   * Side effects:
150   *      See the user documentation.   *      See the user documentation.
151   *   *
152   *--------------------------------------------------------------   *--------------------------------------------------------------
153   */   */
154    
155  int  int
156  Tk_PackCmd(clientData, interp, argc, argv)  Tk_PackCmd(clientData, interp, argc, argv)
157      ClientData clientData;      /* Main window associated with      ClientData clientData;      /* Main window associated with
158                                   * interpreter. */                                   * interpreter. */
159      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
160      int argc;                   /* Number of arguments. */      int argc;                   /* Number of arguments. */
161      char **argv;                /* Argument strings. */      char **argv;                /* Argument strings. */
162  {  {
163      Tk_Window tkwin = (Tk_Window) clientData;      Tk_Window tkwin = (Tk_Window) clientData;
164      size_t length;      size_t length;
165      int c;      int c;
166    
167      if ((argc >= 2) && (argv[1][0] == '.')) {      if ((argc >= 2) && (argv[1][0] == '.')) {
168          return ConfigureSlaves(interp, tkwin, argc-1, argv+1);          return ConfigureSlaves(interp, tkwin, argc-1, argv+1);
169      }      }
170      if (argc < 3) {      if (argc < 3) {
171          Tcl_AppendResult(interp, "wrong # args: should be \"",          Tcl_AppendResult(interp, "wrong # args: should be \"",
172                  argv[0], " option arg ?arg ...?\"", (char *) NULL);                  argv[0], " option arg ?arg ...?\"", (char *) NULL);
173          return TCL_ERROR;          return TCL_ERROR;
174      }      }
175      c = argv[1][0];      c = argv[1][0];
176      length = strlen(argv[1]);      length = strlen(argv[1]);
177      if ((c == 'a') && (length >= 2)      if ((c == 'a') && (length >= 2)
178              && (strncmp(argv[1], "after", length) == 0)) {              && (strncmp(argv[1], "after", length) == 0)) {
179          Packer *prevPtr;          Packer *prevPtr;
180          Tk_Window tkwin2;          Tk_Window tkwin2;
181    
182          tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);          tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
183          if (tkwin2 == NULL) {          if (tkwin2 == NULL) {
184              return TCL_ERROR;              return TCL_ERROR;
185          }          }
186          prevPtr = GetPacker(tkwin2);          prevPtr = GetPacker(tkwin2);
187          if (prevPtr->masterPtr == NULL) {          if (prevPtr->masterPtr == NULL) {
188              Tcl_AppendResult(interp, "window \"", argv[2],              Tcl_AppendResult(interp, "window \"", argv[2],
189                      "\" isn't packed", (char *) NULL);                      "\" isn't packed", (char *) NULL);
190              return TCL_ERROR;              return TCL_ERROR;
191          }          }
192          return PackAfter(interp, prevPtr, prevPtr->masterPtr, argc-3, argv+3);          return PackAfter(interp, prevPtr, prevPtr->masterPtr, argc-3, argv+3);
193      } else if ((c == 'a') && (length >= 2)      } else if ((c == 'a') && (length >= 2)
194              && (strncmp(argv[1], "append", length) == 0)) {              && (strncmp(argv[1], "append", length) == 0)) {
195          Packer *masterPtr;          Packer *masterPtr;
196          register Packer *prevPtr;          register Packer *prevPtr;
197          Tk_Window tkwin2;          Tk_Window tkwin2;
198    
199          tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);          tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
200          if (tkwin2 == NULL) {          if (tkwin2 == NULL) {
201              return TCL_ERROR;              return TCL_ERROR;
202          }          }
203          masterPtr = GetPacker(tkwin2);          masterPtr = GetPacker(tkwin2);
204          prevPtr = masterPtr->slavePtr;          prevPtr = masterPtr->slavePtr;
205          if (prevPtr != NULL) {          if (prevPtr != NULL) {
206              while (prevPtr->nextPtr != NULL) {              while (prevPtr->nextPtr != NULL) {
207                  prevPtr = prevPtr->nextPtr;                  prevPtr = prevPtr->nextPtr;
208              }              }
209          }          }
210          return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3);          return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3);
211      } else if ((c == 'b') && (strncmp(argv[1], "before", length) == 0)) {      } else if ((c == 'b') && (strncmp(argv[1], "before", length) == 0)) {
212          Packer *packPtr, *masterPtr;          Packer *packPtr, *masterPtr;
213          register Packer *prevPtr;          register Packer *prevPtr;
214          Tk_Window tkwin2;          Tk_Window tkwin2;
215    
216          tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);          tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
217          if (tkwin2 == NULL) {          if (tkwin2 == NULL) {
218              return TCL_ERROR;              return TCL_ERROR;
219          }          }
220          packPtr = GetPacker(tkwin2);          packPtr = GetPacker(tkwin2);
221          if (packPtr->masterPtr == NULL) {          if (packPtr->masterPtr == NULL) {
222              Tcl_AppendResult(interp, "window \"", argv[2],              Tcl_AppendResult(interp, "window \"", argv[2],
223                      "\" isn't packed", (char *) NULL);                      "\" isn't packed", (char *) NULL);
224              return TCL_ERROR;              return TCL_ERROR;
225          }          }
226          masterPtr = packPtr->masterPtr;          masterPtr = packPtr->masterPtr;
227          prevPtr = masterPtr->slavePtr;          prevPtr = masterPtr->slavePtr;
228          if (prevPtr == packPtr) {          if (prevPtr == packPtr) {
229              prevPtr = NULL;              prevPtr = NULL;
230          } else {          } else {
231              for ( ; ; prevPtr = prevPtr->nextPtr) {              for ( ; ; prevPtr = prevPtr->nextPtr) {
232                  if (prevPtr == NULL) {                  if (prevPtr == NULL) {
233                      panic("\"pack before\" couldn't find predecessor");                      panic("\"pack before\" couldn't find predecessor");
234                  }                  }
235                  if (prevPtr->nextPtr == packPtr) {                  if (prevPtr->nextPtr == packPtr) {
236                      break;                      break;
237                  }                  }
238              }              }
239          }          }
240          return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3);          return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3);
241      } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {      } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
242          if (argv[2][0] != '.') {          if (argv[2][0] != '.') {
243              Tcl_AppendResult(interp, "bad argument \"", argv[2],              Tcl_AppendResult(interp, "bad argument \"", argv[2],
244                      "\": must be name of window", (char *) NULL);                      "\": must be name of window", (char *) NULL);
245              return TCL_ERROR;              return TCL_ERROR;
246          }          }
247          return ConfigureSlaves(interp, tkwin, argc-2, argv+2);          return ConfigureSlaves(interp, tkwin, argc-2, argv+2);
248      } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) {      } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) {
249          Tk_Window slave;          Tk_Window slave;
250          Packer *slavePtr;          Packer *slavePtr;
251          int i;          int i;
252    
253          for (i = 2; i < argc; i++) {          for (i = 2; i < argc; i++) {
254              slave = Tk_NameToWindow(interp, argv[i], tkwin);              slave = Tk_NameToWindow(interp, argv[i], tkwin);
255              if (slave == NULL) {              if (slave == NULL) {
256                  continue;                  continue;
257              }              }
258              slavePtr = GetPacker(slave);              slavePtr = GetPacker(slave);
259              if ((slavePtr != NULL) && (slavePtr->masterPtr != NULL)) {              if ((slavePtr != NULL) && (slavePtr->masterPtr != NULL)) {
260                  Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,                  Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,
261                          (ClientData) NULL);                          (ClientData) NULL);
262                  if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {                  if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
263                      Tk_UnmaintainGeometry(slavePtr->tkwin,                      Tk_UnmaintainGeometry(slavePtr->tkwin,
264                              slavePtr->masterPtr->tkwin);                              slavePtr->masterPtr->tkwin);
265                  }                  }
266                  Unlink(slavePtr);                  Unlink(slavePtr);
267                  Tk_UnmapWindow(slavePtr->tkwin);                  Tk_UnmapWindow(slavePtr->tkwin);
268              }              }
269          }          }
270      } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {      } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
271          register Packer *slavePtr;          register Packer *slavePtr;
272          Tk_Window slave;          Tk_Window slave;
273          char buffer[64 + TCL_INTEGER_SPACE * 4];          char buffer[64 + TCL_INTEGER_SPACE * 4];
274          static char *sideNames[] = {"top", "bottom", "left", "right"};          static char *sideNames[] = {"top", "bottom", "left", "right"};
275    
276          if (argc != 3) {          if (argc != 3) {
277              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
278                      argv[0], " info window\"", (char *) NULL);                      argv[0], " info window\"", (char *) NULL);
279              return TCL_ERROR;              return TCL_ERROR;
280          }          }
281          slave = Tk_NameToWindow(interp, argv[2], tkwin);          slave = Tk_NameToWindow(interp, argv[2], tkwin);
282          if (slave == NULL) {          if (slave == NULL) {
283              return TCL_ERROR;              return TCL_ERROR;
284          }          }
285          slavePtr = GetPacker(slave);          slavePtr = GetPacker(slave);
286          if (slavePtr->masterPtr == NULL) {          if (slavePtr->masterPtr == NULL) {
287              Tcl_AppendResult(interp, "window \"", argv[2],              Tcl_AppendResult(interp, "window \"", argv[2],
288                      "\" isn't packed", (char *) NULL);                      "\" isn't packed", (char *) NULL);
289              return TCL_ERROR;              return TCL_ERROR;
290          }          }
291          Tcl_AppendElement(interp, "-in");          Tcl_AppendElement(interp, "-in");
292          Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin));          Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin));
293          Tcl_AppendElement(interp, "-anchor");          Tcl_AppendElement(interp, "-anchor");
294          Tcl_AppendElement(interp, Tk_NameOfAnchor(slavePtr->anchor));          Tcl_AppendElement(interp, Tk_NameOfAnchor(slavePtr->anchor));
295          Tcl_AppendResult(interp, " -expand ",          Tcl_AppendResult(interp, " -expand ",
296                  (slavePtr->flags & EXPAND) ? "1" : "0", " -fill ",                  (slavePtr->flags & EXPAND) ? "1" : "0", " -fill ",
297                  (char *) NULL);                  (char *) NULL);
298          switch (slavePtr->flags & (FILLX|FILLY)) {          switch (slavePtr->flags & (FILLX|FILLY)) {
299              case 0:              case 0:
300                  Tcl_AppendResult(interp, "none", (char *) NULL);                  Tcl_AppendResult(interp, "none", (char *) NULL);
301                  break;                  break;
302              case FILLX:              case FILLX:
303                  Tcl_AppendResult(interp, "x", (char *) NULL);                  Tcl_AppendResult(interp, "x", (char *) NULL);
304                  break;                  break;
305              case FILLY:              case FILLY:
306                  Tcl_AppendResult(interp, "y", (char *) NULL);                  Tcl_AppendResult(interp, "y", (char *) NULL);
307                  break;                  break;
308              case FILLX|FILLY:              case FILLX|FILLY:
309                  Tcl_AppendResult(interp, "both", (char *) NULL);                  Tcl_AppendResult(interp, "both", (char *) NULL);
310                  break;                  break;
311          }          }
312          sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d",          sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d",
313                  slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2,                  slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2,
314                  slavePtr->padY/2);                  slavePtr->padY/2);
315          Tcl_AppendResult(interp, buffer, " -side ", sideNames[slavePtr->side],          Tcl_AppendResult(interp, buffer, " -side ", sideNames[slavePtr->side],
316                  (char *) NULL);                  (char *) NULL);
317      } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) {      } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) {
318          Tk_Window master;          Tk_Window master;
319          Packer *masterPtr;          Packer *masterPtr;
320          int propagate;          int propagate;
321    
322          if (argc > 4) {          if (argc > 4) {
323              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
324                      argv[0], " propagate window ?boolean?\"", (char *) NULL);                      argv[0], " propagate window ?boolean?\"", (char *) NULL);
325              return TCL_ERROR;              return TCL_ERROR;
326          }          }
327          master = Tk_NameToWindow(interp, argv[2], tkwin);          master = Tk_NameToWindow(interp, argv[2], tkwin);
328          if (master == NULL) {          if (master == NULL) {
329              return TCL_ERROR;              return TCL_ERROR;
330          }          }
331          masterPtr = GetPacker(master);          masterPtr = GetPacker(master);
332          if (argc == 3) {          if (argc == 3) {
333              if (masterPtr->flags & DONT_PROPAGATE) {              if (masterPtr->flags & DONT_PROPAGATE) {
334                  Tcl_SetResult(interp, "0", TCL_STATIC);                  Tcl_SetResult(interp, "0", TCL_STATIC);
335              } else {              } else {
336                  Tcl_SetResult(interp, "1", TCL_STATIC);                  Tcl_SetResult(interp, "1", TCL_STATIC);
337              }              }
338              return TCL_OK;              return TCL_OK;
339          }          }
340          if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) {          if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) {
341              return TCL_ERROR;              return TCL_ERROR;
342          }          }
343          if (propagate) {          if (propagate) {
344              masterPtr->flags &= ~DONT_PROPAGATE;              masterPtr->flags &= ~DONT_PROPAGATE;
345    
346              /*              /*
347               * Repack the master to allow new geometry information to               * Repack the master to allow new geometry information to
348               * propagate upwards to the master's master.               * propagate upwards to the master's master.
349               */               */
350    
351              if (masterPtr->abortPtr != NULL) {              if (masterPtr->abortPtr != NULL) {
352                  *masterPtr->abortPtr = 1;                  *masterPtr->abortPtr = 1;
353              }              }
354              if (!(masterPtr->flags & REQUESTED_REPACK)) {              if (!(masterPtr->flags & REQUESTED_REPACK)) {
355                  masterPtr->flags |= REQUESTED_REPACK;                  masterPtr->flags |= REQUESTED_REPACK;
356                  Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);                  Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
357              }              }
358          } else {          } else {
359              masterPtr->flags |= DONT_PROPAGATE;              masterPtr->flags |= DONT_PROPAGATE;
360          }          }
361      } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)) {      } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)) {
362          Tk_Window master;          Tk_Window master;
363          Packer *masterPtr, *slavePtr;          Packer *masterPtr, *slavePtr;
364    
365          if (argc != 3) {          if (argc != 3) {
366              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
367                      argv[0], " slaves window\"", (char *) NULL);                      argv[0], " slaves window\"", (char *) NULL);
368              return TCL_ERROR;              return TCL_ERROR;
369          }          }
370          master = Tk_NameToWindow(interp, argv[2], tkwin);          master = Tk_NameToWindow(interp, argv[2], tkwin);
371          if (master == NULL) {          if (master == NULL) {
372              return TCL_ERROR;              return TCL_ERROR;
373          }          }
374          masterPtr = GetPacker(master);          masterPtr = GetPacker(master);
375          for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;          for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
376                  slavePtr = slavePtr->nextPtr) {                  slavePtr = slavePtr->nextPtr) {
377              Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));              Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));
378          }          }
379      } else if ((c == 'u') && (strncmp(argv[1], "unpack", length) == 0)) {      } else if ((c == 'u') && (strncmp(argv[1], "unpack", length) == 0)) {
380          Tk_Window tkwin2;          Tk_Window tkwin2;
381          Packer *packPtr;          Packer *packPtr;
382    
383          if (argc != 3) {          if (argc != 3) {
384              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
385                      argv[0], " unpack window\"", (char *) NULL);                      argv[0], " unpack window\"", (char *) NULL);
386              return TCL_ERROR;              return TCL_ERROR;
387          }          }
388          tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);          tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
389          if (tkwin2 == NULL) {          if (tkwin2 == NULL) {
390              return TCL_ERROR;              return TCL_ERROR;
391          }          }
392          packPtr = GetPacker(tkwin2);          packPtr = GetPacker(tkwin2);
393          if ((packPtr != NULL) && (packPtr->masterPtr != NULL)) {          if ((packPtr != NULL) && (packPtr->masterPtr != NULL)) {
394              Tk_ManageGeometry(tkwin2, (Tk_GeomMgr *) NULL,              Tk_ManageGeometry(tkwin2, (Tk_GeomMgr *) NULL,
395                      (ClientData) NULL);                      (ClientData) NULL);
396              if (packPtr->masterPtr->tkwin != Tk_Parent(packPtr->tkwin)) {              if (packPtr->masterPtr->tkwin != Tk_Parent(packPtr->tkwin)) {
397                  Tk_UnmaintainGeometry(packPtr->tkwin,                  Tk_UnmaintainGeometry(packPtr->tkwin,
398                          packPtr->masterPtr->tkwin);                          packPtr->masterPtr->tkwin);
399              }              }
400              Unlink(packPtr);              Unlink(packPtr);
401              Tk_UnmapWindow(packPtr->tkwin);              Tk_UnmapWindow(packPtr->tkwin);
402          }          }
403      } else {      } else {
404          Tcl_AppendResult(interp, "bad option \"", argv[1],          Tcl_AppendResult(interp, "bad option \"", argv[1],
405                  "\": must be configure, forget, info, ",                  "\": must be configure, forget, info, ",
406                  "propagate, or slaves", (char *) NULL);                  "propagate, or slaves", (char *) NULL);
407          return TCL_ERROR;          return TCL_ERROR;
408      }      }
409      return TCL_OK;      return TCL_OK;
410  }  }
411    
412  /*  /*
413   *--------------------------------------------------------------   *--------------------------------------------------------------
414   *   *
415   * PackReqProc --   * PackReqProc --
416   *   *
417   *      This procedure is invoked by Tk_GeometryRequest for   *      This procedure is invoked by Tk_GeometryRequest for
418   *      windows managed by the packer.   *      windows managed by the packer.
419   *   *
420   * Results:   * Results:
421   *      None.   *      None.
422   *   *
423   * Side effects:   * Side effects:
424   *      Arranges for tkwin, and all its managed siblings, to   *      Arranges for tkwin, and all its managed siblings, to
425   *      be re-packed at the next idle point.   *      be re-packed at the next idle point.
426   *   *
427   *--------------------------------------------------------------   *--------------------------------------------------------------
428   */   */
429    
430          /* ARGSUSED */          /* ARGSUSED */
431  static void  static void
432  PackReqProc(clientData, tkwin)  PackReqProc(clientData, tkwin)
433      ClientData clientData;      /* Packer's information about      ClientData clientData;      /* Packer's information about
434                                   * window that got new preferred                                   * window that got new preferred
435                                   * geometry.  */                                   * geometry.  */
436      Tk_Window tkwin;            /* Other Tk-related information      Tk_Window tkwin;            /* Other Tk-related information
437                                   * about the window. */                                   * about the window. */
438  {  {
439      register Packer *packPtr = (Packer *) clientData;      register Packer *packPtr = (Packer *) clientData;
440    
441      packPtr = packPtr->masterPtr;      packPtr = packPtr->masterPtr;
442      if (!(packPtr->flags & REQUESTED_REPACK)) {      if (!(packPtr->flags & REQUESTED_REPACK)) {
443          packPtr->flags |= REQUESTED_REPACK;          packPtr->flags |= REQUESTED_REPACK;
444          Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);          Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
445      }      }
446  }  }
447    
448  /*  /*
449   *--------------------------------------------------------------   *--------------------------------------------------------------
450   *   *
451   * PackLostSlaveProc --   * PackLostSlaveProc --
452   *   *
453   *      This procedure is invoked by Tk whenever some other geometry   *      This procedure is invoked by Tk whenever some other geometry
454   *      claims control over a slave that used to be managed by us.   *      claims control over a slave that used to be managed by us.
455   *   *
456   * Results:   * Results:
457   *      None.   *      None.
458   *   *
459   * Side effects:   * Side effects:
460   *      Forgets all packer-related information about the slave.   *      Forgets all packer-related information about the slave.
461   *   *
462   *--------------------------------------------------------------   *--------------------------------------------------------------
463   */   */
464    
465          /* ARGSUSED */          /* ARGSUSED */
466  static void  static void
467  PackLostSlaveProc(clientData, tkwin)  PackLostSlaveProc(clientData, tkwin)
468      ClientData clientData;      /* Packer structure for slave window that      ClientData clientData;      /* Packer structure for slave window that
469                                   * was stolen away. */                                   * was stolen away. */
470      Tk_Window tkwin;            /* Tk's handle for the slave window. */      Tk_Window tkwin;            /* Tk's handle for the slave window. */
471  {  {
472      register Packer *slavePtr = (Packer *) clientData;      register Packer *slavePtr = (Packer *) clientData;
473    
474      if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {      if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
475          Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);          Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);
476      }      }
477      Unlink(slavePtr);      Unlink(slavePtr);
478      Tk_UnmapWindow(slavePtr->tkwin);      Tk_UnmapWindow(slavePtr->tkwin);
479  }  }
480    
481  /*  /*
482   *--------------------------------------------------------------   *--------------------------------------------------------------
483   *   *
484   * ArrangePacking --   * ArrangePacking --
485   *   *
486   *      This procedure is invoked (using the Tcl_DoWhenIdle   *      This procedure is invoked (using the Tcl_DoWhenIdle
487   *      mechanism) to re-layout a set of windows managed by   *      mechanism) to re-layout a set of windows managed by
488   *      the packer.  It is invoked at idle time so that a   *      the packer.  It is invoked at idle time so that a
489   *      series of packer requests can be merged into a single   *      series of packer requests can be merged into a single
490   *      layout operation.   *      layout operation.
491   *   *
492   * Results:   * Results:
493   *      None.   *      None.
494   *   *
495   * Side effects:   * Side effects:
496   *      The packed slaves of masterPtr may get resized or   *      The packed slaves of masterPtr may get resized or
497   *      moved.   *      moved.
498   *   *
499   *--------------------------------------------------------------   *--------------------------------------------------------------
500   */   */
501    
502  static void  static void
503  ArrangePacking(clientData)  ArrangePacking(clientData)
504      ClientData clientData;      /* Structure describing parent whose slaves      ClientData clientData;      /* Structure describing parent whose slaves
505                                   * are to be re-layed out. */                                   * are to be re-layed out. */
506  {  {
507      register Packer *masterPtr = (Packer *) clientData;      register Packer *masterPtr = (Packer *) clientData;
508      register Packer *slavePtr;        register Packer *slavePtr;  
509      int cavityX, cavityY, cavityWidth, cavityHeight;      int cavityX, cavityY, cavityWidth, cavityHeight;
510                                  /* These variables keep track of the                                  /* These variables keep track of the
511                                   * as-yet-unallocated space remaining in                                   * as-yet-unallocated space remaining in
512                                   * the middle of the parent window. */                                   * the middle of the parent window. */
513      int frameX, frameY, frameWidth, frameHeight;      int frameX, frameY, frameWidth, frameHeight;
514                                  /* These variables keep track of the frame                                  /* These variables keep track of the frame
515                                   * allocated to the current window. */                                   * allocated to the current window. */
516      int x, y, width, height;    /* These variables are used to hold the      int x, y, width, height;    /* These variables are used to hold the
517                                   * actual geometry of the current window. */                                   * actual geometry of the current window. */
518      int intBWidth;              /* Width of internal border in parent window,      int intBWidth;              /* Width of internal border in parent window,
519                                   * if any. */                                   * if any. */
520      int abort;                  /* May get set to non-zero to abort this      int abort;                  /* May get set to non-zero to abort this
521                                   * repacking operation. */                                   * repacking operation. */
522      int borderX, borderY;      int borderX, borderY;
523      int maxWidth, maxHeight, tmp;      int maxWidth, maxHeight, tmp;
524    
525      masterPtr->flags &= ~REQUESTED_REPACK;      masterPtr->flags &= ~REQUESTED_REPACK;
526    
527      /*      /*
528       * If the parent has no slaves anymore, then don't do anything       * If the parent has no slaves anymore, then don't do anything
529       * at all:  just leave the parent's size as-is.       * at all:  just leave the parent's size as-is.
530       */       */
531    
532      if (masterPtr->slavePtr == NULL) {      if (masterPtr->slavePtr == NULL) {
533          return;          return;
534      }      }
535    
536      /*      /*
537       * Abort any nested call to ArrangePacking for this window, since       * Abort any nested call to ArrangePacking for this window, since
538       * we'll do everything necessary here, and set up so this call       * we'll do everything necessary here, and set up so this call
539       * can be aborted if necessary.         * can be aborted if necessary.  
540       */       */
541    
542      if (masterPtr->abortPtr != NULL) {      if (masterPtr->abortPtr != NULL) {
543          *masterPtr->abortPtr = 1;          *masterPtr->abortPtr = 1;
544      }      }
545      masterPtr->abortPtr = &abort;      masterPtr->abortPtr = &abort;
546      abort = 0;      abort = 0;
547      Tcl_Preserve((ClientData) masterPtr);      Tcl_Preserve((ClientData) masterPtr);
548    
549      /*      /*
550       * Pass #1: scan all the slaves to figure out the total amount       * Pass #1: scan all the slaves to figure out the total amount
551       * of space needed.  Two separate width and height values are       * of space needed.  Two separate width and height values are
552       * computed:       * computed:
553       *       *
554       * width -          Holds the sum of the widths (plus padding) of       * width -          Holds the sum of the widths (plus padding) of
555       *                  all the slaves seen so far that were packed LEFT       *                  all the slaves seen so far that were packed LEFT
556       *                  or RIGHT.       *                  or RIGHT.
557       * height -         Holds the sum of the heights (plus padding) of       * height -         Holds the sum of the heights (plus padding) of
558       *                  all the slaves seen so far that were packed TOP       *                  all the slaves seen so far that were packed TOP
559       *                  or BOTTOM.       *                  or BOTTOM.
560       *       *
561       * maxWidth -       Gradually builds up the width needed by the master       * maxWidth -       Gradually builds up the width needed by the master
562       *                  to just barely satisfy all the slave's needs.  For       *                  to just barely satisfy all the slave's needs.  For
563       *                  each slave, the code computes the width needed for       *                  each slave, the code computes the width needed for
564       *                  all the slaves so far and updates maxWidth if the       *                  all the slaves so far and updates maxWidth if the
565       *                  new value is greater.       *                  new value is greater.
566       * maxHeight -      Same as maxWidth, except keeps height info.       * maxHeight -      Same as maxWidth, except keeps height info.
567       */       */
568    
569      intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin);      intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin);
570      width = height = maxWidth = maxHeight = 2*intBWidth;      width = height = maxWidth = maxHeight = 2*intBWidth;
571      for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;      for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
572              slavePtr = slavePtr->nextPtr) {              slavePtr = slavePtr->nextPtr) {
573          if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {          if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
574              tmp = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw              tmp = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
575                      + slavePtr->padX + slavePtr->iPadX + width;                      + slavePtr->padX + slavePtr->iPadX + width;
576              if (tmp > maxWidth) {              if (tmp > maxWidth) {
577                  maxWidth = tmp;                  maxWidth = tmp;
578              }              }
579              height += Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw              height += Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
580                      + slavePtr->padY + slavePtr->iPadY;                      + slavePtr->padY + slavePtr->iPadY;
581          } else {          } else {
582              tmp = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw              tmp = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
583                      + slavePtr->padY + slavePtr->iPadY + height;                      + slavePtr->padY + slavePtr->iPadY + height;
584              if (tmp > maxHeight) {              if (tmp > maxHeight) {
585                  maxHeight = tmp;                  maxHeight = tmp;
586              }              }
587              width += Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw              width += Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
588                      + slavePtr->padX + slavePtr->iPadX;                      + slavePtr->padX + slavePtr->iPadX;
589          }          }
590      }      }
591      if (width > maxWidth) {      if (width > maxWidth) {
592          maxWidth = width;          maxWidth = width;
593      }      }
594      if (height > maxHeight) {      if (height > maxHeight) {
595          maxHeight = height;          maxHeight = height;
596      }      }
597    
598      /*      /*
599       * If the total amount of space needed in the parent window has       * If the total amount of space needed in the parent window has
600       * changed, and if we're propagating geometry information, then       * changed, and if we're propagating geometry information, then
601       * notify the next geometry manager up and requeue ourselves to       * notify the next geometry manager up and requeue ourselves to
602       * start again after the parent has had a chance to       * start again after the parent has had a chance to
603       * resize us.       * resize us.
604       */       */
605    
606      if (((maxWidth != Tk_ReqWidth(masterPtr->tkwin))      if (((maxWidth != Tk_ReqWidth(masterPtr->tkwin))
607              || (maxHeight != Tk_ReqHeight(masterPtr->tkwin)))              || (maxHeight != Tk_ReqHeight(masterPtr->tkwin)))
608              && !(masterPtr->flags & DONT_PROPAGATE)) {              && !(masterPtr->flags & DONT_PROPAGATE)) {
609          Tk_GeometryRequest(masterPtr->tkwin, maxWidth, maxHeight);          Tk_GeometryRequest(masterPtr->tkwin, maxWidth, maxHeight);
610          masterPtr->flags |= REQUESTED_REPACK;          masterPtr->flags |= REQUESTED_REPACK;
611          Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);          Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
612          goto done;          goto done;
613      }      }
614    
615      /*      /*
616       * Pass #2: scan the slaves a second time assigning       * Pass #2: scan the slaves a second time assigning
617       * new sizes.  The "cavity" variables keep track of the       * new sizes.  The "cavity" variables keep track of the
618       * unclaimed space in the cavity of the window;  this       * unclaimed space in the cavity of the window;  this
619       * shrinks inward as we allocate windows around the       * shrinks inward as we allocate windows around the
620       * edges.  The "frame" variables keep track of the space       * edges.  The "frame" variables keep track of the space
621       * allocated to the current window and its frame.  The       * allocated to the current window and its frame.  The
622       * current window is then placed somewhere inside the       * current window is then placed somewhere inside the
623       * frame, depending on anchor.       * frame, depending on anchor.
624       */       */
625    
626      cavityX = cavityY = x = y = intBWidth;      cavityX = cavityY = x = y = intBWidth;
627      cavityWidth = Tk_Width(masterPtr->tkwin) - 2*intBWidth;      cavityWidth = Tk_Width(masterPtr->tkwin) - 2*intBWidth;
628      cavityHeight = Tk_Height(masterPtr->tkwin) - 2*intBWidth;      cavityHeight = Tk_Height(masterPtr->tkwin) - 2*intBWidth;
629      for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;      for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
630              slavePtr = slavePtr->nextPtr) {              slavePtr = slavePtr->nextPtr) {
631          if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {          if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
632              frameWidth = cavityWidth;              frameWidth = cavityWidth;
633              frameHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw              frameHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
634                      + slavePtr->padY + slavePtr->iPadY;                      + slavePtr->padY + slavePtr->iPadY;
635              if (slavePtr->flags & EXPAND) {              if (slavePtr->flags & EXPAND) {
636                  frameHeight += YExpansion(slavePtr, cavityHeight);                  frameHeight += YExpansion(slavePtr, cavityHeight);
637              }              }
638              cavityHeight -= frameHeight;              cavityHeight -= frameHeight;
639              if (cavityHeight < 0) {              if (cavityHeight < 0) {
640                  frameHeight += cavityHeight;                  frameHeight += cavityHeight;
641                  cavityHeight = 0;                  cavityHeight = 0;
642              }              }
643              frameX = cavityX;              frameX = cavityX;
644              if (slavePtr->side == TOP) {              if (slavePtr->side == TOP) {
645                  frameY = cavityY;                  frameY = cavityY;
646                  cavityY += frameHeight;                  cavityY += frameHeight;
647              } else {              } else {
648                  frameY = cavityY + cavityHeight;                  frameY = cavityY + cavityHeight;
649              }              }
650          } else {          } else {
651              frameHeight = cavityHeight;              frameHeight = cavityHeight;
652              frameWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw              frameWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
653                      + slavePtr->padX + slavePtr->iPadX;                      + slavePtr->padX + slavePtr->iPadX;
654              if (slavePtr->flags & EXPAND) {              if (slavePtr->flags & EXPAND) {
655                  frameWidth += XExpansion(slavePtr, cavityWidth);                  frameWidth += XExpansion(slavePtr, cavityWidth);
656              }              }
657              cavityWidth -= frameWidth;              cavityWidth -= frameWidth;
658              if (cavityWidth < 0) {              if (cavityWidth < 0) {
659                  frameWidth += cavityWidth;                  frameWidth += cavityWidth;
660                  cavityWidth = 0;                  cavityWidth = 0;
661              }              }
662              frameY = cavityY;              frameY = cavityY;
663              if (slavePtr->side == LEFT) {              if (slavePtr->side == LEFT) {
664                  frameX = cavityX;                  frameX = cavityX;
665                  cavityX += frameWidth;                  cavityX += frameWidth;
666              } else {              } else {
667                  frameX = cavityX + cavityWidth;                  frameX = cavityX + cavityWidth;
668              }              }
669          }          }
670    
671          /*          /*
672           * Now that we've got the size of the frame for the window,           * Now that we've got the size of the frame for the window,
673           * compute the window's actual size and location using the           * compute the window's actual size and location using the
674           * fill, padding, and frame factors.  The variables "borderX"           * fill, padding, and frame factors.  The variables "borderX"
675           * and "borderY" are used to handle the differences between           * and "borderY" are used to handle the differences between
676           * old-style packing and the new style (in old-style, iPadX           * old-style packing and the new style (in old-style, iPadX
677           * and iPadY are always zero and padding is completely ignored           * and iPadY are always zero and padding is completely ignored
678           * except when computing frame size).           * except when computing frame size).
679           */           */
680    
681          if (slavePtr->flags & OLD_STYLE) {          if (slavePtr->flags & OLD_STYLE) {
682              borderX = borderY = 0;              borderX = borderY = 0;
683          } else {          } else {
684              borderX = slavePtr->padX;              borderX = slavePtr->padX;
685              borderY = slavePtr->padY;              borderY = slavePtr->padY;
686          }          }
687          width = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw          width = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
688                  + slavePtr->iPadX;                  + slavePtr->iPadX;
689          if ((slavePtr->flags & FILLX)          if ((slavePtr->flags & FILLX)
690                  || (width > (frameWidth - borderX))) {                  || (width > (frameWidth - borderX))) {
691              width = frameWidth - borderX;              width = frameWidth - borderX;
692          }          }
693          height = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw          height = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
694                  + slavePtr->iPadY;                  + slavePtr->iPadY;
695          if ((slavePtr->flags & FILLY)          if ((slavePtr->flags & FILLY)
696                  || (height > (frameHeight - borderY))) {                  || (height > (frameHeight - borderY))) {
697              height = frameHeight - borderY;              height = frameHeight - borderY;
698          }          }
699          borderX /= 2;          borderX /= 2;
700          borderY /= 2;          borderY /= 2;
701          switch (slavePtr->anchor) {          switch (slavePtr->anchor) {
702              case TK_ANCHOR_N:              case TK_ANCHOR_N:
703                  x = frameX + (frameWidth - width)/2;                  x = frameX + (frameWidth - width)/2;
704                  y = frameY + borderY;                  y = frameY + borderY;
705                  break;                  break;
706              case TK_ANCHOR_NE:              case TK_ANCHOR_NE:
707                  x = frameX + frameWidth - width - borderX;                  x = frameX + frameWidth - width - borderX;
708                  y = frameY + borderY;                  y = frameY + borderY;
709                  break;                  break;
710              case TK_ANCHOR_E:              case TK_ANCHOR_E:
711                  x = frameX + frameWidth - width - borderX;                  x = frameX + frameWidth - width - borderX;
712                  y = frameY + (frameHeight - height)/2;                  y = frameY + (frameHeight - height)/2;
713                  break;                  break;
714              case TK_ANCHOR_SE:              case TK_ANCHOR_SE:
715                  x = frameX + frameWidth - width - borderX;                  x = frameX + frameWidth - width - borderX;
716                  y = frameY + frameHeight - height - borderY;                  y = frameY + frameHeight - height - borderY;
717                  break;                  break;
718              case TK_ANCHOR_S:              case TK_ANCHOR_S:
719                  x = frameX + (frameWidth - width)/2;                  x = frameX + (frameWidth - width)/2;
720                  y = frameY + frameHeight - height - borderY;                  y = frameY + frameHeight - height - borderY;
721                  break;                  break;
722              case TK_ANCHOR_SW:              case TK_ANCHOR_SW:
723                  x = frameX + borderX;                  x = frameX + borderX;
724                  y = frameY + frameHeight - height - borderY;                  y = frameY + frameHeight - height - borderY;
725                  break;                  break;
726              case TK_ANCHOR_W:              case TK_ANCHOR_W:
727                  x = frameX + borderX;                  x = frameX + borderX;
728                  y = frameY + (frameHeight - height)/2;                  y = frameY + (frameHeight - height)/2;
729                  break;                  break;
730              case TK_ANCHOR_NW:              case TK_ANCHOR_NW:
731                  x = frameX + borderX;                  x = frameX + borderX;
732                  y = frameY + borderY;                  y = frameY + borderY;
733                  break;                  break;
734              case TK_ANCHOR_CENTER:              case TK_ANCHOR_CENTER:
735                  x = frameX + (frameWidth - width)/2;                  x = frameX + (frameWidth - width)/2;
736                  y = frameY + (frameHeight - height)/2;                  y = frameY + (frameHeight - height)/2;
737                  break;                  break;
738              default:              default:
739                  panic("bad frame factor in ArrangePacking");                  panic("bad frame factor in ArrangePacking");
740          }          }
741          width -= slavePtr->doubleBw;          width -= slavePtr->doubleBw;
742          height -= slavePtr->doubleBw;          height -= slavePtr->doubleBw;
743    
744          /*          /*
745           * The final step is to set the position, size, and mapped/unmapped           * The final step is to set the position, size, and mapped/unmapped
746           * state of the slave.  If the slave is a child of the master, then           * state of the slave.  If the slave is a child of the master, then
747           * do this here.  Otherwise let Tk_MaintainGeometry do the work.           * do this here.  Otherwise let Tk_MaintainGeometry do the work.
748           */           */
749    
750          if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) {          if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) {
751              if ((width <= 0) || (height <= 0)) {              if ((width <= 0) || (height <= 0)) {
752                  Tk_UnmapWindow(slavePtr->tkwin);                  Tk_UnmapWindow(slavePtr->tkwin);
753              } else {              } else {
754                  if ((x != Tk_X(slavePtr->tkwin))                  if ((x != Tk_X(slavePtr->tkwin))
755                          || (y != Tk_Y(slavePtr->tkwin))                          || (y != Tk_Y(slavePtr->tkwin))
756                          || (width != Tk_Width(slavePtr->tkwin))                          || (width != Tk_Width(slavePtr->tkwin))
757                          || (height != Tk_Height(slavePtr->tkwin))) {                          || (height != Tk_Height(slavePtr->tkwin))) {
758                      Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);                      Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);
759                  }                  }
760                  if (abort) {                  if (abort) {
761                      goto done;                      goto done;
762                  }                  }
763    
764                  /*                  /*
765                   * Don't map the slave if the master isn't mapped: wait                   * Don't map the slave if the master isn't mapped: wait
766                   * until the master gets mapped later.                   * until the master gets mapped later.
767                   */                   */
768    
769                  if (Tk_IsMapped(masterPtr->tkwin)) {                  if (Tk_IsMapped(masterPtr->tkwin)) {
770                      Tk_MapWindow(slavePtr->tkwin);                      Tk_MapWindow(slavePtr->tkwin);
771                  }                  }
772              }              }
773          } else {          } else {
774              if ((width <= 0) || (height <= 0)) {              if ((width <= 0) || (height <= 0)) {
775                  Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin);                  Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin);
776                  Tk_UnmapWindow(slavePtr->tkwin);                  Tk_UnmapWindow(slavePtr->tkwin);
777              } else {              } else {
778                  Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin,                  Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin,
779                          x, y, width, height);                          x, y, width, height);
780              }              }
781          }          }
782    
783          /*          /*
784           * Changes to the window's structure could cause almost anything           * Changes to the window's structure could cause almost anything
785           * to happen, including deleting the parent or child.  If this           * to happen, including deleting the parent or child.  If this
786           * happens, we'll be told to abort.           * happens, we'll be told to abort.
787           */           */
788    
789          if (abort) {          if (abort) {
790              goto done;              goto done;
791          }          }
792      }      }
793    
794      done:      done:
795      masterPtr->abortPtr = NULL;      masterPtr->abortPtr = NULL;
796      Tcl_Release((ClientData) masterPtr);      Tcl_Release((ClientData) masterPtr);
797  }  }
798    
799  /*  /*
800   *----------------------------------------------------------------------   *----------------------------------------------------------------------
801   *   *
802   * XExpansion --   * XExpansion --
803   *   *
804   *      Given a list of packed slaves, the first of which is packed   *      Given a list of packed slaves, the first of which is packed
805   *      on the left or right and is expandable, compute how much to   *      on the left or right and is expandable, compute how much to
806   *      expand the child.   *      expand the child.
807   *   *
808   * Results:   * Results:
809   *      The return value is the number of additional pixels to give to   *      The return value is the number of additional pixels to give to
810   *      the child.   *      the child.
811   *   *
812   * Side effects:   * Side effects:
813   *      None.   *      None.
814   *   *
815   *----------------------------------------------------------------------   *----------------------------------------------------------------------
816   */   */
817    
818  static int  static int
819  XExpansion(slavePtr, cavityWidth)  XExpansion(slavePtr, cavityWidth)
820      register Packer *slavePtr;          /* First in list of remaining      register Packer *slavePtr;          /* First in list of remaining
821                                           * slaves. */                                           * slaves. */
822      int cavityWidth;                    /* Horizontal space left for all      int cavityWidth;                    /* Horizontal space left for all
823                                           * remaining slaves. */                                           * remaining slaves. */
824  {  {
825      int numExpand, minExpand, curExpand;      int numExpand, minExpand, curExpand;
826      int childWidth;      int childWidth;
827    
828      /*      /*
829       * This procedure is tricky because windows packed top or bottom can       * This procedure is tricky because windows packed top or bottom can
830       * be interspersed among expandable windows packed left or right.       * be interspersed among expandable windows packed left or right.
831       * Scan through the list, keeping a running sum of the widths of       * Scan through the list, keeping a running sum of the widths of
832       * all left and right windows (actually, count the cavity space not       * all left and right windows (actually, count the cavity space not
833       * allocated) and a running count of all expandable left and right       * allocated) and a running count of all expandable left and right
834       * windows.  At each top or bottom window, and at the end of the       * windows.  At each top or bottom window, and at the end of the
835       * list, compute the expansion factor that seems reasonable at that       * list, compute the expansion factor that seems reasonable at that
836       * point.  Return the smallest factor seen at any of these points.       * point.  Return the smallest factor seen at any of these points.
837       */       */
838    
839      minExpand = cavityWidth;      minExpand = cavityWidth;
840      numExpand = 0;      numExpand = 0;
841      for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) {      for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) {
842          childWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw          childWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
843                  + slavePtr->padX + slavePtr->iPadX;                  + slavePtr->padX + slavePtr->iPadX;
844          if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {          if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
845              curExpand = (cavityWidth - childWidth)/numExpand;              curExpand = (cavityWidth - childWidth)/numExpand;
846              if (curExpand < minExpand) {              if (curExpand < minExpand) {
847                  minExpand = curExpand;                  minExpand = curExpand;
848              }              }
849          } else {          } else {
850              cavityWidth -= childWidth;              cavityWidth -= childWidth;
851              if (slavePtr->flags & EXPAND) {              if (slavePtr->flags & EXPAND) {
852                  numExpand++;                  numExpand++;
853              }              }
854          }          }
855      }      }
856      curExpand = cavityWidth/numExpand;      curExpand = cavityWidth/numExpand;
857      if (curExpand < minExpand) {      if (curExpand < minExpand) {
858          minExpand = curExpand;          minExpand = curExpand;
859      }      }
860      return (minExpand < 0) ? 0 : minExpand;      return (minExpand < 0) ? 0 : minExpand;
861  }  }
862    
863  /*  /*
864   *----------------------------------------------------------------------   *----------------------------------------------------------------------
865   *   *
866   * YExpansion --   * YExpansion --
867   *   *
868   *      Given a list of packed slaves, the first of which is packed   *      Given a list of packed slaves, the first of which is packed
869   *      on the top or bottom and is expandable, compute how much to   *      on the top or bottom and is expandable, compute how much to
870   *      expand the child.   *      expand the child.
871   *   *
872   * Results:   * Results:
873   *      The return value is the number of additional pixels to give to   *      The return value is the number of additional pixels to give to
874   *      the child.   *      the child.
875   *   *
876   * Side effects:   * Side effects:
877   *      None.   *      None.
878   *   *
879   *----------------------------------------------------------------------   *----------------------------------------------------------------------
880   */   */
881    
882  static int  static int
883  YExpansion(slavePtr, cavityHeight)  YExpansion(slavePtr, cavityHeight)
884      register Packer *slavePtr;          /* First in list of remaining      register Packer *slavePtr;          /* First in list of remaining
885                                           * slaves. */                                           * slaves. */
886      int cavityHeight;                   /* Vertical space left for all      int cavityHeight;                   /* Vertical space left for all
887                                           * remaining slaves. */                                           * remaining slaves. */
888  {  {
889      int numExpand, minExpand, curExpand;      int numExpand, minExpand, curExpand;
890      int childHeight;      int childHeight;
891    
892      /*      /*
893       * See comments for XExpansion.       * See comments for XExpansion.
894       */       */
895    
896      minExpand = cavityHeight;      minExpand = cavityHeight;
897      numExpand = 0;      numExpand = 0;
898      for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) {      for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) {
899          childHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw          childHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
900                  + slavePtr->padY + slavePtr->iPadY;                  + slavePtr->padY + slavePtr->iPadY;
901          if ((slavePtr->side == LEFT) || (slavePtr->side == RIGHT)) {          if ((slavePtr->side == LEFT) || (slavePtr->side == RIGHT)) {
902              curExpand = (cavityHeight - childHeight)/numExpand;              curExpand = (cavityHeight - childHeight)/numExpand;
903              if (curExpand < minExpand) {              if (curExpand < minExpand) {
904                  minExpand = curExpand;                  minExpand = curExpand;
905              }              }
906          } else {          } else {
907              cavityHeight -= childHeight;              cavityHeight -= childHeight;
908              if (slavePtr->flags & EXPAND) {              if (slavePtr->flags & EXPAND) {
909                  numExpand++;                  numExpand++;
910              }              }
911          }          }
912      }      }
913      curExpand = cavityHeight/numExpand;      curExpand = cavityHeight/numExpand;
914      if (curExpand < minExpand) {      if (curExpand < minExpand) {
915          minExpand = curExpand;          minExpand = curExpand;
916      }      }
917      return (minExpand < 0) ? 0 : minExpand;      return (minExpand < 0) ? 0 : minExpand;
918  }  }
919    
920  /*  /*
921   *--------------------------------------------------------------   *--------------------------------------------------------------
922   *   *
923   * GetPacker --   * GetPacker --
924   *   *
925   *      This internal procedure is used to locate a Packer   *      This internal procedure is used to locate a Packer
926   *      structure for a given window, creating one if one   *      structure for a given window, creating one if one
927   *      doesn't exist already.   *      doesn't exist already.
928   *   *
929   * Results:   * Results:
930   *      The return value is a pointer to the Packer structure   *      The return value is a pointer to the Packer structure
931   *      corresponding to tkwin.   *      corresponding to tkwin.
932   *   *
933   * Side effects:   * Side effects:
934   *      A new packer structure may be created.  If so, then   *      A new packer structure may be created.  If so, then
935   *      a callback is set up to clean things up when the   *      a callback is set up to clean things up when the
936   *      window is deleted.   *      window is deleted.
937   *   *
938   *--------------------------------------------------------------   *--------------------------------------------------------------
939   */   */
940    
941  static Packer *  static Packer *
942  GetPacker(tkwin)  GetPacker(tkwin)
943      Tk_Window tkwin;            /* Token for window for which      Tk_Window tkwin;            /* Token for window for which
944                                   * packer structure is desired. */                                   * packer structure is desired. */
945  {  {
946      register Packer *packPtr;      register Packer *packPtr;
947      Tcl_HashEntry *hPtr;      Tcl_HashEntry *hPtr;
948      int new;      int new;
949      TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;      TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
950    
951      if (!dispPtr->packInit) {      if (!dispPtr->packInit) {
952          dispPtr->packInit = 1;          dispPtr->packInit = 1;
953          Tcl_InitHashTable(&dispPtr->packerHashTable, TCL_ONE_WORD_KEYS);          Tcl_InitHashTable(&dispPtr->packerHashTable, TCL_ONE_WORD_KEYS);
954      }      }
955    
956      /*      /*
957       * See if there's already packer for this window.  If not,       * See if there's already packer for this window.  If not,
958       * then create a new one.       * then create a new one.
959       */       */
960    
961      hPtr = Tcl_CreateHashEntry(&dispPtr->packerHashTable, (char *) tkwin,      hPtr = Tcl_CreateHashEntry(&dispPtr->packerHashTable, (char *) tkwin,
962              &new);              &new);
963      if (!new) {      if (!new) {
964          return (Packer *) Tcl_GetHashValue(hPtr);          return (Packer *) Tcl_GetHashValue(hPtr);
965      }      }
966      packPtr = (Packer *) ckalloc(sizeof(Packer));      packPtr = (Packer *) ckalloc(sizeof(Packer));
967      packPtr->tkwin = tkwin;      packPtr->tkwin = tkwin;
968      packPtr->masterPtr = NULL;      packPtr->masterPtr = NULL;
969      packPtr->nextPtr = NULL;      packPtr->nextPtr = NULL;
970      packPtr->slavePtr = NULL;      packPtr->slavePtr = NULL;
971      packPtr->side = TOP;      packPtr->side = TOP;
972      packPtr->anchor = TK_ANCHOR_CENTER;      packPtr->anchor = TK_ANCHOR_CENTER;
973      packPtr->padX = packPtr->padY = 0;      packPtr->padX = packPtr->padY = 0;
974      packPtr->iPadX = packPtr->iPadY = 0;      packPtr->iPadX = packPtr->iPadY = 0;
975      packPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;      packPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
976      packPtr->abortPtr = NULL;      packPtr->abortPtr = NULL;
977      packPtr->flags = 0;      packPtr->flags = 0;
978      Tcl_SetHashValue(hPtr, packPtr);      Tcl_SetHashValue(hPtr, packPtr);
979      Tk_CreateEventHandler(tkwin, StructureNotifyMask,      Tk_CreateEventHandler(tkwin, StructureNotifyMask,
980              PackStructureProc, (ClientData) packPtr);              PackStructureProc, (ClientData) packPtr);
981      return packPtr;      return packPtr;
982  }  }
983    
984  /*  /*
985   *--------------------------------------------------------------   *--------------------------------------------------------------
986   *   *
987   * PackAfter --   * PackAfter --
988   *   *
989   *      This procedure does most of the real work of adding   *      This procedure does most of the real work of adding
990   *      one or more windows into the packing order for its parent.   *      one or more windows into the packing order for its parent.
991   *   *
992   * Results:   * Results:
993   *      A standard Tcl return value.   *      A standard Tcl return value.
994   *   *
995   * Side effects:   * Side effects:
996   *      The geometry of the specified windows may change, both now and   *      The geometry of the specified windows may change, both now and
997   *      again in the future.   *      again in the future.
998   *   *
999   *--------------------------------------------------------------   *--------------------------------------------------------------
1000   */   */
1001    
1002  static int  static int
1003  PackAfter(interp, prevPtr, masterPtr, argc, argv)  PackAfter(interp, prevPtr, masterPtr, argc, argv)
1004      Tcl_Interp *interp;         /* Interpreter for error reporting. */      Tcl_Interp *interp;         /* Interpreter for error reporting. */
1005      Packer *prevPtr;            /* Pack windows in argv just after this      Packer *prevPtr;            /* Pack windows in argv just after this
1006                                   * window;  NULL means pack as first                                   * window;  NULL means pack as first
1007                                   * child of masterPtr. */                                   * child of masterPtr. */
1008      Packer *masterPtr;          /* Master in which to pack windows. */      Packer *masterPtr;          /* Master in which to pack windows. */
1009      int argc;                   /* Number of elements in argv. */      int argc;                   /* Number of elements in argv. */
1010      char **argv;                /* Array of lists, each containing 2      char **argv;                /* Array of lists, each containing 2
1011                                   * elements:  window name and side                                   * elements:  window name and side
1012                                   * against which to pack. */                                   * against which to pack. */
1013  {  {
1014      register Packer *packPtr;      register Packer *packPtr;
1015      Tk_Window tkwin, ancestor, parent;      Tk_Window tkwin, ancestor, parent;
1016      size_t length;      size_t length;
1017      char **options;      char **options;
1018      int index, tmp, optionCount, c;      int index, tmp, optionCount, c;
1019    
1020      /*      /*
1021       * Iterate over all of the window specifiers, each consisting of       * Iterate over all of the window specifiers, each consisting of
1022       * two arguments.  The first argument contains the window name and       * two arguments.  The first argument contains the window name and
1023       * the additional arguments contain options such as "top" or       * the additional arguments contain options such as "top" or
1024       * "padx 20".       * "padx 20".
1025       */       */
1026    
1027      for ( ; argc > 0; argc -= 2, argv += 2, prevPtr = packPtr) {      for ( ; argc > 0; argc -= 2, argv += 2, prevPtr = packPtr) {
1028          if (argc < 2) {          if (argc < 2) {
1029              Tcl_AppendResult(interp, "wrong # args: window \"",              Tcl_AppendResult(interp, "wrong # args: window \"",
1030                      argv[0], "\" should be followed by options",                      argv[0], "\" should be followed by options",
1031                      (char *) NULL);                      (char *) NULL);
1032              return TCL_ERROR;              return TCL_ERROR;
1033          }          }
1034    
1035          /*          /*
1036           * Find the packer for the window to be packed, and make sure           * Find the packer for the window to be packed, and make sure
1037           * that the window in which it will be packed is either its           * that the window in which it will be packed is either its
1038           * or a descendant of its parent.           * or a descendant of its parent.
1039           */           */
1040    
1041          tkwin = Tk_NameToWindow(interp, argv[0], masterPtr->tkwin);          tkwin = Tk_NameToWindow(interp, argv[0], masterPtr->tkwin);
1042          if (tkwin == NULL) {          if (tkwin == NULL) {
1043              return TCL_ERROR;              return TCL_ERROR;
1044          }          }
1045    
1046          parent = Tk_Parent(tkwin);          parent = Tk_Parent(tkwin);
1047          for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {          for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
1048              if (ancestor == parent) {              if (ancestor == parent) {
1049                  break;                  break;
1050              }              }
1051              if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) {              if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) {
1052                  badWindow:                  badWindow:
1053                  Tcl_AppendResult(interp, "can't pack ", argv[0],                  Tcl_AppendResult(interp, "can't pack ", argv[0],
1054                          " inside ", Tk_PathName(masterPtr->tkwin),                          " inside ", Tk_PathName(masterPtr->tkwin),
1055                          (char *) NULL);                          (char *) NULL);
1056                  return TCL_ERROR;                  return TCL_ERROR;
1057              }              }
1058          }          }
1059          if (((Tk_FakeWin *) (tkwin))->flags & TK_TOP_LEVEL) {          if (((Tk_FakeWin *) (tkwin))->flags & TK_TOP_LEVEL) {
1060              goto badWindow;              goto badWindow;
1061          }          }
1062          if (tkwin == masterPtr->tkwin) {          if (tkwin == masterPtr->tkwin) {
1063              goto badWindow;              goto badWindow;
1064          }          }
1065          packPtr = GetPacker(tkwin);          packPtr = GetPacker(tkwin);
1066    
1067          /*          /*
1068           * Process options for this window.           * Process options for this window.
1069           */           */
1070    
1071          if (Tcl_SplitList(interp, argv[1], &optionCount, &options) != TCL_OK) {          if (Tcl_SplitList(interp, argv[1], &optionCount, &options) != TCL_OK) {
1072              return TCL_ERROR;              return TCL_ERROR;
1073          }          }
1074          packPtr->side = TOP;          packPtr->side = TOP;
1075          packPtr->anchor = TK_ANCHOR_CENTER;          packPtr->anchor = TK_ANCHOR_CENTER;
1076          packPtr->padX = packPtr->padY = 0;          packPtr->padX = packPtr->padY = 0;
1077          packPtr->iPadX = packPtr->iPadY = 0;          packPtr->iPadX = packPtr->iPadY = 0;
1078          packPtr->flags &= ~(FILLX|FILLY|EXPAND);          packPtr->flags &= ~(FILLX|FILLY|EXPAND);
1079          packPtr->flags |= OLD_STYLE;          packPtr->flags |= OLD_STYLE;
1080          for (index = 0 ; index < optionCount; index++) {          for (index = 0 ; index < optionCount; index++) {
1081              char *curOpt = options[index];              char *curOpt = options[index];
1082    
1083              c = curOpt[0];              c = curOpt[0];
1084              length = strlen(curOpt);              length = strlen(curOpt);
1085    
1086              if ((c == 't')              if ((c == 't')
1087                      && (strncmp(curOpt, "top", length)) == 0) {                      && (strncmp(curOpt, "top", length)) == 0) {
1088                  packPtr->side = TOP;                  packPtr->side = TOP;
1089              } else if ((c == 'b')              } else if ((c == 'b')
1090                      && (strncmp(curOpt, "bottom", length)) == 0) {                      && (strncmp(curOpt, "bottom", length)) == 0) {
1091                  packPtr->side = BOTTOM;                  packPtr->side = BOTTOM;
1092              } else if ((c == 'l')              } else if ((c == 'l')
1093                      && (strncmp(curOpt, "left", length)) == 0) {                      && (strncmp(curOpt, "left", length)) == 0) {
1094                  packPtr->side = LEFT;                  packPtr->side = LEFT;
1095              } else if ((c == 'r')              } else if ((c == 'r')
1096                      && (strncmp(curOpt, "right", length)) == 0) {                      && (strncmp(curOpt, "right", length)) == 0) {
1097                  packPtr->side = RIGHT;                  packPtr->side = RIGHT;
1098              } else if ((c == 'e')              } else if ((c == 'e')
1099                      && (strncmp(curOpt, "expand", length)) == 0) {                      && (strncmp(curOpt, "expand", length)) == 0) {
1100                  packPtr->flags |= EXPAND;                  packPtr->flags |= EXPAND;
1101              } else if ((c == 'f')              } else if ((c == 'f')
1102                      && (strcmp(curOpt, "fill")) == 0) {                      && (strcmp(curOpt, "fill")) == 0) {
1103                  packPtr->flags |= FILLX|FILLY;                  packPtr->flags |= FILLX|FILLY;
1104              } else if ((length == 5) && (strcmp(curOpt, "fillx")) == 0) {              } else if ((length == 5) && (strcmp(curOpt, "fillx")) == 0) {
1105                  packPtr->flags |= FILLX;                  packPtr->flags |= FILLX;
1106              } else if ((length == 5) && (strcmp(curOpt, "filly")) == 0) {              } else if ((length == 5) && (strcmp(curOpt, "filly")) == 0) {
1107                  packPtr->flags |= FILLY;                  packPtr->flags |= FILLY;
1108              } else if ((c == 'p') && (strcmp(curOpt, "padx")) == 0) {              } else if ((c == 'p') && (strcmp(curOpt, "padx")) == 0) {
1109                  if (optionCount < (index+2)) {                  if (optionCount < (index+2)) {
1110                      missingPad:                      missingPad:
1111                      Tcl_AppendResult(interp, "wrong # args: \"", curOpt,                      Tcl_AppendResult(interp, "wrong # args: \"", curOpt,
1112                              "\" option must be followed by screen distance",                              "\" option must be followed by screen distance",
1113                              (char *) NULL);                              (char *) NULL);
1114                      goto error;                      goto error;
1115                  }                  }
1116                  if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp)                  if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp)
1117                          != TCL_OK) || (tmp < 0)) {                          != TCL_OK) || (tmp < 0)) {
1118                      badPad:                      badPad:
1119                      Tcl_AppendResult(interp, "bad pad value \"",                      Tcl_AppendResult(interp, "bad pad value \"",
1120                              options[index+1],                              options[index+1],
1121                              "\": must be positive screen distance",                              "\": must be positive screen distance",
1122                              (char *) NULL);                              (char *) NULL);
1123                      goto error;                      goto error;
1124                  }                  }
1125                  packPtr->padX = tmp;                  packPtr->padX = tmp;
1126                  packPtr->iPadX = 0;                  packPtr->iPadX = 0;
1127                  index++;                  index++;
1128              } else if ((c == 'p') && (strcmp(curOpt, "pady")) == 0) {              } else if ((c == 'p') && (strcmp(curOpt, "pady")) == 0) {
1129                  if (optionCount < (index+2)) {                  if (optionCount < (index+2)) {
1130                      goto missingPad;                      goto missingPad;
1131                  }                  }
1132                  if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp)                  if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp)
1133                          != TCL_OK) || (tmp < 0)) {                          != TCL_OK) || (tmp < 0)) {
1134                      goto badPad;                      goto badPad;
1135                  }                  }
1136                  packPtr->padY = tmp;                  packPtr->padY = tmp;
1137                  packPtr->iPadY = 0;                  packPtr->iPadY = 0;
1138                  index++;                  index++;
1139              } else if ((c == 'f') && (length > 1)              } else if ((c == 'f') && (length > 1)
1140                      && (strncmp(curOpt, "frame", length) == 0)) {                      && (strncmp(curOpt, "frame", length) == 0)) {
1141                  if (optionCount < (index+2)) {                  if (optionCount < (index+2)) {
1142                      Tcl_AppendResult(interp, "wrong # args: \"frame\" ",                      Tcl_AppendResult(interp, "wrong # args: \"frame\" ",
1143                              "option must be followed by anchor point",                              "option must be followed by anchor point",
1144                              (char *) NULL);                              (char *) NULL);
1145                      goto error;                      goto error;
1146                  }                  }
1147                  if (Tk_GetAnchor(interp, options[index+1],                  if (Tk_GetAnchor(interp, options[index+1],
1148                          &packPtr->anchor) != TCL_OK) {                          &packPtr->anchor) != TCL_OK) {
1149                      goto error;                      goto error;
1150                  }                  }
1151                  index++;                  index++;
1152              } else {              } else {
1153                  Tcl_AppendResult(interp, "bad option \"", curOpt,                  Tcl_AppendResult(interp, "bad option \"", curOpt,
1154                          "\": should be top, bottom, left, right, ",                          "\": should be top, bottom, left, right, ",
1155                          "expand, fill, fillx, filly, padx, pady, or frame",                          "expand, fill, fillx, filly, padx, pady, or frame",
1156                          (char *) NULL);                          (char *) NULL);
1157                  goto error;                  goto error;
1158              }              }
1159          }          }
1160    
1161          if (packPtr != prevPtr) {          if (packPtr != prevPtr) {
1162    
1163              /*              /*
1164               * Unpack this window if it's currently packed.               * Unpack this window if it's currently packed.
1165               */               */
1166    
1167              if (packPtr->masterPtr != NULL) {              if (packPtr->masterPtr != NULL) {
1168                  if ((packPtr->masterPtr != masterPtr) &&                  if ((packPtr->masterPtr != masterPtr) &&
1169                          (packPtr->masterPtr->tkwin                          (packPtr->masterPtr->tkwin
1170                          != Tk_Parent(packPtr->tkwin))) {                          != Tk_Parent(packPtr->tkwin))) {
1171                      Tk_UnmaintainGeometry(packPtr->tkwin,                      Tk_UnmaintainGeometry(packPtr->tkwin,
1172                              packPtr->masterPtr->tkwin);                              packPtr->masterPtr->tkwin);
1173                  }                  }
1174                  Unlink(packPtr);                  Unlink(packPtr);
1175              }              }
1176                    
1177              /*              /*
1178               * Add the window in the correct place in its parent's               * Add the window in the correct place in its parent's
1179               * packing order, then make sure that the window is               * packing order, then make sure that the window is
1180               * managed by us.               * managed by us.
1181               */               */
1182    
1183              packPtr->masterPtr = masterPtr;              packPtr->masterPtr = masterPtr;
1184              if (prevPtr == NULL) {              if (prevPtr == NULL) {
1185                  packPtr->nextPtr = masterPtr->slavePtr;                  packPtr->nextPtr = masterPtr->slavePtr;
1186                  masterPtr->slavePtr = packPtr;                  masterPtr->slavePtr = packPtr;
1187              } else {              } else {
1188                  packPtr->nextPtr = prevPtr->nextPtr;                  packPtr->nextPtr = prevPtr->nextPtr;
1189                  prevPtr->nextPtr = packPtr;                  prevPtr->nextPtr = packPtr;
1190              }              }
1191              Tk_ManageGeometry(tkwin, &packerType, (ClientData) packPtr);              Tk_ManageGeometry(tkwin, &packerType, (ClientData) packPtr);
1192          }          }
1193          ckfree((char *) options);          ckfree((char *) options);
1194      }      }
1195    
1196      /*      /*
1197       * Arrange for the parent to be re-packed at the first       * Arrange for the parent to be re-packed at the first
1198       * idle moment.       * idle moment.
1199       */       */
1200    
1201      if (masterPtr->abortPtr != NULL) {      if (masterPtr->abortPtr != NULL) {
1202          *masterPtr->abortPtr = 1;          *masterPtr->abortPtr = 1;
1203      }      }
1204      if (!(masterPtr->flags & REQUESTED_REPACK)) {      if (!(masterPtr->flags & REQUESTED_REPACK)) {
1205          masterPtr->flags |= REQUESTED_REPACK;          masterPtr->flags |= REQUESTED_REPACK;
1206          Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);          Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
1207      }      }
1208      return TCL_OK;      return TCL_OK;
1209    
1210      error:      error:
1211      ckfree((char *) options);      ckfree((char *) options);
1212      return TCL_ERROR;      return TCL_ERROR;
1213  }  }
1214    
1215  /*  /*
1216   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1217   *   *
1218   * Unlink --   * Unlink --
1219   *   *
1220   *      Remove a packer from its parent's list of slaves.   *      Remove a packer from its parent's list of slaves.
1221   *   *
1222   * Results:   * Results:
1223   *      None.   *      None.
1224   *   *
1225   * Side effects:   * Side effects:
1226   *      The parent will be scheduled for repacking.   *      The parent will be scheduled for repacking.
1227   *   *
1228   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1229   */   */
1230    
1231  static void  static void
1232  Unlink(packPtr)  Unlink(packPtr)
1233      register Packer *packPtr;           /* Window to unlink. */      register Packer *packPtr;           /* Window to unlink. */
1234  {  {
1235      register Packer *masterPtr, *packPtr2;      register Packer *masterPtr, *packPtr2;
1236    
1237      masterPtr = packPtr->masterPtr;      masterPtr = packPtr->masterPtr;
1238      if (masterPtr == NULL) {      if (masterPtr == NULL) {
1239          return;          return;
1240      }      }
1241      if (masterPtr->slavePtr == packPtr) {      if (masterPtr->slavePtr == packPtr) {
1242          masterPtr->slavePtr = packPtr->nextPtr;          masterPtr->slavePtr = packPtr->nextPtr;
1243      } else {      } else {
1244          for (packPtr2 = masterPtr->slavePtr; ; packPtr2 = packPtr2->nextPtr) {          for (packPtr2 = masterPtr->slavePtr; ; packPtr2 = packPtr2->nextPtr) {
1245              if (packPtr2 == NULL) {              if (packPtr2 == NULL) {
1246                  panic("Unlink couldn't find previous window");                  panic("Unlink couldn't find previous window");
1247              }              }
1248              if (packPtr2->nextPtr == packPtr) {              if (packPtr2->nextPtr == packPtr) {
1249                  packPtr2->nextPtr = packPtr->nextPtr;                  packPtr2->nextPtr = packPtr->nextPtr;
1250                  break;                  break;
1251              }              }
1252          }          }
1253      }      }
1254      if (!(masterPtr->flags & REQUESTED_REPACK)) {      if (!(masterPtr->flags & REQUESTED_REPACK)) {
1255          masterPtr->flags |= REQUESTED_REPACK;          masterPtr->flags |= REQUESTED_REPACK;
1256          Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);          Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
1257      }      }
1258      if (masterPtr->abortPtr != NULL) {      if (masterPtr->abortPtr != NULL) {
1259          *masterPtr->abortPtr = 1;          *masterPtr->abortPtr = 1;
1260      }      }
1261    
1262      packPtr->masterPtr = NULL;      packPtr->masterPtr = NULL;
1263  }  }
1264    
1265  /*  /*
1266   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1267   *   *
1268   * DestroyPacker --   * DestroyPacker --
1269   *   *
1270   *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release   *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
1271   *      to clean up the internal structure of a packer at a safe time   *      to clean up the internal structure of a packer at a safe time
1272   *      (when no-one is using it anymore).   *      (when no-one is using it anymore).
1273   *   *
1274   * Results:   * Results:
1275   *      None.   *      None.
1276   *   *
1277   * Side effects:   * Side effects:
1278   *      Everything associated with the packer is freed up.   *      Everything associated with the packer is freed up.
1279   *   *
1280   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1281   */   */
1282    
1283  static void  static void
1284  DestroyPacker(memPtr)  DestroyPacker(memPtr)
1285      char *memPtr;               /* Info about packed window that      char *memPtr;               /* Info about packed window that
1286                                   * is now dead. */                                   * is now dead. */
1287  {  {
1288      register Packer *packPtr = (Packer *) memPtr;      register Packer *packPtr = (Packer *) memPtr;
1289      ckfree((char *) packPtr);      ckfree((char *) packPtr);
1290  }  }
1291    
1292  /*  /*
1293   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1294   *   *
1295   * PackStructureProc --   * PackStructureProc --
1296   *   *
1297   *      This procedure is invoked by the Tk event dispatcher in response   *      This procedure is invoked by the Tk event dispatcher in response
1298   *      to StructureNotify events.   *      to StructureNotify events.
1299   *   *
1300   * Results:   * Results:
1301   *      None.   *      None.
1302   *   *
1303   * Side effects:   * Side effects:
1304   *      If a window was just deleted, clean up all its packer-related   *      If a window was just deleted, clean up all its packer-related
1305   *      information.  If it was just resized, repack its slaves, if   *      information.  If it was just resized, repack its slaves, if
1306   *      any.   *      any.
1307   *   *
1308   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1309   */   */
1310    
1311  static void  static void
1312  PackStructureProc(clientData, eventPtr)  PackStructureProc(clientData, eventPtr)
1313      ClientData clientData;              /* Our information about window      ClientData clientData;              /* Our information about window
1314                                           * referred to by eventPtr. */                                           * referred to by eventPtr. */
1315      XEvent *eventPtr;                   /* Describes what just happened. */      XEvent *eventPtr;                   /* Describes what just happened. */
1316  {  {
1317      register Packer *packPtr = (Packer *) clientData;      register Packer *packPtr = (Packer *) clientData;
1318    
1319      if (eventPtr->type == ConfigureNotify) {      if (eventPtr->type == ConfigureNotify) {
1320          if ((packPtr->slavePtr != NULL)          if ((packPtr->slavePtr != NULL)
1321                  && !(packPtr->flags & REQUESTED_REPACK)) {                  && !(packPtr->flags & REQUESTED_REPACK)) {
1322              packPtr->flags |= REQUESTED_REPACK;              packPtr->flags |= REQUESTED_REPACK;
1323              Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);              Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
1324          }          }
1325          if (packPtr->doubleBw != 2*Tk_Changes(packPtr->tkwin)->border_width) {          if (packPtr->doubleBw != 2*Tk_Changes(packPtr->tkwin)->border_width) {
1326              if ((packPtr->masterPtr != NULL)              if ((packPtr->masterPtr != NULL)
1327                      && !(packPtr->masterPtr->flags & REQUESTED_REPACK)) {                      && !(packPtr->masterPtr->flags & REQUESTED_REPACK)) {
1328                  packPtr->doubleBw = 2*Tk_Changes(packPtr->tkwin)->border_width;                  packPtr->doubleBw = 2*Tk_Changes(packPtr->tkwin)->border_width;
1329                  packPtr->masterPtr->flags |= REQUESTED_REPACK;                  packPtr->masterPtr->flags |= REQUESTED_REPACK;
1330                  Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr->masterPtr);                  Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr->masterPtr);
1331              }              }
1332          }          }
1333      } else if (eventPtr->type == DestroyNotify) {      } else if (eventPtr->type == DestroyNotify) {
1334          register Packer *slavePtr, *nextPtr;          register Packer *slavePtr, *nextPtr;
1335    
1336          if (packPtr->masterPtr != NULL) {          if (packPtr->masterPtr != NULL) {
1337              Unlink(packPtr);              Unlink(packPtr);
1338          }          }
1339          for (slavePtr = packPtr->slavePtr; slavePtr != NULL;          for (slavePtr = packPtr->slavePtr; slavePtr != NULL;
1340                  slavePtr = nextPtr) {                  slavePtr = nextPtr) {
1341              Tk_ManageGeometry(slavePtr->tkwin, (Tk_GeomMgr *) NULL,              Tk_ManageGeometry(slavePtr->tkwin, (Tk_GeomMgr *) NULL,
1342                      (ClientData) NULL);                      (ClientData) NULL);
1343              Tk_UnmapWindow(slavePtr->tkwin);              Tk_UnmapWindow(slavePtr->tkwin);
1344              slavePtr->masterPtr = NULL;              slavePtr->masterPtr = NULL;
1345              nextPtr = slavePtr->nextPtr;              nextPtr = slavePtr->nextPtr;
1346              slavePtr->nextPtr = NULL;              slavePtr->nextPtr = NULL;
1347          }          }
1348          if (packPtr->tkwin != NULL) {          if (packPtr->tkwin != NULL) {
1349              TkDisplay *dispPtr = ((TkWindow *) packPtr->tkwin)->dispPtr;              TkDisplay *dispPtr = ((TkWindow *) packPtr->tkwin)->dispPtr;
1350              Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->packerHashTable,              Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->packerHashTable,
1351                      (char *) packPtr->tkwin));                      (char *) packPtr->tkwin));
1352          }          }
1353          if (packPtr->flags & REQUESTED_REPACK) {          if (packPtr->flags & REQUESTED_REPACK) {
1354              Tcl_CancelIdleCall(ArrangePacking, (ClientData) packPtr);              Tcl_CancelIdleCall(ArrangePacking, (ClientData) packPtr);
1355          }          }
1356          packPtr->tkwin = NULL;          packPtr->tkwin = NULL;
1357          Tcl_EventuallyFree((ClientData) packPtr, DestroyPacker);          Tcl_EventuallyFree((ClientData) packPtr, DestroyPacker);
1358      } else if (eventPtr->type == MapNotify) {      } else if (eventPtr->type == MapNotify) {
1359          /*          /*
1360           * When a master gets mapped, must redo the geometry computation           * When a master gets mapped, must redo the geometry computation
1361           * so that all of its slaves get remapped.           * so that all of its slaves get remapped.
1362           */           */
1363    
1364          if ((packPtr->slavePtr != NULL)          if ((packPtr->slavePtr != NULL)
1365                  && !(packPtr->flags & REQUESTED_REPACK)) {                  && !(packPtr->flags & REQUESTED_REPACK)) {
1366              packPtr->flags |= REQUESTED_REPACK;              packPtr->flags |= REQUESTED_REPACK;
1367              Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);              Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
1368          }          }
1369      } else if (eventPtr->type == UnmapNotify) {      } else if (eventPtr->type == UnmapNotify) {
1370          register Packer *packPtr2;          register Packer *packPtr2;
1371    
1372          /*          /*
1373           * Unmap all of the slaves when the master gets unmapped,           * Unmap all of the slaves when the master gets unmapped,
1374           * so that they don't bother to keep redisplaying           * so that they don't bother to keep redisplaying
1375           * themselves.           * themselves.
1376           */           */
1377          for (packPtr2 = packPtr->slavePtr; packPtr2 != NULL;          for (packPtr2 = packPtr->slavePtr; packPtr2 != NULL;
1378               packPtr2 = packPtr2->nextPtr) {               packPtr2 = packPtr2->nextPtr) {
1379              Tk_UnmapWindow(packPtr2->tkwin);              Tk_UnmapWindow(packPtr2->tkwin);
1380          }          }
1381      }      }
1382  }  }
1383    
1384  /*  /*
1385   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1386   *   *
1387   * ConfigureSlaves --   * ConfigureSlaves --
1388   *   *
1389   *      This implements the guts of the "pack configure" command.  Given   *      This implements the guts of the "pack configure" command.  Given
1390   *      a list of slaves and configuration options, it arranges for the   *      a list of slaves and configuration options, it arranges for the
1391   *      packer to manage the slaves and sets the specified options.   *      packer to manage the slaves and sets the specified options.
1392   *   *
1393   * Results:   * Results:
1394   *      TCL_OK is returned if all went well.  Otherwise, TCL_ERROR is   *      TCL_OK is returned if all went well.  Otherwise, TCL_ERROR is
1395   *      returned and the interp's result is set to contain an error message.   *      returned and the interp's result is set to contain an error message.
1396   *   *
1397   * Side effects:   * Side effects:
1398   *      Slave windows get taken over by the packer.   *      Slave windows get taken over by the packer.
1399   *   *
1400   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1401   */   */
1402    
1403  static int  static int
1404  ConfigureSlaves(interp, tkwin, argc, argv)  ConfigureSlaves(interp, tkwin, argc, argv)
1405      Tcl_Interp *interp;         /* Interpreter for error reporting. */      Tcl_Interp *interp;         /* Interpreter for error reporting. */
1406      Tk_Window tkwin;            /* Any window in application containing      Tk_Window tkwin;            /* Any window in application containing
1407                                   * slaves.  Used to look up slave names. */                                   * slaves.  Used to look up slave names. */
1408      int argc;                   /* Number of elements in argv. */      int argc;                   /* Number of elements in argv. */
1409      char *argv[];               /* Argument strings:  contains one or more      char *argv[];               /* Argument strings:  contains one or more
1410                                   * window names followed by any number                                   * window names followed by any number
1411                                   * of "option value" pairs.  Caller must                                   * of "option value" pairs.  Caller must
1412                                   * make sure that there is at least one                                   * make sure that there is at least one
1413                                   * window name. */                                   * window name. */
1414  {  {
1415      Packer *masterPtr, *slavePtr, *prevPtr, *otherPtr;      Packer *masterPtr, *slavePtr, *prevPtr, *otherPtr;
1416      Tk_Window other, slave, parent, ancestor;      Tk_Window other, slave, parent, ancestor;
1417      int i, j, numWindows, c, tmp, positionGiven;      int i, j, numWindows, c, tmp, positionGiven;
1418      size_t length;      size_t length;
1419    
1420      /*      /*
1421       * Find out how many windows are specified.       * Find out how many windows are specified.
1422       */       */
1423    
1424      for (numWindows = 0; numWindows < argc; numWindows++) {      for (numWindows = 0; numWindows < argc; numWindows++) {
1425          if (argv[numWindows][0] != '.') {          if (argv[numWindows][0] != '.') {
1426              break;              break;
1427          }          }
1428      }      }
1429    
1430      /*      /*
1431       * Iterate over all of the slave windows, parsing the configuration       * Iterate over all of the slave windows, parsing the configuration
1432       * options for each slave.  It's a bit wasteful to re-parse the       * options for each slave.  It's a bit wasteful to re-parse the
1433       * options for each slave, but things get too messy if we try to       * options for each slave, but things get too messy if we try to
1434       * parse the arguments just once at the beginning.  For example,       * parse the arguments just once at the beginning.  For example,
1435       * if a slave already is packed we want to just change a few       * if a slave already is packed we want to just change a few
1436       * existing values without resetting everything.  If there are       * existing values without resetting everything.  If there are
1437       * multiple windows, the -after, -before, and -in options only       * multiple windows, the -after, -before, and -in options only
1438       * get processed for the first window.       * get processed for the first window.
1439       */       */
1440    
1441      masterPtr = NULL;      masterPtr = NULL;
1442      prevPtr = NULL;      prevPtr = NULL;
1443      positionGiven = 0;      positionGiven = 0;
1444      for (j = 0; j < numWindows; j++) {      for (j = 0; j < numWindows; j++) {
1445          slave = Tk_NameToWindow(interp, argv[j], tkwin);          slave = Tk_NameToWindow(interp, argv[j], tkwin);
1446          if (slave == NULL) {          if (slave == NULL) {
1447              return TCL_ERROR;              return TCL_ERROR;
1448          }          }
1449          if (Tk_IsTopLevel(slave)) {          if (Tk_IsTopLevel(slave)) {
1450              Tcl_AppendResult(interp, "can't pack \"", argv[j],              Tcl_AppendResult(interp, "can't pack \"", argv[j],
1451                      "\": it's a top-level window", (char *) NULL);                      "\": it's a top-level window", (char *) NULL);
1452              return TCL_ERROR;              return TCL_ERROR;
1453          }          }
1454          slavePtr = GetPacker(slave);          slavePtr = GetPacker(slave);
1455          slavePtr->flags &= ~OLD_STYLE;          slavePtr->flags &= ~OLD_STYLE;
1456    
1457          /*          /*
1458           * If the slave isn't currently packed, reset all of its           * If the slave isn't currently packed, reset all of its
1459           * configuration information to default values (there could           * configuration information to default values (there could
1460           * be old values left from a previous packing).           * be old values left from a previous packing).
1461           */           */
1462    
1463          if (slavePtr->masterPtr == NULL) {          if (slavePtr->masterPtr == NULL) {
1464              slavePtr->side = TOP;              slavePtr->side = TOP;
1465              slavePtr->anchor = TK_ANCHOR_CENTER;              slavePtr->anchor = TK_ANCHOR_CENTER;
1466              slavePtr->padX = slavePtr->padY = 0;              slavePtr->padX = slavePtr->padY = 0;
1467              slavePtr->iPadX = slavePtr->iPadY = 0;              slavePtr->iPadX = slavePtr->iPadY = 0;
1468              slavePtr->flags &= ~(FILLX|FILLY|EXPAND);              slavePtr->flags &= ~(FILLX|FILLY|EXPAND);
1469          }          }
1470    
1471          for (i = numWindows; i < argc; i+=2) {          for (i = numWindows; i < argc; i+=2) {
1472              if ((i+2) > argc) {              if ((i+2) > argc) {
1473                  Tcl_AppendResult(interp, "extra option \"", argv[i],                  Tcl_AppendResult(interp, "extra option \"", argv[i],
1474                          "\" (option with no value?)", (char *) NULL);                          "\" (option with no value?)", (char *) NULL);
1475                  return TCL_ERROR;                  return TCL_ERROR;
1476              }              }
1477              length = strlen(argv[i]);              length = strlen(argv[i]);
1478              if (length < 2) {              if (length < 2) {
1479                  goto badOption;                  goto badOption;
1480              }              }
1481              c = argv[i][1];              c = argv[i][1];
1482              if ((c == 'a') && (strncmp(argv[i], "-after", length) == 0)              if ((c == 'a') && (strncmp(argv[i], "-after", length) == 0)
1483                      && (length >= 2)) {                      && (length >= 2)) {
1484                  if (j == 0) {                  if (j == 0) {
1485                      other = Tk_NameToWindow(interp, argv[i+1], tkwin);                      other = Tk_NameToWindow(interp, argv[i+1], tkwin);
1486                      if (other == NULL) {                      if (other == NULL) {
1487                          return TCL_ERROR;                          return TCL_ERROR;
1488                      }                      }
1489                      prevPtr = GetPacker(other);                      prevPtr = GetPacker(other);
1490                      if (prevPtr->masterPtr == NULL) {                      if (prevPtr->masterPtr == NULL) {
1491                          notPacked:                          notPacked:
1492                          Tcl_AppendResult(interp, "window \"", argv[i+1],                          Tcl_AppendResult(interp, "window \"", argv[i+1],
1493                                  "\" isn't packed", (char *) NULL);                                  "\" isn't packed", (char *) NULL);
1494                          return TCL_ERROR;                          return TCL_ERROR;
1495                      }                      }
1496                      masterPtr = prevPtr->masterPtr;                      masterPtr = prevPtr->masterPtr;
1497                      positionGiven = 1;                      positionGiven = 1;
1498                  }                  }
1499              } else if ((c == 'a') && (strncmp(argv[i], "-anchor", length) == 0)              } else if ((c == 'a') && (strncmp(argv[i], "-anchor", length) == 0)
1500                      && (length >= 2)) {                      && (length >= 2)) {
1501                  if (Tk_GetAnchor(interp, argv[i+1], &slavePtr->anchor)                  if (Tk_GetAnchor(interp, argv[i+1], &slavePtr->anchor)
1502                          != TCL_OK) {                          != TCL_OK) {
1503                      return TCL_ERROR;                      return TCL_ERROR;
1504                  }                  }
1505              } else if ((c == 'b')              } else if ((c == 'b')
1506                      && (strncmp(argv[i], "-before", length) == 0)) {                      && (strncmp(argv[i], "-before", length) == 0)) {
1507                  if (j == 0) {                  if (j == 0) {
1508                      other = Tk_NameToWindow(interp, argv[i+1], tkwin);                      other = Tk_NameToWindow(interp, argv[i+1], tkwin);
1509                      if (other == NULL) {                      if (other == NULL) {
1510                          return TCL_ERROR;                          return TCL_ERROR;
1511                      }                      }
1512                      otherPtr = GetPacker(other);                      otherPtr = GetPacker(other);
1513                      if (otherPtr->masterPtr == NULL) {                      if (otherPtr->masterPtr == NULL) {
1514                          goto notPacked;                          goto notPacked;
1515                      }                      }
1516                      masterPtr = otherPtr->masterPtr;                      masterPtr = otherPtr->masterPtr;
1517                      prevPtr = masterPtr->slavePtr;                      prevPtr = masterPtr->slavePtr;
1518                      if (prevPtr == otherPtr) {                      if (prevPtr == otherPtr) {
1519                          prevPtr = NULL;                          prevPtr = NULL;
1520                      } else {                      } else {
1521                          while (prevPtr->nextPtr != otherPtr) {                          while (prevPtr->nextPtr != otherPtr) {
1522                              prevPtr = prevPtr->nextPtr;                              prevPtr = prevPtr->nextPtr;
1523                          }                          }
1524                      }                      }
1525                      positionGiven = 1;                      positionGiven = 1;
1526                  }                  }
1527              } else if ((c == 'e')              } else if ((c == 'e')
1528                      && (strncmp(argv[i], "-expand", length) == 0)) {                      && (strncmp(argv[i], "-expand", length) == 0)) {
1529                  if (Tcl_GetBoolean(interp, argv[i+1], &tmp) != TCL_OK) {                  if (Tcl_GetBoolean(interp, argv[i+1], &tmp) != TCL_OK) {
1530                      return TCL_ERROR;                      return TCL_ERROR;
1531                  }                  }
1532                  slavePtr->flags &= ~EXPAND;                  slavePtr->flags &= ~EXPAND;
1533                  if (tmp) {                  if (tmp) {
1534                      slavePtr->flags |= EXPAND;                      slavePtr->flags |= EXPAND;
1535                  }                  }
1536              } else if ((c == 'f') && (strncmp(argv[i], "-fill", length) == 0)) {              } else if ((c == 'f') && (strncmp(argv[i], "-fill", length) == 0)) {
1537                  if (strcmp(argv[i+1], "none") == 0) {                  if (strcmp(argv[i+1], "none") == 0) {
1538                      slavePtr->flags &= ~(FILLX|FILLY);                      slavePtr->flags &= ~(FILLX|FILLY);
1539                  } else if (strcmp(argv[i+1], "x") == 0) {                  } else if (strcmp(argv[i+1], "x") == 0) {
1540                      slavePtr->flags = (slavePtr->flags & ~FILLY) | FILLX;                      slavePtr->flags = (slavePtr->flags & ~FILLY) | FILLX;
1541                  } else if (strcmp(argv[i+1], "y") == 0) {                  } else if (strcmp(argv[i+1], "y") == 0) {
1542                      slavePtr->flags = (slavePtr->flags & ~FILLX) | FILLY;                      slavePtr->flags = (slavePtr->flags & ~FILLX) | FILLY;
1543                  } else if (strcmp(argv[i+1], "both") == 0) {                  } else if (strcmp(argv[i+1], "both") == 0) {
1544                      slavePtr->flags |= FILLX|FILLY;                      slavePtr->flags |= FILLX|FILLY;
1545                  } else {                  } else {
1546                      Tcl_AppendResult(interp, "bad fill style \"", argv[i+1],                      Tcl_AppendResult(interp, "bad fill style \"", argv[i+1],
1547                              "\": must be none, x, y, or both", (char *) NULL);                              "\": must be none, x, y, or both", (char *) NULL);
1548                      return TCL_ERROR;                      return TCL_ERROR;
1549                  }                  }
1550              } else if ((c == 'i') && (strcmp(argv[i], "-in") == 0)) {              } else if ((c == 'i') && (strcmp(argv[i], "-in") == 0)) {
1551                  if (j == 0) {                  if (j == 0) {
1552                      other = Tk_NameToWindow(interp, argv[i+1], tkwin);                      other = Tk_NameToWindow(interp, argv[i+1], tkwin);
1553                      if (other == NULL) {                      if (other == NULL) {
1554                          return TCL_ERROR;                          return TCL_ERROR;
1555                      }                      }
1556                      masterPtr = GetPacker(other);                      masterPtr = GetPacker(other);
1557                      prevPtr = masterPtr->slavePtr;                      prevPtr = masterPtr->slavePtr;
1558                      if (prevPtr != NULL) {                      if (prevPtr != NULL) {
1559                          while (prevPtr->nextPtr != NULL) {                          while (prevPtr->nextPtr != NULL) {
1560                              prevPtr = prevPtr->nextPtr;                              prevPtr = prevPtr->nextPtr;
1561                          }                          }
1562                      }                      }
1563                      positionGiven = 1;                      positionGiven = 1;
1564                  }                  }
1565              } else if ((c == 'i') && (strcmp(argv[i], "-ipadx") == 0)) {              } else if ((c == 'i') && (strcmp(argv[i], "-ipadx") == 0)) {
1566                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
1567                          || (tmp < 0)) {                          || (tmp < 0)) {
1568                      badPad:                      badPad:
1569                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
1570                      Tcl_AppendResult(interp, "bad pad value \"", argv[i+1],                      Tcl_AppendResult(interp, "bad pad value \"", argv[i+1],
1571                              "\": must be positive screen distance",                              "\": must be positive screen distance",
1572                              (char *) NULL);                              (char *) NULL);
1573                      return TCL_ERROR;                      return TCL_ERROR;
1574                  }                  }
1575                  slavePtr->iPadX = tmp*2;                  slavePtr->iPadX = tmp*2;
1576              } else if ((c == 'i') && (strcmp(argv[i], "-ipady") == 0)) {              } else if ((c == 'i') && (strcmp(argv[i], "-ipady") == 0)) {
1577                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
1578                          || (tmp< 0)) {                          || (tmp< 0)) {
1579                      goto badPad;                      goto badPad;
1580                  }                  }
1581                  slavePtr->iPadY = tmp*2;                  slavePtr->iPadY = tmp*2;
1582              } else if ((c == 'p') && (strcmp(argv[i], "-padx") == 0)) {              } else if ((c == 'p') && (strcmp(argv[i], "-padx") == 0)) {
1583                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
1584                          || (tmp< 0)) {                          || (tmp< 0)) {
1585                      goto badPad;                      goto badPad;
1586                  }                  }
1587                  slavePtr->padX = tmp*2;                  slavePtr->padX = tmp*2;
1588              } else if ((c == 'p') && (strcmp(argv[i], "-pady") == 0)) {              } else if ((c == 'p') && (strcmp(argv[i], "-pady") == 0)) {
1589                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
1590                          || (tmp< 0)) {                          || (tmp< 0)) {
1591                      goto badPad;                      goto badPad;
1592                  }                  }
1593                  slavePtr->padY = tmp*2;                  slavePtr->padY = tmp*2;
1594              } else if ((c == 's') && (strncmp(argv[i], "-side", length) == 0)) {              } else if ((c == 's') && (strncmp(argv[i], "-side", length) == 0)) {
1595                  c = argv[i+1][0];                  c = argv[i+1][0];
1596                  if ((c == 't') && (strcmp(argv[i+1], "top") == 0)) {                  if ((c == 't') && (strcmp(argv[i+1], "top") == 0)) {
1597                      slavePtr->side = TOP;                      slavePtr->side = TOP;
1598                  } else if ((c == 'b') && (strcmp(argv[i+1], "bottom") == 0)) {                  } else if ((c == 'b') && (strcmp(argv[i+1], "bottom") == 0)) {
1599                      slavePtr->side = BOTTOM;                      slavePtr->side = BOTTOM;
1600                  } else if ((c == 'l') && (strcmp(argv[i+1], "left") == 0)) {                  } else if ((c == 'l') && (strcmp(argv[i+1], "left") == 0)) {
1601                      slavePtr->side = LEFT;                      slavePtr->side = LEFT;
1602                  } else if ((c == 'r') && (strcmp(argv[i+1], "right") == 0)) {                  } else if ((c == 'r') && (strcmp(argv[i+1], "right") == 0)) {
1603                      slavePtr->side = RIGHT;                      slavePtr->side = RIGHT;
1604                  } else {                  } else {
1605                      Tcl_AppendResult(interp, "bad side \"", argv[i+1],                      Tcl_AppendResult(interp, "bad side \"", argv[i+1],
1606                              "\": must be top, bottom, left, or right",                              "\": must be top, bottom, left, or right",
1607                              (char *) NULL);                              (char *) NULL);
1608                      return TCL_ERROR;                      return TCL_ERROR;
1609                  }                  }
1610              } else {              } else {
1611                  badOption:                  badOption:
1612                  Tcl_AppendResult(interp, "unknown or ambiguous option \"",                  Tcl_AppendResult(interp, "unknown or ambiguous option \"",
1613                          argv[i], "\": must be -after, -anchor, -before, ",                          argv[i], "\": must be -after, -anchor, -before, ",
1614                          "-expand, -fill, -in, -ipadx, -ipady, -padx, ",                          "-expand, -fill, -in, -ipadx, -ipady, -padx, ",
1615                          "-pady, or -side", (char *) NULL);                          "-pady, or -side", (char *) NULL);
1616                  return TCL_ERROR;                  return TCL_ERROR;
1617              }              }
1618          }          }
1619    
1620          /*          /*
1621           * If no position in a packing list was specified and the slave           * If no position in a packing list was specified and the slave
1622           * is already packed, then leave it in its current location in           * is already packed, then leave it in its current location in
1623           * its current packing list.           * its current packing list.
1624           */           */
1625    
1626          if (!positionGiven && (slavePtr->masterPtr != NULL)) {          if (!positionGiven && (slavePtr->masterPtr != NULL)) {
1627              masterPtr = slavePtr->masterPtr;              masterPtr = slavePtr->masterPtr;
1628              goto scheduleLayout;              goto scheduleLayout;
1629          }          }
1630    
1631          /*          /*
1632           * If the slave is going to be put back after itself then           * If the slave is going to be put back after itself then
1633           * skip the whole operation, since it won't work anyway.           * skip the whole operation, since it won't work anyway.
1634           */           */
1635    
1636          if (prevPtr == slavePtr) {          if (prevPtr == slavePtr) {
1637              masterPtr = slavePtr->masterPtr;              masterPtr = slavePtr->masterPtr;
1638              goto scheduleLayout;              goto scheduleLayout;
1639          }          }
1640            
1641          /*          /*
1642           * If none of the "-in", "-before", or "-after" options has           * If none of the "-in", "-before", or "-after" options has
1643           * been specified, arrange for the slave to go at the end of           * been specified, arrange for the slave to go at the end of
1644           * the order for its parent.           * the order for its parent.
1645           */           */
1646            
1647          if (!positionGiven) {          if (!positionGiven) {
1648              masterPtr = GetPacker(Tk_Parent(slave));              masterPtr = GetPacker(Tk_Parent(slave));
1649              prevPtr = masterPtr->slavePtr;              prevPtr = masterPtr->slavePtr;
1650              if (prevPtr != NULL) {              if (prevPtr != NULL) {
1651                  while (prevPtr->nextPtr != NULL) {                  while (prevPtr->nextPtr != NULL) {
1652                      prevPtr = prevPtr->nextPtr;                      prevPtr = prevPtr->nextPtr;
1653                  }                  }
1654              }              }
1655          }          }
1656    
1657          /*          /*
1658           * Make sure that the slave's parent is either the master or           * Make sure that the slave's parent is either the master or
1659           * an ancestor of the master, and that the master and slave           * an ancestor of the master, and that the master and slave
1660           * aren't the same.           * aren't the same.
1661           */           */
1662            
1663          parent = Tk_Parent(slave);          parent = Tk_Parent(slave);
1664          for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {          for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
1665              if (ancestor == parent) {              if (ancestor == parent) {
1666                  break;                  break;
1667              }              }
1668              if (Tk_IsTopLevel(ancestor)) {              if (Tk_IsTopLevel(ancestor)) {
1669                  Tcl_AppendResult(interp, "can't pack ", argv[j],                  Tcl_AppendResult(interp, "can't pack ", argv[j],
1670                          " inside ", Tk_PathName(masterPtr->tkwin),                          " inside ", Tk_PathName(masterPtr->tkwin),
1671                          (char *) NULL);                          (char *) NULL);
1672                  return TCL_ERROR;                  return TCL_ERROR;
1673              }              }
1674          }          }
1675          if (slave == masterPtr->tkwin) {          if (slave == masterPtr->tkwin) {
1676              Tcl_AppendResult(interp, "can't pack ", argv[j],              Tcl_AppendResult(interp, "can't pack ", argv[j],
1677                      " inside itself", (char *) NULL);                      " inside itself", (char *) NULL);
1678              return TCL_ERROR;              return TCL_ERROR;
1679          }          }
1680    
1681          /*          /*
1682           * Unpack the slave if it's currently packed, then position it           * Unpack the slave if it's currently packed, then position it
1683           * after prevPtr.           * after prevPtr.
1684           */           */
1685    
1686          if (slavePtr->masterPtr != NULL) {          if (slavePtr->masterPtr != NULL) {
1687              if ((slavePtr->masterPtr != masterPtr) &&              if ((slavePtr->masterPtr != masterPtr) &&
1688                      (slavePtr->masterPtr->tkwin                      (slavePtr->masterPtr->tkwin
1689                      != Tk_Parent(slavePtr->tkwin))) {                      != Tk_Parent(slavePtr->tkwin))) {
1690                  Tk_UnmaintainGeometry(slavePtr->tkwin,                  Tk_UnmaintainGeometry(slavePtr->tkwin,
1691                          slavePtr->masterPtr->tkwin);                          slavePtr->masterPtr->tkwin);
1692              }              }
1693              Unlink(slavePtr);              Unlink(slavePtr);
1694          }          }
1695          slavePtr->masterPtr = masterPtr;          slavePtr->masterPtr = masterPtr;
1696          if (prevPtr == NULL) {          if (prevPtr == NULL) {
1697              slavePtr->nextPtr = masterPtr->slavePtr;              slavePtr->nextPtr = masterPtr->slavePtr;
1698              masterPtr->slavePtr = slavePtr;              masterPtr->slavePtr = slavePtr;
1699          } else {          } else {
1700              slavePtr->nextPtr = prevPtr->nextPtr;              slavePtr->nextPtr = prevPtr->nextPtr;
1701              prevPtr->nextPtr = slavePtr;              prevPtr->nextPtr = slavePtr;
1702          }          }
1703          Tk_ManageGeometry(slave, &packerType, (ClientData) slavePtr);          Tk_ManageGeometry(slave, &packerType, (ClientData) slavePtr);
1704          prevPtr = slavePtr;          prevPtr = slavePtr;
1705    
1706          /*          /*
1707           * Arrange for the parent to be re-packed at the first           * Arrange for the parent to be re-packed at the first
1708           * idle moment.           * idle moment.
1709           */           */
1710    
1711          scheduleLayout:          scheduleLayout:
1712          if (masterPtr->abortPtr != NULL) {          if (masterPtr->abortPtr != NULL) {
1713              *masterPtr->abortPtr = 1;              *masterPtr->abortPtr = 1;
1714          }          }
1715          if (!(masterPtr->flags & REQUESTED_REPACK)) {          if (!(masterPtr->flags & REQUESTED_REPACK)) {
1716              masterPtr->flags |= REQUESTED_REPACK;              masterPtr->flags |= REQUESTED_REPACK;
1717              Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);              Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
1718          }          }
1719      }      }
1720      return TCL_OK;      return TCL_OK;
1721  }  }
1722    
1723  /* End of tkpack.c */  /* End of tkpack.c */

Legend:
Removed from v.69  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25