diff options
Diffstat (limited to 'libXaw/src/Box.c')
-rw-r--r-- | libXaw/src/Box.c | 1347 |
1 files changed, 672 insertions, 675 deletions
diff --git a/libXaw/src/Box.c b/libXaw/src/Box.c index f4f293926..5c6cfa2a2 100644 --- a/libXaw/src/Box.c +++ b/libXaw/src/Box.c @@ -1,675 +1,672 @@ -/* $Xorg: Box.c,v 1.4 2001/02/09 02:03:43 xorgcvs Exp $ */ - -/*********************************************************** - -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. - -******************************************************************/ -/* $XFree86: xc/lib/Xaw/Box.c,v 1.14 2001/01/17 19:42:25 dawes Exp $ */ - -#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 */
|