1 /* $XConsortium: Grid.c /main/5 1995/07/15 20:40:45 drk $ */
2 /*
3  * Motif
4  *
5  * Copyright (c) 1987-2012, The Open Group. All rights reserved.
6  *
7  * These libraries and programs are free software; you can
8  * redistribute them and/or modify them under the terms of the GNU
9  * Lesser General Public License as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  *
13  * These libraries and programs are distributed in the hope that
14  * they will be useful, but WITHOUT ANY WARRANTY; without even the
15  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16  * PURPOSE. See the GNU Lesser General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with these librararies and programs; if not, write
21  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
22  * Floor, Boston, MA 02110-1301 USA
23  */
24 /*
25  * HISTORY
26  */
27 /********************************** WARNING **********************************
28  *
29  * ExmGrid is a demonstration widget.  OSF provides this widget
30  * solely to teach programmers how to write their own Motif widgets.
31  * OSF does not support this widget in any way
32  *********************************** WARNING *********************************/
33 
34 
35 /******************************************************************************
36  *
37  * Grid.c - ExmGrid widget.  This widget manages its children as an MxN matrix.
38  *          The ExmGrid widget demonstrates how to
39  *             * create a relatively easy Motif manager widget.
40  *             * install and use the XmQTspecifyRenderTable trait.
41  *             * install and use the XmQTdialogShellSavvy trait.
42  *          See the "OSF/Motif Widget Writer's Guide" for details.
43  *
44 ******************************************************************************/
45 
46 /* Include appropriate header files. */
47 #include <Exm/GridP.h>  /* private header file for the ExmGrid widget */
48 #include <Xm/GadgetP.h> /* for gadget management functions */
49 #include <Xm/TraitP.h>  /* for trait access functions */
50 #include <Xm/DialogSavvyT.h> /* for XmQTdialogSavvy trait */
51 #include <Xm/SpecRenderT.h> /* for XmQTspecifyRenderTable trait */
52 
53 
54 /* Define macros. */
55 #define Max(x, y) (((x) > (y)) ? (x) : (y))
56 #define WARNING_TOO_MANY_ROWS "Too many rows specified for ExmGrid.\n"
57 #define WARNING_TOO_MANY_COLUMNS "Too many columns specified for ExmGrid.\n"
58 
59 
60 /* Declare static functions. */
61 static void GetDialogTitle(
62                         Widget bb,
63                         int resource,
64                         XtArgVal *value) ;
65 static void ClassPartInitialize(
66                         WidgetClass widgetClass);
67 static void Initialize(
68                         Widget request_w,
69                         Widget new_w,
70                         ArgList args,
71                         Cardinal *num_args );
72 static void Destroy(
73                         Widget wid) ;
74 static void Resize (
75                         Widget w );
76 static void Redisplay (
77                         Widget w,
78                         XEvent *event,
79                         Region region);
80 static Boolean SetValues (
81                         Widget old_w,
82                         Widget request_w,
83                         Widget new_w,
84                         ArgList args,
85                         Cardinal *num_args );
86 static void SetValuesAlmost(
87                         Widget cw,
88                         Widget nw,
89                         XtWidgetGeometry *request,
90                         XtWidgetGeometry *reply) ;
91 static XtGeometryResult QueryGeometry (
92                         Widget w,
93                         XtWidgetGeometry *request,
94                         XtWidgetGeometry *reply);
95 static XtGeometryResult GeometryManager (
96                         Widget w,
97                         XtWidgetGeometry *request,
98                         XtWidgetGeometry *reply);
99 static void ChangeManaged (
100                         Widget w);
101 static Boolean ConstraintSetValues (
102                         Widget cw,
103                         Widget rw,
104                         Widget nw,
105                         ArgList args,
106                         Cardinal *num_args);
107 static void Layout (
108                         Widget wid,
109                         Widget instigator);
110 static void CalcSize (
111                         Widget wid,
112                         Widget instigator,
113                         Dimension *gridWidth,
114                         Dimension *gridHeight);
115 static Boolean NeedRelayout (
116                         Widget new,
117                         Widget cur);
118 static void CallMapUnmap(Widget wid,
119 			 Boolean map_unmap) ;
120 static XmRenderTable GetTable(Widget wid,
121 			   XtEnum type);
122 
123 
124 /* No translations and no actions. */
125 
126 
127 /* Define the resources for the ExmGrid widget. */
128 static XtResource resources[] =
129 {
130     {
131 	XmNrows,
132 	XmCRows,
133 	XmRShort,
134 	sizeof (short),
135 	XtOffsetOf( ExmGridRec, grid.rows),
136 	XmRImmediate,
137         (XtPointer) 4
138     },
139     {
140 	XmNcolumns,
141 	XmCColumns,
142 	XmRShort,
143 	sizeof (short),
144 	XtOffsetOf( ExmGridRec, grid.columns),
145 	XmRImmediate,
146         (XtPointer) 4
147     },
148     {
149 	XmNmarginWidth,
150 	XmCMarginWidth,
151 	XmRHorizontalDimension,
152 	sizeof (Dimension),
153 	XtOffsetOf( ExmGridRec, grid.margin_width),
154 	XmRImmediate,
155         (XtPointer) 10
156     },
157     {
158 	XmNmarginHeight,
159 	XmCMarginHeight,
160 	XmRVerticalDimension,
161 	sizeof (Dimension),
162 	XtOffsetOf(ExmGridRec, grid.margin_height),
163 	XmRImmediate,
164         (XtPointer) 10
165     },
166     {
167 	XmNmapCallback,
168 	XmCCallback,
169 	XmRCallback,
170 	sizeof (XtCallbackList),
171 	XtOffsetOf(ExmGridRec, grid.map_callback),
172 	XmRImmediate,
173 	(XtPointer) NULL
174     },
175     {
176 	XmNunmapCallback,
177 	XmCCallback,
178 	XmRCallback,
179 	sizeof (XtCallbackList),
180 	XtOffsetOf(ExmGridRec, grid.unmap_callback),
181 	XmRImmediate,
182 	(XtPointer) NULL
183     },
184     {
185 	XmNdefaultPosition,
186 	XmCDefaultPosition,
187 	XmRBoolean, sizeof (Boolean),
188 	XtOffsetOf(ExmGridRec, grid.default_position),
189 	XmRImmediate,
190 	(XtPointer) True
191     },
192     {
193 	XmNbuttonRenderTable,
194 	XmCButtonRenderTable,
195 	XmRButtonRenderTable,
196 	sizeof (XmRenderTable),
197 	XtOffsetOf(ExmGridRec, grid.button_render_table),
198 	XmRCallProc, (XtPointer) NULL
199     },
200     {
201 	XmNlabelRenderTable,
202 	XmCLabelRenderTable,
203 	XmRLabelRenderTable,
204 	sizeof (XmRenderTable),
205 	XtOffsetOf(ExmGridRec, grid.label_render_table),
206 	XmRCallProc, (XtPointer) NULL
207     },
208     {
209 	XmNtextRenderTable,
210 	XmCTextRenderTable,
211 	XmRTextRenderTable,
212 	sizeof (XmRenderTable),
213 	XtOffsetOf(ExmGridRec, grid.text_render_table),
214 	XmRCallProc, (XtPointer) NULL
215     },
216     {
217 	XmNdialogTitle,
218 	XmCDialogTitle,
219 	XmRXmString,
220 	sizeof (XmString),
221 	XtOffsetOf(ExmGridRec, grid.dialog_title),
222 	XmRImmediate, (XtPointer) NULL
223     },
224 
225 };
226 
227 /* Three of the preceding resources will be handled as synthetic
228    resources. */
229 static XmSyntheticResource syn_resources[] =
230 {
231     {
232 	XmNmarginWidth,
233 	sizeof (Dimension),
234 	XtOffsetOf( ExmGridRec, grid.margin_width),
235 	XmeFromHorizontalPixels,
236 	XmeToHorizontalPixels
237     },
238     {
239 	XmNmarginHeight,
240 	sizeof (Dimension),
241 	XtOffsetOf( ExmGridRec, grid.margin_height),
242 	XmeFromVerticalPixels,
243 	XmeToVerticalPixels
244     },
245     {
246 	XmNdialogTitle,
247 	sizeof (XmString),
248 	XtOffsetOf( ExmGridRec, grid.dialog_title),
249 	GetDialogTitle,
250 	NULL
251      }
252 };
253 
254 
255 /* Define the two constraints of ExmGrid. */
256 static XtResource constraints[] =
257 {
258     {
259         ExmNgridMarginWidthWithinCell,
260         ExmCGridMarginWidthWithinCell,
261         XmRHorizontalDimension,
262         sizeof (Dimension),
263         XtOffsetOf( ExmGridConstraintRec, grid.grid_margin_width_within_cell),
264         XmRImmediate,
265         (XtPointer) 0
266     },
267     {
268         ExmNgridMarginHeightWithinCell,
269         ExmCGridMarginHeightWithinCell,
270         XmRVerticalDimension,
271         sizeof (Dimension),
272         XtOffsetOf( ExmGridConstraintRec, grid.grid_margin_height_within_cell),
273         XmRImmediate,
274         (XtPointer) 0
275     },
276 };
277 
278 
279 /* Both of the preceding constraints will be handled as synthetic
280    constraints. */
281 static XmSyntheticResource syn_constraints[] =
282 {
283     {
284         ExmNgridMarginWidthWithinCell,
285         sizeof (Dimension),
286         XtOffsetOf( ExmGridConstraintRec, grid.grid_margin_width_within_cell),
287         XmeFromHorizontalPixels,
288         XmeToHorizontalPixels
289     },
290     {
291         ExmNgridMarginHeightWithinCell,
292         sizeof (Dimension),
293         XtOffsetOf( ExmGridConstraintRec, grid.grid_margin_height_within_cell),
294         XmeFromVerticalPixels,
295         XmeToVerticalPixels
296     },
297 };
298 
299 
300 
301 /* Define the widget class record.  See Chapter 4 of the
302    "OSF/Motif Widget Writer's Guide" for details. */
303 externaldef(exmgridclassrec) ExmGridClassRec exmGridClassRec =
304 {
305   { /* Here is the Core class record. */
306     /* superclass */                 (WidgetClass) &xmManagerClassRec,
307     /* class_name */                 "ExmGrid",
308     /* widget_size */                sizeof(ExmGridRec),
309     /* class_initialize */           NULL,
310     /* class_part_initialize */      ClassPartInitialize,
311     /* class_inited */               FALSE,
312     /* initialize */                 Initialize,
313     /* initialize_hook */            NULL,
314     /* realize */                    XtInheritRealize,
315     /* actions */                    NULL,
316     /* num_actions */                0,
317     /* resources */                  resources,
318     /* num_resources */              XtNumber(resources),
319     /* xrm_class */                  NULLQUARK,
320     /* compress_motion */            TRUE,
321     /* compress_exposure */          XtExposeCompressMaximal,
322     /* compress_enterleave */        TRUE,
323     /* visible_interest */           FALSE,
324     /* destroy */                    Destroy,
325     /* resize */                     Resize,
326     /* expose */                     Redisplay,
327     /* set_values */                 SetValues,
328     /* set_values_hook */            NULL,
329     /* set_values_almost */          SetValuesAlmost,
330     /* get_values_hook */            NULL,
331     /* accept_focus */               NULL,
332     /* version */                    XtVersion,
333     /* callback_private */           NULL,
334     /* tm_table */                   XtInheritTranslations,
335     /* query_geometry */             QueryGeometry,
336     /* display_accelerator */        NULL,
337     /* extension */                  NULL,
338   },
339   { /* Here is the Composite class record. */
340     /* geometry_manager */           GeometryManager,
341     /* change_managed */             ChangeManaged,
342     /* insert_child */               XtInheritInsertChild,
343     /* delete_child */               XtInheritDeleteChild,
344     /* extension */                  NULL,
345   },
346   { /* Here is the Constaint class record. */
347     /* constraint_resources */       constraints,
348     /* constraint_num_resources */   XtNumber(constraints),
349     /* constraint_size */            sizeof(ExmGridConstraintRec),
350     /* constraint_initialize */      NULL,
351     /* constraint_destroy */         NULL,
352     /* constraint_set_values */      ConstraintSetValues,
353     /* extension */                  NULL,
354   },
355   { /* Here is the XmManager class record. */
356     /* translations */               XtInheritTranslations,
357     /* syn_resources */              syn_resources,
358     /* num_syn_resources */          XtNumber(syn_resources),
359     /* syn_constraint_resources */   syn_constraints,
360     /* num_syn_constraint_resources */ XtNumber(syn_constraints),
361     /* parent_process */             XmInheritParentProcess,
362     /* extension */                  NULL,
363   },
364   { /* Here is the ExmGrid class record. */
365     /* layout */                     Layout,
366     /* calc_size */                  CalcSize,
367     /* need_relayout */              NeedRelayout,
368     /* extension */                  NULL,
369   }
370 };
371 
372 /* Establish the widget class name as an externally accessible symbol.
373    Use the "externaldef" macro rather than the "extern" keyword. */
374 externaldef(exmgridwidgetclass) WidgetClass exmGridWidgetClass =
375     (WidgetClass) &exmGridClassRec;
376 
377 
378              /* Define trait record variables. */
379 
380 /* Here is the trait record variable for the XmQTdialogSavvy trait. */
381 static XmConst XmDialogSavvyTraitRec gridDST = {
382   0,            /* version */
383   CallMapUnmap, /* trait method */
384 };
385 
386 
387 /* Here is the trait record variable for the XmQTspecifyRenderTable trait. */
388 static XmConst XmSpecRenderTraitRec gridSRTT = {
389   0,		/* version */
390   GetTable,     /* trait method */
391 };
392 
393 
394 /****************************************************************************
395  *
396  *  GetDialogTitle
397  *      Copy the XmString in XmNdialogTitle before returning it to the user.
398  *
399  ****************************************************************************/
400 static void
GetDialogTitle(Widget wid,int resource,XtArgVal * value)401 GetDialogTitle(
402         Widget wid,
403         int resource,
404         XtArgVal *value)
405 {
406    *value = (XtArgVal)XmStringCopy(((ExmGridWidget) wid)->grid.dialog_title);
407 }
408 
409 
410 /****************************************************************************
411  *
412  *  ClassPartInitialize:
413  *      Called when this widget or a subclass of this widget is instantiated.
414  *
415  ****************************************************************************/
416 static void
ClassPartInitialize(WidgetClass widgetClass)417 ClassPartInitialize (
418         WidgetClass widgetClass
419                     )
420 {
421  ExmGridWidgetClass wc = (ExmGridWidgetClass)widgetClass;
422  ExmGridWidgetClass sc = (ExmGridWidgetClass)wc->core_class.superclass;
423 
424   /* The following code allows subclasses of ExmGrid to inherit three of
425      ExmGrid's methods. */
426     if (wc->grid_class.layout == ExmInheritLayout)
427 	wc->grid_class.layout = sc->grid_class.layout;
428     if (wc->grid_class.calc_size == ExmInheritCalcSize)
429 	wc->grid_class.calc_size = sc->grid_class.calc_size;
430     if (wc->grid_class.need_relayout == ExmInheritNeedRelayout)
431 	wc->grid_class.need_relayout = sc->grid_class.need_relayout;
432 
433   /* Install the XmQTdialogShellSavyy trait on this class and on
434      all its future subclasses. */
435     XmeTraitSet(widgetClass, XmQTdialogShellSavvy, (XtPointer) &gridDST);
436 
437   /* Install the XmQTspecifyRenderTable trait on this class and on
438      all its future subclasses. */
439     XmeTraitSet(widgetClass, XmQTspecifyRenderTable, (XtPointer) &gridSRTT);
440 }
441 
442 
443 /**************************************************************************
444  *
445  *  Initialize:
446  *      Called when this widget is first instantiated.
447  *
448  ***************************************************************************/
449 static void
Initialize(Widget request_w,Widget new_w,ArgList args,Cardinal * num_args)450 Initialize (
451         Widget request_w,
452         Widget new_w,
453         ArgList args,
454         Cardinal *num_args
455            )
456 {
457  ExmGridWidget rw = (ExmGridWidget)request_w;
458  ExmGridWidget nw = (ExmGridWidget)new_w;
459 
460   /* Initialize one of the internal fields of the ExmGrid widget. */
461     nw->grid.processing_constraints = False;
462 
463   /* Ensure that user doesn't specify too many rows. */
464     if (rw->grid.rows > EXM_GRID_MAX_NUMBER_OF_ROWS) {
465       XmeWarning((Widget)rw, WARNING_TOO_MANY_ROWS);
466       nw->grid.rows = EXM_GRID_MAX_NUMBER_OF_ROWS;
467     }
468 
469   /* Ensure that user doesn't specify too many columns. */
470     if (rw->grid.columns > EXM_GRID_MAX_NUMBER_OF_COLUMNS) {
471       XmeWarning((Widget)rw, WARNING_TOO_MANY_COLUMNS);
472       nw->grid.columns = EXM_GRID_MAX_NUMBER_OF_COLUMNS;
473     }
474 
475   /* Copy in the dialog title XmString and update our shell */
476     if (nw->grid.dialog_title) {
477       nw->grid.dialog_title = XmStringCopy(rw->grid.dialog_title) ;
478       XmeSetWMShellTitle(nw->grid.dialog_title, XtParent(new_w)) ;
479     }
480 }
481 
482 
483 /****************************************************************************
484  *
485  *  Destroy:
486  *      Called when the widget is destroyed.
487  *
488  ****************************************************************************/
489 static void
Destroy(Widget wid)490 Destroy(
491         Widget wid )
492 {
493  ExmGridWidget grid = (ExmGridWidget)wid;
494 
495   /* Deallocate the dynamic memory that holds the dialog_title. */
496     XmStringFree(grid->grid.dialog_title) ;
497 }
498 
499 
500 /****************************************************************************
501  *
502  *  Resize:
503  *
504  ****************************************************************************/
505 static void
Resize(Widget w)506 Resize (
507         Widget w
508        )
509 {
510  ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass(w);
511 
512   /* Configure the children by calling Layout. */
513     if (gwc->grid_class.layout)
514       (*(gwc->grid_class.layout))(w, NULL);
515     else
516       Layout (w, NULL);
517 }
518 
519 
520 
521 
522 /****************************************************************************
523  *
524  *  Redisplay:
525  *      Called by the Intrinsics in response to an exposure event.
526  *
527  ***************************************************************************/
528 static void
Redisplay(Widget w,XEvent * event,Region region)529 Redisplay (
530         Widget w,
531         XEvent *event,
532         Region region
533           )
534 {
535   /* Pass exposure event down to gadget children. */
536     XmeRedisplayGadgets (w, event, region);
537 }
538 
539 
540 
541 /*****************************************************************************
542  *
543  *  SetValues:
544  *      Called by the Intrinsics whenever any of the resource values change.
545  *
546  ****************************************************************************/
547 static Boolean
SetValues(Widget old_w,Widget request_w,Widget new_w,ArgList args,Cardinal * num_args)548 SetValues (
549         Widget old_w,
550         Widget request_w,
551         Widget new_w,
552         ArgList args,
553         Cardinal *num_args
554           )
555 {
556  ExmGridWidget cw = (ExmGridWidget)old_w;
557  ExmGridWidget rw = (ExmGridWidget)request_w;
558  ExmGridWidget nw = (ExmGridWidget)new_w;
559  Boolean redisplay = False;
560  Boolean need_relayout;
561  ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass(new_w);
562 
563   /* Ensure that user doesn't specify too many rows. */
564     if (rw->grid.rows > EXM_GRID_MAX_NUMBER_OF_ROWS) {
565       XmeWarning((Widget)rw, WARNING_TOO_MANY_ROWS);
566       nw->grid.rows = EXM_GRID_MAX_NUMBER_OF_ROWS;
567     }
568 
569   /* Ensure that user doesn't specify too many rows. */
570     if (rw->grid.columns > EXM_GRID_MAX_NUMBER_OF_COLUMNS) {
571       XmeWarning((Widget)rw, WARNING_TOO_MANY_COLUMNS);
572       nw->grid.columns = EXM_GRID_MAX_NUMBER_OF_COLUMNS;
573     }
574 
575   /* See if any class or subclass resources have changed. */
576     if (gwc->grid_class.need_relayout)
577       need_relayout = (*(gwc->grid_class.need_relayout))(old_w, new_w);
578     else
579       need_relayout = NeedRelayout (old_w, new_w);
580 
581   /* If any geometry resources changed and a new size wasn't specified,
582      recalculate a new ideal size. */
583     if (need_relayout) {
584       /* Reset the widget size so that CalcSize can affect them. */
585 	if (nw->core.width == cw->core.width)
586           nw->core.width = 0;
587 	if (nw->core.height == cw->core.height)
588           nw->core.height = 0;
589 
590       /* Call CalcSize. */
591         if (gwc->grid_class.calc_size)
592           (*(gwc->grid_class.calc_size))(new_w, NULL,
593                                          &nw->core.width, &nw->core.height);
594         else
595           CalcSize (new_w, NULL, &nw->core.width, &nw->core.height);
596 
597 
598       /* If the geometry resources have changed but the size hasn't,
599 	 we need to relayout manually, because Xt won't generate a
600 	 Resize at this point. */
601 	if ((nw->core.width == cw->core.width) &&
602           (nw->core.height == cw->core.height)) {
603 
604          /* Call Layout to configure the children. */
605            if (gwc->grid_class.layout)
606              (*(gwc->grid_class.layout))(new_w, NULL);
607            else
608              Layout(new_w, NULL);
609            redisplay = True ;
610 	}
611     }
612 
613  /* ExmGrid installs the XmQTdialogShellSavvy trait.  Therefore, ExmGrid
614     has to process the Xm_DIALOG_SAVVY_FORCE_ORIGIN case, which is as
615     follows.  A DialogShell always mimics the child position on itself.
616     That is, the "current" position of an ExmGrid within a DialogShell is
617     always 0.  Therefore, if an application tries to set ExmGrid's x or
618     y position to 0, the Intrinsics will not detect a position change and
619     wll not trigger a geometry request.  ExmGrid has to detect this special
620     request and set core.x and core.y to the special value,
621     XmDIALOG_SAVVY_FORCE_ORIGIN.  That is, XmDIALOG_SAVVY_FORCE_ORIGIN
622     tells DialogShell that ExmGrid really does want to move to an x or y
623     position of 0. */
624 
625    if (XmIsDialogShell(XtParent(new_w)))  {   /* Is parent a DialogShell? */
626      Cardinal i ;
627 
628     /* We have to look in the arglist since old_w->core.x is always 0, and
629        if new_w->core.x is also set to 0, we see no change. */
630       for (i=0; i<*num_args; i++) {
631          if (strcmp (args[i].name, XmNx) == 0) {
632 	   if ((args[i].value == 0) && (new_w->core.x == 0))
633              new_w->core.x = XmDIALOG_SAVVY_FORCE_ORIGIN;
634 	 }
635 	 if (strcmp (args[i].name, XmNy) == 0) {
636            if ((args[i].value == 0) && (new_w->core.y == 0))
637              new_w->core.y = XmDIALOG_SAVVY_FORCE_ORIGIN;
638          }
639       } /* end for */
640    } /* end of if */
641 
642    /* Update wm shell title if it has changed */
643    if(nw->grid.dialog_title != cw->grid.dialog_title ) {
644         XmStringFree(cw->grid.dialog_title) ;
645         nw->grid.dialog_title = XmStringCopy(rw->grid.dialog_title) ;
646         XmeSetWMShellTitle(nw->grid.dialog_title, XtParent(new_w)) ;
647    }
648 
649    return (redisplay);
650 }
651 
652 
653 
654 /*************************************************************************
655  *
656  *  SetValuesAlmost:
657  *       Called by the Intrinsics when an XtMakeGeometryRequest call
658  *       returns either XmGeometryAlmost or XtGeometryNo.
659  *
660  ***************************************************************************/
661 static void
SetValuesAlmost(Widget cw,Widget nw,XtWidgetGeometry * request,XtWidgetGeometry * reply)662 SetValuesAlmost(
663         Widget cw,		/* unused */
664         Widget nw,
665         XtWidgetGeometry *request,
666         XtWidgetGeometry *reply )
667 {
668  ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass(nw);
669 
670   /* ExmGrid's parent said XtGeometryNo to ExmGrid's geometry request.
671      Therefore, we need to relayout because this request
672      was due to a change in internal geometry resource of the ExmGrid */
673     if (!reply->request_mode) {
674 	if (gwc->grid_class.layout)
675 	    (*(gwc->grid_class.layout))(nw, NULL);
676 	else
677 	    Layout(nw, NULL);
678     }
679 
680     *request = *reply;
681 }
682 
683 
684 /*************************************************************************
685  *
686  *  QueryGeometry:
687  *       Called by a parent of Grid when the parent needs to find out Grid's
688  *       preferred size.  QueryGeometry calls CalcSize to do find the
689  *       preferred size.
690  *
691  ***************************************************************************/
692 static XtGeometryResult
QueryGeometry(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)693 QueryGeometry (
694         Widget w,
695         XtWidgetGeometry *request,
696         XtWidgetGeometry *reply
697               )
698 {
699  ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass(w);
700 
701   /* If ExmGrid's parent calls XtQueryGeometry before ExmGrid has been
702      realized, use the current size of ExmGrid as the preferred size. */
703   /* Deal with user initial size setting */
704     if (!XtIsRealized(w))  {  /* Widget is not yet realized. */
705 	reply->width = XtWidth(w) ;    /* might be 0 */
706 	reply->height = XtHeight(w) ;  /* might be 0 */
707     } else {	    /* Widget is realized. */
708 	/* always computes natural size afterwards */
709 	reply->width = 0;
710 	reply->height = 0;
711     }
712 
713   /* Call CalcSize to figure out what the preferred size really is. */
714     if (gwc->grid_class.calc_size)
715       (*(gwc->grid_class.calc_size))(w, NULL, &reply->width, &reply->height);
716     else
717       CalcSize (w, NULL, &reply->width, &reply->height);
718 
719   /* This function handles CWidth and CHeight */
720     return XmeReplyToQueryGeometry(w, request, reply) ;
721 }
722 
723 
724 /****************************************************************************
725  *
726  *  GeometryManager:
727  *       Called by Intrinsics in response to a geometry change request from
728  *       one of the children of ExmGrid.
729  *
730  ***************************************************************************/
731 static XtGeometryResult
GeometryManager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)732 GeometryManager (
733         Widget w,  /* instigator */
734         XtWidgetGeometry *request,
735         XtWidgetGeometry *reply
736                 )
737 {
738  ExmGridWidget gw = (ExmGridWidget) XtParent(w);
739  XtWidgetGeometry parentRequest;
740  XtGeometryResult result;
741  Dimension curWidth, curHeight, curBW;
742  ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass((Widget)gw);
743 
744   /* If the request was caused by ConstraintSetValues reset the flag */
745     if (gw->grid.processing_constraints) {
746       gw->grid.processing_constraints = False;
747 	/* The ConstraintSetValues added one to border_width;
748 	   This is the Xt trick used to fire the GM when a non core
749 	   geometry resource (like a constraint) changes.
750 	   now take it away. */
751 	request->border_width -= 1;
752     }
753 
754   /* Save the original child resources. */
755     curWidth = w->core.width;
756     curHeight = w->core.height;
757     curBW = w->core.border_width;
758 
759   /* Deny any requests for a new position. */
760     if ((request->request_mode & CWX) || (request->request_mode & CWY))
761 	return XtGeometryNo ;
762 
763    if (request->request_mode & CWWidth)
764      w->core.width = request->width;
765    if (request->request_mode & CWHeight)
766      w->core.height = request->height;
767    if (request->request_mode & CWBorderWidth)
768      w->core.border_width = request->border_width;
769 
770   /* Calculate a new ideal size based on these requests. */
771   /* Setting width and height to 0 tells CalcSize to override these
772      fields with the calculated width and height. */
773     parentRequest.width = 0;
774     parentRequest.height = 0;
775     if (gwc->grid_class.calc_size)
776 	(*(gwc->grid_class.calc_size))((Widget)gw, w,
777 				       &parentRequest.width,
778 				       &parentRequest.height);
779     else
780 	CalcSize ((Widget)gw, w, &parentRequest.width, &parentRequest.height);
781 
782 
783   /* Ask the Grid's parent if new calculated size is acceptable. */
784     parentRequest.request_mode = CWWidth | CWHeight;
785     if (request->request_mode & XtCWQueryOnly)
786 	parentRequest.request_mode |= XtCWQueryOnly;
787     result = XtMakeGeometryRequest ((Widget)gw, &parentRequest, NULL);
788 
789   /*  Turn XtGeometryAlmost into XtGeometryNo. */
790     if (result == XtGeometryAlmost)
791       result = XtGeometryNo;
792 
793     if (result == XtGeometryNo ||
794 	request->request_mode & XtCWQueryOnly) {
795 	/* Restore original geometry. */
796 	w->core.width = curWidth;
797 	w->core.height = curHeight;
798 	w->core.border_width = curBW;
799    } else {
800        /* result == XtGeometryYes and this wasn't just a query */
801        if (gwc->grid_class.layout)
802 	   (*(gwc->grid_class.layout))((Widget)gw, w);
803        else
804 	   Layout ((Widget)gw, w); /* Layout with this child as the instigator,
805 			              so that we don't resize this child. */
806    }
807 
808    return (result);
809 }
810 
811 
812 
813 /**************************************************************************
814  *
815  *  ChangeManaged:
816  *      Called by the Intrinsics whenever either of the following happens:
817  *           * a managed child becomes unmanaged.
818  *           * an unmanaged child becomes managed.
819  *
820  *************************************************************************/
821 static void
ChangeManaged(Widget w)822 ChangeManaged(
823         Widget w
824              )
825 {
826  Dimension gridWidth, gridHeight;
827  ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass(w);
828 
829   /* If you get an initial (C) size from the user or application, keep it.
830      Otherwise, just force width and height to 0 so that CalcSize will
831      overwrite the appropriate fields. */
832     if (!XtIsRealized(w))  {
833 	/* The first time, only attempts to change non specified sizes */
834 	gridWidth = XtWidth(w) ;   /* might be 0 */
835 	gridHeight = XtHeight(w) ; /* might be 0 */
836     } else {
837 	gridWidth = 0 ;
838 	gridHeight = 0 ;
839     }
840 
841   /* Determine the ideal size of Grid. */
842     if (gwc->grid_class.calc_size)
843 	(*(gwc->grid_class.calc_size))(w, NULL, &gridWidth, &gridHeight);
844     else
845 	CalcSize (w, NULL, &gridWidth, &gridHeight);
846 
847  /* Ask parent of Grid if Grid's new size is acceptable.  Keep asking until
848     parent returns either XtGeometryYes or XtGeometryNo. */
849     while (XtMakeResizeRequest (w, gridWidth, gridHeight,
850    		                &gridWidth, &gridHeight) == XtGeometryAlmost);
851 
852     /* Now that we have a size for the Grid, we can layout the children
853        of the grid. */
854     if (gwc->grid_class.layout)
855 	(*(gwc->grid_class.layout))(w, NULL);
856     else
857 	Layout (w, NULL);
858 
859     /* Update keyboard traversal */
860     XmeNavigChangeManaged (w);
861 }
862 
863 
864 
865 
866 /**************************************************************************
867  *
868  *  ConstraintSetValues:
869  *      Called by Intrinsics if there is any change in any of the constraint
870  *      resources.
871  *
872  **************************************************************************/
873 static Boolean
ConstraintSetValues(Widget cw,Widget rw,Widget nw,ArgList args,Cardinal * num_args)874 ConstraintSetValues (
875     Widget cw,
876     Widget rw,
877     Widget nw,
878     ArgList args,
879     Cardinal *num_args
880                     )
881 {
882  ExmGridConstraint nc;
883  ExmGridConstraint cc;
884  ExmGridWidget gw;
885 
886     if (!XtIsRectObj (nw))
887 	return (False);
888 
889     gw = (ExmGridWidget)XtParent(nw);
890     nc = ExmGridCPart(nw);
891     cc = ExmGridCPart(cw);
892 
893     /* Check for change in ExmNgridMarginWidth or ExmNgridMarginHeight */
894     if ((nc->grid_margin_width_within_cell !=
895 	 cc->grid_margin_width_within_cell ||
896 	 nc->grid_margin_height_within_cell !=
897 	 cc->grid_margin_height_within_cell) &&
898 	XtIsManaged (nw)) {
899 	/* Tell the Intrinsics and the GeometryManager method that a
900 	   reconfigure is needed. */
901 	gw->grid.processing_constraints = True;
902      /* A trick: by altering one of the core geometry fields, Xt will
903         call the parent's geometry_manager method. */
904 	nw->core.border_width += 1;
905     }
906 
907     return (False);
908 }
909 
910 
911 /***************************************************************************
912  *
913  *  Layout:
914  *     Does all the placement of children.
915  *     Instigator tells whether or not to resize all children.
916  *
917  *************************************************************************/
918 static void
Layout(Widget wid,Widget instigator)919 Layout (
920         Widget wid,
921         Widget instigator
922        )
923 {
924  ExmGridWidget gw = (ExmGridWidget) wid ;
925  Dimension mw = gw->grid.margin_width;
926  Dimension mh = gw->grid.margin_height;
927  Dimension TotalWidthOfGridWidget  = gw->core.width;
928  Dimension TotalWidthOfGridMargins, TotalHeightOfGridMargins;
929  Dimension TotalHeightOfGridWidget = gw->core.height;
930  Dimension AvailWidthForChildren = 1, AvailHeightForChildren = 1;
931  Dimension WidthAllottedEachChild, HeightAllottedEachChild;
932  int i, row, column;
933 
934     /* Lay out the children that ExmGrid is currently managing.
935        Each child will be placed somewhere on the rowxcolumn grid. */
936     TotalWidthOfGridMargins = 2 * mw;
937     if (TotalWidthOfGridWidget > TotalWidthOfGridMargins)
938 	AvailWidthForChildren = TotalWidthOfGridWidget -
939 	    TotalWidthOfGridMargins;
940 
941     WidthAllottedEachChild = AvailWidthForChildren / gw->grid.columns;
942 
943     TotalHeightOfGridMargins = 2 * mh;
944     if (TotalHeightOfGridWidget > TotalHeightOfGridMargins)
945 	AvailHeightForChildren = TotalHeightOfGridWidget -
946 	    TotalHeightOfGridMargins;
947     HeightAllottedEachChild = AvailHeightForChildren / gw->grid.rows;
948 
949     /* Now that we know how much space is allotted for each child, we
950        can lay them all out. */
951     row = 0;
952     column = 0;
953     for (i = 0; i < gw->composite.num_children; i++) {
954 	Widget ic = gw->composite.children[i];
955 	ExmGridConstraint glc = ExmGridCPart (ic);
956 	Dimension gmw = glc->grid_margin_width_within_cell;
957 	Dimension gmh = glc->grid_margin_height_within_cell;
958 	Position ChildsStartingX, ChildsStartingY;
959 	Dimension ChildsActualWidth, ChildsActualHeight, cb;
960 
961 	if (!XtIsManaged(ic))
962 	    continue;  /* ignored unmanaged children */
963 
964 	cb = ic->core.border_width;
965 
966 	/* Calculate the position and the size of the child.
967 	   During the layout, the children are all resized
968 	   to exactly fit the cell size minus the cell margin */
969 
970 	ChildsActualWidth = WidthAllottedEachChild - (2 * (gmw + cb));
971 	ChildsStartingX = mw + (column * WidthAllottedEachChild) + gmw;
972 	ChildsStartingY = mh + (row * HeightAllottedEachChild) + gmh;
973 	ChildsActualHeight = HeightAllottedEachChild - 2 * (gmh + cb);
974 
975 	/* If layout is instigated by the GeometryManager don't
976 	   configure the requesting child, just set its geometry and
977 	   let Xt configure it.   */
978 	if (ic != instigator) {
979 	    XmeConfigureObject (ic, ChildsStartingX, ChildsStartingY,
980 				ChildsActualWidth, ChildsActualHeight, cb);
981 	}
982 	else {
983 	    ic->core.x = ChildsStartingX;
984 	    ic->core.y = ChildsStartingY;
985 	    ic->core.width = ChildsActualWidth;
986 	    ic->core.height = ChildsActualHeight;
987 	    ic->core.border_width = cb;
988 	}
989 
990 	/* Advance the column counter until we reach the right edge.
991 	   When we reach the right edge, reset the column
992 	   counter back to 0 (left edge) and advance the row counter. */
993 	column += 1;
994 
995 	if (column == gw->grid.columns) {
996 	    column = 0;
997 	    row += 1;
998 	}
999     }
1000 }
1001 
1002 
1003 
1004 /******************************************************************************
1005  *
1006  *  CalcSize:
1007  *     Called by QueryGeometry, SetValues, GeometryManager, and ChangeManaged.
1008  *     Calculate the ideal size of the ExmGrid widget.
1009  *     Only affects the returned size if it is 0.
1010  *
1011  ****************************************************************************/
1012 static void
CalcSize(Widget wid,Widget instigator,Dimension * TotalWidthOfGridWidget,Dimension * TotalHeightOfGridWidget)1013 CalcSize (
1014         Widget wid,
1015         Widget instigator,
1016         Dimension *TotalWidthOfGridWidget,
1017         Dimension *TotalHeightOfGridWidget
1018          )
1019 {
1020  ExmGridWidget gw = (ExmGridWidget) wid ;
1021  Dimension maxWidth = 1;
1022  Dimension maxHeight = 1;
1023  int i;
1024 
1025   /* Examine each of Grid's children.  Find the biggest child.  The
1026      ideal size of the Grid will be large enough to accomodate the
1027      largest child. */
1028     for (i = 0; i < gw->composite.num_children; i++) {
1029 	Widget ic = gw->composite.children[i];
1030 	ExmGridConstraint glc = ExmGridCPart (ic);
1031 	Dimension width, height;
1032 	Dimension cw, ch, cb;
1033 	XtWidgetGeometry reply;
1034 
1035 	if (!XtIsManaged(ic))
1036             continue ;
1037 
1038 	/* Get child's preferred geometry if not the instigator. */
1039         if (ic != instigator) {
1040 	    XtQueryGeometry (ic, NULL, &reply);
1041 	    cw = (reply.request_mode & CWWidth) ? reply.width :
1042 		ic->core.width;
1043 	    ch = (reply.request_mode & CWHeight) ? reply.height :
1044 		ic->core.height;
1045 	} else {
1046 	    cw = ic->core.width;
1047 	    ch = ic->core.height;
1048 	}
1049 	cb = ic->core.border_width;
1050 
1051 	width = cw + 2 * (cb + glc->grid_margin_width_within_cell);
1052 	height = ch + 2 * (cb + glc->grid_margin_height_within_cell);
1053 
1054 	maxWidth  = Max (width, maxWidth);
1055         maxHeight = Max (height, maxHeight);
1056     }
1057 
1058 
1059  /* The total width of the grid widget should be set to the width of
1060     the largest child widget times the number of columns. */
1061    if (!*TotalWidthOfGridWidget) {
1062        *TotalWidthOfGridWidget = maxWidth * gw->grid.columns +
1063    			         (2 * (gw->grid.margin_width));
1064    }
1065 
1066  /* The total height of the grid widget should be set to the height of
1067     the largest child widget times the number of columns. */
1068    if (!*TotalHeightOfGridWidget) {
1069        *TotalHeightOfGridWidget = maxHeight * gw->grid.rows +
1070    			          (2 * (gw->grid.margin_height));
1071    }
1072 }
1073 
1074 
1075 /****************************************************************************
1076  *
1077  *  NeedRelayout:
1078  *     Called by SetValues.
1079  *     Returns True if a relayout is needed.
1080  *     based on this class and all superclass resources' changes.
1081  *
1082  ***************************************************************************/
1083 static Boolean
NeedRelayout(Widget old_w,Widget new_w)1084 NeedRelayout (
1085         Widget old_w,
1086         Widget new_w
1087          )
1088 {
1089  ExmGridWidget cw = (ExmGridWidget)old_w;
1090  ExmGridWidget nw = (ExmGridWidget)new_w;
1091 
1092     if (nw->grid.margin_width != cw->grid.margin_width ||
1093 	nw->grid.margin_height != cw->grid.margin_height ||
1094 	nw->grid.rows != cw->grid.rows ||
1095 	nw->grid.columns != cw->grid.columns) {
1096 	return True ;
1097     } else
1098 	return False ;
1099 }
1100 
1101 
1102 
1103 
1104 /*-- Trait methods --*/
1105 
1106 
1107 /****************************************************************
1108  *
1109  * Trait method for XmQTdialogShellSavvy trait.
1110  *
1111  **************************************************************/
1112 static void
CallMapUnmap(Widget wid,Boolean map_unmap)1113 CallMapUnmap(
1114 	 Widget wid,
1115 	 Boolean map_unmap)
1116 {
1117     ExmGridWidget grid = (ExmGridWidget) wid ;
1118     XmAnyCallbackStruct call_data;
1119 
1120     call_data.reason = (map_unmap)? XmCR_MAP : XmCR_UNMAP;
1121     call_data.event  = NULL;
1122 
1123     if (map_unmap) {
1124 	XtCallCallbackList (wid, grid->grid.map_callback,
1125 			    &call_data);
1126     } else {
1127 	XtCallCallbackList (wid, grid->grid.unmap_callback,
1128 			    &call_data);
1129     }
1130 }
1131 
1132 /*****************************************************************
1133  *
1134  * Trait method for XmQTspecifyRenderTable.
1135  *
1136 *****************************************************************/
1137 
1138 static XmRenderTable
GetTable(Widget wid,XtEnum type)1139 GetTable(
1140 	 Widget wid,
1141 	 XtEnum type)
1142 {
1143     ExmGridWidget grid = (ExmGridWidget) wid ;
1144 
1145     switch(type) {
1146     case XmLABEL_RENDER_TABLE : return grid->grid.label_render_table ;
1147     case XmBUTTON_RENDER_TABLE : return grid->grid.button_render_table ;
1148     case XmTEXT_RENDER_TABLE : return grid->grid.text_render_table ;
1149     }
1150 
1151     return NULL ;
1152 }
1153 
1154 
1155 /*******************************************************************************
1156  *
1157  *  ExmCreateGrid:
1158  *      Called by an application.
1159  *
1160  ******************************************************************************/
1161 Widget
ExmCreateGrid(Widget parent,char * name,ArgList arglist,Cardinal argcount)1162 ExmCreateGrid (
1163         Widget parent,
1164         char *name,
1165         ArgList arglist,
1166         Cardinal argcount
1167               )
1168 {
1169  /* This is a convenience function to instantiate an ExmGrid widget. */
1170    return (XtCreateWidget (name, exmGridWidgetClass, parent,
1171                            arglist, argcount));
1172 }
1173 
1174 
1175 /*******************************************************************************
1176  *
1177  *  ExmCreateGridDialog
1178  *      Called by an application to create an ExmGrid managed by a
1179  *      DialogShell.
1180  *
1181  ******************************************************************************/
1182 Widget
ExmCreateGridDialog(Widget parent,char * name,ArgList arglist,Cardinal argcount)1183 ExmCreateGridDialog (
1184         Widget parent,
1185         char *name,
1186         ArgList arglist,
1187         Cardinal argcount
1188               )
1189 {
1190    return XmeCreateClassDialog (exmGridWidgetClass,
1191                                 parent, name, arglist, argcount) ;
1192 
1193 }
1194