tkGrid.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:94k
源码类别:

通讯编程

开发平台:

Visual C++

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