#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"
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*);
static void DoLayout(BoxWidget, unsigned int, unsigned int,
Dimension*, Dimension*, Bool);
static Bool TryNewLayout(BoxWidget);
#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 = {
{
(WidgetClass)&compositeClassRec,
"Box",
sizeof(BoxRec),
XawBoxClassInitialize,
NULL,
False,
XawBoxInitialize,
NULL,
XawBoxRealize,
#ifndef OLDXAW
actions,
XtNumber(actions),
#else
NULL,
0,
#endif
resources,
XtNumber(resources),
NULLQUARK,
True,
True,
True,
False,
NULL,
XawBoxResize,
#ifndef OLDXAW
XawBoxExpose,
#else
NULL,
#endif
XawBoxSetValues,
NULL,
XtInheritSetValuesAlmost,
NULL,
NULL,
XtVersion,
NULL,
NULL,
XawBoxQueryGeometry,
XtInheritDisplayAccelerator,
NULL,
},
{
XawBoxGeometryManager,
XawBoxChangeManaged,
XtInheritInsertChild,
XtInheritDeleteChild,
NULL,
},
{
NULL,
},
};
WidgetClass boxWidgetClass = (WidgetClass)&boxClassRec;
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;
Dimension lw, lh;
Dimension bw, bh;
Dimension h_space;
Widget widget;
unsigned int num_mapped_children = 0;
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;
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++;
bw = XtWidth(widget) + (XtBorderWidth(widget)<<1) + h_space;
if ((Dimension)(lw + bw) > width) {
if (lw > h_space) {
AssignMax(w, lw);
if (vbox) {
h += lh + bbw->box.v_space;
lh = 0;
lw = h_space;
}
}
else if (!position) {
DoLayout(bbw, (unsigned)(lw + bw), height, reply_width,
reply_height, position);
return;
}
}
if (position && (lw != XtX(widget) || h != XtY(widget))) {
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) {
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);
}
}
if (lw > h_space) {
AssignMax(w, lw);
h += lh + bbw->box.v_space;
}
*reply_width = Max(w, 1);
*reply_height = Max(h, 1);
}
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)
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)) {
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);
}
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 {
width = 0;
constraint->width = 65535;
}
DoLayout(w, width, 0, &preferred_width, &preferred_height, False);
if (constraint->request_mode & CWHeight
&& preferred_height > constraint->height) {
if (preferred_width <= constraint->width) {
width = preferred_width;
do {
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 {
width = preferred_width;
DoLayout(w, (unsigned)(preferred_width - 1), 0,
&preferred_width, &preferred_height, False);
} while (preferred_height < constraint->height);
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);
}
static void
XawBoxResize(Widget w)
{
Dimension tmp;
DoLayout((BoxWidget)w, XtWidth(w), XtHeight(w), &tmp, &tmp, True);
}
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);
if (XtWidth(bbw) == preferred_width && XtHeight(bbw) == preferred_height)
return (True);
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)
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) {
(void)XtMakeResizeRequest((Widget)bbw,
proposed_width, proposed_height,
&proposed_width, &proposed_height);
return (True);
}
else if (proposed_width != preferred_width) {
DoLayout(bbw, proposed_width, 0,
&preferred_width, &preferred_height, False);
proposed_height = preferred_height;
}
else {
XtWidgetGeometry constraints, reply;
constraints.request_mode = CWHeight;
constraints.height = proposed_height;
(void)XawBoxQueryGeometry((Widget)bbw, &constraints, &reply);
proposed_width = preferred_width;
}
default:
break;
}
iterations++;
} while (iterations < 10);
return (False);
}
static XtGeometryResult
XawBoxGeometryManager(Widget w, XtWidgetGeometry *request,
XtWidgetGeometry *reply)
{
Dimension width, height, borderWidth;
BoxWidget bbw;
if (((request->request_mode & CWX) && request->x != XtX(w))
|| ((request->request_mode & CWY) && request->y != XtY(w)))
return (XtGeometryNo);
if (request->request_mode & (CWWidth | CWHeight | CWBorderWidth)) {
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);
width = XtWidth(w);
height = XtHeight(w);
borderWidth = XtBorderWidth(w);
XtWidth(w) = request->width;
XtHeight(w) = request->height;
XtBorderWidth(w) = request->border_width;
bbw = (BoxWidget) w->core.parent;
if (TryNewLayout(bbw)) {
(*XtClass((Widget)bbw)->core_class.resize)((Widget)bbw);
return (XtGeometryYes);
}
else {
XtWidth(w) = width;
XtHeight(w) = height;
XtBorderWidth(w) = borderWidth;
return (XtGeometryNo);
}
}
return (XtGeometryYes);
}
static void
XawBoxChangeManaged(Widget w)
{
(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);
}
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
}
static Boolean
XawBoxSetValues(Widget current, Widget request, Widget cnew,
ArgList args, Cardinal *num_args)
{
#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
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