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