/*
* tkPack.c --
*
* This file contains code to implement the "packer"
* geometry manager for Tk.
*
* Copyright (c) 1990-1994 The Regents of the University of California.
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tkPack.c 1.63 96/02/15 18:52:33
*/
#include "tkInt.h"
/* For each window that the packer cares about (either because
* the window is managed by the packer or because the window
* has slaves that are managed by the packer), there is a
* structure of the following type:
*/
typedef struct Packer {
* the window has been deleted, but the
* packet hasn't had a chance to clean up
* yet because the structure is still in
* use. */
* is packed (NULL means this window
* isn't managed by the packer). */
* parent. List is priority-ordered:
* first on list gets packed first. */
* inside this window (NULL means
* no packed slaves). */
* this window is packed. */
* than window needs, this indicates how
* where to position window in frame. */
* window (half of this space is left on each
* side). This is space *outside* the window:
* we'll allocate extra space in frame but
* won't enlarge window). */
* window (half this amount will appear on
* each side). */
* width. If this changes, the window
* must be repacked within its parent. */
* call to ArrangePacking already working on
* this window. *abortPtr may be set to 1 to
* abort that nested call. This happens, for
* example, if tkwin or any of its slaves
* is deleted. */
* for definitions. */
} Packer;
/*
* Flag values for Packer structures:
*
* REQUESTED_REPACK: 1 means a Tcl_DoWhenIdle request
* has already been made to repack
* all the slaves of this window.
* FILLX: 1 means if frame allocated for window
* is wider than window needs, expand window
* to fill frame. 0 means don't make window
* any larger than needed.
* FILLY: Same as FILLX, except for height.
* EXPAND: 1 means this window's frame will absorb any
* extra space in the parent window.
* OLD_STYLE: 1 means this window is being managed with
* the old-style packer algorithms (before
* Tk version 3.3). The main difference is
* that padding and filling are done differently.
* DONT_PROPAGATE: 1 means don't set this window's requested
* size. 0 means if this window is a master
* then Tk will set its requested size to fit
* the needs of its slaves.
*/
/*
* Hash table used to map from Tk_Window tokens to corresponding
* Packer structures:
*/
/*
* Have statics in this module been initialized?
*/
static int initialized = 0;
/*
* The following structure is the official type record for the
* packer:
*/
"pack", /* name */
PackReqProc, /* requestProc */
PackLostSlaveProc, /* lostSlaveProc */
};
/*
* Forward declarations for procedures defined later in this file:
*/
char **argv));
int cavityWidth));
int cavityHeight));
/*
*--------------------------------------------------------------
*
* Tk_PackCmd --
*
* This procedure is invoked to process the "pack" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*--------------------------------------------------------------
*/
int
* interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
int c;
}
if (argc < 3) {
return TCL_ERROR;
}
c = argv[1][0];
return TCL_ERROR;
}
"\" isn't packed", (char *) NULL);
return TCL_ERROR;
}
return TCL_ERROR;
}
}
}
return TCL_ERROR;
}
"\" isn't packed", (char *) NULL);
return TCL_ERROR;
}
} else {
panic("\"pack before\" couldn't find predecessor");
}
break;
}
}
}
"\": must be name of window", (char *) NULL);
return TCL_ERROR;
}
int i;
for (i = 2; i < argc; i++) {
continue;
}
(ClientData) NULL);
}
}
}
if (argc != 3) {
return TCL_ERROR;
}
return TCL_ERROR;
}
"\" isn't packed", (char *) NULL);
return TCL_ERROR;
}
(char *) NULL);
case 0:
break;
case FILLX:
break;
case FILLY:
break;
break;
}
(char *) NULL);
int propagate;
if (argc > 4) {
return TCL_ERROR;
}
return TCL_ERROR;
}
if (argc == 3) {
} else {
}
return TCL_OK;
}
return TCL_ERROR;
}
if (propagate) {
/*
* Repack the master to allow new geometry information to
* propagate upwards to the master's master.
*/
}
}
} else {
}
if (argc != 3) {
return TCL_ERROR;
}
return TCL_ERROR;
}
}
if (argc != 3) {
return TCL_ERROR;
}
return TCL_ERROR;
}
(ClientData) NULL);
}
}
} else {
"\": must be configure, forget, info, ",
"propagate, or slaves", (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* PackReqProc --
*
* This procedure is invoked by Tk_GeometryRequest for
* windows managed by the packer.
*
* Results:
* None.
*
* Side effects:
* Arranges for tkwin, and all its managed siblings, to
* be re-packed at the next idle point.
*
*--------------------------------------------------------------
*/
/* ARGSUSED */
static void
* window that got new preferred
* geometry. */
* about the window. */
{
}
}
/*
*--------------------------------------------------------------
*
* PackLostSlaveProc --
*
* This procedure is invoked by Tk whenever some other geometry
* claims control over a slave that used to be managed by us.
*
* Results:
* None.
*
* Side effects:
* Forgets all packer-related information about the slave.
*
*--------------------------------------------------------------
*/
/* ARGSUSED */
static void
* was stolen away. */
{
}
}
/*
*--------------------------------------------------------------
*
* ArrangePacking --
*
* This procedure is invoked (using the Tcl_DoWhenIdle
* mechanism) to re-layout a set of windows managed by
* the packer. It is invoked at idle time so that a
* series of packer requests can be merged into a single
* layout operation.
*
* Results:
* None.
*
* Side effects:
* The packed slaves of masterPtr may get resized or
* moved.
*
*--------------------------------------------------------------
*/
static void
* are to be re-layed out. */
{
/* These variables keep track of the
* as-yet-unallocated space remaining in
* the middle of the parent window. */
/* These variables keep track of the frame
* allocated to the current window. */
* actual geometry of the current window. */
* if any. */
* repacking operation. */
/*
* If the parent has no slaves anymore, then don't do anything
* at all: just leave the parent's size as-is.
*/
return;
}
/*
* Abort any nested call to ArrangePacking for this window, since
* we'll do everything necessary here, and set up so this call
* can be aborted if necessary.
*/
}
abort = 0;
/*
* Pass #1: scan all the slaves to figure out the total amount
* of space needed. Two separate width and height values are
* computed:
*
* width - Holds the sum of the widths (plus padding) of
* all the slaves seen so far that were packed LEFT
* or RIGHT.
* height - Holds the sum of the heights (plus padding) of
* all the slaves seen so far that were packed TOP
* or BOTTOM.
*
* maxWidth - Gradually builds up the width needed by the master
* to just barely satisfy all the slave's needs. For
* each slave, the code computes the width needed for
* all the slaves so far and updates maxWidth if the
* new value is greater.
* maxHeight - Same as maxWidth, except keeps height info.
*/
}
} else {
}
}
}
}
}
/*
* If the total amount of space needed in the parent window has
* changed, and if we're propagating geometry information, then
* notify the next geometry manager up and requeue ourselves to
* start again after the parent has had a chance to
* resize us.
*/
goto done;
}
/*
* Pass #2: scan the slaves a second time assigning
* new sizes. The "cavity" variables keep track of the
* unclaimed space in the cavity of the window; this
* shrinks inward as we allocate windows around the
* edges. The "frame" variables keep track of the space
* allocated to the current window and its frame. The
* current window is then placed somewhere inside the
* frame, depending on anchor.
*/
}
if (cavityHeight < 0) {
cavityHeight = 0;
}
cavityY += frameHeight;
} else {
}
} else {
}
if (cavityWidth < 0) {
cavityWidth = 0;
}
cavityX += frameWidth;
} else {
}
}
/*
* Now that we've got the size of the frame for the window,
* compute the window's actual size and location using the
* fill, padding, and frame factors. The variables "borderX"
* and "borderY" are used to handle the differences between
* old-style packing and the new style (in old-style, iPadX
* and iPadY are always zero and padding is completely ignored
* except when computing frame size).
*/
} else {
}
}
}
borderX /= 2;
borderY /= 2;
case TK_ANCHOR_N:
break;
case TK_ANCHOR_NE:
break;
case TK_ANCHOR_E:
break;
case TK_ANCHOR_SE:
break;
case TK_ANCHOR_S:
break;
case TK_ANCHOR_SW:
break;
case TK_ANCHOR_W:
break;
case TK_ANCHOR_NW:
break;
case TK_ANCHOR_CENTER:
break;
default:
panic("bad frame factor in ArrangePacking");
}
/*
* state of the slave. If the slave is a child of the master, then
* do this here. Otherwise let Tk_MaintainGeometry do the work.
*/
} else {
}
if (abort) {
goto done;
}
/*
* Don't map the slave if the master isn't mapped: wait
* until the master gets mapped later.
*/
}
}
} else {
} else {
}
}
/*
* Changes to the window's structure could cause almost anything
* to happen, including deleting the parent or child. If this
* happens, we'll be told to abort.
*/
if (abort) {
goto done;
}
}
done:
}
/*
*----------------------------------------------------------------------
*
* XExpansion --
*
* Given a list of packed slaves, the first of which is packed
* on the left or right and is expandable, compute how much to
* expand the child.
*
* Results:
* The return value is the number of additional pixels to give to
* the child.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
* slaves. */
int cavityWidth; /* Horizontal space left for all
* remaining slaves. */
{
int childWidth;
/*
* This procedure is tricky because windows packed top or bottom can
* be interspersed among expandable windows packed left or right.
* Scan through the list, keeping a running sum of the widths of
* all left and right windows (actually, count the cavity space not
* allocated) and a running count of all expandable left and right
* windows. At each top or bottom window, and at the end of the
* list, compute the expansion factor that seems reasonable at that
* point. Return the smallest factor seen at any of these points.
*/
numExpand = 0;
}
} else {
numExpand++;
}
}
}
}
}
/*
*----------------------------------------------------------------------
*
* YExpansion --
*
* Given a list of packed slaves, the first of which is packed
* on the top or bottom and is expandable, compute how much to
* expand the child.
*
* Results:
* The return value is the number of additional pixels to give to
* the child.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
* slaves. */
int cavityHeight; /* Vertical space left for all
* remaining slaves. */
{
int childHeight;
/*
* See comments for XExpansion.
*/
numExpand = 0;
}
} else {
numExpand++;
}
}
}
}
}
/*
*--------------------------------------------------------------
*
* GetPacker --
*
* This internal procedure is used to locate a Packer
* structure for a given window, creating one if one
* doesn't exist already.
*
* Results:
* The return value is a pointer to the Packer structure
* corresponding to tkwin.
*
* Side effects:
* A new packer structure may be created. If so, then
* a callback is set up to clean things up when the
* window is deleted.
*
*--------------------------------------------------------------
*/
static Packer *
* packer structure is desired. */
{
int new;
if (!initialized) {
initialized = 1;
}
/*
* See if there's already packer for this window. If not,
* then create a new one.
*/
if (!new) {
}
return packPtr;
}
/*
*--------------------------------------------------------------
*
* PackAfter --
*
* This procedure does most of the real work of adding
* one or more windows into the packing order for its parent.
*
* Results:
* A standard Tcl return value.
*
* Side effects:
* The geometry of the specified windows may change, both now and
* again in the future.
*
*--------------------------------------------------------------
*/
static int
* window; NULL means pack as first
* child of masterPtr. */
int argc; /* Number of elements in argv. */
char **argv; /* Array of lists, each containing 2
* elements: window name and side
* against which to pack. */
{
char **options;
/*
* Iterate over all of the window specifiers, each consisting of
* two arguments. The first argument contains the window name and
* the additional arguments contain options such as "top" or
* "padx 20".
*/
if (argc < 2) {
argv[0], "\" should be followed by options",
(char *) NULL);
return TCL_ERROR;
}
/*
* Find the packer for the window to be packed, and make sure
* that the window in which it will be packed is either its
* or a descendant of its parent.
*/
return TCL_ERROR;
}
break;
}
(char *) NULL);
return TCL_ERROR;
}
}
goto badWindow;
}
goto badWindow;
}
/*
* Process options for this window.
*/
return TCL_ERROR;
}
c = curOpt[0];
if ((c == 't')
} else if ((c == 'b')
} else if ((c == 'l')
} else if ((c == 'r')
} else if ((c == 'e')
} else if ((c == 'f')
"\" option must be followed by screen distance",
(char *) NULL);
goto error;
}
"\": must be positive screen distance",
(char *) NULL);
goto error;
}
index++;
goto missingPad;
}
goto badPad;
}
index++;
"option must be followed by anchor point",
(char *) NULL);
goto error;
}
goto error;
}
index++;
} else {
"\": should be top, bottom, left, right, ",
"expand, fill, fillx, filly, padx, pady, or frame",
(char *) NULL);
goto error;
}
}
/*
* Unpack this window if it's currently packed.
*/
}
}
/*
* Add the window in the correct place in its parent's
* packing order, then make sure that the window is
* managed by us.
*/
} else {
}
}
}
/*
* Arrange for the parent to be re-packed at the first
* idle moment.
*/
}
}
return TCL_OK;
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* Unlink --
*
* Remove a packer from its parent's list of slaves.
*
* Results:
* None.
*
* Side effects:
* The parent will be scheduled for repacking.
*
*----------------------------------------------------------------------
*/
static void
{
return;
}
} else {
panic("Unlink couldn't find previous window");
}
break;
}
}
}
}
}
}
/*
*----------------------------------------------------------------------
*
* DestroyPacker --
*
* This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
* to clean up the internal structure of a packer at a safe time
* (when no-one is using it anymore).
*
* Results:
* None.
*
* Side effects:
* Everything associated with the packer is freed up.
*
*----------------------------------------------------------------------
*/
static void
char *memPtr; /* Info about packed window that
* is now dead. */
{
}
/*
*----------------------------------------------------------------------
*
* PackStructureProc --
*
* This procedure is invoked by the Tk event dispatcher in response
* to StructureNotify events.
*
* Results:
* None.
*
* Side effects:
* If a window was just deleted, clean up all its packer-related
* information. If it was just resized, repack its slaves, if
* any.
*
*----------------------------------------------------------------------
*/
static void
* referred to by eventPtr. */
{
}
}
}
}
(ClientData) NULL);
}
}
/*
* When a master gets mapped, must redo the geometry computation
* so that all of its slaves get remapped.
*/
}
/*
* Unmap all of the slaves when the master gets unmapped,
* so that they don't bother to keep redisplaying
* themselves.
*/
}
}
}
/*
*----------------------------------------------------------------------
*
* ConfigureSlaves --
*
* This implements the guts of the "pack configure" command. Given
* a list of slaves and configuration options, it arranges for the
* packer to manage the slaves and sets the specified options.
*
* Results:
* TCL_OK is returned if all went well. Otherwise, TCL_ERROR is
* returned and interp->result is set to contain an error message.
*
* Side effects:
* Slave windows get taken over by the packer.
*
*----------------------------------------------------------------------
*/
static int
* slaves. Used to look up slave names. */
int argc; /* Number of elements in argv. */
char *argv[]; /* Argument strings: contains one or more
* window names followed by any number
* of "option value" pairs. Caller must
* make sure that there is at least one
* window name. */
{
/*
* Find out how many windows are specified.
*/
break;
}
}
/*
* Iterate over all of the slave windows, parsing the configuration
* options for each slave. It's a bit wasteful to re-parse the
* options for each slave, but things get too messy if we try to
* parse the arguments just once at the beginning. For example,
* if a slave already is packed we want to just change a few
* existing values without resetting everything. If there are
* multiple windows, the -after, -before, and -in options only
* get processed for the first window.
*/
positionGiven = 0;
for (j = 0; j < numWindows; j++) {
return TCL_ERROR;
}
if (Tk_IsTopLevel(slave)) {
"\": it's a top-level window", (char *) NULL);
return TCL_ERROR;
}
/*
* If the slave isn't currently packed, reset all of its
* configuration information to default values (there could
* be old values left from a previous packing).
*/
}
if ((i+2) > argc) {
"\" (option with no value?)", (char *) NULL);
return TCL_ERROR;
}
if (length < 2) {
goto badOption;
}
c = argv[i][1];
&& (length >= 2)) {
if (j == 0) {
return TCL_ERROR;
}
"\" isn't packed", (char *) NULL);
return TCL_ERROR;
}
positionGiven = 1;
}
&& (length >= 2)) {
!= TCL_OK) {
return TCL_ERROR;
}
} else if ((c == 'b')
if (j == 0) {
return TCL_ERROR;
}
goto notPacked;
}
} else {
}
}
positionGiven = 1;
}
} else if ((c == 'e')
return TCL_ERROR;
}
if (tmp) {
}
} else {
"\": must be none, x, y, or both", (char *) NULL);
return TCL_ERROR;
}
if (j == 0) {
return TCL_ERROR;
}
}
}
positionGiven = 1;
}
|| (tmp < 0)) {
"\": must be positive screen distance",
(char *) NULL);
return TCL_ERROR;
}
|| (tmp< 0)) {
goto badPad;
}
|| (tmp< 0)) {
goto badPad;
}
|| (tmp< 0)) {
goto badPad;
}
c = argv[i+1][0];
} else {
"\": must be top, bottom, left, or right",
(char *) NULL);
return TCL_ERROR;
}
} else {
argv[i], "\": must be -after, -anchor, -before, ",
"-expand, -fill, -in, -ipadx, -ipady, -padx, ",
"-pady, or -side", (char *) NULL);
return TCL_ERROR;
}
}
/*
* If no position in a packing list was specified and the slave
* is already packed, then leave it in its current location in
* its current packing list.
*/
goto scheduleLayout;
}
/*
* If the slave is going to be put back after itself then
* skip the whole operation, since it won't work anyway.
*/
goto scheduleLayout;
}
/*
* If none of the "-in", "-before", or "-after" options has
* been specified, arrange for the slave to go at the end of
* the order for its parent.
*/
if (!positionGiven) {
}
}
}
/*
* Make sure that the slave's parent is either the master or
* an ancestor of the master, and that the master and slave
* aren't the same.
*/
break;
}
if (Tk_IsTopLevel(ancestor)) {
(char *) NULL);
return TCL_ERROR;
}
}
" inside itself", (char *) NULL);
return TCL_ERROR;
}
/*
* Unpack the slave if it's currently packed, then position it
* after prevPtr.
*/
}
}
} else {
}
/*
* Arrange for the parent to be re-packed at the first
* idle moment.
*/
}
}
}
return TCL_OK;
}