1 /*
2  * Motif Tools Library, Version 3.1
3  * $Id: Chooser.c,v 1.1.1.1 2001/02/10 13:41:19 motiftools Exp $
4  *
5  * Written by David Flanagan.
6  * Copyright (c) 1992-2001 by David Flanagan.
7  * All Rights Reserved.  See the file COPYRIGHT for details.
8  * This is open source software.  See the file LICENSE for details.
9  * There is no warranty for this software.  See NO_WARRANTY for details.
10  *
11  * $Log: Chooser.c,v $
12  * Revision 1.1.1.1  2001/02/10 13:41:19  motiftools
13  * Initial import of Xmt310 to CVS
14  *
15  *
16  */
17 
18 #include <stdio.h>
19 #include <string.h>
20 #include <Xmt/XmtP.h>
21 #include <Xmt/ChooserP.h>
22 #include <Xmt/Symbols.h>
23 #include <Xmt/Converters.h>
24 #include <Xmt/WidgetType.h>
25 #include <Xmt/Layout.h> /* for XmtNlayoutSensitive resource */
26 #include <Xm/Label.h>
27 #include <Xm/CascadeB.h>
28 #include <Xm/PushB.h>
29 #include <Xm/ToggleB.h>
30 #include <Xm/List.h>
31 #if XmVersion >= 2000
32 #include <Xm/ComboBox.h>
33 #endif
34 
35 static XtResource resources[] = {
36 {XmtNchooserType, XmtCChooserType, XmtRXmtChooserType,
37      sizeof(XmtChooserType), XtOffsetOf(XmtChooserRec, chooser.type),
38      XtRImmediate, (XtPointer)XmtChooserRadioBox},
39 {XmtNnumItems, XmtCNumItems, XtRInt,
40      sizeof(int), XtOffsetOf(XmtChooserRec, chooser.num_items),
41      XtRImmediate, (XtPointer) -1},
42 {XmtNstrings, XmtCStrings, XmtRStringList,
43      sizeof(String *), XtOffsetOf(XmtChooserRec, chooser.strings),
44      XmtRStringList, NULL},
45 {XmtNpixmaps, XmtCPixmaps, XmtRPixmapList,
46      sizeof(Pixmap *), XtOffsetOf(XmtChooserRec, chooser.pixmaps),
47      XmtRPixmapList, NULL},
48 {XmtNselectPixmaps, XmtCSelectPixmaps, XmtRPixmapList,
49      sizeof(Pixmap *), XtOffsetOf(XmtChooserRec, chooser.select_pixmaps),
50      XmtRPixmapList, NULL},
51 {XmtNinsensitivePixmaps, XmtCInsensitivePixmaps, XmtRPixmapList,
52      sizeof(Pixmap *), XtOffsetOf(XmtChooserRec, chooser.insensitive_pixmaps),
53      XmtRPixmapList, NULL},
54 {XmtNvalues, XmtCValues, XtRPointer,
55      sizeof(XtPointer), XtOffsetOf(XmtChooserRec, chooser.values),
56      XtRImmediate, NULL},
57 {XmtNvalueStrings, XmtCValueStrings, XmtRStringList,
58      sizeof(String *), XtOffsetOf(XmtChooserRec, chooser.value_strings),
59      XmtRStringList, NULL},
60 {XmtNvalueType, XmtCValueType, XtRString,
61      sizeof(String), XtOffsetOf(XmtChooserRec, chooser.value_type),
62      XtRString, NULL},
63 {XmtNvalueSize, XmtCValueSize, XtRInt,
64      sizeof(int), XtOffsetOf(XmtChooserRec, chooser.value_size),
65      XtRImmediate, (XtPointer) 0},
66 {XmtNfontList, XmCFontList, XmRFontList,
67      sizeof(XmFontList), XtOffsetOf(XmtChooserRec, chooser.font_list),
68      XtRImmediate, NULL},
69 #if XmVersion >= 2000
70 {XmtNrenderTable, XmCRenderTable, XmRRenderTable,
71      sizeof(XmRenderTable), XtOffsetOf(XmtChooserRec, chooser.render_table),
72      XtRImmediate, (XtPointer) NULL},
73 #endif
74 {XmtNvisibleItems, XmtCVisibleItems, XtRInt,
75      sizeof(int), XtOffsetOf(XmtChooserRec, chooser.visible_items),
76      XtRImmediate, (XtPointer) 8},
77 {XmtNstate, XmtCState, XtRInt,
78      sizeof(int), XtOffsetOf(XmtChooserRec, chooser.state),
79      XtRImmediate, (XtPointer) 0},
80 {XmtNsymbolName, XmtCSymbolName, XtRString,
81      sizeof(String), XtOffsetOf(XmtChooserRec, chooser.symbol_name),
82      XtRImmediate, NULL},
83 {XmtNlabelType, XmtCLabelType, XmRLabelType,
84      sizeof(unsigned char), XtOffsetOf(XmtChooserRec, chooser.label_type),
85      XtRImmediate, (XtPointer)XmSTRING},
86 {XmtNvalueChangedCallback, XtCCallback, XtRCallback,
87      sizeof(XtCallbackList), XtOffsetOf(XmtChooserRec, chooser.callback),
88      XtRCallback, NULL},
89 {XmtNitemWidgets, XtCReadOnly, XtRWidgetList,
90      sizeof(WidgetList), XtOffsetOf(XmtChooserRec, chooser.item_widgets),
91      XtRImmediate, NULL},
92 /*
93  * override defaults for some RowColumn resources
94  */
95 {XmNadjustLast, XmCAdjustLast, XtRBoolean,
96      sizeof(Boolean), XtOffsetOf(XmtChooserRec, row_column.adjust_last),
97      XtRImmediate, (XtPointer) False},
98 {XmNpacking, XmCPacking, XmRPacking,
99      sizeof(unsigned char), XtOffsetOf(XmtChooserRec, row_column.packing),
100      XtRImmediate, (XtPointer) XmPACK_COLUMN},
101 
102 };
103 
104 #if NeedFunctionPrototypes
105 static void ClassInitialize(void);
106 static void ClassPartInitialize(WidgetClass);
107 static void Initialize(Widget, Widget, ArgList, Cardinal *);
108 static void Destroy(Widget);
109 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
110 #else
111 static void ClassInitialize();
112 static void ClassPartInitialize();
113 static void Initialize();
114 static void Destroy();
115 static Boolean SetValues();
116 #endif
117 
118 #define Superclass (&xmRowColumnClassRec)
119 
120 externaldef(xmtchooserclassrec) XmtChooserClassRec xmtChooserClassRec = {  {
121     /* core_class fields */
122     /* superclass         */    (WidgetClass) Superclass,
123     /* class_name         */    "XmtChooser",
124     /* widget_size        */    sizeof(XmtChooserRec),
125     /* class_initialize   */    ClassInitialize,
126     /* class_part_init    */    ClassPartInitialize,
127     /* class_inited       */    FALSE,
128     /* initialize         */    Initialize,
129     /* initialize_hook    */    NULL,
130     /* realize            */    XtInheritRealize,
131     /* actions            */    NULL,
132     /* num_actions        */    0,
133     /* resources          */    resources,
134     /* num_resources      */    XtNumber(resources),
135     /* xrm_class          */    NULLQUARK,
136     /* compress_motion    */    TRUE,
137     /* compress_exposure  */    XtExposeCompressMaximal,
138     /* compress_enterleave*/    FALSE,
139     /* visible_interest   */    FALSE,
140     /* destroy            */    Destroy,
141     /* resize             */    XtInheritResize,
142     /* expose             */    XtInheritExpose,
143     /* set_values         */    SetValues,
144     /* set_values_hook    */    NULL,
145     /* set_values_almost  */    XtInheritSetValuesAlmost,
146     /* get_values_hook    */    NULL,
147     /* accept_focus       */    XtInheritAcceptFocus,
148     /* version            */    XtVersion,
149     /* callback_private   */    NULL,
150     /* tm_table           */    XtInheritTranslations,
151     /* query_geometry     */    XtInheritQueryGeometry,
152     /* display_accelerator*/    XtInheritDisplayAccelerator,
153     /* extension          */    NULL
154   },
155   { /* composite_class fields */
156     /* geometry_manager   */    XtInheritGeometryManager,
157     /* change_managed     */    XtInheritChangeManaged,
158     /* insert_child       */    XtInheritInsertChild,
159     /* delete_child       */    XtInheritDeleteChild,
160     /* extension          */    NULL
161   },
162   { /* constraint_class fields */
163     /* resource list 	  */    NULL,
164     /* num resources	  */    0,
165     /* constraint size    */    sizeof(XmRowColumnConstraintRec),
166     /* init proc	  */    NULL,
167     /* destroy proc       */    NULL,
168     /* set values proc    */    NULL,
169     /* extension 	  */    NULL
170   },
171   { /* manager_class	  */
172     /* translations 	  */    XtInheritTranslations,
173     /* syn_resources	  */	NULL,
174     /* num_syn_resources  */	0,
175     /* syn_cont_resources */	NULL,
176     /* num_syn_cont_resources */0,
177     /* parent_process     */    XmInheritParentProcess,
178     /* extension	  */	NULL
179   },
180   { /* row column class record        */
181     /* proc to interface with widgets */   XmInheritMenuProc,
182     /* proc to arm&activate menu      */   XmInheritArmAndActivate,
183     /* traversal handler              */   XmInheritMenuTraversalProc,
184     /* extension                      */   NULL,
185   },
186   { /* XmtChooser          */
187     /* extension	  */    NULL
188   }
189 };
190 
191 externaldef(xmtchooserwidgetclass) WidgetClass xmtChooserWidgetClass =
192     (WidgetClass)&xmtChooserClassRec;
193 
194 
195 #if NeedFunctionPrototypes
SetStateOnWidgets(XmtChooserWidget cw)196 static void SetStateOnWidgets(XmtChooserWidget cw)
197 #else
198 static void SetStateOnWidgets(cw)
199 XmtChooserWidget cw;
200 #endif
201 {
202     int i, bit;
203 
204     /*
205      * update the subwidgets to reflect the current state.  Don't touch
206      * the symbol value or call callbacks.
207      */
208 
209     if (cw->chooser.num_items == 0) return;
210 
211     if (cw->chooser.type == XmtChooserRadioList) {
212 	XmListDeselectAllItems(cw->chooser.list);
213 	XmListSelectPos(cw->chooser.list, cw->chooser.state+1, False);
214     }
215 #if XmVersion >= 2000
216     else if (cw->chooser.type == XmtChooserComboBox) {
217         XtVaSetValues(cw->chooser.combo_box,
218                       XmNselectedPosition,      cw->chooser.state+1,
219                       NULL);
220     }
221 #endif
222     else if (cw->chooser.type == XmtChooserCheckList) {
223 	XmListDeselectAllItems(cw->chooser.list);
224 	for(i=0, bit = 1; i < cw->chooser.num_items; i++, bit = bit << 1)
225 	    if (cw->chooser.state & bit)
226 		XmListSelectPos(cw->chooser.list, i+1, False);
227     }
228     else if (cw->chooser.type == XmtChooserOption) {
229 	/* XXX this may not work before Motif 1.1.4 */
230 	XtVaSetValues(cw->chooser.option,
231 		      XmNmenuHistory,
232 		      cw->chooser.item_widgets[cw->chooser.state],
233 		      NULL);
234     }
235     else if ((cw->chooser.type == XmtChooserCheckBox) ||
236 	     (cw->chooser.type == XmtChooserCheckPalette)) {
237 	for(i=0, bit = 1; i < cw->chooser.num_items; i++, bit = bit << 1)
238 	    if (cw->chooser.state & bit)
239 		XmToggleButtonSetState(cw->chooser.item_widgets[i],
240 				       True, False);
241 	    else
242 		XmToggleButtonSetState(cw->chooser.item_widgets[i],
243 				       False, False);
244     }
245     else if ((cw->chooser.type == XmtChooserRadioBox) ||
246 	     (cw->chooser.type == XmtChooserRadioPalette)) {
247 	for(i=0; i < cw->chooser.num_items; i++)
248 	    XmToggleButtonSetState(cw->chooser.item_widgets[i], False, False);
249 	XmToggleButtonSetState(cw->chooser.item_widgets[cw->chooser.state],
250 			       True, False);
251     }
252     else {  /* a button box; it doesn't have state */
253 	;
254     }
255 }
256 
257 /* ARGSUSED */
258 #if NeedFunctionPrototypes
ChooserCallback(Widget w,XtPointer tag,XtPointer data)259 static void ChooserCallback(Widget w, XtPointer tag, XtPointer data)
260 #else
261 static void ChooserCallback(w, tag, data)
262 Widget w;
263 XtPointer tag;
264 XtPointer data;
265 #endif
266 {
267     XmtChooserWidget cw = (XmtChooserWidget) tag;
268     XmListCallbackStruct *listdata = (XmListCallbackStruct *) data;
269 #if XmVersion >= 2000
270     XmComboBoxCallbackStruct *combodata = (XmComboBoxCallbackStruct *) data;
271 #endif
272     XmtChooserCallbackStruct call_data;
273     int i;
274 
275     /*
276      * Figure out and record the new state of the Chooser.
277      * Enforce RadioBox behavior where required.
278      * Enforce sensitivity where required (in list widgets).
279      * Update the symbol value, if a symbol was specified.
280      * Invoke the callback that was registered with this Chooser, if it exists.
281      */
282 
283     /*
284      * if a list, check sensitivity.  If the item that was
285      * clicked on is insensitive, restore the old state and return
286      */
287     if ((cw->chooser.type == XmtChooserRadioList) ||
288 	(cw->chooser.type == XmtChooserCheckList)) {
289 	if (cw->chooser.insensitive & (1 << (listdata->item_position-1))) {
290 	    SetStateOnWidgets(cw);
291 	    return;
292 	}
293     }
294 #if XmVersion >= 2000
295     else if (cw->chooser.type == XmtChooserComboBox) {
296 	if (cw->chooser.insensitive & (1 << (combodata->item_position-1))) {
297 	    SetStateOnWidgets(cw);
298 	    return;
299 	}
300     }
301 #endif
302 
303     if (cw->chooser.type == XmtChooserRadioList) {
304 	/* list  positions start numbering from 1 */
305 	call_data.item = call_data.state = cw->chooser.state =
306 	    listdata->item_position - 1;
307     }
308 #if XmVersion >= 2000
309     else if (cw->chooser.type == XmtChooserComboBox) {
310 	/* list  positions start numbering from 1 */
311 	call_data.item = call_data.state = cw->chooser.state =
312 	    combodata->item_position - 1;
313     }
314 #endif
315     else if (cw->chooser.type == XmtChooserCheckList) {
316 	cw->chooser.state = 0;
317 	for(i=0; i < listdata->selected_item_count; i++)
318 	    cw->chooser.state |= (1<<(listdata->selected_item_positions[i]-1));
319 	call_data.state = cw->chooser.state;
320 	call_data.item = listdata->item_position;
321     }
322     else {
323 	/* figure out which button was pressed */
324 	for(i = 0; i < cw->chooser.num_items; i++)
325 	    if (cw->chooser.item_widgets[i] == w) break;
326 	if (i == cw->chooser.num_items) return;  /* just in case */
327 	call_data.item = i;
328 	if ((cw->chooser.type == XmtChooserCheckBox) ||
329 	    (cw->chooser.type == XmtChooserCheckPalette)) {
330 	    cw->chooser.state ^= (1 << i);
331 	    call_data.state = cw->chooser.state;
332 	}
333 	else if ((cw->chooser.type == XmtChooserRadioBox) ||
334 	    (cw->chooser.type == XmtChooserRadioPalette)) {
335 	    /*
336 	     * if user clicked on an already selected item, reselect it
337 	     * otherwise unselect the old selected item.
338 	     */
339 	    if (cw->chooser.state == i)
340 		XmToggleButtonSetState(w, True, False);
341 	    else
342 		XmToggleButtonSetState(cw->chooser.item_widgets
343 				       [cw->chooser.state],
344 				       False,False);
345 	    cw->chooser.state = call_data.state = i;
346 	}
347 	else if (cw->chooser.type == XmtChooserOption)
348 	    cw->chooser.state = call_data.state = i;
349 	else  /* button box */
350 	    call_data.state = -1;
351     }
352 
353     /*
354      * update the symbol value, if we have one.
355      * set a flag that tells our own symbol notify callback that the
356      * widgets are already in the correct state and it need not do
357      * anything.
358      */
359     if (cw->chooser.symbol) {
360 	cw->chooser.ignore_symbol_notify = True;
361 	XmtSymbolSetValue(cw->chooser.symbol, (XtArgVal)cw->chooser.state);
362 	cw->chooser.ignore_symbol_notify = False;
363     }
364 
365     /*
366      * figure out the call_data.valuep, if we have values set.
367      */
368     if (cw->chooser.values)
369 	call_data.valuep = (XtPointer) &((char *)cw->chooser.values)
370 	    [call_data.item * cw->chooser.value_size];
371     else
372 	call_data.valuep = NULL;
373 
374     /* invoke the callbacks registered for this Chooser */
375     XtCallCallbackList((Widget)cw, cw->chooser.callback,(XtPointer)&call_data);
376 }
377 
378 #if NeedFunctionPrototypes
SetStateOnSymbol(XmtChooserWidget cw)379 static void SetStateOnSymbol(XmtChooserWidget cw)
380 #else
381 static void SetStateOnSymbol(cw)
382 XmtChooserWidget cw;
383 #endif
384 {
385     /*
386      * set the symbol state.  This will cause the notify callbacks to
387      * be invoked, which in our case will call SetStateOnWidgets.
388      * So if you call this function, don't call SetStateOnWidgets.
389      */
390     if (cw->chooser.symbol)
391 	XmtSymbolSetValue(cw->chooser.symbol, (XtArgVal)cw->chooser.state);
392 }
393 
394 
395 /* ARGSUSED */
396 #if NeedFunctionPrototypes
ValueChanged(XmtSymbol s,XtPointer tag,XtArgVal value)397 static void ValueChanged(XmtSymbol s, XtPointer tag, XtArgVal value)
398 #else
399 static void ValueChanged(s, tag, value)
400 XmtSymbol s;
401 XtPointer tag;
402 XtArgVal value;
403 #endif
404 {
405     XmtChooserWidget cw = (XmtChooserWidget)tag;
406 
407     /*
408      * update the widget's internal and  displayed state when the symbol value
409      * changes from underneath us.  Note that we do not call the
410      * valueChangedCallback; this is only called when the user changes the
411      * state by interacting with the widget.  Also, it prevents us from
412      * getting into a loop.
413      *
414      * We don't do anything if the ignore flag is set.  This is the case
415      * when the user interacts with the widget to change the state--the widget
416      * state and the subwidgets are already correct, the symbol is updated
417      * and the notify callbacks are called to notify anyone else who cares
418      * about the symbol.
419      */
420 
421     if (cw->chooser.ignore_symbol_notify) return;
422 
423     cw->chooser.state = (int) value;
424     SetStateOnWidgets(cw);
425 }
426 
427 
428 #if NeedFunctionPrototypes
BindSymbol(XmtChooserWidget cw)429 static void BindSymbol(XmtChooserWidget cw)
430 #else
431 static void BindSymbol(cw)
432 XmtChooserWidget cw;
433 #endif
434 {
435     if (cw->chooser.symbol_name) {
436 	cw->chooser.symbol = XmtLookupSymbol(cw->chooser.symbol_name);
437 	if (cw->chooser.symbol) {
438 	    if (XmtSymbolSize(cw->chooser.symbol)!=sizeof(cw->chooser.state)) {
439 		XmtWarningMsg("XmtChooser", "symbolSize",
440 			     "%s: symbol '%s' has wrong size;\n\tshould be int.",
441 			      XtName((Widget)cw), cw->chooser.symbol_name);
442 		cw->chooser.symbol = NULL;
443 	    }
444 	    else {
445 		XmtSymbolAddCallback(cw->chooser.symbol,
446 				     ValueChanged, (XtPointer)cw);
447 		XmtSymbolGetValue(cw->chooser.symbol,
448 				  (XtArgVal*) &cw->chooser.state);
449 	    }
450 	}
451 	else {
452 	    XmtWarningMsg("XmtChooser", "badSymbol",
453 			  "%s: symbol '%s' is undefined.",
454 			  XtName((Widget)cw), cw->chooser.symbol_name);
455 	}
456     }
457     else
458 	cw->chooser.symbol = NULL;
459 }
460 
461 
462 #if NeedFunctionPrototypes
ReleaseSymbol(XmtChooserWidget cw)463 static void ReleaseSymbol(XmtChooserWidget cw)
464 #else
465 static void ReleaseSymbol(cw)
466 XmtChooserWidget cw;
467 #endif
468 {
469     if (cw->chooser.symbol) {
470 	XmtSymbolRemoveCallback(cw->chooser.symbol,
471 				ValueChanged, (XtPointer)cw);
472 	cw->chooser.symbol = NULL;
473     }
474 }
475 
476 #if NeedFunctionPrototypes
CheckType(XmtChooserWidget cw)477 static void CheckType(XmtChooserWidget cw)
478 #else
479 static void CheckType(cw)
480 XmtChooserWidget cw;
481 #endif
482 {
483     /* if this is a check box, then we can't have values */
484     if ((cw->chooser.type == XmtChooserCheckBox) ||
485 	(cw->chooser.type == XmtChooserCheckPalette) ||
486 	(cw->chooser.type == XmtChooserCheckList)) {
487 	XmtWarningMsg("XmtChooser", "badType",
488 		      "%s: XmtNvalues and XmtNvalueStrings resources ignored\n\twhen XmtNchooserType is CheckBox, CheckPalette or CheckList",
489 		      XtName((Widget)cw));
490 	cw->chooser.values = NULL;
491 	cw->chooser.value_strings = NULL;
492 	return;
493     }
494 
495     /* also check that value type and size are set */
496     if (!cw->chooser.value_type  || !cw->chooser.value_size) {
497 	XmtWarningMsg("XmtChooser", "badValues",
498 		      "%s: can't set XmtNvalues or XmtNvalueStrings without\n\talso setting XmtNvalueType and XmtNvalueSize resources",
499 		      XtName((Widget)cw));
500 	cw->chooser.values = NULL;
501 	cw->chooser.value_strings = NULL;
502     }
503 }
504 
505 #if NeedFunctionPrototypes
CopyValues(XmtChooserWidget cw)506 static void CopyValues(XmtChooserWidget cw)
507 #else
508 static void CopyValues(cw)
509 XmtChooserWidget cw;
510 #endif
511 {
512     char *values;
513     int size = cw->chooser.num_items * cw->chooser.value_size;
514 
515     /* if XmtNvalues is set, be sure to ignore XmtNvalueStrings */
516     cw->chooser.value_strings = NULL;
517 
518     values = XtMalloc(size);
519     memcpy(values, (char *)cw->chooser.values, size);
520     cw->chooser.values = (XtPointer) values;
521 }
522 
523 #if NeedFunctionPrototypes
ConvertValueStrings(XmtChooserWidget cw)524 static void ConvertValueStrings(XmtChooserWidget cw)
525 #else
526 static void ConvertValueStrings(cw)
527 XmtChooserWidget cw;
528 #endif
529 {
530     char *values;
531     XrmValue from, to;
532     Boolean status;
533     int i;
534 
535     values = XtCalloc(cw->chooser.num_items, cw->chooser.value_size);
536 
537     /* String values are a special case; no conversion required */
538     if (strcmp(cw->chooser.value_type, XtRString) == 0) {
539 	for(i=0; i < cw->chooser.num_items; i++)
540 	    ((String *)values)[i] = cw->chooser.value_strings[i];
541     }
542     else{
543 	for(i=0; i < cw->chooser.num_items; i++) {
544 	    from.addr = cw->chooser.value_strings[i];
545 	    from.size = strlen(cw->chooser.value_strings[i]) + 1;
546 	    to.addr = &values[i * cw->chooser.value_size];
547 	    to.size = cw->chooser.value_size;
548 	    status = XtConvertAndStore((Widget)cw, XtRString, &from,
549 				       cw->chooser.value_type, &to);
550 	    if (!status) {
551 		XmtWarningMsg("XmtChooser", "convert",
552 			      "%s: conversion failed for item %d of XmtNvalueStrings",
553 			      XtName((Widget)cw), i);
554 	    }
555 	    else if (to.size != cw->chooser.value_size) {
556 		XmtWarningMsg("XmtChooser", "badSize",
557 			      "%s: size of converted values not equal to XmtNvalueSize",
558 			      XtName((Widget)cw));
559 		XtFree(values);
560 		values = NULL;
561 		break;
562 	    }
563 	}
564     }
565 
566     cw->chooser.values = values;
567     /*
568      * we set value_strings to NULL, because we're not making a copy of them,
569      * and so we'll notice a change if the programmer specifies the same
570      * array with different values in it.  This means that querying this
571      * resource doesn't make sense.
572      */
573     cw->chooser.value_strings = NULL;
574 }
575 
576 
577 #if NeedFunctionPrototypes
ClassInitialize(void)578 static void ClassInitialize(void)
579 #else
580 static void ClassInitialize()
581 #endif
582 {
583     static String names[] = {
584 	"ButtonBox", "CheckBox", "CheckList", "CheckPalette",
585 #if XmVersion >= 2000
586         "ComboBox",
587 #endif
588 	"Option", "RadioBox", "RadioList", "RadioPalette"
589     };
590     static int values[] = {
591 	XmtChooserButtonBox, XmtChooserCheckBox, XmtChooserCheckList,
592 	XmtChooserCheckPalette,
593 #if XmVersion >= 2000
594         XmtChooserComboBox,
595 #endif
596         XmtChooserOption, XmtChooserRadioBox,
597 	XmtChooserRadioList, XmtChooserRadioPalette
598     };
599     static String prefixes[] = {"Xmt", "Chooser", NULL};
600 
601     XmtRegisterStringListConverter();
602     XmtRegisterEnumConverter(XmtRXmtChooserType, names, values,
603 			     XtNumber(names), prefixes);
604 }
605 
606 #if NeedFunctionPrototypes
ClassPartInitialize(WidgetClass subclass)607 static void ClassPartInitialize(WidgetClass subclass)
608 #else
609 static void ClassPartInitialize(subclass)
610 WidgetClass subclass;
611 #endif
612 {
613     XmtChooserWidgetClass sub = (XmtChooserWidgetClass)subclass;
614     XmtChooserWidgetClass sup =
615 	(XmtChooserWidgetClass)sub->core_class.superclass;
616 
617     /*
618      * the XmtChooser widget doesn't have any class fields that need
619      * inheritance, but the XmRowColumn does, and that widget does not
620      * handle the inheritance itself.  So we do it here.
621      */
622 #define inherit(field) \
623     if ((XtProc)sub->field == _XtInherit) sub->field = sup->field
624 
625      inherit(row_column_class.menuProcedures);
626      inherit(row_column_class.armAndActivate);
627      inherit(row_column_class.traversalHandler);
628 
629 #undef inherit
630 }
631 
632 /* ARGSUSED */
633 #if NeedFunctionPrototypes
Initialize(Widget request,Widget init,ArgList arglist,Cardinal * num_args)634 static void Initialize(Widget request, Widget init,
635 		       ArgList arglist, Cardinal *num_args)
636 #else
637 static void Initialize(request, init, arglist, num_args)
638 Widget request;
639 Widget init;
640 ArgList arglist;
641 Cardinal *num_args;
642 #endif
643 {
644     XmtChooserWidget nw = (XmtChooserWidget) init;
645     String *array;
646     Pixmap *p;
647     XmString *item_labels = NULL;
648     char namebuf[200];
649     Arg args[10];
650     int i,j;
651 #if XmVersion >= 2000
652     int len;
653     short num_columns;
654 #endif
655 
656     /* lists can't have pixmaps */
657 #if XmVersion < 2000
658     if ((nw->chooser.label_type == XmPIXMAP) &&
659 	((nw->chooser.type == XmtChooserRadioList) ||
660 	 (nw->chooser.type == XmtChooserCheckList))) {
661 #else /* Motif 2.0 or later */
662     if ((nw->chooser.label_type == XmPIXMAP) &&
663 	((nw->chooser.type == XmtChooserRadioList) ||
664 	 (nw->chooser.type == XmtChooserCheckList) ||
665          (nw->chooser.type == XmtChooserComboBox))) {
666 #endif
667 	nw->chooser.label_type = XmSTRING;
668 	XmtWarningMsg("XmtChooser", "pixmapType",
669 		      "%s: XmtNlabelType must be XmSTRING for XmList types.",
670 		      XtName((Widget)nw));
671     }
672 
673     /*
674      * Palettes have zero spacing.  This is a dynamic default resource,
675      * so we can't just override it.  RowCol may do some special processing
676      * on it, so we don't just set it directly.
677      */
678     if ((nw->chooser.type == XmtChooserRadioPalette) ||
679 	(nw->chooser.type == XmtChooserCheckPalette))
680 	XtVaSetValues(init, XmNspacing, 0, NULL);
681 
682 #if XmVersion < 2000
683     /* get the default font from an ancestor font list if none set. */
684     if (nw->chooser.font_list == NULL)
685         nw->chooser.font_list = _XmGetDefaultFontList(init, XmBUTTON_FONTLIST);
686 
687     /* make a private copy of the font list */
688     nw->chooser.font_list = XmFontListCopy(nw->chooser.font_list);
689 
690 #else /* Motif 2.0 or later */
691 
692     if (!nw->chooser.render_table) {
693         if (nw->chooser.font_list) {
694             /*
695              * There is a fontList, so copy it to the renderTable.
696              * NOTE: This code relies on the fact that there is no
697              *       disitinction between a fontList and a renderTable
698              *       in Motif 2.0.
699              */
700             nw->chooser.render_table = XmFontListCopy(nw->chooser.font_list);
701         }
702         else {
703            /*
704             * Nothing was specified, so look up the default
705             * renderTable.
706             */
707             nw->chooser.render_table =
708                 XmeGetDefaultRenderTable(init, XmBUTTON_FONTLIST);
709 
710             /* Make a copy of the renderTable. */
711             nw->chooser.render_table =
712                 XmRenderTableCopy(nw->chooser.render_table, NULL, 0);
713         }
714     }
715     else {
716         /* Make a copy of the renderTable. */
717         nw->chooser.render_table =
718             XmRenderTableCopy(nw->chooser.render_table, NULL, 0);
719     }
720 #endif
721 
722     /*
723      * if we're insensitve, set layoutSensitive, in case we're a child
724      * of a layout and have a caption
725      */
726     if (!nw->core.sensitive || !nw->core.ancestor_sensitive)
727 	XtVaSetValues(init, XmtNlayoutSensitive, False, NULL);
728 
729     /*
730      * Count the strings or pixmaps.
731      * The strings resource may be NULL terminated at this point, or it may
732      * not be.  If num_items is -1 (ie. unspecified) then it had better be
733      * NULL-terminated.  The resource converter delivers a NULL-terminated
734      * array, but most programmers will probably use counted arrays.  It is
735      * also possible that strings is NULL-terminated at less than num_items.
736      * So figure out num_items.
737      */
738     if (nw->chooser.label_type == XmSTRING)
739 	array = nw->chooser.strings;
740     else
741 	array = (String *)nw->chooser.pixmaps;
742 
743     if (array != NULL) {
744 	if (nw->chooser.num_items == -1) /* if unspecified look for a NULL */
745 	    for(i=0; array[i]; i++);
746 	else                         /* if specified, look for a NULL anyway */
747 	    for(i=0; i < nw->chooser.num_items && array[i]; i++);
748 	nw->chooser.num_items = i;
749     }
750     else /* if no strings are specified */
751 	nw->chooser.num_items = 0;
752 
753     /*
754      * Now copy the array of strings and the arrays of pixmaps.
755      * We copy all arrays, regardless of mode.
756      * We copy the array, but not the strings in it.
757      * While copying the selected and insensitive pixmaps we count them, too.
758      */
759     if (nw->chooser.strings != NULL) {
760 	array = (String *)XtMalloc(nw->chooser.num_items*sizeof(String));
761 	for(i=0; i < nw->chooser.num_items; i++) {
762 	    if (nw->chooser.strings[i] == NULL) break;
763 	    array[i] = nw->chooser.strings[i];
764 	}
765 	for(; i < nw->chooser.num_items; i++) array[i] = NULL;
766 	nw->chooser.strings = array;
767     }
768 
769     if (nw->chooser.pixmaps != NULL) {
770 	p = (Pixmap *)XtMalloc(nw->chooser.num_items*sizeof(Pixmap));
771 	for(i=0; i < nw->chooser.num_items; i++) {
772 	    if (nw->chooser.pixmaps[i] == None) break;
773 	    p[i] = nw->chooser.pixmaps[i];
774 	}
775 	for(; i < nw->chooser.num_items; i++) p[i] = XmUNSPECIFIED_PIXMAP;
776 	nw->chooser.pixmaps = p;
777     }
778 
779     if (nw->chooser.select_pixmaps != NULL) {
780 	p = (Pixmap *)XtMalloc(nw->chooser.num_items*sizeof(Pixmap));
781 	for(i=0; i < nw->chooser.num_items; i++) {
782 	    if (nw->chooser.select_pixmaps[i] == None) break;
783 	    p[i] = nw->chooser.select_pixmaps[i];
784 	}
785 	for(; i < nw->chooser.num_items; i++) p[i] = XmUNSPECIFIED_PIXMAP;
786 	nw->chooser.select_pixmaps = p;
787     }
788 
789     if (nw->chooser.insensitive_pixmaps != NULL) {
790 	p = (Pixmap *)XtMalloc(nw->chooser.num_items*sizeof(Pixmap));
791 	for(i=0; i < nw->chooser.num_items; i++) {
792 	    if (nw->chooser.insensitive_pixmaps[i] == None) break;
793 	    p[i] = nw->chooser.insensitive_pixmaps[i];
794 	}
795 	for(; i < nw->chooser.num_items; i++) p[i] = XmUNSPECIFIED_PIXMAP;
796 	nw->chooser.insensitive_pixmaps = p;
797     }
798 
799     /*
800      * if values or valueStrings is set, make sure that the type is okay,
801      * and make sure we have a size and type
802      */
803     if (nw->chooser.values || nw->chooser.value_strings)
804 	CheckType(nw);
805 
806     /*
807      * if values is set, copy the array.
808      * otherwise, if values is not set, but valueStrings is,
809      * convert the strings, and store in values.  We don't copy
810      * valueStrings, because we'll never need to referece it again,
811      * but we set it to NULL, so we can detect when it changes.
812      */
813     if (nw->chooser.values) CopyValues(nw);
814     else if (nw->chooser.value_strings) ConvertValueStrings(nw);
815 
816     /* create the label XmStrings in string mode */
817     if (nw->chooser.label_type == XmSTRING) {
818 	item_labels = (XmString *)
819 	    XtMalloc(nw->chooser.num_items*sizeof(XmString));
820 	for(i = 0; i < nw->chooser.num_items; i++)
821 	    item_labels[i] = XmtCreateXmString(nw->chooser.strings[i]);
822     }
823 
824     /*
825      * Create the widgets.  Option menus are handled separately.
826      */
827     if (nw->chooser.type == XmtChooserOption) {
828 	/*
829 	 * In order to create an Option menu, we have to create the
830 	 * menu pane first before the cascade button and label.
831 	 * The menu shell is automatically created, and
832 	 * its name is not publicly documented.
833 	 */
834 	i = 0;
835 	nw->chooser.pane = XmCreatePulldownMenu(init, "pane", NULL, 0);
836 	XtSetArg(args[i], XmNsubMenuId, nw->chooser.pane); i++;
837 	nw->chooser.option = XmCreateOptionMenu(init, "option", args, i);
838 #if XmVersion >= 1002
839 	/*
840 	 * In Motif 1.2.0, a NULL option label string gives an option menu
841 	 * with some bogus widget name as the label, so we just unmanage
842 	 * the label altogether.  We don't do this in 1.1.4, because
843 	 * with ICS 1.1.4, at least, the option menu doesn't shrink; it
844 	 * continues to allocate space for the label gadget.
845 	 */
846 	XtUnmanageChild(XmOptionLabelGadget(nw->chooser.option));
847 #endif
848 	XtManageChild(nw->chooser.option);
849 #if XmVersion < 2000
850 	XtVaSetValues(XmOptionButtonGadget(nw->chooser.option),
851 		      XmNfontList, nw->chooser.font_list,
852 		      NULL);
853 #else /* Motif 2.0 or later */
854 	XtVaSetValues(XmOptionButtonGadget(nw->chooser.option),
855 		      XmNrenderTable, nw->chooser.render_table,
856 		      NULL);
857 #endif
858     }
859     else if ((nw->chooser.type == XmtChooserRadioList) ||
860 	     (nw->chooser.type == XmtChooserCheckList)) {
861 	i = 0;
862 	XtSetArg(args[i], XmNitems, item_labels); i++;
863 #if XmVersion < 2000
864 	XtSetArg(args[i], XmNfontList, nw->chooser.font_list); i++;
865 #else /* Motif 2.0 or later */
866 	XtSetArg(args[i], XmNrenderTable, nw->chooser.render_table); i++;
867 #endif
868 	XtSetArg(args[i], XmNitemCount, nw->chooser.num_items); i++;
869 	XtSetArg(args[i], XmNvisibleItemCount, nw->chooser.visible_items); i++;
870 	XtSetArg(args[i], XmNselectionPolicy,
871 		 ((nw->chooser.type==XmtChooserRadioList)
872 		  ? XmBROWSE_SELECT : XmMULTIPLE_SELECT)); i++;
873 	nw->chooser.list =
874 	    XmCreateScrolledList(init, "list", args, i);
875 	if (nw->chooser.type == XmtChooserRadioList)
876 	    XtAddCallback(nw->chooser.list, XmNbrowseSelectionCallback,
877 			  ChooserCallback, (XtPointer) nw);
878 	else
879 	    XtAddCallback(nw->chooser.list, XmNmultipleSelectionCallback,
880 			  ChooserCallback, (XtPointer) nw);
881 
882 	    XtManageChild(nw->chooser.list);
883     }
884 #if XmVersion >= 2000
885     else if (nw->chooser.type == XmtChooserComboBox) {
886 	i = 0;
887 	XtSetArg(args[i], XmNitems, item_labels); i++;
888 	XtSetArg(args[i], XmNrenderTable, nw->chooser.render_table); i++;
889 	XtSetArg(args[i], XmNitemCount, nw->chooser.num_items); i++;
890 
891         /*
892          * ComboBoxes look funny with blank space at the bottom, so
893          * if the actual number of items is smaller than the visible
894          * items resource, we override the visible item count.
895          */
896         if (nw->chooser.visible_items > nw->chooser.num_items)
897            nw->chooser.visible_items = nw->chooser.num_items;
898 	XtSetArg(args[i], XmNvisibleItemCount, nw->chooser.visible_items); i++;
899 
900         XtSetArg(args[i], XmNcomboBoxType, XmDROP_DOWN_LIST); i++;
901         XtSetArg(args[i], XmNmatchBehavior, XmQUICK_NAVIGATE); i++;
902 
903         /*
904          * ComboBoxes do not automatically size themselves based on
905          * their contents.  We therefore change the width manually to
906          * match the widest item.
907          */
908         num_columns = 0;
909 	for(j=0; j < nw->chooser.num_items; j++)  {
910             len = strlen(nw->chooser.strings[j]);
911             if (len > num_columns)
912                num_columns = len;
913         }
914         XtSetArg(args[i], XmNcolumns, num_columns); i++;
915 
916         nw->chooser.combo_box =
917             XmCreateComboBox(init, "combobox", args, i);
918 
919         XtAddCallback(nw->chooser.combo_box, XmNselectionCallback,
920                       ChooserCallback, (XtPointer) nw);
921 
922         /*
923          * Get the list widget that was created as part of the ComboBox
924          * so we can manipulate it directly.
925          */
926         nw->chooser.list = XmtNameToWidget(nw->chooser.combo_box, "*List");
927 
928         XtManageChild(nw->chooser.combo_box);
929     }
930 #endif
931 
932     /* If it is not a List widget, go create the internal buttons */
933 #if XmVersion < 2000
934     if ((nw->chooser.type != XmtChooserRadioList) &&
935 	(nw->chooser.type != XmtChooserCheckList)) {
936 #else /* Motif 2.0 or later */
937     if ((nw->chooser.type != XmtChooserRadioList) &&
938 	(nw->chooser.type != XmtChooserCheckList) &&
939         (nw->chooser.type != XmtChooserComboBox)) {
940 #endif
941 	int ac;
942 	Widget parent;
943 
944 	/* For a menu, parent is pane; otherwise self */
945 	if (nw->chooser.type == XmtChooserOption)
946 	    parent = nw->chooser.pane;
947 	else
948 	    parent = (Widget) nw;
949 
950 	/* set up the fixed arguments */
951 	i = 0;
952 	XtSetArg(args[i], XmNlabelType, nw->chooser.label_type); i++;
953 #if XmVersion < 2000
954 	XtSetArg(args[i], XmNfontList, nw->chooser.font_list); i++;
955 #else /* Motif 2.0 or later */
956 	XtSetArg(args[i], XmNrenderTable, nw->chooser.render_table); i++;
957 #endif
958 	if ((nw->chooser.type != XmtChooserButtonBox) &&
959 	    (nw->chooser.type != XmtChooserOption)) {
960 	    XtSetArg(args[i], XmNset, False); i++;
961 	    if (nw->chooser.type == XmtChooserCheckBox) {
962 		XtSetArg(args[i], XmNindicatorType, XmN_OF_MANY); i++;
963 	    }
964 	    else if (nw->chooser.type == XmtChooserRadioBox) {
965 #if XmVersion < 2000
966 		XtSetArg(args[i], XmNindicatorType, XmONE_OF_MANY); i++;
967 #else /* Motif 2.0 or later */
968                 Boolean enable_toggle_visual;
969                 XtVaGetValues(XmGetXmDisplay(XtDisplay((Widget) nw)),
970                               XmNenableToggleVisual, &enable_toggle_visual,
971                               NULL);
972 
973                 if (!enable_toggle_visual) {
974 		    XtSetArg(args[i], XmNindicatorType, XmONE_OF_MANY); i++;
975 		}
976                 else {
977 		    XtSetArg(args[i], XmNindicatorType, XmONE_OF_MANY_ROUND);
978 		    i++;
979 		}
980 #endif
981 	    }
982 	    else if ((nw->chooser.type == XmtChooserRadioPalette) ||
983 		     (nw->chooser.type == XmtChooserCheckPalette)) {
984 		XtSetArg(args[i], XmNindicatorOn, False); i++;
985 		XtSetArg(args[i], XmNshadowThickness, 2); i++;
986 		/* XXX shadow thickness should not be hardcoded. */
987 	    }
988 	}
989 
990 	/* remember the number of fixed arguments */
991 	ac = i;
992 
993 	/* create an array to hold the widgets we create */
994 	nw->chooser.item_widgets = (Widget *)
995 	    XtMalloc(nw->chooser.num_items * sizeof(Widget));
996 
997 	/* set up the label arg(s) and create the widgets */
998 	for(j = 0; j < nw->chooser.num_items; j++) {
999 	    i = ac;
1000 	    sprintf(namebuf, "item%d", j);
1001 	    if (nw->chooser.label_type == XmSTRING) {
1002 		XtSetArg(args[i], XmNlabelString, item_labels[j]);
1003 		i++;
1004 	    }
1005 	    else {
1006 		XtSetArg(args[i], XmNlabelPixmap, nw->chooser.pixmaps[j]); i++;
1007 		if (nw->chooser.select_pixmaps) {
1008 		    XtSetArg(args[i], XmNselectPixmap,
1009 			     nw->chooser.select_pixmaps[j]);
1010 		    i++;
1011 		}
1012 		if (nw->chooser.insensitive_pixmaps) {
1013 		    XtSetArg(args[i], XmNlabelInsensitivePixmap,
1014 			     nw->chooser.insensitive_pixmaps[j]);
1015 		    i++;
1016 		}
1017 	    }
1018 	    if ((nw->chooser.type == XmtChooserOption) ||
1019 	        (nw->chooser.type == XmtChooserButtonBox)) {
1020 		nw->chooser.item_widgets[j] =
1021 		    XmCreatePushButton(parent, namebuf, args,i);
1022 		XtAddCallback(nw->chooser.item_widgets[j], XmNactivateCallback,
1023 			      ChooserCallback, (XtPointer)nw);
1024 	    }
1025 	    else {
1026 		nw->chooser.item_widgets[j] =
1027 		    XmCreateToggleButton(parent, namebuf, args,i);
1028 		XtAddCallback(nw->chooser.item_widgets[j],
1029 			      XmNvalueChangedCallback,
1030 			      ChooserCallback, (XtPointer)nw);
1031 	    }
1032 	}
1033 	XtManageChildren(nw->chooser.item_widgets, nw->chooser.num_items);
1034     }
1035     else { /* if it is a list */
1036 	nw->chooser.item_widgets = NULL;
1037     }
1038 
1039     /* free all the item XmStrings */
1040     if (nw->chooser.label_type == XmSTRING) {
1041 	for(i = 0; i < nw->chooser.num_items; i++)
1042 	    XmStringFree(item_labels[i]);
1043 	XtFree((char *)item_labels);
1044     }
1045 
1046     /*
1047      * if there is a symbol, bind the symbol,
1048      * set up notification, read the initial state,
1049      * and copy the symbol_name.
1050      */
1051     if (nw->chooser.symbol_name) {
1052 	nw->chooser.symbol_name = XtNewString(nw->chooser.symbol_name);
1053 	BindSymbol(nw);
1054     }
1055     else nw->chooser.symbol = NULL;
1056 
1057     /* make the widgets correspond to the initial state */
1058     SetStateOnWidgets(nw);
1059 
1060     /* set initial sensitivity */
1061     nw->chooser.insensitive = 0;
1062 
1063     /* and do other initialization */
1064     nw->chooser.ignore_symbol_notify = False;
1065 }
1066 
1067 #if NeedFunctionPrototypes
Destroy(Widget w)1068 static void Destroy(Widget w)
1069 #else
1070 static void Destroy(w)
1071 Widget w;
1072 #endif
1073 {
1074     XmtChooserWidget cw = (XmtChooserWidget)w;
1075 
1076 #if XmVersion < 2000
1077     /* free the font list */
1078     XmFontListFree(cw->chooser.font_list);
1079 #else /* Motif 2.0 or later */
1080     /* free the renderTable */
1081     XmRenderTableFree(cw->chooser.render_table);
1082 #endif
1083 
1084     /* free the widget array */
1085     XtFree((char *)cw->chooser.item_widgets);
1086 
1087     /* free the arrays, but not the strings themselves */
1088     XtFree((char *)cw->chooser.strings);
1089     XtFree((char *)cw->chooser.pixmaps);
1090     XtFree((char *)cw->chooser.select_pixmaps);
1091     XtFree((char *)cw->chooser.insensitive_pixmaps);
1092     XtFree((char *)cw->chooser.values);
1093 
1094     /* free the symbol name */
1095     XtFree(cw->chooser.symbol_name);
1096 
1097     /* remove symbol callback and free the symbol, if we have one */
1098     ReleaseSymbol(cw);
1099 }
1100 
1101 /* ARGSUSED */
1102 #if NeedFunctionPrototypes
SetValues(Widget current,Widget request,Widget set,ArgList arglist,Cardinal * num_args)1103 static Boolean SetValues(Widget current, Widget request, Widget set,
1104 			 ArgList arglist, Cardinal *num_args)
1105 #else
1106 static Boolean SetValues(current, request, set, arglist, num_args)
1107 Widget current;
1108 Widget request;
1109 Widget set;
1110 ArgList arglist;
1111 Cardinal *num_args;
1112 #endif
1113 {
1114     XmtChooserWidget cw = (XmtChooserWidget) current;
1115     XmtChooserWidget nw = (XmtChooserWidget) set;
1116     Arg args[5];
1117 
1118     if (nw->chooser.type != cw->chooser.type) {
1119 	nw->chooser.type = cw->chooser.type;
1120 	XmtWarningMsg("XmtChooser","cantChangeType",
1121 		     "%s: can't change XmtNchooserType resource.",
1122 		     XtName(set));
1123     }
1124 
1125     if ((nw->chooser.strings != cw->chooser.strings) ||
1126 	(nw->chooser.pixmaps != cw->chooser.pixmaps) ||
1127 	(nw->chooser.select_pixmaps != cw->chooser.select_pixmaps) ||
1128 	(nw->chooser.insensitive_pixmaps != cw->chooser.insensitive_pixmaps))
1129 	XmtWarningMsg("XmtChooser", "cantChange",
1130 		      "%s: can't change labels or pixmaps.",
1131 		      XtName((Widget) nw));
1132 
1133     if (nw->chooser.values != cw->chooser.values) {
1134 	XtFree((char *)cw->chooser.values);
1135 	CheckType(nw);
1136 	if (nw->chooser.values) CopyValues(nw);
1137     }
1138     else if (nw->chooser.value_strings != cw->chooser.value_strings) {
1139 	XtFree((char*) cw->chooser.values);
1140 	CheckType(nw);
1141 	if (nw->chooser.value_strings) ConvertValueStrings(nw);
1142     }
1143 
1144     if (nw->chooser.visible_items != cw->chooser.visible_items) {
1145 #if XmVersion < 2000
1146 	if ((nw->chooser.type==XmtChooserRadioList) ||
1147 	    (nw->chooser.type==XmtChooserCheckList)) {
1148 #else /* Motif 2.0 or later */
1149 	if ((nw->chooser.type==XmtChooserRadioList) ||
1150 	    (nw->chooser.type==XmtChooserCheckList) ||
1151             (nw->chooser.type==XmtChooserComboBox)) {
1152 #endif
1153 	    XtSetArg(args[0], XmNvisibleItemCount, nw->chooser.visible_items);
1154 	    XtSetValues(nw->chooser.list, args, (Cardinal) 1);
1155 	}
1156     }
1157 
1158     if (nw->chooser.symbol_name != cw->chooser.symbol_name) {
1159 	/*
1160 	 * forget the old symbol, if there is one.
1161 	 * bind the new, if not NULL, register callbacks, set new state.
1162 	 * If there is a new state, update the widgets.
1163 	 */
1164 	XtFree(cw->chooser.symbol_name);
1165 	nw->chooser.symbol_name = XtNewString(nw->chooser.symbol_name);
1166 	ReleaseSymbol(cw);
1167 	BindSymbol(nw);
1168 	if (nw->chooser.state != cw->chooser.state)
1169 	    SetStateOnWidgets(nw);
1170     }
1171     else if (nw->chooser.state != cw->chooser.state) {
1172 	/* if state changed, but symbol name didn't */
1173 	if (nw->chooser.symbol) SetStateOnSymbol(nw); /* sets widgets too */
1174 	else SetStateOnWidgets(nw);
1175     }
1176 
1177     /*
1178      * if sensitivity changes, set the layoutSensitive resource, in case
1179      * we're a child of XmtLayout, and have a caption.
1180      */
1181     if ((nw->core.sensitive != cw->core.sensitive) ||
1182 	(nw->core.ancestor_sensitive != cw->core.ancestor_sensitive)) {
1183 	XtVaSetValues(set, XmtNlayoutSensitive,
1184 		      nw->core.sensitive && nw->core.ancestor_sensitive, NULL);
1185     }
1186 
1187     return False;
1188 }
1189 
1190 
1191 #if NeedFunctionPrototypes
BoundsWarning(XmtChooserWidget cw,int n)1192 static void BoundsWarning(XmtChooserWidget cw, int n)
1193 #else
1194 static void BoundsWarning(cw, n)
1195 XmtChooserWidget cw;
1196 int n;
1197 #endif
1198 {
1199     XmtWarningMsg("XmtChooser", "bounds",
1200 		  "Widget '%s' has %d items.  Item %d requested.",
1201 		  XtName((Widget) cw), cw->chooser.num_items, n);
1202 }
1203 
1204 
1205 #if NeedFunctionPrototypes
XmtCreateChooser(Widget parent,StringConst name,ArgList args,Cardinal n)1206 Widget XmtCreateChooser(Widget parent, StringConst name,
1207 			ArgList args, Cardinal n)
1208 #else
1209 Widget XmtCreateChooser(parent, name, args, n)
1210 Widget parent;
1211 StringConst name;
1212 ArgList args;
1213 Cardinal n;
1214 #endif
1215 {
1216     return XtCreateWidget((String)name,xmtChooserWidgetClass, parent, args, n);
1217 }
1218 
1219 #if NeedFunctionPrototypes
XmtChooserGetState(Widget w)1220 int XmtChooserGetState(Widget w)
1221 #else
1222 int XmtChooserGetState(w)
1223 Widget w;
1224 #endif
1225 {
1226     XmtAssertWidgetClass(w, xmtChooserWidgetClass, "XmtChooserGetState");
1227     return ((XmtChooserWidget)w)->chooser.state;
1228 }
1229 
1230 #if NeedFunctionPrototypes
XmtChooserGetValue(Widget w)1231 XtPointer XmtChooserGetValue(Widget w)
1232 #else
1233 XtPointer XmtChooserGetValue(w)
1234 Widget w;
1235 #endif
1236 {
1237     XmtChooserWidget cw = (XmtChooserWidget) w;
1238     XmtAssertWidgetClass(w, xmtChooserWidgetClass, "XmtChooserGetValue");
1239 
1240     if (cw->chooser.values)
1241 	return (XtPointer) &((char *)cw->chooser.values)
1242 	    [cw->chooser.state * cw->chooser.value_size];
1243     else return NULL;
1244 }
1245 
1246 #if NeedFunctionPrototypes
XmtChooserLookupItemValue(Widget w,int item)1247 XtPointer XmtChooserLookupItemValue(Widget w, int item)
1248 #else
1249 XtPointer XmtChooserLookupItemValue(w, item)
1250 Widget w;
1251 int item;
1252 #endif
1253 {
1254     XmtChooserWidget cw = (XmtChooserWidget) w;
1255     XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserLookupItemValue");
1256 
1257     if ((item < 0) || (item > cw->chooser.num_items)) {
1258 	BoundsWarning(cw, item);
1259 	return NULL;
1260     }
1261 
1262     if (cw->chooser.values)
1263 	return (XtPointer)&((char *)cw->chooser.values)
1264 	    [item * cw->chooser.value_size];
1265     else return NULL;
1266 }
1267 
1268 #if NeedFunctionPrototypes
XmtChooserSetItemValue(Widget w,int item,XtPointer valuep)1269 void XmtChooserSetItemValue(Widget w, int item, XtPointer valuep)
1270 #else
1271 void XmtChooserSetItemValue(w, item, valuep)
1272 Widget w;
1273 int item;
1274 XtPointer valuep;
1275 #endif
1276 {
1277     XmtChooserWidget cw = (XmtChooserWidget) w;
1278     XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserLookupItemValue");
1279 
1280     if ((item < 0) || (item > cw->chooser.num_items)) {
1281 	BoundsWarning(cw, item);
1282 	return;
1283     }
1284 
1285     if (!cw->chooser.values)
1286 	cw->chooser.values = (XtPointer) XtCalloc(cw->chooser.num_items,
1287 						  cw->chooser.value_size);
1288 
1289     memmove(&((char *)cw->chooser.values)[item * cw->chooser.value_size],
1290 	    valuep,
1291 	    cw->chooser.value_size);
1292 }
1293 
1294 
1295 #if NeedFunctionPrototypes
XmtChooserSetState(Widget w,int state,XmtWideBoolean notify)1296 void XmtChooserSetState(Widget w, int state, XmtWideBoolean notify)
1297 #else
1298 void XmtChooserSetState(w, state, notify)
1299 Widget w;
1300 int state;
1301 int notify;
1302 #endif
1303 {
1304    XmtChooserWidget cw = (XmtChooserWidget)w;
1305    XmtChooserCallbackStruct call_data;
1306 
1307    XmtAssertWidgetClass(w, xmtChooserWidgetClass, "XmtChooserSetState");
1308 
1309    /* the XmtChooserButtonBox doesn't have a state to set */
1310    if (cw->chooser.type == XmtChooserButtonBox) return;
1311 
1312    /* if this chooser has radio behavior, check bounds on state */
1313    if ((cw->chooser.type != XmtChooserCheckBox) &&
1314        (cw->chooser.type != XmtChooserCheckPalette) &&
1315        (cw->chooser.type != XmtChooserCheckList) &&
1316        ((state < 0) || (state > cw->chooser.num_items))) {
1317        BoundsWarning(cw, state);
1318        return;
1319    }
1320 
1321    cw->chooser.state = state;
1322 
1323    if (cw->chooser.symbol) SetStateOnSymbol(cw);  /* indirectly sets widgets */
1324    else SetStateOnWidgets(cw);
1325 
1326    if (notify) {
1327        call_data.state = state;
1328        call_data.item = -1;  /* -1 flags synthetic state changes */
1329        if (cw->chooser.values &&
1330 #if XmVersion < 2000
1331 	   ((cw->chooser.type == XmtChooserRadioBox) ||
1332 	    (cw->chooser.type == XmtChooserRadioPalette) ||
1333 	    (cw->chooser.type == XmtChooserRadioList) ||
1334 	    (cw->chooser.type == XmtChooserOption)))
1335 #else /* Motif 2.0 or later */
1336 	   ((cw->chooser.type == XmtChooserRadioBox) ||
1337 	    (cw->chooser.type == XmtChooserRadioPalette) ||
1338 	    (cw->chooser.type == XmtChooserRadioList) ||
1339 	    (cw->chooser.type == XmtChooserOption) ||
1340             (cw->chooser.type == XmtChooserComboBox)))
1341 #endif
1342 	   call_data.valuep = (XtPointer) &((char *)cw->chooser.values)
1343 	       [state * cw->chooser.value_size];
1344        else
1345 	   call_data.valuep = NULL;
1346        XtCallCallbackList(w, cw->chooser.callback, (XtPointer)&call_data);
1347    }
1348 }
1349 
1350 #if NeedFunctionPrototypes
XmtChooserLookupItemByName(Widget w,StringConst name)1351 int XmtChooserLookupItemByName(Widget w, StringConst name)
1352 #else
1353 int XmtChooserLookupItemByName(w, name)
1354 Widget w;
1355 StringConst name;
1356 #endif
1357 {
1358    XmtChooserWidget cw = (XmtChooserWidget)w;
1359    int i;
1360 
1361    XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserLookupItemByName");
1362 
1363    if (!name || !cw->chooser.strings) return -1;
1364 
1365    for(i = cw->chooser.num_items-1; i >= 0; i--)
1366        if (cw->chooser.strings[i] && (strcmp(name, cw->chooser.strings[i])==0))
1367 	   break;
1368 
1369    return i;
1370 }
1371 
1372 #if NeedFunctionPrototypes
XmtChooserLookupItemByValue(Widget w,XtPointer valuep)1373 int XmtChooserLookupItemByValue(Widget w, XtPointer valuep)
1374 #else
1375 int XmtChooserLookupItemByValue(w, valuep)
1376 Widget w;
1377 XtPointer valuep;
1378 #endif
1379 {
1380     XmtChooserWidget cw = (XmtChooserWidget)w;
1381     int i;
1382 
1383     XmtAssertWidgetClass(w, xmtChooserWidgetClass,
1384 			 "XmtChooserLookupItemByValue");
1385 
1386     if (!cw->chooser.values) return -1;
1387 
1388     if (strcmp(cw->chooser.value_type, XtRString) == 0) {
1389 	for(i = cw->chooser.num_items-1; i >= 0; i--)
1390 	    if (strcmp(*(String *)valuep,
1391 		       *(String*)&((char *)cw->chooser.values)[i*cw->chooser.value_size]) == 0)
1392 		break;
1393     }
1394     else {
1395 	for(i = cw->chooser.num_items-1; i >= 0; i--)
1396 	    if (memcmp(valuep,
1397 		       &((char*)cw->chooser.values)[i*cw->chooser.value_size],
1398 		       cw->chooser.value_size) == 0) break;
1399     }
1400     return i;
1401 }
1402 
1403 #if NeedFunctionPrototypes
XmtChooserLookupItemName(Widget w,int n)1404 String XmtChooserLookupItemName(Widget w, int n)
1405 #else
1406 String XmtChooserLookupItemName(w, n)
1407 Widget w;
1408 int n;
1409 #endif
1410 {
1411    XmtChooserWidget cw = (XmtChooserWidget)w;
1412 
1413    XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserLookupItemName");
1414 
1415    if ((n < 0) || (n > cw->chooser.num_items)) {
1416        BoundsWarning(cw, n);
1417        return NULL;
1418    }
1419 
1420    if (cw->chooser.strings)
1421        return cw->chooser.strings[n];
1422    else
1423        return NULL;
1424 }
1425 
1426 
1427 #if NeedFunctionPrototypes
XmtChooserSetSensitive(Widget w,int n,XmtWideBoolean sensitive)1428 void XmtChooserSetSensitive(Widget w, int n, XmtWideBoolean sensitive)
1429 #else
1430 void XmtChooserSetSensitive(w, n, sensitive)
1431 Widget w;
1432 int n;
1433 int sensitive;
1434 #endif
1435 {
1436     XmtChooserWidget cw = (XmtChooserWidget)w;
1437 
1438     XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserSetSensitive");
1439 
1440     if ((n < 0) || (n > cw->chooser.num_items)) {
1441 	BoundsWarning(cw, n);
1442 	return;
1443     }
1444 
1445     if (n > 31) {
1446 	XmtWarningMsg("XmtChooserSetSensitive", "size",
1447 		      "can only set sensitivity on first 32 items.");
1448 	return;
1449     }
1450 
1451     /*
1452      * if this is not a list chooser, set the button's sensitivity.
1453      */
1454     if (cw->chooser.item_widgets)
1455 	XtSetSensitive(cw->chooser.item_widgets[n], sensitive);
1456 
1457     /*
1458      * set our internal state
1459      */
1460     if (sensitive)
1461 	cw->chooser.insensitive &= ~(1 << n);
1462     else
1463 	cw->chooser.insensitive |= 1 << n;
1464 }
1465 
1466 #if NeedFunctionPrototypes
XmtChooserGetSensitivity(Widget w,int n)1467 Boolean XmtChooserGetSensitivity(Widget w, int n)
1468 #else
1469 Boolean XmtChooserGetSensitivity(w, n)
1470 Widget w;
1471 int n;
1472 #endif
1473 {
1474     XmtChooserWidget cw = (XmtChooserWidget)w;
1475 
1476     XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserGetSensitivity");
1477 
1478     if ((n < 0) || (n > cw->chooser.num_items)) {
1479 	BoundsWarning(cw, n);
1480 	return False;
1481     }
1482 
1483     if (n > 31) {
1484 	XmtWarningMsg("XmtChooserGetSensitivity", "size",
1485 		      "can only get sensitivity on first 32 items.");
1486 	return False;
1487     }
1488 
1489     if (cw->chooser.insensitive & (1 << n)) return False;
1490     else return True;
1491 }
1492 
1493 #if NeedFunctionPrototypes
setvalue(Widget w,XtPointer address,XrmQuark type,Cardinal size)1494 static void setvalue(Widget w, XtPointer address, XrmQuark type, Cardinal size)
1495 #else
1496 static void setvalue(w, address, type, size)
1497 Widget w;
1498 XtPointer address;
1499 XrmQuark type;
1500 Cardinal size;
1501 #endif
1502 {
1503     XmtChooserWidget cw = (XmtChooserWidget) w;
1504 
1505     if (cw->chooser.values) {
1506 	if (XrmStringToQuark(cw->chooser.value_type) == type) {
1507 	    int i = XmtChooserLookupItemByValue(w, address);
1508 	    if (i != -1)
1509 		XmtChooserSetState(w, i, False);
1510 	    else
1511 		XmtWarningMsg("XmtChooser", "setvalue0",
1512 			      "Widget '%s':\n\tCan't set value from resource.\n\tSpecified value is not one of the legal values.",
1513 			      XtName(w));
1514 	}
1515 	else
1516 	    XmtWarningMsg("XmtChooser", "setvalue1",
1517 		    "Type mismatch:\n\tcan't set value from a resource of type '%s';\n\tWidget '%s' expects a value of type '%s'",
1518 		    XrmQuarkToString(type), XtName(w), cw->chooser.value_type);
1519     }
1520     else {
1521 	int value;
1522 
1523 	if (size == sizeof(int))
1524 	    value = *(int *)address;
1525 	else if (size == sizeof(short))
1526 	    value = (int) *(short *)address;
1527 	else if (size == sizeof(char))
1528 	    value = (int) *(char *)address;
1529 	else {
1530 	    XmtWarningMsg("XmtChooser", "setvalue2",
1531 			  "Type mismatch: \n\tCan't set value from a resource of non-scalar type '%s'.",
1532 			  XrmQuarkToString(type));
1533 	    return;
1534 	}
1535 
1536         XmtChooserSetState(w, value, False);
1537     }
1538 }
1539 
1540 #if NeedFunctionPrototypes
getvalue(Widget w,XtPointer address,XrmQuark type,Cardinal size)1541 static void getvalue(Widget w, XtPointer address, XrmQuark type, Cardinal size)
1542 #else
1543 static void getvalue(w, address, type, size)
1544 Widget w;
1545 XtPointer address;
1546 XrmQuark type;
1547 Cardinal size;
1548 #endif
1549 {
1550     XmtChooserWidget cw = (XmtChooserWidget) w;
1551 
1552     if (cw->chooser.values) {
1553 	if (XrmStringToQuark(cw->chooser.value_type) == type)
1554 	    memmove(address, XmtChooserGetValue(w), cw->chooser.value_size);
1555 	else
1556 	    XmtWarningMsg("XmtChooser", "getvalue0",
1557 		    "Type mismatch:\n\tcan't set value on a resource of type '%s';\n\tWidget '%s' has values of type '%s'",
1558 		    XrmQuarkToString(type), XtName(w), cw->chooser.value_type);
1559     }
1560     else {
1561 	int state = XmtChooserGetState(w);
1562 
1563 	if (size == sizeof(int))
1564 	    *(int *)address = state;
1565 	else if (size == sizeof(short))  /* note we don't warn on overflow */
1566 	    *(short *)address = state;
1567 	else if (size == sizeof(char))
1568 	    *(char *)address = state;
1569 	else {
1570 	    XmtWarningMsg("XmtChooser", "setvalue2",
1571 			  "Type mismatch: \n\tCan't set value from a resource of non-scalar type '%s'.",
1572 			  XrmQuarkToString(type));
1573 	    return;
1574 	}
1575     }
1576 }
1577 
1578 
1579 static XmtWidgetType chooser_widget = {
1580     "XmtChooser",
1581     (WidgetClass)&xmtChooserClassRec,
1582     NULL,
1583     setvalue,
1584     getvalue,
1585 };
1586 
1587 #if NeedFunctionPrototypes
XmtRegisterChooser(void)1588 void XmtRegisterChooser(void)
1589 #else
1590 void XmtRegisterChooser()
1591 #endif
1592 {
1593     XmtRegisterWidgetTypes(&chooser_widget, 1);
1594 }
1595