|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 16527 (0x408f) Types: TextFile Names: »sxPack.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦526ad3590⟧ »EUUGD11/gnu-31mar87/X.V10.R4.tar.Z« └─⟦2109abc41⟧ └─⟦this⟧ »./X.V10R4/Toolkit/Sx/code/sxPack.c«
/* * $Source: /u1/Sx.new/code/RCS/sxPack.c,v $ * $Header: sxPack.c,v 1.1 86/12/03 16:10:35 swick Exp $ */ #ifndef lint static char *rcsid_sxPack_c = "$Header: sxPack.c,v 1.1 86/12/03 16:10:35 swick Exp $"; #endif lint /* * sxPack.c -- * * This file provides simple layout management within a window * by packing subwindows from the outside in to fill the available * space. * * Copyright (C) 1986 Regents of the University of California. * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting * documentation. The University of California makes no * representations about the suitability of this software for * any purpose. It is provided "as is" without express or * implied warranty. */ #ifndef lint static char rcsid[] = "$Header: sxPack.c,v 1.1 86/12/03 16:10:35 swick Exp $ SPRITE (Berkeley)"; #endif not lint #include <sys/types.h> #include <X/Xlib.h> #include "sprite.h" #include "list.h" #include "mem.h" #include "sx.h" #include "sxInt.h" /* * Records of the type below are used to keep track of windows for * packing purposes. Each window that's involved in packing, either * because its location and size are managed automatically or because * it has other windows packed inside it (or both), has an associated * record. */ typedef struct Packer{ List_Links links; /* Refers to siblings that are also packed * inside this window's parent. Being earlier * on this list gives priority in space * allocation. */ Window w; /* X's identifier for this window. */ int x, y; /* Location of window inside parent. */ int width, height; /* Last known dimensions of window (inside * dimensions, not including border). <= 0 * means window isn't mapped at all. */ int border; /* Twice the width of w's border. */ struct Packer *parentPtr; /* Info describing parent. NULL means this * window isn't packed right now. */ Sx_Side side; /* Side of cavity that window abuts. */ int size; /* Size of window in pixels not including * border,in direction perpendicular to * side. */ List_Links children; /* Head of list of children packed inside * this window. */ int flags; /* Miscellaneous flag values. See below. */ } Packer; /* * Flag values for Packers: * * PARENT: 1 means this window has (at some time, if not * presently) been a parent (which means it has * event handlers set up for it). */ #define PARENT 1 /* * Association table used to keep track of all the Packers, hashed on * window id. */ static XAssocTable *packingTable = NULL; extern XAssocTable *XCreateAssocTable(); /* * Forward references to procedures defined later in this file: */ extern void ArrangePacking(); extern void PackDestroyProc(); extern void PackExposeProc(); \f /* *---------------------------------------------------------------------- * * Sx_Pack -- * * Pack a child window inside a parent window. * * Results: * None. * * Side effects: * From now on, child's size and location will be managed * automatically. Child will be placed along one side of * the cavity remaining inside parent after packing all * children from prior calls to Sx_Pack. If size is greater * than zero, it specifies the size of child in the direction * perpendicular to side. The child will completely fill the * cavity along the given side, and will fill the entire * remaining cavity if size is <= 0. Once this child is placed, * other children (specified in later calls to Sx_Pack) * will only use the space that remains inside parent's cavity * after this child (which may be none). If before or after * is given, the child will be inserted in the packing order, * either before before or after after, rather than at the * end of the packing order. * *---------------------------------------------------------------------- */ void Sx_Pack(child, parent, side, size, border, before, after) Window child; /* Window whose size and location are to * be managed automatically from now on. * Must not already be managed by packer, * and must not be mapped right now. This * module takes care of mapping the child, * either now (if the parent has already * been mapped) or when the parent gets * mapped. */ Window parent; /* Parent of child; child will be packed * in here. Caller must eventually arrange * for this window to be mapped, if it isn't * already mapped. */ Sx_Side side; /* Which side of parent child should be * lined up against. */ int size; /* Dimension of child (not including border) * in direction perpendicular to side. <= 0 * means fill entire cavity. */ int border; /* Width of child's border. */ Window before; /* If non-zero, then insert child in order * before this window. */ Window after; /* If non-zero, then insert child in order * after this window. Must be zero if * before is non-zero. */ { Packer *parentPtr, *child2Ptr; Packer *childPtr; /* * First find the information for the parent, and create a new * Packer if we don't already know about the parent. Before * that, build the association table if it didn't exist already. */ border *= 2; if (packingTable == NULL) { packingTable = XCreateAssocTable(16); } parentPtr = (Packer *) XLookUpAssoc(packingTable, (XId) parent); if (parentPtr == NULL) { WindowInfo info; XQueryWindow(parent, &info); parentPtr = (Packer *) Mem_Alloc(sizeof(Packer)); parentPtr->w = parent; parentPtr->x = info.x; parentPtr->y = info.y; if (info.mapped == IsMapped) { parentPtr->width = info.width; parentPtr->height = info.height; } else { parentPtr->width = parentPtr->height = 0; } parentPtr->parentPtr = NULL; List_Init(&parentPtr->children); parentPtr->flags = 0; (void) Sx_HandlerCreate(parent, SX_DESTROYED, PackDestroyProc, (ClientData) parentPtr); XMakeAssoc(packingTable, (XId) parent, (caddr_t) parentPtr); } if (!(parentPtr->flags & PARENT)) { (void) Sx_HandlerCreate(parent, ExposeWindow, PackExposeProc, (ClientData) parentPtr); parentPtr->flags |= PARENT; } /* * See if there's already a Packer for the child (it might be a parent * too). If so, it better not already be a child. If there isn't * already a Packer for the child, make one. */ childPtr = (Packer *) XLookUpAssoc(packingTable, (XId) child); if (childPtr == NULL) { childPtr = (Packer *) Mem_Alloc(sizeof(Packer)); childPtr->w = child; childPtr->width = childPtr->height = 0; List_Init(&childPtr->children); childPtr->flags = 0; (void) Sx_HandlerCreate(child, SX_DESTROYED, PackDestroyProc, (ClientData) childPtr); XMakeAssoc(packingTable, (XId) child, (caddr_t) childPtr); } else if (childPtr->parentPtr != NULL) { Sx_Panic("Sx_Pack: child was already packed."); } /* * Make sure that the parent isn't already somehow a child of * the child. A cycle would cause all sorts of bizarre behavior. */ for (child2Ptr = parentPtr; child2Ptr != NULL; child2Ptr = child2Ptr->parentPtr) { if (child2Ptr == childPtr) { Sx_Panic("Sx_Pack: parent was already packed as descendant of child. Can't have circular packings."); } } /* * Insert the child in the packing order for the parent. Then * reconfigure the windows inside the parent. */ childPtr->border = border; childPtr->parentPtr = parentPtr; childPtr->side = side; childPtr->size = size; if (before != NULL) { after = before; } if (after != NULL) { child2Ptr = (Packer *) XLookUpAssoc(packingTable, (XId) after); if ((child2Ptr == NULL) || (child2Ptr->parentPtr != parentPtr)) { Sx_Panic("Sx_Pack: tried to pack next to a window that isn't \ packed or isn't a sibling."); } if (before != NULL) { List_Insert(&childPtr->links, LIST_BEFORE(&child2Ptr->links)); } else { List_Insert(&childPtr->links, LIST_AFTER(&child2Ptr->links)); } } else { List_Insert(&childPtr->links, LIST_ATREAR(&parentPtr->children)); } ArrangePacking(parentPtr); } \f /* *---------------------------------------------------------------------- * * Sx_CreatePacked -- * * Like Sx_Pack, except create the window to be packed. * * Results: * The return value is a new window whose size and location * will be managed automatically. If parent is mapped, new child * will be too; otherwise, child will be mapped automatically * when parent becomes mapped. See the comments for Sx_Pack * for information on how the layout is managed. * * Side effects: * A new window is created and packing information is set up. * *---------------------------------------------------------------------- */ Window Sx_CreatePacked(parent, side, size, border, before, after, borderPixmap, backgroundPixmap) Window parent; /* Parent of child; child will be packed * in here. Caller must eventually arrange * for this window to be mapped, if it isn't * already mapped. */ Sx_Side side; /* Which side of parent child should be * lined up against. */ int size; /* Dimension of child (not including border) * in direction perpendicular to side. <= 0 * means fill entire cavity. */ int border; /* Width of child's border. */ Window before; /* If non-zero, then insert child in order * before this window. */ Window after; /* If non-zero, then insert child in order * after this window. Must be zero if * before is non-zero. */ Pixmap borderPixmap; /* Border pixmap to use for new window. */ Pixmap backgroundPixmap; /* Background pixmap to use for new window. */ { Window w; w = XCreateWindow(parent, 0, 0, 1, 1, border, borderPixmap, backgroundPixmap); if (w == NULL) { Sx_Panic("Sx_CreatePacked: couldn't create new window."); } Sx_Pack(w, parent, side, size, border, before, after); return w; } \f /* *---------------------------------------------------------------------- * * Sx_Unpack -- * * Don't manage window's location and size anymore. * * Results: * None. * * Side effects: * Window is removed from the packing list for its parent. It's * also unmapped. * *---------------------------------------------------------------------- */ void Sx_Unpack(window) Window window; /* Window whose layout is no longer to be * managed automatically. */ { register Packer *childPtr; if (packingTable == NULL) { return; } childPtr = (Packer *) XLookUpAssoc(packingTable, (XId) window); if ((childPtr == NULL) || (childPtr->parentPtr == NULL)) { return; } List_Remove(&childPtr->links); childPtr->width = childPtr->height = 0; XUnmapWindow(childPtr->w); ArrangePacking(childPtr->parentPtr); childPtr->parentPtr = NULL; } \f /* *---------------------------------------------------------------------- * * ArrangePacking -- * * This procedure scans through the packing list for a parent * window, computing the correct size for each child and modifying * that child's size if it isn't already correct. * * Results: * None. * * Side effects: * Windows' sizes get changed. * *---------------------------------------------------------------------- */ static void ArrangePacking(parentPtr) register Packer *parentPtr; /* Pointer to structure describing * containing window that is to be * re-arranged. */ { register Packer *childPtr; int x, y, width, height; int cavityX, cavityY, cavityWidth, cavityHeight; cavityX = cavityY = 0; cavityWidth = parentPtr->width; cavityHeight = parentPtr->height; if ((cavityWidth == 0) || (cavityHeight == 0)) { return; /* Why bother? */ } LIST_FORALL(&parentPtr->children, ((List_Links *) childPtr)) { if ((childPtr->side == SX_TOP) || (childPtr->side == SX_BOTTOM)) { width = cavityWidth - childPtr->border; height = childPtr->size; if (height <= 0) { height = cavityHeight - childPtr->border; } cavityHeight -= height + childPtr->border; if (cavityHeight < 0) { height += cavityHeight; cavityHeight = 0; } x = cavityX; if (childPtr->side == SX_TOP) { y = cavityY; cavityY += height + childPtr->border; } else { y = cavityY + cavityHeight; } } else { height = cavityHeight - childPtr->border; width = childPtr->size; if (width <= 0) { width = cavityWidth - childPtr->border; } cavityWidth -= width + childPtr->border; if (cavityWidth < 0) { width += cavityWidth; cavityWidth = 0; } if (childPtr->side == SX_LEFT) { x = cavityX; cavityX += width + childPtr->border; } else { x = cavityX + cavityWidth; } y = cavityY; } /* * If the size or location of the child has changed, any * of several things may have to happen: a) reconfigure * the child; b) unmap the child (if it's too small to be * interesting); c) first reconfigure and then map the * child (if it's just gotten large enough to be interesting * again); and/or d) recursively process the child, if its * interior is also packed. */ if ((x != childPtr->x) || (y != childPtr->y) || (width != childPtr->width) || (height != childPtr->height)) { if ((width <= 0) || (height <= 0)) { if ((childPtr->width > 0) && (childPtr->height > 0)) { XUnmapWindow(childPtr->w); } } else { XConfigureWindow(childPtr->w, x, y, width, height); if ((childPtr->width <= 0) || (childPtr->height <= 0)) { XMapWindow(childPtr->w); } } childPtr->x = x; childPtr->y = y; childPtr->width = width; childPtr->height = height; if (!List_IsEmpty(&childPtr->children)) { ArrangePacking(childPtr); } } } } \f /* *---------------------------------------------------------------------- * * PackExposeProc -- * * Called by the Sx dispatcher whenever an ExposeWindow event * occurs for a window whose internal structure is managed by * this file. If the window's size has changed, then all * the children are re-arranged to match it. * * Results: * None. * * Side effects: * The sizes and locations of children for this window get * re-arranged. * *---------------------------------------------------------------------- */ void PackExposeProc(parentPtr, eventPtr) register Packer *parentPtr; /* Parent window whose size may have * changed. */ register XExposeEvent *eventPtr; /* Gives new size of parent. */ { if (eventPtr->subwindow != 0) { return; } if ((parentPtr->width == eventPtr->width) && (parentPtr->height == eventPtr->height)) { return; } parentPtr->height = eventPtr->height; parentPtr->width = eventPtr->width; ArrangePacking(parentPtr); } \f /* *---------------------------------------------------------------------- * * PackDestroyProc -- * * This procedure is called by the Sx dispatcher whenever * a window is destoryed that is packed or has stuff packed * inside it. * * Results: * None. * * Side effects: * The local data structures get cleaned up. * *---------------------------------------------------------------------- */ void PackDestroyProc(parentPtr, eventPtr) register Packer *parentPtr; /* Info about deleted window. */ register XExposeEvent *eventPtr; /* Gives window id. */ { register Packer *childPtr; Window saved; /* * Make sure that we haven't already cleaned up this window. */ if (XLookUpAssoc(packingTable, (XId) eventPtr->window) == NULL) { return; } XDeleteAssoc(packingTable, (XId) eventPtr->window); /* * Unlink from the parent in which it's packed, if any. */ if (parentPtr->parentPtr != NULL) { List_Remove(&parentPtr->links); ArrangePacking(parentPtr->parentPtr); } /* * Recursively process children. */ parentPtr->width = parentPtr->height = 0; saved = eventPtr->window; LIST_FORALL(&parentPtr->children, (List_Links *) childPtr) { eventPtr->window = childPtr->w; PackDestroyProc(childPtr, eventPtr); } eventPtr->window = saved; Mem_Free((Address) parentPtr); }