Home | History | Annotate | Line # | Download | only in src
      1 /***********************************************************
      2 
      3 Copyright 1987, 1988, 1994, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in this Software without prior written authorization from The Open Group.
     24 
     25 
     26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
     27 
     28                         All Rights Reserved
     29 
     30 Permission to use, copy, modify, and distribute this software and its
     31 documentation for any purpose and without fee is hereby granted,
     32 provided that the above copyright notice appear in all copies and that
     33 both that copyright notice and this permission notice appear in
     34 supporting documentation, and that the name of Digital not be
     35 used in advertising or publicity pertaining to distribution of the
     36 software without specific, written prior permission.
     37 
     38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     44 SOFTWARE.
     45 
     46 ******************************************************************/
     47 
     48 #ifdef HAVE_CONFIG_H
     49 #include <config.h>
     50 #endif
     51 #include <X11/IntrinsicP.h>
     52 #include <X11/StringDefs.h>
     53 #include <X11/Xmu/CharSet.h>
     54 #include <X11/Xmu/Converters.h>
     55 #include <X11/Xaw/FormP.h>
     56 #include <X11/Xaw/XawInit.h>
     57 #include "Private.h"
     58 
     59 /*
     60  * Class Methods
     61  */
     62 static void XawFormChangeManaged(Widget);
     63 static void XawFormClassInitialize(void);
     64 static void XawFormClassPartInitialize(WidgetClass);
     65 static void XawFormConstraintInitialize(Widget, Widget, ArgList, Cardinal*);
     66 static Boolean XawFormConstraintSetValues(Widget, Widget, Widget,
     67 					  ArgList, Cardinal*);
     68 static XtGeometryResult XawFormGeometryManager(Widget, XtWidgetGeometry*,
     69 					       XtWidgetGeometry*);
     70 static void XawFormInitialize(Widget, Widget, ArgList, Cardinal*);
     71 #ifndef OLDXAW
     72 static void XawFormRealize(Widget, Mask*, XSetWindowAttributes*);
     73 static void XawFormRedisplay(Widget, XEvent*, Region);
     74 #endif
     75 static XtGeometryResult XawFormQueryGeometry(Widget, XtWidgetGeometry*,
     76 					     XtWidgetGeometry*);
     77 static void XawFormResize(Widget);
     78 static Boolean XawFormSetValues(Widget, Widget, Widget,	ArgList, Cardinal*);
     79 static Boolean Layout(FormWidget, unsigned int, unsigned int, Bool);
     80 
     81 /*
     82  * Prototypes
     83  */
     84 static void _CvtStringToEdgeType(XrmValuePtr, Cardinal*,
     85 				 XrmValuePtr, XrmValuePtr);
     86 static Bool ChangeFormGeometry(Widget, Bool, unsigned int, unsigned int,
     87 			       Dimension*, Dimension*);
     88 Boolean CvtEdgeTypeToString(Display*, XrmValuePtr, Cardinal*,
     89 			    XrmValuePtr, XrmValuePtr, XtPointer*);
     90 static void LayoutChild(Widget);
     91 static int TransformCoord(int, unsigned int, unsigned int, XtEdgeType);
     92 static void ResizeChildren(Widget);
     93 
     94 /*
     95  * Initialization
     96  */
     97 #ifndef OLDXAW
     98 static XtActionsRec actions[] = {
     99   {"set-values", XawSetValuesAction},
    100   {"get-values", XawGetValuesAction},
    101   {"declare",    XawDeclareAction},
    102   {"call-proc",  XawCallProcAction},
    103 };
    104 #endif
    105 
    106 static XrmQuark	QchainLeft, QchainRight, QchainTop, QchainBottom, Qrubber;
    107 
    108 #define default_value	-99999
    109 #define Offset(field) XtOffsetOf(FormRec, form.field)
    110 static XtResource resources[] = {
    111   {
    112     XtNdefaultDistance,
    113     XtCThickness,
    114     XtRInt,
    115     sizeof(int),
    116     Offset(default_spacing),
    117     XtRImmediate,
    118     (XtPointer)4
    119   },
    120 #ifndef OLDXAW
    121   {
    122     XawNdisplayList,
    123     XawCDisplayList,
    124     XawRDisplayList,
    125     sizeof(XawDisplayList*),
    126     Offset(display_list),
    127     XtRImmediate,
    128     NULL
    129   },
    130 #endif
    131 };
    132 #undef Offset
    133 
    134 #define defEdge		XtRubber
    135 
    136 #define Offset(field) XtOffsetOf(FormConstraintsRec, form.field)
    137 static XtResource formConstraintResources[] = {
    138   {
    139     XtNtop,
    140     XtCEdge,
    141     XtREdgeType,
    142     sizeof(XtEdgeType),
    143     Offset(top),
    144     XtRImmediate,
    145     (XtPointer)defEdge
    146   },
    147   {
    148     XtNbottom,
    149     XtCEdge,
    150     XtREdgeType,
    151     sizeof(XtEdgeType),
    152     Offset(bottom),
    153     XtRImmediate,
    154     (XtPointer)defEdge
    155   },
    156   {
    157     XtNleft,
    158     XtCEdge,
    159     XtREdgeType,
    160     sizeof(XtEdgeType),
    161     Offset(left),
    162     XtRImmediate,
    163     (XtPointer)defEdge
    164   },
    165   {
    166     XtNright,
    167     XtCEdge,
    168     XtREdgeType,
    169     sizeof(XtEdgeType),
    170     Offset(right),
    171     XtRImmediate,
    172     (XtPointer)defEdge
    173   },
    174   {
    175     XtNhorizDistance,
    176     XtCThickness,
    177     XtRInt,
    178     sizeof(int),
    179     Offset(dx),
    180     XtRImmediate,
    181     (XtPointer)default_value
    182   },
    183   {
    184     XtNfromHoriz,
    185     XtCWidget,
    186     XtRWidget,
    187     sizeof(Widget),
    188     Offset(horiz_base),
    189     XtRWidget,
    190     NULL
    191   },
    192   {
    193     XtNvertDistance,
    194     XtCThickness,
    195     XtRInt,
    196     sizeof(int),
    197     Offset(dy),
    198     XtRImmediate,
    199     (XtPointer)default_value
    200   },
    201   {
    202     XtNfromVert,
    203     XtCWidget,
    204     XtRWidget,
    205     sizeof(Widget),
    206     Offset(vert_base),
    207     XtRWidget,
    208     NULL
    209   },
    210   {
    211     XtNresizable,
    212     XtCBoolean,
    213     XtRBoolean,
    214     sizeof(Boolean),
    215     Offset(allow_resize),
    216     XtRImmediate,
    217     (XtPointer)False
    218   },
    219 };
    220 #undef Offset
    221 
    222 FormClassRec formClassRec = {
    223   /* core */
    224   {
    225     (WidgetClass)&constraintClassRec,	/* superclass */
    226     "Form",				/* class_name */
    227     sizeof(FormRec),			/* widget_size */
    228     XawFormClassInitialize,		/* class_initialize */
    229     XawFormClassPartInitialize,		/* class_part_init */
    230     False,				/* class_inited */
    231     XawFormInitialize,			/* initialize */
    232     NULL,				/* initialize_hook */
    233 #ifndef OLDXAW
    234     XawFormRealize,			/* realize */
    235     actions,				/* actions */
    236     XtNumber(actions),			/* num_actions */
    237 #else
    238     XtInheritRealize,			/* realize */
    239     NULL,				/* actions */
    240     0,					/* num_actions */
    241 #endif
    242     resources,				/* resources */
    243     XtNumber(resources),		/* num_resources */
    244     NULLQUARK,				/* xrm_class */
    245     True,				/* compress_motion */
    246     True,				/* compress_exposure */
    247     True,				/* compress_enterleave */
    248     False,				/* visible_interest */
    249     NULL,				/* destroy */
    250     XawFormResize,			/* resize */
    251 #ifndef OLDXAW
    252     XawFormRedisplay,			/* expose */
    253 #else
    254     XtInheritExpose,			/* expose */
    255 #endif
    256     XawFormSetValues,			/* set_values */
    257     NULL,				/* set_values_hook */
    258     XtInheritSetValuesAlmost,		/* set_values_almost */
    259     NULL,				/* get_values_hook */
    260     NULL,				/* accept_focus */
    261     XtVersion,				/* version */
    262     NULL,				/* callback_private */
    263     NULL,				/* tm_table */
    264     XawFormQueryGeometry,		/* query_geometry */
    265     XtInheritDisplayAccelerator,	/* display_accelerator */
    266     NULL,				/* extension */
    267   },
    268   /* composite */
    269   {
    270     XawFormGeometryManager,		/* geometry_manager */
    271     XawFormChangeManaged,		/* change_managed */
    272     XtInheritInsertChild,		/* insert_child */
    273     XtInheritDeleteChild,		/* delete_child */
    274     NULL,				/* extension */
    275   },
    276   /* constraint */
    277   {
    278     formConstraintResources,		/* subresourses */
    279     XtNumber(formConstraintResources),	/* subresource_count */
    280     sizeof(FormConstraintsRec),		/* constraint_size */
    281     XawFormConstraintInitialize,	/* initialize */
    282     NULL,				/* destroy */
    283     XawFormConstraintSetValues,		/* set_values */
    284     NULL,				/* extension */
    285   },
    286   /* form */
    287   {
    288     Layout,				/* layout */
    289 #ifndef OLDXAW
    290     NULL,
    291 #endif
    292   },
    293 };
    294 
    295 WidgetClass formWidgetClass = (WidgetClass)&formClassRec;
    296 
    297 /*
    298  * Implementation
    299  */
    300 #ifndef OLDXAW
    301 static void
    302 XawFormRealize(Widget w, Mask *mask, XSetWindowAttributes *attr)
    303 {
    304     (*formWidgetClass->core_class.superclass->core_class.realize)(w, mask, attr);
    305 
    306     if (w->core.background_pixmap > XtUnspecifiedPixmap) {
    307 	XawPixmap *pixmap =
    308 	    XawPixmapFromXPixmap(w->core.background_pixmap, XtScreen(w),
    309 				 w->core.colormap, (int)w->core.depth);
    310 	if (pixmap && pixmap->mask)
    311 	    XawReshapeWidget(w, pixmap);
    312     }
    313 }
    314 
    315 static void
    316 XawFormRedisplay(Widget w, XEvent *event, Region region)
    317 {
    318     FormWidget xaw = (FormWidget)w;
    319 
    320     if (xaw->form.display_list)
    321 	XawRunDisplayList(w, xaw->form.display_list, event, region);
    322 }
    323 #endif
    324 
    325 /*ARGSUSED*/
    326 static void
    327 _CvtStringToEdgeType(XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    328 		     XrmValuePtr fromVal, XrmValuePtr toVal)
    329 {
    330     static XtEdgeType edgeType;
    331     XrmQuark q;
    332     char name[12];
    333 
    334     XmuNCopyISOLatin1Lowered(name, (char*)fromVal->addr, sizeof(name));
    335     q = XrmStringToQuark(name);
    336 
    337     if (q == QchainLeft)
    338 	edgeType = XtChainLeft;
    339     else if (q == QchainRight)
    340 	edgeType = XtChainRight;
    341     else if (q == QchainTop)
    342 	edgeType = XtChainTop;
    343     else if (q == QchainBottom)
    344 	edgeType = XtChainBottom;
    345     else if (q == Qrubber)
    346 	edgeType = XtRubber;
    347     else {
    348 	XtStringConversionWarning(fromVal->addr, XtREdgeType);
    349 	toVal->size = 0;
    350 	toVal->addr = NULL;
    351 	return;
    352     }
    353 
    354     toVal->size = sizeof(XtEdgeType);
    355     toVal->addr = (XPointer)&edgeType;
    356 }
    357 
    358 /*ARGSUSED*/
    359 Boolean
    360 CvtEdgeTypeToString(Display *dpy, XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    361 		    XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data _X_UNUSED)
    362 {
    363     static String buffer;
    364     Cardinal size;
    365 
    366     switch (*(XtEdgeType *)fromVal->addr) {
    367 	case XtChainLeft:
    368 	    buffer = XtEchainLeft;
    369 	    break;
    370 	case XtChainRight:
    371 	    buffer = XtEchainRight;
    372 	    break;
    373 	case XtChainTop:
    374 	    buffer = XtEchainTop;
    375 	    break;
    376 	case XtChainBottom:
    377 	    buffer = XtEchainBottom;
    378 	    break;
    379 	case XtRubber:
    380 	    buffer = XtErubber;
    381 	    break;
    382 	default:
    383 	    XawTypeToStringWarning(dpy, XtREdgeType);
    384 	    toVal->addr = NULL;
    385 	    toVal->size = 0;
    386 	    return (False);
    387     }
    388 
    389     size = (Cardinal)strlen(buffer) + 1;
    390     if (toVal->addr != NULL) {
    391 	if (toVal->size < size)	{
    392 	    toVal->size = size;
    393 	    return (False);
    394 	}
    395 	strcpy((char *)toVal->addr, buffer);
    396     }
    397     else
    398 	toVal->addr = (XPointer)buffer;
    399     toVal->size = sizeof(String);
    400 
    401     return (True);
    402 }
    403 
    404 static void
    405 XawFormClassInitialize(void)
    406 {
    407     static XtConvertArgRec parentCvtArgs[] = {
    408 	{XtBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.parent),
    409 	 sizeof(Widget)}
    410     };
    411 
    412     char name[12];
    413 
    414     XawInitializeWidgetSet();
    415     XmuNCopyISOLatin1Lowered(name, XtEchainLeft, sizeof(name));
    416     QchainLeft = XrmStringToQuark(name);
    417     XmuNCopyISOLatin1Lowered(name, XtEchainRight, sizeof(name));
    418     QchainRight = XrmStringToQuark(name);
    419     XmuNCopyISOLatin1Lowered(name, XtEchainTop, sizeof(name));
    420     QchainTop = XrmStringToQuark(name);
    421     XmuNCopyISOLatin1Lowered(name, XtEchainBottom, sizeof(name));
    422     QchainBottom = XrmStringToQuark(name);
    423     XmuNCopyISOLatin1Lowered(name, XtErubber, sizeof(name));
    424     Qrubber = XrmStringToQuark(name);
    425 
    426     XtAddConverter(XtRString, XtREdgeType, _CvtStringToEdgeType, NULL, 0);
    427     XtSetTypeConverter(XtREdgeType, XtRString, CvtEdgeTypeToString,
    428 		       NULL, 0, XtCacheNone, NULL);
    429     XtSetTypeConverter(XtRString, XtRWidget, XmuNewCvtStringToWidget,
    430 		       parentCvtArgs, XtNumber(parentCvtArgs), XtCacheNone,
    431 		       NULL);
    432     XtSetTypeConverter(XtRWidget, XtRString, XmuCvtWidgetToString,
    433 		       NULL, 0, XtCacheNone, NULL);
    434 }
    435 
    436 static void
    437 XawFormClassPartInitialize(WidgetClass cclass)
    438 {
    439     FormWidgetClass c = (FormWidgetClass)cclass;
    440     FormWidgetClass super = (FormWidgetClass)c->core_class.superclass;
    441 
    442     if (c->form_class.layout == XtInheritLayout)
    443 	c->form_class.layout = super->form_class.layout;
    444 }
    445 
    446 /*ARGSUSED*/
    447 static void
    448 XawFormInitialize(Widget request _X_UNUSED, Widget cnew,
    449 		  ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
    450 {
    451     FormWidget fw = (FormWidget)cnew;
    452 
    453     fw->form.old_width = fw->form.old_height = 0;
    454     fw->form.no_refigure = False;
    455     fw->form.needs_relayout = False;
    456     fw->form.resize_in_layout = True;
    457     fw->form.resize_is_no_op = False;
    458 }
    459 
    460 /*
    461  * Function:
    462  *	ChangeFormGeometry
    463  *
    464  * Parameters:
    465  *	w	   - Form widget
    466  *	query_only - is only a query?
    467  *	width	   - new width and height
    468  *	height	   - ""
    469  *	ret_width  - actual size the form is allowed to resize to (return)
    470  *	ret_height - ""
    471  *
    472  * Description:
    473  *	Ask the parent to change the form widget's geometry.
    474  *
    475  * Returns:
    476  *	True of children may always be resized
    477  */
    478 static Bool
    479 ChangeFormGeometry(Widget w, Bool query_only,
    480 		   unsigned int width, unsigned int height,
    481 		   Dimension *ret_width, Dimension *ret_height)
    482 {
    483     FormWidget fw = (FormWidget)w;
    484     Boolean always_resize_children;
    485     XtGeometryResult result;
    486     XtWidgetGeometry request, return_request;
    487 
    488     /*
    489      * If we are already at the desired size then there is no need
    490      * to ask our parent of we can change size
    491      */
    492     if (width == XtWidth(fw) && height == XtHeight(fw))
    493 	return (True);
    494 
    495     request.width = (Dimension)width;
    496     request.height = (Dimension)height;
    497     request.request_mode = CWWidth | CWHeight;
    498     if (query_only)
    499 	request.request_mode |= XtCWQueryOnly;
    500 
    501     /*
    502      * Do no invoke the resize rules if our size changes here
    503      */
    504     fw->form.resize_is_no_op = True;
    505 
    506     result = XtMakeGeometryRequest(w, &request, &return_request);
    507     if (result == XtGeometryAlmost) {
    508 	request = return_request;
    509 	(void)XtMakeGeometryRequest(w, &request, &return_request);
    510 	always_resize_children = False;
    511     }
    512     else
    513 	always_resize_children = result == XtGeometryYes;
    514 
    515     fw->form.resize_is_no_op = False;
    516 
    517     if (ret_width != NULL)
    518 	*ret_width = request.width;
    519     if (ret_height != NULL)
    520 	*ret_height = request.height;
    521 
    522     return (always_resize_children);
    523 }
    524 
    525 /*
    526  * Function:
    527  *	Layout
    528  *
    529  * Parameters:
    530  *	fw	       - Form widget
    531  *	width	       - unused
    532  *	height	       - ""
    533  *	force_relayout - will force the children to be moved, even if some
    534  *			 go past the edge of the form
    535  *
    536  * Description:
    537  *	Moves all the children around.
    538  *
    539  * Returns:
    540  *	  True if the children are allowed to move from their
    541  *	  current locations to the new ones.
    542  */
    543 /*ARGSUSED*/
    544 static Boolean
    545 Layout(FormWidget fw, unsigned int width _X_UNUSED, unsigned int height _X_UNUSED,
    546        Bool force_relayout)
    547 {
    548     int num_children = (int)fw->composite.num_children;
    549     WidgetList children = fw->composite.children;
    550     Widget *childP;
    551     Dimension maxx, maxy;
    552     Boolean ret_val;
    553 
    554     for (childP = children; childP - children < num_children; childP++) {
    555 	FormConstraints form = (FormConstraints)(*childP)->core.constraints;
    556 	form->form.layout_state = LayoutPending;
    557     }
    558 
    559     maxx = maxy = 1;
    560     for (childP = children; childP - children < num_children; childP++) {
    561 	if (XtIsManaged(*childP)) {
    562 	    FormConstraints form;
    563 	    Position x, y;
    564 
    565 	    form = (FormConstraints)(*childP)->core.constraints;
    566 
    567 	    LayoutChild(*childP);
    568 
    569 	    x = (Position)(form->form.new_x + XtWidth(*childP)
    570 		+ (XtBorderWidth(*childP) << 1));
    571 	    if (x > (int)maxx)
    572 		maxx = (Dimension)x;
    573 
    574 	    y = (Position)(form->form.new_y + XtHeight(*childP)
    575 		+ (XtBorderWidth(*childP) << 1));
    576 	    if (y > (int)maxy)
    577 		maxy = (Dimension)y;
    578 	}
    579     }
    580 
    581     fw->form.preferred_width = (maxx = (Dimension)(maxx + fw->form.default_spacing));
    582     fw->form.preferred_height = (maxy = (Dimension)(maxy + fw->form.default_spacing));
    583 
    584     if (fw->form.resize_in_layout) {
    585 	Boolean always_resize_children;
    586 
    587 	always_resize_children =
    588 	    (Boolean)ChangeFormGeometry((Widget)fw, False, maxx, maxy, NULL, NULL);
    589 
    590 #ifdef OLDXAW
    591 	fw->form.old_width  = fw->core.width;
    592 	fw->form.old_height = fw->core.height;
    593 #endif
    594 
    595 	if (force_relayout)
    596 	    ret_val = True;
    597 	else
    598 	    ret_val = always_resize_children ||
    599 			(XtWidth(fw) >= maxx && XtHeight(fw) >= maxy);
    600 
    601 	if (ret_val)
    602 	    ResizeChildren((Widget)fw);
    603     }
    604     else
    605 	ret_val = False;
    606 
    607     fw->form.needs_relayout = False;
    608 
    609     return (ret_val);
    610 }
    611 
    612 /*
    613  * Function:
    614  *	ResizeChildren
    615  *
    616  * Parameters:
    617  *	w - form widget
    618  *
    619  * Description:
    620  *	Resizes all children to new_x and new_y.
    621  */
    622 static void
    623 ResizeChildren(Widget w)
    624 {
    625     FormWidget fw = (FormWidget)w;
    626     int num_children = (int)fw->composite.num_children;
    627     WidgetList children = fw->composite.children;
    628     Widget *childP;
    629 
    630     for (childP = children; childP - children < num_children; childP++) {
    631 	FormConstraints form;
    632 	Position x, y;
    633 
    634 	if (!XtIsManaged(*childP))
    635 	    continue;
    636 
    637 	form = (FormConstraints)(*childP)->core.constraints;
    638 
    639 	if (fw->form.old_width && fw->form.old_height) {
    640 	    x = (Position)TransformCoord(form->form.new_x, fw->form.old_width,
    641 			       XtWidth(fw), form->form.left);
    642 	    y = (Position)TransformCoord(form->form.new_y, fw->form.old_height,
    643 			       XtHeight(fw), form->form.top);
    644 	}
    645 	else {
    646 	    x = form->form.new_x;
    647 	    y = form->form.new_y;
    648 	}
    649 
    650 	if (fw->form.no_refigure) {
    651 	   /*
    652 	    * I am changing the widget wrapper w/o modifying the window. This is
    653 	    * risky, but I can get away with it since I am the parent of this
    654 	    * widget, and he must ask me for any geometry changes
    655 	    *
    656 	    * The window will be updated when no_refigure is set back to False
    657 	    */
    658 	    XtX(*childP) = x;
    659 	    XtY(*childP) = y;
    660 	}
    661 	else
    662 	    XtMoveWidget(*childP, x, y);
    663     }
    664 }
    665 
    666 static void
    667 LayoutChild(Widget w)
    668 {
    669     FormConstraints form = (FormConstraints)w->core.constraints;
    670     Widget ref;
    671 
    672     switch (form->form.layout_state) {
    673 	case LayoutPending:
    674 	    form->form.layout_state = LayoutInProgress;
    675 	    break;
    676 	case LayoutDone:
    677 	    return;
    678 	case LayoutInProgress: {
    679 	    String subs[2];
    680 	    Cardinal num_subs = 2;
    681 	    subs[0] = w->core.name;
    682 	    subs[1] = w->core.parent->core.name;
    683 
    684 	    XtAppWarningMsg(XtWidgetToApplicationContext(w),
    685 			    "constraintLoop", "xawFormLayout", "XawToolkitError",
    686 			    "constraint loop detected while laying out "
    687 			    "child '%s' in FormWidget '%s'",
    688 			    subs, &num_subs);
    689 	}   return;
    690     }
    691 
    692     form->form.new_x = (Position)form->form.dx;
    693     form->form.new_y = (Position)form->form.dy;
    694     if ((ref = form->form.horiz_base) != NULL) {
    695 	FormConstraints ref_form = (FormConstraints)ref->core.constraints;
    696 
    697 	LayoutChild(ref);
    698 	form->form.new_x = (Position)(form->form.new_x
    699 				      + (ref_form->form.new_x
    700 				      + XtWidth(ref)
    701 				      + (XtBorderWidth(ref) << 1)));
    702     }
    703     if ((ref = form->form.vert_base) != NULL) {
    704 	FormConstraints ref_form = (FormConstraints)ref->core.constraints;
    705 
    706 	LayoutChild(ref);
    707 	form->form.new_y = (Position)(form->form.new_y
    708 				      + (ref_form->form.new_y
    709 				      + XtHeight(ref)
    710 				      + (XtBorderWidth(ref) << 1)));
    711     }
    712 
    713     form->form.layout_state = LayoutDone;
    714 }
    715 
    716 static int
    717 TransformCoord(int loc, unsigned int old, unsigned int cnew, XtEdgeType type)
    718 {
    719     if (type == XtRubber) {
    720 	if ((int)old > 0)
    721 	    loc = (int)(loc * ((double)cnew / (double)old));
    722     }
    723     else if (type == XtChainBottom || type == XtChainRight)
    724 	loc += (int)cnew - (int)old;
    725 
    726     return (loc);
    727 }
    728 
    729 static void
    730 XawFormResize(Widget w)
    731 {
    732     FormWidget fw = (FormWidget)w;
    733     WidgetList children = fw->composite.children;
    734     int num_children = (int)fw->composite.num_children;
    735     Widget *childP;
    736     int x, y;
    737     int width, height;
    738     Boolean unmap = XtIsRealized(w) && w->core.mapped_when_managed &&
    739 		    XtIsManaged(w);
    740 
    741     if (unmap)
    742 	XtUnmapWidget(w);
    743 
    744     if (!fw->form.resize_is_no_op)
    745 	for (childP = children; childP - children < num_children; childP++) {
    746 	    FormConstraints form = (FormConstraints)(*childP)->core.constraints;
    747 
    748 	    if (!XtIsManaged(*childP))
    749 		continue;
    750 
    751 #ifndef OLDXAW
    752 	    x = TransformCoord(form->form.virtual_x, fw->form.old_width,
    753 			      XtWidth(fw), form->form.left);
    754 	    y = TransformCoord(form->form.virtual_y, fw->form.old_height,
    755 			       XtHeight(fw), form->form.top);
    756 	    width = TransformCoord(form->form.virtual_x +
    757 				   form->form.virtual_width +
    758 				   (XtBorderWidth(*childP) << 1),
    759 				   fw->form.old_width, XtWidth(fw),
    760 				   form->form.right) -
    761 				   (x + (XtBorderWidth(*childP) << 1));
    762 	    height = TransformCoord(form->form.virtual_y +
    763 				    form->form.virtual_height +
    764 				    (XtBorderWidth(*childP) << 1),
    765 				    fw->form.old_height, XtHeight(fw),
    766 				    form->form.bottom) -
    767 				    (y + (XtBorderWidth(*childP) << 1));
    768 #else
    769 	    x = TransformCoord(XtX(*childP), fw->form.old_width,
    770 			      XtWidth(fw), form->form.left);
    771 	    y = TransformCoord(XtY(*childP), fw->form.old_height,
    772 			       XtHeight(fw), form->form.top);
    773 	    width = TransformCoord(XtX(*childP) + form->form.virtual_width +
    774 				   (XtBorderWidth(*childP) << 1),
    775 				   fw->form.old_width, XtWidth(fw),
    776 				   form->form.right) -
    777 				   (x + (XtBorderWidth(*childP) << 1));
    778 	    height = TransformCoord(XtY(*childP) + form->form.virtual_height +
    779 				    (XtBorderWidth(*childP) << 1),
    780 				    fw->form.old_height, XtHeight(fw),
    781 				    form->form.bottom) -
    782 				    (y + (XtBorderWidth(*childP) << 1));
    783 	    form->form.virtual_width = (short)width;
    784 	    form->form.virtual_height = (short)height;
    785 #endif
    786 
    787 	    width = width < 1 ? 1 : width;
    788 	    height = height < 1 ? 1 : height;
    789 
    790 	    XtConfigureWidget(*childP,
    791 			      (Position)x, (Position)y,
    792 			      (Dimension)width, (Dimension)height,
    793 			      XtBorderWidth(*childP));
    794 	}
    795 
    796     if (unmap)
    797 	XtMapWidget(w);
    798 
    799 #ifdef OLDXAW
    800     fw->form.old_width = XtWidth(fw);
    801     fw->form.old_height = XtHeight(fw);
    802 #endif
    803 }
    804 
    805 /*ARGSUSED*/
    806 static XtGeometryResult
    807 XawFormGeometryManager(Widget w, XtWidgetGeometry *request,
    808 		       XtWidgetGeometry *reply _X_UNUSED)
    809 {
    810     Dimension old_width, old_height;
    811     FormWidget fw = (FormWidget)XtParent(w);
    812     FormConstraints form = (FormConstraints)w->core.constraints;
    813     XtWidgetGeometry allowed;
    814     XtGeometryResult ret_val;
    815 
    816     if ((request->request_mode & (unsigned)~(XtCWQueryOnly | CWWidth | CWHeight))
    817 	|| !form->form.allow_resize) {
    818 	/* If GeometryManager is invoked during a SetValues call on a child
    819 	 * then it is necessary to compute a new layout if ConstraintSetValues
    820 	 * allowed any constraint changes
    821 	 */
    822 	if (fw->form.needs_relayout)
    823 	    (*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
    824 		(fw, 0, 0, True);
    825 	return (XtGeometryNo);
    826     }
    827 
    828     if (request->request_mode & CWWidth)
    829 	allowed.width = request->width;
    830     else
    831 	allowed.width = XtWidth(w);
    832 
    833     if (request->request_mode & CWHeight)
    834 	allowed.height = request->height;
    835     else
    836 	allowed.height = XtHeight(w);
    837 
    838     if (allowed.width == XtWidth(w) && allowed.height == XtHeight(w)) {
    839 	/* If GeometryManager is invoked during a SetValues call on a child
    840 	 * then it is necessary to compute a new layout if ConstraintSetValues
    841 	 * allowed any constraint changes
    842 	 */
    843 	if (fw->form.needs_relayout)
    844 	    (*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
    845 		(fw, 0, 0, True);
    846 	return (XtGeometryNo);
    847     }
    848 
    849     /*
    850      * Remember the old size, and then set the size to the requested size
    851      */
    852     old_width = XtWidth(w);
    853     old_height = XtHeight(w);
    854     XtWidth(w) = allowed.width;
    855     XtHeight(w) = allowed.height;
    856 
    857     if (request->request_mode & XtCWQueryOnly) {
    858 	Boolean always_resize_children;
    859 	Dimension ret_width, ret_height;
    860 
    861 	fw->form.resize_in_layout = False;
    862 
    863 	(*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
    864 	    (fw, XtWidth(w), XtHeight(w), False);
    865 
    866 	/*
    867 	 * Reset the size of this child back to what it used to be
    868 	 */
    869 	XtWidth(w) = old_width;
    870 	XtHeight(w) = old_height;
    871 
    872 	fw->form.resize_in_layout = True;
    873 
    874 	always_resize_children = (Boolean)ChangeFormGeometry(w, True,
    875 				   fw->form.preferred_width,
    876 				   fw->form.preferred_height,
    877 				   &ret_width, &ret_height);
    878 
    879 	if (always_resize_children
    880 	    || (ret_width >= fw->form.preferred_width
    881 		&& ret_height >= fw->form.preferred_height))
    882 	    ret_val = XtGeometryYes;
    883 	else
    884 	    ret_val = XtGeometryNo;
    885     }
    886     else {
    887 	if ((*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
    888 		(fw, XtWidth(w), XtHeight(w), False)) {
    889 	    Widget *childP;
    890 	    int num_children = (int)fw->composite.num_children;
    891 	    WidgetList children = fw->composite.children;
    892 
    893 	    if (fw->form.no_refigure) {
    894 		/*
    895 		 * I am changing the widget wrapper w/o modifying the window.
    896 		 * This is risky, but I can get away with it since I am the
    897 		 * parent of this widget, and he must ask me for any geometry
    898 		 * changes
    899 		 *
    900 		 * The window will be updated when no_refigure is set back
    901 		 * to False
    902 		 */
    903 		form->form.deferred_resize = True;
    904 		ret_val = XtGeometryDone;
    905 	    }
    906 	    else
    907 		ret_val = XtGeometryYes;
    908 
    909 	    /*
    910 	     * Resets everything.
    911 	     */
    912 	    fw->form.old_width = XtWidth(fw);
    913 	    fw->form.old_height = XtHeight(fw);
    914 	    for (childP = children; childP - children < num_children; childP++) {
    915 		Widget nw = *childP;
    916 
    917 		if (XtIsManaged(nw)) {
    918 		    FormConstraints nform = (FormConstraints)nw->core.constraints;
    919 
    920 #ifndef OLDXAW
    921 		    nform->form.virtual_x = XtX(nw);
    922 		    nform->form.virtual_y = XtY(nw);
    923 #endif
    924 		    nform->form.virtual_width = (short)XtWidth(nw);
    925 		    nform->form.virtual_height = (short)XtHeight(nw);
    926 		}
    927 	    }
    928 	}
    929 	else {
    930 	    XtWidth(w) = old_width;
    931 	    XtHeight(w) = old_height;
    932 	    ret_val = XtGeometryNo;
    933 	}
    934     }
    935 
    936     return (ret_val);
    937 }
    938 
    939 /*ARGSUSED*/
    940 static Boolean
    941 XawFormSetValues(Widget current _X_UNUSED, Widget request _X_UNUSED, Widget cnew _X_UNUSED,
    942 		 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
    943 {
    944 #ifndef OLDXAW
    945     FormWidget f_old = (FormWidget)current;
    946     FormWidget f_new = (FormWidget)cnew;
    947 
    948     if (f_old->core.background_pixmap != f_new->core.background_pixmap) {
    949 	XawPixmap *opix, *npix;
    950 
    951 	opix = XawPixmapFromXPixmap(f_old->core.background_pixmap, XtScreen(f_old),
    952 				    f_old->core.colormap, (int)f_old->core.depth);
    953 	npix = XawPixmapFromXPixmap(f_new->core.background_pixmap, XtScreen(f_new),
    954 				    f_new->core.colormap, (int)f_new->core.depth);
    955 	if ((npix && npix->mask) || (opix && opix->mask))
    956 	    XawReshapeWidget(cnew, npix);
    957     }
    958 #endif /* OLDXAW */
    959 
    960     return (False);
    961 }
    962 
    963 /* ARGSUSED */
    964 static void
    965 XawFormConstraintInitialize(Widget request _X_UNUSED, Widget cnew,
    966 			    ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
    967 {
    968     FormConstraints form = (FormConstraints)cnew->core.constraints;
    969     FormWidget fw = (FormWidget)cnew->core.parent;
    970 
    971 #ifndef OLDXAW
    972     form->form.virtual_x = XtX(cnew);
    973     form->form.virtual_y = XtY(cnew);
    974 #endif
    975     form->form.virtual_width = (short)XtWidth(cnew);
    976     form->form.virtual_height = (short)XtHeight(cnew);
    977 
    978     if (form->form.dx == default_value)
    979 	form->form.dx = fw->form.default_spacing;
    980 
    981     if (form->form.dy == default_value)
    982 	form->form.dy = fw->form.default_spacing;
    983 
    984     form->form.deferred_resize = False;
    985 }
    986 
    987 /*ARGSUSED*/
    988 static Boolean
    989 XawFormConstraintSetValues(Widget current, Widget request _X_UNUSED, Widget cnew,
    990 			   ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
    991 {
    992     FormConstraints cfc = (FormConstraints)current->core.constraints;
    993     FormConstraints nfc = (FormConstraints)cnew->core.constraints;
    994 
    995     if (cfc->form.top != nfc->form.top || cfc->form.bottom != nfc->form.bottom
    996 	|| cfc->form.left != nfc->form.left || cfc->form.right != nfc->form.right
    997 	|| cfc->form.dx != nfc->form.dx || cfc->form.dy != nfc->form.dy
    998 	|| cfc->form.horiz_base != nfc->form.horiz_base
    999 	|| cfc->form.vert_base != nfc->form.vert_base) {
   1000 	FormWidget fp = (FormWidget)XtParent(cnew);
   1001 
   1002 	/* If there are no subclass ConstraintSetValues procedures remaining
   1003 	 * to be invoked, and if there is no geometry request about to be
   1004 	 * made, then invoke the new layout now; else defer it
   1005 	 */
   1006 	if (XtClass(XtParent(cnew)) == formWidgetClass
   1007 	    && XtX(current) == XtX(cnew)
   1008 	    && XtY(current) == XtY(cnew)
   1009 	    && XtWidth(current) == XtWidth(cnew)
   1010 	    && XtHeight(current) == XtHeight(cnew)
   1011 	    && XtBorderWidth(current) == XtBorderWidth(cnew))
   1012 	    Layout(fp, 0, 0, True);
   1013 	else
   1014 	    fp->form.needs_relayout = True;
   1015     }
   1016 
   1017     return (False);
   1018 }
   1019 
   1020 static void
   1021 XawFormChangeManaged(Widget w)
   1022 {
   1023     FormWidget fw = (FormWidget)w;
   1024     WidgetList children, childP;
   1025     int num_children = (int)fw->composite.num_children;
   1026 
   1027     (*((FormWidgetClass)w->core.widget_class)->form_class.layout)
   1028 	(fw, XtWidth(w), XtHeight(w), True);
   1029 
   1030     fw->form.old_width = XtWidth(w);
   1031     fw->form.old_height = XtHeight(w);
   1032     for (children = childP = fw->composite.children;
   1033 	 childP - children < num_children;
   1034 	 childP++) {
   1035 	FormConstraints form;
   1036 	Widget child = *childP;
   1037 	if (!XtIsManaged(child))
   1038 	    continue;
   1039 	form = (FormConstraints)child->core.constraints;
   1040 #ifndef OLDXAW
   1041 	form->form.virtual_x = XtX(child);
   1042 	form->form.virtual_y = XtY(child);
   1043 #endif
   1044 	form->form.virtual_width = (short)XtWidth(child);
   1045 	form->form.virtual_height = (short)XtHeight(child);
   1046     }
   1047 }
   1048 
   1049 static XtGeometryResult
   1050 XawFormQueryGeometry(Widget widget, XtWidgetGeometry *request,
   1051 		     XtWidgetGeometry *reply)
   1052 {
   1053     FormWidget w = (FormWidget)widget;
   1054 
   1055     reply->width = w->form.preferred_width;
   1056     reply->height = w->form.preferred_height;
   1057     reply->request_mode = CWWidth | CWHeight;
   1058 
   1059     if ((request->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight)
   1060 	&& request->width == reply->width
   1061 	&& request->height == reply->height)
   1062 	return (XtGeometryYes);
   1063     else if (reply->width == XtWidth(w) && reply->height == XtHeight(w))
   1064 	return (XtGeometryNo);
   1065 
   1066     return (XtGeometryAlmost);
   1067 }
   1068 
   1069 /*
   1070  * Public routines
   1071  */
   1072 /*
   1073  * Set or reset figuring (ignored if not realized)
   1074  */
   1075 void
   1076 XawFormDoLayout(Widget w,
   1077 #if NeedWidePrototypes
   1078 		Bool force
   1079 #else
   1080 		Boolean force
   1081 #endif
   1082 )
   1083 {
   1084     Widget *childP;
   1085     FormWidget fw = (FormWidget)w;
   1086     int num_children = (int)fw->composite.num_children;
   1087     WidgetList children = fw->composite.children;
   1088 
   1089     if ((fw->form.no_refigure = !force) == True || !XtIsRealized(w))
   1090 	return;
   1091 
   1092     for (childP = children; childP - children < num_children; childP++) {
   1093 	Widget nw = *childP;
   1094 
   1095 	if (XtIsManaged(nw)) {
   1096 	    FormConstraints form = (FormConstraints)nw->core.constraints;
   1097 
   1098 	    /*
   1099 	     * Xt Configure widget is too smart, and optimizes out
   1100 	     * my changes
   1101 	     */
   1102 	    XMoveResizeWindow(XtDisplay(nw), XtWindow(nw),
   1103 			      XtX(nw), XtY(nw), XtWidth(nw), XtHeight(nw));
   1104 
   1105 	    if (form)
   1106 	      if (form->form.deferred_resize &&
   1107 		XtClass(nw)->core_class.resize != NULL) {
   1108 		(*(XtClass(nw)->core_class.resize))(nw);
   1109 		form->form.deferred_resize = False;
   1110 	      }
   1111 	}
   1112     }
   1113 }
   1114