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

Diff of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkgrid.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   * tkGrid.c --   * tkGrid.c --
5   *   *
6   *      Grid based geometry manager.   *      Grid based geometry manager.
7   *   *
8   * Copyright (c) 1996-1997 by Sun Microsystems, Inc.   * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
9   *   *
10   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
11   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12   *   *
13   * RCS: @(#) $Id: tkgrid.c,v 1.1.1.1 2001/06/13 05:02:05 dtashley Exp $   * RCS: @(#) $Id: tkgrid.c,v 1.1.1.1 2001/06/13 05:02:05 dtashley Exp $
14   */   */
15    
16  #include "tkInt.h"  #include "tkInt.h"
17    
18  /*  /*
19   * Convenience Macros   * Convenience Macros
20   */   */
21    
22  #ifdef MAX  #ifdef MAX
23  #   undef MAX  #   undef MAX
24  #endif  #endif
25  #define MAX(x,y)        ((x) > (y) ? (x) : (y))  #define MAX(x,y)        ((x) > (y) ? (x) : (y))
26  #ifdef MIN  #ifdef MIN
27  #   undef MIN  #   undef MIN
28  #endif  #endif
29  #define MIN(x,y)        ((x) > (y) ? (y) : (x))  #define MIN(x,y)        ((x) > (y) ? (y) : (x))
30    
31  #define COLUMN  (1)             /* working on column offsets */  #define COLUMN  (1)             /* working on column offsets */
32  #define ROW     (2)             /* working on row offsets */  #define ROW     (2)             /* working on row offsets */
33    
34  #define CHECK_ONLY      (1)     /* check max slot constraint */  #define CHECK_ONLY      (1)     /* check max slot constraint */
35  #define CHECK_SPACE     (2)     /* alloc more space, don't change max */  #define CHECK_SPACE     (2)     /* alloc more space, don't change max */
36    
37  /*  /*
38   * Pre-allocate enough row and column slots for "typical" sized tables   * Pre-allocate enough row and column slots for "typical" sized tables
39   * this value should be chosen so by the time the extra malloc's are   * this value should be chosen so by the time the extra malloc's are
40   * required, the layout calculations overwehlm them. [A "slot" contains   * required, the layout calculations overwehlm them. [A "slot" contains
41   * information for either a row or column, depending upon the context.]   * information for either a row or column, depending upon the context.]
42   */   */
43    
44  #define TYPICAL_SIZE    25  /* (arbitrary guess) */  #define TYPICAL_SIZE    25  /* (arbitrary guess) */
45  #define PREALLOC        10  /* extra slots to allocate */  #define PREALLOC        10  /* extra slots to allocate */
46    
47  /*  /*
48   * Data structures are allocated dynamically to support arbitrary sized tables.   * Data structures are allocated dynamically to support arbitrary sized tables.
49   * However, the space is proportional to the highest numbered slot with   * However, the space is proportional to the highest numbered slot with
50   * some non-default property.  This limit is used to head off mistakes and   * some non-default property.  This limit is used to head off mistakes and
51   * denial of service attacks by limiting the amount of storage required.   * denial of service attacks by limiting the amount of storage required.
52   */   */
53    
54  #define MAX_ELEMENT     10000  #define MAX_ELEMENT     10000
55    
56  /*  /*
57   * Special characters to support relative layouts.   * Special characters to support relative layouts.
58   */   */
59    
60  #define REL_SKIP        'x'     /* Skip this column. */  #define REL_SKIP        'x'     /* Skip this column. */
61  #define REL_HORIZ       '-'     /* Extend previous widget horizontally. */  #define REL_HORIZ       '-'     /* Extend previous widget horizontally. */
62  #define REL_VERT        '^'     /* Extend widget from row above. */  #define REL_VERT        '^'     /* Extend widget from row above. */
63    
64  /*  /*
65   *  Structure to hold information for grid masters.  A slot is either   *  Structure to hold information for grid masters.  A slot is either
66   *  a row or column.   *  a row or column.
67   */   */
68    
69  typedef struct SlotInfo {  typedef struct SlotInfo {
70          int minSize;            /* The minimum size of this slot (in pixels).          int minSize;            /* The minimum size of this slot (in pixels).
71                                   * It is set via the rowconfigure or                                   * It is set via the rowconfigure or
72                                   * columnconfigure commands. */                                   * columnconfigure commands. */
73          int weight;             /* The resize weight of this slot. (0) means          int weight;             /* The resize weight of this slot. (0) means
74                                   * this slot doesn't resize. Extra space in                                   * this slot doesn't resize. Extra space in
75                                   * the layout is given distributed among slots                                   * the layout is given distributed among slots
76                                   * inproportion to their weights. */                                   * inproportion to their weights. */
77          int pad;                /* Extra padding, in pixels, required for          int pad;                /* Extra padding, in pixels, required for
78                                   * this slot.  This amount is "added" to the                                   * this slot.  This amount is "added" to the
79                                   * largest slave in the slot. */                                   * largest slave in the slot. */
80          int offset;             /* This is a cached value used for          int offset;             /* This is a cached value used for
81                                   * introspection.  It is the pixel                                   * introspection.  It is the pixel
82                                   * offset of the right or bottom edge                                   * offset of the right or bottom edge
83                                   * of this slot from the beginning of the                                   * of this slot from the beginning of the
84                                   * layout. */                                   * layout. */
85          int temp;               /* This is a temporary value used for          int temp;               /* This is a temporary value used for
86                                   * calculating adjusted weights when                                   * calculating adjusted weights when
87                                   * shrinking the layout below its                                   * shrinking the layout below its
88                                   * nominal size. */                                   * nominal size. */
89  } SlotInfo;  } SlotInfo;
90    
91  /*  /*
92   * Structure to hold information during layout calculations.  There   * Structure to hold information during layout calculations.  There
93   * is one of these for each slot, an array for each of the rows or columns.   * is one of these for each slot, an array for each of the rows or columns.
94   */   */
95    
96  typedef struct GridLayout {  typedef struct GridLayout {
97      struct Gridder *binNextPtr; /* The next slave window in this bin.      struct Gridder *binNextPtr; /* The next slave window in this bin.
98                                   * Each bin contains a list of all                                   * Each bin contains a list of all
99                                   * slaves whose spans are >1 and whose                                   * slaves whose spans are >1 and whose
100                                   * right edges fall in this slot. */                                   * right edges fall in this slot. */
101      int minSize;                /* Minimum size needed for this slot,      int minSize;                /* Minimum size needed for this slot,
102                                   * in pixels.  This is the space required                                   * in pixels.  This is the space required
103                                   * to hold any slaves contained entirely                                   * to hold any slaves contained entirely
104                                   * in this slot, adjusted for any slot                                   * in this slot, adjusted for any slot
105                                   * constrants, such as size or padding. */                                   * constrants, such as size or padding. */
106      int pad;                    /* Padding needed for this slot */      int pad;                    /* Padding needed for this slot */
107      int weight;                 /* Slot weight, controls resizing. */      int weight;                 /* Slot weight, controls resizing. */
108      int minOffset;              /* The minimum offset, in pixels, from      int minOffset;              /* The minimum offset, in pixels, from
109                                   * the beginning of the layout to the                                   * the beginning of the layout to the
110                                   * right/bottom edge of the slot calculated                                   * right/bottom edge of the slot calculated
111                                   * from top/left to bottom/right. */                                   * from top/left to bottom/right. */
112      int maxOffset;              /* The maximum offset, in pixels, from      int maxOffset;              /* The maximum offset, in pixels, from
113                                   * the beginning of the layout to the                                   * the beginning of the layout to the
114                                   * right-or-bottom edge of the slot calculated                                   * right-or-bottom edge of the slot calculated
115                                   * from bottom-or-right to top-or-left. */                                   * from bottom-or-right to top-or-left. */
116  } GridLayout;  } GridLayout;
117    
118  /*  /*
119   * Keep one of these for each geometry master.   * Keep one of these for each geometry master.
120   */   */
121    
122  typedef struct {  typedef struct {
123      SlotInfo *columnPtr;        /* Pointer to array of column constraints. */      SlotInfo *columnPtr;        /* Pointer to array of column constraints. */
124      SlotInfo *rowPtr;           /* Pointer to array of row constraints. */      SlotInfo *rowPtr;           /* Pointer to array of row constraints. */
125      int columnEnd;              /* The last column occupied by any slave. */      int columnEnd;              /* The last column occupied by any slave. */
126      int columnMax;              /* The number of columns with constraints. */      int columnMax;              /* The number of columns with constraints. */
127      int columnSpace;            /* The number of slots currently allocated for      int columnSpace;            /* The number of slots currently allocated for
128                                   * column constraints. */                                   * column constraints. */
129      int rowEnd;                 /* The last row occupied by any slave. */      int rowEnd;                 /* The last row occupied by any slave. */
130      int rowMax;                 /* The number of rows with constraints. */      int rowMax;                 /* The number of rows with constraints. */
131      int rowSpace;               /* The number of slots currently allocated      int rowSpace;               /* The number of slots currently allocated
132                                   * for row constraints. */                                   * for row constraints. */
133      int startX;                 /* Pixel offset of this layout within its      int startX;                 /* Pixel offset of this layout within its
134                                   * parent. */                                   * parent. */
135      int startY;                 /* Pixel offset of this layout within its      int startY;                 /* Pixel offset of this layout within its
136                                   * parent. */                                   * parent. */
137  } GridMaster;  } GridMaster;
138    
139  /*  /*
140   * For each window that the grid cares about (either because   * For each window that the grid cares about (either because
141   * the window is managed by the grid or because the window   * the window is managed by the grid or because the window
142   * has slaves that are managed by the grid), there is a   * has slaves that are managed by the grid), there is a
143   * structure of the following type:   * structure of the following type:
144   */   */
145    
146  typedef struct Gridder {  typedef struct Gridder {
147      Tk_Window tkwin;            /* Tk token for window.  NULL means that      Tk_Window tkwin;            /* Tk token for window.  NULL means that
148                                   * the window has been deleted, but the                                   * the window has been deleted, but the
149                                   * gridder hasn't had a chance to clean up                                   * gridder hasn't had a chance to clean up
150                                   * yet because the structure is still in                                   * yet because the structure is still in
151                                   * use. */                                   * use. */
152      struct Gridder *masterPtr;  /* Master window within which this window      struct Gridder *masterPtr;  /* Master window within which this window
153                                   * is managed (NULL means this window                                   * is managed (NULL means this window
154                                   * isn't managed by the gridder). */                                   * isn't managed by the gridder). */
155      struct Gridder *nextPtr;    /* Next window managed within same      struct Gridder *nextPtr;    /* Next window managed within same
156                                   * parent.  List order doesn't matter. */                                   * parent.  List order doesn't matter. */
157      struct Gridder *slavePtr;   /* First in list of slaves managed      struct Gridder *slavePtr;   /* First in list of slaves managed
158                                   * inside this window (NULL means                                   * inside this window (NULL means
159                                   * no grid slaves). */                                   * no grid slaves). */
160      GridMaster *masterDataPtr;  /* Additional data for geometry master. */      GridMaster *masterDataPtr;  /* Additional data for geometry master. */
161      int column, row;            /* Location in the grid (starting      int column, row;            /* Location in the grid (starting
162                                   * from zero). */                                   * from zero). */
163      int numCols, numRows;       /* Number of columns or rows this slave spans.      int numCols, numRows;       /* Number of columns or rows this slave spans.
164                                   * Should be at least 1. */                                   * Should be at least 1. */
165      int padX, padY;             /* Total additional pixels to leave around the      int padX, padY;             /* Total additional pixels to leave around the
166                                   * window (half of this space is left on each                                   * window (half of this space is left on each
167                                   * side).  This is space *outside* the window:                                   * side).  This is space *outside* the window:
168                                   * we'll allocate extra space in frame but                                   * we'll allocate extra space in frame but
169                                   * won't enlarge window). */                                   * won't enlarge window). */
170      int iPadX, iPadY;           /* Total extra pixels to allocate inside the      int iPadX, iPadY;           /* Total extra pixels to allocate inside the
171                                   * window (half this amount will appear on                                   * window (half this amount will appear on
172                                   * each side). */                                   * each side). */
173      int sticky;                 /* which sides of its cavity this window      int sticky;                 /* which sides of its cavity this window
174                                   * sticks to. See below for definitions */                                   * sticks to. See below for definitions */
175      int doubleBw;               /* Twice the window's last known border      int doubleBw;               /* Twice the window's last known border
176                                   * width.  If this changes, the window                                   * width.  If this changes, the window
177                                   * must be re-arranged within its parent. */                                   * must be re-arranged within its parent. */
178      int *abortPtr;              /* If non-NULL, it means that there is a nested      int *abortPtr;              /* If non-NULL, it means that there is a nested
179                                   * call to ArrangeGrid already working on                                   * call to ArrangeGrid already working on
180                                   * this window.  *abortPtr may be set to 1 to                                   * this window.  *abortPtr may be set to 1 to
181                                   * abort that nested call.  This happens, for                                   * abort that nested call.  This happens, for
182                                   * example, if tkwin or any of its slaves                                   * example, if tkwin or any of its slaves
183                                   * is deleted. */                                   * is deleted. */
184      int flags;                  /* Miscellaneous flags;  see below      int flags;                  /* Miscellaneous flags;  see below
185                                   * for definitions. */                                   * for definitions. */
186    
187      /*      /*
188       * These fields are used temporarily for layout calculations only.       * These fields are used temporarily for layout calculations only.
189       */       */
190    
191      struct Gridder *binNextPtr; /* Link to next span>1 slave in this bin. */      struct Gridder *binNextPtr; /* Link to next span>1 slave in this bin. */
192      int size;                   /* Nominal size (width or height) in pixels      int size;                   /* Nominal size (width or height) in pixels
193                                   * of the slave.  This includes the padding. */                                   * of the slave.  This includes the padding. */
194  } Gridder;  } Gridder;
195    
196  /* Flag values for "sticky"ness  The 16 combinations subsume the packer's  /* Flag values for "sticky"ness  The 16 combinations subsume the packer's
197   * notion of anchor and fill.   * notion of anchor and fill.
198   *   *
199   * STICK_NORTH          This window sticks to the top of its cavity.   * STICK_NORTH          This window sticks to the top of its cavity.
200   * STICK_EAST           This window sticks to the right edge of its cavity.   * STICK_EAST           This window sticks to the right edge of its cavity.
201   * STICK_SOUTH          This window sticks to the bottom of its cavity.   * STICK_SOUTH          This window sticks to the bottom of its cavity.
202   * STICK_WEST           This window sticks to the left edge of its cavity.   * STICK_WEST           This window sticks to the left edge of its cavity.
203   */   */
204    
205  #define STICK_NORTH             1  #define STICK_NORTH             1
206  #define STICK_EAST              2  #define STICK_EAST              2
207  #define STICK_SOUTH             4  #define STICK_SOUTH             4
208  #define STICK_WEST              8  #define STICK_WEST              8
209    
210  /*  /*
211   * Flag values for Grid structures:   * Flag values for Grid structures:
212   *   *
213   * REQUESTED_RELAYOUT:          1 means a Tcl_DoWhenIdle request   * REQUESTED_RELAYOUT:          1 means a Tcl_DoWhenIdle request
214   *                              has already been made to re-arrange   *                              has already been made to re-arrange
215   *                              all the slaves of this window.   *                              all the slaves of this window.
216   *   *
217   * DONT_PROPAGATE:              1 means don't set this window's requested   * DONT_PROPAGATE:              1 means don't set this window's requested
218   *                              size.  0 means if this window is a master   *                              size.  0 means if this window is a master
219   *                              then Tk will set its requested size to fit   *                              then Tk will set its requested size to fit
220   *                              the needs of its slaves.   *                              the needs of its slaves.
221   */   */
222    
223  #define REQUESTED_RELAYOUT      1  #define REQUESTED_RELAYOUT      1
224  #define DONT_PROPAGATE          2  #define DONT_PROPAGATE          2
225    
226  /*  /*
227   * Prototypes for procedures used only in this file:   * Prototypes for procedures used only in this file:
228   */   */
229    
230  static void     AdjustForSticky _ANSI_ARGS_((Gridder *slavePtr, int *xPtr,  static void     AdjustForSticky _ANSI_ARGS_((Gridder *slavePtr, int *xPtr,
231                      int *yPtr, int *widthPtr, int *heightPtr));                      int *yPtr, int *widthPtr, int *heightPtr));
232  static int      AdjustOffsets _ANSI_ARGS_((int width,  static int      AdjustOffsets _ANSI_ARGS_((int width,
233                          int elements, SlotInfo *slotPtr));                          int elements, SlotInfo *slotPtr));
234  static void     ArrangeGrid _ANSI_ARGS_((ClientData clientData));  static void     ArrangeGrid _ANSI_ARGS_((ClientData clientData));
235  static int      CheckSlotData _ANSI_ARGS_((Gridder *masterPtr, int slot,  static int      CheckSlotData _ANSI_ARGS_((Gridder *masterPtr, int slot,
236                          int slotType, int checkOnly));                          int slotType, int checkOnly));
237  static int      ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp,  static int      ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp,
238                          Tk_Window tkwin, int argc, char *argv[]));                          Tk_Window tkwin, int argc, char *argv[]));
239  static void     DestroyGrid _ANSI_ARGS_((char *memPtr));  static void     DestroyGrid _ANSI_ARGS_((char *memPtr));
240  static Gridder *GetGrid _ANSI_ARGS_((Tk_Window tkwin));  static Gridder *GetGrid _ANSI_ARGS_((Tk_Window tkwin));
241  static void     GridStructureProc _ANSI_ARGS_((  static void     GridStructureProc _ANSI_ARGS_((
242                          ClientData clientData, XEvent *eventPtr));                          ClientData clientData, XEvent *eventPtr));
243  static void     GridLostSlaveProc _ANSI_ARGS_((ClientData clientData,  static void     GridLostSlaveProc _ANSI_ARGS_((ClientData clientData,
244                          Tk_Window tkwin));                          Tk_Window tkwin));
245  static void     GridReqProc _ANSI_ARGS_((ClientData clientData,  static void     GridReqProc _ANSI_ARGS_((ClientData clientData,
246                          Tk_Window tkwin));                          Tk_Window tkwin));
247  static void     InitMasterData _ANSI_ARGS_((Gridder *masterPtr));  static void     InitMasterData _ANSI_ARGS_((Gridder *masterPtr));
248  static int      ResolveConstraints _ANSI_ARGS_((Gridder *gridPtr,  static int      ResolveConstraints _ANSI_ARGS_((Gridder *gridPtr,
249                          int rowOrColumn, int maxOffset));                          int rowOrColumn, int maxOffset));
250  static void     SetGridSize _ANSI_ARGS_((Gridder *gridPtr));  static void     SetGridSize _ANSI_ARGS_((Gridder *gridPtr));
251  static void     StickyToString _ANSI_ARGS_((int flags, char *result));  static void     StickyToString _ANSI_ARGS_((int flags, char *result));
252  static int      StringToSticky _ANSI_ARGS_((char *string));  static int      StringToSticky _ANSI_ARGS_((char *string));
253  static void     Unlink _ANSI_ARGS_((Gridder *gridPtr));  static void     Unlink _ANSI_ARGS_((Gridder *gridPtr));
254    
255  static Tk_GeomMgr gridMgrType = {  static Tk_GeomMgr gridMgrType = {
256      "grid",                     /* name */      "grid",                     /* name */
257      GridReqProc,                /* requestProc */      GridReqProc,                /* requestProc */
258      GridLostSlaveProc,          /* lostSlaveProc */      GridLostSlaveProc,          /* lostSlaveProc */
259  };  };
260    
261  /*  /*
262   *--------------------------------------------------------------   *--------------------------------------------------------------
263   *   *
264   * Tk_GridCmd --   * Tk_GridCmd --
265   *   *
266   *      This procedure is invoked to process the "grid" Tcl command.   *      This procedure is invoked to process the "grid" Tcl command.
267   *      See the user documentation for details on what it does.   *      See the user documentation for details on what it does.
268   *   *
269   * Results:   * Results:
270   *      A standard Tcl result.   *      A standard Tcl result.
271   *   *
272   * Side effects:   * Side effects:
273   *      See the user documentation.   *      See the user documentation.
274   *   *
275   *--------------------------------------------------------------   *--------------------------------------------------------------
276   */   */
277    
278  int  int
279  Tk_GridCmd(clientData, interp, argc, argv)  Tk_GridCmd(clientData, interp, argc, argv)
280      ClientData clientData;      /* Main window associated with      ClientData clientData;      /* Main window associated with
281                                   * interpreter. */                                   * interpreter. */
282      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
283      int argc;                   /* Number of arguments. */      int argc;                   /* Number of arguments. */
284      char **argv;                /* Argument strings. */      char **argv;                /* Argument strings. */
285  {  {
286      Tk_Window tkwin = (Tk_Window) clientData;      Tk_Window tkwin = (Tk_Window) clientData;
287      Gridder *masterPtr;         /* master grid record */      Gridder *masterPtr;         /* master grid record */
288      GridMaster *gridPtr;        /* pointer to grid data */      GridMaster *gridPtr;        /* pointer to grid data */
289      size_t length;              /* streing length of argument */      size_t length;              /* streing length of argument */
290      char c;                     /* 1st character of argument */      char c;                     /* 1st character of argument */
291        
292      if ((argc >= 2) && ((argv[1][0] == '.') || (argv[1][0] == REL_SKIP) ||      if ((argc >= 2) && ((argv[1][0] == '.') || (argv[1][0] == REL_SKIP) ||
293                  (argv[1][0] == REL_VERT))) {                  (argv[1][0] == REL_VERT))) {
294          return ConfigureSlaves(interp, tkwin, argc-1, argv+1);          return ConfigureSlaves(interp, tkwin, argc-1, argv+1);
295      }      }
296      if (argc < 3) {      if (argc < 3) {
297          Tcl_AppendResult(interp, "wrong # args: should be \"",          Tcl_AppendResult(interp, "wrong # args: should be \"",
298                  argv[0], " option arg ?arg ...?\"", (char *) NULL);                  argv[0], " option arg ?arg ...?\"", (char *) NULL);
299          return TCL_ERROR;          return TCL_ERROR;
300      }      }
301      c = argv[1][0];      c = argv[1][0];
302      length = strlen(argv[1]);      length = strlen(argv[1]);
303        
304      if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {      if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {
305          Tk_Window master;          Tk_Window master;
306          int row, column;        /* origin for bounding box */          int row, column;        /* origin for bounding box */
307          int row2, column2;      /* end of bounding box */          int row2, column2;      /* end of bounding box */
308          int endX, endY;         /* last column/row in the layout */          int endX, endY;         /* last column/row in the layout */
309          int x=0, y=0;           /* starting pixels for this bounding box */          int x=0, y=0;           /* starting pixels for this bounding box */
310          int width, height;      /* size of the bounding box */          int width, height;      /* size of the bounding box */
311          char buf[TCL_INTEGER_SPACE * 4];          char buf[TCL_INTEGER_SPACE * 4];
312    
313          if (argc!=3 && argc != 5 && argc != 7) {          if (argc!=3 && argc != 5 && argc != 7) {
314              Tcl_AppendResult(interp, "wrong number of arguments: ",              Tcl_AppendResult(interp, "wrong number of arguments: ",
315                      "must be \"",argv[0],                      "must be \"",argv[0],
316                      " bbox master ?column row ?column row??\"",                      " bbox master ?column row ?column row??\"",
317                      (char *) NULL);                      (char *) NULL);
318              return TCL_ERROR;              return TCL_ERROR;
319          }          }
320                    
321          master = Tk_NameToWindow(interp, argv[2], tkwin);          master = Tk_NameToWindow(interp, argv[2], tkwin);
322          if (master == NULL) {          if (master == NULL) {
323              return TCL_ERROR;              return TCL_ERROR;
324          }          }
325          masterPtr = GetGrid(master);          masterPtr = GetGrid(master);
326    
327          if (argc >= 5) {          if (argc >= 5) {
328              if (Tcl_GetInt(interp, argv[3], &column) != TCL_OK) {              if (Tcl_GetInt(interp, argv[3], &column) != TCL_OK) {
329                  return TCL_ERROR;                  return TCL_ERROR;
330              }              }
331              if (Tcl_GetInt(interp, argv[4], &row) != TCL_OK) {              if (Tcl_GetInt(interp, argv[4], &row) != TCL_OK) {
332                  return TCL_ERROR;                  return TCL_ERROR;
333              }              }
334              column2 = column;              column2 = column;
335              row2 = row;              row2 = row;
336          }          }
337    
338          if (argc == 7) {          if (argc == 7) {
339              if (Tcl_GetInt(interp, argv[5], &column2) != TCL_OK) {              if (Tcl_GetInt(interp, argv[5], &column2) != TCL_OK) {
340                  return TCL_ERROR;                  return TCL_ERROR;
341              }              }
342              if (Tcl_GetInt(interp, argv[6], &row2) != TCL_OK) {              if (Tcl_GetInt(interp, argv[6], &row2) != TCL_OK) {
343                  return TCL_ERROR;                  return TCL_ERROR;
344              }              }
345          }          }
346    
347          gridPtr = masterPtr->masterDataPtr;          gridPtr = masterPtr->masterDataPtr;
348          if (gridPtr == NULL) {          if (gridPtr == NULL) {
349              Tcl_SetResult(interp, "0 0 0 0", TCL_STATIC);              Tcl_SetResult(interp, "0 0 0 0", TCL_STATIC);
350              return(TCL_OK);              return(TCL_OK);
351          }          }
352    
353          SetGridSize(masterPtr);          SetGridSize(masterPtr);
354          endX = MAX(gridPtr->columnEnd, gridPtr->columnMax);          endX = MAX(gridPtr->columnEnd, gridPtr->columnMax);
355          endY = MAX(gridPtr->rowEnd, gridPtr->rowMax);          endY = MAX(gridPtr->rowEnd, gridPtr->rowMax);
356    
357          if ((endX == 0) || (endY == 0)) {          if ((endX == 0) || (endY == 0)) {
358              Tcl_SetResult(interp, "0 0 0 0", TCL_STATIC);              Tcl_SetResult(interp, "0 0 0 0", TCL_STATIC);
359              return(TCL_OK);              return(TCL_OK);
360          }          }
361          if (argc == 3) {          if (argc == 3) {
362              row = column = 0;              row = column = 0;
363              row2 = endY;              row2 = endY;
364              column2 = endX;              column2 = endX;
365          }          }
366    
367          if (column > column2) {          if (column > column2) {
368              int temp = column;              int temp = column;
369              column = column2, column2 = temp;              column = column2, column2 = temp;
370          }          }
371          if (row > row2) {          if (row > row2) {
372              int temp = row;              int temp = row;
373              row = row2, row2 = temp;              row = row2, row2 = temp;
374          }          }
375    
376          if (column > 0 && column < endX) {          if (column > 0 && column < endX) {
377              x = gridPtr->columnPtr[column-1].offset;              x = gridPtr->columnPtr[column-1].offset;
378          } else if  (column > 0) {          } else if  (column > 0) {
379              x = gridPtr->columnPtr[endX-1].offset;              x = gridPtr->columnPtr[endX-1].offset;
380          }          }
381    
382          if (row > 0 && row < endY) {          if (row > 0 && row < endY) {
383              y = gridPtr->rowPtr[row-1].offset;              y = gridPtr->rowPtr[row-1].offset;
384          } else if (row > 0) {          } else if (row > 0) {
385              y = gridPtr->rowPtr[endY-1].offset;              y = gridPtr->rowPtr[endY-1].offset;
386          }          }
387    
388          if (column2 < 0) {          if (column2 < 0) {
389              width = 0;              width = 0;
390          } else if (column2 >= endX) {          } else if (column2 >= endX) {
391              width = gridPtr->columnPtr[endX-1].offset - x;              width = gridPtr->columnPtr[endX-1].offset - x;
392          } else {          } else {
393              width = gridPtr->columnPtr[column2].offset - x;              width = gridPtr->columnPtr[column2].offset - x;
394          }          }
395    
396          if (row2 < 0) {          if (row2 < 0) {
397              height = 0;              height = 0;
398          } else if (row2 >= endY) {          } else if (row2 >= endY) {
399              height = gridPtr->rowPtr[endY-1].offset - y;              height = gridPtr->rowPtr[endY-1].offset - y;
400          } else {          } else {
401              height = gridPtr->rowPtr[row2].offset - y;              height = gridPtr->rowPtr[row2].offset - y;
402          }          }
403    
404          sprintf(buf, "%d %d %d %d", x + gridPtr->startX, y + gridPtr->startY,          sprintf(buf, "%d %d %d %d", x + gridPtr->startX, y + gridPtr->startY,
405                  width, height);                  width, height);
406          Tcl_SetResult(interp, buf, TCL_VOLATILE);          Tcl_SetResult(interp, buf, TCL_VOLATILE);
407      } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {      } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
408          if (argv[2][0] != '.') {          if (argv[2][0] != '.') {
409              Tcl_AppendResult(interp, "bad argument \"", argv[2],              Tcl_AppendResult(interp, "bad argument \"", argv[2],
410                      "\": must be name of window", (char *) NULL);                      "\": must be name of window", (char *) NULL);
411              return TCL_ERROR;              return TCL_ERROR;
412          }          }
413          return ConfigureSlaves(interp, tkwin, argc-2, argv+2);          return ConfigureSlaves(interp, tkwin, argc-2, argv+2);
414      } else if (((c == 'f') && (strncmp(argv[1], "forget", length) == 0))  ||      } else if (((c == 'f') && (strncmp(argv[1], "forget", length) == 0))  ||
415              ((c == 'r') && (strncmp(argv[1], "remove", length) == 0))) {              ((c == 'r') && (strncmp(argv[1], "remove", length) == 0))) {
416          Tk_Window slave;          Tk_Window slave;
417          Gridder *slavePtr;          Gridder *slavePtr;
418          int i;          int i;
419            
420          for (i = 2; i < argc; i++) {          for (i = 2; i < argc; i++) {
421              slave = Tk_NameToWindow(interp, argv[i], tkwin);              slave = Tk_NameToWindow(interp, argv[i], tkwin);
422              if (slave == NULL) {              if (slave == NULL) {
423                  return TCL_ERROR;                  return TCL_ERROR;
424              }              }
425              slavePtr = GetGrid(slave);              slavePtr = GetGrid(slave);
426              if (slavePtr->masterPtr != NULL) {              if (slavePtr->masterPtr != NULL) {
427    
428                  /*                  /*
429                   * For "forget", reset all the settings to their defaults                   * For "forget", reset all the settings to their defaults
430                   */                   */
431    
432                  if (c == 'f') {                  if (c == 'f') {
433                      slavePtr->column = slavePtr->row = -1;                      slavePtr->column = slavePtr->row = -1;
434                      slavePtr->numCols = 1;                      slavePtr->numCols = 1;
435                      slavePtr->numRows = 1;                      slavePtr->numRows = 1;
436                      slavePtr->padX = slavePtr->padY = 0;                      slavePtr->padX = slavePtr->padY = 0;
437                      slavePtr->iPadX = slavePtr->iPadY = 0;                      slavePtr->iPadX = slavePtr->iPadY = 0;
438                      slavePtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;                      slavePtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
439                      if (slavePtr->flags & REQUESTED_RELAYOUT) {                      if (slavePtr->flags & REQUESTED_RELAYOUT) {
440                          Tcl_CancelIdleCall(ArrangeGrid, (ClientData) slavePtr);                          Tcl_CancelIdleCall(ArrangeGrid, (ClientData) slavePtr);
441                      }                      }
442                      slavePtr->flags = 0;                      slavePtr->flags = 0;
443                      slavePtr->sticky = 0;                      slavePtr->sticky = 0;
444                  }                  }
445                  Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,                  Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,
446                          (ClientData) NULL);                          (ClientData) NULL);
447                  if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {                  if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
448                      Tk_UnmaintainGeometry(slavePtr->tkwin,                      Tk_UnmaintainGeometry(slavePtr->tkwin,
449                              slavePtr->masterPtr->tkwin);                              slavePtr->masterPtr->tkwin);
450                  }                  }
451                  Unlink(slavePtr);                  Unlink(slavePtr);
452                  Tk_UnmapWindow(slavePtr->tkwin);                  Tk_UnmapWindow(slavePtr->tkwin);
453              }              }
454          }          }
455      } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {      } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
456          register Gridder *slavePtr;          register Gridder *slavePtr;
457          Tk_Window slave;          Tk_Window slave;
458          char buffer[64 + TCL_INTEGER_SPACE * 4];          char buffer[64 + TCL_INTEGER_SPACE * 4];
459            
460          if (argc != 3) {          if (argc != 3) {
461              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
462                      argv[0], " info window\"", (char *) NULL);                      argv[0], " info window\"", (char *) NULL);
463              return TCL_ERROR;              return TCL_ERROR;
464          }          }
465          slave = Tk_NameToWindow(interp, argv[2], tkwin);          slave = Tk_NameToWindow(interp, argv[2], tkwin);
466          if (slave == NULL) {          if (slave == NULL) {
467              return TCL_ERROR;              return TCL_ERROR;
468          }          }
469          slavePtr = GetGrid(slave);          slavePtr = GetGrid(slave);
470          if (slavePtr->masterPtr == NULL) {          if (slavePtr->masterPtr == NULL) {
471              Tcl_ResetResult(interp);              Tcl_ResetResult(interp);
472              return TCL_OK;              return TCL_OK;
473          }          }
474            
475          Tcl_AppendElement(interp, "-in");          Tcl_AppendElement(interp, "-in");
476          Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin));          Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin));
477          sprintf(buffer, " -column %d -row %d -columnspan %d -rowspan %d",          sprintf(buffer, " -column %d -row %d -columnspan %d -rowspan %d",
478                  slavePtr->column, slavePtr->row,                  slavePtr->column, slavePtr->row,
479                  slavePtr->numCols, slavePtr->numRows);                  slavePtr->numCols, slavePtr->numRows);
480          Tcl_AppendResult(interp, buffer, (char *) NULL);          Tcl_AppendResult(interp, buffer, (char *) NULL);
481          sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d",          sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d",
482                  slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2,                  slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2,
483                  slavePtr->padY/2);                  slavePtr->padY/2);
484          Tcl_AppendResult(interp, buffer, (char *) NULL);          Tcl_AppendResult(interp, buffer, (char *) NULL);
485          StickyToString(slavePtr->sticky,buffer);          StickyToString(slavePtr->sticky,buffer);
486          Tcl_AppendResult(interp, " -sticky ", buffer, (char *) NULL);          Tcl_AppendResult(interp, " -sticky ", buffer, (char *) NULL);
487      } else if((c == 'l') && (strncmp(argv[1], "location", length) == 0)) {      } else if((c == 'l') && (strncmp(argv[1], "location", length) == 0)) {
488          Tk_Window master;          Tk_Window master;
489          register SlotInfo *slotPtr;          register SlotInfo *slotPtr;
490          int x, y;               /* Offset in pixels, from edge of parent. */          int x, y;               /* Offset in pixels, from edge of parent. */
491          int i, j;               /* Corresponding column and row indeces. */          int i, j;               /* Corresponding column and row indeces. */
492          int endX, endY;         /* end of grid */          int endX, endY;         /* end of grid */
493          char buf[TCL_INTEGER_SPACE * 2];          char buf[TCL_INTEGER_SPACE * 2];
494    
495          if (argc != 5) {          if (argc != 5) {
496              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
497                      argv[0], " location master x y\"", (char *)NULL);                      argv[0], " location master x y\"", (char *)NULL);
498              return TCL_ERROR;              return TCL_ERROR;
499          }          }
500    
501          master = Tk_NameToWindow(interp, argv[2], tkwin);          master = Tk_NameToWindow(interp, argv[2], tkwin);
502          if (master == NULL) {          if (master == NULL) {
503              return TCL_ERROR;              return TCL_ERROR;
504          }          }
505    
506          if (Tk_GetPixels(interp, master, argv[3], &x) != TCL_OK) {          if (Tk_GetPixels(interp, master, argv[3], &x) != TCL_OK) {
507              return TCL_ERROR;              return TCL_ERROR;
508          }          }
509          if (Tk_GetPixels(interp, master, argv[4], &y) != TCL_OK) {          if (Tk_GetPixels(interp, master, argv[4], &y) != TCL_OK) {
510              return TCL_ERROR;              return TCL_ERROR;
511          }          }
512    
513          masterPtr = GetGrid(master);          masterPtr = GetGrid(master);
514          if (masterPtr->masterDataPtr == NULL) {          if (masterPtr->masterDataPtr == NULL) {
515              Tcl_SetResult(interp, "-1 -1", TCL_STATIC);              Tcl_SetResult(interp, "-1 -1", TCL_STATIC);
516              return TCL_OK;              return TCL_OK;
517          }          }
518          gridPtr = masterPtr->masterDataPtr;          gridPtr = masterPtr->masterDataPtr;
519    
520          /*          /*
521           * Update any pending requests.  This is not always the           * Update any pending requests.  This is not always the
522           * steady state value, as more configure events could be in           * steady state value, as more configure events could be in
523           * the pipeline, but its as close as its easy to get.           * the pipeline, but its as close as its easy to get.
524           */           */
525    
526          while (masterPtr->flags & REQUESTED_RELAYOUT) {          while (masterPtr->flags & REQUESTED_RELAYOUT) {
527              Tcl_CancelIdleCall(ArrangeGrid, (ClientData) masterPtr);              Tcl_CancelIdleCall(ArrangeGrid, (ClientData) masterPtr);
528              ArrangeGrid ((ClientData) masterPtr);              ArrangeGrid ((ClientData) masterPtr);
529          }          }
530          SetGridSize(masterPtr);          SetGridSize(masterPtr);
531          endX = MAX(gridPtr->columnEnd, gridPtr->columnMax);          endX = MAX(gridPtr->columnEnd, gridPtr->columnMax);
532          endY = MAX(gridPtr->rowEnd, gridPtr->rowMax);          endY = MAX(gridPtr->rowEnd, gridPtr->rowMax);
533    
534          slotPtr  = masterPtr->masterDataPtr->columnPtr;          slotPtr  = masterPtr->masterDataPtr->columnPtr;
535          if (x < masterPtr->masterDataPtr->startX) {          if (x < masterPtr->masterDataPtr->startX) {
536              i = -1;              i = -1;
537          } else {          } else {
538              x -= masterPtr->masterDataPtr->startX;              x -= masterPtr->masterDataPtr->startX;
539              for (i=0;slotPtr[i].offset < x && i < endX; i++) {              for (i=0;slotPtr[i].offset < x && i < endX; i++) {
540                  /* null body */                  /* null body */
541              }              }
542          }          }
543    
544          slotPtr  = masterPtr->masterDataPtr->rowPtr;          slotPtr  = masterPtr->masterDataPtr->rowPtr;
545          if (y < masterPtr->masterDataPtr->startY) {          if (y < masterPtr->masterDataPtr->startY) {
546              j = -1;              j = -1;
547          } else {          } else {
548              y -= masterPtr->masterDataPtr->startY;              y -= masterPtr->masterDataPtr->startY;
549              for (j=0;slotPtr[j].offset < y && j < endY; j++) {              for (j=0;slotPtr[j].offset < y && j < endY; j++) {
550                  /* null body */                  /* null body */
551              }              }
552          }          }
553    
554          sprintf(buf, "%d %d", i, j);          sprintf(buf, "%d %d", i, j);
555          Tcl_SetResult(interp, buf, TCL_VOLATILE);          Tcl_SetResult(interp, buf, TCL_VOLATILE);
556      } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) {      } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) {
557          Tk_Window master;          Tk_Window master;
558          int propagate;          int propagate;
559            
560          if (argc > 4) {          if (argc > 4) {
561              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
562                      argv[0], " propagate window ?boolean?\"",                      argv[0], " propagate window ?boolean?\"",
563                      (char *) NULL);                      (char *) NULL);
564              return TCL_ERROR;              return TCL_ERROR;
565          }          }
566          master = Tk_NameToWindow(interp, argv[2], tkwin);          master = Tk_NameToWindow(interp, argv[2], tkwin);
567          if (master == NULL) {          if (master == NULL) {
568              return TCL_ERROR;              return TCL_ERROR;
569          }          }
570          masterPtr = GetGrid(master);          masterPtr = GetGrid(master);
571          if (argc == 3) {          if (argc == 3) {
572              Tcl_SetResult(interp,              Tcl_SetResult(interp,
573                      ((masterPtr->flags & DONT_PROPAGATE) ? "0" : "1"),                      ((masterPtr->flags & DONT_PROPAGATE) ? "0" : "1"),
574                      TCL_STATIC);                      TCL_STATIC);
575              return TCL_OK;              return TCL_OK;
576          }          }
577          if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) {          if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) {
578              return TCL_ERROR;              return TCL_ERROR;
579          }          }
580                    
581          /* Only request a relayout if the propagation bit changes */          /* Only request a relayout if the propagation bit changes */
582                    
583          if ((!propagate) ^ (masterPtr->flags&DONT_PROPAGATE)) {          if ((!propagate) ^ (masterPtr->flags&DONT_PROPAGATE)) {
584              if (propagate) {              if (propagate) {
585                  masterPtr->flags &= ~DONT_PROPAGATE;                  masterPtr->flags &= ~DONT_PROPAGATE;
586              } else {              } else {
587                  masterPtr->flags |= DONT_PROPAGATE;                  masterPtr->flags |= DONT_PROPAGATE;
588              }              }
589                
590              /*              /*
591               * Re-arrange the master to allow new geometry information to               * Re-arrange the master to allow new geometry information to
592               * propagate upwards to the master's master.               * propagate upwards to the master's master.
593               */               */
594                
595              if (masterPtr->abortPtr != NULL) {              if (masterPtr->abortPtr != NULL) {
596                  *masterPtr->abortPtr = 1;                  *masterPtr->abortPtr = 1;
597              }              }
598              if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {              if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
599                  masterPtr->flags |= REQUESTED_RELAYOUT;                  masterPtr->flags |= REQUESTED_RELAYOUT;
600                  Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);                  Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
601              }              }
602          }          }
603      } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0)      } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0)
604              && (length > 1)) {              && (length > 1)) {
605          Tk_Window master;          Tk_Window master;
606    
607          if (argc != 3) {          if (argc != 3) {
608              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
609                      argv[0], " size window\"", (char *) NULL);                      argv[0], " size window\"", (char *) NULL);
610              return TCL_ERROR;              return TCL_ERROR;
611          }          }
612          master = Tk_NameToWindow(interp, argv[2], tkwin);          master = Tk_NameToWindow(interp, argv[2], tkwin);
613          if (master == NULL) {          if (master == NULL) {
614              return TCL_ERROR;              return TCL_ERROR;
615          }          }
616          masterPtr = GetGrid(master);          masterPtr = GetGrid(master);
617    
618          if (masterPtr->masterDataPtr != NULL) {          if (masterPtr->masterDataPtr != NULL) {
619              char buf[TCL_INTEGER_SPACE * 2];              char buf[TCL_INTEGER_SPACE * 2];
620    
621              SetGridSize(masterPtr);              SetGridSize(masterPtr);
622              gridPtr = masterPtr->masterDataPtr;              gridPtr = masterPtr->masterDataPtr;
623              sprintf(buf, "%d %d",              sprintf(buf, "%d %d",
624                      MAX(gridPtr->columnEnd, gridPtr->columnMax),                      MAX(gridPtr->columnEnd, gridPtr->columnMax),
625                      MAX(gridPtr->rowEnd, gridPtr->rowMax));                      MAX(gridPtr->rowEnd, gridPtr->rowMax));
626              Tcl_SetResult(interp, buf, TCL_VOLATILE);              Tcl_SetResult(interp, buf, TCL_VOLATILE);
627          } else {          } else {
628              Tcl_SetResult(interp, "0 0", TCL_STATIC);              Tcl_SetResult(interp, "0 0", TCL_STATIC);
629          }          }
630      } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)      } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)
631              && (length > 1)) {              && (length > 1)) {
632          Tk_Window master;          Tk_Window master;
633          Gridder *slavePtr;          Gridder *slavePtr;
634          int i, value;          int i, value;
635          int row = -1, column = -1;          int row = -1, column = -1;
636    
637          if ((argc < 3) || ((argc%2) == 0)) {          if ((argc < 3) || ((argc%2) == 0)) {
638              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
639                      argv[0], " slaves window ?-option value...?\"",                      argv[0], " slaves window ?-option value...?\"",
640                      (char *) NULL);                      (char *) NULL);
641              return TCL_ERROR;              return TCL_ERROR;
642          }          }
643    
644          for (i=3; i<argc; i+=2) {          for (i=3; i<argc; i+=2) {
645              length = strlen(argv[i]);              length = strlen(argv[i]);
646              if ((*argv[i] != '-') || (length < 2)) {              if ((*argv[i] != '-') || (length < 2)) {
647                  Tcl_AppendResult(interp, "invalid args: should be \"",                  Tcl_AppendResult(interp, "invalid args: should be \"",
648                          argv[0], " slaves window ?-option value...?\"",                          argv[0], " slaves window ?-option value...?\"",
649                          (char *) NULL);                          (char *) NULL);
650                  return TCL_ERROR;                  return TCL_ERROR;
651              }              }
652              if (Tcl_GetInt(interp, argv[i+1], &value) != TCL_OK) {              if (Tcl_GetInt(interp, argv[i+1], &value) != TCL_OK) {
653                  return TCL_ERROR;                  return TCL_ERROR;
654              }              }
655              if (value < 0) {              if (value < 0) {
656                  Tcl_AppendResult(interp, argv[i],                  Tcl_AppendResult(interp, argv[i],
657                          " is an invalid value: should NOT be < 0",                          " is an invalid value: should NOT be < 0",
658                          (char *) NULL);                          (char *) NULL);
659                  return TCL_ERROR;                  return TCL_ERROR;
660              }              }
661              if (strncmp(argv[i], "-column", length) == 0) {              if (strncmp(argv[i], "-column", length) == 0) {
662                  column = value;                  column = value;
663              } else if (strncmp(argv[i], "-row", length) == 0) {              } else if (strncmp(argv[i], "-row", length) == 0) {
664                  row = value;                  row = value;
665              } else {              } else {
666                  Tcl_AppendResult(interp, argv[i],                  Tcl_AppendResult(interp, argv[i],
667                          " is an invalid option: should be \"",                          " is an invalid option: should be \"",
668                          "-row, -column\"",                          "-row, -column\"",
669                          (char *) NULL);                          (char *) NULL);
670                  return TCL_ERROR;                  return TCL_ERROR;
671              }              }
672          }          }
673          master = Tk_NameToWindow(interp, argv[2], tkwin);          master = Tk_NameToWindow(interp, argv[2], tkwin);
674          if (master == NULL) {          if (master == NULL) {
675              return TCL_ERROR;              return TCL_ERROR;
676          }          }
677          masterPtr = GetGrid(master);          masterPtr = GetGrid(master);
678    
679          for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;          for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
680                                               slavePtr = slavePtr->nextPtr) {                                               slavePtr = slavePtr->nextPtr) {
681              if (column>=0 && (slavePtr->column > column              if (column>=0 && (slavePtr->column > column
682                      || slavePtr->column+slavePtr->numCols-1 < column)) {                      || slavePtr->column+slavePtr->numCols-1 < column)) {
683                  continue;                  continue;
684              }              }
685              if (row>=0 && (slavePtr->row > row ||              if (row>=0 && (slavePtr->row > row ||
686                      slavePtr->row+slavePtr->numRows-1 < row)) {                      slavePtr->row+slavePtr->numRows-1 < row)) {
687                  continue;                  continue;
688              }              }
689              Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));              Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));
690          }          }
691    
692      /*      /*
693       * Sample argument combinations:       * Sample argument combinations:
694       *  grid columnconfigure <master> <index> -option       *  grid columnconfigure <master> <index> -option
695       *  grid columnconfigure <master> <index> -option value -option value       *  grid columnconfigure <master> <index> -option value -option value
696       *  grid rowconfigure <master> <index>       *  grid rowconfigure <master> <index>
697       *  grid rowconfigure <master> <index> -option       *  grid rowconfigure <master> <index> -option
698       *  grid rowconfigure <master> <index> -option value -option value.       *  grid rowconfigure <master> <index> -option value -option value.
699       */       */
700        
701      } else if(((c == 'c') && (strncmp(argv[1], "columnconfigure", length) == 0)      } else if(((c == 'c') && (strncmp(argv[1], "columnconfigure", length) == 0)
702              && (length >= 3)) ||              && (length >= 3)) ||
703              ((c == 'r') && (strncmp(argv[1], "rowconfigure", length) == 0)              ((c == 'r') && (strncmp(argv[1], "rowconfigure", length) == 0)
704              && (length >=2))) {              && (length >=2))) {
705          Tk_Window master;          Tk_Window master;
706          SlotInfo *slotPtr = NULL;          SlotInfo *slotPtr = NULL;
707          int slot;               /* the column or row number */          int slot;               /* the column or row number */
708          size_t length;          /* the # of chars in the "-option" string */          size_t length;          /* the # of chars in the "-option" string */
709          int slotType;           /* COLUMN or ROW */          int slotType;           /* COLUMN or ROW */
710          int size;               /* the configuration value */          int size;               /* the configuration value */
711          int checkOnly;          /* check the size only */          int checkOnly;          /* check the size only */
712          int argcPtr;            /* Number of items in index list */          int argcPtr;            /* Number of items in index list */
713          char **argvPtr;         /* array of indeces */          char **argvPtr;         /* array of indeces */
714          char **indexP;          /* String value of current index list item. */          char **indexP;          /* String value of current index list item. */
715          int ok;                 /* temporary TCL result code */          int ok;                 /* temporary TCL result code */
716          int i;          int i;
717    
718          if (((argc%2 != 0) && (argc>6)) || (argc < 4)) {          if (((argc%2 != 0) && (argc>6)) || (argc < 4)) {
719              Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],              Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
720                      " ", argv[1], " master index ?-option value...?\"",                      " ", argv[1], " master index ?-option value...?\"",
721                      (char *)NULL);                      (char *)NULL);
722              return TCL_ERROR;              return TCL_ERROR;
723          }          }
724    
725          master = Tk_NameToWindow(interp, argv[2], tkwin);          master = Tk_NameToWindow(interp, argv[2], tkwin);
726          if (master == NULL) {          if (master == NULL) {
727              return TCL_ERROR;              return TCL_ERROR;
728          }          }
729    
730          if (Tcl_SplitList(interp, argv[3], &argcPtr, &argvPtr) != TCL_OK) {          if (Tcl_SplitList(interp, argv[3], &argcPtr, &argvPtr) != TCL_OK) {
731              return TCL_ERROR;              return TCL_ERROR;
732          }          }
733    
734          checkOnly = ((argc == 4) || (argc == 5));          checkOnly = ((argc == 4) || (argc == 5));
735          masterPtr = GetGrid(master);          masterPtr = GetGrid(master);
736          slotType = (c == 'c') ? COLUMN : ROW;          slotType = (c == 'c') ? COLUMN : ROW;
737          if (checkOnly && argcPtr > 1) {          if (checkOnly && argcPtr > 1) {
738              Tcl_AppendResult(interp, argv[3],              Tcl_AppendResult(interp, argv[3],
739                      " must be a single element.", (char *) NULL);                      " must be a single element.", (char *) NULL);
740              Tcl_Free((char *)argvPtr);              Tcl_Free((char *)argvPtr);
741              return TCL_ERROR;              return TCL_ERROR;
742          }          }
743          for (indexP=argvPtr; *indexP != NULL; indexP++) {          for (indexP=argvPtr; *indexP != NULL; indexP++) {
744              if (Tcl_GetInt(interp, *indexP, &slot) != TCL_OK) {              if (Tcl_GetInt(interp, *indexP, &slot) != TCL_OK) {
745                  Tcl_Free((char *)argvPtr);                  Tcl_Free((char *)argvPtr);
746                  return TCL_ERROR;                  return TCL_ERROR;
747              }              }
748              ok = CheckSlotData(masterPtr, slot, slotType, checkOnly);              ok = CheckSlotData(masterPtr, slot, slotType, checkOnly);
749              if ((ok!=TCL_OK) && ((argc<4) || (argc>5))) {              if ((ok!=TCL_OK) && ((argc<4) || (argc>5))) {
750                  Tcl_AppendResult(interp, argv[0],                  Tcl_AppendResult(interp, argv[0],
751                          " ", argv[1], ": \"", *argvPtr,"\" is out of range",                          " ", argv[1], ": \"", *argvPtr,"\" is out of range",
752                          (char *) NULL);                          (char *) NULL);
753                  Tcl_Free((char *)argvPtr);                  Tcl_Free((char *)argvPtr);
754                  return TCL_ERROR;                  return TCL_ERROR;
755              } else if (ok == TCL_OK) {              } else if (ok == TCL_OK) {
756                  slotPtr = (slotType == COLUMN) ?                  slotPtr = (slotType == COLUMN) ?
757                          masterPtr->masterDataPtr->columnPtr :                          masterPtr->masterDataPtr->columnPtr :
758                          masterPtr->masterDataPtr->rowPtr;                          masterPtr->masterDataPtr->rowPtr;
759              }              }
760    
761              /*              /*
762               * Return all of the options for this row or column.  If the               * Return all of the options for this row or column.  If the
763               * request is out of range, return all 0's.               * request is out of range, return all 0's.
764               */               */
765    
766              if (argc == 4) {              if (argc == 4) {
767                  Tcl_Free((char *)argvPtr);                  Tcl_Free((char *)argvPtr);
768              }              }
769              if ((argc == 4) && (ok == TCL_OK)) {              if ((argc == 4) && (ok == TCL_OK)) {
770                  char buf[64 + TCL_INTEGER_SPACE * 3];                  char buf[64 + TCL_INTEGER_SPACE * 3];
771                                    
772                  sprintf(buf, "-minsize %d -pad %d -weight %d",                  sprintf(buf, "-minsize %d -pad %d -weight %d",
773                          slotPtr[slot].minSize,slotPtr[slot].pad,                          slotPtr[slot].minSize,slotPtr[slot].pad,
774                          slotPtr[slot].weight);                          slotPtr[slot].weight);
775                  Tcl_SetResult(interp, buf, TCL_VOLATILE);                  Tcl_SetResult(interp, buf, TCL_VOLATILE);
776                  return (TCL_OK);                  return (TCL_OK);
777              } else if (argc == 4) {              } else if (argc == 4) {
778                  Tcl_SetResult(interp, "-minsize 0 -pad 0 -weight 0",                  Tcl_SetResult(interp, "-minsize 0 -pad 0 -weight 0",
779                          TCL_STATIC);                          TCL_STATIC);
780                  return (TCL_OK);                  return (TCL_OK);
781              }              }
782    
783              /*              /*
784               * Loop through each option value pair, setting the values as required.               * Loop through each option value pair, setting the values as required.
785               * If only one option is given, with no value, the current value is               * If only one option is given, with no value, the current value is
786               * returned.               * returned.
787               */               */
788    
789              for (i=4; i<argc; i+=2) {              for (i=4; i<argc; i+=2) {
790                  length = strlen(argv[i]);                  length = strlen(argv[i]);
791                  if ((*argv[i] != '-') || length < 2) {                  if ((*argv[i] != '-') || length < 2) {
792                      Tcl_AppendResult(interp, "invalid arg \"",                      Tcl_AppendResult(interp, "invalid arg \"",
793                              argv[i], "\" :expecting -minsize, -pad, or -weight.",                              argv[i], "\" :expecting -minsize, -pad, or -weight.",
794                              (char *) NULL);                              (char *) NULL);
795                      Tcl_Free((char *)argvPtr);                      Tcl_Free((char *)argvPtr);
796                      return TCL_ERROR;                      return TCL_ERROR;
797                  }                  }
798                  if (strncmp(argv[i], "-minsize", length) == 0) {                  if (strncmp(argv[i], "-minsize", length) == 0) {
799                      if (argc == 5) {                      if (argc == 5) {
800                          char buf[TCL_INTEGER_SPACE];                          char buf[TCL_INTEGER_SPACE];
801                          int value;                          int value;
802    
803                          value = (ok == TCL_OK) ? slotPtr[slot].minSize : 0;                          value = (ok == TCL_OK) ? slotPtr[slot].minSize : 0;
804                          sprintf(buf, "%d", value);                          sprintf(buf, "%d", value);
805                          Tcl_SetResult(interp, buf, TCL_VOLATILE);                          Tcl_SetResult(interp, buf, TCL_VOLATILE);
806                      } else if (Tk_GetPixels(interp, master, argv[i+1], &size)                      } else if (Tk_GetPixels(interp, master, argv[i+1], &size)
807                              != TCL_OK) {                              != TCL_OK) {
808                          Tcl_Free((char *)argvPtr);                          Tcl_Free((char *)argvPtr);
809                          return TCL_ERROR;                          return TCL_ERROR;
810                      } else {                      } else {
811                          slotPtr[slot].minSize = size;                          slotPtr[slot].minSize = size;
812                      }                      }
813                  }                  }
814                  else if (strncmp(argv[i], "-weight", length) == 0) {                  else if (strncmp(argv[i], "-weight", length) == 0) {
815                      int wt;                      int wt;
816                      if (argc == 5) {                      if (argc == 5) {
817                          char buf[TCL_INTEGER_SPACE];                          char buf[TCL_INTEGER_SPACE];
818                          int value;                          int value;
819    
820                          value = (ok == TCL_OK) ? slotPtr[slot].weight : 0;                          value = (ok == TCL_OK) ? slotPtr[slot].weight : 0;
821                          sprintf(buf, "%d", value);                          sprintf(buf, "%d", value);
822                          Tcl_SetResult(interp, buf, TCL_VOLATILE);                          Tcl_SetResult(interp, buf, TCL_VOLATILE);
823                      } else if (Tcl_GetInt(interp, argv[i+1], &wt) != TCL_OK) {                      } else if (Tcl_GetInt(interp, argv[i+1], &wt) != TCL_OK) {
824                          Tcl_Free((char *)argvPtr);                          Tcl_Free((char *)argvPtr);
825                          return TCL_ERROR;                          return TCL_ERROR;
826                      } else if (wt < 0) {                      } else if (wt < 0) {
827                          Tcl_AppendResult(interp, "invalid arg \"", argv[i],                          Tcl_AppendResult(interp, "invalid arg \"", argv[i],
828                                  "\": should be non-negative", (char *) NULL);                                  "\": should be non-negative", (char *) NULL);
829                          Tcl_Free((char *)argvPtr);                          Tcl_Free((char *)argvPtr);
830                          return TCL_ERROR;                          return TCL_ERROR;
831                      } else {                      } else {
832                          slotPtr[slot].weight = wt;                          slotPtr[slot].weight = wt;
833                      }                      }
834                  }                  }
835                  else if (strncmp(argv[i], "-pad", length) == 0) {                  else if (strncmp(argv[i], "-pad", length) == 0) {
836                      if (argc == 5) {                      if (argc == 5) {
837                          char buf[TCL_INTEGER_SPACE];                          char buf[TCL_INTEGER_SPACE];
838                          int value;                          int value;
839    
840                          value = (ok == TCL_OK) ? slotPtr[slot].pad : 0;                          value = (ok == TCL_OK) ? slotPtr[slot].pad : 0;
841                          sprintf(buf, "%d", value);                          sprintf(buf, "%d", value);
842                          Tcl_SetResult(interp, buf, TCL_VOLATILE);                          Tcl_SetResult(interp, buf, TCL_VOLATILE);
843                      } else if (Tk_GetPixels(interp, master, argv[i+1], &size)                      } else if (Tk_GetPixels(interp, master, argv[i+1], &size)
844                              != TCL_OK) {                              != TCL_OK) {
845                          Tcl_Free((char *)argvPtr);                          Tcl_Free((char *)argvPtr);
846                          return TCL_ERROR;                          return TCL_ERROR;
847                      } else if (size < 0) {                      } else if (size < 0) {
848                          Tcl_AppendResult(interp, "invalid arg \"", argv[i],                          Tcl_AppendResult(interp, "invalid arg \"", argv[i],
849                                  "\": should be non-negative", (char *) NULL);                                  "\": should be non-negative", (char *) NULL);
850                          Tcl_Free((char *)argvPtr);                          Tcl_Free((char *)argvPtr);
851                          return TCL_ERROR;                          return TCL_ERROR;
852                      } else {                      } else {
853                          slotPtr[slot].pad = size;                          slotPtr[slot].pad = size;
854                      }                      }
855                  } else {                  } else {
856                      Tcl_AppendResult(interp, "invalid arg \"",                      Tcl_AppendResult(interp, "invalid arg \"",
857                              argv[i], "\": expecting -minsize, -pad, or -weight.",                              argv[i], "\": expecting -minsize, -pad, or -weight.",
858                              (char *) NULL);                              (char *) NULL);
859                      Tcl_Free((char *)argvPtr);                      Tcl_Free((char *)argvPtr);
860                      return TCL_ERROR;                      return TCL_ERROR;
861                  }                  }
862              }              }
863          }          }
864          Tcl_Free((char *)argvPtr);          Tcl_Free((char *)argvPtr);
865    
866          /*          /*
867           * If we changed a property, re-arrange the table,           * If we changed a property, re-arrange the table,
868           * and check for constraint shrinkage.           * and check for constraint shrinkage.
869           */           */
870    
871          if (argc != 5) {          if (argc != 5) {
872              if (slotType == ROW) {              if (slotType == ROW) {
873                  int last = masterPtr->masterDataPtr->rowMax - 1;                  int last = masterPtr->masterDataPtr->rowMax - 1;
874                  while ((last >= 0) && (slotPtr[last].weight == 0)                  while ((last >= 0) && (slotPtr[last].weight == 0)
875                          && (slotPtr[last].pad == 0)                          && (slotPtr[last].pad == 0)
876                          && (slotPtr[last].minSize == 0)) {                          && (slotPtr[last].minSize == 0)) {
877                      last--;                      last--;
878                  }                  }
879                  masterPtr->masterDataPtr->rowMax = last+1;                  masterPtr->masterDataPtr->rowMax = last+1;
880              } else {              } else {
881                  int last = masterPtr->masterDataPtr->columnMax - 1;                  int last = masterPtr->masterDataPtr->columnMax - 1;
882                  while ((last >= 0) && (slotPtr[last].weight == 0)                  while ((last >= 0) && (slotPtr[last].weight == 0)
883                          && (slotPtr[last].pad == 0)                          && (slotPtr[last].pad == 0)
884                          && (slotPtr[last].minSize == 0)) {                          && (slotPtr[last].minSize == 0)) {
885                      last--;                      last--;
886                  }                  }
887                  masterPtr->masterDataPtr->columnMax = last + 1;                  masterPtr->masterDataPtr->columnMax = last + 1;
888              }              }
889    
890              if (masterPtr->abortPtr != NULL) {              if (masterPtr->abortPtr != NULL) {
891                  *masterPtr->abortPtr = 1;                  *masterPtr->abortPtr = 1;
892              }              }
893              if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {              if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
894                  masterPtr->flags |= REQUESTED_RELAYOUT;                  masterPtr->flags |= REQUESTED_RELAYOUT;
895                  Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);                  Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
896              }              }
897          }          }
898      } else {      } else {
899          Tcl_AppendResult(interp, "bad option \"", argv[1],          Tcl_AppendResult(interp, "bad option \"", argv[1],
900                  "\":  must be bbox, columnconfigure, configure, forget, info, ",                  "\":  must be bbox, columnconfigure, configure, forget, info, ",
901                  "location, propagate, remove, rowconfigure, size, or slaves.",                  "location, propagate, remove, rowconfigure, size, or slaves.",
902                  (char *) NULL);                  (char *) NULL);
903          return TCL_ERROR;          return TCL_ERROR;
904      }      }
905      return TCL_OK;      return TCL_OK;
906  }  }
907    
908  /*  /*
909   *--------------------------------------------------------------   *--------------------------------------------------------------
910   *   *
911   * GridReqProc --   * GridReqProc --
912   *   *
913   *      This procedure is invoked by Tk_GeometryRequest for   *      This procedure is invoked by Tk_GeometryRequest for
914   *      windows managed by the grid.   *      windows managed by the grid.
915   *   *
916   * Results:   * Results:
917   *      None.   *      None.
918   *   *
919   * Side effects:   * Side effects:
920   *      Arranges for tkwin, and all its managed siblings, to   *      Arranges for tkwin, and all its managed siblings, to
921   *      be re-arranged at the next idle point.   *      be re-arranged at the next idle point.
922   *   *
923   *--------------------------------------------------------------   *--------------------------------------------------------------
924   */   */
925    
926  static void  static void
927  GridReqProc(clientData, tkwin)  GridReqProc(clientData, tkwin)
928      ClientData clientData;      /* Grid's information about      ClientData clientData;      /* Grid's information about
929                                   * window that got new preferred                                   * window that got new preferred
930                                   * geometry.  */                                   * geometry.  */
931      Tk_Window tkwin;            /* Other Tk-related information      Tk_Window tkwin;            /* Other Tk-related information
932                                   * about the window. */                                   * about the window. */
933  {  {
934      register Gridder *gridPtr = (Gridder *) clientData;      register Gridder *gridPtr = (Gridder *) clientData;
935    
936      gridPtr = gridPtr->masterPtr;      gridPtr = gridPtr->masterPtr;
937      if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {      if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
938          gridPtr->flags |= REQUESTED_RELAYOUT;          gridPtr->flags |= REQUESTED_RELAYOUT;
939          Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);          Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
940      }      }
941  }  }
942    
943  /*  /*
944   *--------------------------------------------------------------   *--------------------------------------------------------------
945   *   *
946   * GridLostSlaveProc --   * GridLostSlaveProc --
947   *   *
948   *      This procedure is invoked by Tk whenever some other geometry   *      This procedure is invoked by Tk whenever some other geometry
949   *      claims control over a slave that used to be managed by us.   *      claims control over a slave that used to be managed by us.
950   *   *
951   * Results:   * Results:
952   *      None.   *      None.
953   *   *
954   * Side effects:   * Side effects:
955   *      Forgets all grid-related information about the slave.   *      Forgets all grid-related information about the slave.
956   *   *
957   *--------------------------------------------------------------   *--------------------------------------------------------------
958   */   */
959    
960  static void  static void
961  GridLostSlaveProc(clientData, tkwin)  GridLostSlaveProc(clientData, tkwin)
962      ClientData clientData;      /* Grid structure for slave window that      ClientData clientData;      /* Grid structure for slave window that
963                                   * was stolen away. */                                   * was stolen away. */
964      Tk_Window tkwin;            /* Tk's handle for the slave window. */      Tk_Window tkwin;            /* Tk's handle for the slave window. */
965  {  {
966      register Gridder *slavePtr = (Gridder *) clientData;      register Gridder *slavePtr = (Gridder *) clientData;
967    
968      if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {      if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
969          Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);          Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);
970      }      }
971      Unlink(slavePtr);      Unlink(slavePtr);
972      Tk_UnmapWindow(slavePtr->tkwin);      Tk_UnmapWindow(slavePtr->tkwin);
973  }  }
974    
975  /*  /*
976   *--------------------------------------------------------------   *--------------------------------------------------------------
977   *   *
978   * AdjustOffsets --   * AdjustOffsets --
979   *   *
980   *      This procedure adjusts the size of the layout to fit in the   *      This procedure adjusts the size of the layout to fit in the
981   *      space provided.  If it needs more space, the extra is added   *      space provided.  If it needs more space, the extra is added
982   *      according to the weights.  If it needs less, the space is removed   *      according to the weights.  If it needs less, the space is removed
983   *      according to the weights, but at no time does the size drop below   *      according to the weights, but at no time does the size drop below
984   *      the minsize specified for that slot.   *      the minsize specified for that slot.
985   *   *
986   * Results:   * Results:
987   *      The initial offset of the layout,   *      The initial offset of the layout,
988   *      if all the weights are zero, else 0.   *      if all the weights are zero, else 0.
989   *   *
990   * Side effects:   * Side effects:
991   *      The slot offsets are modified to shrink the layout.   *      The slot offsets are modified to shrink the layout.
992   *   *
993   *--------------------------------------------------------------   *--------------------------------------------------------------
994   */   */
995    
996  static int  static int
997  AdjustOffsets(size, slots, slotPtr)  AdjustOffsets(size, slots, slotPtr)
998      int size;                   /* The total layout size (in pixels). */      int size;                   /* The total layout size (in pixels). */
999      int slots;                  /* Number of slots. */      int slots;                  /* Number of slots. */
1000      register SlotInfo *slotPtr; /* Pointer to slot array. */      register SlotInfo *slotPtr; /* Pointer to slot array. */
1001  {  {
1002      register int slot;          /* Current slot. */      register int slot;          /* Current slot. */
1003      int diff;                   /* Extra pixels needed to add to the layout. */      int diff;                   /* Extra pixels needed to add to the layout. */
1004      int totalWeight = 0;        /* Sum of the weights for all the slots. */      int totalWeight = 0;        /* Sum of the weights for all the slots. */
1005      int weight = 0;             /* Sum of the weights so far. */      int weight = 0;             /* Sum of the weights so far. */
1006      int minSize = 0;            /* Minimum possible layout size. */      int minSize = 0;            /* Minimum possible layout size. */
1007      int newDiff;                /* The most pixels that can be added on      int newDiff;                /* The most pixels that can be added on
1008                                   * the current pass. */                                   * the current pass. */
1009    
1010      diff = size - slotPtr[slots-1].offset;      diff = size - slotPtr[slots-1].offset;
1011    
1012      /*      /*
1013       * The layout is already the correct size; all done.       * The layout is already the correct size; all done.
1014       */       */
1015    
1016      if (diff == 0) {      if (diff == 0) {
1017          return(0);          return(0);
1018      }      }
1019    
1020      /*      /*
1021       * If all the weights are zero, center the layout in its parent if       * If all the weights are zero, center the layout in its parent if
1022       * there is extra space, else clip on the bottom/right.       * there is extra space, else clip on the bottom/right.
1023       */       */
1024    
1025      for (slot=0; slot < slots; slot++) {      for (slot=0; slot < slots; slot++) {
1026          totalWeight += slotPtr[slot].weight;          totalWeight += slotPtr[slot].weight;
1027      }      }
1028    
1029      if (totalWeight == 0 ) {      if (totalWeight == 0 ) {
1030          return(diff > 0 ? diff/2 : 0);          return(diff > 0 ? diff/2 : 0);
1031      }      }
1032    
1033      /*      /*
1034       * Add extra space according to the slot weights.  This is done       * Add extra space according to the slot weights.  This is done
1035       * cumulatively to prevent round-off error accumulation.       * cumulatively to prevent round-off error accumulation.
1036       */       */
1037    
1038      if (diff > 0) {      if (diff > 0) {
1039          for (weight=slot=0; slot < slots; slot++) {          for (weight=slot=0; slot < slots; slot++) {
1040              weight += slotPtr[slot].weight;              weight += slotPtr[slot].weight;
1041              slotPtr[slot].offset += diff * weight / totalWeight;              slotPtr[slot].offset += diff * weight / totalWeight;
1042          }          }
1043          return(0);          return(0);
1044      }      }
1045    
1046      /*      /*
1047       * The layout must shrink below its requested size.  Compute the       * The layout must shrink below its requested size.  Compute the
1048       * minimum possible size by looking at the slot minSizes.       * minimum possible size by looking at the slot minSizes.
1049       */       */
1050    
1051      for (slot=0; slot < slots; slot++) {      for (slot=0; slot < slots; slot++) {
1052          if (slotPtr[slot].weight > 0) {          if (slotPtr[slot].weight > 0) {
1053              minSize += slotPtr[slot].minSize;              minSize += slotPtr[slot].minSize;
1054          } else if (slot > 0) {          } else if (slot > 0) {
1055              minSize += slotPtr[slot].offset - slotPtr[slot-1].offset;              minSize += slotPtr[slot].offset - slotPtr[slot-1].offset;
1056          } else {          } else {
1057              minSize += slotPtr[slot].offset;              minSize += slotPtr[slot].offset;
1058          }          }
1059      }      }
1060    
1061      /*      /*
1062       * If the requested size is less than the minimum required size,       * If the requested size is less than the minimum required size,
1063       * set the slot sizes to their minimum values, then clip on the       * set the slot sizes to their minimum values, then clip on the
1064       * bottom/right.       * bottom/right.
1065       */       */
1066    
1067      if (size <= minSize) {      if (size <= minSize) {
1068          int offset = 0;          int offset = 0;
1069          for (slot=0; slot < slots; slot++) {          for (slot=0; slot < slots; slot++) {
1070              if (slotPtr[slot].weight > 0) {              if (slotPtr[slot].weight > 0) {
1071                  offset += slotPtr[slot].minSize;                  offset += slotPtr[slot].minSize;
1072              } else if (slot > 0) {              } else if (slot > 0) {
1073                  offset += slotPtr[slot].offset - slotPtr[slot-1].offset;                  offset += slotPtr[slot].offset - slotPtr[slot-1].offset;
1074              } else {              } else {
1075                  offset += slotPtr[slot].offset;                  offset += slotPtr[slot].offset;
1076              }              }
1077              slotPtr[slot].offset = offset;              slotPtr[slot].offset = offset;
1078          }          }
1079          return(0);          return(0);
1080      }      }
1081    
1082      /*      /*
1083       * Remove space from slots according to their weights.  The weights       * Remove space from slots according to their weights.  The weights
1084       * get renormalized anytime a slot shrinks to its minimum size.       * get renormalized anytime a slot shrinks to its minimum size.
1085       */       */
1086    
1087      while (diff < 0) {      while (diff < 0) {
1088    
1089          /*          /*
1090           * Find the total weight for the shrinkable slots.           * Find the total weight for the shrinkable slots.
1091           */           */
1092    
1093          for (totalWeight=slot=0; slot < slots; slot++) {          for (totalWeight=slot=0; slot < slots; slot++) {
1094              int current = (slot == 0) ? slotPtr[slot].offset :              int current = (slot == 0) ? slotPtr[slot].offset :
1095                      slotPtr[slot].offset - slotPtr[slot-1].offset;                      slotPtr[slot].offset - slotPtr[slot-1].offset;
1096              if (current > slotPtr[slot].minSize) {              if (current > slotPtr[slot].minSize) {
1097                  totalWeight += slotPtr[slot].weight;                  totalWeight += slotPtr[slot].weight;
1098                  slotPtr[slot].temp = slotPtr[slot].weight;                  slotPtr[slot].temp = slotPtr[slot].weight;
1099              } else {              } else {
1100                  slotPtr[slot].temp = 0;                  slotPtr[slot].temp = 0;
1101              }              }
1102          }          }
1103          if (totalWeight == 0) {          if (totalWeight == 0) {
1104              break;              break;
1105          }          }
1106    
1107          /*          /*
1108           * Find the maximum amount of space we can distribute this pass.           * Find the maximum amount of space we can distribute this pass.
1109           */           */
1110    
1111          newDiff = diff;          newDiff = diff;
1112          for (slot = 0; slot < slots; slot++) {          for (slot = 0; slot < slots; slot++) {
1113              int current;                /* current size of this slot */              int current;                /* current size of this slot */
1114              int maxDiff;                /* max diff that would cause              int maxDiff;                /* max diff that would cause
1115                                           * this slot to equal its minsize */                                           * this slot to equal its minsize */
1116              if (slotPtr[slot].temp == 0) {              if (slotPtr[slot].temp == 0) {
1117                  continue;                  continue;
1118              }              }
1119              current = (slot == 0) ? slotPtr[slot].offset :              current = (slot == 0) ? slotPtr[slot].offset :
1120                      slotPtr[slot].offset - slotPtr[slot-1].offset;                      slotPtr[slot].offset - slotPtr[slot-1].offset;
1121              maxDiff = totalWeight * (slotPtr[slot].minSize - current)              maxDiff = totalWeight * (slotPtr[slot].minSize - current)
1122                      / slotPtr[slot].temp;                      / slotPtr[slot].temp;
1123              if (maxDiff > newDiff) {              if (maxDiff > newDiff) {
1124                  newDiff = maxDiff;                  newDiff = maxDiff;
1125              }              }
1126          }          }
1127    
1128          /*          /*
1129           * Now distribute the space.           * Now distribute the space.
1130           */           */
1131    
1132          for (weight=slot=0; slot < slots; slot++) {          for (weight=slot=0; slot < slots; slot++) {
1133              weight += slotPtr[slot].temp;              weight += slotPtr[slot].temp;
1134              slotPtr[slot].offset += newDiff * weight / totalWeight;              slotPtr[slot].offset += newDiff * weight / totalWeight;
1135          }          }
1136          diff -= newDiff;          diff -= newDiff;
1137      }      }
1138      return(0);      return(0);
1139  }  }
1140    
1141  /*  /*
1142   *--------------------------------------------------------------   *--------------------------------------------------------------
1143   *   *
1144   * AdjustForSticky --   * AdjustForSticky --
1145   *   *
1146   *      This procedure adjusts the size of a slave in its cavity based   *      This procedure adjusts the size of a slave in its cavity based
1147   *      on its "sticky" flags.   *      on its "sticky" flags.
1148   *   *
1149   * Results:   * Results:
1150   *      The input x, y, width, and height are changed to represent the   *      The input x, y, width, and height are changed to represent the
1151   *      desired coordinates of the slave.   *      desired coordinates of the slave.
1152   *   *
1153   * Side effects:   * Side effects:
1154   *      None.   *      None.
1155   *   *
1156   *--------------------------------------------------------------   *--------------------------------------------------------------
1157   */   */
1158    
1159  static void  static void
1160  AdjustForSticky(slavePtr, xPtr, yPtr, widthPtr, heightPtr)  AdjustForSticky(slavePtr, xPtr, yPtr, widthPtr, heightPtr)
1161      Gridder *slavePtr;  /* Slave window to arrange in its cavity. */      Gridder *slavePtr;  /* Slave window to arrange in its cavity. */
1162      int *xPtr;          /* Pixel location of the left edge of the cavity. */      int *xPtr;          /* Pixel location of the left edge of the cavity. */
1163      int *yPtr;          /* Pixel location of the top edge of the cavity. */      int *yPtr;          /* Pixel location of the top edge of the cavity. */
1164      int *widthPtr;      /* Width of the cavity (in pixels). */      int *widthPtr;      /* Width of the cavity (in pixels). */
1165      int *heightPtr;     /* Height of the cavity (in pixels). */      int *heightPtr;     /* Height of the cavity (in pixels). */
1166  {  {
1167      int diffx=0;        /* Cavity width - slave width. */      int diffx=0;        /* Cavity width - slave width. */
1168      int diffy=0;        /* Cavity hight - slave height. */      int diffy=0;        /* Cavity hight - slave height. */
1169      int sticky = slavePtr->sticky;      int sticky = slavePtr->sticky;
1170    
1171      *xPtr += slavePtr->padX/2;      *xPtr += slavePtr->padX/2;
1172      *widthPtr -= slavePtr->padX;      *widthPtr -= slavePtr->padX;
1173      *yPtr += slavePtr->padY/2;      *yPtr += slavePtr->padY/2;
1174      *heightPtr -= slavePtr->padY;      *heightPtr -= slavePtr->padY;
1175    
1176      if (*widthPtr > (Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX)) {      if (*widthPtr > (Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX)) {
1177          diffx = *widthPtr - (Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX);          diffx = *widthPtr - (Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX);
1178          *widthPtr = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX;          *widthPtr = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX;
1179      }      }
1180    
1181      if (*heightPtr > (Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY)) {      if (*heightPtr > (Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY)) {
1182          diffy = *heightPtr - (Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY);          diffy = *heightPtr - (Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY);
1183          *heightPtr = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY;          *heightPtr = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY;
1184      }      }
1185    
1186      if (sticky&STICK_EAST && sticky&STICK_WEST) {      if (sticky&STICK_EAST && sticky&STICK_WEST) {
1187          *widthPtr += diffx;          *widthPtr += diffx;
1188      }      }
1189      if (sticky&STICK_NORTH && sticky&STICK_SOUTH) {      if (sticky&STICK_NORTH && sticky&STICK_SOUTH) {
1190          *heightPtr += diffy;          *heightPtr += diffy;
1191      }      }
1192      if (!(sticky&STICK_WEST)) {      if (!(sticky&STICK_WEST)) {
1193          *xPtr += (sticky&STICK_EAST) ? diffx : diffx/2;          *xPtr += (sticky&STICK_EAST) ? diffx : diffx/2;
1194      }      }
1195      if (!(sticky&STICK_NORTH)) {      if (!(sticky&STICK_NORTH)) {
1196          *yPtr += (sticky&STICK_SOUTH) ? diffy : diffy/2;          *yPtr += (sticky&STICK_SOUTH) ? diffy : diffy/2;
1197      }      }
1198  }  }
1199    
1200  /*  /*
1201   *--------------------------------------------------------------   *--------------------------------------------------------------
1202   *   *
1203   * ArrangeGrid --   * ArrangeGrid --
1204   *   *
1205   *      This procedure is invoked (using the Tcl_DoWhenIdle   *      This procedure is invoked (using the Tcl_DoWhenIdle
1206   *      mechanism) to re-layout a set of windows managed by   *      mechanism) to re-layout a set of windows managed by
1207   *      the grid.  It is invoked at idle time so that a   *      the grid.  It is invoked at idle time so that a
1208   *      series of grid requests can be merged into a single   *      series of grid requests can be merged into a single
1209   *      layout operation.   *      layout operation.
1210   *   *
1211   * Results:   * Results:
1212   *      None.   *      None.
1213   *   *
1214   * Side effects:   * Side effects:
1215   *      The slaves of masterPtr may get resized or moved.   *      The slaves of masterPtr may get resized or moved.
1216   *   *
1217   *--------------------------------------------------------------   *--------------------------------------------------------------
1218   */   */
1219    
1220  static void  static void
1221  ArrangeGrid(clientData)  ArrangeGrid(clientData)
1222      ClientData clientData;      /* Structure describing parent whose slaves      ClientData clientData;      /* Structure describing parent whose slaves
1223                                   * are to be re-layed out. */                                   * are to be re-layed out. */
1224  {  {
1225      register Gridder *masterPtr = (Gridder *) clientData;      register Gridder *masterPtr = (Gridder *) clientData;
1226      register Gridder *slavePtr;      register Gridder *slavePtr;
1227      GridMaster *slotPtr = masterPtr->masterDataPtr;      GridMaster *slotPtr = masterPtr->masterDataPtr;
1228      int abort;      int abort;
1229      int width, height;          /* requested size of layout, in pixels */      int width, height;          /* requested size of layout, in pixels */
1230      int realWidth, realHeight;  /* actual size layout should take-up */      int realWidth, realHeight;  /* actual size layout should take-up */
1231    
1232      masterPtr->flags &= ~REQUESTED_RELAYOUT;      masterPtr->flags &= ~REQUESTED_RELAYOUT;
1233    
1234      /*      /*
1235       * If the parent has no slaves anymore, then don't do anything       * If the parent has no slaves anymore, then don't do anything
1236       * at all:  just leave the parent's size as-is.  Otherwise there is       * at all:  just leave the parent's size as-is.  Otherwise there is
1237       * no way to "relinquish" control over the parent so another geometry       * no way to "relinquish" control over the parent so another geometry
1238       * manager can take over.       * manager can take over.
1239       */       */
1240    
1241      if (masterPtr->slavePtr == NULL) {      if (masterPtr->slavePtr == NULL) {
1242          return;          return;
1243      }      }
1244    
1245      if (masterPtr->masterDataPtr == NULL) {      if (masterPtr->masterDataPtr == NULL) {
1246          return;          return;
1247      }      }
1248    
1249      /*      /*
1250       * Abort any nested call to ArrangeGrid for this window, since       * Abort any nested call to ArrangeGrid for this window, since
1251       * we'll do everything necessary here, and set up so this call       * we'll do everything necessary here, and set up so this call
1252       * can be aborted if necessary.         * can be aborted if necessary.  
1253       */       */
1254    
1255      if (masterPtr->abortPtr != NULL) {      if (masterPtr->abortPtr != NULL) {
1256          *masterPtr->abortPtr = 1;          *masterPtr->abortPtr = 1;
1257      }      }
1258      masterPtr->abortPtr = &abort;      masterPtr->abortPtr = &abort;
1259      abort = 0;      abort = 0;
1260      Tcl_Preserve((ClientData) masterPtr);      Tcl_Preserve((ClientData) masterPtr);
1261    
1262      /*      /*
1263       * Call the constraint engine to fill in the row and column offsets.       * Call the constraint engine to fill in the row and column offsets.
1264       */       */
1265    
1266      SetGridSize(masterPtr);      SetGridSize(masterPtr);
1267      width =  ResolveConstraints(masterPtr, COLUMN, 0);      width =  ResolveConstraints(masterPtr, COLUMN, 0);
1268      height = ResolveConstraints(masterPtr, ROW, 0);      height = ResolveConstraints(masterPtr, ROW, 0);
1269      width += 2*Tk_InternalBorderWidth(masterPtr->tkwin);      width += 2*Tk_InternalBorderWidth(masterPtr->tkwin);
1270      height += 2*Tk_InternalBorderWidth(masterPtr->tkwin);      height += 2*Tk_InternalBorderWidth(masterPtr->tkwin);
1271    
1272      if (((width != Tk_ReqWidth(masterPtr->tkwin))      if (((width != Tk_ReqWidth(masterPtr->tkwin))
1273              || (height != Tk_ReqHeight(masterPtr->tkwin)))              || (height != Tk_ReqHeight(masterPtr->tkwin)))
1274              && !(masterPtr->flags & DONT_PROPAGATE)) {              && !(masterPtr->flags & DONT_PROPAGATE)) {
1275          Tk_GeometryRequest(masterPtr->tkwin, width, height);          Tk_GeometryRequest(masterPtr->tkwin, width, height);
1276          if (width>1 && height>1) {          if (width>1 && height>1) {
1277              masterPtr->flags |= REQUESTED_RELAYOUT;              masterPtr->flags |= REQUESTED_RELAYOUT;
1278              Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);              Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
1279          }          }
1280          masterPtr->abortPtr = NULL;          masterPtr->abortPtr = NULL;
1281          Tcl_Release((ClientData) masterPtr);          Tcl_Release((ClientData) masterPtr);
1282          return;          return;
1283      }      }
1284    
1285      /*      /*
1286       * If the currently requested layout size doesn't match the parent's       * If the currently requested layout size doesn't match the parent's
1287       * window size, then adjust the slot offsets according to the       * window size, then adjust the slot offsets according to the
1288       * weights.  If all of the weights are zero, center the layout in       * weights.  If all of the weights are zero, center the layout in
1289       * its parent.  I haven't decided what to do if the parent is smaller       * its parent.  I haven't decided what to do if the parent is smaller
1290       * than the requested size.       * than the requested size.
1291       */       */
1292    
1293      realWidth = Tk_Width(masterPtr->tkwin) -      realWidth = Tk_Width(masterPtr->tkwin) -
1294              2*Tk_InternalBorderWidth(masterPtr->tkwin);              2*Tk_InternalBorderWidth(masterPtr->tkwin);
1295      realHeight = Tk_Height(masterPtr->tkwin) -      realHeight = Tk_Height(masterPtr->tkwin) -
1296              2*Tk_InternalBorderWidth(masterPtr->tkwin);              2*Tk_InternalBorderWidth(masterPtr->tkwin);
1297      slotPtr->startX = AdjustOffsets(realWidth,      slotPtr->startX = AdjustOffsets(realWidth,
1298              MAX(slotPtr->columnEnd,slotPtr->columnMax), slotPtr->columnPtr);              MAX(slotPtr->columnEnd,slotPtr->columnMax), slotPtr->columnPtr);
1299      slotPtr->startY = AdjustOffsets(realHeight,      slotPtr->startY = AdjustOffsets(realHeight,
1300              MAX(slotPtr->rowEnd,slotPtr->rowMax), slotPtr->rowPtr);              MAX(slotPtr->rowEnd,slotPtr->rowMax), slotPtr->rowPtr);
1301      slotPtr->startX += Tk_InternalBorderWidth(masterPtr->tkwin);      slotPtr->startX += Tk_InternalBorderWidth(masterPtr->tkwin);
1302      slotPtr->startY += Tk_InternalBorderWidth(masterPtr->tkwin);      slotPtr->startY += Tk_InternalBorderWidth(masterPtr->tkwin);
1303    
1304      /*      /*
1305       * Now adjust the actual size of the slave to its cavity by       * Now adjust the actual size of the slave to its cavity by
1306       * computing the cavity size, and adjusting the widget according       * computing the cavity size, and adjusting the widget according
1307       * to its stickyness.       * to its stickyness.
1308       */       */
1309    
1310      for (slavePtr = masterPtr->slavePtr; slavePtr != NULL && !abort;      for (slavePtr = masterPtr->slavePtr; slavePtr != NULL && !abort;
1311              slavePtr = slavePtr->nextPtr) {              slavePtr = slavePtr->nextPtr) {
1312          int x, y;                       /* top left coordinate */          int x, y;                       /* top left coordinate */
1313          int width, height;              /* slot or slave size */          int width, height;              /* slot or slave size */
1314          int col = slavePtr->column;          int col = slavePtr->column;
1315          int row = slavePtr->row;          int row = slavePtr->row;
1316    
1317          x = (col>0) ? slotPtr->columnPtr[col-1].offset : 0;          x = (col>0) ? slotPtr->columnPtr[col-1].offset : 0;
1318          y = (row>0) ? slotPtr->rowPtr[row-1].offset : 0;          y = (row>0) ? slotPtr->rowPtr[row-1].offset : 0;
1319    
1320          width = slotPtr->columnPtr[slavePtr->numCols+col-1].offset - x;          width = slotPtr->columnPtr[slavePtr->numCols+col-1].offset - x;
1321          height = slotPtr->rowPtr[slavePtr->numRows+row-1].offset - y;          height = slotPtr->rowPtr[slavePtr->numRows+row-1].offset - y;
1322    
1323          x += slotPtr->startX;          x += slotPtr->startX;
1324          y += slotPtr->startY;          y += slotPtr->startY;
1325    
1326          AdjustForSticky(slavePtr, &x, &y, &width, &height);          AdjustForSticky(slavePtr, &x, &y, &width, &height);
1327    
1328          /*          /*
1329           * Now put the window in the proper spot.  (This was taken directly           * Now put the window in the proper spot.  (This was taken directly
1330           * from tkPack.c.)  If the slave is a child of the master, then           * from tkPack.c.)  If the slave is a child of the master, then
1331           * do this here.  Otherwise let Tk_MaintainGeometry do the work.           * do this here.  Otherwise let Tk_MaintainGeometry do the work.
1332           */           */
1333    
1334          if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) {          if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) {
1335              if ((width <= 0) || (height <= 0)) {              if ((width <= 0) || (height <= 0)) {
1336                  Tk_UnmapWindow(slavePtr->tkwin);                  Tk_UnmapWindow(slavePtr->tkwin);
1337              } else {              } else {
1338                  if ((x != Tk_X(slavePtr->tkwin))                  if ((x != Tk_X(slavePtr->tkwin))
1339                          || (y != Tk_Y(slavePtr->tkwin))                          || (y != Tk_Y(slavePtr->tkwin))
1340                          || (width != Tk_Width(slavePtr->tkwin))                          || (width != Tk_Width(slavePtr->tkwin))
1341                          || (height != Tk_Height(slavePtr->tkwin))) {                          || (height != Tk_Height(slavePtr->tkwin))) {
1342                      Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);                      Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);
1343                  }                  }
1344                  if (abort) {                  if (abort) {
1345                      break;                      break;
1346                  }                  }
1347    
1348                  /*                  /*
1349                   * Don't map the slave if the master isn't mapped: wait                   * Don't map the slave if the master isn't mapped: wait
1350                   * until the master gets mapped later.                   * until the master gets mapped later.
1351                   */                   */
1352    
1353                  if (Tk_IsMapped(masterPtr->tkwin)) {                  if (Tk_IsMapped(masterPtr->tkwin)) {
1354                      Tk_MapWindow(slavePtr->tkwin);                      Tk_MapWindow(slavePtr->tkwin);
1355                  }                  }
1356              }              }
1357          } else {          } else {
1358              if ((width <= 0) || (height <= 0)) {              if ((width <= 0) || (height <= 0)) {
1359                  Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin);                  Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin);
1360                  Tk_UnmapWindow(slavePtr->tkwin);                  Tk_UnmapWindow(slavePtr->tkwin);
1361              } else {              } else {
1362                  Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin,                  Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin,
1363                          x, y, width, height);                          x, y, width, height);
1364              }              }
1365          }          }
1366      }      }
1367    
1368      masterPtr->abortPtr = NULL;      masterPtr->abortPtr = NULL;
1369      Tcl_Release((ClientData) masterPtr);      Tcl_Release((ClientData) masterPtr);
1370  }  }
1371    
1372  /*  /*
1373   *--------------------------------------------------------------   *--------------------------------------------------------------
1374   *   *
1375   * ResolveConstraints --   * ResolveConstraints --
1376   *   *
1377   *      Resolve all of the column and row boundaries.  Most of   *      Resolve all of the column and row boundaries.  Most of
1378   *      the calculations are identical for rows and columns, so this procedure   *      the calculations are identical for rows and columns, so this procedure
1379   *      is called twice, once for rows, and again for columns.   *      is called twice, once for rows, and again for columns.
1380   *   *
1381   * Results:   * Results:
1382   *      The offset (in pixels) from the left/top edge of this layout is   *      The offset (in pixels) from the left/top edge of this layout is
1383   *      returned.   *      returned.
1384   *   *
1385   * Side effects:   * Side effects:
1386   *      The slot offsets are copied into the SlotInfo structure for the   *      The slot offsets are copied into the SlotInfo structure for the
1387   *      geometry master.   *      geometry master.
1388   *   *
1389   *--------------------------------------------------------------   *--------------------------------------------------------------
1390   */   */
1391    
1392  static int  static int
1393  ResolveConstraints(masterPtr, slotType, maxOffset)  ResolveConstraints(masterPtr, slotType, maxOffset)
1394      Gridder *masterPtr;         /* The geometry master for this grid. */      Gridder *masterPtr;         /* The geometry master for this grid. */
1395      int slotType;               /* Either ROW or COLUMN. */      int slotType;               /* Either ROW or COLUMN. */
1396      int maxOffset;              /* The actual maximum size of this layout      int maxOffset;              /* The actual maximum size of this layout
1397                                   * in pixels,  or 0 (not currently used). */                                   * in pixels,  or 0 (not currently used). */
1398  {  {
1399      register SlotInfo *slotPtr; /* Pointer to row/col constraints. */      register SlotInfo *slotPtr; /* Pointer to row/col constraints. */
1400      register Gridder *slavePtr; /* List of slave windows in this grid. */      register Gridder *slavePtr; /* List of slave windows in this grid. */
1401      int constraintCount;        /* Count of rows or columns that have      int constraintCount;        /* Count of rows or columns that have
1402                                   * constraints. */                                   * constraints. */
1403      int slotCount;              /* Last occupied row or column. */      int slotCount;              /* Last occupied row or column. */
1404      int gridCount;              /* The larger of slotCount and constraintCount.      int gridCount;              /* The larger of slotCount and constraintCount.
1405                                   */                                   */
1406      GridLayout *layoutPtr;      /* Temporary layout structure. */      GridLayout *layoutPtr;      /* Temporary layout structure. */
1407      int requiredSize;           /* The natural size of the grid (pixels).      int requiredSize;           /* The natural size of the grid (pixels).
1408                                   * This is the minimum size needed to                                   * This is the minimum size needed to
1409                                   * accomodate all of the slaves at their                                   * accomodate all of the slaves at their
1410                                   * requested sizes. */                                   * requested sizes. */
1411      int offset;                 /* The pixel offset of the right edge of the      int offset;                 /* The pixel offset of the right edge of the
1412                                   * current slot from the beginning of the                                   * current slot from the beginning of the
1413                                   * layout. */                                   * layout. */
1414      int slot;                   /* The current slot. */      int slot;                   /* The current slot. */
1415      int start;                  /* The first slot of a contiguous set whose      int start;                  /* The first slot of a contiguous set whose
1416                                   * constraints are not yet fully resolved. */                                   * constraints are not yet fully resolved. */
1417      int end;                    /* The Last slot of a contiguous set whose      int end;                    /* The Last slot of a contiguous set whose
1418                                   * constraints are not yet fully resolved. */                                   * constraints are not yet fully resolved. */
1419    
1420      /*      /*
1421       * For typical sized tables, we'll use stack space for the layout data       * For typical sized tables, we'll use stack space for the layout data
1422       * to avoid the overhead of a malloc and free for every layout.       * to avoid the overhead of a malloc and free for every layout.
1423       */       */
1424    
1425      GridLayout layoutData[TYPICAL_SIZE + 1];      GridLayout layoutData[TYPICAL_SIZE + 1];
1426    
1427      if (slotType == COLUMN) {      if (slotType == COLUMN) {
1428          constraintCount = masterPtr->masterDataPtr->columnMax;          constraintCount = masterPtr->masterDataPtr->columnMax;
1429          slotCount = masterPtr->masterDataPtr->columnEnd;          slotCount = masterPtr->masterDataPtr->columnEnd;
1430          slotPtr  = masterPtr->masterDataPtr->columnPtr;          slotPtr  = masterPtr->masterDataPtr->columnPtr;
1431      } else {      } else {
1432          constraintCount = masterPtr->masterDataPtr->rowMax;          constraintCount = masterPtr->masterDataPtr->rowMax;
1433          slotCount = masterPtr->masterDataPtr->rowEnd;          slotCount = masterPtr->masterDataPtr->rowEnd;
1434          slotPtr  = masterPtr->masterDataPtr->rowPtr;          slotPtr  = masterPtr->masterDataPtr->rowPtr;
1435      }      }
1436    
1437      /*      /*
1438       * Make sure there is enough memory for the layout.       * Make sure there is enough memory for the layout.
1439       */       */
1440    
1441      gridCount = MAX(constraintCount,slotCount);      gridCount = MAX(constraintCount,slotCount);
1442      if (gridCount >= TYPICAL_SIZE) {      if (gridCount >= TYPICAL_SIZE) {
1443          layoutPtr = (GridLayout *) ckalloc(sizeof(GridLayout) * (1+gridCount));          layoutPtr = (GridLayout *) ckalloc(sizeof(GridLayout) * (1+gridCount));
1444      } else {      } else {
1445          layoutPtr = layoutData;          layoutPtr = layoutData;
1446      }      }
1447    
1448      /*      /*
1449       * Allocate an extra layout slot to represent the left/top edge of       * Allocate an extra layout slot to represent the left/top edge of
1450       * the 0th slot to make it easier to calculate slot widths from       * the 0th slot to make it easier to calculate slot widths from
1451       * offsets without special case code.       * offsets without special case code.
1452       * Initialize the "dummy" slot to the left/top of the table.       * Initialize the "dummy" slot to the left/top of the table.
1453       * This slot avoids special casing the first slot.       * This slot avoids special casing the first slot.
1454       */       */
1455    
1456      layoutPtr->minOffset = 0;      layoutPtr->minOffset = 0;
1457      layoutPtr->maxOffset = 0;      layoutPtr->maxOffset = 0;
1458      layoutPtr++;      layoutPtr++;
1459    
1460      /*      /*
1461       * Step 1.       * Step 1.
1462       * Copy the slot constraints into the layout structure,       * Copy the slot constraints into the layout structure,
1463       * and initialize the rest of the fields.       * and initialize the rest of the fields.
1464       */       */
1465    
1466      for (slot=0; slot < constraintCount; slot++) {      for (slot=0; slot < constraintCount; slot++) {
1467          layoutPtr[slot].minSize = slotPtr[slot].minSize;          layoutPtr[slot].minSize = slotPtr[slot].minSize;
1468          layoutPtr[slot].weight =  slotPtr[slot].weight;          layoutPtr[slot].weight =  slotPtr[slot].weight;
1469          layoutPtr[slot].pad =  slotPtr[slot].pad;          layoutPtr[slot].pad =  slotPtr[slot].pad;
1470          layoutPtr[slot].binNextPtr = NULL;          layoutPtr[slot].binNextPtr = NULL;
1471      }      }
1472      for(;slot<gridCount;slot++) {      for(;slot<gridCount;slot++) {
1473          layoutPtr[slot].minSize = 0;          layoutPtr[slot].minSize = 0;
1474          layoutPtr[slot].weight = 0;          layoutPtr[slot].weight = 0;
1475          layoutPtr[slot].pad = 0;          layoutPtr[slot].pad = 0;
1476          layoutPtr[slot].binNextPtr = NULL;          layoutPtr[slot].binNextPtr = NULL;
1477      }      }
1478    
1479      /*      /*
1480       * Step 2.       * Step 2.
1481       * Slaves with a span of 1 are used to determine the minimum size of       * Slaves with a span of 1 are used to determine the minimum size of
1482       * each slot.  Slaves whose span is two or more slots don't       * each slot.  Slaves whose span is two or more slots don't
1483       * contribute to the minimum size of each slot directly, but can cause       * contribute to the minimum size of each slot directly, but can cause
1484       * slots to grow if their size exceeds the the sizes of the slots they       * slots to grow if their size exceeds the the sizes of the slots they
1485       * span.       * span.
1486       *       *
1487       * Bin all slaves whose spans are > 1 by their right edges.  This       * Bin all slaves whose spans are > 1 by their right edges.  This
1488       * allows the computation on minimum and maximum possible layout       * allows the computation on minimum and maximum possible layout
1489       * sizes at each slot boundary, without the need to re-sort the slaves.       * sizes at each slot boundary, without the need to re-sort the slaves.
1490       */       */
1491    
1492      switch (slotType) {      switch (slotType) {
1493          case COLUMN:          case COLUMN:
1494              for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;              for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
1495                          slavePtr = slavePtr->nextPtr) {                          slavePtr = slavePtr->nextPtr) {
1496                  int rightEdge = slavePtr->column + slavePtr->numCols - 1;                  int rightEdge = slavePtr->column + slavePtr->numCols - 1;
1497                  slavePtr->size = Tk_ReqWidth(slavePtr->tkwin) +                  slavePtr->size = Tk_ReqWidth(slavePtr->tkwin) +
1498                          slavePtr->padX + slavePtr->iPadX + slavePtr->doubleBw;                          slavePtr->padX + slavePtr->iPadX + slavePtr->doubleBw;
1499                  if (slavePtr->numCols > 1) {                  if (slavePtr->numCols > 1) {
1500                      slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;                      slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
1501                      layoutPtr[rightEdge].binNextPtr = slavePtr;                      layoutPtr[rightEdge].binNextPtr = slavePtr;
1502                  } else {                  } else {
1503                      int size = slavePtr->size + layoutPtr[rightEdge].pad;                      int size = slavePtr->size + layoutPtr[rightEdge].pad;
1504                      if (size > layoutPtr[rightEdge].minSize) {                      if (size > layoutPtr[rightEdge].minSize) {
1505                          layoutPtr[rightEdge].minSize = size;                          layoutPtr[rightEdge].minSize = size;
1506                      }                      }
1507                  }                  }
1508              }              }
1509              break;              break;
1510          case ROW:          case ROW:
1511              for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;              for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
1512                          slavePtr = slavePtr->nextPtr) {                          slavePtr = slavePtr->nextPtr) {
1513                  int rightEdge = slavePtr->row + slavePtr->numRows - 1;                  int rightEdge = slavePtr->row + slavePtr->numRows - 1;
1514                  slavePtr->size = Tk_ReqHeight(slavePtr->tkwin) +                  slavePtr->size = Tk_ReqHeight(slavePtr->tkwin) +
1515                          slavePtr->padY + slavePtr->iPadY + slavePtr->doubleBw;                          slavePtr->padY + slavePtr->iPadY + slavePtr->doubleBw;
1516                  if (slavePtr->numRows > 1) {                  if (slavePtr->numRows > 1) {
1517                      slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;                      slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
1518                      layoutPtr[rightEdge].binNextPtr = slavePtr;                      layoutPtr[rightEdge].binNextPtr = slavePtr;
1519                  } else {                  } else {
1520                      int size = slavePtr->size + layoutPtr[rightEdge].pad;                      int size = slavePtr->size + layoutPtr[rightEdge].pad;
1521                      if (size > layoutPtr[rightEdge].minSize) {                      if (size > layoutPtr[rightEdge].minSize) {
1522                          layoutPtr[rightEdge].minSize = size;                          layoutPtr[rightEdge].minSize = size;
1523                      }                      }
1524                  }                  }
1525              }              }
1526              break;              break;
1527          }          }
1528    
1529      /*      /*
1530       * Step 3.       * Step 3.
1531       * Determine the minimum slot offsets going from left to right       * Determine the minimum slot offsets going from left to right
1532       * that would fit all of the slaves.  This determines the minimum       * that would fit all of the slaves.  This determines the minimum
1533       */       */
1534    
1535      for (offset=slot=0; slot < gridCount; slot++) {      for (offset=slot=0; slot < gridCount; slot++) {
1536          layoutPtr[slot].minOffset = layoutPtr[slot].minSize + offset;          layoutPtr[slot].minOffset = layoutPtr[slot].minSize + offset;
1537          for (slavePtr = layoutPtr[slot].binNextPtr; slavePtr != NULL;          for (slavePtr = layoutPtr[slot].binNextPtr; slavePtr != NULL;
1538                      slavePtr = slavePtr->binNextPtr) {                      slavePtr = slavePtr->binNextPtr) {
1539              int span = (slotType == COLUMN) ? slavePtr->numCols : slavePtr->numRows;              int span = (slotType == COLUMN) ? slavePtr->numCols : slavePtr->numRows;
1540              int required = slavePtr->size + layoutPtr[slot - span].minOffset;              int required = slavePtr->size + layoutPtr[slot - span].minOffset;
1541              if (required > layoutPtr[slot].minOffset) {              if (required > layoutPtr[slot].minOffset) {
1542                  layoutPtr[slot].minOffset = required;                  layoutPtr[slot].minOffset = required;
1543              }              }
1544          }          }
1545          offset = layoutPtr[slot].minOffset;          offset = layoutPtr[slot].minOffset;
1546      }      }
1547    
1548      /*      /*
1549       * At this point, we know the minimum required size of the entire layout.       * At this point, we know the minimum required size of the entire layout.
1550       * It might be prudent to stop here if our "master" will resize itself       * It might be prudent to stop here if our "master" will resize itself
1551       * to this size.       * to this size.
1552       */       */
1553    
1554      requiredSize = offset;      requiredSize = offset;
1555      if (maxOffset > offset) {      if (maxOffset > offset) {
1556          offset=maxOffset;          offset=maxOffset;
1557      }      }
1558    
1559      /*      /*
1560       * Step 4.       * Step 4.
1561       * Determine the minimum slot offsets going from right to left,       * Determine the minimum slot offsets going from right to left,
1562       * bounding the pixel range of each slot boundary.       * bounding the pixel range of each slot boundary.
1563       * Pre-fill all of the right offsets with the actual size of the table;       * Pre-fill all of the right offsets with the actual size of the table;
1564       * they will be reduced as required.       * they will be reduced as required.
1565       */       */
1566    
1567      for (slot=0; slot < gridCount; slot++) {      for (slot=0; slot < gridCount; slot++) {
1568          layoutPtr[slot].maxOffset = offset;          layoutPtr[slot].maxOffset = offset;
1569      }      }
1570      for (slot=gridCount-1; slot > 0;) {      for (slot=gridCount-1; slot > 0;) {
1571          for (slavePtr = layoutPtr[slot].binNextPtr; slavePtr != NULL;          for (slavePtr = layoutPtr[slot].binNextPtr; slavePtr != NULL;
1572                      slavePtr = slavePtr->binNextPtr) {                      slavePtr = slavePtr->binNextPtr) {
1573              int span = (slotType == COLUMN) ? slavePtr->numCols : slavePtr->numRows;              int span = (slotType == COLUMN) ? slavePtr->numCols : slavePtr->numRows;
1574              int require = offset - slavePtr->size;              int require = offset - slavePtr->size;
1575              int startSlot  = slot - span;              int startSlot  = slot - span;
1576              if (startSlot >=0 && require < layoutPtr[startSlot].maxOffset) {              if (startSlot >=0 && require < layoutPtr[startSlot].maxOffset) {
1577                  layoutPtr[startSlot].maxOffset = require;                  layoutPtr[startSlot].maxOffset = require;
1578              }              }
1579          }          }
1580          offset -= layoutPtr[slot].minSize;          offset -= layoutPtr[slot].minSize;
1581          slot--;          slot--;
1582          if (layoutPtr[slot].maxOffset < offset) {          if (layoutPtr[slot].maxOffset < offset) {
1583              offset = layoutPtr[slot].maxOffset;              offset = layoutPtr[slot].maxOffset;
1584          } else {          } else {
1585              layoutPtr[slot].maxOffset = offset;              layoutPtr[slot].maxOffset = offset;
1586          }          }
1587      }      }
1588    
1589      /*      /*
1590       * Step 5.       * Step 5.
1591       * At this point, each slot boundary has a range of values that       * At this point, each slot boundary has a range of values that
1592       * will satisfy the overall layout size.       * will satisfy the overall layout size.
1593       * Make repeated passes over the layout structure looking for       * Make repeated passes over the layout structure looking for
1594       * spans of slot boundaries where the minOffsets are less than       * spans of slot boundaries where the minOffsets are less than
1595       * the maxOffsets, and adjust the offsets according to the slot       * the maxOffsets, and adjust the offsets according to the slot
1596       * weights.  At each pass, at least one slot boundary will have       * weights.  At each pass, at least one slot boundary will have
1597       * its range of possible values fixed at a single value.       * its range of possible values fixed at a single value.
1598       */       */
1599    
1600      for (start=0; start < gridCount;) {      for (start=0; start < gridCount;) {
1601          int totalWeight = 0;    /* Sum of the weights for all of the          int totalWeight = 0;    /* Sum of the weights for all of the
1602                                   * slots in this span. */                                   * slots in this span. */
1603          int need = 0;           /* The minimum space needed to layout          int need = 0;           /* The minimum space needed to layout
1604                                   * this span. */                                   * this span. */
1605          int have;               /* The actual amount of space that will          int have;               /* The actual amount of space that will
1606                                   * be taken up by this span. */                                   * be taken up by this span. */
1607          int weight;             /* Cumulative weights of the columns in          int weight;             /* Cumulative weights of the columns in
1608                                   * this span. */                                   * this span. */
1609          int noWeights = 0;      /* True if the span has no weights. */          int noWeights = 0;      /* True if the span has no weights. */
1610    
1611          /*          /*
1612           * Find a span by identifying ranges of slots whose edges are           * Find a span by identifying ranges of slots whose edges are
1613           * already constrained at fixed offsets, but whose internal           * already constrained at fixed offsets, but whose internal
1614           * slot boundaries have a range of possible positions.           * slot boundaries have a range of possible positions.
1615           */           */
1616    
1617          if (layoutPtr[start].minOffset == layoutPtr[start].maxOffset) {          if (layoutPtr[start].minOffset == layoutPtr[start].maxOffset) {
1618              start++;              start++;
1619              continue;              continue;
1620          }          }
1621    
1622          for (end=start+1; end<gridCount; end++) {          for (end=start+1; end<gridCount; end++) {
1623              if (layoutPtr[end].minOffset == layoutPtr[end].maxOffset) {              if (layoutPtr[end].minOffset == layoutPtr[end].maxOffset) {
1624                  break;                  break;
1625              }              }
1626          }          }
1627    
1628          /*          /*
1629           * We found a span.  Compute the total weight, minumum space required,           * We found a span.  Compute the total weight, minumum space required,
1630           * for this span, and the actual amount of space the span should           * for this span, and the actual amount of space the span should
1631           * use.           * use.
1632           */           */
1633    
1634          for (slot=start; slot<=end; slot++) {          for (slot=start; slot<=end; slot++) {
1635              totalWeight += layoutPtr[slot].weight;              totalWeight += layoutPtr[slot].weight;
1636              need += layoutPtr[slot].minSize;              need += layoutPtr[slot].minSize;
1637          }          }
1638          have = layoutPtr[end].maxOffset - layoutPtr[start-1].minOffset;          have = layoutPtr[end].maxOffset - layoutPtr[start-1].minOffset;
1639    
1640          /*          /*
1641           * If all the weights in the span are zero, then distribute the           * If all the weights in the span are zero, then distribute the
1642           * extra space evenly.           * extra space evenly.
1643           */           */
1644    
1645          if (totalWeight == 0) {          if (totalWeight == 0) {
1646              noWeights++;              noWeights++;
1647              totalWeight = end - start + 1;              totalWeight = end - start + 1;
1648          }          }
1649    
1650          /*          /*
1651           * It might not be possible to give the span all of the space           * It might not be possible to give the span all of the space
1652           * available on this pass without violating the size constraints           * available on this pass without violating the size constraints
1653           * of one or more of the internal slot boundaries.           * of one or more of the internal slot boundaries.
1654           * Determine the maximum amount of space that when added to the           * Determine the maximum amount of space that when added to the
1655           * entire span, would cause a slot boundary to have its possible           * entire span, would cause a slot boundary to have its possible
1656           * range reduced to one value, and reduce the amount of extra           * range reduced to one value, and reduce the amount of extra
1657           * space allocated on this pass accordingly.           * space allocated on this pass accordingly.
1658           *           *
1659           * The calculation is done cumulatively to avoid accumulating           * The calculation is done cumulatively to avoid accumulating
1660           * roundoff errors.           * roundoff errors.
1661           */           */
1662    
1663          for (weight=0,slot=start; slot<end; slot++) {          for (weight=0,slot=start; slot<end; slot++) {
1664              int diff = layoutPtr[slot].maxOffset - layoutPtr[slot].minOffset;              int diff = layoutPtr[slot].maxOffset - layoutPtr[slot].minOffset;
1665              weight += noWeights ? 1 : layoutPtr[slot].weight;              weight += noWeights ? 1 : layoutPtr[slot].weight;
1666              if ((noWeights || layoutPtr[slot].weight>0) &&              if ((noWeights || layoutPtr[slot].weight>0) &&
1667                      (diff*totalWeight/weight) < (have-need)) {                      (diff*totalWeight/weight) < (have-need)) {
1668                  have = diff * totalWeight / weight + need;                  have = diff * totalWeight / weight + need;
1669              }              }
1670          }          }
1671    
1672          /*          /*
1673           * Now distribute the extra space among the slots by           * Now distribute the extra space among the slots by
1674           * adjusting the minSizes and minOffsets.           * adjusting the minSizes and minOffsets.
1675           */           */
1676    
1677          for (weight=0,slot=start; slot<end; slot++) {          for (weight=0,slot=start; slot<end; slot++) {
1678              weight += noWeights ? 1 : layoutPtr[slot].weight;              weight += noWeights ? 1 : layoutPtr[slot].weight;
1679              layoutPtr[slot].minOffset +=              layoutPtr[slot].minOffset +=
1680                  (int)((double) (have-need) * weight/totalWeight + 0.5);                  (int)((double) (have-need) * weight/totalWeight + 0.5);
1681              layoutPtr[slot].minSize = layoutPtr[slot].minOffset              layoutPtr[slot].minSize = layoutPtr[slot].minOffset
1682                      - layoutPtr[slot-1].minOffset;                      - layoutPtr[slot-1].minOffset;
1683          }          }
1684          layoutPtr[slot].minSize = layoutPtr[slot].minOffset          layoutPtr[slot].minSize = layoutPtr[slot].minOffset
1685                  - layoutPtr[slot-1].minOffset;                  - layoutPtr[slot-1].minOffset;
1686    
1687          /*          /*
1688           * Having pushed the top/left boundaries of the slots to           * Having pushed the top/left boundaries of the slots to
1689           * take up extra space, the bottom/right space is recalculated           * take up extra space, the bottom/right space is recalculated
1690           * to propagate the new space allocation.           * to propagate the new space allocation.
1691           */           */
1692    
1693          for (slot=end; slot > start; slot--) {          for (slot=end; slot > start; slot--) {
1694              layoutPtr[slot-1].maxOffset =              layoutPtr[slot-1].maxOffset =
1695                      layoutPtr[slot].maxOffset-layoutPtr[slot].minSize;                      layoutPtr[slot].maxOffset-layoutPtr[slot].minSize;
1696          }          }
1697      }      }
1698    
1699    
1700      /*      /*
1701       * Step 6.       * Step 6.
1702       * All of the space has been apportioned; copy the       * All of the space has been apportioned; copy the
1703       * layout information back into the master.       * layout information back into the master.
1704       */       */
1705    
1706      for (slot=0; slot < gridCount; slot++) {      for (slot=0; slot < gridCount; slot++) {
1707          slotPtr[slot].offset = layoutPtr[slot].minOffset;          slotPtr[slot].offset = layoutPtr[slot].minOffset;
1708      }      }
1709    
1710      --layoutPtr;      --layoutPtr;
1711      if (layoutPtr != layoutData) {      if (layoutPtr != layoutData) {
1712          Tcl_Free((char *)layoutPtr);          Tcl_Free((char *)layoutPtr);
1713      }      }
1714      return requiredSize;      return requiredSize;
1715  }  }
1716    
1717  /*  /*
1718   *--------------------------------------------------------------   *--------------------------------------------------------------
1719   *   *
1720   * GetGrid --   * GetGrid --
1721   *   *
1722   *      This internal procedure is used to locate a Grid   *      This internal procedure is used to locate a Grid
1723   *      structure for a given window, creating one if one   *      structure for a given window, creating one if one
1724   *      doesn't exist already.   *      doesn't exist already.
1725   *   *
1726   * Results:   * Results:
1727   *      The return value is a pointer to the Grid structure   *      The return value is a pointer to the Grid structure
1728   *      corresponding to tkwin.   *      corresponding to tkwin.
1729   *   *
1730   * Side effects:   * Side effects:
1731   *      A new grid structure may be created.  If so, then   *      A new grid structure may be created.  If so, then
1732   *      a callback is set up to clean things up when the   *      a callback is set up to clean things up when the
1733   *      window is deleted.   *      window is deleted.
1734   *   *
1735   *--------------------------------------------------------------   *--------------------------------------------------------------
1736   */   */
1737    
1738  static Gridder *  static Gridder *
1739  GetGrid(tkwin)  GetGrid(tkwin)
1740      Tk_Window tkwin;            /* Token for window for which      Tk_Window tkwin;            /* Token for window for which
1741                                   * grid structure is desired. */                                   * grid structure is desired. */
1742  {  {
1743      register Gridder *gridPtr;      register Gridder *gridPtr;
1744      Tcl_HashEntry *hPtr;      Tcl_HashEntry *hPtr;
1745      int new;      int new;
1746      TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;      TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
1747    
1748      if (!dispPtr->gridInit) {      if (!dispPtr->gridInit) {
1749          Tcl_InitHashTable(&dispPtr->gridHashTable, TCL_ONE_WORD_KEYS);          Tcl_InitHashTable(&dispPtr->gridHashTable, TCL_ONE_WORD_KEYS);
1750          dispPtr->gridInit = 1;          dispPtr->gridInit = 1;
1751      }      }
1752    
1753      /*      /*
1754       * See if there's already grid for this window.  If not,       * See if there's already grid for this window.  If not,
1755       * then create a new one.       * then create a new one.
1756       */       */
1757    
1758      hPtr = Tcl_CreateHashEntry(&dispPtr->gridHashTable, (char *) tkwin, &new);      hPtr = Tcl_CreateHashEntry(&dispPtr->gridHashTable, (char *) tkwin, &new);
1759      if (!new) {      if (!new) {
1760          return (Gridder *) Tcl_GetHashValue(hPtr);          return (Gridder *) Tcl_GetHashValue(hPtr);
1761      }      }
1762      gridPtr = (Gridder *) ckalloc(sizeof(Gridder));      gridPtr = (Gridder *) ckalloc(sizeof(Gridder));
1763      gridPtr->tkwin = tkwin;      gridPtr->tkwin = tkwin;
1764      gridPtr->masterPtr = NULL;      gridPtr->masterPtr = NULL;
1765      gridPtr->masterDataPtr = NULL;      gridPtr->masterDataPtr = NULL;
1766      gridPtr->nextPtr = NULL;      gridPtr->nextPtr = NULL;
1767      gridPtr->slavePtr = NULL;      gridPtr->slavePtr = NULL;
1768      gridPtr->binNextPtr = NULL;      gridPtr->binNextPtr = NULL;
1769    
1770      gridPtr->column = gridPtr->row = -1;      gridPtr->column = gridPtr->row = -1;
1771      gridPtr->numCols = 1;      gridPtr->numCols = 1;
1772      gridPtr->numRows = 1;      gridPtr->numRows = 1;
1773    
1774      gridPtr->padX = gridPtr->padY = 0;      gridPtr->padX = gridPtr->padY = 0;
1775      gridPtr->iPadX = gridPtr->iPadY = 0;      gridPtr->iPadX = gridPtr->iPadY = 0;
1776      gridPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;      gridPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
1777      gridPtr->abortPtr = NULL;      gridPtr->abortPtr = NULL;
1778      gridPtr->flags = 0;      gridPtr->flags = 0;
1779      gridPtr->sticky = 0;      gridPtr->sticky = 0;
1780      gridPtr->size = 0;      gridPtr->size = 0;
1781      gridPtr->masterDataPtr = NULL;      gridPtr->masterDataPtr = NULL;
1782      Tcl_SetHashValue(hPtr, gridPtr);      Tcl_SetHashValue(hPtr, gridPtr);
1783      Tk_CreateEventHandler(tkwin, StructureNotifyMask,      Tk_CreateEventHandler(tkwin, StructureNotifyMask,
1784              GridStructureProc, (ClientData) gridPtr);              GridStructureProc, (ClientData) gridPtr);
1785      return gridPtr;      return gridPtr;
1786  }  }
1787    
1788  /*  /*
1789   *--------------------------------------------------------------   *--------------------------------------------------------------
1790   *   *
1791   * SetGridSize --   * SetGridSize --
1792   *   *
1793   *      This internal procedure sets the size of the grid occupied   *      This internal procedure sets the size of the grid occupied
1794   *      by slaves.   *      by slaves.
1795   *   *
1796   * Results:   * Results:
1797   *      none   *      none
1798   *   *
1799   * Side effects:   * Side effects:
1800   *      The width and height arguments are filled in the master data structure.   *      The width and height arguments are filled in the master data structure.
1801   *      Additional space is allocated for the constraints to accomodate   *      Additional space is allocated for the constraints to accomodate
1802   *      the offsets.   *      the offsets.
1803   *   *
1804   *--------------------------------------------------------------   *--------------------------------------------------------------
1805   */   */
1806    
1807  static void  static void
1808  SetGridSize(masterPtr)  SetGridSize(masterPtr)
1809      Gridder *masterPtr;                 /* The geometry master for this grid. */      Gridder *masterPtr;                 /* The geometry master for this grid. */
1810  {  {
1811      register Gridder *slavePtr;         /* Current slave window. */      register Gridder *slavePtr;         /* Current slave window. */
1812      int maxX = 0, maxY = 0;      int maxX = 0, maxY = 0;
1813    
1814      for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;      for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
1815                  slavePtr = slavePtr->nextPtr) {                  slavePtr = slavePtr->nextPtr) {
1816          maxX = MAX(maxX,slavePtr->numCols + slavePtr->column);          maxX = MAX(maxX,slavePtr->numCols + slavePtr->column);
1817          maxY = MAX(maxY,slavePtr->numRows + slavePtr->row);          maxY = MAX(maxY,slavePtr->numRows + slavePtr->row);
1818      }      }
1819      masterPtr->masterDataPtr->columnEnd = maxX;      masterPtr->masterDataPtr->columnEnd = maxX;
1820      masterPtr->masterDataPtr->rowEnd = maxY;      masterPtr->masterDataPtr->rowEnd = maxY;
1821      CheckSlotData(masterPtr, maxX, COLUMN, CHECK_SPACE);      CheckSlotData(masterPtr, maxX, COLUMN, CHECK_SPACE);
1822      CheckSlotData(masterPtr, maxY, ROW, CHECK_SPACE);      CheckSlotData(masterPtr, maxY, ROW, CHECK_SPACE);
1823  }  }
1824    
1825  /*  /*
1826   *--------------------------------------------------------------   *--------------------------------------------------------------
1827   *   *
1828   * CheckSlotData --   * CheckSlotData --
1829   *   *
1830   *      This internal procedure is used to manage the storage for   *      This internal procedure is used to manage the storage for
1831   *      row and column (slot) constraints.   *      row and column (slot) constraints.
1832   *   *
1833   * Results:   * Results:
1834   *      TRUE if the index is OK, False otherwise.   *      TRUE if the index is OK, False otherwise.
1835   *   *
1836   * Side effects:   * Side effects:
1837   *      A new master grid structure may be created.  If so, then   *      A new master grid structure may be created.  If so, then
1838   *      it is initialized.  In addition, additional storage for   *      it is initialized.  In addition, additional storage for
1839   *      a row or column constraints may be allocated, and the constraint   *      a row or column constraints may be allocated, and the constraint
1840   *      maximums are adjusted.   *      maximums are adjusted.
1841   *   *
1842   *--------------------------------------------------------------   *--------------------------------------------------------------
1843   */   */
1844    
1845  static int  static int
1846  CheckSlotData(masterPtr, slot, slotType, checkOnly)  CheckSlotData(masterPtr, slot, slotType, checkOnly)
1847      Gridder *masterPtr; /* the geometry master for this grid */      Gridder *masterPtr; /* the geometry master for this grid */
1848      int slot;           /* which slot to look at */      int slot;           /* which slot to look at */
1849      int slotType;       /* ROW or COLUMN */      int slotType;       /* ROW or COLUMN */
1850      int checkOnly;      /* don't allocate new space if true */      int checkOnly;      /* don't allocate new space if true */
1851  {  {
1852      int numSlot;        /* number of slots already allocated (Space) */      int numSlot;        /* number of slots already allocated (Space) */
1853      int end;            /* last used constraint */      int end;            /* last used constraint */
1854    
1855      /*      /*
1856       * If slot is out of bounds, return immediately.       * If slot is out of bounds, return immediately.
1857       */       */
1858    
1859      if (slot < 0 || slot >= MAX_ELEMENT) {      if (slot < 0 || slot >= MAX_ELEMENT) {
1860          return TCL_ERROR;          return TCL_ERROR;
1861      }      }
1862    
1863      if ((checkOnly == CHECK_ONLY) && (masterPtr->masterDataPtr == NULL)) {      if ((checkOnly == CHECK_ONLY) && (masterPtr->masterDataPtr == NULL)) {
1864          return TCL_ERROR;          return TCL_ERROR;
1865      }      }
1866    
1867      /*      /*
1868       * If we need to allocate more space, allocate a little extra to avoid       * If we need to allocate more space, allocate a little extra to avoid
1869       * repeated re-alloc's for large tables.  We need enough space to       * repeated re-alloc's for large tables.  We need enough space to
1870       * hold all of the offsets as well.       * hold all of the offsets as well.
1871       */       */
1872    
1873      InitMasterData(masterPtr);      InitMasterData(masterPtr);
1874      end = (slotType == ROW) ? masterPtr->masterDataPtr->rowMax :      end = (slotType == ROW) ? masterPtr->masterDataPtr->rowMax :
1875              masterPtr->masterDataPtr->columnMax;              masterPtr->masterDataPtr->columnMax;
1876      if (checkOnly == CHECK_ONLY) {      if (checkOnly == CHECK_ONLY) {
1877          return  (end < slot) ? TCL_ERROR : TCL_OK;          return  (end < slot) ? TCL_ERROR : TCL_OK;
1878      } else {      } else {
1879          numSlot = (slotType == ROW) ? masterPtr->masterDataPtr->rowSpace          numSlot = (slotType == ROW) ? masterPtr->masterDataPtr->rowSpace
1880                                      : masterPtr->masterDataPtr->columnSpace;                                      : masterPtr->masterDataPtr->columnSpace;
1881          if (slot >= numSlot) {          if (slot >= numSlot) {
1882              int      newNumSlot = slot + PREALLOC ;              int      newNumSlot = slot + PREALLOC ;
1883              size_t   oldSize = numSlot    * sizeof(SlotInfo) ;              size_t   oldSize = numSlot    * sizeof(SlotInfo) ;
1884              size_t   newSize = newNumSlot * sizeof(SlotInfo) ;              size_t   newSize = newNumSlot * sizeof(SlotInfo) ;
1885              SlotInfo *new = (SlotInfo *) ckalloc(newSize);              SlotInfo *new = (SlotInfo *) ckalloc(newSize);
1886              SlotInfo *old = (slotType == ROW) ?              SlotInfo *old = (slotType == ROW) ?
1887                      masterPtr->masterDataPtr->rowPtr :                      masterPtr->masterDataPtr->rowPtr :
1888                      masterPtr->masterDataPtr->columnPtr;                      masterPtr->masterDataPtr->columnPtr;
1889              memcpy((VOID *) new, (VOID *) old, oldSize );              memcpy((VOID *) new, (VOID *) old, oldSize );
1890              memset((VOID *) (new+numSlot), 0, newSize - oldSize );              memset((VOID *) (new+numSlot), 0, newSize - oldSize );
1891              Tcl_Free((char *) old);              Tcl_Free((char *) old);
1892              if (slotType == ROW) {              if (slotType == ROW) {
1893                  masterPtr->masterDataPtr->rowPtr = new ;                  masterPtr->masterDataPtr->rowPtr = new ;
1894                  masterPtr->masterDataPtr->rowSpace = newNumSlot ;                  masterPtr->masterDataPtr->rowSpace = newNumSlot ;
1895              } else {              } else {
1896                  masterPtr->masterDataPtr->columnPtr = new;                  masterPtr->masterDataPtr->columnPtr = new;
1897                  masterPtr->masterDataPtr->columnSpace = newNumSlot ;                  masterPtr->masterDataPtr->columnSpace = newNumSlot ;
1898              }              }
1899          }          }
1900          if (slot >= end && checkOnly != CHECK_SPACE) {          if (slot >= end && checkOnly != CHECK_SPACE) {
1901              if (slotType == ROW) {              if (slotType == ROW) {
1902                  masterPtr->masterDataPtr->rowMax = slot+1;                  masterPtr->masterDataPtr->rowMax = slot+1;
1903              } else {              } else {
1904                  masterPtr->masterDataPtr->columnMax = slot+1;                  masterPtr->masterDataPtr->columnMax = slot+1;
1905              }              }
1906          }          }
1907          return TCL_OK;          return TCL_OK;
1908      }      }
1909  }  }
1910    
1911  /*  /*
1912   *--------------------------------------------------------------   *--------------------------------------------------------------
1913   *   *
1914   * InitMasterData --   * InitMasterData --
1915   *   *
1916   *      This internal procedure is used to allocate and initialize   *      This internal procedure is used to allocate and initialize
1917   *      the data for a geometry master, if the data   *      the data for a geometry master, if the data
1918   *      doesn't exist already.   *      doesn't exist already.
1919   *   *
1920   * Results:   * Results:
1921   *      none   *      none
1922   *   *
1923   * Side effects:   * Side effects:
1924   *      A new master grid structure may be created.  If so, then   *      A new master grid structure may be created.  If so, then
1925   *      it is initialized.   *      it is initialized.
1926   *   *
1927   *--------------------------------------------------------------   *--------------------------------------------------------------
1928   */   */
1929    
1930  static void  static void
1931  InitMasterData(masterPtr)  InitMasterData(masterPtr)
1932      Gridder *masterPtr;      Gridder *masterPtr;
1933  {  {
1934      size_t size;      size_t size;
1935      if (masterPtr->masterDataPtr == NULL) {      if (masterPtr->masterDataPtr == NULL) {
1936          GridMaster *gridPtr = masterPtr->masterDataPtr =          GridMaster *gridPtr = masterPtr->masterDataPtr =
1937                  (GridMaster *) ckalloc(sizeof(GridMaster));                  (GridMaster *) ckalloc(sizeof(GridMaster));
1938          size = sizeof(SlotInfo) * TYPICAL_SIZE;          size = sizeof(SlotInfo) * TYPICAL_SIZE;
1939    
1940          gridPtr->columnEnd = 0;          gridPtr->columnEnd = 0;
1941          gridPtr->columnMax = 0;          gridPtr->columnMax = 0;
1942          gridPtr->columnPtr = (SlotInfo *) ckalloc(size);          gridPtr->columnPtr = (SlotInfo *) ckalloc(size);
1943          gridPtr->columnSpace = TYPICAL_SIZE;          gridPtr->columnSpace = TYPICAL_SIZE;
1944          gridPtr->rowEnd = 0;          gridPtr->rowEnd = 0;
1945          gridPtr->rowMax = 0;          gridPtr->rowMax = 0;
1946          gridPtr->rowPtr = (SlotInfo *) ckalloc(size);          gridPtr->rowPtr = (SlotInfo *) ckalloc(size);
1947          gridPtr->rowSpace = TYPICAL_SIZE;          gridPtr->rowSpace = TYPICAL_SIZE;
1948          gridPtr->startX = 0;          gridPtr->startX = 0;
1949          gridPtr->startY = 0;          gridPtr->startY = 0;
1950    
1951          memset((VOID *) gridPtr->columnPtr, 0, size);          memset((VOID *) gridPtr->columnPtr, 0, size);
1952          memset((VOID *) gridPtr->rowPtr, 0, size);          memset((VOID *) gridPtr->rowPtr, 0, size);
1953      }      }
1954  }  }
1955    
1956  /*  /*
1957   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1958   *   *
1959   * Unlink --   * Unlink --
1960   *   *
1961   *      Remove a grid from its parent's list of slaves.   *      Remove a grid from its parent's list of slaves.
1962   *   *
1963   * Results:   * Results:
1964   *      None.   *      None.
1965   *   *
1966   * Side effects:   * Side effects:
1967   *      The parent will be scheduled for re-arranging, and the size of the   *      The parent will be scheduled for re-arranging, and the size of the
1968   *      grid will be adjusted accordingly   *      grid will be adjusted accordingly
1969   *   *
1970   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1971   */   */
1972    
1973  static void  static void
1974  Unlink(slavePtr)  Unlink(slavePtr)
1975      register Gridder *slavePtr;         /* Window to unlink. */      register Gridder *slavePtr;         /* Window to unlink. */
1976  {  {
1977      register Gridder *masterPtr, *slavePtr2;      register Gridder *masterPtr, *slavePtr2;
1978      GridMaster *gridPtr;        /* pointer to grid data */      GridMaster *gridPtr;        /* pointer to grid data */
1979    
1980      masterPtr = slavePtr->masterPtr;      masterPtr = slavePtr->masterPtr;
1981      if (masterPtr == NULL) {      if (masterPtr == NULL) {
1982          return;          return;
1983      }      }
1984    
1985      gridPtr = masterPtr->masterDataPtr;      gridPtr = masterPtr->masterDataPtr;
1986      if (masterPtr->slavePtr == slavePtr) {      if (masterPtr->slavePtr == slavePtr) {
1987          masterPtr->slavePtr = slavePtr->nextPtr;          masterPtr->slavePtr = slavePtr->nextPtr;
1988      }      }
1989      else {      else {
1990          for (slavePtr2 = masterPtr->slavePtr; ; slavePtr2 = slavePtr2->nextPtr) {          for (slavePtr2 = masterPtr->slavePtr; ; slavePtr2 = slavePtr2->nextPtr) {
1991              if (slavePtr2 == NULL) {              if (slavePtr2 == NULL) {
1992                  panic("Unlink couldn't find previous window");                  panic("Unlink couldn't find previous window");
1993              }              }
1994              if (slavePtr2->nextPtr == slavePtr) {              if (slavePtr2->nextPtr == slavePtr) {
1995                  slavePtr2->nextPtr = slavePtr->nextPtr;                  slavePtr2->nextPtr = slavePtr->nextPtr;
1996                  break;                  break;
1997              }              }
1998          }          }
1999      }      }
2000      if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {      if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
2001          masterPtr->flags |= REQUESTED_RELAYOUT;          masterPtr->flags |= REQUESTED_RELAYOUT;
2002          Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);          Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
2003      }      }
2004      if (masterPtr->abortPtr != NULL) {      if (masterPtr->abortPtr != NULL) {
2005          *masterPtr->abortPtr = 1;          *masterPtr->abortPtr = 1;
2006      }      }
2007    
2008      if ((slavePtr->numCols+slavePtr->column == gridPtr->columnMax)      if ((slavePtr->numCols+slavePtr->column == gridPtr->columnMax)
2009              || (slavePtr->numRows+slavePtr->row == gridPtr->rowMax)) {              || (slavePtr->numRows+slavePtr->row == gridPtr->rowMax)) {
2010      }      }
2011      slavePtr->masterPtr = NULL;      slavePtr->masterPtr = NULL;
2012  }  }
2013    
2014  /*  /*
2015   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2016   *   *
2017   * DestroyGrid --   * DestroyGrid --
2018   *   *
2019   *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release   *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
2020   *      to clean up the internal structure of a grid at a safe time   *      to clean up the internal structure of a grid at a safe time
2021   *      (when no-one is using it anymore).   Cleaning up the grid involves   *      (when no-one is using it anymore).   Cleaning up the grid involves
2022   *      freeing the main structure for all windows. and the master structure   *      freeing the main structure for all windows. and the master structure
2023   *      for geometry managers.   *      for geometry managers.
2024   *   *
2025   * Results:   * Results:
2026   *      None.   *      None.
2027   *   *
2028   * Side effects:   * Side effects:
2029   *      Everything associated with the grid is freed up.   *      Everything associated with the grid is freed up.
2030   *   *
2031   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2032   */   */
2033    
2034  static void  static void
2035  DestroyGrid(memPtr)  DestroyGrid(memPtr)
2036      char *memPtr;               /* Info about window that is now dead. */      char *memPtr;               /* Info about window that is now dead. */
2037  {  {
2038      register Gridder *gridPtr = (Gridder *) memPtr;      register Gridder *gridPtr = (Gridder *) memPtr;
2039    
2040      if (gridPtr->masterDataPtr != NULL) {      if (gridPtr->masterDataPtr != NULL) {
2041          if (gridPtr->masterDataPtr->rowPtr != NULL) {          if (gridPtr->masterDataPtr->rowPtr != NULL) {
2042              Tcl_Free((char *) gridPtr->masterDataPtr -> rowPtr);              Tcl_Free((char *) gridPtr->masterDataPtr -> rowPtr);
2043          }          }
2044          if (gridPtr->masterDataPtr->columnPtr != NULL) {          if (gridPtr->masterDataPtr->columnPtr != NULL) {
2045              Tcl_Free((char *) gridPtr->masterDataPtr -> columnPtr);              Tcl_Free((char *) gridPtr->masterDataPtr -> columnPtr);
2046          }          }
2047          Tcl_Free((char *) gridPtr->masterDataPtr);          Tcl_Free((char *) gridPtr->masterDataPtr);
2048      }      }
2049      Tcl_Free((char *) gridPtr);      Tcl_Free((char *) gridPtr);
2050  }  }
2051    
2052  /*  /*
2053   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2054   *   *
2055   * GridStructureProc --   * GridStructureProc --
2056   *   *
2057   *      This procedure is invoked by the Tk event dispatcher in response   *      This procedure is invoked by the Tk event dispatcher in response
2058   *      to StructureNotify events.   *      to StructureNotify events.
2059   *   *
2060   * Results:   * Results:
2061   *      None.   *      None.
2062   *   *
2063   * Side effects:   * Side effects:
2064   *      If a window was just deleted, clean up all its grid-related   *      If a window was just deleted, clean up all its grid-related
2065   *      information.  If it was just resized, re-configure its slaves, if   *      information.  If it was just resized, re-configure its slaves, if
2066   *      any.   *      any.
2067   *   *
2068   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2069   */   */
2070    
2071  static void  static void
2072  GridStructureProc(clientData, eventPtr)  GridStructureProc(clientData, eventPtr)
2073      ClientData clientData;              /* Our information about window      ClientData clientData;              /* Our information about window
2074                                           * referred to by eventPtr. */                                           * referred to by eventPtr. */
2075      XEvent *eventPtr;                   /* Describes what just happened. */      XEvent *eventPtr;                   /* Describes what just happened. */
2076  {  {
2077      register Gridder *gridPtr = (Gridder *) clientData;      register Gridder *gridPtr = (Gridder *) clientData;
2078      TkDisplay *dispPtr = ((TkWindow *) gridPtr->tkwin)->dispPtr;      TkDisplay *dispPtr = ((TkWindow *) gridPtr->tkwin)->dispPtr;
2079    
2080      if (eventPtr->type == ConfigureNotify) {      if (eventPtr->type == ConfigureNotify) {
2081          if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {          if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
2082              gridPtr->flags |= REQUESTED_RELAYOUT;              gridPtr->flags |= REQUESTED_RELAYOUT;
2083              Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);              Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
2084          }          }
2085          if (gridPtr->doubleBw != 2*Tk_Changes(gridPtr->tkwin)->border_width) {          if (gridPtr->doubleBw != 2*Tk_Changes(gridPtr->tkwin)->border_width) {
2086              if ((gridPtr->masterPtr != NULL) &&              if ((gridPtr->masterPtr != NULL) &&
2087                      !(gridPtr->masterPtr->flags & REQUESTED_RELAYOUT)) {                      !(gridPtr->masterPtr->flags & REQUESTED_RELAYOUT)) {
2088                  gridPtr->doubleBw = 2*Tk_Changes(gridPtr->tkwin)->border_width;                  gridPtr->doubleBw = 2*Tk_Changes(gridPtr->tkwin)->border_width;
2089                  gridPtr->masterPtr->flags |= REQUESTED_RELAYOUT;                  gridPtr->masterPtr->flags |= REQUESTED_RELAYOUT;
2090                  Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr->masterPtr);                  Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr->masterPtr);
2091              }              }
2092          }          }
2093      } else if (eventPtr->type == DestroyNotify) {      } else if (eventPtr->type == DestroyNotify) {
2094          register Gridder *gridPtr2, *nextPtr;          register Gridder *gridPtr2, *nextPtr;
2095    
2096          if (gridPtr->masterPtr != NULL) {          if (gridPtr->masterPtr != NULL) {
2097              Unlink(gridPtr);              Unlink(gridPtr);
2098          }          }
2099          for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL;          for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL;
2100                                             gridPtr2 = nextPtr) {                                             gridPtr2 = nextPtr) {
2101              Tk_UnmapWindow(gridPtr2->tkwin);              Tk_UnmapWindow(gridPtr2->tkwin);
2102              gridPtr2->masterPtr = NULL;              gridPtr2->masterPtr = NULL;
2103              nextPtr = gridPtr2->nextPtr;              nextPtr = gridPtr2->nextPtr;
2104              gridPtr2->nextPtr = NULL;              gridPtr2->nextPtr = NULL;
2105          }          }
2106          Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->gridHashTable,          Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->gridHashTable,
2107                  (char *) gridPtr->tkwin));                  (char *) gridPtr->tkwin));
2108          if (gridPtr->flags & REQUESTED_RELAYOUT) {          if (gridPtr->flags & REQUESTED_RELAYOUT) {
2109              Tcl_CancelIdleCall(ArrangeGrid, (ClientData) gridPtr);              Tcl_CancelIdleCall(ArrangeGrid, (ClientData) gridPtr);
2110          }          }
2111          gridPtr->tkwin = NULL;          gridPtr->tkwin = NULL;
2112          Tcl_EventuallyFree((ClientData) gridPtr, DestroyGrid);          Tcl_EventuallyFree((ClientData) gridPtr, DestroyGrid);
2113      } else if (eventPtr->type == MapNotify) {      } else if (eventPtr->type == MapNotify) {
2114          if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {          if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
2115              gridPtr->flags |= REQUESTED_RELAYOUT;              gridPtr->flags |= REQUESTED_RELAYOUT;
2116              Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);              Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
2117          }          }
2118      } else if (eventPtr->type == UnmapNotify) {      } else if (eventPtr->type == UnmapNotify) {
2119          register Gridder *gridPtr2;          register Gridder *gridPtr2;
2120    
2121          for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL;          for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL;
2122                                             gridPtr2 = gridPtr2->nextPtr) {                                             gridPtr2 = gridPtr2->nextPtr) {
2123              Tk_UnmapWindow(gridPtr2->tkwin);              Tk_UnmapWindow(gridPtr2->tkwin);
2124          }          }
2125      }      }
2126  }  }
2127    
2128  /*  /*
2129   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2130   *   *
2131   * ConfigureSlaves --   * ConfigureSlaves --
2132   *   *
2133   *      This implements the guts of the "grid configure" command.  Given   *      This implements the guts of the "grid configure" command.  Given
2134   *      a list of slaves and configuration options, it arranges for the   *      a list of slaves and configuration options, it arranges for the
2135   *      grid to manage the slaves and sets the specified options.   *      grid to manage the slaves and sets the specified options.
2136   *      arguments consist of windows or window shortcuts followed by   *      arguments consist of windows or window shortcuts followed by
2137   *      "-option value" pairs.   *      "-option value" pairs.
2138   *   *
2139   * Results:   * Results:
2140   *      TCL_OK is returned if all went well.  Otherwise, TCL_ERROR is   *      TCL_OK is returned if all went well.  Otherwise, TCL_ERROR is
2141   *      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.
2142   *   *
2143   * Side effects:   * Side effects:
2144   *      Slave windows get taken over by the grid.   *      Slave windows get taken over by the grid.
2145   *   *
2146   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2147   */   */
2148    
2149  static int  static int
2150  ConfigureSlaves(interp, tkwin, argc, argv)  ConfigureSlaves(interp, tkwin, argc, argv)
2151      Tcl_Interp *interp;         /* Interpreter for error reporting. */      Tcl_Interp *interp;         /* Interpreter for error reporting. */
2152      Tk_Window tkwin;            /* Any window in application containing      Tk_Window tkwin;            /* Any window in application containing
2153                                   * slaves.  Used to look up slave names. */                                   * slaves.  Used to look up slave names. */
2154      int argc;                   /* Number of elements in argv. */      int argc;                   /* Number of elements in argv. */
2155      char *argv[];               /* Argument strings:  contains one or more      char *argv[];               /* Argument strings:  contains one or more
2156                                   * window names followed by any number                                   * window names followed by any number
2157                                   * of "option value" pairs.  Caller must                                   * of "option value" pairs.  Caller must
2158                                   * make sure that there is at least one                                   * make sure that there is at least one
2159                                   * window name. */                                   * window name. */
2160  {  {
2161      Gridder *masterPtr;      Gridder *masterPtr;
2162      Gridder *slavePtr;      Gridder *slavePtr;
2163      Tk_Window other, slave, parent, ancestor;      Tk_Window other, slave, parent, ancestor;
2164      int i, j, c, tmp;      int i, j, c, tmp;
2165      size_t length;      size_t length;
2166      int numWindows;      int numWindows;
2167      int width;      int width;
2168      int defaultColumn = 0;      /* default column number */      int defaultColumn = 0;      /* default column number */
2169      int defaultColumnSpan = 1;  /* default number of columns */      int defaultColumnSpan = 1;  /* default number of columns */
2170      char *lastWindow;           /* use this window to base current      char *lastWindow;           /* use this window to base current
2171                                   * Row/col on */                                   * Row/col on */
2172    
2173      /*      /*
2174       * Count the number of windows, or window short-cuts.       * Count the number of windows, or window short-cuts.
2175       */       */
2176    
2177      for(numWindows=i=0;i<argc;i++) {      for(numWindows=i=0;i<argc;i++) {
2178          char firstChar = *argv[i];          char firstChar = *argv[i];
2179          if (firstChar == '.') {          if (firstChar == '.') {
2180              numWindows++;              numWindows++;
2181              continue;              continue;
2182          }          }
2183          length = strlen(argv[i]);          length = strlen(argv[i]);
2184          if (length > 1 && firstChar == '-') {          if (length > 1 && firstChar == '-') {
2185              break;              break;
2186          }          }
2187          if (length > 1) {          if (length > 1) {
2188              Tcl_AppendResult(interp, "unexpected parameter, \"",              Tcl_AppendResult(interp, "unexpected parameter, \"",
2189                      argv[i], "\", in configure list. ",                      argv[i], "\", in configure list. ",
2190                      "Should be window name or option", (char *) NULL);                      "Should be window name or option", (char *) NULL);
2191              return TCL_ERROR;              return TCL_ERROR;
2192          }          }
2193    
2194          if ((firstChar == REL_HORIZ) && ((numWindows == 0) ||          if ((firstChar == REL_HORIZ) && ((numWindows == 0) ||
2195                  (*argv[i-1] == REL_SKIP) || (*argv[i-1] == REL_VERT))) {                  (*argv[i-1] == REL_SKIP) || (*argv[i-1] == REL_VERT))) {
2196              Tcl_AppendResult(interp,              Tcl_AppendResult(interp,
2197                      "Must specify window before shortcut '-'.",                      "Must specify window before shortcut '-'.",
2198                      (char *) NULL);                      (char *) NULL);
2199              return TCL_ERROR;              return TCL_ERROR;
2200          }          }
2201    
2202          if ((firstChar == REL_VERT) || (firstChar == REL_SKIP)          if ((firstChar == REL_VERT) || (firstChar == REL_SKIP)
2203                  || (firstChar == REL_HORIZ)) {                  || (firstChar == REL_HORIZ)) {
2204              continue;              continue;
2205          }          }
2206    
2207          Tcl_AppendResult(interp, "invalid window shortcut, \"",          Tcl_AppendResult(interp, "invalid window shortcut, \"",
2208                  argv[i], "\" should be '-', 'x', or '^'", (char *) NULL);                  argv[i], "\" should be '-', 'x', or '^'", (char *) NULL);
2209          return TCL_ERROR;          return TCL_ERROR;
2210      }      }
2211      numWindows = i;      numWindows = i;
2212    
2213      if ((argc-numWindows)&1) {      if ((argc-numWindows)&1) {
2214          Tcl_AppendResult(interp, "extra option or",          Tcl_AppendResult(interp, "extra option or",
2215                  " option with no value", (char *) NULL);                  " option with no value", (char *) NULL);
2216          return TCL_ERROR;          return TCL_ERROR;
2217      }      }
2218    
2219      /*      /*
2220       * Iterate over all of the slave windows and short-cuts, parsing       * Iterate over all of the slave windows and short-cuts, parsing
2221       * 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
2222       * 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
2223       * parse the arguments just once at the beginning.  For example,       * parse the arguments just once at the beginning.  For example,
2224       * if a slave already is managed we want to just change a few       * if a slave already is managed we want to just change a few
2225       * existing values without resetting everything.  If there are       * existing values without resetting everything.  If there are
2226       * multiple windows, the -in option only gets processed for the       * multiple windows, the -in option only gets processed for the
2227       * first window.       * first window.
2228       */       */
2229    
2230      masterPtr = NULL;      masterPtr = NULL;
2231      for (j = 0; j < numWindows; j++) {      for (j = 0; j < numWindows; j++) {
2232          char firstChar = *argv[j];          char firstChar = *argv[j];
2233    
2234          /*          /*
2235           * '^' and 'x' cause us to skip a column.  '-' is processed           * '^' and 'x' cause us to skip a column.  '-' is processed
2236           * as part of its preceeding slave.           * as part of its preceeding slave.
2237           */           */
2238    
2239          if ((firstChar == REL_VERT) || (firstChar == REL_SKIP)) {          if ((firstChar == REL_VERT) || (firstChar == REL_SKIP)) {
2240              defaultColumn++;              defaultColumn++;
2241              continue;              continue;
2242          }          }
2243          if (firstChar == REL_HORIZ) {          if (firstChar == REL_HORIZ) {
2244              continue;              continue;
2245          }          }
2246    
2247          for (defaultColumnSpan=1;          for (defaultColumnSpan=1;
2248                  j + defaultColumnSpan < numWindows &&                  j + defaultColumnSpan < numWindows &&
2249                  (*argv[j+defaultColumnSpan] == REL_HORIZ);                  (*argv[j+defaultColumnSpan] == REL_HORIZ);
2250                  defaultColumnSpan++) {                  defaultColumnSpan++) {
2251              /* null body */              /* null body */
2252          }          }
2253    
2254          slave = Tk_NameToWindow(interp, argv[j], tkwin);          slave = Tk_NameToWindow(interp, argv[j], tkwin);
2255          if (slave == NULL) {          if (slave == NULL) {
2256              return TCL_ERROR;              return TCL_ERROR;
2257          }          }
2258          if (Tk_IsTopLevel(slave)) {          if (Tk_IsTopLevel(slave)) {
2259              Tcl_AppendResult(interp, "can't manage \"", argv[j],              Tcl_AppendResult(interp, "can't manage \"", argv[j],
2260                      "\": it's a top-level window", (char *) NULL);                      "\": it's a top-level window", (char *) NULL);
2261              return TCL_ERROR;              return TCL_ERROR;
2262          }          }
2263          slavePtr = GetGrid(slave);          slavePtr = GetGrid(slave);
2264    
2265          /*          /*
2266           * The following statement is taken from tkPack.c:           * The following statement is taken from tkPack.c:
2267           *           *
2268           * "If the slave isn't currently managed, reset all of its           * "If the slave isn't currently managed, reset all of its
2269           * configuration information to default values (there could           * configuration information to default values (there could
2270           * be old values left from a previous packer)."           * be old values left from a previous packer)."
2271           *           *
2272           * I [D.S.] disagree with this statement.  If a slave is disabled (using           * I [D.S.] disagree with this statement.  If a slave is disabled (using
2273           * "forget") and then re-enabled, I submit that 90% of the time the           * "forget") and then re-enabled, I submit that 90% of the time the
2274           * programmer will want it to retain its old configuration information.           * programmer will want it to retain its old configuration information.
2275           * If the programmer doesn't want this behavior, then the           * If the programmer doesn't want this behavior, then the
2276           * defaults can be reestablished by hand, without having to worry           * defaults can be reestablished by hand, without having to worry
2277           * about keeping track of the old state.           * about keeping track of the old state.
2278           */           */
2279    
2280          for (i = numWindows; i < argc; i+=2) {          for (i = numWindows; i < argc; i+=2) {
2281              length = strlen(argv[i]);              length = strlen(argv[i]);
2282              c = argv[i][1];              c = argv[i][1];
2283    
2284              if (length < 2) {              if (length < 2) {
2285                  Tcl_AppendResult(interp, "unknown or ambiguous option \"",                  Tcl_AppendResult(interp, "unknown or ambiguous option \"",
2286                          argv[i], "\": must be ",                          argv[i], "\": must be ",
2287                          "-column, -columnspan, -in, -ipadx, -ipady, ",                          "-column, -columnspan, -in, -ipadx, -ipady, ",
2288                          "-padx, -pady, -row, -rowspan, or -sticky",                          "-padx, -pady, -row, -rowspan, or -sticky",
2289                          (char *) NULL);                          (char *) NULL);
2290                  return TCL_ERROR;                  return TCL_ERROR;
2291              }              }
2292              if ((c == 'c') && (strncmp(argv[i], "-column", length) == 0)) {              if ((c == 'c') && (strncmp(argv[i], "-column", length) == 0)) {
2293                  if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) {                  if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) {
2294                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
2295                      Tcl_AppendResult(interp, "bad column value \"", argv[i+1],                      Tcl_AppendResult(interp, "bad column value \"", argv[i+1],
2296                              "\": must be a non-negative integer", (char *)NULL);                              "\": must be a non-negative integer", (char *)NULL);
2297                      return TCL_ERROR;                      return TCL_ERROR;
2298                  }                  }
2299                  slavePtr->column = tmp;                  slavePtr->column = tmp;
2300              } else if ((c == 'c')              } else if ((c == 'c')
2301                      && (strncmp(argv[i], "-columnspan", length) == 0)) {                      && (strncmp(argv[i], "-columnspan", length) == 0)) {
2302                  if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp <= 0) {                  if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp <= 0) {
2303                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
2304                      Tcl_AppendResult(interp, "bad columnspan value \"", argv[i+1],                      Tcl_AppendResult(interp, "bad columnspan value \"", argv[i+1],
2305                              "\": must be a positive integer", (char *)NULL);                              "\": must be a positive integer", (char *)NULL);
2306                      return TCL_ERROR;                      return TCL_ERROR;
2307                  }                  }
2308                  slavePtr->numCols = tmp;                  slavePtr->numCols = tmp;
2309              } else if ((c == 'i') && (strncmp(argv[i], "-in", length) == 0)) {              } else if ((c == 'i') && (strncmp(argv[i], "-in", length) == 0)) {
2310                  other = Tk_NameToWindow(interp, argv[i+1], tkwin);                  other = Tk_NameToWindow(interp, argv[i+1], tkwin);
2311                  if (other == NULL) {                  if (other == NULL) {
2312                      return TCL_ERROR;                      return TCL_ERROR;
2313                  }                  }
2314                  if (other == slave) {                  if (other == slave) {
2315                      Tcl_SetResult(interp, "Window can't be managed in itself",                      Tcl_SetResult(interp, "Window can't be managed in itself",
2316                              TCL_STATIC);                              TCL_STATIC);
2317                      return TCL_ERROR;                      return TCL_ERROR;
2318                  }                  }
2319                  masterPtr = GetGrid(other);                  masterPtr = GetGrid(other);
2320                  InitMasterData(masterPtr);                  InitMasterData(masterPtr);
2321              } else if ((c == 'i')              } else if ((c == 'i')
2322                      && (strncmp(argv[i], "-ipadx", length) == 0)) {                      && (strncmp(argv[i], "-ipadx", length) == 0)) {
2323                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
2324                          || (tmp < 0)) {                          || (tmp < 0)) {
2325                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
2326                      Tcl_AppendResult(interp, "bad ipadx value \"", argv[i+1],                      Tcl_AppendResult(interp, "bad ipadx value \"", argv[i+1],
2327                              "\": must be positive screen distance",                              "\": must be positive screen distance",
2328                              (char *) NULL);                              (char *) NULL);
2329                      return TCL_ERROR;                      return TCL_ERROR;
2330                  }                  }
2331                  slavePtr->iPadX = tmp*2;                  slavePtr->iPadX = tmp*2;
2332              } else if ((c == 'i')              } else if ((c == 'i')
2333                      && (strncmp(argv[i], "-ipady", length) == 0)) {                      && (strncmp(argv[i], "-ipady", length) == 0)) {
2334                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
2335                          || (tmp< 0)) {                          || (tmp< 0)) {
2336                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
2337                      Tcl_AppendResult(interp, "bad ipady value \"", argv[i+1],                      Tcl_AppendResult(interp, "bad ipady value \"", argv[i+1],
2338                              "\": must be positive screen distance",                              "\": must be positive screen distance",
2339                              (char *) NULL);                              (char *) NULL);
2340                      return TCL_ERROR;                      return TCL_ERROR;
2341                  }                  }
2342                  slavePtr->iPadY = tmp*2;                  slavePtr->iPadY = tmp*2;
2343              } else if ((c == 'p')              } else if ((c == 'p')
2344                      && (strncmp(argv[i], "-padx", length) == 0)) {                      && (strncmp(argv[i], "-padx", length) == 0)) {
2345                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
2346                          || (tmp< 0)) {                          || (tmp< 0)) {
2347                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
2348                      Tcl_AppendResult(interp, "bad padx value \"", argv[i+1],                      Tcl_AppendResult(interp, "bad padx value \"", argv[i+1],
2349                              "\": must be positive screen distance",                              "\": must be positive screen distance",
2350                              (char *) NULL);                              (char *) NULL);
2351                      return TCL_ERROR;                      return TCL_ERROR;
2352                  }                  }
2353                  slavePtr->padX = tmp*2;                  slavePtr->padX = tmp*2;
2354              } else if ((c == 'p')              } else if ((c == 'p')
2355                      && (strncmp(argv[i], "-pady", length) == 0)) {                      && (strncmp(argv[i], "-pady", length) == 0)) {
2356                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)                  if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
2357                          || (tmp< 0)) {                          || (tmp< 0)) {
2358                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
2359                      Tcl_AppendResult(interp, "bad pady value \"", argv[i+1],                      Tcl_AppendResult(interp, "bad pady value \"", argv[i+1],
2360                              "\": must be positive screen distance",                              "\": must be positive screen distance",
2361                              (char *) NULL);                              (char *) NULL);
2362                      return TCL_ERROR;                      return TCL_ERROR;
2363                  }                  }
2364                  slavePtr->padY = tmp*2;                  slavePtr->padY = tmp*2;
2365              } else if ((c == 'r') && (strncmp(argv[i], "-row", length) == 0)) {              } else if ((c == 'r') && (strncmp(argv[i], "-row", length) == 0)) {
2366                  if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) {                  if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) {
2367                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
2368                      Tcl_AppendResult(interp, "bad grid value \"", argv[i+1],                      Tcl_AppendResult(interp, "bad grid value \"", argv[i+1],
2369                              "\": must be a non-negative integer", (char *)NULL);                              "\": must be a non-negative integer", (char *)NULL);
2370                      return TCL_ERROR;                      return TCL_ERROR;
2371                  }                  }
2372                  slavePtr->row = tmp;                  slavePtr->row = tmp;
2373              } else if ((c == 'r')              } else if ((c == 'r')
2374                      && (strncmp(argv[i], "-rowspan", length) == 0)) {                      && (strncmp(argv[i], "-rowspan", length) == 0)) {
2375                  if ((Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK) || tmp<=0) {                  if ((Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK) || tmp<=0) {
2376                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
2377                      Tcl_AppendResult(interp, "bad rowspan value \"", argv[i+1],                      Tcl_AppendResult(interp, "bad rowspan value \"", argv[i+1],
2378                              "\": must be a positive integer", (char *)NULL);                              "\": must be a positive integer", (char *)NULL);
2379                      return TCL_ERROR;                      return TCL_ERROR;
2380                  }                  }
2381                  slavePtr->numRows = tmp;                  slavePtr->numRows = tmp;
2382              } else if ((c == 's')              } else if ((c == 's')
2383                      && strncmp(argv[i], "-sticky", length) == 0) {                      && strncmp(argv[i], "-sticky", length) == 0) {
2384                  int sticky = StringToSticky(argv[i+1]);                  int sticky = StringToSticky(argv[i+1]);
2385                  if (sticky == -1) {                  if (sticky == -1) {
2386                      Tcl_AppendResult(interp, "bad stickyness value \"", argv[i+1],                      Tcl_AppendResult(interp, "bad stickyness value \"", argv[i+1],
2387                              "\": must be a string containing n, e, s, and/or w",                              "\": must be a string containing n, e, s, and/or w",
2388                              (char *)NULL);                              (char *)NULL);
2389                      return TCL_ERROR;                      return TCL_ERROR;
2390                  }                  }
2391                  slavePtr->sticky = sticky;                  slavePtr->sticky = sticky;
2392              } else {              } else {
2393                  Tcl_AppendResult(interp, "unknown or ambiguous option \"",                  Tcl_AppendResult(interp, "unknown or ambiguous option \"",
2394                          argv[i], "\": must be ",                          argv[i], "\": must be ",
2395                          "-column, -columnspan, -in, -ipadx, -ipady, ",                          "-column, -columnspan, -in, -ipadx, -ipady, ",
2396                          "-padx, -pady, -row, -rowspan, or -sticky",                          "-padx, -pady, -row, -rowspan, or -sticky",
2397                          (char *) NULL);                          (char *) NULL);
2398                  return TCL_ERROR;                  return TCL_ERROR;
2399              }              }
2400          }          }
2401    
2402          /*          /*
2403           * Make sure we have a geometry master.  We look at:           * Make sure we have a geometry master.  We look at:
2404           *  1)   the -in flag           *  1)   the -in flag
2405           *  2)   the geometry master of the first slave (if specified)           *  2)   the geometry master of the first slave (if specified)
2406           *  3)   the parent of the first slave.           *  3)   the parent of the first slave.
2407           */           */
2408            
2409          if (masterPtr == NULL) {          if (masterPtr == NULL) {
2410              masterPtr = slavePtr->masterPtr;              masterPtr = slavePtr->masterPtr;
2411          }          }
2412          parent = Tk_Parent(slave);          parent = Tk_Parent(slave);
2413          if (masterPtr == NULL) {          if (masterPtr == NULL) {
2414              masterPtr = GetGrid(parent);              masterPtr = GetGrid(parent);
2415              InitMasterData(masterPtr);              InitMasterData(masterPtr);
2416          }          }
2417    
2418          if (slavePtr->masterPtr != NULL && slavePtr->masterPtr != masterPtr) {          if (slavePtr->masterPtr != NULL && slavePtr->masterPtr != masterPtr) {
2419              Unlink(slavePtr);              Unlink(slavePtr);
2420              slavePtr->masterPtr = NULL;              slavePtr->masterPtr = NULL;
2421          }          }
2422    
2423          if (slavePtr->masterPtr == NULL) {          if (slavePtr->masterPtr == NULL) {
2424              Gridder *tempPtr = masterPtr->slavePtr;              Gridder *tempPtr = masterPtr->slavePtr;
2425              slavePtr->masterPtr = masterPtr;              slavePtr->masterPtr = masterPtr;
2426              masterPtr->slavePtr = slavePtr;              masterPtr->slavePtr = slavePtr;
2427              slavePtr->nextPtr = tempPtr;              slavePtr->nextPtr = tempPtr;
2428          }          }
2429    
2430          /*          /*
2431           * Make sure that the slave's parent is either the master or           * Make sure that the slave's parent is either the master or
2432           * an ancestor of the master, and that the master and slave           * an ancestor of the master, and that the master and slave
2433           * aren't the same.           * aren't the same.
2434           */           */
2435    
2436          for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {          for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
2437              if (ancestor == parent) {              if (ancestor == parent) {
2438                  break;                  break;
2439              }              }
2440              if (Tk_IsTopLevel(ancestor)) {              if (Tk_IsTopLevel(ancestor)) {
2441                  Tcl_AppendResult(interp, "can't put ", argv[j],                  Tcl_AppendResult(interp, "can't put ", argv[j],
2442                          " inside ", Tk_PathName(masterPtr->tkwin),                          " inside ", Tk_PathName(masterPtr->tkwin),
2443                          (char *) NULL);                          (char *) NULL);
2444                  Unlink(slavePtr);                  Unlink(slavePtr);
2445                  return TCL_ERROR;                  return TCL_ERROR;
2446              }              }
2447          }          }
2448    
2449          /*          /*
2450           * Try to make sure our master isn't managed by us.           * Try to make sure our master isn't managed by us.
2451           */           */
2452    
2453          if (masterPtr->masterPtr == slavePtr) {          if (masterPtr->masterPtr == slavePtr) {
2454              Tcl_AppendResult(interp, "can't put ", argv[j],              Tcl_AppendResult(interp, "can't put ", argv[j],
2455                      " inside ", Tk_PathName(masterPtr->tkwin),                      " inside ", Tk_PathName(masterPtr->tkwin),
2456                      ", would cause management loop.",                      ", would cause management loop.",
2457                      (char *) NULL);                      (char *) NULL);
2458              Unlink(slavePtr);              Unlink(slavePtr);
2459              return TCL_ERROR;              return TCL_ERROR;
2460          }          }
2461    
2462          Tk_ManageGeometry(slave, &gridMgrType, (ClientData) slavePtr);          Tk_ManageGeometry(slave, &gridMgrType, (ClientData) slavePtr);
2463    
2464          /*          /*
2465           * Assign default position information.           * Assign default position information.
2466           */           */
2467    
2468          if (slavePtr->column == -1) {          if (slavePtr->column == -1) {
2469              slavePtr->column = defaultColumn;              slavePtr->column = defaultColumn;
2470          }          }
2471          slavePtr->numCols += defaultColumnSpan - 1;          slavePtr->numCols += defaultColumnSpan - 1;
2472          if (slavePtr->row == -1) {          if (slavePtr->row == -1) {
2473              if (masterPtr->masterDataPtr == NULL) {              if (masterPtr->masterDataPtr == NULL) {
2474                  slavePtr->row = 0;                  slavePtr->row = 0;
2475              } else {              } else {
2476                  slavePtr->row = masterPtr->masterDataPtr->rowEnd;                  slavePtr->row = masterPtr->masterDataPtr->rowEnd;
2477              }              }
2478          }          }
2479          defaultColumn += slavePtr->numCols;          defaultColumn += slavePtr->numCols;
2480          defaultColumnSpan = 1;          defaultColumnSpan = 1;
2481