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
XawFormRealize(Widget w,Mask * mask,XSetWindowAttributes * attr)302 XawFormRealize(Widget w, Mask *mask, XSetWindowAttributes *attr)
303 {
304     XawPixmap *pixmap;
305 
306     (*formWidgetClass->core_class.superclass->core_class.realize)(w, mask, attr);
307 
308     if (w->core.background_pixmap > XtUnspecifiedPixmap) {
309 	pixmap = XawPixmapFromXPixmap(w->core.background_pixmap, XtScreen(w),
310 				      w->core.colormap, (int)w->core.depth);
311 	if (pixmap && pixmap->mask)
312 	    XawReshapeWidget(w, pixmap);
313     }
314 }
315 
316 static void
XawFormRedisplay(Widget w,XEvent * event,Region region)317 XawFormRedisplay(Widget w, XEvent *event, Region region)
318 {
319     FormWidget xaw = (FormWidget)w;
320 
321     if (xaw->form.display_list)
322 	XawRunDisplayList(w, xaw->form.display_list, event, region);
323 }
324 #endif
325 
326 /*ARGSUSED*/
327 static void
_CvtStringToEdgeType(XrmValuePtr args _X_UNUSED,Cardinal * num_args _X_UNUSED,XrmValuePtr fromVal,XrmValuePtr toVal)328 _CvtStringToEdgeType(XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED,
329 		     XrmValuePtr fromVal, XrmValuePtr toVal)
330 {
331     static XtEdgeType edgeType;
332     XrmQuark q;
333     char name[12];
334 
335     XmuNCopyISOLatin1Lowered(name, (char*)fromVal->addr, sizeof(name));
336     q = XrmStringToQuark(name);
337 
338     if (q == QchainLeft)
339 	edgeType = XtChainLeft;
340     else if (q == QchainRight)
341 	edgeType = XtChainRight;
342     else if (q == QchainTop)
343 	edgeType = XtChainTop;
344     else if (q == QchainBottom)
345 	edgeType = XtChainBottom;
346     else if (q == Qrubber)
347 	edgeType = XtRubber;
348     else {
349 	XtStringConversionWarning(fromVal->addr, XtREdgeType);
350 	toVal->size = 0;
351 	toVal->addr = NULL;
352 	return;
353     }
354 
355     toVal->size = sizeof(XtEdgeType);
356     toVal->addr = (XPointer)&edgeType;
357 }
358 
359 /*ARGSUSED*/
360 Boolean
CvtEdgeTypeToString(Display * dpy,XrmValuePtr args _X_UNUSED,Cardinal * num_args _X_UNUSED,XrmValuePtr fromVal,XrmValuePtr toVal,XtPointer * data _X_UNUSED)361 CvtEdgeTypeToString(Display *dpy, XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED,
362 		    XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data _X_UNUSED)
363 {
364     static String buffer;
365     Cardinal size;
366 
367     switch (*(XtEdgeType *)fromVal->addr) {
368 	case XtChainLeft:
369 	    buffer = XtEchainLeft;
370 	    break;
371 	case XtChainRight:
372 	    buffer = XtEchainRight;
373 	    break;
374 	case XtChainTop:
375 	    buffer = XtEchainTop;
376 	    break;
377 	case XtChainBottom:
378 	    buffer = XtEchainBottom;
379 	    break;
380 	case XtRubber:
381 	    buffer = XtErubber;
382 	    break;
383 	default:
384 	    XawTypeToStringWarning(dpy, XtREdgeType);
385 	    toVal->addr = NULL;
386 	    toVal->size = 0;
387 	    return (False);
388     }
389 
390     size = (Cardinal)strlen(buffer) + 1;
391     if (toVal->addr != NULL) {
392 	if (toVal->size < size)	{
393 	    toVal->size = size;
394 	    return (False);
395 	}
396 	strcpy((char *)toVal->addr, buffer);
397     }
398     else
399 	toVal->addr = (XPointer)buffer;
400     toVal->size = sizeof(String);
401 
402     return (True);
403 }
404 
405 static void
XawFormClassInitialize(void)406 XawFormClassInitialize(void)
407 {
408     static XtConvertArgRec parentCvtArgs[] = {
409 	{XtBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.parent),
410 	 sizeof(Widget)}
411     };
412 
413     char name[12];
414 
415     XawInitializeWidgetSet();
416     XmuNCopyISOLatin1Lowered(name, XtEchainLeft, sizeof(name));
417     QchainLeft = XrmStringToQuark(name);
418     XmuNCopyISOLatin1Lowered(name, XtEchainRight, sizeof(name));
419     QchainRight = XrmStringToQuark(name);
420     XmuNCopyISOLatin1Lowered(name, XtEchainTop, sizeof(name));
421     QchainTop = XrmStringToQuark(name);
422     XmuNCopyISOLatin1Lowered(name, XtEchainBottom, sizeof(name));
423     QchainBottom = XrmStringToQuark(name);
424     XmuNCopyISOLatin1Lowered(name, XtErubber, sizeof(name));
425     Qrubber = XrmStringToQuark(name);
426 
427     XtAddConverter(XtRString, XtREdgeType, _CvtStringToEdgeType, NULL, 0);
428     XtSetTypeConverter(XtREdgeType, XtRString, CvtEdgeTypeToString,
429 		       NULL, 0, XtCacheNone, NULL);
430     XtSetTypeConverter(XtRString, XtRWidget, XmuNewCvtStringToWidget,
431 		       parentCvtArgs, XtNumber(parentCvtArgs), XtCacheNone,
432 		       NULL);
433     XtSetTypeConverter(XtRWidget, XtRString, XmuCvtWidgetToString,
434 		       NULL, 0, XtCacheNone, NULL);
435 }
436 
437 static void
XawFormClassPartInitialize(WidgetClass cclass)438 XawFormClassPartInitialize(WidgetClass cclass)
439 {
440     FormWidgetClass c = (FormWidgetClass)cclass;
441     FormWidgetClass super = (FormWidgetClass)c->core_class.superclass;
442 
443     if (c->form_class.layout == XtInheritLayout)
444 	c->form_class.layout = super->form_class.layout;
445 }
446 
447 /*ARGSUSED*/
448 static void
XawFormInitialize(Widget request _X_UNUSED,Widget cnew,ArgList args _X_UNUSED,Cardinal * num_args _X_UNUSED)449 XawFormInitialize(Widget request _X_UNUSED, Widget cnew,
450 		  ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
451 {
452     FormWidget fw = (FormWidget)cnew;
453 
454     fw->form.old_width = fw->form.old_height = 0;
455     fw->form.no_refigure = False;
456     fw->form.needs_relayout = False;
457     fw->form.resize_in_layout = True;
458     fw->form.resize_is_no_op = False;
459 }
460 
461 /*
462  * Function:
463  *	ChangeFormGeometry
464  *
465  * Parameters:
466  *	w	   - Form widget
467  *	query_only - is only a query?
468  *	width	   - new width and height
469  *	height	   - ""
470  *	ret_width  - actual size the form is allowed to resize to (return)
471  *	ret_height - ""
472  *
473  * Description:
474  *	Ask the parent to change the form widget's geometry.
475  *
476  * Returns:
477  *	True of children may always be resized
478  */
479 static Bool
ChangeFormGeometry(Widget w,Bool query_only,unsigned int width,unsigned int height,Dimension * ret_width,Dimension * ret_height)480 ChangeFormGeometry(Widget w, Bool query_only,
481 		   unsigned int width, unsigned int height,
482 		   Dimension *ret_width, Dimension *ret_height)
483 {
484     FormWidget fw = (FormWidget)w;
485     Boolean always_resize_children;
486     XtGeometryResult result;
487     XtWidgetGeometry request, return_request;
488 
489     /*
490      * If we are already at the desired size then there is no need
491      * to ask our parent of we can change size
492      */
493     if (width == XtWidth(fw) && height == XtHeight(fw))
494 	return (True);
495 
496     request.width = (Dimension)width;
497     request.height = (Dimension)height;
498     request.request_mode = CWWidth | CWHeight;
499     if (query_only)
500 	request.request_mode |= XtCWQueryOnly;
501 
502     /*
503      * Do no invoke the resize rules if our size changes here
504      */
505     fw->form.resize_is_no_op = True;
506 
507     result = XtMakeGeometryRequest(w, &request, &return_request);
508     if (result == XtGeometryAlmost) {
509 	request = return_request;
510 	(void)XtMakeGeometryRequest(w, &request, &return_request);
511 	always_resize_children = False;
512     }
513     else
514 	always_resize_children = result == XtGeometryYes;
515 
516     fw->form.resize_is_no_op = False;
517 
518     if (ret_width != NULL)
519 	*ret_width = request.width;
520     if (ret_height != NULL)
521 	*ret_height = request.height;
522 
523     return (always_resize_children);
524 }
525 
526 /*
527  * Function:
528  *	Layout
529  *
530  * Parameters:
531  *	fw	       - Form widget
532  *	width	       - unused
533  *	height	       - ""
534  *	force_relayout - will force the children to be moved, even if some
535  *			 go past the edge of the form
536  *
537  * Description:
538  *	Moves all the children around.
539  *
540  * Returns:
541  *	  True if the children are allowed to move from their
542  *	  current locations to the new ones.
543  */
544 /*ARGSUSED*/
545 static Boolean
Layout(FormWidget fw,unsigned int width _X_UNUSED,unsigned int height _X_UNUSED,Bool force_relayout)546 Layout(FormWidget fw, unsigned int width _X_UNUSED, unsigned int height _X_UNUSED,
547        Bool force_relayout)
548 {
549     int num_children = (int)fw->composite.num_children;
550     WidgetList children = fw->composite.children;
551     Widget *childP;
552     Dimension maxx, maxy;
553     Boolean ret_val;
554 
555     for (childP = children; childP - children < num_children; childP++) {
556 	FormConstraints form = (FormConstraints)(*childP)->core.constraints;
557 	form->form.layout_state = LayoutPending;
558     }
559 
560     maxx = maxy = 1;
561     for (childP = children; childP - children < num_children; childP++) {
562 	if (XtIsManaged(*childP)) {
563 	    FormConstraints form;
564 	    Position x, y;
565 
566 	    form = (FormConstraints)(*childP)->core.constraints;
567 
568 	    LayoutChild(*childP);
569 
570 	    x = (Position)(form->form.new_x + XtWidth(*childP)
571 		+ (XtBorderWidth(*childP) << 1));
572 	    if (x > (int)maxx)
573 		maxx = (Dimension)x;
574 
575 	    y = (Position)(form->form.new_y + XtHeight(*childP)
576 		+ (XtBorderWidth(*childP) << 1));
577 	    if (y > (int)maxy)
578 		maxy = (Dimension)y;
579 	}
580     }
581 
582     fw->form.preferred_width = (maxx = (Dimension)(maxx + fw->form.default_spacing));
583     fw->form.preferred_height = (maxy = (Dimension)(maxy + fw->form.default_spacing));
584 
585     if (fw->form.resize_in_layout) {
586 	Boolean always_resize_children;
587 
588 	always_resize_children =
589 	    (Boolean)ChangeFormGeometry((Widget)fw, False, maxx, maxy, NULL, NULL);
590 
591 #ifdef OLDXAW
592 	fw->form.old_width  = fw->core.width;
593 	fw->form.old_height = fw->core.height;
594 #endif
595 
596 	if (force_relayout)
597 	    ret_val = True;
598 	else
599 	    ret_val = always_resize_children ||
600 			(XtWidth(fw) >= maxx && XtHeight(fw) >= maxy);
601 
602 	if (ret_val)
603 	    ResizeChildren((Widget)fw);
604     }
605     else
606 	ret_val = False;
607 
608     fw->form.needs_relayout = False;
609 
610     return (ret_val);
611 }
612 
613 /*
614  * Function:
615  *	ResizeChildren
616  *
617  * Parameters:
618  *	w - form widget
619  *
620  * Description:
621  *	Resizes all children to new_x and new_y.
622  */
623 static void
ResizeChildren(Widget w)624 ResizeChildren(Widget w)
625 {
626     FormWidget fw = (FormWidget)w;
627     int num_children = (int)fw->composite.num_children;
628     WidgetList children = fw->composite.children;
629     Widget *childP;
630 
631     for (childP = children; childP - children < num_children; childP++) {
632 	FormConstraints form;
633 	Position x, y;
634 
635 	if (!XtIsManaged(*childP))
636 	    continue;
637 
638 	form = (FormConstraints)(*childP)->core.constraints;
639 
640 	if (fw->form.old_width && fw->form.old_height) {
641 	    x = (Position)TransformCoord(form->form.new_x, fw->form.old_width,
642 			       XtWidth(fw), form->form.left);
643 	    y = (Position)TransformCoord(form->form.new_y, fw->form.old_height,
644 			       XtHeight(fw), form->form.top);
645 	}
646 	else {
647 	    x = form->form.new_x;
648 	    y = form->form.new_y;
649 	}
650 
651 	if (fw->form.no_refigure) {
652 	   /*
653 	    * I am changing the widget wrapper w/o modifing the window.  This is
654 	    * risky, but I can get away with it since I am the parent of this
655 	    * widget, and he must ask me for any geometry changes
656 	    *
657 	    * The window will be updated when no_refigure is set back to False
658 	    */
659 	    XtX(*childP) = x;
660 	    XtY(*childP) = y;
661 	}
662 	else
663 	    XtMoveWidget(*childP, x, y);
664     }
665 }
666 
667 static void
LayoutChild(Widget w)668 LayoutChild(Widget w)
669 {
670     FormConstraints form = (FormConstraints)w->core.constraints;
671     Widget ref;
672 
673     switch (form->form.layout_state) {
674 	case LayoutPending:
675 	    form->form.layout_state = LayoutInProgress;
676 	    break;
677 	case LayoutDone:
678 	    return;
679 	case LayoutInProgress: {
680 	    String subs[2];
681 	    Cardinal num_subs = 2;
682 	    subs[0] = w->core.name;
683 	    subs[1] = w->core.parent->core.name;
684 
685 	    XtAppWarningMsg(XtWidgetToApplicationContext(w),
686 			    "constraintLoop", "xawFormLayout", "XawToolkitError",
687 			    "constraint loop detected while laying out "
688 			    "child '%s' in FormWidget '%s'",
689 			    subs, &num_subs);
690 	}   return;
691     }
692 
693     form->form.new_x = (Position)form->form.dx;
694     form->form.new_y = (Position)form->form.dy;
695     if ((ref = form->form.horiz_base) != NULL) {
696 	FormConstraints ref_form = (FormConstraints)ref->core.constraints;
697 
698 	LayoutChild(ref);
699 	form->form.new_x = (Position)(form->form.new_x
700 				      + (ref_form->form.new_x
701 				      + XtWidth(ref)
702 				      + (XtBorderWidth(ref) << 1)));
703     }
704     if ((ref = form->form.vert_base) != NULL) {
705 	FormConstraints ref_form = (FormConstraints)ref->core.constraints;
706 
707 	LayoutChild(ref);
708 	form->form.new_y = (Position)(form->form.new_y
709 				      + (ref_form->form.new_y
710 				      + XtHeight(ref)
711 				      + (XtBorderWidth(ref) << 1)));
712     }
713 
714     form->form.layout_state = LayoutDone;
715 }
716 
717 static int
TransformCoord(int loc,unsigned int old,unsigned int cnew,XtEdgeType type)718 TransformCoord(int loc, unsigned int old, unsigned int cnew, XtEdgeType type)
719 {
720     if (type == XtRubber) {
721 	if ((int)old > 0)
722 	    loc = (int)(loc * ((double)cnew / (double)old));
723     }
724     else if (type == XtChainBottom || type == XtChainRight)
725 	loc += (int)cnew - (int)old;
726 
727     return (loc);
728 }
729 
730 static void
XawFormResize(Widget w)731 XawFormResize(Widget w)
732 {
733     FormWidget fw = (FormWidget)w;
734     WidgetList children = fw->composite.children;
735     int num_children = (int)fw->composite.num_children;
736     Widget *childP;
737     int x, y;
738     int width, height;
739     Boolean unmap = XtIsRealized(w) && w->core.mapped_when_managed &&
740 		    XtIsManaged(w);
741 
742     if (unmap)
743 	XtUnmapWidget(w);
744 
745     if (!fw->form.resize_is_no_op)
746 	for (childP = children; childP - children < num_children; childP++) {
747 	    FormConstraints form = (FormConstraints)(*childP)->core.constraints;
748 
749 	    if (!XtIsManaged(*childP))
750 		continue;
751 
752 #ifndef OLDXAW
753 	    x = TransformCoord(form->form.virtual_x, fw->form.old_width,
754 			      XtWidth(fw), form->form.left);
755 	    y = TransformCoord(form->form.virtual_y, fw->form.old_height,
756 			       XtHeight(fw), form->form.top);
757 	    width = TransformCoord(form->form.virtual_x +
758 				   form->form.virtual_width +
759 				   (XtBorderWidth(*childP) << 1),
760 				   fw->form.old_width, XtWidth(fw),
761 				   form->form.right) -
762 				   (x + (XtBorderWidth(*childP) << 1));
763 	    height = TransformCoord(form->form.virtual_y +
764 				    form->form.virtual_height +
765 				    (XtBorderWidth(*childP) << 1),
766 				    fw->form.old_height, XtHeight(fw),
767 				    form->form.bottom) -
768 				    (y + (XtBorderWidth(*childP) << 1));
769 #else
770 	    x = TransformCoord(XtX(*childP), fw->form.old_width,
771 			      XtWidth(fw), form->form.left);
772 	    y = TransformCoord(XtY(*childP), fw->form.old_height,
773 			       XtHeight(fw), form->form.top);
774 	    width = TransformCoord(XtX(*childP) + form->form.virtual_width +
775 				   (XtBorderWidth(*childP) << 1),
776 				   fw->form.old_width, XtWidth(fw),
777 				   form->form.right) -
778 				   (x + (XtBorderWidth(*childP) << 1));
779 	    height = TransformCoord(XtY(*childP) + form->form.virtual_height +
780 				    (XtBorderWidth(*childP) << 1),
781 				    fw->form.old_height, XtHeight(fw),
782 				    form->form.bottom) -
783 				    (y + (XtBorderWidth(*childP) << 1));
784 	    form->form.virtual_width = width;
785 	    form->form.virtual_height = height;
786 #endif
787 
788 	    width = width < 1 ? 1 : width;
789 	    height = height < 1 ? 1 : height;
790 
791 	    XtConfigureWidget(*childP,
792 			      (Position)x, (Position)y,
793 			      (Dimension)width, (Dimension)height,
794 			      XtBorderWidth(*childP));
795 	}
796 
797     if (unmap)
798 	XtMapWidget(w);
799 
800 #ifdef OLDXAW
801     fw->form.old_width = XtWidth(fw);
802     fw->form.old_height = XtHeight(fw);
803 #endif
804 }
805 
806 /*ARGSUSED*/
807 static XtGeometryResult
XawFormGeometryManager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply _X_UNUSED)808 XawFormGeometryManager(Widget w, XtWidgetGeometry *request,
809 		       XtWidgetGeometry *reply _X_UNUSED)
810 {
811     Dimension old_width, old_height;
812     FormWidget fw = (FormWidget)XtParent(w);
813     FormConstraints form = (FormConstraints)w->core.constraints;
814     XtWidgetGeometry allowed;
815     XtGeometryResult ret_val;
816 
817     if ((request->request_mode & (unsigned)~(XtCWQueryOnly | CWWidth | CWHeight))
818 	|| !form->form.allow_resize) {
819 	/* If GeometryManager is invoked during a SetValues call on a child
820 	 * then it is necessary to compute a new layout if ConstraintSetValues
821 	 * allowed any constraint changes
822 	 */
823 	if (fw->form.needs_relayout)
824 	    (*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
825 		(fw, 0, 0, True);
826 	return (XtGeometryNo);
827     }
828 
829     if (request->request_mode & CWWidth)
830 	allowed.width = request->width;
831     else
832 	allowed.width = XtWidth(w);
833 
834     if (request->request_mode & CWHeight)
835 	allowed.height = request->height;
836     else
837 	allowed.height = XtHeight(w);
838 
839     if (allowed.width == XtWidth(w) && allowed.height == XtHeight(w)) {
840 	/* If GeometryManager is invoked during a SetValues call on a child
841 	 * then it is necessary to compute a new layout if ConstraintSetValues
842 	 * allowed any constraint changes
843 	 */
844 	if (fw->form.needs_relayout)
845 	    (*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
846 		(fw, 0, 0, True);
847 	return (XtGeometryNo);
848     }
849 
850     /*
851      * Remember the old size, and then set the size to the requested size
852      */
853     old_width = XtWidth(w);
854     old_height = XtHeight(w);
855     XtWidth(w) = allowed.width;
856     XtHeight(w) = allowed.height;
857 
858     if (request->request_mode & XtCWQueryOnly) {
859 	Boolean always_resize_children;
860 	Dimension ret_width, ret_height;
861 
862 	fw->form.resize_in_layout = False;
863 
864 	(*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
865 	    (fw, XtWidth(w), XtHeight(w), False);
866 
867 	/*
868 	 * Reset the size of this child back to what it used to be
869 	 */
870 	XtWidth(w) = old_width;
871 	XtHeight(w) = old_height;
872 
873 	fw->form.resize_in_layout = True;
874 
875 	always_resize_children = (Boolean)ChangeFormGeometry(w, True,
876 				   fw->form.preferred_width,
877 				   fw->form.preferred_height,
878 				   &ret_width, &ret_height);
879 
880 	if (always_resize_children
881 	    || (ret_width >= fw->form.preferred_width
882 		&& ret_height >= fw->form.preferred_height))
883 	    ret_val = XtGeometryYes;
884 	else
885 	    ret_val = XtGeometryNo;
886     }
887     else {
888 	if ((*((FormWidgetClass)fw->core.widget_class)->form_class.layout)
889 		(fw, XtWidth(w), XtHeight(w), False)) {
890 	    Widget *childP;
891 	    int num_children = (int)fw->composite.num_children;
892 	    WidgetList children = fw->composite.children;
893 
894 	    if (fw->form.no_refigure) {
895 		/*
896 		 * I am changing the widget wrapper w/o modifing the window.
897 		 * This is risky, but I can get away with it since I am the
898 		 * parent of this widget, and he must ask me for any geometry
899 		 * changes
900 		 *
901 		 * The window will be updated when no_refigure is set back
902 		 * to False
903 		 */
904 		form->form.deferred_resize = True;
905 		ret_val = XtGeometryDone;
906 	    }
907 	    else
908 		ret_val = XtGeometryYes;
909 
910 	    /*
911 	     * Resets everything.
912 	     */
913 	    fw->form.old_width = XtWidth(fw);
914 	    fw->form.old_height = XtHeight(fw);
915 	    for (childP = children; childP - children < num_children; childP++) {
916 		Widget nw = *childP;
917 
918 		if (XtIsManaged(nw)) {
919 		    FormConstraints nform = (FormConstraints)nw->core.constraints;
920 
921 #ifndef OLDXAW
922 		    nform->form.virtual_x = XtX(nw);
923 		    nform->form.virtual_y = XtY(nw);
924 #endif
925 		    nform->form.virtual_width = (short)XtWidth(nw);
926 		    nform->form.virtual_height = (short)XtHeight(nw);
927 		}
928 	    }
929 	}
930 	else {
931 	    XtWidth(w) = old_width;
932 	    XtHeight(w) = old_height;
933 	    ret_val = XtGeometryNo;
934 	}
935     }
936 
937     return (ret_val);
938 }
939 
940 /*ARGSUSED*/
941 static Boolean
XawFormSetValues(Widget current _X_UNUSED,Widget request _X_UNUSED,Widget cnew _X_UNUSED,ArgList args _X_UNUSED,Cardinal * num_args _X_UNUSED)942 XawFormSetValues(Widget current _X_UNUSED, Widget request _X_UNUSED, Widget cnew _X_UNUSED,
943 		 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
944 {
945 #ifndef OLDXAW
946     FormWidget f_old = (FormWidget)current;
947     FormWidget f_new = (FormWidget)cnew;
948 
949     if (f_old->core.background_pixmap != f_new->core.background_pixmap) {
950 	XawPixmap *opix, *npix;
951 
952 	opix = XawPixmapFromXPixmap(f_old->core.background_pixmap, XtScreen(f_old),
953 				    f_old->core.colormap, (int)f_old->core.depth);
954 	npix = XawPixmapFromXPixmap(f_new->core.background_pixmap, XtScreen(f_new),
955 				    f_new->core.colormap, (int)f_new->core.depth);
956 	if ((npix && npix->mask) || (opix && opix->mask))
957 	    XawReshapeWidget(cnew, npix);
958     }
959 #endif /* OLDXAW */
960 
961     return (False);
962 }
963 
964 /* ARGSUSED */
965 static void
XawFormConstraintInitialize(Widget request _X_UNUSED,Widget cnew,ArgList args _X_UNUSED,Cardinal * num_args _X_UNUSED)966 XawFormConstraintInitialize(Widget request _X_UNUSED, Widget cnew,
967 			    ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
968 {
969     FormConstraints form = (FormConstraints)cnew->core.constraints;
970     FormWidget fw = (FormWidget)cnew->core.parent;
971 
972 #ifndef OLDXAW
973     form->form.virtual_x = XtX(cnew);
974     form->form.virtual_y = XtY(cnew);
975 #endif
976     form->form.virtual_width = (short)XtWidth(cnew);
977     form->form.virtual_height = (short)XtHeight(cnew);
978 
979     if (form->form.dx == default_value)
980 	form->form.dx = fw->form.default_spacing;
981 
982     if (form->form.dy == default_value)
983 	form->form.dy = fw->form.default_spacing;
984 
985     form->form.deferred_resize = False;
986 }
987 
988 /*ARGSUSED*/
989 static Boolean
XawFormConstraintSetValues(Widget current,Widget request _X_UNUSED,Widget cnew,ArgList args _X_UNUSED,Cardinal * num_args _X_UNUSED)990 XawFormConstraintSetValues(Widget current, Widget request _X_UNUSED, Widget cnew,
991 			   ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
992 {
993     FormConstraints cfc = (FormConstraints)current->core.constraints;
994     FormConstraints nfc = (FormConstraints)cnew->core.constraints;
995 
996     if (cfc->form.top != nfc->form.top || cfc->form.bottom != nfc->form.bottom
997 	|| cfc->form.left != nfc->form.left || cfc->form.right != nfc->form.right
998 	|| cfc->form.dx != nfc->form.dx || cfc->form.dy != nfc->form.dy
999 	|| cfc->form.horiz_base != nfc->form.horiz_base
1000 	|| cfc->form.vert_base != nfc->form.vert_base) {
1001 	FormWidget fp = (FormWidget)XtParent(cnew);
1002 
1003 	/* If there are no subclass ConstraintSetValues procedures remaining
1004 	 * to be invoked, and if there is no geometry request about to be
1005 	 * made, then invoke the new layout now; else defer it
1006 	 */
1007 	if (XtClass(XtParent(cnew)) == formWidgetClass
1008 	    && XtX(current) == XtX(cnew)
1009 	    && XtY(current) == XtY(cnew)
1010 	    && XtWidth(current) == XtWidth(cnew)
1011 	    && XtHeight(current) == XtHeight(cnew)
1012 	    && XtBorderWidth(current) == XtBorderWidth(cnew))
1013 	    Layout(fp, 0, 0, True);
1014 	else
1015 	    fp->form.needs_relayout = True;
1016     }
1017 
1018     return (False);
1019 }
1020 
1021 static void
XawFormChangeManaged(Widget w)1022 XawFormChangeManaged(Widget w)
1023 {
1024     FormWidget fw = (FormWidget)w;
1025     FormConstraints form;
1026     WidgetList children, childP;
1027     int num_children = (int)fw->composite.num_children;
1028     Widget child;
1029 
1030     (*((FormWidgetClass)w->core.widget_class)->form_class.layout)
1031 	(fw, XtWidth(w), XtHeight(w), True);
1032 
1033     fw->form.old_width = XtWidth(w);
1034     fw->form.old_height = XtHeight(w);
1035     for (children = childP = fw->composite.children;
1036 	 childP - children < num_children;
1037 	 childP++) {
1038 	child = *childP;
1039 	if (!XtIsManaged(child))
1040 	    continue;
1041 	form = (FormConstraints)child->core.constraints;
1042 #ifndef OLDXAW
1043 	form->form.virtual_x = XtX(child);
1044 	form->form.virtual_y = XtY(child);
1045 #endif
1046 	form->form.virtual_width = (short)XtWidth(child);
1047 	form->form.virtual_height = (short)XtHeight(child);
1048     }
1049 }
1050 
1051 static XtGeometryResult
XawFormQueryGeometry(Widget widget,XtWidgetGeometry * request,XtWidgetGeometry * reply)1052 XawFormQueryGeometry(Widget widget, XtWidgetGeometry *request,
1053 		     XtWidgetGeometry *reply)
1054 {
1055     FormWidget w = (FormWidget)widget;
1056 
1057     reply->width = w->form.preferred_width;
1058     reply->height = w->form.preferred_height;
1059     reply->request_mode = CWWidth | CWHeight;
1060 
1061     if ((request->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight)
1062 	&& request->width == reply->width
1063 	&& request->height == reply->height)
1064 	return (XtGeometryYes);
1065     else if (reply->width == XtWidth(w) && reply->height == XtHeight(w))
1066 	return (XtGeometryNo);
1067 
1068     return (XtGeometryAlmost);
1069 }
1070 
1071 /*
1072  * Public routines
1073  */
1074 /*
1075  * Set or reset figuring (ignored if not realized)
1076  */
1077 void
XawFormDoLayout(Widget w,Bool force)1078 XawFormDoLayout(Widget w,
1079 #if NeedWidePrototypes
1080 		Bool force
1081 #else
1082 		Boolean force
1083 #endif
1084 )
1085 {
1086     Widget *childP;
1087     FormWidget fw = (FormWidget)w;
1088     int num_children = (int)fw->composite.num_children;
1089     WidgetList children = fw->composite.children;
1090 
1091     if ((fw->form.no_refigure = !force) == True || !XtIsRealized(w))
1092 	return;
1093 
1094     for (childP = children; childP - children < num_children; childP++) {
1095 	Widget nw = *childP;
1096 
1097 	if (XtIsManaged(nw)) {
1098 	    FormConstraints form = (FormConstraints)nw->core.constraints;
1099 
1100 	    /*
1101 	     * Xt Configure widget is too smart, and optimizes out
1102 	     * my changes
1103 	     */
1104 	    XMoveResizeWindow(XtDisplay(nw), XtWindow(nw),
1105 			      XtX(nw), XtY(nw), XtWidth(nw), XtHeight(nw));
1106 
1107 	    if (form)
1108 	      if (form->form.deferred_resize &&
1109 		XtClass(nw)->core_class.resize != NULL) {
1110 		(*(XtClass(nw)->core_class.resize))(nw);
1111 		form->form.deferred_resize = False;
1112 	      }
1113 	}
1114     }
1115 }
1116