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

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkPanedWindow.c --
  3.  *
  4.  * This module implements "paned window" widgets that are object
  5.  * based.  A "paned window" is a widget that manages the geometry for
  6.  * some number of other widgets, placing a movable "sash" between them,
  7.  * which can be used to alter the relative sizes of adjacent widgets.
  8.  *
  9.  * Copyright (c) 1997 Sun Microsystems, Inc.
  10.  * Copyright (c) 2000 Ajuba Solutions.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * RCS: @(#) $Id: tkPanedWindow.c,v 1.13.2.11 2007/04/29 02:24:02 das Exp $
  16.  */
  17. #include "tkPort.h"
  18. #include "default.h"
  19. #include "tkInt.h"
  20. /* Flag values for "sticky"ness  The 16 combinations subsume the packer's
  21.  * notion of anchor and fill.
  22.  *
  23.  * STICK_NORTH   This window sticks to the top of its cavity.
  24.  * STICK_EAST This window sticks to the right edge of its cavity.
  25.  * STICK_SOUTH This window sticks to the bottom of its cavity.
  26.  * STICK_WEST This window sticks to the left edge of its cavity.
  27.  */
  28. #define STICK_NORTH 1
  29. #define STICK_EAST 2
  30. #define STICK_SOUTH 4
  31. #define STICK_WEST 8
  32. /*
  33.  * The following table defines the legal values for the -orient option.
  34.  */
  35. static char *orientStrings[] = {
  36.     "horizontal", "vertical", (char *) NULL
  37. };
  38. enum orient { ORIENT_HORIZONTAL, ORIENT_VERTICAL };
  39. typedef struct {
  40.     Tk_OptionTable pwOptions; /* Token for paned window option table. */
  41.     Tk_OptionTable slaveOpts; /* Token for slave cget option table. */
  42. } OptionTables;
  43. /*
  44.  * One structure of the following type is kept for each window
  45.  * managed by a paned window widget.
  46.  */
  47. typedef struct Slave {
  48.     Tk_Window tkwin; /* Window being managed. */
  49.     
  50.     int minSize; /* Minimum size of this pane, on the
  51.  * relevant axis, in pixels. */
  52.     int padx; /* Additional padding requested for
  53.  * slave, in the x dimension. */
  54.     int pady; /* Additional padding requested for
  55.  * slave, in the y dimension. */
  56.     Tcl_Obj *widthPtr, *heightPtr; /* Tcl_Obj rep's of slave width/height,
  57.  * to allow for null values. */
  58.     int width; /* Slave width. */
  59.     int height; /* Slave height. */
  60.     int sticky; /* Sticky string. */
  61.     int x, y; /* Coordinates of the widget. */
  62.     int paneWidth, paneHeight; /* Pane dimensions (may be different
  63.  * from slave width/height). */
  64.     int sashx, sashy; /* Coordinates of the sash of the
  65.  * right or bottom of this pane. */
  66.     int markx, marky; /* Coordinates of the last mark set
  67.  * for the sash. */
  68.     int handlex, handley; /* Coordinates of the sash handle. */
  69.     struct PanedWindow *masterPtr; /* Paned window managing the window. */
  70.     Tk_Window after; /* Placeholder for parsing options. */
  71.     Tk_Window before; /* Placeholder for parsing options. */
  72. } Slave;
  73. /*
  74.  * A data structure of the following type is kept for each paned window
  75.  * widget managed by this file:
  76.  */
  77. typedef struct PanedWindow {
  78.     Tk_Window tkwin; /* Window that embodies the paned window. */
  79.     Tk_Window proxywin; /* Window for the resizing proxy. */
  80.     Display *display; /* X's token for the window's display. */
  81.     Tcl_Interp *interp; /* Interpreter associated with widget. */
  82.     Tcl_Command widgetCmd; /* Token for square's widget command. */
  83.     Tk_OptionTable optionTable; /* Token representing the configuration
  84.  * specifications. */
  85.     Tk_OptionTable slaveOpts; /* Token for slave cget table. */
  86.     Tk_3DBorder background; /* Background color. */
  87.     int borderWidth; /* Value of -borderwidth option. */
  88.     int relief; /* 3D border effect (TK_RELIEF_RAISED, etc) */
  89.     Tcl_Obj *widthPtr; /* Tcl_Obj rep for width. */
  90.     Tcl_Obj *heightPtr; /* Tcl_Obj rep for height. */
  91.     int width, height; /* Width and height of the widget. */
  92.     enum orient orient; /* Orientation of the widget. */
  93.     Tk_Cursor cursor; /* Current cursor for window, or None. */
  94.     int resizeOpaque; /* Boolean indicating whether resize should be
  95.  * opaque or rubberband style. */
  96.     
  97.     int sashRelief; /* Relief used to draw sash. */
  98.     int sashWidth; /* Width of each sash, in pixels. */
  99.     Tcl_Obj *sashWidthPtr; /* Tcl_Obj rep for sash width. */
  100.     int sashPad; /* Additional padding around each sash. */
  101.     Tcl_Obj *sashPadPtr; /* Tcl_Obj rep for sash padding. */
  102.     int showHandle; /* Boolean indicating whether sash handles
  103.  * should be drawn. */
  104.     int handleSize; /* Size of one side of a sash handle (handles
  105.  * are square), in pixels. */
  106.     int handlePad; /* Distance from border to draw handle. */
  107.     Tcl_Obj *handleSizePtr; /* Tcl_Obj rep for handle size. */
  108.     Tk_Cursor sashCursor; /* Cursor used when mouse is above a sash. */
  109.     GC gc; /* Graphics context for copying from
  110.  * off-screen pixmap onto screen. */
  111.     int proxyx, proxyy; /* Proxy x,y coordinates. */
  112.     Slave **slaves; /* Pointer to array of Slaves. */
  113.     int numSlaves; /* Number of slaves. */
  114.     int sizeofSlaves; /* Number of elements in the slaves array. */
  115.     int flags; /* Flags for widget; see below. */
  116. } PanedWindow;
  117. /*
  118.  * Flags used for paned windows:
  119.  *
  120.  * REDRAW_PENDING: Non-zero means a DoWhenIdle handler has
  121.  * been queued to redraw this window.
  122.  *
  123.  * WIDGET_DELETED: Non-zero means that the paned window has
  124.  * been, or is in the process of being, deleted.
  125.  *
  126.  * RESIZE_PENDING: Non-zero means that the window might need to
  127.  * change its size (or the size of its panes)
  128.  * because of a change in the size of one of its
  129.  * children.
  130.  */
  131. #define REDRAW_PENDING 0x0001
  132. #define WIDGET_DELETED 0x0002
  133. #define REQUESTED_RELAYOUT 0x0004
  134. #define RECOMPUTE_GEOMETRY 0x0008
  135. #define PROXY_REDRAW_PENDING 0x0010
  136. #define RESIZE_PENDING 0x0020
  137. /*
  138.  * Forward declarations for procedures defined later in this file:
  139.  */
  140. int Tk_PanedWindowObjCmd _ANSI_ARGS_((ClientData clientData,
  141. Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]));
  142. static void PanedWindowCmdDeletedProc _ANSI_ARGS_((ClientData clientData));
  143. static int ConfigurePanedWindow _ANSI_ARGS_((Tcl_Interp *interp,
  144. PanedWindow *pwPtr, int objc, Tcl_Obj *CONST objv[]));
  145. static void DestroyPanedWindow _ANSI_ARGS_((PanedWindow *pwPtr));
  146. static void DisplayPanedWindow _ANSI_ARGS_((ClientData clientData));
  147. static void PanedWindowEventProc _ANSI_ARGS_((ClientData clientData,
  148. XEvent *eventPtr));
  149. static void ProxyWindowEventProc _ANSI_ARGS_((ClientData clientData,
  150. XEvent *eventPtr));
  151. static void DisplayProxyWindow _ANSI_ARGS_((ClientData clientData));
  152. static void PanedWindowWorldChanged _ANSI_ARGS_((ClientData instanceData));
  153. static int PanedWindowWidgetObjCmd _ANSI_ARGS_((ClientData clientData,
  154. Tcl_Interp *, int objc, Tcl_Obj * CONST objv[]));
  155. static void PanedWindowLostSlaveProc _ANSI_ARGS_((ClientData clientData,
  156. Tk_Window tkwin));
  157. static void PanedWindowReqProc _ANSI_ARGS_((ClientData clientData,
  158. Tk_Window tkwin));
  159. static void ArrangePanes _ANSI_ARGS_((ClientData clientData));
  160. static void Unlink _ANSI_ARGS_((Slave *slavePtr));
  161. static Slave * GetPane _ANSI_ARGS_((PanedWindow *pwPtr, Tk_Window tkwin));
  162. static void SlaveStructureProc _ANSI_ARGS_((ClientData clientData,
  163. XEvent *eventPtr));
  164. static int PanedWindowSashCommand _ANSI_ARGS_((PanedWindow *pwPtr,
  165. Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]));
  166. static int PanedWindowProxyCommand _ANSI_ARGS_((PanedWindow *pwPtr,
  167. Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]));
  168. static void ComputeGeometry _ANSI_ARGS_((PanedWindow *pwPtr));
  169. static int ConfigureSlaves _ANSI_ARGS_((PanedWindow *pwPtr,
  170. Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]));
  171. static void DestroyOptionTables _ANSI_ARGS_((ClientData clientData,
  172. Tcl_Interp *interp));
  173. static int SetSticky _ANSI_ARGS_((ClientData clientData,
  174. Tcl_Interp *interp, Tk_Window tkwin,
  175. Tcl_Obj **value, char *recordPtr, int internalOffset,
  176. char *oldInternalPtr, int flags));
  177. static Tcl_Obj *GetSticky _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin,
  178. char *recordPtr, int internalOffset));
  179. static void RestoreSticky _ANSI_ARGS_((ClientData clientData,
  180. Tk_Window tkwin, char *internalPtr,
  181. char *oldInternalPtr));
  182. static void AdjustForSticky _ANSI_ARGS_((int sticky, int cavityWidth,
  183. int cavityHeight, int *xPtr, int *yPtr,
  184. int *slaveWidthPtr, int *slaveHeightPtr));
  185. static void MoveSash _ANSI_ARGS_((PanedWindow *pwPtr, int sash, int diff));
  186. static int ObjectIsEmpty _ANSI_ARGS_((Tcl_Obj *objPtr));
  187. static char * ComputeSlotAddress _ANSI_ARGS_((char *recordPtr, int offset));
  188. static int PanedWindowIdentifyCoords _ANSI_ARGS_((PanedWindow *pwPtr,
  189. Tcl_Interp *interp, int x, int y));
  190. /*
  191.  * Sashes are between panes only, so there is one less sash than slaves
  192.  */
  193. #define ValidSashIndex(pwPtr, sash) 
  194. (((sash) >= 0) && ((sash) < ((pwPtr)->numSlaves-1)))
  195. static Tk_GeomMgr panedWindowMgrType = {
  196.     "panedwindow", /* name */
  197.     PanedWindowReqProc, /* requestProc */
  198.     PanedWindowLostSlaveProc, /* lostSlaveProc */
  199. };
  200. /*
  201.  * Information used for objv parsing.
  202.  */
  203. #define GEOMETRY 0x0001
  204. /*
  205.  * The following structure contains pointers to functions used for processing
  206.  * the custom "-sticky" option for slave windows.
  207.  */
  208. static Tk_ObjCustomOption stickyOption = {
  209.     "sticky", /* name */
  210.     SetSticky, /* setProc */
  211.     GetSticky, /* getProc */
  212.     RestoreSticky, /* restoreProc */
  213.     (Tk_CustomOptionFreeProc *)NULL, /* freeProc */
  214.     0
  215. };
  216. static Tk_OptionSpec optionSpecs[] = {
  217.     {TK_OPTION_BORDER, "-background", "background", "Background",
  218.  DEF_PANEDWINDOW_BG_COLOR, -1, Tk_Offset(PanedWindow, background), 0,
  219.  (ClientData) DEF_PANEDWINDOW_BG_MONO},
  220.     {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
  221.  (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth"},
  222.     {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
  223.  (char *) NULL, 0, -1, 0, (ClientData) "-background"},
  224.     {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  225.  DEF_PANEDWINDOW_BORDERWIDTH, -1, Tk_Offset(PanedWindow, borderWidth),
  226.          0, 0, GEOMETRY},
  227.     {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
  228.  DEF_PANEDWINDOW_CURSOR, -1, Tk_Offset(PanedWindow, cursor),
  229.  TK_OPTION_NULL_OK, 0, 0},
  230.     {TK_OPTION_PIXELS, "-handlepad", "handlePad", "HandlePad",
  231.  DEF_PANEDWINDOW_HANDLEPAD, -1, Tk_Offset(PanedWindow, handlePad),
  232.          0, 0, GEOMETRY},
  233.     {TK_OPTION_PIXELS, "-handlesize", "handleSize", "HandleSize",
  234.  DEF_PANEDWINDOW_HANDLESIZE, Tk_Offset(PanedWindow, handleSizePtr),
  235.  Tk_Offset(PanedWindow, handleSize), 0, 0, GEOMETRY},
  236.     {TK_OPTION_PIXELS, "-height", "height", "Height",
  237.  DEF_PANEDWINDOW_HEIGHT, Tk_Offset(PanedWindow, heightPtr),
  238.  Tk_Offset(PanedWindow, height), TK_OPTION_NULL_OK, 0, GEOMETRY},
  239.     {TK_OPTION_BOOLEAN, "-opaqueresize", "opaqueResize", "OpaqueResize",
  240.  DEF_PANEDWINDOW_OPAQUERESIZE, -1,
  241.          Tk_Offset(PanedWindow, resizeOpaque), 0, 0, 0},
  242.     {TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient",
  243.  DEF_PANEDWINDOW_ORIENT, -1, Tk_Offset(PanedWindow, orient), 
  244.  0, (ClientData) orientStrings, GEOMETRY},
  245.     {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
  246.  DEF_PANEDWINDOW_RELIEF, -1, Tk_Offset(PanedWindow, relief), 0, 0, 0},
  247.     {TK_OPTION_CURSOR, "-sashcursor", "sashCursor", "Cursor",
  248.  DEF_PANEDWINDOW_SASHCURSOR, -1, Tk_Offset(PanedWindow, sashCursor),
  249.  TK_OPTION_NULL_OK, 0, 0},
  250.     {TK_OPTION_PIXELS, "-sashpad", "sashPad", "SashPad",
  251.  DEF_PANEDWINDOW_SASHPAD, -1, Tk_Offset(PanedWindow, sashPad),
  252.          0, 0, GEOMETRY},
  253.     {TK_OPTION_RELIEF, "-sashrelief", "sashRelief", "Relief",
  254.  DEF_PANEDWINDOW_SASHRELIEF, -1, Tk_Offset(PanedWindow, sashRelief),
  255.          0, 0, 0},
  256.     {TK_OPTION_PIXELS, "-sashwidth", "sashWidth", "Width",
  257.  DEF_PANEDWINDOW_SASHWIDTH, Tk_Offset(PanedWindow, sashWidthPtr),
  258.  Tk_Offset(PanedWindow, sashWidth), 0, 0, GEOMETRY},
  259.     {TK_OPTION_BOOLEAN, "-showhandle", "showHandle", "ShowHandle",
  260.  DEF_PANEDWINDOW_SHOWHANDLE, -1, Tk_Offset(PanedWindow, showHandle),
  261.          0, 0, GEOMETRY},
  262.     {TK_OPTION_PIXELS, "-width", "width", "Width",
  263.  DEF_PANEDWINDOW_WIDTH, Tk_Offset(PanedWindow, widthPtr),
  264.  Tk_Offset(PanedWindow, width), TK_OPTION_NULL_OK, 0, GEOMETRY},
  265.     {TK_OPTION_END}
  266. };
  267. static Tk_OptionSpec slaveOptionSpecs[] = {
  268.     {TK_OPTION_WINDOW, "-after", (char *) NULL, (char *) NULL,
  269.  DEF_PANEDWINDOW_PANE_AFTER, -1, Tk_Offset(Slave, after),
  270.          TK_OPTION_NULL_OK, 0, 0},
  271.     {TK_OPTION_WINDOW, "-before", (char *) NULL, (char *) NULL,
  272.          DEF_PANEDWINDOW_PANE_BEFORE, -1, Tk_Offset(Slave, before),
  273.          TK_OPTION_NULL_OK, 0, 0},
  274.     {TK_OPTION_PIXELS, "-height", (char *) NULL, (char *) NULL,
  275.  DEF_PANEDWINDOW_PANE_HEIGHT, Tk_Offset(Slave, heightPtr),
  276.          Tk_Offset(Slave, height), TK_OPTION_NULL_OK, 0, 0},
  277.     {TK_OPTION_PIXELS, "-minsize", (char *) NULL, (char *) NULL,
  278.  DEF_PANEDWINDOW_PANE_MINSIZE, -1, Tk_Offset(Slave, minSize), 0, 0, 0},
  279.     {TK_OPTION_PIXELS, "-padx", (char *) NULL, (char *) NULL,
  280.  DEF_PANEDWINDOW_PANE_PADX, -1, Tk_Offset(Slave, padx), 0, 0, 0},
  281.     {TK_OPTION_PIXELS, "-pady", (char *) NULL, (char *) NULL,
  282.  DEF_PANEDWINDOW_PANE_PADY, -1, Tk_Offset(Slave, pady), 0, 0, 0},
  283.     {TK_OPTION_CUSTOM, "-sticky", (char *) NULL, (char *) NULL,
  284.  DEF_PANEDWINDOW_PANE_STICKY, -1, Tk_Offset(Slave, sticky), 0,
  285.          (ClientData) &stickyOption, 0},
  286.     {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL,
  287.  DEF_PANEDWINDOW_PANE_WIDTH, Tk_Offset(Slave, widthPtr),
  288.          Tk_Offset(Slave, width), TK_OPTION_NULL_OK, 0, 0},
  289.     {TK_OPTION_END}
  290. };
  291.     
  292. /*
  293.  *--------------------------------------------------------------
  294.  *
  295.  * Tk_PanedWindowObjCmd --
  296.  *
  297.  * This procedure is invoked to process the "panedwindow" Tcl
  298.  * command.  It creates a new "panedwindow" widget.
  299.  *
  300.  * Results:
  301.  * A standard Tcl result.
  302.  *
  303.  * Side effects:
  304.  * A new widget is created and configured.
  305.  *
  306.  *--------------------------------------------------------------
  307.  */
  308. int
  309. Tk_PanedWindowObjCmd(clientData, interp, objc, objv)
  310.     ClientData clientData; /* NULL. */
  311.     Tcl_Interp *interp; /* Current interpreter. */
  312.     int objc; /* Number of arguments. */
  313.     Tcl_Obj * CONST objv[]; /* Argument objects. */
  314. {
  315.     PanedWindow *pwPtr;
  316.     Tk_Window tkwin, parent;
  317.     OptionTables *pwOpts;
  318.     XSetWindowAttributes atts;
  319.     if (objc < 2) {
  320. Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
  321. return TCL_ERROR;
  322.     }
  323.     tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), 
  324.     Tcl_GetStringFromObj(objv[1], NULL), NULL);
  325.     if (tkwin == NULL) {
  326. return TCL_ERROR;
  327.     }
  328.     pwOpts = (OptionTables *)
  329. Tcl_GetAssocData(interp, "PanedWindowOptionTables", NULL);
  330.     if (pwOpts == NULL) {
  331. /*
  332.  * The first time this procedure is invoked, the option tables will
  333.  * be NULL.  We then create the option tables from the templates
  334.  * and store a pointer to the tables as the command's clinical so
  335.  * we'll have easy access to it in the future.
  336.  */
  337. pwOpts = (OptionTables *) ckalloc(sizeof(OptionTables));
  338. /* Set up an exit handler to free the optionTables struct */
  339. Tcl_SetAssocData(interp, "PanedWindowOptionTables",
  340. DestroyOptionTables, (ClientData) pwOpts);
  341. /* Create the paned window option tables. */
  342. pwOpts->pwOptions = Tk_CreateOptionTable(interp, optionSpecs);
  343. pwOpts->slaveOpts = Tk_CreateOptionTable(interp, slaveOptionSpecs);
  344.     }
  345.     Tk_SetClass(tkwin, "Panedwindow");
  346.     /*
  347.      * Allocate and initialize the widget record.
  348.      */
  349.     pwPtr = (PanedWindow *) ckalloc(sizeof(PanedWindow));
  350.     memset((void *)pwPtr, 0, (sizeof(PanedWindow)));
  351.     pwPtr->tkwin = tkwin;
  352.     pwPtr->display = Tk_Display(tkwin);
  353.     pwPtr->interp = interp;
  354.     pwPtr->widgetCmd = Tcl_CreateObjCommand(interp,
  355.     Tk_PathName(pwPtr->tkwin), PanedWindowWidgetObjCmd,
  356.     (ClientData) pwPtr, PanedWindowCmdDeletedProc);
  357.     pwPtr->optionTable = pwOpts->pwOptions;
  358.     pwPtr->slaveOpts = pwOpts->slaveOpts;
  359.     pwPtr->relief = TK_RELIEF_RAISED;
  360.     pwPtr->gc = None;
  361.     pwPtr->cursor = None;
  362.     pwPtr->sashCursor = None;
  363.     /*
  364.      * Keep a hold of the associated tkwin until we destroy the widget,
  365.      * otherwise Tk might free it while we still need it.
  366.      */
  367.     Tcl_Preserve((ClientData) pwPtr->tkwin);
  368.     if (Tk_InitOptions(interp, (char *) pwPtr, pwOpts->pwOptions,
  369.     tkwin) != TCL_OK) {
  370. Tk_DestroyWindow(pwPtr->tkwin);
  371. return TCL_ERROR;
  372.     }
  373.     Tk_CreateEventHandler(pwPtr->tkwin, ExposureMask|StructureNotifyMask,
  374.     PanedWindowEventProc, (ClientData) pwPtr);
  375.     /*
  376.      * Find the toplevel ancestor of the panedwindow, and make a proxy
  377.      * win as a child of that window; this way the proxy can always float
  378.      * above slaves in the panedwindow.
  379.      */
  380.     parent = Tk_Parent(pwPtr->tkwin);
  381.     while (!(Tk_IsTopLevel(parent))) {
  382. parent = Tk_Parent(parent);
  383. if (parent == NULL) {
  384.     parent = pwPtr->tkwin;
  385.     break;
  386. }
  387.     }
  388.     pwPtr->proxywin = Tk_CreateAnonymousWindow(interp, parent, (char *) NULL);
  389.     /*
  390.      * The proxy window has to be able to share GCs with the main
  391.      * panedwindow despite being children of windows with potentially
  392.      * different characteristics, and it looks better that way too.
  393.      * [Bug 702230]
  394.      * Also Set the X window save under attribute to avoid expose events as
  395.      * the proxy sash is dragged across the panes.  [Bug 1036963]
  396.      */
  397.     Tk_SetWindowVisual(pwPtr->proxywin,
  398.     Tk_Visual(tkwin), Tk_Depth(tkwin), Tk_Colormap(tkwin));
  399.     Tk_CreateEventHandler(pwPtr->proxywin, ExposureMask, ProxyWindowEventProc,
  400.     (ClientData) pwPtr);
  401.     atts.save_under = True;
  402.     Tk_ChangeWindowAttributes(pwPtr->proxywin, CWSaveUnder, &atts);
  403.     if (ConfigurePanedWindow(interp, pwPtr, objc - 2, objv + 2) != TCL_OK) {
  404. Tk_DestroyWindow(pwPtr->proxywin);
  405. Tk_DestroyWindow(pwPtr->tkwin);
  406. return TCL_ERROR;
  407.     }
  408.     Tcl_SetStringObj(Tcl_GetObjResult(interp), Tk_PathName(pwPtr->tkwin), -1);
  409.     return TCL_OK;
  410. }
  411. /*
  412.  *--------------------------------------------------------------
  413.  *
  414.  * PanedWindowWidgetObjCmd --
  415.  *
  416.  * This procedure is invoked to process the Tcl command
  417.  * that corresponds to a widget managed by this module.
  418.  * See the user documentation for details on what it does.
  419.  *
  420.  * Results:
  421.  * A standard Tcl result.
  422.  *
  423.  * Side effects:
  424.  * See the user documentation.
  425.  *
  426.  *--------------------------------------------------------------
  427.  */
  428. static int
  429. PanedWindowWidgetObjCmd(clientData, interp, objc, objv)
  430.     ClientData clientData; /* Information about square widget. */
  431.     Tcl_Interp *interp; /* Current interpreter. */
  432.     int objc; /* Number of arguments. */
  433.     Tcl_Obj * CONST objv[]; /* Argument objects. */
  434. {
  435.     PanedWindow *pwPtr = (PanedWindow *) clientData;
  436.     int result = TCL_OK;
  437.     static CONST char *optionStrings[] = {"add", "cget", "configure", "forget",
  438. "identify", "panecget",
  439.                                         "paneconfigure", "panes",
  440.                                         "proxy", "sash", (char *) NULL};
  441.     enum options { PW_ADD, PW_CGET, PW_CONFIGURE, PW_FORGET, PW_IDENTIFY,
  442.        PW_PANECGET, PW_PANECONFIGURE, PW_PANES, PW_PROXY,
  443.                        PW_SASH };
  444.     Tcl_Obj *resultObj;
  445.     int index, count, i, x, y;
  446.     Tk_Window tkwin;
  447.     Slave *slavePtr;
  448.     
  449.     if (objc < 2) {
  450. Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg...?");
  451. return TCL_ERROR;
  452.     }
  453.     if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "command",
  454.     0, &index) != TCL_OK) {
  455. return TCL_ERROR;
  456.     }
  457.     Tcl_Preserve((ClientData) pwPtr);
  458.     
  459.     switch ((enum options) index) {
  460. case PW_ADD: {
  461.     if (objc < 3) {
  462. Tcl_WrongNumArgs(interp, 2, objv, "widget ?widget ...?");
  463. result = TCL_ERROR;
  464. break;
  465.     }
  466.     
  467.     result = ConfigureSlaves(pwPtr, interp, objc, objv);
  468.     break;
  469. }
  470. case PW_CGET: {
  471.     if (objc != 3) {
  472. Tcl_WrongNumArgs(interp, 2, objv, "option");
  473. result = TCL_ERROR;
  474. break;
  475.     }
  476.     resultObj = Tk_GetOptionValue(interp, (char *) pwPtr,
  477.     pwPtr->optionTable, objv[2], pwPtr->tkwin);
  478.     if (resultObj == NULL) {
  479. result = TCL_ERROR;
  480.     } else {
  481. Tcl_SetObjResult(interp, resultObj);
  482.     }
  483.     break;
  484. }
  485. case PW_CONFIGURE: {
  486.     resultObj = NULL;
  487.     if (objc <= 3) {
  488. resultObj = Tk_GetOptionInfo(interp, (char *) pwPtr,
  489. pwPtr->optionTable,
  490. (objc == 3) ? objv[2] : (Tcl_Obj *) NULL,
  491. pwPtr->tkwin);
  492. if (resultObj == NULL) {
  493.     result = TCL_ERROR;
  494. } else {
  495.     Tcl_SetObjResult(interp, resultObj);
  496. }
  497.     } else {
  498. result = ConfigurePanedWindow(interp, pwPtr, objc - 2,
  499. objv + 2);
  500.     }
  501.     break;
  502. }
  503. case PW_FORGET: {
  504.     Tk_Window slave;
  505.     int i;
  506.     
  507.     if (objc < 3) {
  508. Tcl_WrongNumArgs(interp, 2, objv, "widget ?widget ...?");
  509. result = TCL_ERROR;
  510. break;
  511.     }
  512.     /*
  513.      * Clean up each window named in the arg list.
  514.      */
  515.     for (count = 0, i = 2; i < objc; i++) {
  516. slave = Tk_NameToWindow(interp, Tcl_GetString(objv[i]),
  517. pwPtr->tkwin);
  518. if (slave == NULL) {
  519.     continue;
  520. }
  521. slavePtr = GetPane(pwPtr, slave);
  522. if ((slavePtr != NULL) && (slavePtr->masterPtr != NULL)) {
  523.     count++;
  524.     Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,
  525.     (ClientData) NULL);
  526.     Tk_UnmaintainGeometry(slavePtr->tkwin, pwPtr->tkwin);
  527.     Tk_DeleteEventHandler(slavePtr->tkwin, StructureNotifyMask,
  528.     SlaveStructureProc, (ClientData) slavePtr);
  529.     Tk_UnmapWindow(slavePtr->tkwin);
  530.     Unlink(slavePtr);
  531. }
  532. if (count != 0) {
  533.     ComputeGeometry(pwPtr);
  534. }
  535.     }
  536.     break;
  537. }
  538. case PW_IDENTIFY: {
  539.     if (objc != 4) {
  540. Tcl_WrongNumArgs(interp, 2, objv, "x y");
  541. result = TCL_ERROR;
  542. break;
  543.     }
  544.     if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK)
  545.     || (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) {
  546. result = TCL_ERROR;
  547. break;
  548.     }
  549.     
  550.     result = PanedWindowIdentifyCoords(pwPtr, interp, x, y);
  551.     break;
  552. }
  553. case PW_PANECGET: {
  554.     if (objc != 4) {
  555. Tcl_WrongNumArgs(interp, 2, objv, "pane option");
  556. result = TCL_ERROR;
  557. break;
  558.     }
  559.     tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[2]),
  560.     pwPtr->tkwin);
  561.     if (tkwin == NULL) {
  562. result = TCL_ERROR;
  563. break;
  564.     }
  565.     resultObj = NULL;
  566.     for (i = 0; i < pwPtr->numSlaves; i++) {
  567. if (pwPtr->slaves[i]->tkwin == tkwin) {
  568.     resultObj = Tk_GetOptionValue(interp,
  569.     (char *) pwPtr->slaves[i], pwPtr->slaveOpts,
  570.     objv[3], tkwin);
  571. }
  572.     }
  573.     if (i == pwPtr->numSlaves) {
  574. Tcl_SetResult(interp, "not managed by this window",
  575. TCL_STATIC);
  576.     }
  577.     if (resultObj == NULL) {
  578. result = TCL_ERROR;
  579.     } else {
  580. Tcl_SetObjResult(interp, resultObj);
  581.     }
  582.     break;
  583. }
  584. case PW_PANECONFIGURE: {
  585.     if (objc < 3) {
  586. Tcl_WrongNumArgs(interp, 2, objv,
  587. "pane ?option? ?value option value ...?");
  588. result = TCL_ERROR;
  589. break;
  590.     }
  591.     resultObj = NULL;
  592.     if (objc <= 4) {
  593. tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[2]),
  594. pwPtr->tkwin);
  595. for (i = 0; i < pwPtr->numSlaves; i++) {
  596.     if (pwPtr->slaves[i]->tkwin == tkwin) {
  597. resultObj = Tk_GetOptionInfo(interp,
  598. (char *) pwPtr->slaves[i],
  599. pwPtr->slaveOpts,
  600. (objc == 4) ? objv[3] : (Tcl_Obj *) NULL,
  601. pwPtr->tkwin);
  602. if (resultObj == NULL) {
  603.     result = TCL_ERROR;
  604. } else {
  605.     Tcl_SetObjResult(interp, resultObj);
  606. }
  607. break;
  608.     }
  609. }
  610.     } else {
  611. result = ConfigureSlaves(pwPtr, interp, objc, objv);
  612.     }
  613.     break;
  614. }
  615.     
  616. case PW_PANES: {
  617.     resultObj = Tcl_NewObj();
  618.     Tcl_IncrRefCount(resultObj);
  619.     for (i = 0; i < pwPtr->numSlaves; i++) {
  620. Tcl_ListObjAppendElement(interp, resultObj,
  621. Tcl_NewStringObj(Tk_PathName(pwPtr->slaves[i]->tkwin),
  622. -1));
  623.     }
  624.     Tcl_SetObjResult(interp, resultObj);
  625.     Tcl_DecrRefCount(resultObj);
  626.     break;
  627. }
  628. case PW_PROXY: {
  629.     result = PanedWindowProxyCommand(pwPtr, interp, objc, objv);
  630.     break;
  631. }
  632. case PW_SASH: {
  633.     result = PanedWindowSashCommand(pwPtr, interp, objc, objv);
  634.     break;
  635. }
  636.     }
  637.     Tcl_Release((ClientData) pwPtr);
  638.     return result;
  639. }
  640. /*
  641.  *----------------------------------------------------------------------
  642.  *
  643.  * ConfigureSlaves --
  644.  *
  645.  * Add or alter the configuration options of a slave in a paned
  646.  * window.
  647.  *
  648.  * Results:
  649.  * Standard Tcl result.
  650.  *
  651.  * Side effects:
  652.  * Depends on options; may add a slave to the paned window, may
  653.  * alter the geometry management options of a slave.
  654.  *
  655.  *----------------------------------------------------------------------
  656.  */
  657. static int
  658. ConfigureSlaves(pwPtr, interp, objc, objv)
  659.     PanedWindow *pwPtr; /* Information about paned window. */
  660.     Tcl_Interp *interp; /* Current interpreter. */
  661.     int objc; /* Number of arguments. */
  662.     Tcl_Obj * CONST objv[]; /* Argument objects. */
  663. {
  664.     int i, firstOptionArg, j, found, doubleBw, index, numNewSlaves, haveLoc;
  665.     int insertIndex;
  666.     Tk_Window tkwin = NULL, ancestor, parent;
  667.     Slave *slavePtr, **inserts, **new;
  668.     Slave options;
  669.     char *arg;
  670.    
  671.     /*
  672.      * Find the non-window name arguments; these are the configure options
  673.      * for the slaves.  Also validate that the window names given are
  674.      * legitimate (ie, they are real windows, they are not the panedwindow
  675.      * itself, etc.).
  676.      */
  677.     for (i = 2; i < objc; i++) {
  678. arg = Tcl_GetString(objv[i]);
  679. if (arg[0] == '-') {
  680.     break;
  681. } else {
  682.     tkwin = Tk_NameToWindow(interp, arg, pwPtr->tkwin);
  683.     if (tkwin == NULL) {
  684. /*
  685.  * Just a plain old bad window; Tk_NameToWindow filled in an
  686.  * error message for us.
  687.  */
  688. return TCL_ERROR;
  689.     } else if (tkwin == pwPtr->tkwin) {
  690. /*
  691.  * A panedwindow cannot manage itself.
  692.  */
  693. Tcl_ResetResult(interp);
  694. Tcl_AppendResult(interp, "can't add ", arg, " to itself",
  695. (char *) NULL);
  696. return TCL_ERROR;
  697.     } else if (Tk_IsTopLevel(tkwin)) {
  698. /*
  699.  * A panedwindow cannot manage a toplevel.
  700.  */
  701. Tcl_ResetResult(interp);
  702. Tcl_AppendResult(interp, "can't add toplevel ", arg, " to ",
  703. Tk_PathName(pwPtr->tkwin), (char *) NULL);
  704. return TCL_ERROR;
  705.     } else {
  706. /*
  707.  * Make sure the panedwindow is the parent of the slave,
  708.  * or a descendant of the slave's parent.
  709.  */
  710. parent = Tk_Parent(tkwin);
  711. for (ancestor = pwPtr->tkwin;;ancestor = Tk_Parent(ancestor)) {
  712.     if (ancestor == parent) {
  713. break;
  714.     }
  715.     if (Tk_IsTopLevel(ancestor)) {
  716. Tcl_ResetResult(interp);
  717. Tcl_AppendResult(interp, "can't add ", arg,
  718. " to ", Tk_PathName(pwPtr->tkwin),
  719. (char *) NULL);
  720. return TCL_ERROR;
  721.     }
  722. }
  723.     }
  724. }
  725.     }
  726.     firstOptionArg = i;
  727.     /*
  728.      * Pre-parse the configuration options, to get the before/after specifiers
  729.      * into an easy-to-find location (a local variable).  Also, check the
  730.      * return from Tk_SetOptions once, here, so we can save a little bit of
  731.      * extra testing in the for loop below.
  732.      */
  733.     memset((void *)&options, 0, sizeof(Slave));
  734.     if (Tk_SetOptions(interp, (char *) &options, pwPtr->slaveOpts,
  735.     objc - firstOptionArg, objv + firstOptionArg,
  736.     pwPtr->tkwin, NULL, NULL) != TCL_OK) {
  737. return TCL_ERROR;
  738.     }
  739.     /*
  740.      * If either -after or -before was given, find the numerical index that
  741.      * corresponds to the given window.  If both -after and -before are
  742.      * given, the option precedence is:  -after, then -before.
  743.      */
  744.     index = -1;
  745.     haveLoc = 0;
  746.     if (options.after != None) {
  747. tkwin = options.after;
  748. haveLoc = 1;
  749. for (i = 0; i < pwPtr->numSlaves; i++) {
  750.     if (options.after == pwPtr->slaves[i]->tkwin) {
  751. index = i + 1;
  752. break;
  753.     }
  754. }
  755.     } else if (options.before != None) {
  756. tkwin = options.before;
  757. haveLoc = 1;
  758. for (i = 0; i < pwPtr->numSlaves; i++) {
  759.     if (options.before == pwPtr->slaves[i]->tkwin) {
  760. index = i;
  761. break;
  762.     }
  763. }
  764.     }
  765.     /*
  766.      * If a window was given for -after/-before, but it's not a window
  767.      * managed by the panedwindow, throw an error
  768.      */
  769.     if (haveLoc && index == -1) {
  770. Tcl_ResetResult(interp);
  771. Tcl_AppendResult(interp, "window "", Tk_PathName(tkwin),
  772. "" is not managed by ", Tk_PathName(pwPtr->tkwin),
  773. (char *) NULL);
  774. Tk_FreeConfigOptions((char *) &options, pwPtr->slaveOpts,
  775. pwPtr->tkwin);
  776. return TCL_ERROR;
  777.     }
  778.     /*
  779.      * Allocate an array to hold, in order, the pointers to the slave
  780.      * structures corresponding to the windows specified.  Some of those
  781.      * structures may already have existed, some may be new.
  782.      */
  783.     inserts = (Slave **)ckalloc(sizeof(Slave *) * (firstOptionArg - 2));
  784.     insertIndex = 0;
  785.     
  786.     /*
  787.      * Populate the inserts array, creating new slave structures as necessary,
  788.      * applying the options to each structure as we go, and, if necessary,
  789.      * marking the spot in the original slaves array as empty (for pre-existing
  790.      * slave structures).
  791.      */
  792.     for (i = 0, numNewSlaves = 0; i < firstOptionArg - 2; i++) {
  793. /*
  794.  * We don't check that tkwin is NULL here, because the pre-pass above
  795.  * guarantees that the input at this stage is good.
  796.  */
  797. tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[i + 2]),
  798. pwPtr->tkwin);
  799. found = 0;
  800. for (j = 0; j < pwPtr->numSlaves; j++) {
  801.     if (pwPtr->slaves[j] != NULL && pwPtr->slaves[j]->tkwin == tkwin) {
  802. Tk_SetOptions(interp, (char *) pwPtr->slaves[j],
  803. pwPtr->slaveOpts, objc - firstOptionArg,
  804. objv + firstOptionArg, pwPtr->tkwin, NULL, NULL);
  805. if (pwPtr->slaves[j]->minSize < 0) {
  806.     pwPtr->slaves[j]->minSize = 0;
  807. }
  808. found = 1;
  809. /*
  810.  * If the slave is supposed to move, add it to the inserts
  811.  * array now; otherwise, leave it where it is.
  812.  */
  813. if (index != -1) {
  814.     inserts[insertIndex++] = pwPtr->slaves[j];
  815.     pwPtr->slaves[j] = NULL;
  816. }
  817. break;
  818.     }
  819. }
  820. if (found) {
  821.     continue;
  822. }
  823. /*
  824.  * Make sure this slave wasn't already put into the inserts array,
  825.  * ie, when the user specifies the same window multiple times in
  826.  * a single add commaned.
  827.  */
  828. for (j = 0; j < insertIndex; j++) {
  829.     if (inserts[j]->tkwin == tkwin) {
  830. found = 1;
  831. break;
  832.     }
  833. }
  834. if (found) {
  835.     continue;
  836. }
  837. /*
  838.  * Create a new slave structure and initialize it.  All slaves
  839.  * start out with their "natural" dimensions.
  840.  */
  841. slavePtr = (Slave *) ckalloc(sizeof(Slave));
  842. memset(slavePtr, 0, sizeof(Slave));
  843. Tk_InitOptions(interp, (char *)slavePtr, pwPtr->slaveOpts,
  844. pwPtr->tkwin);
  845. Tk_SetOptions(interp, (char *)slavePtr, pwPtr->slaveOpts,
  846. objc - firstOptionArg, objv + firstOptionArg,
  847. pwPtr->tkwin, NULL, NULL);
  848. slavePtr->tkwin = tkwin;
  849. slavePtr->masterPtr = pwPtr;
  850. doubleBw = 2 * Tk_Changes(slavePtr->tkwin)->border_width;
  851. if (slavePtr->width > 0) {
  852.     slavePtr->paneWidth = slavePtr->width;
  853. } else {
  854.     slavePtr->paneWidth = Tk_ReqWidth(tkwin) + doubleBw;
  855. }
  856. if (slavePtr->height > 0) {
  857.     slavePtr->paneHeight = slavePtr->height;
  858. } else {
  859.     slavePtr->paneHeight = Tk_ReqHeight(tkwin) + doubleBw;
  860. }
  861. if (slavePtr->minSize < 0) {
  862.     slavePtr->minSize = 0;
  863. }
  864. /*
  865.  * Set up the geometry management callbacks for this slave.
  866.  */
  867. Tk_CreateEventHandler(slavePtr->tkwin, StructureNotifyMask,
  868. SlaveStructureProc, (ClientData) slavePtr);
  869. Tk_ManageGeometry(slavePtr->tkwin, &panedWindowMgrType,
  870. (ClientData) slavePtr);
  871. inserts[insertIndex++] = slavePtr;
  872. numNewSlaves++;
  873.     }
  874.     /*
  875.      * Allocate the new slaves array, then copy the slaves into it, in
  876.      * order.
  877.      */
  878.     i = sizeof(Slave *) * (pwPtr->numSlaves+numNewSlaves);
  879.     new = (Slave **)ckalloc((unsigned) i);
  880.     memset(new, 0, (size_t) i);
  881.     if (index == -1) {
  882. /*
  883.  * If none of the existing slaves have to be moved, just copy the old
  884.  * and append the new.
  885.  */
  886. memcpy((void *)&(new[0]), pwPtr->slaves,
  887. sizeof(Slave *) * pwPtr->numSlaves);
  888. memcpy((void *)&(new[pwPtr->numSlaves]), inserts,
  889. sizeof(Slave *) * numNewSlaves);
  890.     } else {
  891. /*
  892.  * If some of the existing slaves were moved, the old slaves array
  893.  * will be partially populated, with some valid and some invalid
  894.  * entries.  Walk through it, copying valid entries to the new slaves
  895.  * array as we go; when we get to the insert location for the new
  896.  * slaves, copy the inserts array over, then finish off the old slaves
  897.  * array.
  898.  */
  899. for (i = 0, j = 0; i < index; i++) {
  900.     if (pwPtr->slaves[i] != NULL) {
  901. new[j] = pwPtr->slaves[i];
  902. j++;
  903.     }
  904. }
  905. memcpy((void *)&(new[j]), inserts, sizeof(Slave *) * (insertIndex));
  906. j += firstOptionArg - 2;
  907. for (i = index; i < pwPtr->numSlaves; i++) {
  908.     if (pwPtr->slaves[i] != NULL) {
  909. new[j] = pwPtr->slaves[i];
  910. j++;
  911.     }
  912. }
  913.     }
  914.     /*
  915.      * Make the new slaves array the paned window's slave array, and clean up.
  916.      */
  917.     ckfree((void *)pwPtr->slaves);
  918.     ckfree((void *)inserts);
  919.     pwPtr->slaves = new;
  920.     /*
  921.      * Set the paned window's slave count to the new value.
  922.      */
  923.     pwPtr->numSlaves += numNewSlaves;
  924.     Tk_FreeConfigOptions((char *) &options, pwPtr->slaveOpts, pwPtr->tkwin);
  925.     
  926.     ComputeGeometry(pwPtr);
  927.     return TCL_OK;
  928. }
  929. /*
  930.  *----------------------------------------------------------------------
  931.  *
  932.  * PanedWindowSashCommand --
  933.  *
  934.  * Implementation of the panedwindow sash subcommand.  See the user
  935.  * documentation for details on what it does.
  936.  *
  937.  * Results:
  938.  * Standard Tcl result.
  939.  *
  940.  * Side effects:
  941.  * Depends on the arguments.
  942.  *
  943.  *----------------------------------------------------------------------
  944.  */
  945. static int
  946. PanedWindowSashCommand(pwPtr, interp, objc, objv)
  947.     PanedWindow *pwPtr; /* Pointer to paned window information. */
  948.     Tcl_Interp *interp; /* Current interpreter. */
  949.     int objc; /* Number of arguments. */
  950.     Tcl_Obj * CONST objv[]; /* Argument objects. */
  951. {
  952.     static CONST char *sashOptionStrings[] = { "coord", "dragto", "mark",
  953.      "place", (char *) NULL };
  954.     enum sashOptions { SASH_COORD, SASH_DRAGTO, SASH_MARK, SASH_PLACE };
  955.     int index, sash, x, y, diff;
  956.     Tcl_Obj *coords[2];
  957.     Slave *slavePtr;
  958.     
  959.     if (objc < 3) {
  960. Tcl_WrongNumArgs(interp, 2, objv, "option ?arg ...?");
  961. return TCL_ERROR;
  962.     }
  963.     if (Tcl_GetIndexFromObj(interp, objv[2], sashOptionStrings,
  964.     "option", 0, &index) != TCL_OK) {
  965. return TCL_ERROR;
  966.     }
  967.     Tcl_ResetResult(interp);
  968.     switch ((enum sashOptions) index) {
  969. case SASH_COORD: {
  970.     if (objc != 4) {
  971. Tcl_WrongNumArgs(interp, 3, objv, "index");
  972. return TCL_ERROR;
  973.     }
  974.     if (Tcl_GetIntFromObj(interp, objv[3], &sash) != TCL_OK) {
  975. return TCL_ERROR;
  976.     }
  977.     if (!ValidSashIndex(pwPtr, sash)) {
  978. Tcl_ResetResult(interp);
  979. Tcl_SetResult(interp, "invalid sash index", TCL_STATIC);
  980. return TCL_ERROR;
  981.     }
  982.     slavePtr = pwPtr->slaves[sash];
  983.     
  984.     coords[0] = Tcl_NewIntObj(slavePtr->sashx);
  985.     coords[1] = Tcl_NewIntObj(slavePtr->sashy);
  986.     Tcl_SetListObj(Tcl_GetObjResult(interp), 2, coords);
  987.     break;
  988. }
  989. case SASH_MARK: {
  990.     if (objc != 6 && objc != 4) {
  991. Tcl_WrongNumArgs(interp, 3, objv, "index ?x y?");
  992. return TCL_ERROR;
  993.     }
  994.     
  995.     if (Tcl_GetIntFromObj(interp, objv[3], &sash) != TCL_OK) {
  996. return TCL_ERROR;
  997.     }
  998.     if (!ValidSashIndex(pwPtr, sash)) {
  999. Tcl_ResetResult(interp);
  1000. Tcl_SetResult(interp, "invalid sash index", TCL_STATIC);
  1001. return TCL_ERROR;
  1002.     }
  1003.     if (objc == 6) {
  1004. if (Tcl_GetIntFromObj(interp, objv[4], &x) != TCL_OK) {
  1005.     return TCL_ERROR;
  1006. }
  1007. if (Tcl_GetIntFromObj(interp, objv[5], &y) != TCL_OK) {
  1008.     return TCL_ERROR;
  1009. }
  1010. pwPtr->slaves[sash]->markx = x;
  1011. pwPtr->slaves[sash]->marky = y;
  1012.     } else {
  1013. coords[0] = Tcl_NewIntObj(pwPtr->slaves[sash]->markx);
  1014. coords[1] = Tcl_NewIntObj(pwPtr->slaves[sash]->marky);
  1015. Tcl_SetListObj(Tcl_GetObjResult(interp), 2, coords);
  1016.     }
  1017.     break;
  1018. }
  1019. case SASH_DRAGTO:
  1020. case SASH_PLACE: {
  1021.     if (objc != 6) {
  1022. Tcl_WrongNumArgs(interp, 3, objv, "index x y");
  1023. return TCL_ERROR;
  1024.     }
  1025.     
  1026.     if (Tcl_GetIntFromObj(interp, objv[3], &sash) != TCL_OK) {
  1027. return TCL_ERROR;
  1028.     }
  1029.     if (!ValidSashIndex(pwPtr, sash)) {
  1030. Tcl_ResetResult(interp);
  1031. Tcl_SetResult(interp, "invalid sash index", TCL_STATIC);
  1032. return TCL_ERROR;
  1033.     }
  1034.     if (Tcl_GetIntFromObj(interp, objv[4], &x) != TCL_OK) {
  1035. return TCL_ERROR;
  1036.     }
  1037.     if (Tcl_GetIntFromObj(interp, objv[5], &y) != TCL_OK) {
  1038. return TCL_ERROR;
  1039.     }
  1040.     
  1041.     slavePtr = pwPtr->slaves[sash];
  1042.     if (pwPtr->orient == ORIENT_HORIZONTAL) {
  1043. if (index == SASH_PLACE) {
  1044.     diff = x - pwPtr->slaves[sash]->sashx;
  1045. } else {
  1046.     diff = x - pwPtr->slaves[sash]->markx;
  1047. }
  1048.     } else {
  1049. if (index == SASH_PLACE) {
  1050.     diff = y - pwPtr->slaves[sash]->sashy;
  1051. } else {
  1052.     diff = y - pwPtr->slaves[sash]->marky;
  1053. }
  1054.     }
  1055.     MoveSash(pwPtr, sash, diff);
  1056.     ComputeGeometry(pwPtr);
  1057. }
  1058.     }
  1059.     return TCL_OK;
  1060. }
  1061. /*
  1062.  *----------------------------------------------------------------------
  1063.  *
  1064.  * ConfigurePanedWindow --
  1065.  *
  1066.  * This procedure is called to process an argv/argc list in
  1067.  * conjunction with the Tk option database to configure (or
  1068.  * reconfigure) a paned window widget.
  1069.  *
  1070.  * Results:
  1071.  * The return value is a standard Tcl result.  If TCL_ERROR is
  1072.  * returned, then the interp's result contains an error message.
  1073.  *
  1074.  * Side effects:
  1075.  * Configuration information, such as colors, border width,
  1076.  * etc. get set for pwPtr;  old resources get freed,
  1077.  * if there were any.
  1078.  *
  1079.  *----------------------------------------------------------------------
  1080.  */
  1081. static int
  1082. ConfigurePanedWindow(interp, pwPtr, objc, objv)
  1083.     Tcl_Interp *interp; /* Used for error reporting. */
  1084.     PanedWindow *pwPtr; /* Information about widget. */
  1085.     int objc; /* Number of arguments. */
  1086.     Tcl_Obj *CONST objv[]; /* Argument values. */
  1087. {
  1088.     Tk_SavedOptions savedOptions;
  1089.     int typemask = 0;
  1090.     
  1091.     if (Tk_SetOptions(interp, (char *) pwPtr, pwPtr->optionTable, objc, objv,
  1092.     pwPtr->tkwin, &savedOptions, &typemask) != TCL_OK) {
  1093. Tk_RestoreSavedOptions(&savedOptions);
  1094. return TCL_ERROR;
  1095.     }
  1096.     Tk_FreeSavedOptions(&savedOptions);
  1097.     PanedWindowWorldChanged((ClientData) pwPtr);
  1098.     /*
  1099.      * If an option that affects geometry has changed, make a relayout
  1100.      * request.
  1101.      */
  1102.     if (typemask & GEOMETRY) {
  1103. ComputeGeometry(pwPtr);
  1104.     }
  1105.     
  1106.     return TCL_OK;
  1107. }
  1108. /*
  1109.  *----------------------------------------------------------------------
  1110.  *
  1111.  * PanedWindowWorldChanged --
  1112.  *
  1113.  * This procedure is invoked anytime a paned window's world has
  1114.  * changed in some way that causes the widget to have to recompute
  1115.  * graphics contexts and geometry.
  1116.  *
  1117.  * Results:
  1118.  * None.
  1119.  *
  1120.  * Side effects:
  1121.  * Paned window will be relayed out and redisplayed.
  1122.  *
  1123.  *----------------------------------------------------------------------
  1124.  */
  1125. static void
  1126. PanedWindowWorldChanged(instanceData)
  1127.     ClientData instanceData; /* Information about the paned window. */
  1128. {
  1129.     XGCValues gcValues;
  1130.     GC newGC;
  1131.     PanedWindow *pwPtr = (PanedWindow *) instanceData;
  1132.     /*
  1133.      * Allocated a graphics context for drawing the paned window widget
  1134.      * elements (background, sashes, etc.) and set the window background.
  1135.      */
  1136.     
  1137.     gcValues.background = Tk_3DBorderColor(pwPtr->background)->pixel;
  1138.     newGC = Tk_GetGC(pwPtr->tkwin, GCBackground, &gcValues);
  1139.     if (pwPtr->gc != None) {
  1140. Tk_FreeGC(pwPtr->display, pwPtr->gc);
  1141.     }
  1142.     pwPtr->gc = newGC;
  1143.     Tk_SetWindowBackground(pwPtr->tkwin, gcValues.background);
  1144.     /*
  1145.      * Issue geometry size requests to Tk.
  1146.      */
  1147.     Tk_SetInternalBorder(pwPtr->tkwin, pwPtr->borderWidth);
  1148.     if (pwPtr->width > 0 && pwPtr->height > 0) {
  1149. Tk_GeometryRequest(pwPtr->tkwin, pwPtr->width, pwPtr->height);
  1150.     }
  1151.     /*
  1152.      * Arrange for the window to be redrawn, if neccessary.
  1153.      */
  1154.     if (Tk_IsMapped(pwPtr->tkwin) && !(pwPtr->flags & REDRAW_PENDING)) {
  1155. Tcl_DoWhenIdle(DisplayPanedWindow, (ClientData) pwPtr);
  1156. pwPtr->flags |= REDRAW_PENDING;
  1157.     }
  1158. }
  1159. /*
  1160.  *--------------------------------------------------------------
  1161.  *
  1162.  * PanedWindowEventProc --
  1163.  *
  1164.  * This procedure is invoked by the Tk dispatcher for various
  1165.  * events on paned windows.
  1166.  *
  1167.  * Results:
  1168.  * None.
  1169.  *
  1170.  * Side effects:
  1171.  * When the window gets deleted, internal structures get
  1172.  * cleaned up.  When it gets exposed, it is redisplayed.
  1173.  *
  1174.  *--------------------------------------------------------------
  1175.  */
  1176. static void
  1177. PanedWindowEventProc(clientData, eventPtr)
  1178.     ClientData clientData; /* Information about window. */
  1179.     XEvent *eventPtr; /* Information about event. */
  1180. {
  1181.     PanedWindow *pwPtr = (PanedWindow *) clientData;
  1182.     if (eventPtr->type == Expose) {
  1183. if (pwPtr->tkwin != NULL && !(pwPtr->flags & REDRAW_PENDING)) {
  1184.     Tcl_DoWhenIdle(DisplayPanedWindow, (ClientData) pwPtr);
  1185.     pwPtr->flags |= REDRAW_PENDING;
  1186. }
  1187.     } else if (eventPtr->type == ConfigureNotify) {
  1188. pwPtr->flags |= REQUESTED_RELAYOUT;
  1189. if (pwPtr->tkwin != NULL && !(pwPtr->flags & REDRAW_PENDING)) {
  1190.     Tcl_DoWhenIdle(DisplayPanedWindow, (ClientData) pwPtr);
  1191.     pwPtr->flags |= REDRAW_PENDING;
  1192. }
  1193.     } else if (eventPtr->type == DestroyNotify) {
  1194. DestroyPanedWindow(pwPtr);
  1195.     }
  1196. }
  1197. /*
  1198.  *----------------------------------------------------------------------
  1199.  *
  1200.  * PanedWindowCmdDeletedProc --
  1201.  *
  1202.  * This procedure is invoked when a widget command is deleted.  If
  1203.  * the widget isn't already in the process of being destroyed,
  1204.  * this command destroys it.
  1205.  *
  1206.  * Results:
  1207.  * None.
  1208.  *
  1209.  * Side effects:
  1210.  * The widget is destroyed.
  1211.  *
  1212.  *----------------------------------------------------------------------
  1213.  */
  1214. static void
  1215. PanedWindowCmdDeletedProc(clientData)
  1216.     ClientData clientData; /* Pointer to widget record for widget. */
  1217. {
  1218.     PanedWindow *pwPtr = (PanedWindow *) clientData;
  1219.     /*
  1220.      * This procedure could be invoked either because the window was
  1221.      * destroyed and the command was then deleted or because the command was
  1222.      * deleted, and then this procedure destroys the widget.  The
  1223.      * WIDGET_DELETED flag distinguishes these cases.
  1224.      */
  1225.     if (!(pwPtr->flags & WIDGET_DELETED)) {
  1226. Tk_DestroyWindow(pwPtr->proxywin);
  1227. Tk_DestroyWindow(pwPtr->tkwin);
  1228.     }
  1229. }
  1230. /*
  1231.  *--------------------------------------------------------------
  1232.  *
  1233.  * DisplayPanedWindow --
  1234.  *
  1235.  * This procedure redraws the contents of a paned window widget.
  1236.  * It is invoked as a do-when-idle handler, so it only runs
  1237.  * when there's nothing else for the application to do.
  1238.  *
  1239.  * Results:
  1240.  * None.
  1241.  *
  1242.  * Side effects:
  1243.  * Information appears on the screen.
  1244.  *
  1245.  *--------------------------------------------------------------
  1246.  */
  1247. static void
  1248. DisplayPanedWindow(clientData)
  1249.     ClientData clientData; /* Information about window. */
  1250. {
  1251.     PanedWindow *pwPtr = (PanedWindow *) clientData;
  1252.     Slave *slavePtr;
  1253.     Pixmap pixmap;
  1254.     Tk_Window tkwin = pwPtr->tkwin;
  1255.     int i, sashWidth, sashHeight;
  1256.     const int horizontal = (pwPtr->orient == ORIENT_HORIZONTAL);
  1257.     pwPtr->flags &= ~REDRAW_PENDING;
  1258.     if ((pwPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  1259. return;
  1260.     }
  1261.     if (pwPtr->flags & REQUESTED_RELAYOUT) {
  1262. ArrangePanes(clientData);
  1263.     }
  1264. #ifndef TK_NO_DOUBLE_BUFFERING
  1265.     /*
  1266.      * Create a pixmap for double-buffering, if necessary.
  1267.      */
  1268.     pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
  1269.     Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  1270. #else
  1271.     pixmap = Tk_WindowId(tkwin);
  1272. #endif /* TK_NO_DOUBLE_BUFFERING */
  1273.     /*
  1274.      * Redraw the widget's background and border.
  1275.      */
  1276.     Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, 0, 0,
  1277.     Tk_Width(tkwin), Tk_Height(tkwin), pwPtr->borderWidth,
  1278.     pwPtr->relief);
  1279.     /*
  1280.      * Set up boilerplate geometry values for sashes (width, height, common
  1281.      * coordinates).
  1282.      */
  1283.     if (horizontal) {
  1284. sashHeight = Tk_Height(tkwin) - (2 * Tk_InternalBorderWidth(tkwin));
  1285. sashWidth = pwPtr->sashWidth;
  1286.     } else {
  1287. sashWidth = Tk_Width(tkwin) - (2 * Tk_InternalBorderWidth(tkwin));
  1288. sashHeight = pwPtr->sashWidth;
  1289.     }
  1290.     /*
  1291.      * Draw the sashes.
  1292.      */
  1293.     for (i = 0; i < pwPtr->numSlaves - 1; i++) {
  1294. slavePtr = pwPtr->slaves[i];
  1295. Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background,
  1296. slavePtr->sashx, slavePtr->sashy,
  1297. sashWidth, sashHeight, 1, pwPtr->sashRelief);
  1298. if (pwPtr->showHandle) {
  1299.     Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background,
  1300.     slavePtr->handlex, slavePtr->handley,
  1301.     pwPtr->handleSize, pwPtr->handleSize, 1,
  1302.     TK_RELIEF_RAISED);
  1303. }
  1304.     }
  1305. #ifndef TK_NO_DOUBLE_BUFFERING
  1306.     /*
  1307.      * Copy the information from the off-screen pixmap onto the screen,
  1308.      * then delete the pixmap.
  1309.      */
  1310.     XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin), pwPtr->gc,
  1311.     0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin),
  1312.     0, 0);
  1313.     Tk_FreePixmap(Tk_Display(tkwin), pixmap);
  1314. #endif /* TK_NO_DOUBLE_BUFFERING */
  1315. }
  1316. /*
  1317.  *----------------------------------------------------------------------
  1318.  *
  1319.  * DestroyPanedWindow --
  1320.  *
  1321.  * This procedure is invoked by PanedWindowEventProc to free the
  1322.  * internal structure of a paned window.
  1323.  *
  1324.  * Results:
  1325.  * None.
  1326.  *
  1327.  * Side effects:
  1328.  * Everything associated with the paned window is freed up.
  1329.  *
  1330.  *----------------------------------------------------------------------
  1331.  */
  1332. static void
  1333. DestroyPanedWindow(pwPtr)
  1334.     PanedWindow *pwPtr; /* Info about paned window widget. */
  1335. {
  1336.     int i;
  1337.     
  1338.     /*
  1339.      * First mark the widget as in the process of being deleted,
  1340.      * so that any code that causes calls to other paned window procedures
  1341.      * will abort.
  1342.      */
  1343.     pwPtr->flags |= WIDGET_DELETED;
  1344.     /*
  1345.      * Cancel idle callbacks for redrawing the widget and for rearranging
  1346.      * the panes.
  1347.      */
  1348.     if (pwPtr->flags & REDRAW_PENDING) {
  1349. Tcl_CancelIdleCall(DisplayPanedWindow, (ClientData) pwPtr);
  1350.     }
  1351.     if (pwPtr->flags & RESIZE_PENDING) {
  1352. Tcl_CancelIdleCall(ArrangePanes, (ClientData) pwPtr);
  1353.     }
  1354.     /*
  1355.      * Clean up the slave list; foreach slave:
  1356.      *  o  Cancel the slave's structure notification callback
  1357.      *  o  Cancel geometry management for the slave.
  1358.      *  o  Free memory for the slave
  1359.      */
  1360.     
  1361.     for (i = 0; i < pwPtr->numSlaves; i++) {
  1362. Tk_DeleteEventHandler(pwPtr->slaves[i]->tkwin, StructureNotifyMask,
  1363. SlaveStructureProc, (ClientData) pwPtr->slaves[i]);
  1364. Tk_ManageGeometry(pwPtr->slaves[i]->tkwin, NULL, NULL);
  1365. Tk_FreeConfigOptions((char *)pwPtr->slaves[i], pwPtr->slaveOpts,
  1366. pwPtr->tkwin);
  1367. ckfree((void *)pwPtr->slaves[i]);
  1368. pwPtr->slaves[i] = NULL;
  1369.     }
  1370.     if (pwPtr->slaves) {
  1371. ckfree((char *) pwPtr->slaves);
  1372.     }
  1373.     /*
  1374.      * Remove the widget command from the interpreter.
  1375.      */
  1376.     Tcl_DeleteCommandFromToken(pwPtr->interp, pwPtr->widgetCmd);
  1377.     /*
  1378.      * Let Tk_FreeConfigOptions clean up the rest.
  1379.      */
  1380.     Tk_FreeConfigOptions((char *) pwPtr, pwPtr->optionTable, pwPtr->tkwin);
  1381.     Tcl_Release((ClientData) pwPtr->tkwin);
  1382.     pwPtr->tkwin = NULL;
  1383.     Tcl_EventuallyFree((ClientData) pwPtr, TCL_DYNAMIC);
  1384. }
  1385. /*
  1386.  *--------------------------------------------------------------
  1387.  *
  1388.  * PanedWindowReqProc --
  1389.  *
  1390.  * This procedure is invoked by Tk_GeometryRequest for
  1391.  * windows managed by a paned window.
  1392.  *
  1393.  * Results:
  1394.  * None.
  1395.  *
  1396.  * Side effects:
  1397.  * Arranges for tkwin, and all its managed siblings, to
  1398.  * be re-arranged at the next idle point.
  1399.  *
  1400.  *--------------------------------------------------------------
  1401.  */
  1402. static void
  1403. PanedWindowReqProc(clientData, tkwin)
  1404.     ClientData clientData; /* Paned window's information about
  1405.  * window that got new preferred
  1406.  * geometry.  */
  1407.     Tk_Window tkwin; /* Other Tk-related information
  1408.  * about the window. */
  1409. {
  1410.     Slave *slavePtr = (Slave *) clientData;
  1411.     PanedWindow *pwPtr = (PanedWindow *) (slavePtr->masterPtr);
  1412.     if (Tk_IsMapped(pwPtr->tkwin)) {
  1413. if (!(pwPtr->flags & RESIZE_PENDING)) {
  1414.     pwPtr->flags |= RESIZE_PENDING;
  1415.     Tcl_DoWhenIdle(ArrangePanes, (ClientData) pwPtr);
  1416. }
  1417.     } else {
  1418. int doubleBw = 2 * Tk_Changes(slavePtr->tkwin)->border_width;
  1419. if (slavePtr->width <= 0) {
  1420.     slavePtr->paneWidth = Tk_ReqWidth(slavePtr->tkwin) + doubleBw;
  1421. }
  1422. if (slavePtr->height <= 0) {
  1423.     slavePtr->paneHeight = Tk_ReqHeight(slavePtr->tkwin) + doubleBw;
  1424. }
  1425. ComputeGeometry(pwPtr);
  1426.     }
  1427. }
  1428. /*
  1429.  *--------------------------------------------------------------
  1430.  *
  1431.  * PanedWindowLostSlaveProc --
  1432.  *
  1433.  * This procedure is invoked by Tk whenever some other geometry
  1434.  * claims control over a slave that used to be managed by us.
  1435.  *
  1436.  * Results:
  1437.  * None.
  1438.  *
  1439.  * Side effects:
  1440.  * Forgets all information about the slave.  Causes geometry to
  1441.  * be recomputed for the panedwindow.
  1442.  *
  1443.  *--------------------------------------------------------------
  1444.  */
  1445. static void
  1446. PanedWindowLostSlaveProc(clientData, tkwin)
  1447.     ClientData clientData; /* Grid structure for slave window that
  1448.  * was stolen away. */
  1449.     Tk_Window tkwin; /* Tk's handle for the slave window. */
  1450. {
  1451.     register Slave *slavePtr = (Slave *) clientData;
  1452.     PanedWindow *pwPtr = (PanedWindow *) (slavePtr->masterPtr);
  1453.     if (pwPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
  1454. Tk_UnmaintainGeometry(slavePtr->tkwin, pwPtr->tkwin);
  1455.     }
  1456.     Unlink(slavePtr);
  1457.     Tk_DeleteEventHandler(slavePtr->tkwin, StructureNotifyMask,
  1458.     SlaveStructureProc, (ClientData) slavePtr);
  1459.     Tk_UnmapWindow(slavePtr->tkwin);
  1460.     slavePtr->tkwin = NULL;
  1461.     ckfree((void *)slavePtr);
  1462.     ComputeGeometry(pwPtr);
  1463. }
  1464. /*
  1465.  *--------------------------------------------------------------
  1466.  *
  1467.  * ArrangePanes --
  1468.  *
  1469.  * This procedure is invoked (using the Tcl_DoWhenIdle
  1470.  * mechanism) to re-layout a set of windows managed by
  1471.  * a paned window.  It is invoked at idle time so that a
  1472.  * series of pane requests can be merged into a single
  1473.  * layout operation.
  1474.  *
  1475.  * Results:
  1476.  * None.
  1477.  *
  1478.  * Side effects:
  1479.  * The slaves of masterPtr may get resized or moved.
  1480.  *
  1481.  *--------------------------------------------------------------
  1482.  */
  1483. static void
  1484. ArrangePanes(clientData)
  1485.     ClientData clientData; /* Structure describing parent whose slaves
  1486.  * are to be re-layed out. */
  1487. {
  1488.     register PanedWindow *pwPtr = (PanedWindow *) clientData;
  1489.     register Slave *slavePtr;
  1490.     int i, slaveWidth, slaveHeight, slaveX, slaveY;
  1491.     int paneWidth, paneHeight, paneSize, paneMinSize;
  1492.     int doubleBw;
  1493.     int x, y;
  1494.     int sashWidth, sashOffset, sashCount, handleOffset;
  1495.     int sashReserve, sxReserve, syReserve;
  1496.     int internalBW;
  1497.     int paneDynSize, paneDynMinSize, pwHeight, pwWidth, pwSize;
  1498.     int stretchReserve, stretchAmount;
  1499.     const int horizontal = (pwPtr->orient == ORIENT_HORIZONTAL);
  1500.     pwPtr->flags &= ~(REQUESTED_RELAYOUT|RESIZE_PENDING);
  1501.     /*
  1502.      * If the parent has no slaves anymore, then don't do anything
  1503.      * at all:  just leave the parent's size as-is.  Otherwise there is
  1504.      * no way to "relinquish" control over the parent so another geometry
  1505.      * manager can take over.
  1506.      */
  1507.     if (pwPtr->numSlaves == 0) {
  1508. return;
  1509.     }
  1510.     Tcl_Preserve((ClientData) pwPtr);
  1511.     /*
  1512.      * First pass; compute sizes
  1513.      */
  1514.     paneDynSize = paneDynMinSize = 0;
  1515.     internalBW = Tk_InternalBorderWidth(pwPtr->tkwin);
  1516.     pwHeight = Tk_Height(pwPtr->tkwin) - (2 * internalBW);
  1517.     pwWidth = Tk_Width(pwPtr->tkwin) - (2 * internalBW);
  1518.     x = y = internalBW;
  1519.     stretchReserve = (horizontal ? pwWidth : pwHeight);
  1520.     /*
  1521.      * Calculate the sash width, including handle and padding,
  1522.      * and the sash and handle offsets.
  1523.      */
  1524.     sashOffset = handleOffset = pwPtr->sashPad;
  1525.     if (pwPtr->showHandle && pwPtr->handleSize > pwPtr->sashWidth) {
  1526. sashWidth = (2 * pwPtr->sashPad) + pwPtr->handleSize;
  1527. sashOffset = ((pwPtr->handleSize - pwPtr->sashWidth) / 2)
  1528. + pwPtr->sashPad;
  1529.     } else {
  1530. sashWidth = (2 * pwPtr->sashPad) + pwPtr->sashWidth;
  1531. handleOffset = ((pwPtr->sashWidth - pwPtr->handleSize) / 2)
  1532. + pwPtr->sashPad;
  1533.     }
  1534.     sashCount = pwPtr->numSlaves - 1;
  1535.     for (i = 0; i < pwPtr->numSlaves; i++) {
  1536. slavePtr = pwPtr->slaves[i];
  1537. /*
  1538.  * Compute the total size needed by all the slaves and the
  1539.  * left-over, or shortage of space available.
  1540.  */
  1541. if (horizontal) {
  1542.     paneSize = slavePtr->paneWidth;
  1543.     stretchReserve -= paneSize + (2 * slavePtr->padx);
  1544. } else {
  1545.     paneSize = slavePtr->paneHeight;
  1546.     stretchReserve -= paneSize + (2 * slavePtr->pady);
  1547. }
  1548. if (i == sashCount) {
  1549.     paneDynSize += paneSize;
  1550.     paneDynMinSize += slavePtr->minSize;
  1551. } else {
  1552.     stretchReserve -= sashWidth;
  1553. }
  1554.     }
  1555.     /*
  1556.      * Second pass; adjust/arrange panes.
  1557.      */
  1558.     for (i = 0; i < pwPtr->numSlaves; i++) {
  1559. slavePtr = pwPtr->slaves[i];
  1560. /*
  1561.  * Compute the size of this slave.  The algorithm (assuming a
  1562.  * horizontal paned window) is:
  1563.  *
  1564.  * 1.  Get "base" dimensions.  If a width or height is specified
  1565.  * for this slave, use those values; else use the
  1566.  * ReqWidth/ReqHeight.
  1567.  * 2.  Using base dimensions, pane dimensions, and sticky values,
  1568.  * determine the x and y, and actual width and height of the
  1569.  * widget.
  1570.  */
  1571. doubleBw = 2 * Tk_Changes(slavePtr->tkwin)->border_width;
  1572. slaveWidth = (slavePtr->width > 0 ? slavePtr->width :
  1573. Tk_ReqWidth(slavePtr->tkwin) + doubleBw);
  1574. slaveHeight = (slavePtr->height > 0 ? slavePtr->height :
  1575. Tk_ReqHeight(slavePtr->tkwin) + doubleBw);
  1576. paneMinSize = slavePtr->minSize;
  1577. /*
  1578.  * Calculate pane width and height.
  1579.  */
  1580. if (horizontal) {
  1581.     paneSize = slavePtr->paneWidth;
  1582.     pwSize = pwWidth;
  1583. } else {
  1584.     paneSize = slavePtr->paneHeight;
  1585.     pwSize = pwHeight;
  1586. }
  1587. if (Tk_IsMapped(pwPtr->tkwin)) {
  1588.     if (i == pwPtr->numSlaves - 1) {
  1589. double frac;
  1590. if (paneDynSize > 0) {
  1591.     frac = (double)paneSize / (double)paneDynSize;
  1592. } else {
  1593.     frac = (double)paneSize / (double)pwSize;
  1594. }
  1595. paneDynSize -= paneSize;
  1596. paneDynMinSize -= slavePtr->minSize;
  1597. stretchAmount = (int) (frac * stretchReserve);
  1598. if (paneSize + stretchAmount >= paneMinSize) {
  1599.     stretchReserve -= stretchAmount;
  1600.     paneSize += stretchAmount;
  1601. } else {
  1602.     stretchReserve += paneSize - paneMinSize;
  1603.     paneSize = paneMinSize;
  1604. }
  1605.         if (stretchReserve > 0) {
  1606.     paneSize += stretchReserve;
  1607.     stretchReserve = 0;
  1608.         }
  1609.     } else if (paneDynSize - paneDynMinSize + stretchReserve < 0) {
  1610. if (paneSize + paneDynSize - paneDynMinSize + stretchReserve
  1611. <= paneMinSize) {
  1612.     stretchReserve += paneSize - paneMinSize;
  1613.     paneSize = paneMinSize;
  1614. } else {
  1615.     paneSize += paneDynSize - paneDynMinSize + stretchReserve;
  1616.     stretchReserve = paneDynMinSize - paneDynSize;
  1617. }
  1618.     }
  1619. }
  1620. if (horizontal) {
  1621.     paneWidth = paneSize;
  1622.     paneHeight = pwHeight - (2 * slavePtr->pady);
  1623. } else {
  1624.     paneWidth = pwWidth - (2 * slavePtr->padx);
  1625.     paneHeight = paneSize;
  1626. }
  1627. /*
  1628.  * Adjust for area reserved for sashes.
  1629.  */
  1630. if (sashCount) {
  1631.     sashReserve = sashWidth * sashCount;
  1632.     if (horizontal) {
  1633. sxReserve = sashReserve;
  1634. syReserve = 0;
  1635.     } else {
  1636. sxReserve = 0;
  1637. syReserve = sashReserve;
  1638.     }
  1639. } else {
  1640.     sxReserve = syReserve = 0;
  1641. }
  1642. if (pwWidth - sxReserve < x + paneWidth - internalBW) {
  1643.     paneWidth = pwWidth - sxReserve - x + internalBW;
  1644. }
  1645. if (pwHeight - syReserve < y + paneHeight - internalBW) {
  1646.     paneHeight = pwHeight - syReserve - y + internalBW;
  1647. }
  1648. if (slaveWidth > paneWidth) {
  1649.     slaveWidth = paneWidth;
  1650. }
  1651. if (slaveHeight > paneHeight) {
  1652.     slaveHeight = paneHeight;
  1653. }
  1654. slavePtr->x = x;
  1655. slavePtr->y = y;
  1656. /*
  1657.  * Compute the location of the sash at the right or bottom of the
  1658.  * parcel and the location of the next parcel.
  1659.  */
  1660. if (horizontal) {
  1661.     x += paneWidth + (2 * slavePtr->padx);
  1662.     if (x < internalBW) {
  1663. x = internalBW;
  1664.     }
  1665.     slavePtr->sashx   = x + sashOffset;
  1666.     slavePtr->sashy   = y;
  1667.     slavePtr->handlex = x + handleOffset;
  1668.     slavePtr->handley = y + pwPtr->handlePad;
  1669.     x += sashWidth;
  1670. } else {
  1671.     y += paneHeight + (2 * slavePtr->pady);
  1672.     if (y < internalBW) {
  1673. y = internalBW;
  1674.     }
  1675.     slavePtr->sashx   = x;
  1676.     slavePtr->sashy   = y + sashOffset;
  1677.     slavePtr->handlex = x + pwPtr->handlePad;
  1678.     slavePtr->handley = y + handleOffset;
  1679.     y += sashWidth;
  1680. }
  1681. /*
  1682.  * Compute the actual dimensions of the slave in the pane.
  1683.  */
  1684. slaveX = slavePtr->x;
  1685. slaveY = slavePtr->y;
  1686. AdjustForSticky(slavePtr->sticky, paneWidth, paneHeight,
  1687. &slaveX, &slaveY, &slaveWidth, &slaveHeight);
  1688. slaveX += slavePtr->padx;
  1689. slaveY += slavePtr->pady;
  1690. /*
  1691.  * Now put the window in the proper spot.
  1692.  */
  1693. if (slaveWidth <= 0 || slaveHeight <= 0 ||
  1694. (horizontal ? slaveX - internalBW > pwWidth :
  1695. slaveY - internalBW > pwHeight)) {
  1696.     Tk_UnmaintainGeometry(slavePtr->tkwin, pwPtr->tkwin);
  1697.     Tk_UnmapWindow(slavePtr->tkwin);
  1698. } else {
  1699.     Tk_MaintainGeometry(slavePtr->tkwin, pwPtr->tkwin,
  1700.     slaveX, slaveY, slaveWidth, slaveHeight);
  1701. }
  1702. sashCount--;
  1703.     }
  1704.     Tcl_Release((ClientData) pwPtr);
  1705. }
  1706. /*
  1707.  *----------------------------------------------------------------------
  1708.  *
  1709.  * Unlink --
  1710.  *
  1711.  * Remove a slave from a paned window.
  1712.  *
  1713.  * Results:
  1714.  * None.
  1715.  *
  1716.  * Side effects:
  1717.  * The paned window will be scheduled for re-arranging and redrawing.
  1718.  *
  1719.  *----------------------------------------------------------------------
  1720.  */
  1721. static void
  1722. Unlink(slavePtr)
  1723.     register Slave *slavePtr; /* Window to unlink. */
  1724. {
  1725.     register PanedWindow *masterPtr;
  1726.     int i, j;
  1727.     
  1728.     masterPtr = slavePtr->masterPtr;
  1729.     if (masterPtr == NULL) {
  1730. return;
  1731.     }
  1732.     /*
  1733.      * Find the specified slave in the panedwindow's list of slaves, then
  1734.      * remove it from that list.
  1735.      */
  1736.     for (i = 0; i < masterPtr->numSlaves; i++) {
  1737. if (masterPtr->slaves[i] == slavePtr) {
  1738.     for (j = i; j < masterPtr->numSlaves - 1; j++) {
  1739. masterPtr->slaves[j] = masterPtr->slaves[j + 1];
  1740.     }
  1741.     break;
  1742. }
  1743.     }
  1744.     /*
  1745.      * Clean out any -after or -before references to this slave
  1746.      */
  1747.     for (i = 0; i < masterPtr->numSlaves; i++) {
  1748. if (masterPtr->slaves[i]->before == slavePtr->tkwin) {
  1749.     masterPtr->slaves[i]->before = None;
  1750. }
  1751. if (masterPtr->slaves[i]->after == slavePtr->tkwin) {
  1752.     masterPtr->slaves[i]->after = None;
  1753. }
  1754.     }
  1755.     masterPtr->flags |= REQUESTED_RELAYOUT;
  1756.     if (!(masterPtr->flags & REDRAW_PENDING)) {
  1757. masterPtr->flags |= REDRAW_PENDING;
  1758. Tcl_DoWhenIdle(DisplayPanedWindow, (ClientData) masterPtr);
  1759.     }
  1760.     /*
  1761.      * Set the slave's masterPtr to NULL, so that we can tell that the
  1762.      * slave is no longer attached to any panedwindow.
  1763.      */
  1764.     slavePtr->masterPtr = NULL;
  1765.     masterPtr->numSlaves--;
  1766. }
  1767. /*
  1768.  *----------------------------------------------------------------------
  1769.  *
  1770.  * GetPane --
  1771.  *
  1772.  * Given a token to a Tk window, find the pane that corresponds to
  1773.  * that token in a given paned window.
  1774.  *
  1775.  * Results:
  1776.  * Pointer to the slave structure, or NULL if the window is not
  1777.  * managed by this paned window.
  1778.  *
  1779.  * Side effects:
  1780.  * None.
  1781.  *
  1782.  *----------------------------------------------------------------------
  1783.  */
  1784. static Slave *
  1785. GetPane(pwPtr, tkwin)
  1786.     PanedWindow *pwPtr; /* Pointer to the paned window info. */
  1787.     Tk_Window tkwin; /* Window to search for. */
  1788. {
  1789.     int i;
  1790.     for (i = 0; i < pwPtr->numSlaves; i++) {
  1791. if (pwPtr->slaves[i]->tkwin == tkwin) {
  1792.     return pwPtr->slaves[i];
  1793. }
  1794.     }
  1795.     return NULL;
  1796. }
  1797. /*
  1798.  *--------------------------------------------------------------
  1799.  *
  1800.  * SlaveStructureProc --
  1801.  *
  1802.  * This procedure is invoked whenever StructureNotify events
  1803.  * occur for a window that's managed by a paned window.  This
  1804.  * procedure's only purpose is to clean up when windows are
  1805.  * deleted.
  1806.  *
  1807.  * Results:
  1808.  * None.
  1809.  *
  1810.  * Side effects:
  1811.  * The paned window slave structure associated with the window
  1812.  * is freed, and the slave is disassociated from the paned
  1813.  * window which managed it.
  1814.  *
  1815.  *--------------------------------------------------------------
  1816.  */
  1817. static void
  1818. SlaveStructureProc(clientData, eventPtr)
  1819.     ClientData clientData; /* Pointer to record describing window item. */
  1820.     XEvent *eventPtr; /* Describes what just happened. */
  1821. {
  1822.     Slave *slavePtr = (Slave *) clientData;
  1823.     PanedWindow *pwPtr = slavePtr->masterPtr;
  1824.     
  1825.     if (eventPtr->type == DestroyNotify) {
  1826. Unlink(slavePtr);
  1827. slavePtr->tkwin = NULL;
  1828. ckfree((void *)slavePtr);
  1829. ComputeGeometry(pwPtr);
  1830.     }
  1831. }
  1832. /*
  1833.  *----------------------------------------------------------------------
  1834.  *
  1835.  * ComputeGeometry --
  1836.  *
  1837.  * Compute geometry for the paned window, including coordinates of
  1838.  * all slave windows and each sash.
  1839.  *
  1840.  * Results:
  1841.  * None.
  1842.  *
  1843.  * Side effects:
  1844.  * Recomputes geometry information for a paned window.
  1845.  *
  1846.  *----------------------------------------------------------------------
  1847.  */
  1848. static void
  1849. ComputeGeometry(pwPtr)
  1850.     PanedWindow *pwPtr; /* Pointer to the Paned Window structure. */
  1851. {
  1852.     int i, x, y, doubleBw, internalBw;
  1853.     int sashWidth, sashOffset, handleOffset;
  1854.     int reqWidth, reqHeight, dim;
  1855.     Slave *slavePtr;
  1856.     const int horizontal = (pwPtr->orient == ORIENT_HORIZONTAL);
  1857.     pwPtr->flags |= REQUESTED_RELAYOUT;
  1858.     x = y = internalBw = Tk_InternalBorderWidth(pwPtr->tkwin);
  1859.     reqWidth = reqHeight = 0;
  1860.     /*
  1861.      * Sashes and handles share space on the display.  To simplify
  1862.      * processing below, precompute the x and y offsets of the handles and
  1863.      * sashes within the space occupied by their combination; later, just add
  1864.      * those offsets blindly (avoiding the extra showHandle, etc, checks).
  1865.      */
  1866.     sashOffset = handleOffset = pwPtr->sashPad;
  1867.     if (pwPtr->showHandle && pwPtr->handleSize > pwPtr->sashWidth) {
  1868. sashWidth = (2 * pwPtr->sashPad) + pwPtr->handleSize;
  1869. sashOffset = ((pwPtr->handleSize - pwPtr->sashWidth) / 2)
  1870. + pwPtr->sashPad;
  1871.     } else {
  1872. sashWidth = (2 * pwPtr->sashPad) + pwPtr->sashWidth;
  1873. handleOffset = ((pwPtr->sashWidth - pwPtr->handleSize) / 2)
  1874. + pwPtr->sashPad;
  1875.     }
  1876.     for (i = 0; i < pwPtr->numSlaves; i++) {
  1877. slavePtr = pwPtr->slaves[i];
  1878. /*
  1879.  * First set the coordinates for the top left corner of the slave's
  1880.  * parcel.
  1881.  */
  1882. slavePtr->x = x;
  1883. slavePtr->y = y;
  1884. /*
  1885.  * Make sure the pane's paned dimension is at least minsize.
  1886.  * This check may be redundant, since the only way to change a pane's
  1887.  * size is by moving a sash, and that code checks the minsize.
  1888.  */
  1889. if (horizontal) {
  1890.     if (slavePtr->paneWidth < slavePtr->minSize) {
  1891. slavePtr->paneWidth = slavePtr->minSize;
  1892.     }
  1893. } else {
  1894.     if (slavePtr->paneHeight < slavePtr->minSize) {
  1895. slavePtr->paneHeight = slavePtr->minSize;
  1896.     }
  1897. }
  1898. /*
  1899.  * Compute the location of the sash at the right or bottom of the
  1900.  * parcel.
  1901.  */
  1902. if (horizontal) {
  1903.     x += slavePtr->paneWidth + (2 * slavePtr->padx);
  1904.     slavePtr->sashx   = x + sashOffset;
  1905.     slavePtr->sashy   = y;
  1906.     slavePtr->handlex = x + handleOffset;
  1907.     slavePtr->handley = y + pwPtr->handlePad;
  1908.     x += sashWidth;
  1909. } else {
  1910.     y += slavePtr->paneHeight + (2 * slavePtr->pady);
  1911.     slavePtr->sashx   = x;
  1912.     slavePtr->sashy   = y + sashOffset;
  1913.     slavePtr->handlex = x + pwPtr->handlePad;
  1914.     slavePtr->handley = y + handleOffset;
  1915.     y += sashWidth;
  1916. }
  1917. /*
  1918.  * Find the maximum height/width of the slaves, for computing the
  1919.  * requested height/width of the paned window.
  1920.  */
  1921. if (horizontal) {
  1922.     /*
  1923.      * If the slave has an explicit height set, use that; otherwise,
  1924.      * use the slave's requested height.
  1925.      */
  1926.     if (slavePtr->height > 0) {
  1927. dim = slavePtr->height;
  1928.     } else {
  1929. doubleBw = 2 * Tk_Changes(slavePtr->tkwin)->border_width;
  1930. dim = Tk_ReqHeight(slavePtr->tkwin) + doubleBw;
  1931.     }
  1932.     dim += 2 * slavePtr->pady;
  1933.     if (dim > reqHeight) {
  1934. reqHeight = dim;
  1935.     }
  1936. } else {
  1937.     /*
  1938.      * If the slave has an explicit width set use that; otherwise,
  1939.      * use the slave's requested width.
  1940.      */
  1941.     if (slavePtr->width > 0) {
  1942. dim = slavePtr->width;
  1943.     } else {
  1944. doubleBw = 2 * Tk_Changes(slavePtr->tkwin)->border_width;
  1945. dim = Tk_ReqWidth(slavePtr->tkwin) + doubleBw;
  1946.     }
  1947.     dim += 2 * slavePtr->padx;
  1948.     if (dim > reqWidth) {
  1949. reqWidth = dim;
  1950.     }
  1951. }
  1952.     }
  1953.     /*
  1954.      * The loop above should have left x (or y) equal to the sum of the
  1955.      * widths (or heights) of the widgets, plus the size of one sash and
  1956.      * the sash padding for each widget, plus the width of the left (or top)
  1957.      * border of the paned window.
  1958.      *
  1959.      * The requested width (or height) is therefore x (or y) minus the size of
  1960.      * one sash and padding, plus the width of the right (or bottom) border
  1961.      * of the paned window.
  1962.      *
  1963.      * The height (or width) is equal to the maximum height (or width) of
  1964.      * the slaves, plus the width of the border of the top and bottom (or left
  1965.      * and right) of the paned window.
  1966.      *
  1967.      * If the panedwindow has an explicit width/height set use that; otherwise,
  1968.      * use the requested width/height.
  1969.      */
  1970.     if (horizontal) {
  1971. reqWidth = (pwPtr->width > 0 ?
  1972. pwPtr->width : x - sashWidth + internalBw);
  1973. reqHeight = (pwPtr->height > 0 ?
  1974. pwPtr->height : reqHeight + (2 * internalBw));
  1975.     } else {
  1976. reqWidth = (pwPtr->width > 0 ?
  1977. pwPtr->width : reqWidth + (2 * internalBw));
  1978. reqHeight = (pwPtr->height > 0 ?
  1979. pwPtr->height : y - sashWidth + internalBw);
  1980.     }
  1981.     Tk_GeometryRequest(pwPtr->tkwin, reqWidth, reqHeight);
  1982.     if (Tk_IsMapped(pwPtr->tkwin) && !(pwPtr->flags & REDRAW_PENDING)) {
  1983. pwPtr->flags |= REDRAW_PENDING;
  1984. Tcl_DoWhenIdle(DisplayPanedWindow, (ClientData) pwPtr);
  1985.     }
  1986. }
  1987. /*
  1988.  *----------------------------------------------------------------------
  1989.  *
  1990.  * DestroyOptionTables --
  1991.  *
  1992.  * This procedure is registered as an exit callback when the paned window
  1993.  * command is first called.  It cleans up the OptionTables structure
  1994.  * allocated by that command.
  1995.  *
  1996.  * Results:
  1997.  * None.
  1998.  *
  1999.  * Side effects:
  2000.  * Frees memory.
  2001.  *
  2002.  *----------------------------------------------------------------------
  2003.  */
  2004. static void
  2005. DestroyOptionTables(clientData, interp)
  2006.     ClientData clientData; /* Pointer to the OptionTables struct */
  2007.     Tcl_Interp *interp; /* Pointer to the calling interp */
  2008. {
  2009.     ckfree((char *)clientData);
  2010.     return;
  2011. }
  2012. /*
  2013.  *----------------------------------------------------------------------
  2014.  *
  2015.  * GetSticky -
  2016.  *
  2017.  * Converts an internal boolean combination of "sticky" bits into a
  2018.  * a Tcl string obj containing zero or mor of n, s, e, or w.
  2019.  *
  2020.  * Results:
  2021.  * Tcl_Obj containing the string representation of the sticky value.
  2022.  *
  2023.  * Side effects:
  2024.  * Creates a new Tcl_Obj.
  2025.  *
  2026.  *----------------------------------------------------------------------
  2027.  */
  2028. static Tcl_Obj *
  2029. GetSticky(clientData, tkwin, recordPtr, internalOffset)
  2030.     ClientData clientData;
  2031.     Tk_Window tkwin;
  2032.     char *recordPtr; /* Pointer to widget record. */
  2033.     int internalOffset; /* Offset within *recordPtr containing the
  2034.  * sticky value. */
  2035. {
  2036.     int sticky = *(int *)(recordPtr + internalOffset);
  2037.     static char buffer[5];
  2038.     int count = 0;
  2039.     if (sticky & STICK_NORTH) {
  2040.      buffer[count++] = 'n';
  2041.     }
  2042.     if (sticky & STICK_EAST) {
  2043.      buffer[count++] = 'e';
  2044.     }
  2045.     if (sticky & STICK_SOUTH) {
  2046.      buffer[count++] = 's';
  2047.     }
  2048.     if (sticky & STICK_WEST) {
  2049.      buffer[count++] = 'w';
  2050.     }
  2051.     buffer[count] = '';
  2052.     return Tcl_NewStringObj(buffer, -1);
  2053. }
  2054. /*
  2055.  *----------------------------------------------------------------------
  2056.  *
  2057.  * SetSticky --
  2058.  *
  2059.  * Converts a Tcl_Obj representing a widgets stickyness into an
  2060.  * integer value.
  2061.  *
  2062.  * Results:
  2063.  * Standard Tcl result.
  2064.  *
  2065.  * Side effects:
  2066.  * May store the integer value into the internal representation
  2067.  * pointer.  May change the pointer to the Tcl_Obj to NULL to indicate
  2068.  * that the specified string was empty and that is acceptable.
  2069.  *
  2070.  *----------------------------------------------------------------------
  2071.  */
  2072. static int
  2073. SetSticky(clientData, interp, tkwin, value, recordPtr, internalOffset,
  2074. oldInternalPtr, flags)
  2075.     ClientData clientData;
  2076.     Tcl_Interp *interp; /* Current interp; may be used for errors. */
  2077.     Tk_Window tkwin; /* Window for which option is being set. */
  2078.     Tcl_Obj **value; /* Pointer to the pointer to the value object.
  2079.  * We use a pointer to the pointer because
  2080.  * we may need to return a value (NULL). */
  2081.     char *recordPtr; /* Pointer to storage for the widget record. */
  2082.     int internalOffset; /* Offset within *recordPtr at which the
  2083.    internal value is to be stored. */
  2084.     char *oldInternalPtr; /* Pointer to storage for the old value. */
  2085.     int flags; /* Flags for the option, set Tk_SetOptions. */
  2086. {
  2087.     int sticky = 0;
  2088.     char c, *string, *internalPtr;
  2089.     internalPtr = ComputeSlotAddress(recordPtr, internalOffset);
  2090.     
  2091.     if (flags & TK_OPTION_NULL_OK && ObjectIsEmpty(*value)) {
  2092. *value = NULL;
  2093.     } else {
  2094. /*
  2095.  * Convert the sticky specifier into an integer value.
  2096.  */
  2097. string = Tcl_GetString(*value);
  2098.     
  2099. while ((c = *string++) != '') {
  2100.     switch (c) {
  2101. case 'n': case 'N': sticky |= STICK_NORTH; break;
  2102. case 'e': case 'E': sticky |= STICK_EAST;  break;
  2103. case 's': case 'S': sticky |= STICK_SOUTH; break;
  2104. case 'w': case 'W': sticky |= STICK_WEST;  break;
  2105. case ' ': case ',': case 't': case 'r': case 'n': break;
  2106. default: {
  2107.     Tcl_ResetResult(interp);
  2108.     Tcl_AppendResult(interp, "bad stickyness value "",
  2109.     Tcl_GetString(*value), "": must be a string ",
  2110.     "containing zero or more of n, e, s, and w",
  2111.     (char *)NULL);
  2112.     return TCL_ERROR;
  2113. }
  2114.     }
  2115. }
  2116.     }
  2117.     if (internalPtr != NULL) {
  2118. *((int *) oldInternalPtr) = *((int *) internalPtr);
  2119. *((int *) internalPtr) = sticky;
  2120.     }
  2121.     return TCL_OK;
  2122. }
  2123. /*
  2124.  *----------------------------------------------------------------------
  2125.  *
  2126.  * RestoreSticky --
  2127.  *
  2128.  * Restore a sticky option value from a saved value.
  2129.  *
  2130.  * Results:
  2131.  * None.
  2132.  *
  2133.  * Side effects:
  2134.  * Restores the old value.
  2135.  *
  2136.  *----------------------------------------------------------------------
  2137.  */
  2138. static void
  2139. RestoreSticky(clientData, tkwin, internalPtr, oldInternalPtr)
  2140.     ClientData clientData;
  2141.     Tk_Window tkwin;
  2142.     char *internalPtr; /* Pointer to storage for value. */
  2143.     char *oldInternalPtr; /* Pointer to old value. */
  2144. {
  2145.     *(int *)internalPtr = *(int *)oldInternalPtr;
  2146. }
  2147. /*
  2148.  *----------------------------------------------------------------------
  2149.  *
  2150.  * AdjustForSticky --
  2151.  *
  2152.  * Given the x,y coords of the top-left corner of a pane, the
  2153.  * dimensions of that pane, and the dimensions of a slave, compute
  2154.  * the x,y coords and actual dimensions of the slave based on the slave's
  2155.  * sticky value.
  2156.  *
  2157.  * Results:
  2158.  * No direct return; sets the x, y, slaveWidth and slaveHeight to
  2159.  * correct values.
  2160.  *
  2161.  * Side effects:
  2162.  * None.
  2163.  *
  2164.  *----------------------------------------------------------------------
  2165.  */
  2166. static void
  2167. AdjustForSticky(sticky, cavityWidth, cavityHeight, xPtr, yPtr,
  2168. slaveWidthPtr, slaveHeightPtr)
  2169.     int sticky; /* Sticky value; see top of file for definition. */
  2170.     int cavityWidth; /* Width of the cavity. */
  2171.     int cavityHeight; /* Height of the cavity. */
  2172.     int *xPtr, *yPtr; /* Initially, coordinates of the top-left
  2173.  * corner of cavity; also return values for
  2174.  * actual x, y coords of slave. */
  2175.     int *slaveWidthPtr; /* Slave width. */
  2176.     int *slaveHeightPtr; /* Slave height. */
  2177. {
  2178.     int diffx=0; /* Cavity width - slave width. */
  2179.     int diffy=0; /* Cavity hight - slave height. */
  2180.     if (cavityWidth > *slaveWidthPtr) {
  2181. diffx = cavityWidth - *slaveWidthPtr;
  2182.     }
  2183.     if (cavityHeight > *slaveHeightPtr) {
  2184. diffy = cavityHeight - *slaveHeightPtr;
  2185.     }
  2186.     if ((sticky & STICK_EAST) && (sticky & STICK_WEST)) {
  2187. *slaveWidthPtr += diffx;
  2188.     }
  2189.     if ((sticky & STICK_NORTH) && (sticky & STICK_SOUTH)) {
  2190. *slaveHeightPtr += diffy;
  2191.     }
  2192.     if (!(sticky & STICK_WEST)) {
  2193.      *xPtr += (sticky & STICK_EAST) ? diffx : diffx/2;
  2194.     }
  2195.     if (!(sticky & STICK_NORTH)) {
  2196.      *yPtr += (sticky & STICK_SOUTH) ? diffy : diffy/2;
  2197.     }
  2198. }
  2199. /*
  2200.  *----------------------------------------------------------------------
  2201.  *
  2202.  * MoveSash --
  2203.  *
  2204.  * Move the sash given by index the amount given.
  2205.  *
  2206.  * Results:
  2207.  * None.
  2208.  *
  2209.  * Side effects:
  2210.  * Recomputes the sizes of the panes in a panedwindow.
  2211.  *
  2212.  *----------------------------------------------------------------------
  2213.  */
  2214. static void
  2215. MoveSash(pwPtr, sash, diff)
  2216.     PanedWindow *pwPtr;
  2217.     int sash;
  2218.     int diff;
  2219. {
  2220.     int i;
  2221.     int expandPane, reduceFirst, reduceLast, reduceIncr, slaveSize, sashOffset;
  2222.     Slave *slavePtr;
  2223.     int stretchReserve = 0;
  2224.     int nextSash = sash + 1;
  2225.     const int horizontal = (pwPtr->orient == ORIENT_HORIZONTAL);
  2226.     if (diff == 0)
  2227. return;
  2228.     /*
  2229.      * Update the slave sizes with their real sizes.
  2230.      */
  2231.     if (pwPtr->showHandle && pwPtr->handleSize > pwPtr->sashWidth) {
  2232. sashOffset = ((pwPtr->handleSize - pwPtr->sashWidth) / 2)
  2233. + pwPtr->sashPad;
  2234.     } else {
  2235. sashOffset = pwPtr->sashPad;
  2236.     }
  2237.     for (i = 0; i < pwPtr->numSlaves; i++) {
  2238. slavePtr = pwPtr->slaves[i];
  2239. if (horizontal) {
  2240.     slavePtr->paneWidth = slavePtr->width = slavePtr->sashx
  2241.     - sashOffset - slavePtr->x - (2 * slavePtr->padx);
  2242. } else {
  2243.     slavePtr->paneWidth = slavePtr->height = slavePtr->sashy
  2244.     - sashOffset - slavePtr->y - (2 * slavePtr->pady);
  2245. }
  2246.     }
  2247.     /*
  2248.      * Consolidate +/-diff variables to reduce duplicate code.
  2249.      */
  2250.     if (diff > 0) {
  2251. expandPane = sash;
  2252. reduceFirst = nextSash;
  2253. reduceLast = pwPtr->numSlaves;
  2254. reduceIncr = 1;
  2255.     } else {
  2256. diff = abs(diff);
  2257. expandPane = nextSash;
  2258. reduceFirst = sash;
  2259. reduceLast = -1;
  2260. reduceIncr = -1;
  2261.     }
  2262.     /*
  2263.      * Calculate how much room we have to stretch in
  2264.      * and adjust diff value accordingly.
  2265.      */
  2266.     for (i = reduceFirst; i != reduceLast; i += reduceIncr) {
  2267. slavePtr = pwPtr->slaves[i];
  2268. if (horizontal) {
  2269.     stretchReserve += slavePtr->width - slavePtr->minSize;
  2270. } else {
  2271.     stretchReserve += slavePtr->height - slavePtr->minSize;
  2272. }
  2273.     }
  2274.     if (stretchReserve <= 0) {
  2275. return;
  2276.     }
  2277.     if (diff > stretchReserve) {
  2278. diff = stretchReserve;
  2279.     }
  2280.     /*
  2281.      * Expand pane by diff amount.
  2282.      */
  2283.     slavePtr = pwPtr->slaves[expandPane];
  2284.     if (horizontal) {
  2285. slavePtr->paneWidth = slavePtr->width += diff;
  2286.     } else {
  2287. slavePtr->paneHeight = slavePtr->height += diff;
  2288.     }
  2289.     /*
  2290.      * Reduce panes, respecting minsize, until diff amount has been used.
  2291.      */
  2292.     for (i = reduceFirst; i != reduceLast; i += reduceIncr) {
  2293. slavePtr = pwPtr->slaves[i];
  2294. if (horizontal) {
  2295.     slaveSize = slavePtr->width;
  2296. } else {
  2297.     slaveSize = slavePtr->height;
  2298. }
  2299. if (diff > (slaveSize - slavePtr->minSize)) {
  2300.     diff -= slaveSize - slavePtr->minSize;
  2301.     slaveSize = slavePtr->minSize;
  2302. } else {
  2303.     slaveSize -= diff;
  2304.     i = reduceLast - reduceIncr;
  2305. }
  2306. if (horizontal) {
  2307.     slavePtr->paneWidth = slavePtr->width = slaveSize;
  2308. } else {
  2309.     slavePtr->paneHeight = slavePtr->height = slaveSize;
  2310. }
  2311.     }
  2312. }
  2313. /*
  2314.  *----------------------------------------------------------------------
  2315.  *
  2316.  * ProxyWindowEventProc --
  2317.  *
  2318.  * This procedure is invoked by the Tk dispatcher for various
  2319.  * events on paned window proxy windows.
  2320.  *
  2321.  * Results:
  2322.  * None.
  2323.  *
  2324.  * Side effects:
  2325.  * When the window gets deleted, internal structures get
  2326.  * cleaned up.  When it gets exposed, it is redisplayed.
  2327.  *
  2328.  *--------------------------------------------------------------
  2329.  */
  2330. static void
  2331. ProxyWindowEventProc(clientData, eventPtr)
  2332.     ClientData clientData; /* Information about window. */
  2333.     XEvent *eventPtr; /* Information about event. */
  2334. {
  2335.     PanedWindow *pwPtr = (PanedWindow *) clientData;
  2336.     if (eventPtr->type == Expose) {
  2337. if (pwPtr->proxywin != NULL &&!(pwPtr->flags & PROXY_REDRAW_PENDING)) {
  2338.     Tcl_DoWhenIdle(DisplayProxyWindow, (ClientData) pwPtr);
  2339.     pwPtr->flags |= PROXY_REDRAW_PENDING;
  2340. }
  2341.     }
  2342. }
  2343. /*
  2344.  *--------------------------------------------------------------
  2345.  *
  2346.  * DisplayProxyWindow --
  2347.  *
  2348.  * This procedure redraws a paned window proxy window.
  2349.  * It is invoked as a do-when-idle handler, so it only runs
  2350.  * when there's nothing else for the application to do.
  2351.  *
  2352.  * Results:
  2353.  * None.
  2354.  *
  2355.  * Side effects:
  2356.  * Information appears on the screen.
  2357.  *
  2358.  *--------------------------------------------------------------
  2359.  */
  2360. static void
  2361. DisplayProxyWindow(clientData)
  2362.     ClientData clientData; /* Information about window. */
  2363. {
  2364.     PanedWindow *pwPtr = (PanedWindow *) clientData;
  2365.     Pixmap pixmap;
  2366.     Tk_Window tkwin = pwPtr->proxywin;
  2367.     pwPtr->flags &= ~PROXY_REDRAW_PENDING;
  2368.     if ((tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  2369. return;
  2370.     }
  2371. #ifndef TK_NO_DOUBLE_BUFFERING
  2372.     /*
  2373.      * Create a pixmap for double-buffering, if necessary.
  2374.      */
  2375.     pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
  2376.     Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  2377. #else
  2378.     pixmap = Tk_WindowId(tkwin);
  2379. #endif /* TK_NO_DOUBLE_BUFFERING */
  2380.     /*
  2381.      * Redraw the widget's background and border.
  2382.      */
  2383.     Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, 0, 0,
  2384.     Tk_Width(tkwin), Tk_Height(tkwin), 2, pwPtr->sashRelief);
  2385. #ifndef TK_NO_DOUBLE_BUFFERING
  2386.     /*
  2387.      * Copy the pixmap to the display.
  2388.      */
  2389.     XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin), pwPtr->gc,
  2390.     0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin),
  2391.     0, 0);
  2392.     Tk_FreePixmap(Tk_Display(tkwin), pixmap);
  2393. #endif /* TK_NO_DOUBLE_BUFFERING */
  2394. }
  2395. /*
  2396.  *----------------------------------------------------------------------
  2397.  *
  2398.  * PanedWindowProxyCommand --
  2399.  *
  2400.  * Handles the panedwindow proxy subcommand.  See the user
  2401.  * documentation for details.
  2402.  *
  2403.  * Results:
  2404.  * Standard Tcl result.
  2405.  *
  2406.  * Side effects:
  2407.  * May map or unmap the proxy sash.
  2408.  *
  2409.  *----------------------------------------------------------------------
  2410.  */
  2411. static int
  2412. PanedWindowProxyCommand(pwPtr, interp, objc, objv)
  2413.     PanedWindow *pwPtr; /* Pointer to paned window information. */
  2414.     Tcl_Interp *interp; /* Current interpreter. */
  2415.     int objc; /* Number of arguments. */
  2416.     Tcl_Obj * CONST objv[]; /* Argument objects. */
  2417. {
  2418.     static CONST char *optionStrings[] = { "coord", "forget", "place",
  2419.  (char *) NULL };
  2420.     enum options { PROXY_COORD, PROXY_FORGET, PROXY_PLACE };
  2421.     int index, x, y, sashWidth, sashHeight;
  2422.     Tcl_Obj *coords[2];
  2423.     
  2424.     if (objc < 3) {
  2425. Tcl_WrongNumArgs(interp, 2, objv, "option ?arg ...?");
  2426. return TCL_ERROR;
  2427.     }
  2428.     if (Tcl_GetIndexFromObj(interp, objv[2], optionStrings, "option", 0,
  2429.     &index) != TCL_OK) {
  2430. return TCL_ERROR;
  2431.     }
  2432.     switch ((enum options) index) {
  2433. case PROXY_COORD:
  2434.     if (objc != 3) {
  2435. Tcl_WrongNumArgs(interp, 3, objv, NULL);
  2436. return TCL_ERROR;
  2437.     }
  2438.     coords[0] = Tcl_NewIntObj(pwPtr->proxyx);
  2439.     coords[1] = Tcl_NewIntObj(pwPtr->proxyy);
  2440.     Tcl_SetListObj(Tcl_GetObjResult(interp), 2, coords);
  2441.     break;
  2442. case PROXY_FORGET:
  2443.     if (objc != 3) {
  2444. Tcl_WrongNumArgs(interp, 3, objv, NULL);
  2445. return TCL_ERROR;
  2446.     }
  2447.     if (Tk_IsMapped(pwPtr->proxywin)) {
  2448. Tk_UnmapWindow(pwPtr->proxywin);
  2449. Tk_UnmaintainGeometry(pwPtr->proxywin, pwPtr->tkwin);
  2450.     }
  2451.     break;
  2452. case PROXY_PLACE: {
  2453.     if (objc != 5) {
  2454. Tcl_WrongNumArgs(interp, 3, objv, "x y");
  2455. return TCL_ERROR;
  2456.     }
  2457.     if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) {
  2458. return TCL_ERROR;
  2459.     }
  2460.     if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) {
  2461. return TCL_ERROR;
  2462.     }
  2463.     if (pwPtr->orient == ORIENT_HORIZONTAL) {
  2464. if (x < 0) {
  2465.     x = 0;
  2466. }
  2467. y = Tk_InternalBorderWidth(pwPtr->tkwin);
  2468. sashWidth = pwPtr->sashWidth;
  2469. sashHeight = Tk_Height(pwPtr->tkwin) -
  2470.     (2 * Tk_InternalBorderWidth(pwPtr->tkwin));
  2471.     } else {
  2472. if (y < 0) {
  2473.     y = 0;
  2474. }
  2475. x = Tk_InternalBorderWidth(pwPtr->tkwin);
  2476. sashHeight = pwPtr->sashWidth;
  2477. sashWidth = Tk_Width(pwPtr->tkwin) -
  2478.     (2 * Tk_InternalBorderWidth(pwPtr->tkwin));
  2479.     }
  2480.     /*
  2481.      * Stash the proxy coordinates for future "proxy coord" calls.
  2482.      */
  2483.     pwPtr->proxyx = x;
  2484.     pwPtr->proxyy = y;
  2485.     
  2486.     /*
  2487.      * Make sure the proxy window is higher in the stacking order
  2488.      * than the slaves, so that it will be visible when drawn.
  2489.      * It would be more correct to push the proxy window just high
  2490.      * enough to appear above the highest slave, but it's much easier
  2491.      * to just force it all the way to the top of the stacking order.
  2492.      */
  2493.     
  2494.     Tk_RestackWindow(pwPtr->proxywin, Above, NULL);
  2495.     
  2496.     /*
  2497.      * Let Tk_MaintainGeometry take care of placing the window at
  2498.      * the right coordinates.
  2499.      */
  2500.     Tk_MaintainGeometry(pwPtr->proxywin, pwPtr->tkwin,
  2501.     x, y, sashWidth, sashHeight);
  2502.     break;
  2503. }
  2504.     }
  2505.     return TCL_OK;
  2506. }
  2507. /*
  2508.  *----------------------------------------------------------------------
  2509.  *
  2510.  * ObjectIsEmpty --
  2511.  *
  2512.  * This procedure tests whether the string value of an object is
  2513.  * empty.
  2514.  *
  2515.  * Results:
  2516.  * The return value is 1 if the string value of objPtr has length
  2517.  * zero, and 0 otherwise.
  2518.  *
  2519.  * Side effects:
  2520.  * May cause object shimmering, since this function can force a
  2521.  * conversion to a string object.
  2522.  *
  2523.  *----------------------------------------------------------------------
  2524.  */
  2525. static int
  2526. ObjectIsEmpty(objPtr)
  2527.     Tcl_Obj *objPtr; /* Object to test.  May be NULL. */
  2528. {
  2529.     int length;
  2530.     if (objPtr == NULL) {
  2531. return 1;
  2532.     }
  2533.     if (objPtr->bytes != NULL) {
  2534. return (objPtr->length == 0);
  2535.     }
  2536.     Tcl_GetStringFromObj(objPtr, &length);
  2537.     return (length == 0);
  2538. }
  2539. /*
  2540.  *----------------------------------------------------------------------
  2541.  *
  2542.  * ComputeInternalPointer --
  2543.  *
  2544.  * Given a pointer to the start of a record and the offset of a slot
  2545.  * within that record, compute the address of that slot.
  2546.  *
  2547.  * Results:
  2548.  * If offset is non-negative, returns the computed address; else,
  2549.  * returns NULL.
  2550.  *
  2551.  * Side effects:
  2552.  * None.
  2553.  *
  2554.  *----------------------------------------------------------------------
  2555.  */
  2556. static char *
  2557. ComputeSlotAddress(recordPtr, offset)
  2558.     char *recordPtr; /* Pointer to the start of a record. */
  2559.     int offset; /* Offset of a slot within that record; may be < 0. */
  2560. {
  2561.     if (offset >= 0) {
  2562. return recordPtr + offset;
  2563.     } else {
  2564. return NULL;
  2565.     }
  2566. }
  2567. /*
  2568.  *----------------------------------------------------------------------
  2569.  *
  2570.  * PanedWindowIdentifyCoords --
  2571.  *
  2572.  * Given a pair of x,y coordinates, identify the panedwindow component
  2573.  * at that point, if any.
  2574.  *
  2575.  * Results:
  2576.  * Standard Tcl result.
  2577.  *
  2578.  * Side effects:
  2579.  * Modifies the interpreter's result to contain either an empty list,
  2580.  * or a two element list of the form {sash n} or {handle n} to indicate
  2581.  * that the point lies within the n'th sash or handle.
  2582.  *
  2583.  *----------------------------------------------------------------------
  2584.  */
  2585. static int
  2586. PanedWindowIdentifyCoords(pwPtr, interp, x, y)
  2587.     PanedWindow *pwPtr; /* Information about the widget. */
  2588.     Tcl_Interp *interp; /* Interpreter in which to store result. */
  2589.     int x, y; /* Coordinates of the point to identify. */
  2590. {
  2591.     Tcl_Obj *list;
  2592.     int i, sashHeight, sashWidth, thisx, thisy;
  2593.     int found, isHandle, lpad, rpad, tpad, bpad;
  2594.     list = Tcl_NewObj();
  2595.     if (pwPtr->orient == ORIENT_HORIZONTAL) {
  2596. if (Tk_IsMapped(pwPtr->tkwin)) {
  2597.     sashHeight = Tk_Height(pwPtr->tkwin);
  2598. } else {
  2599.     sashHeight = Tk_ReqHeight(pwPtr->tkwin);
  2600. }
  2601. sashHeight -= 2 * Tk_InternalBorderWidth(pwPtr->tkwin);
  2602. if (pwPtr->showHandle && pwPtr->handleSize > pwPtr->sashWidth) {
  2603.     sashWidth = pwPtr->handleSize;
  2604.     lpad = (pwPtr->handleSize - pwPtr->sashWidth) / 2;
  2605.     rpad = pwPtr->handleSize - lpad;
  2606.     lpad += pwPtr->sashPad;
  2607.     rpad += pwPtr->sashPad;
  2608. } else {
  2609.     sashWidth = pwPtr->sashWidth;
  2610.     lpad = rpad = pwPtr->sashPad;
  2611. }
  2612. tpad = bpad = 0;
  2613.     } else {
  2614. if (pwPtr->showHandle && pwPtr->handleSize > pwPtr->sashWidth) {
  2615.     sashHeight = pwPtr->handleSize;
  2616.     tpad = (pwPtr->handleSize - pwPtr->sashWidth) / 2;
  2617.     bpad = pwPtr->handleSize - tpad;
  2618.     tpad += pwPtr->sashPad;
  2619.     bpad += pwPtr->sashPad;
  2620. } else {
  2621.     sashHeight = pwPtr->sashWidth;
  2622.     tpad = bpad = pwPtr->sashPad;
  2623. }
  2624. if (Tk_IsMapped(pwPtr->tkwin)) {
  2625.     sashWidth = Tk_Width(pwPtr->tkwin);
  2626. } else {
  2627.     sashWidth = Tk_ReqWidth(pwPtr->tkwin);
  2628. }
  2629. sashWidth -= 2 * Tk_InternalBorderWidth(pwPtr->tkwin);
  2630. lpad = rpad = 0;
  2631.     }
  2632.     
  2633.     isHandle = 0;
  2634.     found = -1;
  2635.     for (i = 0; i < pwPtr->numSlaves - 1; i++) {
  2636. thisx = pwPtr->slaves[i]->sashx;
  2637. thisy = pwPtr->slaves[i]->sashy;
  2638. if (((thisx - lpad) <= x && x <= (thisx + rpad + sashWidth)) &&
  2639. ((thisy - tpad) <= y && y <= (thisy + bpad + sashHeight))) {
  2640.     found = i;
  2641.     /*
  2642.      * Determine if the point is over the handle or the sash.
  2643.      */
  2644.     if (pwPtr->showHandle) {
  2645. thisx = pwPtr->slaves[i]->handlex;
  2646. thisy = pwPtr->slaves[i]->handley;
  2647. if (pwPtr->orient == ORIENT_HORIZONTAL) {
  2648.     if (thisy <= y && y <= (thisy + pwPtr->handleSize)) {
  2649. isHandle = 1;
  2650.     }
  2651. } else {
  2652.     if (thisx <= x && x <= (thisx + pwPtr->handleSize)) {
  2653. isHandle = 1;
  2654.     }
  2655. }
  2656.     }
  2657.     break;
  2658. }
  2659.     }
  2660.     /*
  2661.      * Set results.
  2662.      */
  2663.     if (found != -1) {
  2664. Tcl_ListObjAppendElement(interp, list, Tcl_NewIntObj(found));
  2665. if (isHandle) {
  2666.     Tcl_ListObjAppendElement(interp, list,
  2667.     Tcl_NewStringObj("handle", -1));
  2668. } else {
  2669.     Tcl_ListObjAppendElement(interp, list,
  2670.     Tcl_NewStringObj("sash", -1));
  2671. }
  2672.     }
  2673.     
  2674.     Tcl_SetObjResult(interp, list);
  2675.     return TCL_OK;
  2676. }