diff options
Diffstat (limited to 'libXaw/src/Box.c')
-rw-r--r-- | libXaw/src/Box.c | 1344 |
1 files changed, 672 insertions, 672 deletions
diff --git a/libXaw/src/Box.c b/libXaw/src/Box.c index 5c6cfa2a2..7aa14a5e8 100644 --- a/libXaw/src/Box.c +++ b/libXaw/src/Box.c @@ -1,672 +1,672 @@ -/***********************************************************
-
-Copyright 1987, 1988, 1994, 1998 The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, 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 above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from The Open Group.
-
-
-Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
-
- All Rights Reserved
-
-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, and that the name of Digital not be
-used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission.
-
-DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
-DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
-SOFTWARE.
-
-******************************************************************/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <X11/IntrinsicP.h>
-#include <X11/StringDefs.h>
-#include <X11/Xmu/Misc.h>
-#include <X11/Xaw/BoxP.h>
-#include <X11/Xaw/XawInit.h>
-#include "Private.h"
-
-/*
- * Class Methods
- */
-static void XawBoxChangeManaged(Widget);
-static void XawBoxClassInitialize(void);
-#ifndef OLDXAW
-static void XawBoxExpose(Widget, XEvent*, Region);
-#endif
-static XtGeometryResult XawBoxGeometryManager(Widget, XtWidgetGeometry*,
- XtWidgetGeometry*);
-static void XawBoxInitialize(Widget, Widget, ArgList, Cardinal*);
-static XtGeometryResult XawBoxQueryGeometry(Widget, XtWidgetGeometry*,
- XtWidgetGeometry*);
-static void XawBoxRealize(Widget, Mask*, XSetWindowAttributes*);
-static void XawBoxResize(Widget);
-static Boolean XawBoxSetValues(Widget, Widget, Widget,
- ArgList, Cardinal*);
-
-/*
- * Prototypes
- */
-static void DoLayout(BoxWidget, unsigned int, unsigned int,
- Dimension*, Dimension*, Bool);
-static Bool TryNewLayout(BoxWidget);
-
-/*
- * Initialization
- */
-#ifndef OLDXAW
-static XtActionsRec actions[] = {
- {"set-values", XawSetValuesAction},
- {"get-values", XawGetValuesAction},
- {"declare", XawDeclareAction},
- {"call-proc", XawCallProcAction},
-};
-#endif
-
-static XtResource resources[] = {
- {
- XtNhSpace,
- XtCHSpace,
- XtRDimension,
- sizeof(Dimension),
- XtOffsetOf(BoxRec, box.h_space),
- XtRImmediate,
- (XtPointer)4
- },
- {
- XtNvSpace,
- XtCVSpace,
- XtRDimension,
- sizeof(Dimension),
- XtOffsetOf(BoxRec, box.v_space),
- XtRImmediate,
- (XtPointer)4
- },
- {
- XtNorientation,
- XtCOrientation,
- XtROrientation,
- sizeof(XtOrientation),
- XtOffsetOf(BoxRec, box.orientation),
- XtRImmediate,
- (XtPointer)XtorientVertical
- },
-#ifndef OLDXAW
- {
- XawNdisplayList,
- XawCDisplayList,
- XawRDisplayList,
- sizeof(XawDisplayList*),
- XtOffsetOf(BoxRec, box.display_list),
- XtRImmediate,
- NULL
- },
-#endif
-};
-
-BoxClassRec boxClassRec = {
- /* core */
- {
- (WidgetClass)&compositeClassRec, /* superclass */
- "Box", /* class_name */
- sizeof(BoxRec), /* widget_size */
- XawBoxClassInitialize, /* class_initialize */
- NULL, /* class_part_init */
- False, /* class_inited */
- XawBoxInitialize, /* initialize */
- NULL, /* initialize_hook */
- XawBoxRealize, /* realize */
-#ifndef OLDXAW
- actions, /* actions */
- XtNumber(actions), /* num_actions */
-#else
- NULL, /* actions */
- 0, /* num_actions */
-#endif
- resources, /* resources */
- XtNumber(resources), /* num_resources */
- NULLQUARK, /* xrm_class */
- True, /* compress_motion */
- True, /* compress_exposure */
- True, /* compress_enterleave */
- False, /* visible_interest */
- NULL, /* destroy */
- XawBoxResize, /* resize */
-#ifndef OLDXAW
- XawBoxExpose, /* expose */
-#else
- NULL, /* expose */
-#endif
- XawBoxSetValues, /* set_values */
- NULL, /* set_values_hook */
- XtInheritSetValuesAlmost, /* set_values_almost */
- NULL, /* get_values_hook */
- NULL, /* accept_focus */
- XtVersion, /* version */
- NULL, /* callback_private */
- NULL, /* tm_table */
- XawBoxQueryGeometry, /* query_geometry */
- XtInheritDisplayAccelerator, /* display_accelerator */
- NULL, /* extension */
- },
- /* composite */
- {
- XawBoxGeometryManager, /* geometry_manager */
- XawBoxChangeManaged, /* change_managed */
- XtInheritInsertChild, /* insert_child */
- XtInheritDeleteChild, /* delete_child */
- NULL, /* extension */
- },
- /* box */
- {
- NULL, /* extension */
- },
-};
-
-WidgetClass boxWidgetClass = (WidgetClass)&boxClassRec;
-
-/*
- * Do a layout, either actually assigning positions, or just calculating size.
- * Returns minimum width and height that will preserve the same layout.
- */
-static void
-DoLayout(BoxWidget bbw, unsigned int width, unsigned int height,
- Dimension *reply_width, Dimension *reply_height, Bool position)
-{
- Boolean vbox = (bbw->box.orientation == XtorientVertical);
- Cardinal i;
- Dimension w, h; /* Width and height needed for box */
- Dimension lw, lh; /* Width and height needed for current line */
- Dimension bw, bh; /* Width and height needed for current widget */
- Dimension h_space; /* Local copy of bbw->box.h_space */
- Widget widget; /* Current widget */
- unsigned int num_mapped_children = 0;
-
- /* Box width and height */
- h_space = bbw->box.h_space;
-
- w = 0;
- for (i = 0; i < bbw->composite.num_children; i++) {
- if (XtIsManaged(bbw->composite.children[i])
- && bbw->composite.children[i]->core.width > w)
- w = bbw->composite.children[i]->core.width;
- }
- w += h_space;
- if (w > width)
- width = w;
- h = bbw->box.v_space;
-
- /* Line width and height */
- lh = 0;
- lw = h_space;
-
- for (i = 0; i < bbw->composite.num_children; i++) {
- widget = bbw->composite.children[i];
- if (widget->core.managed) {
- if (widget->core.mapped_when_managed)
- num_mapped_children++;
- /* Compute widget width */
- bw = XtWidth(widget) + (XtBorderWidth(widget)<<1) + h_space;
- if ((Dimension)(lw + bw) > width) {
- if (lw > h_space) {
- /* At least one widget on this line, and
- * can't fit any more. Start new line if vbox
- */
- AssignMax(w, lw);
- if (vbox) {
- h += lh + bbw->box.v_space;
- lh = 0;
- lw = h_space;
- }
- }
- else if (!position) {
- /* too narrow for this widget; we'll assume we can grow */
- DoLayout(bbw, (unsigned)(lw + bw), height, reply_width,
- reply_height, position);
- return;
- }
- }
- if (position && (lw != XtX(widget) || h != XtY(widget))) {
- /* It would be nice to use window gravity, but there isn't
- * sufficient fine-grain control to nicely handle all
- * situations (e.g. when only the height changes --
- * a common case). Explicit unmapping is a cheap hack
- * to speed things up & avoid the visual jitter as
- * things slide around.
- *
- * %%% perhaps there should be a client resource to
- * control this. If so, we'll have to optimize to
- * perform the moves from the correct end so we don't
- * force extra exposures as children occlude each other.
- */
- if (XtIsRealized(widget) && widget->core.mapped_when_managed)
- XUnmapWindow( XtDisplay(widget), XtWindow(widget));
- XtMoveWidget(widget, (int)lw, (int)h);
- }
- lw += bw;
- bh = XtHeight(widget) + (XtBorderWidth(widget) << 1);
- AssignMax(lh, bh);
- }
- }
-
- if (!vbox && width && lw > width && lh < height) {
- /* reduce width if too wide and height not filled */
- Dimension sw = lw, sh = lh;
- Dimension width_needed = width;
- XtOrientation orientation = bbw->box.orientation;
-
- bbw->box.orientation = XtorientVertical;
- while (sh < height && sw > width) {
- width_needed = sw;
- DoLayout(bbw, (unsigned)(sw-1), height, &sw, &sh, False);
- }
- if (sh < height)
- width_needed = sw;
- if (width_needed != lw) {
- DoLayout(bbw, width_needed, height,
- reply_width, reply_height, position);
- bbw->box.orientation = orientation;
- return;
- }
- bbw->box.orientation = orientation;
- }
- if (vbox && (width < w || width < lw)) {
- AssignMax(w, lw);
- DoLayout(bbw, w, height, reply_width, reply_height, position);
- return;
- }
- if (position && XtIsRealized((Widget)bbw)) {
- if (bbw->composite.num_children == num_mapped_children)
- XMapSubwindows(XtDisplay((Widget)bbw), XtWindow((Widget)bbw));
- else {
- int ii = bbw->composite.num_children;
- Widget *childP = bbw->composite.children;
-
- for (; ii > 0; childP++, ii--)
- if (XtIsRealized(*childP) && XtIsManaged(*childP)
- && (*childP)->core.mapped_when_managed)
- XtMapWidget(*childP);
- }
- }
-
- /* Finish off last line */
- if (lw > h_space) {
- AssignMax(w, lw);
- h += lh + bbw->box.v_space;
- }
-
- *reply_width = Max(w, 1);
- *reply_height = Max(h, 1);
-}
-
-/*
- * Calculate preferred size, given constraining box, caching it in the widget
- */
-static XtGeometryResult
-XawBoxQueryGeometry(Widget widget, XtWidgetGeometry *constraint,
- XtWidgetGeometry *preferred)
-{
- BoxWidget w = (BoxWidget)widget;
- Dimension width;
- Dimension preferred_width = w->box.preferred_width;
- Dimension preferred_height = w->box.preferred_height;
-
- constraint->request_mode &= CWWidth | CWHeight;
-
- if (constraint->request_mode == 0)
- /* parent isn't going to change w or h, so nothing to re-compute */
- return (XtGeometryYes);
-
- if (constraint->request_mode == w->box.last_query_mode
- && (!(constraint->request_mode & CWWidth)
- || constraint->width == w->box.last_query_width)
- && (!(constraint->request_mode & CWHeight)
- || constraint->height == w->box.last_query_height)) {
- /* same query; current preferences are still valid */
- preferred->request_mode = CWWidth | CWHeight;
- preferred->width = preferred_width;
- preferred->height = preferred_height;
- if (constraint->request_mode == (CWWidth | CWHeight)
- && constraint->width == preferred_width
- && constraint->height == preferred_height)
- return (XtGeometryYes);
- else
- return (XtGeometryAlmost);
- }
-
- /* else gotta do it the long way...
- I have a preference for tall and narrow, so if my width is
- constrained, I'll accept it; otherwise, I'll compute the minimum
- width that will fit me within the height constraint */
-
- w->box.last_query_mode = constraint->request_mode;
- w->box.last_query_width = constraint->width;
- w->box.last_query_height= constraint->height;
-
- if (constraint->request_mode & CWWidth)
- width = constraint->width;
- else { /* if (constraint->request_mode & CWHeight) */
- /* let's see if I can become any narrower */
- width = 0;
- constraint->width = 65535;
- }
-
- /* height is currently ignored by DoLayout.
- height = (constraint->request_mode & CWHeight) ? constraint->height
- : *preferred_height;
- */
- DoLayout(w, width, 0, &preferred_width, &preferred_height, False);
-
- if (constraint->request_mode & CWHeight
- && preferred_height > constraint->height) {
- /* find minimum width for this height */
- if (preferred_width <= constraint->width) {
- width = preferred_width;
- do { /* find some width big enough to stay within this height */
- width <<= 1;
- if (width > constraint->width)
- width = constraint->width;
- DoLayout(w, width, 0, &preferred_width, &preferred_height, False);
- } while (preferred_height > constraint->height
- && width < constraint->width);
- if (width != constraint->width) {
- do { /* find minimum width */
- width = preferred_width;
- DoLayout(w, (unsigned)(preferred_width - 1), 0,
- &preferred_width, &preferred_height, False);
- } while (preferred_height < constraint->height);
- /* one last time */
- DoLayout(w, width, 0, &preferred_width, &preferred_height, False);
- }
- }
- }
-
- preferred->request_mode = CWWidth | CWHeight;
- preferred->width = w->box.preferred_width = preferred_width;
- preferred->height = w->box.preferred_height = preferred_height;
-
- if (constraint->request_mode == (CWWidth|CWHeight)
- && constraint->width == preferred_width
- && constraint->height == preferred_height)
- return (XtGeometryYes);
-
- return (XtGeometryAlmost);
-}
-
-/*
- * Actually layout the box
- */
-static void
-XawBoxResize(Widget w)
-{
- Dimension tmp;
-
- DoLayout((BoxWidget)w, XtWidth(w), XtHeight(w), &tmp, &tmp, True);
-}
-
-/*
- * Try to do a new layout within the current width and height;
- * if that fails try to resize and do it within the box returne
- * by XawBoxQueryGeometry
- *
- * TryNewLayout just says if it's possible, and doesn't actually move the kids
- */
-static Bool
-TryNewLayout(BoxWidget bbw)
-{
- Dimension preferred_width, preferred_height;
- Dimension proposed_width, proposed_height;
- int iterations;
-
- DoLayout(bbw, bbw->core.width, bbw->core.height,
- &preferred_width, &preferred_height, False);
-
- /* at this point, preferred_width is guaranteed to not be greater
- than bbw->core.width unless some child is larger, so there's no
- point in re-computing another layout */
-
- if (XtWidth(bbw) == preferred_width && XtHeight(bbw) == preferred_height)
- return (True);
-
- /* let's see if our parent will go for a new size */
- iterations = 0;
- proposed_width = preferred_width;
- proposed_height = preferred_height;
- do {
- switch (XtMakeResizeRequest((Widget)bbw,proposed_width,proposed_height,
- &proposed_width, &proposed_height)) {
- case XtGeometryYes:
- return (True);
- case XtGeometryNo:
- if (iterations > 0)
- /* protect from malicious parents who change their minds */
- DoLayout(bbw, bbw->core.width, bbw->core.height,
- &preferred_width, &preferred_height, False);
- if (preferred_width <= XtWidth(bbw)
- && preferred_height <= XtHeight(bbw))
- return (True);
- else
- return (False);
- case XtGeometryAlmost:
- if (proposed_height >= preferred_height &&
- proposed_width >= preferred_width) {
- /*
- * Take it, and assume the parent knows what it is doing.
- *
- * The parent must accept this since it was returned in
- * almost.
- */
- (void)XtMakeResizeRequest((Widget)bbw,
- proposed_width, proposed_height,
- &proposed_width, &proposed_height);
- return (True);
- }
- else if (proposed_width != preferred_width) {
- /* recalc bounding box; height might change */
- DoLayout(bbw, proposed_width, 0,
- &preferred_width, &preferred_height, False);
- proposed_height = preferred_height;
- }
- else { /* proposed_height != preferred_height */
- XtWidgetGeometry constraints, reply;
-
- constraints.request_mode = CWHeight;
- constraints.height = proposed_height;
- (void)XawBoxQueryGeometry((Widget)bbw, &constraints, &reply);
- proposed_width = preferred_width;
- }
- /*FALLTHROUGH*/
- default:
- break;
- }
- iterations++;
- } while (iterations < 10);
-
- return (False);
-}
-
-/*
- * Geometry Manager
- *
- * 'reply' is unused; we say only yeay or nay, never almost.
- */
-/*ARGSUSED*/
-static XtGeometryResult
-XawBoxGeometryManager(Widget w, XtWidgetGeometry *request,
- XtWidgetGeometry *reply)
-{
- Dimension width, height, borderWidth;
- BoxWidget bbw;
-
- /* Position request always denied */
- if (((request->request_mode & CWX) && request->x != XtX(w))
- || ((request->request_mode & CWY) && request->y != XtY(w)))
- return (XtGeometryNo);
-
- /* Size changes must see if the new size can be accomodated */
- if (request->request_mode & (CWWidth | CWHeight | CWBorderWidth)) {
- /* Make all three fields in the request valid */
- if ((request->request_mode & CWWidth) == 0)
- request->width = XtWidth(w);
- if ((request->request_mode & CWHeight) == 0)
- request->height = XtHeight(w);
- if ((request->request_mode & CWBorderWidth) == 0)
- request->border_width = XtBorderWidth(w);
-
- /* Save current size and set to new size */
- width = XtWidth(w);
- height = XtHeight(w);
- borderWidth = XtBorderWidth(w);
- XtWidth(w) = request->width;
- XtHeight(w) = request->height;
- XtBorderWidth(w) = request->border_width;
-
- /* Decide if new layout works:
- (1) new widget is smaller,
- (2) new widget fits in existing Box,
- (3) Box can be expanded to allow new widget to fit
- */
-
- bbw = (BoxWidget) w->core.parent;
-
- if (TryNewLayout(bbw)) {
- /* Fits in existing or new space, relayout */
- (*XtClass((Widget)bbw)->core_class.resize)((Widget)bbw);
- return (XtGeometryYes);
- }
- else {
- /* Cannot satisfy request, change back to original geometry */
- XtWidth(w) = width;
- XtHeight(w) = height;
- XtBorderWidth(w) = borderWidth;
- return (XtGeometryNo);
- }
- }
-
- /* Any stacking changes don't make a difference, so allow if that's all */
- return (XtGeometryYes);
-}
-
-static void
-XawBoxChangeManaged(Widget w)
-{
- /* Reconfigure the box */
- (void)TryNewLayout((BoxWidget)w);
- XawBoxResize(w);
-}
-
-static void
-XawBoxClassInitialize(void)
-{
- XawInitializeWidgetSet();
- XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation,
- NULL, 0);
- XtSetTypeConverter(XtROrientation, XtRString, XmuCvtOrientationToString,
- NULL, 0, XtCacheNone, NULL);
-}
-
-/*ARGSUSED*/
-static void
-XawBoxInitialize(Widget request, Widget cnew,
- ArgList args, Cardinal *num_args)
-{
- BoxWidget newbbw = (BoxWidget)cnew;
-
- newbbw->box.last_query_mode = CWWidth | CWHeight;
- newbbw->box.last_query_width = newbbw->box.last_query_height = 0;
- newbbw->box.preferred_width = Max(newbbw->box.h_space, 1);
- newbbw->box.preferred_height = Max(newbbw->box.v_space, 1);
-
- if (XtWidth(newbbw) == 0)
- XtWidth(newbbw) = newbbw->box.preferred_width;
-
- if (XtHeight(newbbw) == 0)
- XtHeight(newbbw) = newbbw->box.preferred_height;
-}
-
-static void
-XawBoxRealize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
-{
-#ifndef OLDXAW
- XawPixmap *pixmap;
-#endif
-
- XtCreateWindow(w, InputOutput, (Visual *)CopyFromParent,
- *valueMask, attributes);
-
-#ifndef OLDXAW
- if (w->core.background_pixmap > XtUnspecifiedPixmap) {
- pixmap = XawPixmapFromXPixmap(w->core.background_pixmap, XtScreen(w),
- w->core.colormap, w->core.depth);
- if (pixmap && pixmap->mask)
- XawReshapeWidget(w, pixmap);
- }
-#endif
-}
-
-/*ARGSUSED*/
-static Boolean
-XawBoxSetValues(Widget current, Widget request, Widget cnew,
- ArgList args, Cardinal *num_args)
-{
- /* need to relayout if h_space or v_space change */
-#ifndef OLDXAW
- BoxWidget b_old = (BoxWidget)current;
- BoxWidget b_new = (BoxWidget)cnew;
-
- if (b_old->core.background_pixmap != b_new->core.background_pixmap) {
- XawPixmap *opix, *npix;
-
- opix = XawPixmapFromXPixmap(b_old->core.background_pixmap,
- XtScreen(b_old), b_old->core.colormap,
- b_old->core.depth);
- npix = XawPixmapFromXPixmap(b_new->core.background_pixmap,
- XtScreen(b_new), b_new->core.colormap,
- b_new->core.depth);
- if ((npix && npix->mask) || (opix && opix->mask))
- XawReshapeWidget(cnew, npix);
- }
-#endif /* OLDXAW */
-
- return (False);
-}
-
-#ifndef OLDXAW
-static void
-XawBoxExpose(Widget w, XEvent *event, Region region)
-{
- BoxWidget xaw = (BoxWidget)w;
-
- if (xaw->box.display_list)
- XawRunDisplayList(w, xaw->box.display_list, event, region);
-}
-#endif /* OLDXAW */
+/*********************************************************** + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, 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 above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +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, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <X11/IntrinsicP.h> +#include <X11/StringDefs.h> +#include <X11/Xmu/Misc.h> +#include <X11/Xaw/BoxP.h> +#include <X11/Xaw/XawInit.h> +#include "Private.h" + +/* + * Class Methods + */ +static void XawBoxChangeManaged(Widget); +static void XawBoxClassInitialize(void); +#ifndef OLDXAW +static void XawBoxExpose(Widget, XEvent*, Region); +#endif +static XtGeometryResult XawBoxGeometryManager(Widget, XtWidgetGeometry*, + XtWidgetGeometry*); +static void XawBoxInitialize(Widget, Widget, ArgList, Cardinal*); +static XtGeometryResult XawBoxQueryGeometry(Widget, XtWidgetGeometry*, + XtWidgetGeometry*); +static void XawBoxRealize(Widget, Mask*, XSetWindowAttributes*); +static void XawBoxResize(Widget); +static Boolean XawBoxSetValues(Widget, Widget, Widget, + ArgList, Cardinal*); + +/* + * Prototypes + */ +static void DoLayout(BoxWidget, unsigned int, unsigned int, + Dimension*, Dimension*, Bool); +static Bool TryNewLayout(BoxWidget); + +/* + * Initialization + */ +#ifndef OLDXAW +static XtActionsRec actions[] = { + {"set-values", XawSetValuesAction}, + {"get-values", XawGetValuesAction}, + {"declare", XawDeclareAction}, + {"call-proc", XawCallProcAction}, +}; +#endif + +static XtResource resources[] = { + { + XtNhSpace, + XtCHSpace, + XtRDimension, + sizeof(Dimension), + XtOffsetOf(BoxRec, box.h_space), + XtRImmediate, + (XtPointer)4 + }, + { + XtNvSpace, + XtCVSpace, + XtRDimension, + sizeof(Dimension), + XtOffsetOf(BoxRec, box.v_space), + XtRImmediate, + (XtPointer)4 + }, + { + XtNorientation, + XtCOrientation, + XtROrientation, + sizeof(XtOrientation), + XtOffsetOf(BoxRec, box.orientation), + XtRImmediate, + (XtPointer)XtorientVertical + }, +#ifndef OLDXAW + { + XawNdisplayList, + XawCDisplayList, + XawRDisplayList, + sizeof(XawDisplayList*), + XtOffsetOf(BoxRec, box.display_list), + XtRImmediate, + NULL + }, +#endif +}; + +BoxClassRec boxClassRec = { + /* core */ + { + (WidgetClass)&compositeClassRec, /* superclass */ + "Box", /* class_name */ + sizeof(BoxRec), /* widget_size */ + XawBoxClassInitialize, /* class_initialize */ + NULL, /* class_part_init */ + False, /* class_inited */ + XawBoxInitialize, /* initialize */ + NULL, /* initialize_hook */ + XawBoxRealize, /* realize */ +#ifndef OLDXAW + actions, /* actions */ + XtNumber(actions), /* num_actions */ +#else + NULL, /* actions */ + 0, /* num_actions */ +#endif + resources, /* resources */ + XtNumber(resources), /* num_resources */ + NULLQUARK, /* xrm_class */ + True, /* compress_motion */ + True, /* compress_exposure */ + True, /* compress_enterleave */ + False, /* visible_interest */ + NULL, /* destroy */ + XawBoxResize, /* resize */ +#ifndef OLDXAW + XawBoxExpose, /* expose */ +#else + NULL, /* expose */ +#endif + XawBoxSetValues, /* set_values */ + NULL, /* set_values_hook */ + XtInheritSetValuesAlmost, /* set_values_almost */ + NULL, /* get_values_hook */ + NULL, /* accept_focus */ + XtVersion, /* version */ + NULL, /* callback_private */ + NULL, /* tm_table */ + XawBoxQueryGeometry, /* query_geometry */ + XtInheritDisplayAccelerator, /* display_accelerator */ + NULL, /* extension */ + }, + /* composite */ + { + XawBoxGeometryManager, /* geometry_manager */ + XawBoxChangeManaged, /* change_managed */ + XtInheritInsertChild, /* insert_child */ + XtInheritDeleteChild, /* delete_child */ + NULL, /* extension */ + }, + /* box */ + { + NULL, /* extension */ + }, +}; + +WidgetClass boxWidgetClass = (WidgetClass)&boxClassRec; + +/* + * Do a layout, either actually assigning positions, or just calculating size. + * Returns minimum width and height that will preserve the same layout. + */ +static void +DoLayout(BoxWidget bbw, unsigned int width, unsigned int height, + Dimension *reply_width, Dimension *reply_height, Bool position) +{ + Boolean vbox = (bbw->box.orientation == XtorientVertical); + Cardinal i; + Dimension w, h; /* Width and height needed for box */ + Dimension lw, lh; /* Width and height needed for current line */ + Dimension bw, bh; /* Width and height needed for current widget */ + Dimension h_space; /* Local copy of bbw->box.h_space */ + Widget widget; /* Current widget */ + unsigned int num_mapped_children = 0; + + /* Box width and height */ + h_space = bbw->box.h_space; + + w = 0; + for (i = 0; i < bbw->composite.num_children; i++) { + if (XtIsManaged(bbw->composite.children[i]) + && bbw->composite.children[i]->core.width > w) + w = bbw->composite.children[i]->core.width; + } + w += h_space; + if (w > width) + width = w; + h = bbw->box.v_space; + + /* Line width and height */ + lh = 0; + lw = h_space; + + for (i = 0; i < bbw->composite.num_children; i++) { + widget = bbw->composite.children[i]; + if (widget->core.managed) { + if (widget->core.mapped_when_managed) + num_mapped_children++; + /* Compute widget width */ + bw = XtWidth(widget) + (XtBorderWidth(widget)<<1) + h_space; + if ((Dimension)(lw + bw) > width) { + if (lw > h_space) { + /* At least one widget on this line, and + * can't fit any more. Start new line if vbox + */ + AssignMax(w, lw); + if (vbox) { + h += lh + bbw->box.v_space; + lh = 0; + lw = h_space; + } + } + else if (!position) { + /* too narrow for this widget; we'll assume we can grow */ + DoLayout(bbw, (unsigned)(lw + bw), height, reply_width, + reply_height, position); + return; + } + } + if (position && (lw != XtX(widget) || h != XtY(widget))) { + /* It would be nice to use window gravity, but there isn't + * sufficient fine-grain control to nicely handle all + * situations (e.g. when only the height changes -- + * a common case). Explicit unmapping is a cheap hack + * to speed things up & avoid the visual jitter as + * things slide around. + * + * %%% perhaps there should be a client resource to + * control this. If so, we'll have to optimize to + * perform the moves from the correct end so we don't + * force extra exposures as children occlude each other. + */ + if (XtIsRealized(widget) && widget->core.mapped_when_managed) + XUnmapWindow( XtDisplay(widget), XtWindow(widget)); + XtMoveWidget(widget, (int)lw, (int)h); + } + lw += bw; + bh = XtHeight(widget) + (XtBorderWidth(widget) << 1); + AssignMax(lh, bh); + } + } + + if (!vbox && width && lw > width && lh < height) { + /* reduce width if too wide and height not filled */ + Dimension sw = lw, sh = lh; + Dimension width_needed = width; + XtOrientation orientation = bbw->box.orientation; + + bbw->box.orientation = XtorientVertical; + while (sh < height && sw > width) { + width_needed = sw; + DoLayout(bbw, (unsigned)(sw-1), height, &sw, &sh, False); + } + if (sh < height) + width_needed = sw; + if (width_needed != lw) { + DoLayout(bbw, width_needed, height, + reply_width, reply_height, position); + bbw->box.orientation = orientation; + return; + } + bbw->box.orientation = orientation; + } + if (vbox && (width < w || width < lw)) { + AssignMax(w, lw); + DoLayout(bbw, w, height, reply_width, reply_height, position); + return; + } + if (position && XtIsRealized((Widget)bbw)) { + if (bbw->composite.num_children == num_mapped_children) + XMapSubwindows(XtDisplay((Widget)bbw), XtWindow((Widget)bbw)); + else { + int ii = bbw->composite.num_children; + Widget *childP = bbw->composite.children; + + for (; ii > 0; childP++, ii--) + if (XtIsRealized(*childP) && XtIsManaged(*childP) + && (*childP)->core.mapped_when_managed) + XtMapWidget(*childP); + } + } + + /* Finish off last line */ + if (lw > h_space) { + AssignMax(w, lw); + h += lh + bbw->box.v_space; + } + + *reply_width = Max(w, 1); + *reply_height = Max(h, 1); +} + +/* + * Calculate preferred size, given constraining box, caching it in the widget + */ +static XtGeometryResult +XawBoxQueryGeometry(Widget widget, XtWidgetGeometry *constraint, + XtWidgetGeometry *preferred) +{ + BoxWidget w = (BoxWidget)widget; + Dimension width; + Dimension preferred_width = w->box.preferred_width; + Dimension preferred_height = w->box.preferred_height; + + constraint->request_mode &= CWWidth | CWHeight; + + if (constraint->request_mode == 0) + /* parent isn't going to change w or h, so nothing to re-compute */ + return (XtGeometryYes); + + if (constraint->request_mode == w->box.last_query_mode + && (!(constraint->request_mode & CWWidth) + || constraint->width == w->box.last_query_width) + && (!(constraint->request_mode & CWHeight) + || constraint->height == w->box.last_query_height)) { + /* same query; current preferences are still valid */ + preferred->request_mode = CWWidth | CWHeight; + preferred->width = preferred_width; + preferred->height = preferred_height; + if (constraint->request_mode == (CWWidth | CWHeight) + && constraint->width == preferred_width + && constraint->height == preferred_height) + return (XtGeometryYes); + else + return (XtGeometryAlmost); + } + + /* else gotta do it the long way... + I have a preference for tall and narrow, so if my width is + constrained, I'll accept it; otherwise, I'll compute the minimum + width that will fit me within the height constraint */ + + w->box.last_query_mode = constraint->request_mode; + w->box.last_query_width = constraint->width; + w->box.last_query_height= constraint->height; + + if (constraint->request_mode & CWWidth) + width = constraint->width; + else { /* if (constraint->request_mode & CWHeight) */ + /* let's see if I can become any narrower */ + width = 0; + constraint->width = 65535; + } + + /* height is currently ignored by DoLayout. + height = (constraint->request_mode & CWHeight) ? constraint->height + : *preferred_height; + */ + DoLayout(w, width, 0, &preferred_width, &preferred_height, False); + + if (constraint->request_mode & CWHeight + && preferred_height > constraint->height) { + /* find minimum width for this height */ + if (preferred_width <= constraint->width) { + width = preferred_width; + do { /* find some width big enough to stay within this height */ + width <<= 1; + if (width > constraint->width) + width = constraint->width; + DoLayout(w, width, 0, &preferred_width, &preferred_height, False); + } while (preferred_height > constraint->height + && width < constraint->width); + if (width != constraint->width) { + do { /* find minimum width */ + width = preferred_width; + DoLayout(w, (unsigned)(preferred_width - 1), 0, + &preferred_width, &preferred_height, False); + } while (preferred_height < constraint->height); + /* one last time */ + DoLayout(w, width, 0, &preferred_width, &preferred_height, False); + } + } + } + + preferred->request_mode = CWWidth | CWHeight; + preferred->width = w->box.preferred_width = preferred_width; + preferred->height = w->box.preferred_height = preferred_height; + + if (constraint->request_mode == (CWWidth|CWHeight) + && constraint->width == preferred_width + && constraint->height == preferred_height) + return (XtGeometryYes); + + return (XtGeometryAlmost); +} + +/* + * Actually layout the box + */ +static void +XawBoxResize(Widget w) +{ + Dimension tmp; + + DoLayout((BoxWidget)w, XtWidth(w), XtHeight(w), &tmp, &tmp, True); +} + +/* + * Try to do a new layout within the current width and height; + * if that fails try to resize and do it within the box returne + * by XawBoxQueryGeometry + * + * TryNewLayout just says if it's possible, and doesn't actually move the kids + */ +static Bool +TryNewLayout(BoxWidget bbw) +{ + Dimension preferred_width, preferred_height; + Dimension proposed_width, proposed_height; + int iterations; + + DoLayout(bbw, bbw->core.width, bbw->core.height, + &preferred_width, &preferred_height, False); + + /* at this point, preferred_width is guaranteed to not be greater + than bbw->core.width unless some child is larger, so there's no + point in re-computing another layout */ + + if (XtWidth(bbw) == preferred_width && XtHeight(bbw) == preferred_height) + return (True); + + /* let's see if our parent will go for a new size */ + iterations = 0; + proposed_width = preferred_width; + proposed_height = preferred_height; + do { + switch (XtMakeResizeRequest((Widget)bbw,proposed_width,proposed_height, + &proposed_width, &proposed_height)) { + case XtGeometryYes: + return (True); + case XtGeometryNo: + if (iterations > 0) + /* protect from malicious parents who change their minds */ + DoLayout(bbw, bbw->core.width, bbw->core.height, + &preferred_width, &preferred_height, False); + if (preferred_width <= XtWidth(bbw) + && preferred_height <= XtHeight(bbw)) + return (True); + else + return (False); + case XtGeometryAlmost: + if (proposed_height >= preferred_height && + proposed_width >= preferred_width) { + /* + * Take it, and assume the parent knows what it is doing. + * + * The parent must accept this since it was returned in + * almost. + */ + (void)XtMakeResizeRequest((Widget)bbw, + proposed_width, proposed_height, + &proposed_width, &proposed_height); + return (True); + } + else if (proposed_width != preferred_width) { + /* recalc bounding box; height might change */ + DoLayout(bbw, proposed_width, 0, + &preferred_width, &preferred_height, False); + proposed_height = preferred_height; + } + else { /* proposed_height != preferred_height */ + XtWidgetGeometry constraints, reply; + + constraints.request_mode = CWHeight; + constraints.height = proposed_height; + (void)XawBoxQueryGeometry((Widget)bbw, &constraints, &reply); + proposed_width = preferred_width; + } + /*FALLTHROUGH*/ + default: + break; + } + iterations++; + } while (iterations < 10); + + return (False); +} + +/* + * Geometry Manager + * + * 'reply' is unused; we say only yeay or nay, never almost. + */ +/*ARGSUSED*/ +static XtGeometryResult +XawBoxGeometryManager(Widget w, XtWidgetGeometry *request, + XtWidgetGeometry *reply) +{ + Dimension width, height, borderWidth; + BoxWidget bbw; + + /* Position request always denied */ + if (((request->request_mode & CWX) && request->x != XtX(w)) + || ((request->request_mode & CWY) && request->y != XtY(w))) + return (XtGeometryNo); + + /* Size changes must see if the new size can be accomodated */ + if (request->request_mode & (CWWidth | CWHeight | CWBorderWidth)) { + /* Make all three fields in the request valid */ + if ((request->request_mode & CWWidth) == 0) + request->width = XtWidth(w); + if ((request->request_mode & CWHeight) == 0) + request->height = XtHeight(w); + if ((request->request_mode & CWBorderWidth) == 0) + request->border_width = XtBorderWidth(w); + + /* Save current size and set to new size */ + width = XtWidth(w); + height = XtHeight(w); + borderWidth = XtBorderWidth(w); + XtWidth(w) = request->width; + XtHeight(w) = request->height; + XtBorderWidth(w) = request->border_width; + + /* Decide if new layout works: + (1) new widget is smaller, + (2) new widget fits in existing Box, + (3) Box can be expanded to allow new widget to fit + */ + + bbw = (BoxWidget) w->core.parent; + + if (TryNewLayout(bbw)) { + /* Fits in existing or new space, relayout */ + (*XtClass((Widget)bbw)->core_class.resize)((Widget)bbw); + return (XtGeometryYes); + } + else { + /* Cannot satisfy request, change back to original geometry */ + XtWidth(w) = width; + XtHeight(w) = height; + XtBorderWidth(w) = borderWidth; + return (XtGeometryNo); + } + } + + /* Any stacking changes don't make a difference, so allow if that's all */ + return (XtGeometryYes); +} + +static void +XawBoxChangeManaged(Widget w) +{ + /* Reconfigure the box */ + (void)TryNewLayout((BoxWidget)w); + XawBoxResize(w); +} + +static void +XawBoxClassInitialize(void) +{ + XawInitializeWidgetSet(); + XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation, + NULL, 0); + XtSetTypeConverter(XtROrientation, XtRString, XmuCvtOrientationToString, + NULL, 0, XtCacheNone, NULL); +} + +/*ARGSUSED*/ +static void +XawBoxInitialize(Widget request, Widget cnew, + ArgList args, Cardinal *num_args) +{ + BoxWidget newbbw = (BoxWidget)cnew; + + newbbw->box.last_query_mode = CWWidth | CWHeight; + newbbw->box.last_query_width = newbbw->box.last_query_height = 0; + newbbw->box.preferred_width = Max(newbbw->box.h_space, 1); + newbbw->box.preferred_height = Max(newbbw->box.v_space, 1); + + if (XtWidth(newbbw) == 0) + XtWidth(newbbw) = newbbw->box.preferred_width; + + if (XtHeight(newbbw) == 0) + XtHeight(newbbw) = newbbw->box.preferred_height; +} + +static void +XawBoxRealize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes) +{ +#ifndef OLDXAW + XawPixmap *pixmap; +#endif + + XtCreateWindow(w, InputOutput, (Visual *)CopyFromParent, + *valueMask, attributes); + +#ifndef OLDXAW + if (w->core.background_pixmap > XtUnspecifiedPixmap) { + pixmap = XawPixmapFromXPixmap(w->core.background_pixmap, XtScreen(w), + w->core.colormap, w->core.depth); + if (pixmap && pixmap->mask) + XawReshapeWidget(w, pixmap); + } +#endif +} + +/*ARGSUSED*/ +static Boolean +XawBoxSetValues(Widget current, Widget request, Widget cnew, + ArgList args, Cardinal *num_args) +{ + /* need to relayout if h_space or v_space change */ +#ifndef OLDXAW + BoxWidget b_old = (BoxWidget)current; + BoxWidget b_new = (BoxWidget)cnew; + + if (b_old->core.background_pixmap != b_new->core.background_pixmap) { + XawPixmap *opix, *npix; + + opix = XawPixmapFromXPixmap(b_old->core.background_pixmap, + XtScreen(b_old), b_old->core.colormap, + b_old->core.depth); + npix = XawPixmapFromXPixmap(b_new->core.background_pixmap, + XtScreen(b_new), b_new->core.colormap, + b_new->core.depth); + if ((npix && npix->mask) || (opix && opix->mask)) + XawReshapeWidget(cnew, npix); + } +#endif /* OLDXAW */ + + return (False); +} + +#ifndef OLDXAW +static void +XawBoxExpose(Widget w, XEvent *event, Region region) +{ + BoxWidget xaw = (BoxWidget)w; + + if (xaw->box.display_list) + XawRunDisplayList(w, xaw->box.display_list, event, region); +} +#endif /* OLDXAW */ |