1 /*
2  * Motif Tools Library, Version 3.1
3  * $Id: CallbackCvt.c,v 1.3 2001/09/19 02:57:18 grmcdorman 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: CallbackCvt.c,v $
12  * Revision 1.3  2001/09/19 02:57:18  grmcdorman
13  * This change makes the following modifications:
14  *   A new program, printConfig, is provided. This is built by a
15  *   simple rule in the Makefile and not installed. It prints
16  *   significant defines from Xmt.tmpl.
17  *
18  *   XmtP.h is now generated from XmtP.h.in using printConfig. As
19  *   a result, code compiled outside of the Xmt Imakefiles will
20  *   have all of the Xmt.tmpl defines.
21  *
22  *   Source files are modified to use XmtP.h instead of Xmt.h.
23  *
24  *   WorkingBox.c is modified to use the new Progress widget.
25  *   It can be compiled in the old style if WORKINGBOX_USE_SCALE is
26  *   defined at compile time.
27  *
28  *   Because XmtP.h is generated dynamically, it is removed from CVS
29  *   with this check-in.
30  *
31  * Revision 1.2  2001/04/15 15:29:36  grmcdorman
32  *   * XmtCallCallback has two new arguments types: XmtRCallbackUserData, which
33  *     is the XmNuserData value, and XmtRCallbackImmediate, which is a value
34  *     embedded in the list.
35  *
36  *   * Two new functions, XmtCreateQueryListChildren and XmtCreateQueryListChild,
37  *     are provided. They are like the XmtCreate* functions except that they
38  *     return a list of the widgets created (quark and pointer to the widget).
39  *
40  *   * Major enhancements to XmtInputField:
41  *     - The input field now has a cancel() action. This reverts the field's
42  *       value to that prior to the start of editing (i.e. the last commit).
43  *       No default translation is bound to this action, however.
44  *     - There is a callback for the cancel action (XmtNcancelCallback).
45  *     - The input field can be set to cancel, commit, or do nothing on focus
46  *       out. (Previously, it always did a commit). The default is commit.
47  *       (XmtNfocusOutAction)
48  *
49  *   * XmtLayout:
50  *     - It now has a losingFocusCallback (XmNloosingFocusCallback).
51  *     - It, and the layout widgets (XmtLayoutBox/XmtLayoutString), now
52  *       support background pixmaps.
53  *     - It now supports XmNresizePolicy.
54  *     - Strings in the layout parser are converted to XmStrings by
55  *       XtConvertAndStore, so any custom XmString conversion is used
56  *       (as, for example, the Xmt convert, which supports the @[]
57  *       embedded items)
58  *
59  *   * Other:
60  *     - Pixmaps are convered using XtConvertAndStore, again to allow
61  *       custom converters.
62  *
63  * Bug Fixes: (for Solaris 2.5.1/Motif 1.2/Sparc system)
64  *   * XmtInputField did not work properly if the widget had traversalOn
65  *     false.
66  *   * XmtLayout's child geometry manager was called by Xt when
67  *     a shell child was added to the layout; it did not handle
68  *     this case.
69  *   * XmtLayout had an XmtWarningMsg call with a missing argument (line 2029).
70  *   * Widgets automatically created by XmtLayout parsing have been given
71  *     non-blank names. [You may wish to tweak this by adding, for example,
72  *     a leading underscore.]
73  *   * Under some circumstances, XmtNameToWidget could be called during
74  *     widget creation, with 'w->core.num_popups' uninitialized. The
75  *     workaround applied is to ignore the popup list if the 'num_popups'
76  *     value is more than 50 or negative.
77  *
78  * Revision 1.1.1.1  2001/02/10 13:40:36  motiftools
79  * Initial import of Xmt310 to CVS
80  *
81  *
82  */
83 
84 #include <Xmt/XmtP.h>
85 #include <Xmt/ProceduresP.h>
86 #include <Xmt/Symbols.h>
87 #include <Xmt/ConvertersP.h>
88 #include <Xmt/Util.h>
89 #include <Xmt/Lexer.h>
90 #include <Xmt/QuarksP.h>
91 
92 typedef struct {
93     String procedure_name;
94     XmtProcedureInfo *procedure;
95     String argument_strings[XmtMAX_PROCEDURE_ARGS];
96     XtPointer arguments[XmtMAX_PROCEDURE_ARGS];
97     XmtSymbol symbols[XmtMAX_PROCEDURE_ARGS];
98     Boolean error;
99 } CallInfo;
100 
101 
102 typedef struct {
103     CallInfo *calls;
104     int num_calls;
105 } Callback;
106 
107 typedef void (*XmtProcedure0)(
108 #if NeedFunctionPrototypes
109 			      void
110 #endif
111 			      );
112 typedef void (*XmtProcedure1)(
113 #if NeedFunctionPrototypes
114   				   XtPointer
115 #endif
116 			      );
117 typedef void (*XmtProcedure2)(
118 #if NeedFunctionPrototypes
119   				   XtPointer, XtPointer
120 #endif
121 			      );
122 typedef void (*XmtProcedure3)(
123 #if NeedFunctionPrototypes
124   				   XtPointer, XtPointer, XtPointer
125 #endif
126 			      );
127 typedef void (*XmtProcedure4)(
128 #if NeedFunctionPrototypes
129   				   XtPointer, XtPointer,
130 				   XtPointer, XtPointer
131 #endif
132 			      );
133 typedef void (*XmtProcedure5)(
134 #if NeedFunctionPrototypes
135   				   XtPointer, XtPointer, XtPointer,
136 				   XtPointer, XtPointer
137 #endif
138 			      );
139 typedef void (*XmtProcedure6)(
140 #if NeedFunctionPrototypes
141   				   XtPointer, XtPointer, XtPointer,
142 				   XtPointer, XtPointer, XtPointer
143 #endif
144 			      );
145 typedef void (*XmtProcedure7)(
146 #if NeedFunctionPrototypes
147   				   XtPointer, XtPointer, XtPointer,
148 				   XtPointer, XtPointer, XtPointer,
149 				   XtPointer
150 #endif
151 			      );
152 typedef void (*XmtProcedure8)(
153 #if NeedFunctionPrototypes
154   				   XtPointer, XtPointer, XtPointer,
155 				   XtPointer, XtPointer, XtPointer,
156 				   XtPointer, XtPointer
157 #endif
158 			      );
159 
160 #if NeedFunctionPrototypes
ExpectedWarning(String s)161 static void ExpectedWarning(String s)
162 #else
163 static void ExpectedWarning(s)
164 String s;
165 #endif
166 {
167     XmtWarningMsg("XmtConvertStringToCallback", "expected",
168 		  "%s expected.",
169 		  s);
170 }
171 
172 #if NeedFunctionPrototypes
ParseCall(XmtLexer l,CallInfo * ci)173 static Boolean ParseCall(XmtLexer l, CallInfo *ci)
174 #else
175 static Boolean ParseCall(l, ci)
176 XmtLexer l;
177 CallInfo *ci;
178 #endif
179 {
180     XmtLexerToken tok;
181     Cardinal num_args;
182     int i;
183 
184     ci->procedure_name = NULL;
185     ci->procedure = NULL;
186     for(i=0; i < XmtMAX_PROCEDURE_ARGS; i++) {
187 	ci->argument_strings[i] = NULL;
188 	ci->arguments[i] = NULL;
189 	ci->symbols[i] = NULL;
190     }
191     ci->error = False;
192 
193     tok = XmtLexerGetToken(l);
194     if (tok != XmtLexerIdent) {
195 	ExpectedWarning("procedure name");
196 	goto error;
197     }
198 
199     ci->procedure_name = XmtLexerStrValue(l);
200     XmtLexerConsumeToken(l);
201 
202     if (XmtLexerGetToken(l) != XmtLexerLParen) {
203 	ExpectedWarning("'('");
204 	goto error;
205     }
206 
207     XmtLexerGetArgList(l,ci->argument_strings,XmtMAX_PROCEDURE_ARGS,&num_args);
208     return True;
209 
210  error:
211     /* free any strings allocated so far.  XtFree is okay with NULL */
212     XtFree(ci->procedure_name);
213     ci->procedure_name = NULL;
214     for(i=0; i < XmtMAX_PROCEDURE_ARGS; i++) {
215 	XtFree(ci->argument_strings[i]);
216 	ci->argument_strings[i] = NULL;
217     }
218     return False;
219 }
220 
221 
222 #if NeedFunctionPrototypes
StringToCallback(String str)223 static Callback *StringToCallback(String str)
224 #else
225 static Callback *StringToCallback(str)
226 String str;
227 #endif
228 {
229     static XmtLexer l = NULL;
230     XmtLexerToken tok;
231     int num, max;
232     CallInfo *calls;
233     Callback *cb;
234     Boolean stat;
235 
236     if (l == NULL)
237 	l = XmtLexerCreate((String *)NULL, 0);
238 
239     XmtLexerInit(l, str);
240 
241     num = max = 0;
242     calls = NULL;
243 
244     while(XmtLexerGetToken(l) != XmtLexerEndOfString) {
245 	if (num == max) {
246 	    if (max == 0) max = 4; else max *= 2;
247 	    calls = (CallInfo*)XtRealloc((char*)calls, sizeof(CallInfo) * max);
248 	}
249 	/* parse a single procedure call */
250 	stat = ParseCall(l, &calls[num]);
251 	if (stat) num++;
252 	else { /* on error read 'till next semicolon */
253 	    while(1) {
254 		tok = XmtLexerGetToken(l);
255 		if ((tok == XmtLexerSemicolon) ||
256 		    (tok == XmtLexerEndOfString)) break;
257 		XmtLexerConsumeToken(l);
258 	    }
259 	}
260 
261 	/* and discard any semicolons */
262 	while (XmtLexerGetToken(l) == XmtLexerSemicolon)
263 	    XmtLexerConsumeToken(l);
264     }
265 
266     if (num == 0) { /* if empty string or errors */
267 	XtFree((char *)calls);
268 	cb = NULL;
269     }
270     else {
271 	calls = (CallInfo *)XtRealloc((char *)calls, sizeof(CallInfo)*num);
272 	cb = XtNew(Callback);
273 	cb->calls = calls;
274 	cb->num_calls = num;
275     }
276     return cb;
277 }
278 
279 
280 #if NeedFunctionPrototypes
DestroyCallback(Callback * cb)281 static void DestroyCallback(Callback *cb)
282 #else
283 static void DestroyCallback(cb)
284 Callback *cb;
285 #endif
286 {
287     int i,j;
288     CallInfo *info;
289 
290     for(i=0; i < cb->num_calls; i++) {
291 	info = &cb->calls[i];
292 	XtFree(info->procedure_name);
293 	for(j=0; j < XmtMAX_PROCEDURE_ARGS; j++)
294 	    XtFree(info->argument_strings[j]);
295     }
296     XtFree((char *) cb->calls);
297     XtFree((char *)cb);
298 }
299 
300 #if NeedFunctionPrototypes
ConvertArg(Widget w,CallInfo * call,int i,int j,int arg_index)301 static void ConvertArg(Widget w, CallInfo *call, int i, int j, int arg_index)
302 #else
303 static void ConvertArg(w, call, i, j, arg_index)
304 Widget w;
305 CallInfo *call;
306 int i;
307 int j;
308 int arg_index;
309 #endif
310 {
311     XrmValue from, to;
312     Boolean stat;
313     XmtProcedureInfo *proc = call->procedure;
314 
315     /*
316      * if the argument is a symbol name, bind it,
317      * check the type, and remember the symbol
318      */
319     if (call->argument_strings[j][0] == '$') {
320 	call->symbols[i] = XmtLookupSymbol(&call->argument_strings[j][1]);
321 
322 	if (!call->symbols[i]) {
323 	    XmtWarningMsg("XmtCallCallbacks", "symbol",
324 			  "argument %d of procedure %s.\n\tSymbol '%s' is undefined.",
325 			  j, call->procedure_name,
326 			  call->argument_strings[j]);
327 	}
328 	else {
329 	    /*
330 	     * check symbol type.
331 	     * A buffer symbol will match a string argument.
332 	     */
333 	    XrmQuark symtype = XmtSymbolTypeQuark(call->symbols[i]);
334 	    XrmQuark argtype = (XrmQuark) proc->argument_types[arg_index];
335 	    if ((symtype != argtype) &&
336 		!((symtype == XmtQBuffer) && (argtype == XmtQString))) {
337 		XmtWarningMsg("XmtCallCallbacks", "symbolType",
338 			      "type mismatch:\n\targument %d of procedure %s.\n\tSymbol '%s' is not of type %s",
339 			      j, call->procedure_name,
340 			      XmtSymbolName(call->symbols[i]),
341 			      XrmQuarkToString((XrmQuark)
342 					       proc->argument_types[arg_index]));
343 		call->symbols[i] = NULL;
344 	    }
345 	}
346 	if (!call->symbols[i]) call->error = True;
347     }
348     else {
349 	/*
350 	 * if it is not a symbol, then if it is a string constant, we're done.
351 	 * otherwise, we've got to convert our string to the appropriate type.
352 	 */
353 	if ((XrmQuark)proc->argument_types[arg_index] == XmtQString) {
354 	    call->arguments[i] = (XtPointer)call->argument_strings[j];
355 	}
356 	else {
357 	    from.addr = (XPointer) call->argument_strings[j];
358 	    from.size = strlen(from.addr)+1;
359 	    to.addr = (XPointer) NULL;
360 	    /* XtConvertAndStore() will ensure that converted
361 	     * values are freed when the widget w is destroyed.
362 	     */
363 	    stat = XtConvertAndStore(w, XtRString, &from,
364 			   XrmQuarkToString((XrmQuark)proc->argument_types[arg_index]),
365 				     &to);
366 
367 	    if (!stat) {
368 		XmtWarningMsg("XmtCallCallbacks", "typeMismatch",
369 			      "type mismatch: \n\targument %d of procedure %s.\n\tCan't convert \"%s\" to type %s",
370 			      j, call->procedure_name,
371 			      call->argument_strings[i],
372 			      XrmQuarkToString((XrmQuark)
373 					       proc->argument_types[arg_index]));
374 		call->error = True;
375 	    }
376 	    else {
377 		/* XXX
378 		 * This code isn't as portable as it should be, but it
379 		 * does seem to work on 32-bit architectures, and 64-bit Alpha.
380 		 * I don't know if there are any architectures that have
381 		 * calling conventions unlike those assumed here.
382 		 *
383 		 * All functions registered with the callback converter
384 		 * must expect arguments of the same size as XtPointer.
385 		 * This means that chars and shorts must be "widened"
386 		 * to longs.  Also, arguments of type double are not
387 		 * supported
388 		 */
389 		switch(to.size) {
390 		case 1:
391 		    call->arguments[i] = (XtPointer)(long)*(char *)to.addr;
392 		    break;
393 		case 2:
394 		    /* XXX signed vs. unsigned??? */
395 		    call->arguments[i] = (XtPointer)(long)*(short *)to.addr;
396 		    break;
397  		case 4:
398  		    call->arguments[i] = (XtPointer)(long)*(int *)to.addr;
399  		    break;
400 		default:
401 		    call->arguments[i] = (XtPointer)*(long *)to.addr;
402 		}
403 	    }
404 	}
405     }
406 }
407 
408 
409 #if NeedFunctionPrototypes
XmtCallCallback(Widget w,XtPointer tag,XtPointer data)410 static void XmtCallCallback(Widget w, XtPointer tag, XtPointer data)
411 #else
412 static void XmtCallCallback(w, tag, data)
413 Widget w;
414 XtPointer tag;
415 XtPointer data;
416 #endif
417 {
418     Callback *cb = (Callback *) tag;
419     CallInfo *call;
420     XmtProcedureInfo *proc;
421     Boolean firsttime;
422     int n;
423     int i, j, arg_index;
424 
425     for(n=0; n < cb->num_calls; n++) {
426 	call = &cb->calls[n];
427 
428 	if (call->error) {
429 	    XmtWarningMsg("XmtCallCallback", "badCall",
430 			  "not calling %s() because of previous errors.",
431 			  call->procedure_name);
432 	    continue;
433 	}
434 
435 	/* if this is the 1st time, figure out the procedure info */
436 	/* also set a flag for use below */
437 	if (call->procedure == NULL) {
438 	    firsttime = True;
439 	    call->procedure = XmtLookupProcedure(call->procedure_name);
440 	    if (call->procedure == NULL) {
441 		XmtWarningMsg("XmtCallCallback", "unknown",
442 			      "unknown procedure %s",
443 			      call->procedure_name);
444 		continue;
445 	    }
446 	}
447 	else firsttime = False;
448 
449 	proc = call->procedure;
450 
451 	/* if this is the first time, check the # of arguments */
452 	if (firsttime) {
453 	    for(i=0;
454 		(i < XmtMAX_PROCEDURE_ARGS) && (call->argument_strings[i]);
455 		i++);
456 
457 	    if (i != proc->expected_args) {
458 		XmtWarningMsg("XmtCallCallback", "wrongNum",
459 			      "procedure %s expects %d arguments.",
460 			      call->procedure_name, proc->expected_args);
461 		call->error = True;
462 		continue;
463 	    }
464 	}
465 
466 	/* build up the array of arguments */
467 	i = j = 0;
468 	arg_index = 0;
469 	while((i < XmtMAX_PROCEDURE_ARGS) &&
470 	      (proc->argument_types[arg_index] != (String)NULLQUARK)) {
471 	    if ((XrmQuark)proc->argument_types[arg_index] == _XmtQCallbackWidget)
472 		call->arguments[i] = (XtPointer) w;
473 	    else if ((XrmQuark)proc->argument_types[arg_index] == _XmtQCallbackData)
474 		call->arguments[i] = data;
475 	    else if((XrmQuark)proc->argument_types[arg_index]==_XmtQCallbackAppContext)
476 		call->arguments[i] =(XtPointer)XtWidgetToApplicationContext(w);
477 	    else if ((XrmQuark)proc->argument_types[arg_index] == _XmtQCallbackWindow)
478 		call->arguments[i] = (XtPointer) XtWindow(w);
479 	    else if ((XrmQuark)proc->argument_types[arg_index] == _XmtQCallbackDisplay)
480 		call->arguments[i] = (XtPointer) XtDisplay(w);
481 	    else if ((XrmQuark)proc->argument_types[arg_index] == _XmtQCallbackUnused)
482 		call->arguments[i] = NULL;
483 	    else if ((XrmQuark)proc->argument_types[arg_index] == _XmtQCallbackUserData) {
484 		/* The Motif userData resource. */
485 		XtPointer   userData;
486 
487 		XtVaGetValues(w, XmNuserData, &userData, NULL);
488 		call->arguments[i] = userData;
489 	    } else if ((XrmQuark)proc->argument_types[arg_index] == _XmtQCallbackImmediate) {
490 		/* An immediate value, passed in the argument type list. */
491 		if (i < XmtMAX_PROCEDURE_ARGS - 1) {
492 		    arg_index++;
493 		    call->arguments[i] = (XtPointer) proc->argument_types[arg_index];
494 		}
495 	    } else {
496 		/*
497 		 * if this is the first time this CallInfo has been called,
498 		 * we've got to convert the argument string to the expected
499 		 * type, or to a symbol of the expected type.  If the argument
500 		 * is a constant, then we can use it for all subsequent calls.
501 		 * if the argument is a symbol, we save the bound symbol,
502 		 * and look up its value for each subsequent call.
503 		 * Note we convert argument_string[j] to argument[i].
504 		 */
505 		if (firsttime) {
506 		    ConvertArg(w, call, i, j, arg_index);
507 		}
508 		/*
509 		 * if the arg is a symbol, get its value.
510 		 * Otherwise, its a constant, already converted, so do nothing.
511 		 */
512 		if (call->symbols[i]) {
513 		    XmtSymbolGetValue(call->symbols[i],
514 				      (XtArgVal *)&call->arguments[i]);
515 		}
516 		j++;
517 	    }
518 	    if (call->error) break;
519 	    i++;
520 	    arg_index++;
521 	}
522 
523 	if (call->error) continue;
524 
525 	/*
526 	 * Call the function.
527 	 * If you change XmtMAX_PROCEDURE_ARGS, change this code too.
528 	 * Note that all functions declared this way must expect
529 	 * all their arguments to be the same size as XtPointer.
530 	 * On most (all?) architectures it is safe to pass extra arguments
531 	 * to functions, so we could just do case 8: here in all cases.
532 	 * But this is a little cleaner when using a debugger, for example.
533 	 */
534 	switch(i) {  /* number of arguments*/
535 	case 0:
536 	    (*((XmtProcedure0)proc->function))();
537 	    break;
538 	case 1:
539 	    (*((XmtProcedure1)proc->function))(call->arguments[0]);
540 	    break;
541 	case 2:
542 	    (*((XmtProcedure2)proc->function))
543 		(call->arguments[0], call->arguments[1]);
544 	    break;
545 	case 3:
546 	    (*((XmtProcedure3)proc->function))
547 		(call->arguments[0], call->arguments[1],
548 		 call->arguments[2]);
549 	    break;
550 	case 4:
551 	    (*((XmtProcedure4)proc->function))
552 		(call->arguments[0], call->arguments[1],
553 		 call->arguments[2], call->arguments[3]);
554 	    break;
555 	case 5:
556 	    (*((XmtProcedure5)proc->function))
557 		(call->arguments[0], call->arguments[1],
558 		 call->arguments[2], call->arguments[3],
559 		 call->arguments[4]);
560 	    break;
561 	case 6:
562 	    (*((XmtProcedure6)proc->function))
563 		(call->arguments[0], call->arguments[1],
564 		 call->arguments[2], call->arguments[3],
565 		 call->arguments[4], call->arguments[5]);
566 	    break;
567 	case 7:
568 	    (*((XmtProcedure7)proc->function))
569 		(call->arguments[0], call->arguments[1],
570 		 call->arguments[2], call->arguments[3],
571 		 call->arguments[4], call->arguments[5],
572 		 call->arguments[6]);
573 	    break;
574 	case 8:
575 	    (*((XmtProcedure8)proc->function))
576 		(call->arguments[0], call->arguments[1],
577 		 call->arguments[2], call->arguments[3],
578 		 call->arguments[4], call->arguments[5],
579 		 call->arguments[6], call->arguments[7]);
580 	    break;
581 	}
582 
583     }
584 }
585 
586 
587 /* ARGSUSED */
588 #if NeedFunctionPrototypes
XmtConvertStringToCallback(Display * dpy,XrmValue * args,Cardinal * num_args,XrmValue * from,XrmValue * to,XtPointer * converter_data)589 Boolean XmtConvertStringToCallback(Display *dpy,
590 				   XrmValue *args, Cardinal *num_args,
591 				   XrmValue *from, XrmValue *to,
592 				   XtPointer *converter_data)
593 #else
594 Boolean XmtConvertStringToCallback(dpy, args, num_args, from, to,
595 				   converter_data)
596 Display *dpy;
597 XrmValue *args;
598 Cardinal *num_args;
599 XrmValue *from;
600 XrmValue *to;
601 XtPointer *converter_data;
602 #endif
603 {
604     Callback *callback;
605     XtCallbackList list;
606 
607     callback = StringToCallback((char *)from->addr);
608 
609     if (callback == NULL) { /* error, couldn't convert */
610 	/* XXX print the string here, and mark where the error occured. */
611 	return False;
612     }
613     else {
614 	list = (XtCallbackList)XtCalloc(sizeof(XtCallbackRec), 2);
615 	list[0].callback = (XtCallbackProc) XmtCallCallback;
616 	list[0].closure = (XtPointer) callback;
617 	done(XtCallbackList, list);
618     }
619 }
620 
621 /* ARGSUSED */
622 #if NeedFunctionPrototypes
XmtDestroyCallback(XtAppContext app,XrmValue * to,XtPointer converter_data,XrmValue * args,Cardinal * num_args)623 static void XmtDestroyCallback(XtAppContext app, XrmValue *to,
624 			       XtPointer converter_data,
625 			       XrmValue *args, Cardinal *num_args)
626 #else
627 static void XmtDestroyCallback(app, to, converter_data, args, num_args)
628 XtAppContext app;
629 XrmValue *to;
630 XtPointer converter_data;
631 XrmValue *args;
632 Cardinal *num_args;
633 #endif
634 {
635     XtCallbackList list = *(XtCallbackList *)to->addr;
636 
637     DestroyCallback((Callback *)list[0].closure);
638     XtFree((char *)list);
639 }
640 
641 #if NeedFunctionPrototypes
XmtRegisterCallbackConverter(void)642 void XmtRegisterCallbackConverter(void)
643 #else
644 void XmtRegisterCallbackConverter()
645 #endif
646 {
647     static Boolean registered = False;
648 
649     if (!registered) {
650 	registered = True;
651 	/*
652 	 * Note that the results of this converter cannot be cached, because
653 	 * the callback arguments need to be converted in the context of
654 	 * their particular widget and thus cannot be shared.  It doesn't
655 	 * make much sense, however, to have lots of widgets with the same
656 	 * callbacks and arguments, however, so this is no great loss.
657 	 */
658 	XtSetTypeConverter(XtRString, XtRCallback,
659 			   XmtConvertStringToCallback, NULL, 0,
660 			   XtCacheNone | XtCacheRefCount,
661 			   XmtDestroyCallback);
662 
663 	/* ensure that the quarks we need will exist when the
664 	 * converter is called
665 	 */
666 	_XmtInitQuarks();
667 
668 	/*
669 	 * we also register the converter in variables declared in
670 	 * GlobalsI.h so that it can be looked up by the automatic
671 	 * widget creation routines.  We don't want those routines to
672 	 * reference these directly because then they would be linked
673 	 * together.
674 	 */
675 	_XmtCallbackConverter = XmtConvertStringToCallback;
676     }
677 }
678 
679 #if NeedFunctionPrototypes
XmtCallbackCheckList(XtCallbackList list,XmtProcedure proc)680 Boolean XmtCallbackCheckList(XtCallbackList list, XmtProcedure proc)
681 #else
682 Boolean XmtCallbackCheckList(list, proc)
683 XtCallbackList list;
684 XmtProcedure proc;
685 #endif
686 {
687     Callback *cb;
688     int i;
689 
690     /* for each item in the callback list */
691     for(; list->callback != NULL; list++) {
692 	/* if the procedures match exactly */
693 	if (list->callback == (XtCallbackProc) proc) return True;
694 	/* else if it is the result of the converter */
695 	else if (list->callback == (XtCallbackProc) XmtCallCallback) {
696 	    /* the client data is a list of calls */
697 	    cb = (Callback *) list->closure;
698 	    for (i=0; i < cb->num_calls; i++) {
699 		/* if the callback has been called once and already converted*/
700 		if (cb->calls[i].procedure) {
701 		    if (cb->calls[i].procedure->function == proc) return True;
702 		}
703 		/* otherwise, we've got to look up procedures by name */
704 		else {
705 		    XmtProcedureInfo *procedure;
706 		    procedure =XmtLookupProcedure(cb->calls[i].procedure_name);
707 		    if (procedure && procedure->function == proc) return True;
708 		}
709 	    }
710 	}
711     }
712     return False;
713 }
714 
715