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