1 /*
2  * Motif
3  *
4  * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22 */
23 #ifdef REV_INFO
24 #ifndef lint
25 static char rcsid[] = "$XConsortium: GeoUtils.c /main/13 1996/08/15 17:11:25 pascale $"
26 #endif
27 #endif
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 
33 
34 #ifndef X_NOT_STDC_ENV
35 #include <stdlib.h>
36 #endif
37 #include "XmI.h"
38 #include "GeoUtilsI.h"
39 #include "GMUtilsI.h"
40 
41 
42 /********    Static Function Declarations    ********/
43 
44 static XtGeometryResult QueryAnyPolicy(
45                         XmGeoMatrix geoSpec,
46                         XtWidgetGeometry *parentRequestRtn) ;
47 static XtGeometryResult QueryGrowPolicy(
48                         XmGeoMatrix geoSpec,
49                         XtWidgetGeometry *parentRequestRtn) ;
50 static XtGeometryResult QueryNonePolicy(
51                         XmGeoMatrix geoSpec,
52                         XtWidgetGeometry *parentRequestRtn) ;
53 static Dimension _XmGeoStretchVertical(
54                         XmGeoMatrix geoSpec,
55 #if NeedWidePrototypes
56                         int actualH,
57                         int desiredH) ;
58 #else
59                         Dimension actualH,
60                         Dimension desiredH) ;
61 #endif /* NeedWidePrototypes */
62 static Dimension _XmGeoFillVertical(
63                         XmGeoMatrix geoSpec,
64 #if NeedWidePrototypes
65                         int actualH,
66                         int desiredH) ;
67 #else
68                         Dimension actualH,
69                         Dimension desiredH) ;
70 #endif /* NeedWidePrototypes */
71 static void _XmGeoCalcFill(
72 #if NeedWidePrototypes
73                         int fillSpace,
74                         int margin,
75 #else
76                         Dimension fillSpace,
77                         Dimension margin,
78 #endif /* NeedWidePrototypes */
79                         unsigned int numBoxes,
80 #if NeedWidePrototypes
81                         int endSpec,
82                         int betweenSpec,
83 #else
84                         Dimension endSpec,
85                         Dimension betweenSpec,
86 #endif /* NeedWidePrototypes */
87                         Dimension *pEndSpace,
88                         Dimension *pBetweenSpace) ;
89 static int boxWidthCompare(
90                         XmConst void *boxPtr1,
91                         XmConst void *boxPtr2) ;
92 static void FitBoxesAveraging(
93                         XmKidGeometry rowPtr,
94                         unsigned int numBoxes,
95 #if NeedWidePrototypes
96                         int boxWidth,
97 #else
98                         Dimension boxWidth,
99 #endif /* NeedWidePrototypes */
100                         int amtOffset) ;
101 static void FitBoxesProportional(
102                         XmKidGeometry rowPtr,
103                         unsigned int numBoxes,
104 #if NeedWidePrototypes
105                         int boxWidth,
106 #else
107                         Dimension boxWidth,
108 #endif /* NeedWidePrototypes */
109                         int amtOffset) ;
110 static void SegmentFill(
111                         XmKidGeometry rowBoxes,
112                         unsigned int numBoxes,
113                         XmGeoRowLayout layoutPtr,
114 #if NeedWidePrototypes
115                         int x,
116                         int width,
117                         int marginW,
118                         int endX,
119                         int maxX,
120                         int endSpace,
121                         int betweenSpace) ;
122 #else
123                         Position x,
124                         Dimension width,
125                         Dimension marginW,
126                         Position endX,
127                         Position maxX,
128                         Dimension endSpace,
129                         Dimension betweenSpace) ;
130 #endif /* NeedWidePrototypes */
131 static Position _XmGeoLayoutWrap(
132                         XmKidGeometry rowPtr,
133                         XmGeoRowLayout layoutPtr,
134 #if NeedWidePrototypes
135                         int x,
136                         int y,
137                         int endSpace,
138                         int betweenSpace,
139                         int maxX,
140                         int width,
141                         int marginW) ;
142 #else
143                         Position x,
144                         Position y,
145                         Dimension endSpace,
146                         Dimension betweenSpace,
147                         Position maxX,
148                         Dimension width,
149                         Dimension marginW) ;
150 #endif /* NeedWidePrototypes */
151 static Position _XmGeoLayoutSimple(
152                         XmKidGeometry rowPtr,
153                         XmGeoRowLayout layoutPtr,
154 #if NeedWidePrototypes
155                         int x,
156                         int y,
157                         int maxX,
158                         int endSpace,
159                         int betweenSpace) ;
160 #else
161                         Position x,
162                         Position y,
163                         Position maxX,
164                         Dimension endSpace,
165                         Dimension betweenSpace) ;
166 #endif /* NeedWidePrototypes */
167 static Position _XmGeoArrangeList(
168                         XmKidGeometry rowBoxes,
169                         XmGeoRowLayout layoutPtr,
170 #if NeedWidePrototypes
171                         int x,
172                         int y,
173                         int width,
174                         int marginW,
175                         int marginH) ;
176 #else
177                         Position x,
178                         Position y,
179                         Dimension width,
180                         Dimension marginW,
181                         Dimension marginH) ;
182 #endif /* NeedWidePrototypes */
183 
184 /********    End Static Function Declarations    ********/
185 
186 /****************************************************************/
187 
188 
189 #ifdef DEBUG_GEOUTILS
190 
191 void PrintBox( char * hdr, XmKidGeometry box) ;
192 void PrintList( char * hdr, XmKidGeometry listPtr) ;
193 void PrintMatrix( char * hdr, XmGeoMatrix spec) ;
194 
195 #endif /* DEBUG_GEOUTILS */
196 
197 
198 /****************************************************************/
199 XtGeometryResult
_XmHandleQueryGeometry(Widget widget,XtWidgetGeometry * intended,XtWidgetGeometry * desired,unsigned int resize_policy,XmGeoCreateProc createMatrix)200 _XmHandleQueryGeometry(
201         Widget widget,
202         XtWidgetGeometry *intended,
203         XtWidgetGeometry *desired,
204 #if NeedWidePrototypes
205         unsigned int resize_policy,
206 #else
207         unsigned char resize_policy,
208 #endif /* NeedWidePrototypes */
209         XmGeoCreateProc createMatrix)
210 {
211     Dimension       width = 0 ;
212     Dimension       height = 0 ;
213     XmGeoMatrix     geoSpec ;
214 
215     /* first determine what is the desired size, using the resize_policy. */
216     if (resize_policy == XmRESIZE_NONE) {
217 	desired->width = XtWidth(widget) ;
218 	desired->height = XtHeight(widget) ;
219     } else {
220 	if (GMode( intended) & CWWidth) width = intended->width;
221 	if (GMode( intended) & CWHeight) height = intended->height;
222 
223 	geoSpec = (*createMatrix)( widget, NULL, NULL) ;
224 	_XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ;
225 	_XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0,
226 			   &width, &height) ;
227 	_XmGeoMatrixFree( geoSpec) ;
228 	if ((resize_policy == XmRESIZE_GROW) &&
229 	    ((width < XtWidth(widget)) ||
230 	     (height < XtHeight(widget)))) {
231 	    desired->width = XtWidth(widget) ;
232 	    desired->height = XtHeight(widget) ;
233 	} else {
234 	    desired->width = width ;
235 	    desired->height = height ;
236 	}
237     }
238 
239     /* deal with user initial size setting */
240     if (!XtIsRealized(widget))  {
241 	if (XtWidth(widget) != 0) desired->width = XtWidth(widget) ;
242 	if (XtHeight(widget) != 0) desired->height = XtHeight(widget) ;
243     }
244 
245     return XmeReplyToQueryGeometry(widget, intended, desired) ;
246 }
247 
248 
249 /****************************************************************/
250 XtGeometryResult
_XmHandleGeometryManager(Widget wid,Widget instigator,XtWidgetGeometry * desired,XtWidgetGeometry * allowed,unsigned int policy,XmGeoMatrix * cachePtr,XmGeoCreateProc createMatrix)251 _XmHandleGeometryManager(
252         Widget wid,
253         Widget instigator,
254         XtWidgetGeometry *desired,
255         XtWidgetGeometry *allowed,
256 #if NeedWidePrototypes
257         unsigned int policy,
258 #else
259         unsigned char policy,
260 #endif /* NeedWidePrototypes */
261         XmGeoMatrix *cachePtr,
262         XmGeoCreateProc createMatrix)
263 {
264             XmGeoMatrix     geoSpec ;
265             XtWidgetGeometry parentRequest ;
266             XtGeometryResult queryResult ;
267             XtGeometryResult result ;
268 /****************/
269 
270     if(    !cachePtr    )
271     {
272         /* Almost replies are not entertained unless caching is supported.
273         */
274         allowed = NULL ;
275         }
276     else
277     {   geoSpec = *cachePtr ;
278 
279         if(    geoSpec    )
280         {
281             if(    (geoSpec->composite == wid)
282                 && (geoSpec->instigator == instigator)
283                 && _XmGeometryEqual( instigator, geoSpec->in_layout, desired)    )
284             {
285                 /* This is a successive geometry request which matches the
286                 *   cached geometry record.
287                 */
288                 if(    GMode( desired) & XtCWQueryOnly    )
289                 {   return( XtGeometryYes) ;
290                     }
291                 else
292                 {   /* If we get here, we should have already verified that
293                     *   the current layout is acceptable to the parent, so
294                     *   we will ignore the result of the request.
295                     */
296                     if(    geoSpec->parent_request.request_mode    )
297                     {
298                         geoSpec->parent_request.request_mode &= ~XtCWQueryOnly ;
299 
300                         XtMakeGeometryRequest( wid, &geoSpec->parent_request,
301                                                                             NULL) ;
302                         }
303                     _XmGeoMatrixSet( geoSpec) ;
304 
305                     _XmGeoMatrixFree( geoSpec) ;
306                     *cachePtr = NULL ;
307 
308                     return( XtGeometryYes) ;
309                     }
310                 }
311             else
312             {   /* Cached geometry is different than current request, so clear
313                 *   existing cache record and allow request to be processed.
314                 */
315                 _XmGeoMatrixFree( geoSpec) ;
316                 *cachePtr = NULL ;
317                 }
318             }
319         }
320     /*	Get box list and arrange boxes according to policy.
321     */
322     geoSpec = (*createMatrix)( wid, instigator, desired) ;
323 
324     if(    geoSpec->no_geo_request
325         && (*geoSpec->no_geo_request)( geoSpec)    )
326     {
327         _XmGeoMatrixFree( geoSpec) ;
328         return( XtGeometryNo) ;
329         }
330 
331     /* The following Query routines only respond with XtGeometryYes or
332     *    XtGeometryNo.  All requests made to the parent are strictly
333     *    queries.
334     *  A return value (from these routines!) of XtGeometryNo means that
335     *    the composite widget would need to change size in order to
336     *    entertain the child's request, and that the parent said "no"
337     *    to the request.  A XtGeometryNo leaves no alternatives to the
338     *    child's geometry request.
339     *  A return value of XtGeometryYes means that either the composite
340     *    widget does not need to change size to entertain the child's
341     *    request, or that negotiation with the parent yielded a viable
342     *    geometry layout.  If the composite widget does not need to
343     *    change size, then request_mode field of the returned geometry
344     *    structure will contain zero.  Otherwise, the returned geometry
345     *    structure will contain a request which is guaranteed to be
346     *    accepted by a subsequent request to the parent.
347     *  A return value of XtGeometryYes always loads the return geometry
348     *    structure with valid data.
349     */
350     switch(    policy    )
351     {
352         case XmRESIZE_GROW:
353         {   queryResult = QueryGrowPolicy( geoSpec, &parentRequest) ;
354 	    break;
355             }
356 	case XmRESIZE_NONE:
357         {   queryResult = QueryNonePolicy( geoSpec, &parentRequest) ;
358             break ;
359             }
360 	case XmRESIZE_ANY:
361         default:
362         {   queryResult = QueryAnyPolicy( geoSpec, &parentRequest) ;
363             break ;
364             }
365         }
366     result = XtGeometryNo ; /* Setup default response. */
367 
368     /* If parent replies XtGeometryYes, then build appropriate reply for
369     *   instigator.  Otherwise, it is not reasonable to try to find a child
370     *   size which would result in an acceptable overall size, so just say no.
371     */
372     if(    queryResult == XtGeometryYes    )
373     {
374         if(    _XmGeoReplyYes( instigator, desired, geoSpec->in_layout)    )
375         {
376             /* Reply Yes since desired geometry is same as the
377             *   instigator geometry in this layout.
378             */
379             if(    GMode( desired) & XtCWQueryOnly    )
380             {
381                 geoSpec->parent_request = parentRequest ;
382                 result = XtGeometryYes ;
383                 }
384             else
385             {   /* Don't need almost reply and this is not a query, so do it!
386                 */
387                 if(    parentRequest.request_mode    )
388                 {
389                     /* The geometry request in parentRequest has already
390                     *   been tested by a query to the parent, so should
391                     *   always be honored.
392                     */
393                     parentRequest.request_mode &= ~XtCWQueryOnly ;
394 
395                     XtMakeGeometryRequest( wid, &parentRequest, NULL) ;
396                     }
397                 _XmGeoMatrixSet( geoSpec) ;
398 
399                 result = XtGeometryYes ;
400                 }
401             }
402         else
403         {   /* If allowed and not an exception then reply Almost, since
404             *   desired geometry is different than geometry in this layout.
405             */
406             if(    allowed
407                 && (    !geoSpec->almost_except
408                      || !(*(geoSpec->almost_except))(geoSpec))    )
409             {
410                 geoSpec->parent_request = parentRequest ;
411                 result = XtGeometryAlmost ;
412                 }
413             }
414         }
415     switch(    result    )
416     {
417         case XtGeometryAlmost:
418         {
419             /* Cache "almost" replies.  Variables cachePtr and allowed are
420             *   guaranteed to be non-null since almost replies are prevented
421             *   if either is null.
422             */
423             if(geoSpec->in_layout) {
424 		*cachePtr = geoSpec ;
425 		*allowed = *(geoSpec->in_layout) ;
426             } else /* For fixing OSF CR 5956 */ {
427 		allowed = NULL ;
428 		*cachePtr = NULL ;
429 		result = XtGeometryNo ;
430 	    }
431             break ;
432 	}
433         case XtGeometryYes:
434         {
435             /* This must be a query-only request, or the response would
436             *   be XtGeometryYes.  Cache this reply if caching is
437             *   supported.  Otherwise, drop through and free geoSpec.
438             */
439             if(    cachePtr    )
440             {   *cachePtr = geoSpec ;
441                 break ;
442                 }
443             }
444         default:
445         {   _XmGeoMatrixFree( geoSpec) ;
446             break ;
447             }
448         }
449     return( result) ;
450     }
451 
452 /****************************************************************
453  * Handle geometry request for XmRESIZE_ANY resize policy.
454  * Accept request allowed by parent.
455  * Reject request to change both width and height if both
456  *   are disallowed by parent, but return almost if one is
457  *   allowed.
458  ****************/
459 static XtGeometryResult
QueryAnyPolicy(XmGeoMatrix geoSpec,XtWidgetGeometry * parentRequestRtn)460 QueryAnyPolicy(
461         XmGeoMatrix geoSpec,
462         XtWidgetGeometry *parentRequestRtn )
463 {
464             Widget          wid ;
465             Dimension       layoutW ;
466             Dimension       layoutH ;
467             XtWidgetGeometry parentResponse ;
468             XtGeometryResult queryResult ;
469             Dimension       almostW ;
470             Dimension       almostH ;
471 /****************/
472 
473     wid = geoSpec->composite ;
474 
475     _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ;
476 
477     layoutW = 0 ;
478     layoutH = 0 ;
479     _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &layoutW,
480                                                                     &layoutH) ;
481     /*	Load request.
482     */
483     parentRequestRtn->request_mode = CWWidth | CWHeight ;
484     parentRequestRtn->width = layoutW ;
485     parentRequestRtn->height = layoutH ;
486 
487     /*	Query parent only if necessary.
488     */
489     if(    (layoutW == XtWidth( wid))
490         && (layoutH == XtHeight( wid))    )
491     {
492         parentRequestRtn->request_mode = 0 ;
493         queryResult = XtGeometryYes ;
494         }
495     else
496     {   parentRequestRtn->request_mode |= XtCWQueryOnly ;
497 
498         queryResult = XtMakeGeometryRequest( wid, parentRequestRtn,
499                                                              &parentResponse) ;
500         if(    queryResult == XtGeometryAlmost    )
501         {
502             if(    (parentResponse.request_mode & (CWWidth | CWHeight))
503                                                    != (CWWidth | CWHeight)    )
504             {   queryResult = XtGeometryNo ;
505                 }
506             else
507             {   /* The protocol guarantees an XtGeometryYes reply for
508                 *   for an immediately subsequent request which is
509                 *   identical to the XtGeometryAlmost reply.
510                 */
511                 *parentRequestRtn = parentResponse ;
512                 queryResult = XtGeometryYes ;
513 
514                 almostW = parentResponse.width ;
515                 almostH = parentResponse.height ;
516 
517                 if(    (almostW != layoutW)  ||  (almostH != layoutH)    )
518                 {
519                     /* Response to geometry request was different than
520                     *   requested geometry in fields that we care about.
521                     *   So, try a new arrangement with the area being
522                     *   offered by the parent.
523                     */
524                     _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ;
525                     layoutW = almostW ;
526                     layoutH = almostH ;
527                     _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0,
528                                                           &layoutW, &layoutH) ;
529                     if(    (almostW != layoutW)  ||  (almostH != layoutH)    )
530                     {
531                         /* The children cannot be laid-out in the area offered
532                         *   by the parent, so parent result is No.
533                         */
534                         queryResult = XtGeometryNo ;
535                         }
536                     }
537                 }
538             }
539         }
540     return( queryResult) ;
541     }
542 
543 /****************************************************************
544  * Handle geometry request for XmRESIZE_GROW resize policy.
545  * Accept request which would increase or maintain current size.
546  * Reject request which would decrease both preferred width
547  *   and preferred height, but return almost if only one
548  *   would decrease.
549  ****************/
550 static XtGeometryResult
QueryGrowPolicy(XmGeoMatrix geoSpec,XtWidgetGeometry * parentRequestRtn)551 QueryGrowPolicy(
552         XmGeoMatrix geoSpec,
553         XtWidgetGeometry *parentRequestRtn )
554 {
555             Widget          wid ;
556             Dimension       layoutW ;
557             Dimension       layoutH ;
558             XtWidgetGeometry parentResponse ;
559             XtGeometryResult queryResult ;
560             Dimension       almostW ;
561             Dimension       almostH ;
562 /****************/
563 
564     wid = geoSpec->composite ;
565 
566     _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ;
567 
568     if(    geoSpec->instig_request.request_mode & CWWidth    )
569     {   layoutW = 0 ;               /* Let the layout routine choose a width.*/
570         }
571     else
572     {   layoutW = XtWidth( wid) ;   /* All changes will be reflected in      */
573         }                           /*   vertical dimension.                 */
574     layoutH = XtHeight( wid) ;  /* Layout routine will grow vert., if needed.*/
575 
576     _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &layoutW,
577                                                                     &layoutH) ;
578     if(    layoutW < XtWidth( wid)    )
579     {
580         /* Try again, this time passing the width to _XmGeoArrangeBoxes.
581         */
582         _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ;
583 
584         layoutW = XtWidth( wid) ;
585         layoutH = XtHeight( wid) ;
586         _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &layoutW,
587                                                                     &layoutH) ;
588         }
589     /*	Load request.
590     */
591     parentRequestRtn->request_mode = CWWidth | CWHeight ;
592     parentRequestRtn->width = layoutW ;
593     parentRequestRtn->height = layoutH ;
594 
595     /*	Query parent only if necessary.
596     */
597     if(    (layoutW == XtWidth( wid))
598         && (layoutH == XtHeight( wid))    )
599     {
600         parentRequestRtn->request_mode = 0 ;
601         queryResult = XtGeometryYes ;
602         }
603     else
604     {   parentRequestRtn->request_mode |= XtCWQueryOnly ;
605 
606         queryResult = XtMakeGeometryRequest( wid, parentRequestRtn,
607                                                              &parentResponse) ;
608         if(    queryResult == XtGeometryAlmost    )
609         {
610             if(    (parentResponse.request_mode & (CWWidth | CWHeight))
611                                                    != (CWWidth | CWHeight)    )
612             {   queryResult = XtGeometryNo ;
613                 }
614             else
615             {   /* The protocol guarantees an XtGeometryYes reply for
616                 *   for an immediately subsequent request which is
617                 *   identical to the XtGeometryAlmost reply.
618                 */
619                 *parentRequestRtn = parentResponse ;
620                 queryResult = XtGeometryYes ;
621 
622                 almostW = parentResponse.width ;
623                 almostH = parentResponse.height ;
624 
625                 if(    (almostW < XtWidth( wid))
626                     || (almostH < XtHeight( wid))    )
627                 {
628                     queryResult = XtGeometryNo ;
629                     }
630                 else
631                 {   if(    (almostW != layoutW)  ||  (almostH != layoutH)    )
632                     {
633                         /* Response to geometry request was different than
634                         *   requested geometry in fields that we care about.
635                         *   So, try a new arrangement with the area being
636                         *   offered by the parent.
637                         */
638                         _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ;
639                         layoutW = almostW ;
640                         layoutH = almostH ;
641                         _XmGeoArrangeBoxes( geoSpec, (Position) 0,
642                                             (Position) 0, &layoutW, &layoutH) ;
643                         if(    (almostW != layoutW)  ||  (almostH != layoutH) )
644                         {
645                             /* The children cannot be laid-out in the area
646                             *   offered by the parent, so parent result is No.
647                             */
648                             queryResult = XtGeometryNo ;
649                             }
650                         }
651                     }
652                 }
653             }
654         }
655     return( queryResult) ;
656     }
657 /****************************************************************
658  * Handle geometry request for XmRESIZE_NONE resize policy.
659  * Accept request which would not change preferred size and
660  *   allowed by parent.
661  * Reject request which would change both preferred width
662  *   and preferred height, but return almost if only one
663  *   would change and parent allows the other.
664  ****************/
665 static XtGeometryResult
QueryNonePolicy(XmGeoMatrix geoSpec,XtWidgetGeometry * parentRequestRtn)666 QueryNonePolicy(
667         XmGeoMatrix geoSpec,
668         XtWidgetGeometry *parentRequestRtn )
669 {
670             Widget          wid ;
671             Dimension       layoutW ;
672             Dimension       layoutH ;
673 /****************/
674 
675     wid = geoSpec->composite ;
676 
677     _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ;
678 
679     layoutW = XtWidth( wid) ;
680     layoutH = XtHeight( wid) ;
681     _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0,
682                                                           &layoutW, &layoutH) ;
683     parentRequestRtn->request_mode = 0 ;
684 
685     if(    (layoutW != XtWidth( wid))  ||  (layoutH != XtHeight( wid))    )
686     {   return( XtGeometryNo) ;
687         }
688 
689     return( XtGeometryYes) ;
690     }
691 
692 /****************************************************************/
693 void
_XmHandleSizeUpdate(Widget wid,unsigned int policy,XmGeoCreateProc createMatrix)694 _XmHandleSizeUpdate(
695         Widget wid,
696 #if NeedWidePrototypes
697         unsigned int policy,
698 #else
699         unsigned char policy,
700 #endif /* NeedWidePrototypes */
701         XmGeoCreateProc createMatrix)
702 {
703             XmGeoMatrix     geoSpec ;
704             Dimension       w ;
705             Dimension       h ;
706             Dimension       r_w ;
707             Dimension       r_h ;
708             XtGeometryResult parentResult = XtGeometryNo ;
709 /****************/
710 
711     geoSpec = (*createMatrix)( wid, NULL, NULL) ;
712 
713     _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ;
714 
715     switch(    policy    )
716     {
717         case XmRESIZE_NONE:
718         {
719             w = XtWidth( wid) ;
720             h = XtHeight( wid) ;
721             _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &w, &h) ;
722 
723             break ;
724             }
725         case XmRESIZE_GROW:
726         {
727             w = 0 ;
728             h = XtHeight( wid) ;
729             _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &w, &h) ;
730 
731             if(    w < XtWidth( wid)    )
732             {   w = XtWidth( wid) ;
733                 h = XtHeight( wid) ;
734                 _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0,
735                                                                       &w, &h) ;
736                 }
737             break ;
738             }
739         case XmRESIZE_ANY:
740         default:
741         {
742             w = 0 ;
743             h = 0 ;
744             _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &w, &h) ;
745 
746             break ;
747             }
748         }
749 
750     if(    ((w == XtWidth( wid))  &&  (h == XtHeight( wid)))    )
751     {   parentResult = XtGeometryYes ;
752         }
753     else
754     {   if(    policy != XmRESIZE_NONE    )
755         {
756             parentResult = XtMakeResizeRequest( wid, w, h, &r_w, &r_h) ;
757 
758             if(    parentResult == XtGeometryAlmost    )
759             {
760                 if(    (policy == XmRESIZE_GROW)
761                     && (   (r_w < XtWidth( wid))
762                         || (r_h < XtHeight( wid)))    )
763                 {
764                     parentResult = XtGeometryNo ;
765                     }
766                 else
767                 {   w = r_w ;
768                     h = r_h ;
769                     _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0,
770                                                                       &w, &h) ;
771                     if(    (w == r_w)  &&  (h == r_h)    )
772                     {   XtMakeResizeRequest( wid, w, h, NULL, NULL) ;
773                         }
774                     else
775                     {   parentResult = XtGeometryNo ;
776                         }
777                     }
778                 }
779             }
780         }
781     if(    parentResult != XtGeometryNo    )
782     {   _XmGeoMatrixSet( geoSpec) ;
783         }
784     _XmGeoMatrixFree( geoSpec) ;
785     return ;
786     }
787 
788 /****************************************************************
789  * This routine allocates and initializes the data structure used
790  *   to describe a matrix of geometry boxes.  Supplemental initialization
791  *   may be required for some of the fields of the data structure, if
792  *   the user uses these fields in its supplied co-routines.
793  * Rows of the GeoMatrix are lists of kid boxes which are terminated with
794  *   a NULL in the kid widget field of the box structure.  This routine
795  *   automatically allocates extra boxes to use to mark the end of each
796  *   row list.
797  * This routine initializes all fields to NULL.
798  * The pointer returned by this routine should be freed by the user
799  *   using the _XmGeoMatrixFree() routine.
800  ****************/
801 XmGeoMatrix
_XmGeoMatrixAlloc(unsigned int numRows,unsigned int numBoxes,unsigned int extSize)802 _XmGeoMatrixAlloc(
803         unsigned int numRows,       /* Number of rows of widgets to layout.*/
804         unsigned int numBoxes,      /* Total number of widgets of matrix.*/
805         unsigned int extSize )      /* Extension record size (bytes).*/
806 {
807             XmGeoMatrix     geoSpecPtr ;
808             unsigned int    matrixRecSize ;
809             unsigned int    layoutRecSize ;
810             unsigned int    kidGeoRecSize ;
811             unsigned int    layoutSize ;
812             unsigned int    boxesSize ;
813             unsigned int    totalSize ;
814 /****************/
815 
816     /* Get sizes of the various components of the GeoMatrix.  Round up to
817     *   prevent alignment problems.
818     */
819     matrixRecSize = sizeof( XmGeoMatrixRec) ;
820     if(    matrixRecSize & 0x03    )
821     {   matrixRecSize = (matrixRecSize + 4) & ~((unsigned int) 0x03) ;
822         }
823     layoutRecSize = sizeof( XmGeoRowLayoutRec) ;
824     if(    layoutRecSize & 0x03    )
825     {   layoutRecSize = (layoutRecSize + 4) & ~((unsigned int) 0x03) ;
826         }
827     kidGeoRecSize = sizeof( XmKidGeometryRec) ;
828     if(    kidGeoRecSize & 0x03    )
829     {   kidGeoRecSize = (kidGeoRecSize + 4) & ~((unsigned int) 0x03) ;
830         }
831     layoutSize = (numRows + 1) * layoutRecSize ;
832     /* Extra boxes are used to mark the end of each row.
833     */
834     boxesSize = (numBoxes + numRows) * kidGeoRecSize ;
835     totalSize = matrixRecSize + layoutSize + boxesSize + extSize ;
836 
837     geoSpecPtr = (XmGeoMatrix) XtCalloc( 1, totalSize) ;   /* Must be zeroed.*/
838 
839     /* Set locations of arrays of row layout, box, and extension records.
840     */
841     geoSpecPtr->layouts = (XmGeoMajorLayout) (((char *) geoSpecPtr)
842                                                              + matrixRecSize) ;
843     geoSpecPtr->boxes = (XmKidGeometry) (((char *) geoSpecPtr)
844                                                 + matrixRecSize + layoutSize) ;
845     if(    extSize    )
846     {   geoSpecPtr->extension = (XtPointer) (((char *) geoSpecPtr)
847                                     + matrixRecSize + layoutSize + boxesSize) ;
848         }
849     return( geoSpecPtr) ;
850     }
851 void
_XmGeoMatrixFree(XmGeoMatrix geo_spec)852 _XmGeoMatrixFree(
853 	XmGeoMatrix geo_spec)
854 {
855   if(    geo_spec->ext_destructor    )
856     {
857       (*(geo_spec->ext_destructor))( geo_spec->extension) ;
858     }
859   XtFree( (char *) geo_spec) ;
860 }
861 
862 /****************************************************************
863  * If the widget specified by the "kidWid" parameter is non-NULL and is managed,
864  *   its value is copied into the appropriate field of the kid geometry
865  *   structure provided by the "geo" parameter and TRUE is returned.
866  * Otherwise, nothing is done and FALSE is returned.
867  ****************/
868 Boolean
_XmGeoSetupKid(XmKidGeometry geo,Widget kidWid)869 _XmGeoSetupKid(
870         XmKidGeometry geo,          /* Must be non-NULL.*/
871         Widget kidWid )
872 {
873 /****************/
874     if(    !kidWid  ||  !XtIsManaged( kidWid)    )
875     {   return( FALSE) ;
876         }
877     /* The widget ID will be used for subsequent "get" operation.
878     */
879     geo->kid = (Widget) kidWid;
880 
881     /* Return TRUE so the user knows that the box record was filled with
882     *   a widget ID and can then increment the box pointer for the next
883     *   managed widget to be setup.
884     */
885     return( TRUE) ;
886     }
887 
888 /****************************************************************
889  * This routine goes through the widget matrix and retrieves the appropriate
890  *   values for the KidGeometry boxes.  Field values of the boxes may be
891  *   altered according to requirements specified in each row structure of
892  *   the geoSpec.
893  * If the widget id within the matrix matches the instigator field of the
894  *   geoSpec, then the value for the box is taken from the request field of
895  *   the geoSpec or the widget itself as appropriate.
896  ****************/
897 void
_XmGeoMatrixGet(XmGeoMatrix geoSpec,int geoType)898 _XmGeoMatrixGet(
899         XmGeoMatrix geoSpec,
900         int geoType )               /* XmGET_PREFERRED_SIZE or */
901 {
902     register XmKidGeometry   boxPtr ;
903             XmKidGeometry   rowPtr ;
904             XmGeoRowLayout  layoutPtr ;
905             XtWidgetGeometry * request ;
906             Widget          instigator ;
907 /****************/
908 
909     request = &geoSpec->instig_request ;
910     instigator = geoSpec->instigator ;
911     rowPtr = geoSpec->boxes ;
912     layoutPtr = &(geoSpec->layouts->row) ;
913 
914     while(    !(layoutPtr->end)    )
915     {
916         boxPtr = rowPtr ;
917         while(    boxPtr->kid    )
918         {
919             _XmGeoLoadValues( boxPtr->kid, geoType, instigator, request,
920                                                               &(boxPtr->box)) ;
921             if(    boxPtr->kid == instigator    )
922             {   geoSpec->in_layout = &(boxPtr->box) ;
923                 }
924             ++boxPtr ;
925             }
926         if(    layoutPtr->fix_up    )
927         {
928             (*(layoutPtr->fix_up))( geoSpec, geoType,
929 				        (XmGeoMajorLayout) layoutPtr, rowPtr) ;
930             }
931         rowPtr = boxPtr + 1 ;   /* Skip over NULL box marking the end of row.*/
932         ++layoutPtr ;           /* Go to next row layout record.*/
933         }
934 #ifdef DEBUG_GEOUTILS
935     PrintMatrix( "(get) ", geoSpec) ;
936 #endif
937     return ;
938     }
939 
940 /****************************************************************
941  * The XtConfigureWidget routine is called on all widgets of the geoSpec
942  *   matrix as needed (when the geometry values of the box have changed).
943  *   If a widget ID matches that of the instigator field of the geoSpec,
944  *   then that widget is not configured.
945  * Any layout "fixup" routines which are specified in the row structure
946  *   of the geoSpec are called before and after the call
947  *   to XmeConfigureObject, with appropriate parameter values.
948  ****************/
949 void
_XmGeoMatrixSet(XmGeoMatrix geoSpec)950 _XmGeoMatrixSet(
951         XmGeoMatrix geoSpec )
952 {
953     register XmKidGeometry   rowPtr ;
954     register XmGeoRowLayout  layoutPtr ;
955             Boolean         fixUps = FALSE ;
956 /****************/
957 
958 #ifdef DEBUG_GEOUTILS
959     PrintMatrix( "(set) ", geoSpec) ;
960 #endif
961 
962     /* Give the user a chance to avoid setting the widgets to box values.
963     */
964     if(    !geoSpec->set_except  ||  !(*geoSpec->set_except)( geoSpec)    )
965     {
966         /* Give the user a chance to modify box sizes before setting
967         *   the widget to the values defined in the box record.
968         */
969         layoutPtr = &(geoSpec->layouts->row) ;
970         rowPtr = geoSpec->boxes ;
971         while(    !(layoutPtr->end)    )
972         {
973             if(    layoutPtr->fix_up    )
974             {
975                 /* Call the user's routine which may modify boxes of this row.
976                 */
977                 (*(layoutPtr->fix_up))( geoSpec, XmGEO_PRE_SET,
978                                         (XmGeoMajorLayout) layoutPtr, rowPtr) ;
979                 fixUps = TRUE ;
980                 }
981             rowPtr += layoutPtr->box_count + 1 ;         /* Skip to next row.*/
982             ++layoutPtr ;
983             }
984         /* Now set the widgets to the values in the boxes.
985         */
986         layoutPtr = &(geoSpec->layouts->row) ;
987         rowPtr = geoSpec->boxes ;
988         while(    !(layoutPtr->end)    )
989         {
990             _XmSetKidGeo( rowPtr, geoSpec->instigator) ;
991 
992             rowPtr += layoutPtr->box_count + 1 ;         /* Skip to next row.*/
993             ++layoutPtr ;
994             }
995         if(    fixUps    )
996         {
997             /* Now call the fix_up routines again, to give the user a chance to
998             *   undo the chances to the boxes in order to keep consistency for
999             *   subsequent layout operations.
1000             */
1001             layoutPtr = &(geoSpec->layouts->row) ;
1002             rowPtr = geoSpec->boxes ;
1003             while(    !(layoutPtr->end)    )
1004             {
1005                 if(    layoutPtr->fix_up    )
1006                 {
1007                     (*(layoutPtr->fix_up))( geoSpec, XmGEO_POST_SET,
1008                                         (XmGeoMajorLayout) layoutPtr, rowPtr) ;
1009                     }
1010                 rowPtr += layoutPtr->box_count + 1 ;     /* Skip to next row.*/
1011                 ++layoutPtr ;
1012                 }
1013             }
1014         }
1015     return ;
1016     }
1017 
1018 /****************************************************************
1019  * This routine adjusts boxes according to policies regarding border size
1020  *   and even-sized boxes.  Box dimensions are altered appropriately if
1021  *   even_width or even_height parameters are set.  Borders are set if
1022  *   uniform_border is TRUE.
1023  ****************/
1024 void
_XmGeoAdjustBoxes(XmGeoMatrix geoSpec)1025 _XmGeoAdjustBoxes(
1026         XmGeoMatrix geoSpec )
1027 {
1028     register XmKidGeometry   rowPtr ;
1029     register XmKidGeometry   boxPtr ;
1030             XmGeoRowLayout  layoutPtr ;
1031             Dimension       globalSetBorder ;
1032             Dimension       globalBorder ;
1033             Dimension       borderValue ;
1034 /****************/
1035 
1036     globalSetBorder = geoSpec->uniform_border ;
1037     globalBorder = geoSpec->border ;
1038 
1039     rowPtr = geoSpec->boxes ;
1040     layoutPtr = &(geoSpec->layouts->row) ;
1041 
1042     while(    !(layoutPtr->end)    )
1043     {
1044         if(    layoutPtr->even_width    )
1045         {   _XmGeoBoxesSameWidth( rowPtr, layoutPtr->even_width) ;
1046             }
1047         if(    layoutPtr->even_height    )
1048         {   _XmGeoBoxesSameHeight( rowPtr, layoutPtr->even_height) ;
1049             }
1050         if(    globalSetBorder  ||  layoutPtr->uniform_border    )
1051         {   if(    globalSetBorder    )
1052             {   borderValue = globalBorder ;
1053                 }
1054             else
1055             {   borderValue = layoutPtr->border ;
1056                 }
1057             boxPtr = rowPtr ;
1058             while(    boxPtr->kid    )
1059             {   boxPtr->box.border_width = borderValue ;
1060                 ++boxPtr ;
1061                 }
1062             }
1063         while(    (rowPtr++)->kid    )  /* Go to next row of boxes. */
1064         { /*EMPTY*/  }
1065         ++layoutPtr ;           /* Go to next row layout record.*/
1066         }
1067     return ;
1068     }
1069 
1070 /****************************************************************
1071  * This routine traverses the matrix and collects data regarding the
1072  *   sizes of boxes, the minimum fill area expected, and various other
1073  *   parameters which are used during the layout process.
1074  ****************/
1075 void
_XmGeoGetDimensions(XmGeoMatrix geoSpec)1076 _XmGeoGetDimensions(
1077         XmGeoMatrix geoSpec )
1078 {
1079     register XmKidGeometry   rowPtr ;
1080     register XmKidGeometry   boxPtr ;
1081             XmGeoRowLayout  layoutPtr ;
1082             Dimension       boxH ;
1083             Dimension       rowH ;
1084             Dimension       rowW ;
1085             Dimension       matrixFillH ;
1086             Dimension       matrixBoxesH ;
1087             Dimension       matrixW ;
1088             Dimension       endSpaceW ;
1089             unsigned int    numBoxes ;
1090             Dimension       marginW ;
1091             Dimension       marginH ;
1092 /****************/
1093 
1094     marginH = geoSpec->margin_h ;
1095     marginW = geoSpec->margin_w ;
1096     rowPtr = geoSpec->boxes ;
1097     layoutPtr = &(geoSpec->layouts->row) ;
1098     matrixW = 0 ;
1099     matrixBoxesH = 0 ;
1100     matrixFillH = layoutPtr->space_above ;
1101     if(    matrixFillH < marginH    )
1102     {   matrixFillH = 0 ;
1103         }
1104     else
1105     {   matrixFillH -= marginH ;  /* This dimension does not include margins.*/
1106         }
1107     geoSpec->stretch_boxes = FALSE ;
1108     while(    !(layoutPtr->end)    )
1109     {
1110         /* Gather information about the height, width, and number of boxes
1111         *   in the row.
1112         */
1113         rowW = 0 ;
1114         rowH = 0 ;
1115         numBoxes = 0 ;
1116         boxPtr = rowPtr ;
1117         while(    boxPtr->kid    )
1118         {   rowW += boxPtr->box.width + (boxPtr->box.border_width << 1) ;
1119             boxH = boxPtr->box.height + (boxPtr->box.border_width << 1) ;
1120             ASSIGN_MAX( rowH, boxH) ;   /* The tallest box is the row height.*/
1121             ++numBoxes ;
1122             ++boxPtr ;
1123             }
1124         /* Fill row layout record with info about row.
1125         */
1126         layoutPtr->max_box_height = rowH ;/* Tallest box in row, with border.*/
1127         layoutPtr->boxes_width = rowW ; /* Sum of box widths and borders.*/
1128         layoutPtr->box_count = numBoxes ;
1129 
1130         /* Check for vertical stetch row.
1131         */
1132         if(    layoutPtr->stretch_height    )
1133         {   if(    layoutPtr->fit_mode != XmGEO_WRAP    )
1134             {   geoSpec->stretch_boxes = TRUE ;
1135                 }
1136             else
1137             {   layoutPtr->stretch_height = FALSE ;
1138                 }
1139             }
1140         /* Compute row width to generate matrix width.  Exclude margins.
1141         */
1142         if(    layoutPtr->space_end > marginW    )
1143         {   endSpaceW = layoutPtr->space_end - marginW ;
1144             }
1145         else
1146         {   endSpaceW = 0 ;
1147             }
1148         /* Fill width is the minimum spacing between (borders of) boxes plus
1149         *   any extra space required at ends.  Margins are not included.
1150         */
1151         layoutPtr->fill_width = (endSpaceW << 1)
1152                                 + ((numBoxes - 1) * layoutPtr->space_between) ;
1153         /* Maximum row width is the overall matrix width, less margins.  Add
1154         *   box width to fill width for total width this row.
1155         */
1156         rowW += layoutPtr->fill_width ;
1157         ASSIGN_MAX( matrixW, rowW) ;
1158         rowPtr = boxPtr + 1 ;   /* Skip over NULL box marking the end of row.*/
1159         ++layoutPtr ;           /* Go to next row layout record.*/
1160         /* Accumulate heights of each row.
1161         */
1162         matrixFillH += layoutPtr->space_above ;
1163         matrixBoxesH += rowH ;
1164         }
1165     /* The matrixFillH variable already has fill space included from the final
1166     *   row layout record.  This must be reduced by the amount of the margin,
1167     *   or a smaller amount if the amount specified was less than the margin.
1168     */
1169     if(    layoutPtr->space_above < marginH    )
1170     {   matrixFillH -= layoutPtr->space_above ;
1171         }
1172     else
1173     {   matrixFillH -= marginH ;
1174         }
1175     geoSpec->max_major = matrixW ;         /* Widest row, excluding margins. */
1176     geoSpec->boxes_minor = matrixBoxesH ;  /* Sum of tallest box in each row.*/
1177     geoSpec->fill_minor = matrixFillH ;    /* Sum of vertical fill spacing.  */
1178     }
1179 
1180 /****************************************************************
1181  * After the boxes have been layed-out according to the minimum vertical fill
1182  *   requirements of the matrix, this routine stretches the layout to fill
1183  *   any extra space required by the managing widget.
1184  * Returns new height after extra spacing is inserted.
1185  ****************/
1186 static Dimension
_XmGeoStretchVertical(XmGeoMatrix geoSpec,int actualH,int desiredH)1187 _XmGeoStretchVertical(
1188         XmGeoMatrix geoSpec,
1189 #if NeedWidePrototypes
1190         int actualH,
1191         int desiredH )
1192 #else
1193         Dimension actualH,
1194         Dimension desiredH )
1195 #endif /* NeedWidePrototypes */
1196 {
1197     register XmGeoRowLayout  layoutPtr ;
1198     register XmKidGeometry   rowPtr ;
1199             int             fillOffset ;
1200             int             stretchableSpace ;
1201             int             deltaY ;
1202             int             deltaH ;
1203 /****************/
1204 
1205     layoutPtr = &(geoSpec->layouts->row) ;
1206     stretchableSpace = 0 ;
1207     fillOffset = ((int) desiredH) - ((int) actualH) ;
1208     if(    fillOffset < 0    )
1209     {   /* Must shrink stretchable boxes.
1210         */
1211         while(    !layoutPtr->end    )
1212         {   if(    layoutPtr->stretch_height
1213                     && (layoutPtr->max_box_height > layoutPtr->min_height)    )
1214             {
1215                 stretchableSpace += layoutPtr->max_box_height
1216                                                       - layoutPtr->min_height ;
1217                 }
1218             ++layoutPtr ;
1219             }
1220         if(    -fillOffset > stretchableSpace    )
1221         {   fillOffset = -stretchableSpace ;
1222             }
1223         }
1224     else
1225     {   /* Must grow stretchable boxes.
1226         */
1227         while(    !layoutPtr->end    )
1228         {   if(    layoutPtr->stretch_height    )
1229             {   stretchableSpace += layoutPtr->max_box_height ;
1230                 }
1231             ++layoutPtr ;
1232             }
1233         }
1234     if(    !stretchableSpace    )
1235     {   /* No stretchable boxes, so return with current height.
1236         */
1237         return( actualH) ;
1238         }
1239     deltaY = 0 ;
1240     rowPtr = geoSpec->boxes ;
1241     layoutPtr = &(geoSpec->layouts->row) ;
1242     while(    !layoutPtr->end    )
1243     {   if(    layoutPtr->stretch_height    )
1244         {
1245             if(    fillOffset < 0    )
1246             {   if(    layoutPtr->max_box_height > layoutPtr->min_height    )
1247                 {   deltaH = (((int) (layoutPtr->max_box_height
1248                                         - layoutPtr->min_height)) * fillOffset)
1249                                                            / stretchableSpace ;
1250                     }
1251                 else
1252                 {   deltaH = 0 ;
1253                     }
1254                 /* deltaH is now <= 0.
1255                 */
1256                 while(    rowPtr->kid    )
1257                 {
1258 		    int boxCorrection = layoutPtr->max_box_height
1259                                                          - rowPtr->box.height ;
1260 		    if(    boxCorrection > -deltaH    )
1261 		    {   boxCorrection = -deltaH ;
1262 			}
1263 		    rowPtr->box.height += deltaH + boxCorrection ;
1264 		    rowPtr->box.y += deltaY - (boxCorrection >> 1) ;
1265                     ++rowPtr ;
1266                     }
1267                 }
1268             else /* fillOffset >= 0 */
1269             {
1270                 deltaH = (layoutPtr->max_box_height * fillOffset)
1271                                                            / stretchableSpace ;
1272                 while(    rowPtr->kid    )
1273                 {   rowPtr->box.height += deltaH ;
1274                     rowPtr->box.y += deltaY ;
1275                     ++rowPtr ;
1276                     }
1277                 }
1278             deltaY += deltaH ;
1279             }
1280         else
1281         {   while(    rowPtr->kid    )
1282             {   rowPtr->box.y += deltaY ;
1283                 ++rowPtr ;
1284                 }
1285             }
1286         ++rowPtr ;
1287         ++layoutPtr ;
1288         }
1289     return( actualH + deltaY) ;                    /* Return new height.*/
1290     }
1291 
1292 /****************************************************************
1293  * After the boxes have been layed-out according to the minimum vertical fill
1294  *   requirements of the matrix, this routine stretches the layout to fill
1295  *   any extra space required by the managing widget.
1296  * Returns new height after extra spacing is inserted.
1297  ****************/
1298 static Dimension
_XmGeoFillVertical(XmGeoMatrix geoSpec,int actualH,int desiredH)1299 _XmGeoFillVertical(
1300         XmGeoMatrix geoSpec,
1301 #if NeedWidePrototypes
1302         int actualH,
1303         int desiredH )
1304 #else
1305         Dimension actualH,
1306         Dimension desiredH )
1307 #endif /* NeedWidePrototypes */
1308 {
1309     register XmGeoRowLayout  layoutPtr ;
1310     register XmKidGeometry   rowPtr ;
1311             unsigned long   fillAmount ;
1312             unsigned long   totalSpecSpace ;
1313             Dimension       marginH ;
1314             Dimension       firstSpecSpace ;
1315             Dimension       lastSpecSpace ;
1316             Dimension       currentFirstSpace ;
1317             Dimension       currentLastSpace ;
1318             Dimension       newFirstSpace ;
1319             Dimension       newLastSpace ;
1320             int             deltaY ;
1321 /****************/
1322 
1323     /* Need to accumulate specified spacing factors, saving first and last
1324     *   ends separately.
1325     */
1326     layoutPtr = &(geoSpec->layouts->row) ;
1327     totalSpecSpace = 0 ;
1328     firstSpecSpace = layoutPtr->space_above ;
1329     while(    !(++layoutPtr)->end    )
1330     {   totalSpecSpace += layoutPtr->space_above ;
1331         }
1332     lastSpecSpace = layoutPtr->space_above ;
1333     totalSpecSpace += firstSpecSpace + lastSpecSpace ;
1334     if(    !totalSpecSpace    )
1335     {   /* Zero spacing specified, so just return as is.
1336         */
1337         return( actualH) ;
1338         }
1339     /* Must reconstruct the actual spacing, which is the specified minimum.
1340     * Save current end spacing separately, since everything done here is
1341     *   relative to the actual coordinates of the matrix and it will be
1342     *   needed later.
1343     */
1344     marginH = geoSpec->margin_h ;
1345     currentFirstSpace = (firstSpecSpace < marginH) ? marginH : firstSpecSpace ;
1346     currentLastSpace  = (lastSpecSpace < marginH) ? marginH : lastSpecSpace ;
1347 
1348     /* Fill amount includes the current fill plus margins and extra
1349     *   spacing.
1350     */
1351     fillAmount = (desiredH - actualH) + geoSpec->fill_minor
1352                                        + currentFirstSpace + currentLastSpace ;
1353     newFirstSpace = (Dimension) ((fillAmount * (unsigned long) firstSpecSpace)
1354                                                             / totalSpecSpace) ;
1355     newLastSpace = (Dimension) ((fillAmount * (unsigned long) lastSpecSpace)
1356                                                             / totalSpecSpace) ;
1357     if(    newFirstSpace < marginH    )
1358     {   fillAmount -= marginH ;
1359         totalSpecSpace -= firstSpecSpace ;
1360         newFirstSpace = marginH ;
1361         }
1362     if(    newLastSpace < marginH    )
1363     {   fillAmount -= marginH ;
1364         totalSpecSpace -= lastSpecSpace ;
1365         newLastSpace = marginH ;
1366         }
1367     /* Now traverse the matrix, offsetting all y-ccordinates according to
1368     *   additional spacing.  Wrapped lines receive no extra spacing between
1369     *   them.
1370     */
1371     deltaY = newFirstSpace - currentFirstSpace ;
1372     rowPtr = geoSpec->boxes ;
1373     layoutPtr = &(geoSpec->layouts->row) ;
1374     for(;;)
1375     {   while(    rowPtr->kid    )
1376         {   rowPtr->box.y += deltaY ;
1377             ++rowPtr ;
1378             }
1379         ++rowPtr ;
1380         ++layoutPtr ;
1381         if(    layoutPtr->end    )
1382         {   break ;
1383             }
1384         deltaY += (int) (((((unsigned long) layoutPtr->space_above)
1385                     * fillAmount) / totalSpecSpace) - layoutPtr->space_above) ;
1386         }
1387     deltaY += newLastSpace - currentLastSpace ;
1388 
1389     return( actualH + deltaY) ;                    /* Return new height.*/
1390     }
1391 
1392 /****************************************************************
1393  * Calculates and returns appropriate fill factor from given layout
1394  *   parameters.  Also returns appropriate spacing for ends.
1395  * The fill factor returned is for use with all spacing between boxes, but
1396  *   not the ends (use provided spacing).
1397  ****************/
1398 static void
_XmGeoCalcFill(int fillSpace,int margin,unsigned int numBoxes,int endSpec,int betweenSpec,Dimension * pEndSpace,Dimension * pBetweenSpace)1399 _XmGeoCalcFill(
1400 #if NeedWidePrototypes
1401         int fillSpace,
1402         int margin,
1403 #else
1404         Dimension fillSpace,        /* Fill space, including margins.*/
1405         Dimension margin,           /* Margin (included in fillSpace).*/
1406 #endif /* NeedWidePrototypes */
1407         unsigned int numBoxes,
1408 #if NeedWidePrototypes
1409         int endSpec,
1410         int betweenSpec,
1411 #else
1412         Dimension endSpec,
1413         Dimension betweenSpec,
1414 #endif /* NeedWidePrototypes */
1415         Dimension *pEndSpace,       /* Receives end spacing.*/
1416         Dimension *pBetweenSpace )  /* Receives between spacing.*/
1417 {
1418             Dimension       totalSpecSpace ;/* Sum of specified spacing.*/
1419 /****************/
1420 
1421     if(    !endSpec    )
1422     {   if(    numBoxes == 1    )
1423         {   endSpec = 1 ;
1424             }
1425         else
1426         {   if(    !betweenSpec    )
1427             {   betweenSpec = (Dimension) (numBoxes - 1) ;
1428                 }
1429             }
1430         }
1431     totalSpecSpace = (betweenSpec * (numBoxes - 1)) + (endSpec << 1) ;
1432     *pEndSpace = (endSpec * fillSpace) / totalSpecSpace ;
1433 
1434     if(    *pEndSpace < margin    )
1435     {
1436         if(    (endSpec << 1) < totalSpecSpace    )
1437         {   totalSpecSpace -= endSpec << 1 ;
1438             }
1439         else
1440         {   totalSpecSpace = 1 ;
1441             }
1442         if(    (margin << 1) < fillSpace    )
1443         {   fillSpace -= margin << 1 ;
1444             }
1445         else
1446         {   fillSpace = 0 ;
1447             }
1448         *pEndSpace = margin ;
1449         }
1450     *pBetweenSpace = (betweenSpec * fillSpace) / totalSpecSpace ;
1451     return ;
1452     }
1453 
1454 /****************************************************************
1455  * The x, y, width, and height fields of the boxes in the geoSpec matrix
1456  *   are modified with values appropriate for the layout parameters specified
1457  *   by x, y, pW, and pH.
1458  * The overall width and height dimensions at the specified locations
1459  *   of pW and pH must be initially set to their desired values, or zero
1460  *   for the default layout.
1461  * The actual values of the width and height (after layout) are returned at
1462  *   the locations pW and pH.
1463  ****************/
1464 void
_XmGeoArrangeBoxes(XmGeoMatrix geoSpec,int x,int y,Dimension * pW,Dimension * pH)1465 _XmGeoArrangeBoxes(
1466         XmGeoMatrix geoSpec,        /* Array of box lists (rows).*/
1467 #if NeedWidePrototypes
1468         int x,
1469         int y,
1470 #else
1471         Position x,                 /* X coordinate of composite.*/
1472         Position y,                 /* Y coordinate of composite.*/
1473 #endif /* NeedWidePrototypes */
1474         Dimension *pW,              /* Initial value is minimum width.*/
1475         Dimension *pH )             /* Initial value is minimum height.*/
1476 {
1477             Dimension       marginW ;   /* Margin between sides and boxes.*/
1478             Dimension       marginH ;   /* Margin between top/bot and boxes.*/
1479             XmKidGeometry   rowPtr ;
1480             XmGeoRowLayout  layoutPtr ;
1481             Dimension       actualW ;
1482             Dimension       actualH ;
1483             Dimension       initY ;
1484 /****************/
1485 
1486     if(    geoSpec->arrange_boxes
1487        &&  (geoSpec->arrange_boxes != _XmGeoArrangeBoxes)    )
1488       {
1489 	(*(geoSpec->arrange_boxes))( geoSpec, x, y, pW, pH) ;
1490 	return ;
1491       }
1492     /* Fix box dimensions according to even_height/width and uniform_border
1493     *   specifications.
1494     */
1495     _XmGeoAdjustBoxes( geoSpec) ;
1496 
1497     /* Compute layout dimensions.
1498     */
1499     _XmGeoGetDimensions( geoSpec) ;
1500 
1501     /* Initialize global layout dimensions.
1502     */
1503     marginW = geoSpec->margin_w ;
1504     marginH = geoSpec->margin_h ;
1505     actualW = geoSpec->max_major + (marginW << 1) ;
1506 
1507 /****** the value of this assignment is never used **********
1508     actualH = geoSpec->boxes_minor + geoSpec->fill_minor + (marginH << 1) ;
1509 *************************************************************/
1510 
1511     /* Adjust layout dimensions to requested dimensions.
1512     */
1513     if(    *pW    )
1514     {   actualW = *pW ;
1515         }
1516 
1517 /******* the value assigned to actualH is never used *************
1518     if(    *pH    )
1519     {   actualH = *pH ;
1520         }
1521 ******************************************************************/
1522 
1523     /* Save initial Y coordinate for later computation of height.
1524     */
1525     initY = y ;
1526 
1527     /* Layout horizontal position of each box in row, one row at a time.
1528     */
1529     layoutPtr = &(geoSpec->layouts->row) ;
1530     rowPtr = geoSpec->boxes ;
1531     /* Add first end spacing.
1532     */
1533     if(    layoutPtr->space_above > marginH    )
1534     {   y += layoutPtr->space_above ;
1535         }
1536     else
1537     {   y += marginH ;
1538         }
1539     while(    !(layoutPtr->end)    )
1540     {
1541         /* Arrange one row of boxes at a time.
1542         */
1543         y = _XmGeoArrangeList( rowPtr, layoutPtr, x, y, actualW,
1544                                                             marginW, marginH) ;
1545         rowPtr += layoutPtr->box_count + 1 ;             /* Skip to next row.*/
1546         ++layoutPtr ;
1547 
1548         /* Add between-row spacing.
1549         */
1550         y += layoutPtr->space_above ;
1551         }
1552     if(    layoutPtr->space_above < marginH    )
1553     {   /* Fill out to the minimum margin if previous spacing is less
1554         *   than margin.
1555         */
1556         y += marginH - layoutPtr->space_above ;
1557         }
1558     actualH = y - initY ;
1559     if(    *pH  &&  (actualH != *pH)    )
1560     {   if(    geoSpec->stretch_boxes    )
1561         {   /* Has stretchable boxes, so grow or shrink using stretch.
1562             */
1563             actualH = _XmGeoStretchVertical( geoSpec, actualH, *pH) ;
1564             }
1565         else
1566         {   if(    actualH < *pH    )
1567             {   /* Layout is smaller than specified height, so fill vertically.
1568                 */
1569                 actualH = _XmGeoFillVertical( geoSpec, actualH, *pH) ;
1570                 }
1571             }
1572         }
1573     /* Set return values of actual width and height of matrix.
1574     */
1575     geoSpec->width = actualW ;
1576     if(    *pW < actualW    )
1577     {   *pW = actualW ;
1578         }
1579     geoSpec->height = actualH ;
1580     if(    *pH < actualH    )
1581     {   *pH = actualH ;
1582         }
1583     return ;
1584     }
1585 
1586 /****************************************************************/
1587 static int
boxWidthCompare(XmConst void * boxPtr1,XmConst void * boxPtr2)1588 boxWidthCompare(
1589         XmConst void * boxPtr1,
1590         XmConst void * boxPtr2 )
1591 {
1592 /****************/
1593 
1594     return( (*((XmKidGeometry *) boxPtr1))->box.width
1595                                  > (*((XmKidGeometry *) boxPtr2))->box.width) ;
1596     }
1597 /****************************************************************
1598  * This routine alters box sizes such that the composite width is reduced
1599  *   by the offset amount specified.  The boxWidth parameter is assumed to
1600  *   contain the sum of the all box widths, including borders.
1601  * The algorithm used by this routine tends to average the width of all boxes.
1602  *   In other words, to achieve the desired width reduction, the largest boxes
1603  *   are reduced first, possibly until all boxes are the same width
1604  *   (thereafter reducing all boxes evenly).
1605  ****************/
1606 static void
FitBoxesAveraging(XmKidGeometry rowPtr,unsigned int numBoxes,int boxWidth,int amtOffset)1607 FitBoxesAveraging(
1608         XmKidGeometry rowPtr,
1609         unsigned int numBoxes,
1610 #if NeedWidePrototypes
1611         int boxWidth,
1612 #else
1613         Dimension boxWidth,
1614 #endif /* NeedWidePrototypes */
1615         int amtOffset )
1616 {
1617             unsigned int    Index ;
1618             XmKidGeometry * sortedBoxes ;
1619 /****************/
1620 
1621     /* Get memory to use for sorting the list of boxes.
1622     */
1623     sortedBoxes = (XmKidGeometry *) XtMalloc( numBoxes
1624                                                     * sizeof( XmKidGeometry)) ;
1625     /* Enter the boxes into the array and sort.
1626     */
1627     Index = 0 ;
1628     while(    Index < numBoxes    )
1629     {   sortedBoxes[Index] = &rowPtr[Index] ;
1630         /* Need to remove the border_width component from boxWidth.
1631         */
1632         boxWidth -= (rowPtr[Index].box.border_width << 1) ;
1633         ++Index ;
1634         }
1635     qsort( (void *) sortedBoxes, (size_t) numBoxes, sizeof( XmKidGeometry),
1636                                                              boxWidthCompare) ;
1637     /* Now sorted with smallest box first.
1638     */
1639     Index = 0 ;
1640     while(    Index < numBoxes    )
1641     {
1642         /* The right-hand side of the comparison represents the amount of
1643         *   area that would be truncated if all boxes were the same width
1644         *   as sortedBoxes[Index].  The loop will break when the Index
1645         *   points to the smallest box in the list to be truncated.
1646         */
1647         if(   amtOffset >= ((int) (boxWidth - ((sortedBoxes[Index]->box.width)
1648                                                    * (numBoxes - Index))))    )
1649         {   break ;
1650             }
1651         /* This keeps the above comparison simple.
1652         */
1653         boxWidth -= sortedBoxes[Index]->box.width ;
1654         ++Index ;
1655         }
1656     if(    Index < numBoxes    )
1657     {
1658         if(    (int) boxWidth > amtOffset    )
1659         {
1660             boxWidth = (boxWidth - amtOffset) / (numBoxes - Index) ;
1661 
1662             if(    !boxWidth    )
1663             {   boxWidth = 1 ;
1664                 }
1665             }
1666         else
1667         {   boxWidth = 1 ;
1668             }
1669         /* boxWidth is now the truncated width of the remaining boxes
1670         *   in the sorted list.  Set these boxes appropriately.
1671         */
1672         while(    Index < numBoxes    )
1673         {   sortedBoxes[Index]->box.width = boxWidth ;
1674             ++Index ;
1675             }
1676         }
1677     XtFree( (char *) sortedBoxes) ;
1678 
1679     return ;
1680     }
1681 
1682 /****************************************************************
1683  * This routine alters the width of boxes in proportion to the width of each
1684  *   box such that the total change is equal to amtOffset.  If amtOffset is
1685  *   greater than zero, the total width is reduced (a "fit").  Otherwise,
1686  *   the total width is increased (a "fill").
1687  ****************/
1688 static void
FitBoxesProportional(XmKidGeometry rowPtr,unsigned int numBoxes,int boxWidth,int amtOffset)1689 FitBoxesProportional(
1690         XmKidGeometry rowPtr,
1691         unsigned int numBoxes,
1692 #if NeedWidePrototypes
1693         int boxWidth,
1694 #else
1695         Dimension boxWidth,
1696 #endif /* NeedWidePrototypes */
1697         int amtOffset )
1698 {
1699             int             deltaX ;
1700             int             deltaW ;
1701 /****************/
1702 
1703 
1704     if(    boxWidth >= numBoxes    )
1705     {
1706         deltaX = 0 ;
1707         while(    rowPtr->kid    )
1708         {
1709             deltaW = (amtOffset * (int)(rowPtr->box.width
1710                        + (rowPtr->box.border_width << 1))) / ((int) boxWidth) ;
1711             if(    deltaW < ((int) rowPtr->box.width)    )
1712             {   rowPtr->box.width -= deltaW ;
1713                 }
1714             else
1715             {   rowPtr->box.width = 1 ;
1716                 }
1717             rowPtr->box.x += deltaX ;
1718             deltaX -= deltaW ;
1719             ++rowPtr ;
1720             }
1721         }
1722     else /* boxWidth < numBoxes */
1723     {
1724         if(    (-amtOffset) > numBoxes    )
1725         {
1726             boxWidth = (-amtOffset) / numBoxes ;
1727             }
1728         else
1729         {   boxWidth = 1 ;
1730             }
1731         deltaX = 0 ;
1732         while(    rowPtr->kid    )
1733         {
1734             rowPtr->box.width = boxWidth ;
1735             rowPtr->box.x += deltaX ;
1736             deltaX += boxWidth ;
1737             ++rowPtr ;
1738             }
1739 
1740         }
1741     return ;
1742     }
1743 
1744 /****************************************************************/
1745 static void
SegmentFill(XmKidGeometry rowBoxes,unsigned int numBoxes,XmGeoRowLayout layoutPtr,int x,int width,int marginW,int endX,int maxX,int endSpace,int betweenSpace)1746 SegmentFill(
1747         XmKidGeometry rowBoxes,
1748         unsigned int numBoxes,
1749         XmGeoRowLayout layoutPtr,
1750 #if NeedWidePrototypes
1751         int x,
1752         int width,
1753         int marginW,
1754         int endX,
1755         int maxX,
1756         int endSpace,
1757         int betweenSpace )
1758 #else
1759         Position x,
1760         Dimension width,
1761         Dimension marginW,
1762         Position endX,
1763         Position maxX,
1764         Dimension endSpace,
1765         Dimension betweenSpace )
1766 #endif /* NeedWidePrototypes */
1767 {
1768             Widget          holdEnd ;
1769             Dimension       spacedWidth ;
1770             Dimension       boxWidth ;
1771             Dimension       sumW ;
1772             int             amtOffset ;
1773             Dimension       totalFill ;
1774             Position        rowX ;
1775             XmKidGeometry   rowPtr ;
1776 /****************/
1777 
1778     holdEnd = rowBoxes[numBoxes].kid ;
1779     rowBoxes[numBoxes].kid = NULL ;
1780 
1781     spacedWidth = (betweenSpace * (numBoxes - 1)) + (endSpace << 1) ;
1782     amtOffset = ((int) spacedWidth + (maxX - endX)) ;
1783     if(    (amtOffset > 0)  &&  (amtOffset < width)    )
1784     {   boxWidth = width - amtOffset ;
1785         }
1786     else
1787     {   boxWidth = 1 ;
1788         }
1789     sumW = boxWidth + spacedWidth ;
1790 
1791     amtOffset = ((int) sumW) - ((int) width) ;
1792     /* Setup the default spacing.
1793     */
1794     betweenSpace = layoutPtr->space_between ;
1795     endSpace = (layoutPtr->space_end < marginW)
1796                                              ? marginW : layoutPtr->space_end ;
1797     switch(    layoutPtr->fill_mode    )
1798     {   case XmGEO_CENTER:
1799         {
1800             /* Compute new spacing values to result in a centered
1801             *   layout when passed to the simple layout routine.
1802             */
1803             if(    width > sumW    )
1804             {   totalFill = (spacedWidth + width) - sumW ;
1805                 }
1806             else
1807             {   totalFill = marginW << 1 ;
1808                 }
1809             {   /* This little exercise is needed for when NeedWidePrototypes
1810                 *   has value 1 which causes endSpace and betweenSpace to
1811                 *   become "int"s, and a pointer to an int cannot be passed
1812                 *   as an argument where a pointer to a dimension is required.
1813                 */
1814                         Dimension eSpace ;
1815                         Dimension bSpace ;
1816                 _XmGeoCalcFill( totalFill, marginW, numBoxes,
1817                                 layoutPtr->space_end, layoutPtr->space_between,
1818                                                             &eSpace, &bSpace) ;
1819                 endSpace = eSpace ;
1820                 betweenSpace = bSpace ;
1821                 }
1822             break ;
1823             }
1824         case XmGEO_PACK:
1825         {   /* For a packed layout, just layout with extra space
1826             *   at the end of the row.
1827             */
1828             break ;
1829             }
1830         case XmGEO_EXPAND:
1831         default:
1832         {   /* FitBoxesProportional will fill if amtOffset < 0,
1833             *    as it is here.
1834             */
1835             FitBoxesProportional( rowBoxes, numBoxes, boxWidth, amtOffset) ;
1836             break ;
1837             }
1838         }
1839     rowX = x + endSpace ;
1840     rowPtr = rowBoxes ;
1841     while(    rowPtr->kid    )
1842     {
1843         rowPtr->box.x = rowX ;
1844         rowX += rowPtr->box.width + (rowPtr->box.border_width << 1)
1845                                                                + betweenSpace ;
1846         ++rowPtr ;
1847         }
1848     rowBoxes[numBoxes].kid = holdEnd ;
1849     return ;
1850     }
1851 
1852 /****************************************************************
1853  * This routine lays out the row of boxes with the spacing specified in
1854  *   the endSpace and betweenSpace parameters.  If the width of a row
1855  *   which contains more than one box causes the right edge of the
1856  *   row to be greater than maxX, then the boxes will wrap to the next
1857  *   line.
1858  * The Y coordinate of the space following the layout is returned.
1859  ****************/
1860 static Position
_XmGeoLayoutWrap(XmKidGeometry rowPtr,XmGeoRowLayout layoutPtr,int x,int y,int endSpace,int betweenSpace,int maxX,int width,int marginW)1861 _XmGeoLayoutWrap(
1862         XmKidGeometry rowPtr,
1863         XmGeoRowLayout layoutPtr,
1864 #if NeedWidePrototypes
1865         int x,
1866         int y,
1867         int endSpace,
1868         int betweenSpace,
1869         int maxX,
1870         int width,
1871         int marginW )
1872 #else
1873         Position x,
1874         Position y,
1875         Dimension endSpace,
1876         Dimension betweenSpace,
1877         Position maxX,
1878         Dimension width,
1879         Dimension marginW )
1880 #endif /* NeedWidePrototypes */
1881 {
1882             Position        rowX ;
1883             Dimension       rowH ;
1884             Position        boxMaxX ;
1885             unsigned int    numBoxes ;
1886             Dimension       boxH ;
1887             int             deltaW ;
1888             XmKidGeometry   rowBegin ;
1889     register XmKidGeometry  boxPtr ;
1890             Position        endX ;
1891 /****************/
1892 
1893     rowX = x + endSpace ;
1894     rowH = layoutPtr->max_box_height ;
1895     numBoxes = 0 ;
1896     rowBegin = rowPtr ;
1897     boxPtr = rowPtr ;
1898     while(    boxPtr->kid    )
1899     {   boxMaxX = rowX + boxPtr->box.width + (boxPtr->box.border_width << 1) ;
1900 
1901         if(    (boxMaxX > maxX)  &&  numBoxes    )
1902         {   /* Wrap the line.  Also adjust preceding segment according to
1903             *   fill policy.
1904             */
1905             endX = rowX - betweenSpace ;
1906             SegmentFill( rowBegin, numBoxes, layoutPtr, x, width,
1907                                  marginW, endX, maxX, endSpace, betweenSpace) ;
1908             numBoxes = 0 ;
1909             rowX = x + endSpace ;
1910             y += rowH ;
1911             rowBegin = boxPtr ;
1912             boxMaxX = rowX + boxPtr->box.width
1913                                             + (boxPtr->box.border_width << 1) ;
1914             }
1915         if(    boxMaxX > maxX    )
1916         {   /* Since it wasn't wrapped, there must be only one box in this
1917             *   segment.  It is too wide, so simply truncate it.
1918             */
1919             deltaW = ((int) (endSpace + boxMaxX)) - ((int) (maxX + marginW)) ;
1920             if(    (deltaW < ((int) boxPtr->box.width))  &&  (deltaW > 0)    )
1921             {   boxPtr->box.width -= deltaW ;
1922                 }
1923             else
1924             {   boxPtr->box.width = 1 ;
1925                 }
1926             boxMaxX = rowX + boxPtr->box.width
1927                                             + (boxPtr->box.border_width << 1) ;
1928             }
1929         boxPtr->box.x = rowX ;
1930         boxPtr->box.y = y ;
1931         boxH = boxPtr->box.height + (boxPtr->box.border_width << 1) ;
1932         if(    boxH != rowH    )
1933         {   /* If box height is not the same as the maximum box height
1934             *   of the row, then adjust y to center the box in the row.
1935             */
1936             boxPtr->box.y += (((int) rowH - (int) boxH) >> 1) ;
1937             }
1938         rowX = boxMaxX + betweenSpace ;
1939         ++numBoxes ;
1940         ++boxPtr ;
1941         }
1942     endX = rowX - betweenSpace ;
1943     SegmentFill( rowBegin, numBoxes, layoutPtr, x, width,
1944                                  marginW, endX, maxX, endSpace, betweenSpace) ;
1945     if(    layoutPtr->sticky_end    )
1946     {
1947         boxPtr = &rowPtr[layoutPtr->box_count - 1] ;
1948         endX = maxX - (boxPtr->box.width + (boxPtr->box.border_width << 1)) ;
1949         if(    endX > boxPtr->box.x    )
1950         {   boxPtr->box.x = endX ;
1951             }
1952         }
1953     return( y + rowH) ;
1954     }
1955 /****************************************************************
1956  * This routine does a simple layout of the boxes in the row.  It assumes
1957  *   that all boxes have been conditioned to fit appropriately with the
1958  *   spacing specified by the endSpace and betweenSpace parameters.
1959  * The Y coordinate of the space following the layout is returned.
1960  ****************/
1961 static Position
_XmGeoLayoutSimple(XmKidGeometry rowPtr,XmGeoRowLayout layoutPtr,int x,int y,int maxX,int endSpace,int betweenSpace)1962 _XmGeoLayoutSimple(
1963         XmKidGeometry rowPtr,
1964         XmGeoRowLayout layoutPtr,
1965 #if NeedWidePrototypes
1966         int x,
1967         int y,
1968         int maxX,
1969         int endSpace,
1970         int betweenSpace )
1971 #else
1972         Position x,
1973         Position y,
1974         Position maxX,
1975         Dimension endSpace,
1976         Dimension betweenSpace )
1977 #endif /* NeedWidePrototypes */
1978 {
1979             Position        rowX ;
1980             Position        newX ;
1981             Dimension       rowH ;
1982             Dimension       boxH ;
1983 /****************/
1984 
1985     rowH = layoutPtr->max_box_height ;
1986     rowX = x + endSpace ;
1987     while(    rowPtr->kid    )
1988     {
1989         rowPtr->box.x = rowX ;
1990         rowPtr->box.y = y ;
1991         boxH = rowPtr->box.height + (rowPtr->box.border_width << 1) ;
1992         if(    boxH != rowH    )
1993         {   /* If box height is not the same as the maximum box height
1994             *   of the row, then adjust y to center the box in the row.
1995             */
1996             rowPtr->box.y += ((rowH - boxH) >> 1) ;
1997             }
1998         rowX += rowPtr->box.width + (rowPtr->box.border_width << 1)
1999                                                                + betweenSpace ;
2000         ++rowPtr ;
2001         }
2002     if(    layoutPtr->sticky_end    )
2003     {
2004         --rowPtr ;
2005         newX = maxX - (rowPtr->box.width + (rowPtr->box.border_width << 1)) ;
2006         if(    newX > rowPtr->box.x    )
2007         {   rowPtr->box.x = newX ;
2008             }
2009         }
2010     return( y + rowH) ;
2011     }
2012 
2013 
2014 /****************************************************************
2015  * This routines lays out the boxes in this row according to the specified
2016  *   paramaters and the policies specified in the layout record at layoutPtr.
2017  ****************/
2018 /*ARGSUSED*/
2019 static Position
_XmGeoArrangeList(XmKidGeometry rowBoxes,XmGeoRowLayout layoutPtr,int x,int y,int width,int marginW,int marginH)2020 _XmGeoArrangeList(
2021         XmKidGeometry rowBoxes,
2022         XmGeoRowLayout layoutPtr,
2023 #if NeedWidePrototypes
2024         int x,
2025         int y,
2026         int width,
2027         int marginW,
2028         int marginH )		/* unused */
2029 #else
2030         Position x,
2031         Position y,
2032         Dimension width,
2033         Dimension marginW,
2034         Dimension marginH )	/* unused */
2035 #endif /* NeedWidePrototypes */
2036 {
2037             Dimension       sumW ;
2038             unsigned int    numBoxes ;
2039             Dimension       betweenBoxes ;
2040             Dimension       endsOfBoxes ;
2041             int             amtOffset ;
2042             Dimension       boxWidth ;
2043             Position        maxX ;
2044             Dimension       totalFill ;
2045 /****************/
2046 
2047     numBoxes = layoutPtr->box_count ;
2048     boxWidth = layoutPtr->boxes_width ;
2049     sumW = boxWidth + layoutPtr->fill_width + (marginW << 1) ;
2050     amtOffset = ((int) sumW) - ((int) width) ;
2051     /* Setup the default spacing.
2052     */
2053     betweenBoxes = layoutPtr->space_between ;
2054     endsOfBoxes = (layoutPtr->space_end < marginW)
2055                                              ? marginW : layoutPtr->space_end ;
2056     maxX = x + width - marginW ;
2057 
2058     if(    (sumW > width)  &&  (layoutPtr->fit_mode == XmGEO_WRAP)    )
2059     {   /* Wrapping is required, so fill routines and other policy decisions
2060         *   are not needed.  Do the layout using the wrap routine and we're
2061         *   done.
2062         */
2063         y = _XmGeoLayoutWrap( rowBoxes, layoutPtr, x, y, endsOfBoxes,
2064                                           betweenBoxes, maxX, width, marginW) ;
2065         }
2066     else
2067     {   if(    sumW > width    )
2068         {   switch(    layoutPtr->fit_mode    )
2069             {   case XmGEO_AVERAGING:
2070                 {   FitBoxesAveraging( rowBoxes, numBoxes, boxWidth,
2071                                                                    amtOffset) ;
2072                     break ;
2073                     }
2074                 case XmGEO_PROPORTIONAL:
2075                 default:
2076                 {   FitBoxesProportional( rowBoxes, numBoxes, boxWidth,
2077                                                                    amtOffset) ;
2078                     }
2079                 }
2080             }
2081         else
2082         {   if(    sumW < width    )
2083             {   switch(    layoutPtr->fill_mode    )
2084                 {   case XmGEO_CENTER:
2085                     {
2086                         /* Compute new spacing values to result in a centered
2087                         *   layout when passed to the simple layout routine.
2088                         */
2089                         totalFill = (marginW << 1) + layoutPtr->fill_width
2090                                                                + width - sumW ;
2091                         _XmGeoCalcFill( totalFill, marginW, numBoxes,
2092                                 layoutPtr->space_end, layoutPtr->space_between,
2093                                                  &endsOfBoxes, &betweenBoxes) ;
2094                         break ;
2095                         }
2096                     case XmGEO_PACK:
2097                     {   /* For a packed layout, just layout with extra space
2098                         *   at the end of the row.
2099                         */
2100                         break ;
2101                         }
2102                     case XmGEO_EXPAND:
2103                     default:
2104                     {   /* FitBoxesProportional will fill if amtOffset < 0,
2105                         *    as it is here.
2106                         */
2107                         FitBoxesProportional( rowBoxes, numBoxes, boxWidth,
2108                                                                    amtOffset) ;
2109                         break ;
2110                         }
2111                     }
2112                 }
2113             }
2114         y = _XmGeoLayoutSimple( rowBoxes, layoutPtr, x, y, maxX,
2115                                                    endsOfBoxes, betweenBoxes) ;
2116         }
2117     return( y) ;
2118     }
2119 
2120 /****************************************************************
2121  * Changes boxes in the kid geometry list to have desired width.
2122  * If width > 1, then use the specified width.
2123  * If width == 1, then use the width of the widest box.
2124  * If width == 0, then do not change the boxes but return the width of
2125  *   the widest box.
2126  * Returns the value of the width actually used.
2127  ****************/
2128 Dimension
_XmGeoBoxesSameWidth(XmKidGeometry rowPtr,int width)2129 _XmGeoBoxesSameWidth(
2130         XmKidGeometry rowPtr,
2131 #if NeedWidePrototypes
2132         int width )
2133 #else
2134         Dimension width )
2135 #endif /* NeedWidePrototypes */
2136 {
2137     register XmKidGeometry   boxPtr ;
2138     register Dimension       useW ;
2139 /****************/
2140 
2141     useW = width ;  /* Setup default width of each box in row, as specified.*/
2142 
2143     if(    width <= 1    )
2144     {
2145         /* If user specified width parameter of zero or one, then find the
2146         *   width of the widest box.
2147         */
2148         boxPtr = rowPtr ;
2149         while(    boxPtr->kid    )
2150         {   ASSIGN_MAX( useW, boxPtr->box.width) ;
2151             ++boxPtr ;
2152             }
2153         }
2154     if(    width    )
2155     {
2156         /* If width parameter is non-zero, then set the boxes appropriately.
2157         */
2158         boxPtr = rowPtr ;
2159         while(    boxPtr->kid    )
2160         {   boxPtr->box.width = useW ;
2161             ++boxPtr ;
2162             }
2163         }
2164     return( useW) ;
2165     }
2166 /****************************************************************
2167  * Changes boxes in the kid geometry list to have desired height.
2168  * If height > 1, then use the specified height.
2169  * If height == 1, then use the height of the tallest box.
2170  * If height == 0, then do not change the boxes but return the height of
2171  *   the tallest box.
2172  * Returns the value of the height actually used.
2173  ****************/
2174 Dimension
_XmGeoBoxesSameHeight(XmKidGeometry rowPtr,int height)2175 _XmGeoBoxesSameHeight(
2176         XmKidGeometry rowPtr,
2177 #if NeedWidePrototypes
2178         int height )
2179 #else
2180         Dimension height )
2181 #endif /* NeedWidePrototypes */
2182 {
2183     register XmKidGeometry   boxPtr ;
2184     register Dimension       useH ;
2185 /****************/
2186 
2187     useH = height ; /* Setup default height of each box in row, as specified.*/
2188 
2189     if(    height <= 1    )
2190     {
2191         /* If user specified height parameter of zero or one, then find the
2192         *   height of the tallest box.
2193         */
2194         boxPtr = rowPtr ;
2195         while(    boxPtr->kid    )
2196         {   ASSIGN_MAX( useH, boxPtr->box.height) ;
2197             ++boxPtr ;
2198             }
2199         }
2200     if(    height    )
2201     {
2202         /* If height parameter is non-zero, then set the boxes appropriately.
2203         */
2204         boxPtr = rowPtr ;
2205         while(    boxPtr->kid    )
2206         {   boxPtr->box.height = useH ;
2207             ++boxPtr ;
2208             }
2209         }
2210     return( useH) ;
2211     }
2212 
2213 /**************************************************************** ARGSUSED
2214  * This routine is a fixup routine which can be used for rows which consist
2215  *   of a single separator widget.  The effect of this routine is to have
2216  *   the separator ignore the margin width.
2217  ****************/
2218 /*ARGSUSED*/
2219 void
_XmSeparatorFix(XmGeoMatrix geoSpec,int action,XmGeoMajorLayout layoutPtr,XmKidGeometry rowPtr)2220 _XmSeparatorFix(
2221         XmGeoMatrix geoSpec,
2222         int action,
2223         XmGeoMajorLayout layoutPtr, /* unused */
2224         XmKidGeometry rowPtr )
2225 {
2226     register Dimension       marginW ;
2227     register Dimension       twoMarginW ;
2228 /****************/
2229 
2230     marginW = geoSpec->margin_w ;
2231     twoMarginW = (marginW << 1) ;
2232 
2233     switch(    action    )
2234     {
2235         case XmGEO_PRE_SET:
2236         {   rowPtr->box.x -= marginW ;
2237             rowPtr->box.width += twoMarginW ;
2238             break ;
2239             }
2240         default:
2241         {   if(    rowPtr->box.width > twoMarginW    )
2242             {
2243                 /* Avoid subtracting a margin from box width which would
2244                 *   result in underflow.
2245                 */
2246                 rowPtr->box.x += marginW ;
2247                 rowPtr->box.width -= twoMarginW ;
2248                 }
2249             if(    action == XmGET_PREFERRED_SIZE    )
2250             {
2251                 /* Set width to some small value so it does not
2252                 *   effect total width of matrix.
2253                 */
2254                 rowPtr->box.width = 1 ;
2255                 }
2256             break ;
2257             }
2258         }
2259     return ;
2260     }
2261 
2262 
2263 /**************************************************************** ARGSUSED
2264  * This routine is a fixup routine which can be used for rows which consist
2265  *   of a single MenuBar RowColumn.  The effect of this routine is to have
2266  *   the RowColumn ignore the margin width and height.
2267  ****************/
2268 /*ARGSUSED*/
2269 void
_XmMenuBarFix(XmGeoMatrix geoSpec,int action,XmGeoMajorLayout layoutPtr,XmKidGeometry rowPtr)2270 _XmMenuBarFix(
2271         XmGeoMatrix geoSpec,
2272         int action,
2273         XmGeoMajorLayout layoutPtr, /* unused */
2274         XmKidGeometry rowPtr )
2275 {
2276     register Dimension       marginW ;
2277     register Dimension       marginH ;
2278     register Dimension       twoMarginW ;
2279 /****************/
2280 
2281     marginW = geoSpec->margin_w ;
2282     twoMarginW = (marginW << 1) ;
2283     marginH = geoSpec->margin_h ;
2284 
2285     switch(    action    )
2286     {
2287         case XmGEO_PRE_SET:
2288         {   rowPtr->box.x -= marginW ;
2289             rowPtr->box.width += twoMarginW ;
2290             rowPtr->box.y -= marginH ;
2291             break ;
2292             }
2293         default:
2294         {   if(    rowPtr->box.width > twoMarginW    )
2295             {
2296                 /* Avoid subtracting a margin from box width which would
2297                 *   result in underflow.
2298                 */
2299                 rowPtr->box.x += marginW ;
2300                 rowPtr->box.width -= twoMarginW ;
2301                 }
2302             if(    action == XmGET_PREFERRED_SIZE    )
2303             {
2304                 /* Set width to some small value so it does not
2305                 *   effect total width of matrix.
2306                 */
2307                 rowPtr->box.width = 1 ;
2308                 }
2309             break ;
2310             }
2311         }
2312     return ;
2313     }
2314 
2315 /****************************************************************/
2316 void
_XmGeoLoadValues(Widget wid,int geoType,Widget instigator,XtWidgetGeometry * request,XtWidgetGeometry * geoResult)2317 _XmGeoLoadValues(
2318         Widget wid,
2319         int geoType,
2320         Widget instigator,
2321         XtWidgetGeometry *request,
2322         XtWidgetGeometry *geoResult )
2323 {
2324             XtWidgetGeometry reply ;
2325             XtWidgetGeometry * geoSource ;
2326 /****************/
2327 
2328     if(    wid == instigator    )
2329     {   /* If this widget is making the request, then use the request info.
2330         */
2331         geoSource = request ;
2332         }
2333     else
2334     {   geoSource = &reply ;
2335 
2336         switch(    geoType    )
2337         {
2338             case XmGET_PREFERRED_SIZE:
2339             {   XtQueryGeometry( wid, NULL, &reply) ;
2340                 break ;
2341                 }
2342             case XmGET_ACTUAL_SIZE:
2343             default:
2344             {   reply.request_mode = 0 ;  /* Will cause geoSpec to be loaded.*/
2345                 break ;
2346                 }
2347             }
2348         }
2349     geoResult->x = IsX( geoSource) ? geoSource->x : XtX( wid) ;
2350     geoResult->y = IsY( geoSource) ? geoSource->y : XtY( wid) ;
2351     geoResult->width = IsWidth( geoSource) ? geoSource->width : XtWidth( wid) ;
2352     geoResult->height = IsHeight( geoSource)
2353                                          ? geoSource->height : XtHeight( wid) ;
2354     geoResult->border_width = IsBorder( geoSource)
2355                               ? geoSource->border_width : XtBorderWidth( wid) ;
2356     geoResult->request_mode = CWX | CWY | CWWidth | CWHeight | CWBorderWidth ;
2357     return ;
2358     }
2359 
2360 /****************************************************************
2361  * Get a count of the managed kids of a parent, it is assumed that all
2362  *   gadgets are always managed
2363  ****************/
2364 int
_XmGeoCount_kids(register CompositeWidget c)2365 _XmGeoCount_kids(
2366         register CompositeWidget c )
2367 {
2368     register int i, n = 0 ;
2369 /****************/
2370 
2371     for(    i = 0 ; i < c->composite.num_children ; i++    )
2372     {
2373         if(    c->composite.children[i]->core.managed    )
2374         {   n++ ;
2375             }
2376         }
2377     return( n) ;
2378     }
2379 
2380 /**************************************************************** ARGSUSED
2381  * Assemble a kid box for each child widget and gadget, fill in data about
2382  *   each widget and optionally set up uniform border widths.
2383  * Returns a list of records, last one has a 'kid' field of NULL.  This memory
2384  *   for this list should eventually be freed with a call to XtFree().
2385  ****************/
2386 /*ARGSUSED*/
2387 XmKidGeometry
_XmGetKidGeo(Widget wid,Widget instigator,XtWidgetGeometry * request,int uniform_border,int border,int uniform_width_margins,int uniform_height_margins,Widget help,int geo_type)2388 _XmGetKidGeo(
2389         Widget wid,                     /* Widget w/ children. */
2390         Widget instigator,              /* May point to a child who */
2391         XtWidgetGeometry *request,      /*   is asking to change. */
2392         int uniform_border,             /* T/F, enforce it. */
2393 #if NeedWidePrototypes
2394         int border,
2395 #else
2396         Dimension border,               /* Value to use if enforcing.*/
2397 #endif /* NeedWidePrototypes */
2398         int uniform_width_margins,      /* unused.  T/F, enforce it. */
2399         int uniform_height_margins,     /* unused.  T/F, enforce it. */
2400         Widget help,                    /* May point to a help kid. */
2401         int geo_type )                  /* Actual or preferred. */
2402 {
2403             CompositeWidget c = (CompositeWidget) wid ;
2404             XmKidGeometry   geo ;
2405             Widget          kidWid ;
2406             int             i ;
2407             int             j = 0 ;
2408             Boolean         helpFound = FALSE ;
2409 /****************/
2410 
2411     geo = (XmKidGeometry) XtMalloc(
2412                             (_XmGeoCount_kids (c) + 1) * sizeof (XmKidGeometryRec)) ;
2413     /* load all managed kids */
2414     for(    i = 0 ; i < c->composite.num_children ; i++    )
2415     {
2416         kidWid = c->composite.children[i] ;
2417         if(    XtIsManaged( kidWid)    )
2418         {   if(    kidWid == help    )
2419             {   /* Save to put help widget at the end of the widget list.*/
2420                 helpFound = TRUE ;
2421                 }
2422             else
2423             {   geo[j].kid = kidWid ;
2424 
2425                 _XmGeoLoadValues( kidWid, geo_type, instigator, request,
2426                                                                &(geo[j].box)) ;
2427                 if(    uniform_border    )     /* if asked override border */
2428                 {   geo[j].box.border_width = border ;
2429                     }
2430                 j++ ;
2431                 }
2432             }
2433         }
2434     if(    helpFound    )                 /* put help guy into list */
2435     {
2436         geo[j].kid = help ;
2437 
2438         _XmGeoLoadValues( help, geo_type, instigator, request, &(geo[j].box)) ;
2439 
2440         if(    uniform_border    )         /* if asked override border */
2441         {   geo[j].box.border_width = border ;
2442             }
2443         j++ ;
2444         }
2445     geo[j].kid = NULL ;                /* signal end of list */
2446 
2447     return( geo) ;
2448     }
2449 
2450 /****************************************************************/
2451 void
_XmGeoClearRectObjAreas(RectObj r,XWindowChanges * old)2452 _XmGeoClearRectObjAreas(
2453         RectObj r,
2454         XWindowChanges *old )
2455 {
2456             Widget          parent = XtParent( r) ;
2457             int             bw2 ;
2458 /****************/
2459 
2460     bw2 = old->border_width << 1;
2461     XClearArea( XtDisplay( parent), XtWindow( parent), old->x, old->y,
2462                                    old->width + bw2, old->height + bw2, TRUE) ;
2463 
2464     bw2 = r->rectangle.border_width << 1;
2465     XClearArea( XtDisplay( parent), XtWindow( parent), (int) r->rectangle.x,
2466                (int) r->rectangle.y, (unsigned int) (r->rectangle.width + bw2),
2467                             (unsigned int) (r->rectangle.height + bw2), TRUE) ;
2468     return ;
2469     }
2470 
2471 /**************************************************************** ARGSUSED
2472  * Take the kid geometry array and change each kid to match them.
2473  *   remember not to do the resize of the instigator.
2474  * The kid geometry "kg" is assumed to be fully specified.
2475  ****************/
2476 void
_XmSetKidGeo(XmKidGeometry kg,Widget instigator)2477 _XmSetKidGeo(
2478         XmKidGeometry kg,
2479         Widget instigator )
2480 {
2481     Widget          w ;
2482     XtWidgetGeometry * b ;
2483     int             i ;
2484 /****************/
2485 
2486     for(    i=0 ; kg[i].kid != NULL ; i++    )  {
2487         w = (Widget) kg[i].kid ;
2488         b = &(kg[i].box) ;
2489 
2490         if(    w != instigator    ) {
2491 	    XmeConfigureObject( w, b->x, b->y,
2492 			       b->width, b->height, b->border_width) ;
2493 	}  else {
2494 	    XtX( w) = b->x ;
2495 	    XtY( w) = b->y ;
2496 	    XtWidth( w) = b->width ;
2497 	    XtHeight( w) = b->height ;
2498 	    XtBorderWidth( w) = b->border_width ;
2499 	}
2500     }
2501     return ;
2502 }
2503 
2504 /****************************************************************
2505  * Returns TRUE if all specified geometries of geoA are equal to either the
2506  *   specified geometries of geoB or to the geometry of the widget, and
2507  *   vice versa.  The XtCWQueryOnly bit is ignored.
2508  ****************/
2509 Boolean
_XmGeometryEqual(Widget wid,XtWidgetGeometry * geoA,XtWidgetGeometry * geoB)2510 _XmGeometryEqual(
2511         Widget wid,
2512         XtWidgetGeometry *geoA,
2513         XtWidgetGeometry *geoB )
2514 {
2515 /****************/
2516     if(!geoA){ /* For fixing OSF CR 5956 */
2517          return(False);
2518     }
2519 
2520     if(    IsWidth( geoA)  ||  IsWidth( geoB)    )
2521     {
2522         if(    IsWidth( geoA)  &&  IsWidth( geoB)    )
2523         {   if(    geoA->width != geoB->width    )
2524             {   return( FALSE) ;
2525                 }
2526             }
2527         else
2528         {   if(    IsWidth( geoA)    )
2529             {   if(    geoA->width != XtWidth( wid)    )
2530                 {   return( FALSE) ;
2531                     }
2532                 }
2533             else
2534             {   if(    IsWidth( geoB)    )
2535                 {   if(    geoB->width != XtWidth( wid)    )
2536                     {   return( FALSE) ;
2537                         }
2538                     }
2539                 }
2540             }
2541         }
2542     if(    IsHeight( geoA)  ||  IsHeight( geoB)    )
2543     {
2544         if(    IsHeight( geoA)  &&  IsHeight( geoB)    )
2545         {   if(    geoA->height != geoB->height    )
2546             {   return( FALSE) ;
2547                 }
2548             }
2549         else
2550         {   if(    IsHeight( geoA)    )
2551             {   if(    geoA->height != XtHeight( wid)    )
2552                 {   return( FALSE) ;
2553                     }
2554                 }
2555             else
2556             {   if(    IsHeight( geoB)    )
2557                 {   if(    geoB->height != XtHeight( wid)    )
2558                     {   return( FALSE) ;
2559                         }
2560                     }
2561                 }
2562             }
2563         }
2564     if(    IsBorder( geoA)  ||  IsBorder( geoB)    )
2565     {
2566         if(    IsBorder( geoA)  &&  IsBorder( geoB)    )
2567         {   if(    geoA->border_width != geoB->border_width    )
2568             {   return( FALSE) ;
2569                 }
2570             }
2571         else
2572         {   if(    IsBorder( geoA)    )
2573             {   if(    geoA->border_width != XtBorderWidth( wid)    )
2574                 {   return( FALSE) ;
2575                     }
2576                 }
2577             else
2578             {   if(    IsBorder( geoB)    )
2579                 {   if(    geoB->border_width != XtBorderWidth( wid)    )
2580                     {   return( FALSE) ;
2581                         }
2582                     }
2583                 }
2584             }
2585         }
2586     if(    IsX( geoA)  ||  IsX( geoB)    )
2587     {
2588         if(    IsX( geoA)  &&  IsX( geoB)    )
2589         {   if(    geoA->x != geoB->x    )
2590             {   return( FALSE) ;
2591                 }
2592             }
2593         else
2594         {   if(    IsX( geoA)    )
2595             {   if(    geoA->x != XtX( wid)    )
2596                 {   return( FALSE) ;
2597                     }
2598                 }
2599             else
2600             {   if(    IsX( geoB)    )
2601                 {   if(    geoB->x != XtX( wid)    )
2602                     {   return( FALSE) ;
2603                         }
2604                     }
2605                 }
2606             }
2607         }
2608     if(    IsY( geoA)  ||  IsY( geoB)    )
2609     {
2610         if(    IsY( geoA)  &&  IsY( geoB)    )
2611         {   if(    geoA->y != geoB->y    )
2612             {   return( FALSE) ;
2613                 }
2614             }
2615         else
2616         {   if(    IsY( geoA)    )
2617             {   if(    geoA->y != XtY( wid)    )
2618                 {   return( FALSE) ;
2619                     }
2620                 }
2621             else
2622             {   if(    IsY( geoB)    )
2623                 {   if(    geoB->y != XtY( wid)    )
2624                     {   return( FALSE) ;
2625                         }
2626                     }
2627                 }
2628             }
2629         }
2630     return( TRUE) ;
2631     }
2632 
2633 /****************************************************************
2634  * Returns TRUE if all specified geometries of "desired" correspond to
2635  *   specified geometries of "response" and are equal to them.
2636  * The XtCWQueryOnly bit is ignored.
2637  ****************/
2638 /*ARGSUSED*/
2639 Boolean
_XmGeoReplyYes(Widget wid,XtWidgetGeometry * desired,XtWidgetGeometry * response)2640 _XmGeoReplyYes(
2641         Widget wid,		/* unused */
2642         XtWidgetGeometry *desired,
2643         XtWidgetGeometry *response )
2644 {
2645 /****************/
2646     if(!response){ /* For fixing OSF CR 5956 */
2647          return(False);
2648     }
2649     if(    IsWidth( desired)    )
2650     {
2651         if(    !IsWidth( response)
2652             || (desired->width != response->width)    )
2653         {
2654             return( FALSE) ;
2655             }
2656         }
2657     if(    IsHeight( desired)    )
2658     {
2659         if(    !IsHeight( response)
2660             || (desired->height != response->height)    )
2661         {
2662             return( FALSE) ;
2663             }
2664         }
2665     if(    IsBorder( desired)    )
2666     {
2667         if(    !IsBorder( response)
2668             || (desired->border_width != response->border_width)    )
2669         {
2670             return( FALSE) ;
2671             }
2672         }
2673     if(    IsX( desired)    )
2674     {
2675         if(    !IsX( response)
2676             || (desired->x != response->x)    )
2677         {
2678             return( FALSE) ;
2679             }
2680         }
2681     if(    IsY( desired)    )
2682     {
2683         if(    !IsY( response)
2684             || (desired->y != response->y)    )
2685         {
2686             return( FALSE) ;
2687             }
2688         }
2689     return( TRUE) ;
2690     }
2691 
2692 /****************************************************************
2693  * This routine calls the geometry manager and accept the almost
2694  ****************/
2695 XtGeometryResult
_XmMakeGeometryRequest(Widget w,XtWidgetGeometry * geom)2696 _XmMakeGeometryRequest(
2697         Widget w,
2698         XtWidgetGeometry *geom )
2699 {
2700   XtWidgetGeometry allowed ;
2701   XtGeometryResult answer ;
2702 /****************/
2703 
2704   answer = XtMakeGeometryRequest( w, geom, &allowed) ;
2705 
2706   /* On an almost, accept the returned value and make
2707    *   a second request to get an XtGeometryYes returned.
2708    */
2709   if(    answer == XtGeometryAlmost    )
2710     {
2711       /* The Intrinsics protocol guarantees a Yes response
2712        * to a request with identical geometry to that which
2713        * was returned by a previous request returning almost.
2714        */
2715       *geom = allowed ;
2716       answer = XtMakeGeometryRequest( w, geom, &allowed) ;
2717     }
2718   return answer ;
2719 }
2720 
2721 
2722 /****************************************************************/
2723 #ifdef DEBUG_GEOUTILS
2724 /****************************************************************/
2725 void
PrintBox(char * hdr,XmKidGeometry box)2726 PrintBox(
2727             char *          hdr,
2728             XmKidGeometry   box)
2729 /****************
2730  *
2731  ****************/
2732 {
2733 /****************/
2734     printf( "%sw: %X, m: 0x%X, x: %d, y: %d, w: %d, h: %d, b: %d\n",
2735                   hdr, box->kid, box->box.request_mode, box->box.x, box->box.y,
2736                       box->box.width, box->box.height, box->box.border_width) ;
2737     return ;
2738     }
2739 /****************************************************************/
2740 void
PrintList(char * hdr,XmKidGeometry listPtr)2741 PrintList(
2742             char *          hdr,
2743             XmKidGeometry   listPtr)
2744 /****************
2745  *
2746  ****************/
2747 {
2748             int             num ;
2749             char            subhdr[256] ;
2750 /****************/
2751 
2752     num = 0 ;
2753     while(    listPtr->kid    )
2754     {   sprintf( subhdr, "%si: %d ", hdr, num) ;
2755         PrintBox( subhdr, listPtr) ;
2756         ++num ;
2757         ++listPtr ;
2758         }
2759     return ;
2760     }
2761 
2762 /****************************************************************/
2763 void
PrintMatrix(char * hdr,XmGeoMatrix spec)2764 PrintMatrix(
2765             char *          hdr,
2766             XmGeoMatrix     spec)
2767 /****************
2768  *
2769  ****************/
2770 {
2771             int             row ;
2772             int             col ;
2773             XmKidGeometry   boxPtr ;
2774             XmGeoRowLayout  layoutPtr ;
2775             char            subhdr[256] ;
2776 /****************/
2777     row = 1 ;
2778     boxPtr = spec->boxes ;
2779     layoutPtr = spec->layouts.row ;
2780     while(    !(layoutPtr->end)    )
2781     {   col = 1 ;
2782         while(    boxPtr->kid    )
2783         {   sprintf( subhdr, "%srow: %d, col: %d, ", hdr, row, col) ;
2784             PrintBox( subhdr, boxPtr) ;
2785             ++col ;
2786             ++boxPtr ;
2787             }
2788         ++row ;
2789         ++boxPtr ;
2790         ++layoutPtr ;
2791         }
2792     return ;
2793     }
2794 /****************************************************************/
2795 #endif /* DEBUG_GEOUTILS */
2796 /****************************************************************/
2797