1 /* $XConsortium: Form.c,v 1.52 94/04/17 20:12:06 kaleb Exp $ */
2 
3 /***********************************************************
4 
5 Copyright (c) 1987, 1988, 1994  X Consortium
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 
24 Except as contained in this notice, the name of the X Consortium shall not be
25 used in advertising or otherwise to promote the sale, use or other dealings
26 in this Software without prior written authorization from the X Consortium.
27 
28 
29 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
30 
31                         All Rights Reserved
32 
33 Permission to use, copy, modify, and distribute this software and its
34 documentation for any purpose and without fee is hereby granted,
35 provided that the above copyright notice appear in all copies and that
36 both that copyright notice and this permission notice appear in
37 supporting documentation, and that the name of Digital not be
38 used in advertising or publicity pertaining to distribution of the
39 software without specific, written prior permission.
40 
41 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
42 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
43 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
44 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
45 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
46 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 SOFTWARE.
48 
49 ******************************************************************/
50 
51 #include <X11/IntrinsicP.h>
52 #include <X11/StringDefs.h>
53 #include <X11/Xmu/Converters.h>
54 #include <X11/Xmu/CharSet.h>
55 #include <X11/Xaw3d/XawInit.h>
56 #include <X11/Xaw3d/FormP.h>
57 
58 /* Private Definitions */
59 
60 static int default_value = -99999;
61 
62 #define Offset(field) XtOffsetOf(FormRec, form.field)
63 static XtResource resources[] = {
64     {XtNdefaultDistance, XtCThickness, XtRInt, sizeof(int),
65 	Offset(default_spacing), XtRImmediate, (XtPointer)4}
66 };
67 #undef Offset
68 
69 static XtEdgeType defEdge = XtRubber;
70 
71 #define Offset(field) XtOffsetOf(FormConstraintsRec, form.field)
72 static XtResource formConstraintResources[] = {
73     {XtNtop, XtCEdge, XtREdgeType, sizeof(XtEdgeType),
74 	Offset(top), XtREdgeType, (XtPointer)&defEdge},
75     {XtNbottom, XtCEdge, XtREdgeType, sizeof(XtEdgeType),
76 	Offset(bottom), XtREdgeType, (XtPointer)&defEdge},
77     {XtNleft, XtCEdge, XtREdgeType, sizeof(XtEdgeType),
78 	Offset(left), XtREdgeType, (XtPointer)&defEdge},
79     {XtNright, XtCEdge, XtREdgeType, sizeof(XtEdgeType),
80 	Offset(right), XtREdgeType, (XtPointer)&defEdge},
81     {XtNhorizDistance, XtCThickness, XtRInt, sizeof(int),
82 	Offset(dx), XtRInt, (XtPointer) &default_value},
83     {XtNfromHoriz, XtCWidget, XtRWidget, sizeof(Widget),
84 	Offset(horiz_base), XtRWidget, (XtPointer)NULL},
85     {XtNvertDistance, XtCThickness, XtRInt, sizeof(int),
86 	Offset(dy), XtRInt, (XtPointer) &default_value},
87     {XtNfromVert, XtCWidget, XtRWidget, sizeof(Widget),
88 	Offset(vert_base), XtRWidget, (XtPointer)NULL},
89     {XtNresizable, XtCBoolean, XtRBoolean, sizeof(Boolean),
90 	Offset(allow_resize), XtRImmediate, (XtPointer) FALSE},
91 };
92 #undef Offset
93 
94 static void ClassInitialize(), ClassPartInitialize(), Initialize(), Resize();
95 static void ConstraintInitialize();
96 static Boolean SetValues(), ConstraintSetValues();
97 static XtGeometryResult GeometryManager(), PreferredGeometry();
98 static void ChangeManaged();
99 static Boolean Layout();
100 
101 static void LayoutChild(), ResizeChildren();
102 
103 FormClassRec formClassRec = {
104   { /* core_class fields */
105     /* superclass         */    (WidgetClass) &constraintClassRec,
106     /* class_name         */    "Form",
107     /* widget_size        */    sizeof(FormRec),
108     /* class_initialize   */    ClassInitialize,
109     /* class_part_init    */    ClassPartInitialize,
110     /* class_inited       */    FALSE,
111     /* initialize         */    Initialize,
112     /* initialize_hook    */    NULL,
113     /* realize            */    XtInheritRealize,
114     /* actions            */    NULL,
115     /* num_actions        */    0,
116     /* resources          */    resources,
117     /* num_resources      */    XtNumber(resources),
118     /* xrm_class          */    NULLQUARK,
119     /* compress_motion    */    TRUE,
120     /* compress_exposure  */    TRUE,
121     /* compress_enterleave*/    TRUE,
122     /* visible_interest   */    FALSE,
123     /* destroy            */    NULL,
124     /* resize             */    Resize,
125     /* expose             */    XtInheritExpose,
126     /* set_values         */    SetValues,
127     /* set_values_hook    */    NULL,
128     /* set_values_almost  */    XtInheritSetValuesAlmost,
129     /* get_values_hook    */    NULL,
130     /* accept_focus       */    NULL,
131     /* version            */    XtVersion,
132     /* callback_private   */    NULL,
133     /* tm_table           */    NULL,
134     /* query_geometry     */	PreferredGeometry,
135     /* display_accelerator*/	XtInheritDisplayAccelerator,
136     /* extension          */	NULL
137   },
138   { /* composite_class fields */
139     /* geometry_manager   */   GeometryManager,
140     /* change_managed     */   ChangeManaged,
141     /* insert_child       */   XtInheritInsertChild,
142     /* delete_child       */   XtInheritDeleteChild,
143     /* extension          */   NULL
144   },
145   { /* constraint_class fields */
146     /* subresourses       */   formConstraintResources,
147     /* subresource_count  */   XtNumber(formConstraintResources),
148     /* constraint_size    */   sizeof(FormConstraintsRec),
149     /* initialize         */   ConstraintInitialize,
150     /* destroy            */   NULL,
151     /* set_values         */   ConstraintSetValues,
152     /* extension          */   NULL
153   },
154   { /* form_class fields */
155     /* layout             */   Layout
156   }
157 };
158 
159 WidgetClass formWidgetClass = (WidgetClass)&formClassRec;
160 
161 /****************************************************************
162  *
163  * Private Procedures
164  *
165  ****************************************************************/
166 
167 
168 static XrmQuark	XtQChainLeft, XtQChainRight, XtQChainTop,
169 		XtQChainBottom, XtQRubber;
170 
171 /* ARGSUSED */
_CvtStringToEdgeType(args,num_args,fromVal,toVal)172 static void _CvtStringToEdgeType(args, num_args, fromVal, toVal)
173     XrmValuePtr args;		/* unused */
174     Cardinal    *num_args;      /* unused */
175     XrmValuePtr fromVal;
176     XrmValuePtr toVal;
177 {
178   static XtEdgeType edgeType;
179   XrmQuark q;
180   char lowerName[40];
181 
182   if (strlen ((char*) fromVal->addr) < sizeof lowerName) {
183     XmuCopyISOLatin1Lowered (lowerName, (char*)fromVal->addr);
184     q = XrmStringToQuark(lowerName);
185     if (q == XtQChainLeft)        edgeType = XtChainLeft;
186     else if (q == XtQChainRight)  edgeType = XtChainRight;
187     else if (q == XtQChainTop)    edgeType = XtChainTop;
188     else if (q == XtQChainBottom) edgeType = XtChainBottom;
189     else if (q == XtQRubber)      edgeType = XtRubber;
190     else {
191       toVal->size = 0;
192       toVal->addr = NULL;
193       return;
194     }
195     toVal->size = sizeof edgeType;
196     toVal->addr = (XPointer) &edgeType;
197     return;
198   }
199   toVal->addr = NULL;
200   toVal->size = 0;
201 }
202 
ClassInitialize()203 static void ClassInitialize()
204 {
205     static XtConvertArgRec parentCvtArgs[] = {
206 	{XtBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.parent),
207 	     sizeof(Widget)}
208     };
209     XawInitializeWidgetSet();
210     XtQChainLeft   = XrmPermStringToQuark("chainleft");
211     XtQChainRight  = XrmPermStringToQuark("chainright");
212     XtQChainTop    = XrmPermStringToQuark("chaintop");
213     XtQChainBottom = XrmPermStringToQuark("chainbottom");
214     XtQRubber      = XrmPermStringToQuark("rubber");
215 
216     XtAddConverter( XtRString, XtREdgeType, _CvtStringToEdgeType,
217 		    (XtConvertArgList)NULL, 0 );
218     XtSetTypeConverter (XtRString, XtRWidget, XmuNewCvtStringToWidget,
219 			parentCvtArgs, XtNumber(parentCvtArgs), XtCacheNone,
220 			(XtDestructor)NULL);
221 }
222 
ClassPartInitialize(class)223 static void ClassPartInitialize(class)
224     WidgetClass class;
225 {
226     FormWidgetClass c = (FormWidgetClass)class;
227     FormWidgetClass super = (FormWidgetClass)
228 	c->core_class.superclass;
229 
230     if (c->form_class.layout == XtInheritLayout)
231 	c->form_class.layout = super->form_class.layout;
232 }
233 
234 /* ARGSUSED */
Initialize(request,new,args,num_args)235 static void Initialize(request, new, args, num_args)
236     Widget request, new;
237     ArgList args;
238     Cardinal *num_args;
239 {
240     FormWidget fw = (FormWidget)new;
241 
242     fw->form.old_width = fw->core.width;
243     fw->form.old_height = fw->core.height;
244     fw->form.no_refigure = False;
245     fw->form.needs_relayout = False;
246     fw->form.resize_in_layout = True;
247     fw->form.resize_is_no_op = False;
248 }
249 
250 /*	Function Name: ChangeFormGeometry
251  *	Description: Ask the parent to change the form widget's geometry.
252  *	Arguments: w - the Form widget.
253  *                 query_only - TRUE if this is only a query.
254  *                 width, height - the new width and height.
255  *                 ret_width, ret_height - the actual size the form is allowed
256  *                                         to resize to.
257  *	Returns: TRUE of children may always be resized.
258  */
259 
260 static Boolean
ChangeFormGeometry(w,query_only,width,height,ret_width,ret_height)261 ChangeFormGeometry(w, query_only, width, height, ret_width, ret_height)
262 Widget w;
263 Boolean query_only;
264 Dimension width, height;
265 Dimension *ret_width, *ret_height;
266 {
267     FormWidget fw = (FormWidget) w;
268     Boolean always_resize_children;
269     XtGeometryResult result;
270     XtWidgetGeometry request, return_request;
271 
272     /*
273      * If we are already at the desired size then there is no need
274      * to ask our parent of we can change size.
275      */
276 
277     if ( (width == fw->core.width) && (height == fw->core.height) )
278 	return(TRUE);
279 
280     request.width = width;
281     request.height = height;
282     request.request_mode = CWWidth | CWHeight;
283     if (query_only)
284 	request.request_mode |= XtCWQueryOnly;
285 
286     /*
287      * Do no invoke the resize rules if our size changes here.
288      */
289 
290     fw->form.resize_is_no_op = TRUE;
291 
292     result = XtMakeGeometryRequest(w, &request, &return_request);
293     if (result == XtGeometryAlmost) {
294 	request = return_request;
295 	(void) XtMakeGeometryRequest(w, &request, &return_request);
296 	always_resize_children = FALSE;
297     }
298     else
299 	always_resize_children = (result == XtGeometryYes);
300 
301     fw->form.resize_is_no_op = FALSE;
302 
303     if (ret_width != NULL)
304 	*ret_width = request.width;
305     if (ret_height != NULL)
306 	*ret_height = request.height;
307 
308     return(always_resize_children);
309 }
310 
311 /*	Function Name: Layout
312  *	Description: Moves all the children around.
313  *	Arguments: fw - the Form widget.
314  *                 width, height - ** UNUSED **.
315  *                 force_relayout - will force the children to be
316  *                                 moved, even if some go past the edge
317  *                                 of the form.
318  *	Returns: True if the children are allowed to move from their
319  *               current locations to the new ones.
320  */
321 
322 /* ARGSUSED */
Layout(fw,width,height,force_relayout)323 static Boolean Layout(fw, width, height, force_relayout)
324     FormWidget fw;
325     Dimension width, height;
326     Boolean force_relayout;
327 {
328     int num_children = fw->composite.num_children;
329     WidgetList children = fw->composite.children;
330     Widget *childP;
331     Dimension maxx, maxy;
332     Boolean ret_val;
333 
334     for (childP = children; childP - children < num_children; childP++) {
335 	FormConstraints form = (FormConstraints)(*childP)->core.constraints;
336 	form->form.layout_state = LayoutPending;
337     }
338 
339     maxx = maxy = 1;
340     for (childP = children; childP - children < num_children; childP++) {
341 	if (XtIsManaged(*childP)) {
342 	    FormConstraints form;
343 	    Position x, y;
344 
345 	    form = (FormConstraints)(*childP)->core.constraints;
346 
347 	    LayoutChild(*childP);
348 
349 	    x = form->form.new_x + (*childP)->core.width +
350 		((*childP)->core.border_width << 1);
351 	    if (x > (int)maxx)
352 		maxx = x;
353 
354 	    y = form->form.new_y + (*childP)->core.height +
355 		((*childP)->core.border_width << 1);
356 	    if (y > (int)maxy)
357 		maxy = y;
358 	}
359     }
360 
361     fw->form.preferred_width = (maxx += fw->form.default_spacing);
362     fw->form.preferred_height = (maxy += fw->form.default_spacing);
363 
364     if (fw->form.resize_in_layout) {
365 	Boolean always_resize_children;
366 
367 	always_resize_children =
368 	    ChangeFormGeometry( (Widget) fw, FALSE, maxx, maxy,
369 				(Dimension *)NULL, (Dimension *)NULL);
370 
371 	fw->form.old_width  = fw->core.width;
372 	fw->form.old_height = fw->core.height;
373 
374 	ret_val = (always_resize_children || ( (fw->core.width >= maxx) &&
375 					      (fw->core.height >= maxy)));
376 
377 	if (force_relayout)
378 	    ret_val = TRUE;
379 
380 	if (ret_val)
381 	    ResizeChildren((Widget) fw);
382     }
383     else
384 	ret_val = False;
385 
386     fw->form.needs_relayout = False;
387     return ret_val;
388 }
389 
390 /*	Function Name: ResizeChildren
391  *	Description: Resizes all children to new_x and new_y.
392  *	Arguments: w - the form widget.
393  *	Returns: none.
394  */
395 
ResizeChildren(w)396 static void ResizeChildren(w)
397 Widget w;
398 {
399     FormWidget fw = (FormWidget) w;
400     int num_children = fw->composite.num_children;
401     WidgetList children = fw->composite.children;
402     Widget *childP;
403 
404     for (childP = children; childP - children < num_children; childP++) {
405 	FormConstraints form;
406 
407 	if (!XtIsManaged(*childP))
408 	    continue;
409 
410 	form = (FormConstraints)(*childP)->core.constraints;
411 	if (fw->form.no_refigure) {
412 /*
413  * I am changing the widget wrapper w/o modifing the window.  This is
414  * risky, but I can get away with it since I am the parent of this
415  * widget, and he must ask me for any geometry changes.
416  *
417  * The window will be updated when no_refigure is set back to False.
418  */
419 	    (*childP)->core.x = form->form.new_x;
420 	    (*childP)->core.y = form->form.new_y;
421 	}
422 	else
423 	    XtMoveWidget(*childP, form->form.new_x, form->form.new_y);
424     }
425 }
426 
427 
LayoutChild(w)428 static void LayoutChild(w)
429     Widget w;
430 {
431     FormConstraints form = (FormConstraints)w->core.constraints;
432     Widget ref;
433 
434     switch (form->form.layout_state) {
435 
436       case LayoutPending:
437 	form->form.layout_state = LayoutInProgress;
438 	break;
439 
440       case LayoutDone:
441 	return;
442 
443       case LayoutInProgress:
444 	{
445 	String subs[2];
446 	Cardinal num_subs = 2;
447 	subs[0] = w->core.name;
448 	subs[1] = w->core.parent->core.name;
449 	XtAppWarningMsg(XtWidgetToApplicationContext(w),
450 			"constraintLoop","xawFormLayout","XawToolkitError",
451    "constraint loop detected while laying out child '%s' in FormWidget '%s'",
452 			subs, &num_subs);
453 	return;
454 	}
455     }
456 
457     form->form.new_x = form->form.dx;
458     form->form.new_y = form->form.dy;
459     if ((ref = form->form.horiz_base) != (Widget)NULL) {
460 	FormConstraints ref_form = (FormConstraints) ref->core.constraints;
461 
462 	LayoutChild(ref);
463 	form->form.new_x += (ref_form->form.new_x +
464 			     ref->core.width + (ref->core.border_width << 1));
465     }
466     if ((ref = form->form.vert_base) != (Widget)NULL) {
467 	FormConstraints ref_form = (FormConstraints) ref->core.constraints;
468 
469 	LayoutChild(ref);
470 	form->form.new_y += (ref_form->form.new_y +
471 			     ref->core.height + (ref->core.border_width << 1));
472     }
473 
474     form->form.layout_state = LayoutDone;
475 }
476 
477 
TransformCoord(loc,old,new,type)478 static Position TransformCoord(loc, old, new, type)
479     Position loc;
480     Dimension old, new;
481     XtEdgeType type;
482 {
483     if (type == XtRubber) {
484         if ( ((int) old) > 0)
485 	    loc = (int)(loc * new) / (int)old;
486     }
487     else if (type == XtChainBottom || type == XtChainRight)
488       loc += (Position)new - (Position)old;
489 
490     /* I don't see any problem with returning values less than zero. */
491 
492     return (loc);
493 }
494 
Resize(w)495 static void Resize(w)
496     Widget w;
497 {
498     FormWidget fw = (FormWidget)w;
499     WidgetList children = fw->composite.children;
500     int num_children = fw->composite.num_children;
501     Widget *childP;
502     Position x, y;
503     Dimension width, height;
504 
505     if (!fw->form.resize_is_no_op)
506 	for (childP = children; childP - children < num_children; childP++) {
507 	    FormConstraints form= (FormConstraints)(*childP)->core.constraints;
508 	    if (!XtIsManaged(*childP)) continue;
509 	    x = TransformCoord( (*childP)->core.x, fw->form.old_width,
510 			       fw->core.width, form->form.left );
511 	    y = TransformCoord( (*childP)->core.y, fw->form.old_height,
512 			       fw->core.height, form->form.top );
513 
514 	    form->form.virtual_width =
515 		TransformCoord((Position)((*childP)->core.x
516 					  + form->form.virtual_width
517 					  + 2 * (*childP)->core.border_width),
518 			       fw->form.old_width, fw->core.width,
519 			       form->form.right )
520 		    - (x + 2 * (*childP)->core.border_width);
521 
522 	    form->form.virtual_height =
523 		TransformCoord((Position)((*childP)->core.y
524 					  + form->form.virtual_height
525 					  + 2 * (*childP)->core.border_width),
526 			       fw->form.old_height, fw->core.height,
527 			       form->form.bottom )
528 		    - ( y + 2 * (*childP)->core.border_width);
529 
530 	    width = (Dimension)
531 		(form->form.virtual_width < 1) ? 1 : form->form.virtual_width;
532 	    height = (Dimension)
533 	       (form->form.virtual_height < 1) ? 1 : form->form.virtual_height;
534 
535 	    XtConfigureWidget(*childP,x,y, (Dimension)width, (Dimension)height,
536 			      (*childP)->core.border_width );
537 	}
538 
539     fw->form.old_width = fw->core.width;
540     fw->form.old_height = fw->core.height;
541 }
542 
543 /*
544  * I don't want to even think about what ``Almost'' would mean - Chris.
545  */
546 
547 /* ARGSUSED */
GeometryManager(w,request,reply)548 static XtGeometryResult GeometryManager(w, request, reply)
549     Widget w;
550     XtWidgetGeometry *request;
551     XtWidgetGeometry *reply;	/* RETURN */
552 {
553     Dimension old_width, old_height;
554     FormWidget fw = (FormWidget) XtParent(w);
555     FormConstraints form = (FormConstraints) w->core.constraints;
556     XtWidgetGeometry allowed;
557     XtGeometryResult ret_val;
558 
559     if ((request->request_mode & ~(XtCWQueryOnly | CWWidth | CWHeight)) ||
560 	!form->form.allow_resize) {
561 
562 	/* If GeometryManager is invoked during a SetValues call on a child
563          * then it is necessary to compute a new layout if ConstraintSetValues
564          * allowed any constraint changes. */
565 
566 	if (fw->form.needs_relayout)
567 	    (*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
568 		(fw, 0, 0, True);
569 	return(XtGeometryNo);
570     }
571 
572     if (request->request_mode & CWWidth)
573 	allowed.width = request->width;
574     else
575 	allowed.width = w->core.width;
576 
577     if (request->request_mode & CWHeight)
578 	allowed.height = request->height;
579     else
580 	allowed.height = w->core.height;
581 
582     if (allowed.width == w->core.width && allowed.height == w->core.height) {
583 
584 	/* If GeometryManager is invoked during a SetValues call on a child
585          * then it is necessary to compute a new layout if ConstraintSetValues
586          * allowed any constraint changes. */
587 
588 	if (fw->form.needs_relayout)
589 	    (*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
590 		(fw, 0, 0, True);
591 	return(XtGeometryNo);
592     }
593 
594     /*
595      * Remember the old size, and then set the size to the requested size.
596      */
597 
598     old_width = w->core.width;
599     old_height = w->core.height;
600     w->core.width = allowed.width;
601     w->core.height = allowed.height;
602 
603     if (request->request_mode & XtCWQueryOnly) {
604 	Boolean always_resize_children;
605 	Dimension ret_width, ret_height;
606 
607 	fw->form.resize_in_layout = FALSE;
608 
609 	(*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
610   	                                 ( fw, w->core.width, w->core.height,
611 					   FALSE );
612 
613 	/*
614 	 * Reset the size of this child back to what it used to be.
615 	 */
616 
617 	w->core.width = old_width;
618 	w->core.height = old_height;
619 
620 	fw->form.resize_in_layout = TRUE;
621 
622 	always_resize_children = ChangeFormGeometry(w, TRUE,
623 				   fw->form.preferred_width,
624 				   fw->form.preferred_height,
625 				   &ret_width, &ret_height);
626 
627 	if (always_resize_children ||
628 	    ((ret_width >= fw->form.preferred_width) &&
629 	     (ret_height >= fw->form.preferred_height)))
630 	{
631 	    ret_val = XtGeometryYes;
632 	}
633 	else
634 	    ret_val = XtGeometryNo;
635     }
636     else {
637 	if ((*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
638 	                                  ( fw, w->core.width, w->core.height,
639 					    FALSE))
640 	{
641 	    form->form.virtual_width = w->core.width;   /* reset virtual */
642 	    form->form.virtual_height = w->core.height; /* width and height. */
643 	    if (fw->form.no_refigure) {
644 /*
645  * I am changing the widget wrapper w/o modifing the window.  This is
646  * risky, but I can get away with it since I am the parent of this
647  * widget, and he must ask me for any geometry changes.
648  *
649  * The window will be updated when no_refigure is set back to False.
650  */
651 		form->form.deferred_resize = True;
652 		ret_val = XtGeometryDone;
653 	    }
654 	    else
655 		ret_val = XtGeometryYes;
656 	}
657 	else {
658 	    w->core.width = old_width;
659 	    w->core.height = old_height;
660 	    ret_val = XtGeometryNo;
661 	}
662     }
663 
664     return(ret_val);
665 }
666 
667 
668 /* ARGSUSED */
SetValues(current,request,new,args,num_args)669 static Boolean SetValues(current, request, new, args, num_args)
670     Widget current, request, new;
671     ArgList args;
672     Cardinal *num_args;
673 {
674     return( FALSE );
675 }
676 
677 
678 /* ARGSUSED */
ConstraintInitialize(request,new,args,num_args)679 static void ConstraintInitialize(request, new, args, num_args)
680     Widget request, new;
681     ArgList args;
682     Cardinal *num_args;
683 {
684     FormConstraints form = (FormConstraints)new->core.constraints;
685     FormWidget fw = (FormWidget)new->core.parent;
686 
687     form->form.virtual_width = (int) new->core.width;
688     form->form.virtual_height = (int) new->core.height;
689 
690     if (form->form.dx == default_value)
691         form->form.dx = fw->form.default_spacing;
692 
693     if (form->form.dy == default_value)
694         form->form.dy = fw->form.default_spacing;
695 
696     form->form.deferred_resize = False;
697 }
698 
699 /*ARGSUSED*/
ConstraintSetValues(current,request,new,args,num_args)700 static Boolean ConstraintSetValues(current, request, new, args, num_args)
701     Widget current, request, new;
702     ArgList args;
703     Cardinal *num_args;
704 {
705   FormConstraints cfc = (FormConstraints) current->core.constraints;
706   FormConstraints nfc = (FormConstraints) new->core.constraints;
707 
708   if (cfc->form.top          != nfc->form.top         ||
709       cfc->form.bottom       != nfc->form.bottom      ||
710       cfc->form.left         != nfc->form.left        ||
711       cfc->form.right        != nfc->form.right       ||
712       cfc->form.dx           != nfc->form.dx          ||
713       cfc->form.dy           != nfc->form.dy          ||
714       cfc->form.horiz_base   != nfc->form.horiz_base  ||
715       cfc->form.vert_base    != nfc->form.vert_base) {
716 
717       FormWidget fp = (FormWidget) XtParent(new);
718 
719     /* If there are no subclass ConstraintSetValues procedures remaining
720      * to be invoked, and if there is no geometry request about to be
721      * made, then invoke the new layout now; else defer it. */
722 
723     if (XtClass(XtParent(new))  == formWidgetClass	&&
724 	current->core.x		== new->core.x		&&
725 	current->core.y		== new->core.y		&&
726 	current->core.width	== new->core.width	&&
727 	current->core.height	== new->core.height	&&
728 	current->core.border_width == new->core.border_width)
729 	Layout(fp, 0, 0, True);
730     else fp->form.needs_relayout = True;
731   }
732   return( FALSE );
733 }
734 
ChangeManaged(w)735 static void ChangeManaged(w)
736     Widget w;
737 {
738   FormWidget fw = (FormWidget)w;
739   FormConstraints form;
740   WidgetList children, childP;
741   int num_children = fw->composite.num_children;
742   Widget child;
743 
744   /*
745    * Reset virtual width and height for all children.
746    */
747 
748   for (children = childP = fw->composite.children ;
749        childP - children < num_children; childP++) {
750     child = *childP;
751     if (XtIsManaged(child)) {
752       form = (FormConstraints)child->core.constraints;
753 
754 /*
755  * If the size is one (1) then we must not change the virtual sizes, as
756  * they contain useful information.  If someone actually wants a widget of
757  * width or height one (1) in a form widget he will lose, can't win them all.
758  *
759  * Chris D. Peterson 2/9/89.
760  */
761 
762       if ( child->core.width != 1)
763 	form->form.virtual_width = (int) child->core.width;
764       if ( child->core.height != 1)
765 	form->form.virtual_height = (int) child->core.height;
766     }
767   }
768   (*((FormWidgetClass)w->core.widget_class)->form_class.layout)
769   	                                 ((FormWidget) w, w->core.width,
770 					  w->core.height, TRUE);
771 }
772 
773 
PreferredGeometry(widget,request,reply)774 static XtGeometryResult PreferredGeometry( widget, request, reply  )
775     Widget widget;
776     XtWidgetGeometry *request, *reply;
777 {
778     FormWidget w = (FormWidget)widget;
779 
780     reply->width = w->form.preferred_width;
781     reply->height = w->form.preferred_height;
782     reply->request_mode = CWWidth | CWHeight;
783     if (  request->request_mode & (CWWidth | CWHeight) ==
784 	    (CWWidth | CWHeight)
785 	  && request->width == reply->width
786 	  && request->height == reply->height)
787 	return XtGeometryYes;
788     else if (reply->width == w->core.width && reply->height == w->core.height)
789 	return XtGeometryNo;
790     else
791 	return XtGeometryAlmost;
792 }
793 
794 
795 /**********************************************************************
796  *
797  * Public routines
798  *
799  **********************************************************************/
800 
801 /*
802  * Set or reset figuring (ignored if not realized)
803  */
804 
805 void
806 #if NeedFunctionPrototypes
XawFormDoLayout(Widget w,int doit)807 XawFormDoLayout(Widget w,
808 #if NeedWidePrototypes
809 		int doit)
810 #else
811 		Boolean doit)
812 #endif
813 #else
814 XawFormDoLayout(w, doit)
815 Widget w;
816 Boolean doit;
817 #endif
818 {
819     Widget *childP;
820     FormWidget fw = (FormWidget)w;
821     int num_children = fw->composite.num_children;
822     WidgetList children = fw->composite.children;
823 
824     if ( ((fw->form.no_refigure = !doit) == TRUE) || !XtIsRealized(w) )
825 	return;
826 
827     for (childP = children; childP - children < num_children; childP++) {
828 	Widget w = *childP;
829 	if (XtIsManaged(w)) {
830 	    FormConstraints form = (FormConstraints)w->core.constraints;
831 
832 	    /*
833 	     * Xt Configure widget is too smart, and optimizes out
834 	     * my changes.
835 	     */
836 
837 	    XMoveResizeWindow(XtDisplay(w), XtWindow(w),
838 			      w->core.x, w->core.y,
839 			      w->core.width, w->core.height);
840 
841 	    if (form->form.deferred_resize &&
842 		XtClass(w)->core_class.resize != (XtWidgetProc) NULL) {
843 		(*(XtClass(w)->core_class.resize))(w);
844 		form->form.deferred_resize = False;
845 	    }
846 	}
847     }
848 }
849