/* * Copyright 1991 Massachusetts Institute of Technology * * 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, and that the name of M.I.T. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. * 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. * * Author: Keith Packard, MIT X Consortium */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #ifdef MOTIF # include #endif #if defined(LAYOUT) # include "LayoutP.h" #else # include #endif #include #include #include "LayYY.h" #undef DEBUG #ifdef DEBUG static char *DBUG_currentproc, *DBUG_lastproc; static int DBUG_level = 0; # define DBUG_ENTER(s) \ {DBUG_lastproc=DBUG_currentproc;DBUG_currentproc=s;\ fprintf(stderr,"begin: (%d) %s\n",++DBUG_level,s);} # define DBUG_VOID_RETURN \ {fprintf(stderr,"end: (%d) %s\n",DBUG_level--,DBUG_currentproc); \ DBUG_currentproc=DBUG_lastproc;return;} # define DBUG_RETURN(f,v) \ {fprintf(stderr,"return (%d) %s (",DBUG_level--,DBUG_currentproc); \ fprintf(stderr,(f),(v)); \ fprintf(stderr,")\n"); DBUG_currentproc=DBUG_lastproc;return (v);} # define DBUG_PRINT(f,s) \ {fprintf(stderr," (%d) %s:",DBUG_level, DBUG_currentproc); \ fprintf(stderr,f,s);fprintf(stderr,"\n");} #else # define DBUG_ENTER(s) # define DBUG_VOID_RETURN return # define DBUG_PRINT(f,s) # define DBUG_RETURN(f,v) return(v) #endif /***************************************************************************** * * Full instance record declaration * ****************************************************************************/ #define offset(field) XtOffsetOf(LayoutRec, layout.field) static XtResource resources[] = { {XtNlayout, XtCLayout, XtRLayout, sizeof (BoxPtr), offset(layout), XtRLayout, NULL }, {XtNdebug, XtCBoolean, XtRBoolean, sizeof(Boolean), offset(debug), XtRImmediate, (XtPointer) FALSE}, }; #undef offset static void ClassInitialize(void); static void Initialize(Widget, Widget, ArgList, Cardinal *); static void Resize(Widget); static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *); static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *, XtWidgetGeometry *); static void ChangeManaged(Widget); static void InsertChild(Widget); static XtGeometryResult QueryGeometry (Widget, XtWidgetGeometry *, XtWidgetGeometry *); static void GetDesiredSize (Widget); #ifdef MOTIF static void Redisplay (Widget, XEvent *, Region); #endif static void LayoutLayout (LayoutWidget, Bool); static void LayoutGetNaturalSize (LayoutWidget, Dimension *, Dimension *); static void LayoutFreeLayout (BoxPtr); #ifdef MOTIF #define SuperClass ((ConstraintWidgetClass)&xmManagerClassRec) #else #define SuperClass ((ConstraintWidgetClass)&constraintClassRec) #endif LayoutClassRec layoutClassRec = { { /* core class fields */ /* superclass */ (WidgetClass) SuperClass, /* class name */ "Layout", /* size */ sizeof(LayoutRec), /* class_initialize */ ClassInitialize, /* class_part init */ NULL, /* class_inited */ FALSE, /* initialize */ Initialize, /* initialize_hook */ NULL, /* realize */ XtInheritRealize, /* actions */ NULL, /* num_actions */ 0, /* resources */ resources, /* resource_count */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ FALSE, /* compress_exposure */ 0, /* compress_enterleave*/ FALSE, /* visible_interest */ FALSE, /* destroy */ NULL, /* resize */ Resize, #ifdef MOTIF /* expose */ Redisplay, #else /* expose */ NULL, #endif /* set_values */ SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback_private */ NULL, #ifdef MOTIF /* tm_table */ XtInheritTranslations, #else /* tm_table */ NULL, #endif /* query_geometry */ QueryGeometry, /* display_accelerator*/ XtInheritDisplayAccelerator, /* extension */ NULL }, { /* composite class fields */ /* geometry_manager */ GeometryManager, /* change_managed */ ChangeManaged, /* insert_child */ InsertChild, /* delete_child */ XtInheritDeleteChild, /* extension */ NULL }, { /* constraint class fields */ /* subresources */ NULL, /* subresource_count */ 0, /* constraint_size */ sizeof(LayoutConstraintsRec), /* initialize */ NULL, /* destroy */ NULL, /* set_values */ NULL, /* extension */ NULL }, #ifdef MOTIF { /* manager class */ XtInheritTranslations, /* translations */ NULL, /* syn resources */ 0, /* num syn_resources */ NULL, /* get_cont_resources */ 0, /* num_get_cont_resources */ XmInheritParentProcess, /* parent_process */ NULL, /* extension */ }, #endif { /* layout_class fields */ 0 } }; WidgetClass layoutWidgetClass = (WidgetClass) &layoutClassRec; #define ForAllChildren(pw, childP) \ for ( (childP) = (pw)->composite.children ; \ (childP) < (pw)->composite.children + (pw)->composite.num_children ; \ (childP)++ ) if (!XtIsManaged(*childP)) ; else /************************************************************ * * Semi-public routines. * ************************************************************/ /* Function Name: ClassInitialize * Description: The Layout widgets class initialization proc. * Arguments: none. * Returns: none. */ /*ARGSUSED*/ static Boolean CvtStringToLayout (Display *dpy, XrmValue *args, Cardinal *num_args, XrmValue *from, XrmValue *to, XtPointer *converter_data) { static BoxPtr tmp; LayYYsetsource ((char *) from->addr); if (!to->addr) to->addr = (XtPointer)&tmp; LayYYsetdest ((BoxPtr *) to->addr); to->size = sizeof (BoxPtr *); return LayYYparse() ? FALSE : TRUE; } /*ARGSUSED*/ static void DisposeLayout (XtAppContext app, XrmValue *to, XtPointer data, XrmValuePtr args, Cardinal *num_args) { LayoutFreeLayout (* (LayoutPtr *) to->addr); } static void ClassInitialize(void) { XtSetTypeConverter ( XtRString, XtRLayout, CvtStringToLayout, (XtConvertArgList)NULL, (Cardinal)0, XtCacheNone, DisposeLayout ); } #ifdef MOTIF static void Redisplay (Widget gw, XEvent *event, Region region) { /* * If the Layout widget is visible, redraw gadgets. */ if ( XtIsRealized ( gw ) && gw->core.visible ) { _XmRedisplayGadgets ( gw, event, region ); } /* ChangeManaged(gw);*/ } #endif /*ARGSUSED*/ static XtGeometryResult GeometryManager(Widget child, XtWidgetGeometry *request, XtWidgetGeometry *reply) { LayoutWidget w = (LayoutWidget) XtParent(child); SubInfoPtr p = SubInfo(child); int bw; Bool changed, bwChanged; bw = p->naturalBw; changed = FALSE; bwChanged = FALSE; if (request->request_mode & CWBorderWidth && request->border_width != child->core.border_width) { p->naturalBw = bw; bw = request->border_width; changed = TRUE; bwChanged = TRUE; } if (bwChanged || ((request->request_mode & CWWidth) && request->width != child->core.width)) { p->naturalSize[LayoutHorizontal] = request->width + bw * 2; changed = TRUE; } if (bwChanged || ((request->request_mode & CWHeight) && request->height != child->core.height)) { p->naturalSize[LayoutVertical] = request->height + bw * 2; changed = TRUE; } if (changed) LayoutLayout (w, TRUE); return XtGeometryDone; } /* ARGSUSED */ static void Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args) { /* LayoutWidget w = (LayoutWidget)new; */ } static void ChangeManaged(Widget gw) { LayoutWidget w = (LayoutWidget) gw; Widget *children; DBUG_ENTER("changeManaged"); ForAllChildren (w, children) GetDesiredSize (*children); LayoutLayout ((LayoutWidget) w, TRUE); #ifdef MOTIF _XmNavigChangeManaged ( gw ); #endif DBUG_VOID_RETURN; } static void GetDesiredSize (Widget child) { XtWidgetGeometry desired; SubInfoPtr p; XtQueryGeometry (child, (XtWidgetGeometry *) NULL, &desired); p = SubInfo (child); p->naturalBw = desired.border_width; p->naturalSize[LayoutHorizontal] = desired.width + desired.border_width * 2; p->naturalSize[LayoutVertical] = desired.height + desired.border_width * 2; } static void InsertChild (Widget child) { (*SuperClass->composite_class.insert_child) (child); GetDesiredSize (child); } static void Resize(Widget gw) { LayoutLayout ((LayoutWidget) gw, FALSE); } /* ARGSUSED */ static Boolean SetValues(Widget gold, Widget greq, Widget gnew, ArgList args, Cardinal *num_args) { LayoutWidget old = (LayoutWidget) gold, new = (LayoutWidget) gnew; if (old->layout.layout != new->layout.layout) LayoutLayout (new, TRUE); return FALSE; } /* SetValues */ static XtGeometryResult QueryGeometry (Widget gw, XtWidgetGeometry *request, XtWidgetGeometry *prefered_return) { LayoutWidget w = (LayoutWidget) gw; XtGeometryResult result; XtWidgetGeometry prefered_size; if (request && !(request->request_mode & (CWWidth|CWHeight))) return XtGeometryYes; LayoutGetNaturalSize (w, &prefered_size.width, &prefered_size.height); prefered_return->request_mode = 0; result = XtGeometryYes; if (!request) { prefered_return->width = prefered_size.width; prefered_return->height= prefered_size.height; if (prefered_size.width != w->core.width) { prefered_return->request_mode |= CWWidth; result = XtGeometryAlmost; } if (prefered_size.height != w->core.height) { prefered_return->request_mode |= CWHeight; result = XtGeometryAlmost; } } else { if (request->request_mode & CWWidth) { if (prefered_size.width > request->width) { if (prefered_size.width == w->core.width) result = XtGeometryNo; else if (result != XtGeometryNo) { result = XtGeometryAlmost; prefered_return->request_mode |= CWWidth; prefered_return->width = prefered_size.width; } } } if (request->request_mode & CWHeight) { if (prefered_size.height > request->height) { if (prefered_size.height == w->core.height) result = XtGeometryNo; else if (result != XtGeometryNo) { result = XtGeometryAlmost; prefered_return->request_mode |= CWHeight; prefered_return->height = prefered_size.height; } } } } return result; } /* * Layout section. Exports LayoutGetNaturalSize and * LayoutLayout to above section */ static void PrintGlue (GlueRec g) { if (g.order == 0 || g.value != 1.0) (void) printf ("%g", g.value); if (g.order > 0) { (void) printf ("%s", " inf"); if (g.order > 1) (void) printf (" %d", g.order); } } static void PrintDirection (LayoutDirection dir) { switch (dir) { case LayoutHorizontal: (void) printf ("%s", "horizontal"); break; case LayoutVertical: (void) printf ("%s", "vertical"); break; default: (void) printf ("Unknown layout direction %d\n", dir); break; } } static void TabTo(int level) { while (level--) (void) printf ("%s", " "); } static void PrintBox (BoxPtr box, int level) { BoxPtr child; TabTo (level); (void) printf ("%s", "< "); (void) printf ("%s", " + "); PrintGlue (box->params.stretch[LayoutHorizontal]); (void) printf ("%s", " - "); PrintGlue (box->params.shrink[LayoutHorizontal]); (void) printf ("%s", " * "); (void) printf ("%s", " + "); PrintGlue (box->params.stretch[LayoutVertical]); (void) printf ("%s", " - "); PrintGlue (box->params.shrink[LayoutVertical]); (void) printf ("%s", " >"); (void) printf (" size: %d x %d", box->size[0], box->size[1]); (void) printf (" natural: %d x %d ", box->natural[0], box->natural[1]); switch (box->type) { case BoxBox: PrintDirection (box->u.box.dir); (void) printf ("%s\n", ""); for (child = box->u.box.firstChild; child; child = child->nextSibling) PrintBox (child, level+1); break; case WidgetBox: (void) printf (" %s\n", XrmQuarkToString (box->u.widget.quark)); break; case GlueBox: (void) printf ("%s\n", " glue"); break; case VariableBox: (void) printf (" variable %s\n", XrmQuarkToString (box->u.variable.quark)); break; } } static ExprPtr LookupVariable (BoxPtr child, XrmQuark quark) { BoxPtr parent, box; DBUG_ENTER("LookupVariable"); DBUG_PRINT("name = <%s>",XrmQuarkToString(quark)); DBUG_PRINT("child = %p",child); while ((parent = child->parent)) { for (box = parent->u.box.firstChild; box != child; box = box->nextSibling) { if (box->type == VariableBox && box->u.variable.quark == quark) DBUG_RETURN("%p", box->u.variable.expr); } child = parent; } DBUG_RETURN("failure -> %d",0); } static double Evaluate (LayoutWidget l, BoxPtr box, ExprPtr expr, double natural) { double left, right, down; Widget widget; SubInfoPtr info; DBUG_PRINT("Evaluate %d", expr->type); switch (expr->type) { case Constant: return expr->u.constant; case Binary: left = Evaluate (l, box, expr->u.binary.left, natural); right = Evaluate (l, box, expr->u.binary.right, natural); switch (expr->u.binary.op) { case Plus: return left + right; case Minus: return left - right; case Times: return left * right; case Divide: return left / right; case Percent: return right * left / 100.0; } case Unary: down = Evaluate (l, box, expr->u.unary.down, natural); switch (expr->u.unary.op) { case Percent: return natural * down / 100.0; case Minus: return -down; case Plus: case Times: case Divide: break; } case Width: widget = QuarkToWidget (l, expr->u.width); if (!widget) return 0; info = SubInfo (widget); return info->naturalSize[LayoutHorizontal]; case Height: widget = QuarkToWidget (l, expr->u.height); if (!widget) return 0; info = SubInfo (widget); return info->naturalSize[LayoutVertical]; case Variable: { /* in the original code there was no nexpr, expr was overwritten by LookupVariable and the expression "expr->u.variable" to obtain the variable name for the errormessage cause a segmentation violation */ ExprPtr nexpr; nexpr = LookupVariable (box, expr->u.variable); if (!nexpr) { char buf[256]; (void) sprintf (buf, "Layout: undefined variable %s\n", XrmQuarkToString (expr->u.variable)); XtError (buf); return 0.0; } return Evaluate (l, box, nexpr, natural); } } return 0.0; } static void DisposeExpr (ExprPtr expr) { if (!expr) return; switch (expr->type) { case Constant: break; case Binary: DisposeExpr (expr->u.binary.left); DisposeExpr (expr->u.binary.right); break; case Unary: DisposeExpr (expr->u.unary.down); break; case Width: case Height: case Variable: break; } Dispose (expr); } #define CheckGlue(l, box, glue, n) { \ if (glue.expr) \ glue.value = Evaluate (l, box, glue.expr, n); \ if (glue.order == 0 && glue.value == 0) \ glue.order = -1; \ else if (glue.order == -1 && glue.value != 0) \ glue.order = 0; \ } #define DoStretch(l, box, dir) \ CheckGlue (l, box, box->params.stretch[dir], (double) box->natural[dir]); #define DoShrink(l, box, dir) \ CheckGlue (l, box, box->params.shrink[dir], (double) box->natural[dir]) /* compute the natural sizes of a box */ static void ComputeNaturalSizes (LayoutWidget l, BoxPtr box, LayoutDirection dir) { BoxPtr child; Widget w; SubInfoPtr info; int minStretchOrder, minShrinkOrder; LayoutDirection thisDir; DBUG_ENTER("ComputeNaturalSizes"); DBUG_PRINT("box->type=%d",box->type); switch (box->type) { case WidgetBox: w = box->u.widget.widget = QuarkToWidget (l, box->u.widget.quark); if (!w) { box->natural[LayoutHorizontal] = 0; box->natural[LayoutVertical] = 0; } else { info = SubInfo (w); box->natural[LayoutHorizontal] = info->naturalSize[LayoutHorizontal]; box->natural[LayoutVertical] = info->naturalSize[LayoutVertical]; } DoStretch (l, box, dir); DoShrink (l, box, dir); DoStretch (l, box, !dir); DoShrink (l, box, !dir); break; case GlueBox: box->natural[dir] = Evaluate (l, box, box->u.glue.expr, 0.0); box->natural[!dir] = 0; DoStretch (l, box, dir); DoShrink (l, box, dir); break; case BoxBox: thisDir = box->u.box.dir; box->natural[0] = 0; box->natural[1] = 0; minStretchOrder = 100000; minShrinkOrder = 100000; ZeroGlue (box->params.shrink[thisDir]); ZeroGlue (box->params.stretch[thisDir]); box->params.shrink[!thisDir].order = 100000; box->params.stretch[!thisDir].order = 100000; for (child = box->u.box.firstChild; child; child = child->nextSibling) { ComputeNaturalSizes (l, child, thisDir); /* * along box axis: * normal size += child normal size * shrink += child shrink * stretch += child stretch */ box->natural[thisDir] += child->natural[thisDir]; AddGlue (box->params.shrink[thisDir], box->params.shrink[thisDir], child->params.shrink[thisDir]); AddGlue (box->params.stretch[thisDir], box->params.stretch[thisDir], child->params.stretch[thisDir]); /* * normal to box axis: * normal size = maximum child normal size of minimum shrink order * shrink = difference between normal size and minimum shrink * stretch = minimum child stretch */ if (box->natural[!thisDir] >= child->natural[!thisDir]) { if (child->params.stretch[!thisDir].order < minShrinkOrder) { box->natural[!thisDir] = child->natural[!thisDir]; minStretchOrder = child->params.stretch[!thisDir].order; if (child->params.shrink[!thisDir].order < minShrinkOrder) minShrinkOrder = child->params.shrink[!thisDir].order; } } else { if (child->params.shrink[!thisDir].order <= minStretchOrder) { box->natural[!thisDir] = child->natural[!thisDir]; minShrinkOrder = child->params.shrink[!thisDir].order; if (child->params.stretch[!thisDir].order < minStretchOrder) minStretchOrder = child->params.stretch[!thisDir].order; } } MinGlue (box->params.stretch[!thisDir], box->params.stretch[!thisDir], child->params.stretch[!thisDir]); MinGlue (box->params.shrink[!thisDir], box->params.shrink[!thisDir], child->params.shrink[!thisDir]); } if (box->params.shrink[!thisDir].order <= 0) { int minSize; int largestMinSize; largestMinSize = 0; for (child = box->u.box.firstChild; child; child = child->nextSibling) { if (child->params.shrink[!thisDir].order <= 0) { minSize = child->natural[!thisDir] - child->params.shrink[!thisDir].value; if (minSize > largestMinSize) largestMinSize = minSize; } } box->params.shrink[!thisDir].value = box->natural[!thisDir] - largestMinSize; if (box->params.shrink[!thisDir].value == 0) box->params.shrink[!thisDir].order = -1; else box->params.shrink[!thisDir].order = 0; } break; case VariableBox: break; } DBUG_VOID_RETURN; } /* given the box's geometry, set the geometry of the pieces */ #define GluePart(a,b,dist) ((a) ? ((int) (((a) * (dist)) / (b) + \ ((dist >= 0) ? 0.5 : -0.5))) : 0) static Bool ComputeSizes (BoxPtr box) { LayoutDirection dir; BoxPtr child; GlueRec stretch; GlueRec shrink; GlueRec totalGlue[2]; double remainingGlue; GluePtr glue; int size; int totalSizes; int totalChange[2]; int change; int remainingChange; Bool shrinking; Bool happy; int i; int maxGlue; dir = box->u.box.dir; size = box->size[dir]; stretch = box->params.stretch[dir]; shrink = box->params.shrink[dir]; /* pick the correct adjustment parameters based on the change direction */ totalChange[0] = size - box->natural[dir]; shrinking = totalChange[0] < 0; totalChange[1] = 0; totalGlue[1].order = 100000; totalGlue[1].value = 0; maxGlue = 1; if (shrinking) { totalGlue[0] = shrink; /* for first-order infinites, shrink it to zero and then * shrink the zero-orders */ if (shrink.order == 1) { totalSizes = 0; remainingGlue = 0; for (child = box->u.box.firstChild; child; child = child->nextSibling) { switch (child->params.shrink[dir].order) { case 0: remainingGlue += child->params.shrink[dir].value; break; case 1: totalSizes += child->natural[dir]; break; } } if (totalSizes < -totalChange[0]) { totalGlue[1] = shrink; totalGlue[0].order = 0; totalGlue[0].value = remainingGlue; totalChange[1] = -totalSizes; totalChange[0] = totalChange[0] - totalChange[1]; maxGlue = 2; } } if (totalGlue[0].order <= 0 && totalChange[0] > totalGlue[0].value) { totalChange[0] = totalGlue[0].value; } } else totalGlue[0] = stretch; /* adjust each box */ totalSizes = 0; remainingGlue = totalGlue[0].value + totalGlue[1].value; remainingChange = totalChange[0] + totalChange[1]; happy = True; for (child = box->u.box.firstChild; child; child = child->nextSibling) { /* never add glue or stretch to a VariableBox! */ if (child->type == VariableBox) continue; if (shrinking) glue = &child->params.shrink[dir]; else glue = &child->params.stretch[dir]; child->size[dir] = child->natural[dir]; for (i = 0; i < maxGlue; i++) { if (glue->order == totalGlue[i].order) { remainingGlue -= glue->value; if (remainingGlue <= 0) change = remainingChange; else change = GluePart (glue->value, totalGlue[i].value, totalChange[i]); child->size[dir] += change; remainingChange -= change; } } child->size[!dir] = box->size[!dir]; totalSizes += child->size[dir]; if (child->type == BoxBox) if (!ComputeSizes (child)) happy = False; } return totalSizes == box->size[dir] && happy; } static void SetSizes (BoxPtr box, Position x, Position y) { BoxPtr child; int width, height; int bw; Widget w; SubInfoPtr info; switch (box->type) { case WidgetBox: w = box->u.widget.widget; if (w) { info = SubInfo(w); /* info = (SubInfoPtr) w->core.constraints; */ width = box->size[LayoutHorizontal]; height = box->size[LayoutVertical]; bw = info->naturalBw; width -= bw * 2; height -= bw * 2; /* Widgets which grow too small are placed off screen */ if (width <= 0 || height <= 0) { width = 1; height = 1; bw = 0; x = -1; y = -1; } XtConfigureWidget (w, x, y, (Dimension)width, (Dimension)height, (Dimension)bw); } break; case BoxBox: for (child = box->u.box.firstChild; child; child = child->nextSibling) { SetSizes (child, x, y); if (box->u.box.dir == LayoutHorizontal) x += child->size[LayoutHorizontal]; else y += child->size[LayoutVertical]; } break; case GlueBox: case VariableBox: break; } } static void LayoutFreeLayout (BoxPtr box) { BoxPtr child, next; switch (box->type) { case BoxBox: for (child = box->u.box.firstChild; child; child = next) { next = child->nextSibling; LayoutFreeLayout (child); } break; case GlueBox: DisposeExpr (box->u.glue.expr); break; case WidgetBox: case VariableBox: default: break; } DisposeExpr (box->params.stretch[LayoutHorizontal].expr); DisposeExpr (box->params.shrink[LayoutHorizontal].expr); DisposeExpr (box->params.stretch[LayoutVertical].expr); DisposeExpr (box->params.shrink[LayoutVertical].expr); Dispose (box); } static void LayoutGetNaturalSize (LayoutWidget l, Dimension *widthp, Dimension *heightp) { BoxPtr box; DBUG_ENTER("LayoutGetNaturalSize"); box = l->layout.layout; if (box) { ComputeNaturalSizes (l, box, LayoutHorizontal); *widthp = box->natural[LayoutHorizontal]; *heightp = box->natural[LayoutVertical]; } else { *widthp = 0; *heightp = 0; } DBUG_VOID_RETURN; } static void LayoutLayout (LayoutWidget l, Bool attemptResize) { BoxPtr box; Dimension width, height; Dimension prefered_width, prefered_height; DBUG_ENTER("LayoutLayout"); box = l->layout.layout; if (!box) return; LayoutGetNaturalSize (l, &prefered_width, &prefered_height); if (l->core.width == 0 || l->core.height == 0) { l->core.width = prefered_width; l->core.height = prefered_height; } box->size[LayoutHorizontal] = l->core.width; box->size[LayoutVertical] = l->core.height; if (!ComputeSizes (box) && attemptResize) { XtMakeResizeRequest ((Widget) l, prefered_width, prefered_height, &width, &height); if (width != box->size[LayoutHorizontal] || height != box->size[LayoutVertical]) { box->size[LayoutHorizontal] = width; box->size[LayoutVertical] = height; ComputeSizes (box); } } if (l->layout.debug) { PrintBox (box, 0); fflush (stdout); } SetSizes (box, 0, 0); DBUG_VOID_RETURN; }