2
* Motif Tools Library, Version 3.1
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.
12
* Revision 1.1.1.1 2001/07/18 11:06:01 root
15
* Revision 1.1 2001/06/12 15:00:21 andre
16
* AA-2001-06-12-0: replaced Xmt212 by Xmt310
17
* (http://sourceforge.net/projects/motiftools) with
18
* our xmt212 patches applied
24
#include <Xmt/ProceduresP.h>
25
#include <Xmt/Symbols.h>
26
#include <Xmt/ConvertersP.h>
28
#include <Xmt/Lexer.h>
29
#include <Xmt/QuarksP.h>
32
String procedure_name;
33
XmtProcedureInfo *procedure;
34
String argument_strings[XmtMAX_PROCEDURE_ARGS];
35
XtPointer arguments[XmtMAX_PROCEDURE_ARGS];
36
XmtSymbol symbols[XmtMAX_PROCEDURE_ARGS];
46
typedef void (*XmtProcedure0)(
47
#if NeedFunctionPrototypes
51
typedef void (*XmtProcedure1)(
52
#if NeedFunctionPrototypes
56
typedef void (*XmtProcedure2)(
57
#if NeedFunctionPrototypes
61
typedef void (*XmtProcedure3)(
62
#if NeedFunctionPrototypes
63
XtPointer, XtPointer, XtPointer
66
typedef void (*XmtProcedure4)(
67
#if NeedFunctionPrototypes
72
typedef void (*XmtProcedure5)(
73
#if NeedFunctionPrototypes
74
XtPointer, XtPointer, XtPointer,
78
typedef void (*XmtProcedure6)(
79
#if NeedFunctionPrototypes
80
XtPointer, XtPointer, XtPointer,
81
XtPointer, XtPointer, XtPointer
84
typedef void (*XmtProcedure7)(
85
#if NeedFunctionPrototypes
86
XtPointer, XtPointer, XtPointer,
87
XtPointer, XtPointer, XtPointer,
91
typedef void (*XmtProcedure8)(
92
#if NeedFunctionPrototypes
93
XtPointer, XtPointer, XtPointer,
94
XtPointer, XtPointer, XtPointer,
99
#if NeedFunctionPrototypes
100
static void ExpectedWarning(String s)
102
static void ExpectedWarning(s)
106
XmtWarningMsg("XmtConvertStringToCallback", "expected",
111
#if NeedFunctionPrototypes
112
static Boolean ParseCall(XmtLexer l, CallInfo *ci)
114
static Boolean ParseCall(l, ci)
123
ci->procedure_name = NULL;
124
ci->procedure = NULL;
125
for(i=0; i < XmtMAX_PROCEDURE_ARGS; i++) {
126
ci->argument_strings[i] = NULL;
127
ci->arguments[i] = NULL;
128
ci->symbols[i] = NULL;
132
tok = XmtLexerGetToken(l);
133
if (tok != XmtLexerIdent) {
134
ExpectedWarning("procedure name");
138
ci->procedure_name = XmtLexerStrValue(l);
139
XmtLexerConsumeToken(l);
141
if (XmtLexerGetToken(l) != XmtLexerLParen) {
142
ExpectedWarning("'('");
146
XmtLexerGetArgList(l,ci->argument_strings,XmtMAX_PROCEDURE_ARGS,&num_args);
150
/* free any strings allocated so far. XtFree is okay with NULL */
151
XtFree(ci->procedure_name);
152
ci->procedure_name = NULL;
153
for(i=0; i < XmtMAX_PROCEDURE_ARGS; i++) {
154
XtFree(ci->argument_strings[i]);
155
ci->argument_strings[i] = NULL;
161
#if NeedFunctionPrototypes
162
static Callback *StringToCallback(String str)
164
static Callback *StringToCallback(str)
168
static XmtLexer l = NULL;
176
l = XmtLexerCreate((String *)NULL, 0);
178
XmtLexerInit(l, str);
183
while(XmtLexerGetToken(l) != XmtLexerEndOfString) {
185
if (max == 0) max = 4; else max *= 2;
186
calls = (CallInfo*)XtRealloc((char*)calls, sizeof(CallInfo) * max);
188
/* parse a single procedure call */
189
stat = ParseCall(l, &calls[num]);
191
else { /* on error read 'till next semicolon */
193
tok = XmtLexerGetToken(l);
194
if ((tok == XmtLexerSemicolon) ||
195
(tok == XmtLexerEndOfString)) break;
196
XmtLexerConsumeToken(l);
200
/* and discard any semicolons */
201
while (XmtLexerGetToken(l) == XmtLexerSemicolon)
202
XmtLexerConsumeToken(l);
205
if (num == 0) { /* if empty string or errors */
206
XtFree((char *)calls);
210
calls = (CallInfo *)XtRealloc((char *)calls, sizeof(CallInfo)*num);
211
cb = XtNew(Callback);
219
#if NeedFunctionPrototypes
220
static void DestroyCallback(Callback *cb)
222
static void DestroyCallback(cb)
229
for(i=0; i < cb->num_calls; i++) {
230
info = &cb->calls[i];
231
XtFree(info->procedure_name);
232
for(j=0; j < XmtMAX_PROCEDURE_ARGS; j++)
233
XtFree(info->argument_strings[j]);
235
XtFree((char *) cb->calls);
239
#if NeedFunctionPrototypes
240
static void ConvertArg(Widget w, CallInfo *call, int i, int j)
242
static void ConvertArg(w, call, i, j)
251
XmtProcedureInfo *proc = call->procedure;
254
* if the argument is a symbol name, bind it,
255
* check the type, and remember the symbol
257
if (call->argument_strings[j][0] == '$') {
258
call->symbols[i] = XmtLookupSymbol(&call->argument_strings[j][1]);
260
if (!call->symbols[i]) {
261
XmtWarningMsg("XmtCallCallbacks", "symbol",
262
"argument %d of procedure %s.\n\tSymbol '%s' is undefined.",
263
j, call->procedure_name,
264
call->argument_strings[j]);
269
* A buffer symbol will match a string argument.
271
XrmQuark symtype = XmtSymbolTypeQuark(call->symbols[i]);
272
XrmQuark argtype = (XrmQuark) proc->argument_types[i];
273
if ((symtype != argtype) &&
274
!((symtype == XmtQBuffer) && (argtype == XmtQString))) {
275
XmtWarningMsg("XmtCallCallbacks", "symbolType",
276
"type mismatch:\n\targument %d of procedure %s.\n\tSymbol '%s' is not of type %s",
277
j, call->procedure_name,
278
XmtSymbolName(call->symbols[i]),
279
XrmQuarkToString((XrmQuark)
280
proc->argument_types[i]));
281
call->symbols[i] = NULL;
284
if (!call->symbols[i]) call->error = True;
288
* if it is not a symbol, then if it is a string constant, we're done.
289
* otherwise, we've got to convert our string to the appropriate type.
291
if ((XrmQuark)proc->argument_types[i] == XmtQString) {
292
call->arguments[i] = (XtPointer)call->argument_strings[j];
295
from.addr = (XPointer) call->argument_strings[j];
296
from.size = strlen(from.addr)+1;
297
to.addr = (XPointer) NULL;
298
/* XtConvertAndStore() will ensure that converted
299
* values are freed when the widget w is destroyed.
301
stat = XtConvertAndStore(w, XtRString, &from,
302
XrmQuarkToString((XrmQuark)proc->argument_types[i]),
306
XmtWarningMsg("XmtCallCallbacks", "typeMismatch",
307
"type mismatch: \n\targument %d of procedure %s.\n\tCan't convert \"%s\" to type %s",
308
j, call->procedure_name,
309
call->argument_strings[i],
310
XrmQuarkToString((XrmQuark)
311
proc->argument_types[i]));
316
* This code isn't as portable as it should be, but it
317
* does seem to work on 32-bit architectures, and 64-bit Alpha.
318
* I don't know if there are any architectures that have
319
* calling conventions unlike those assumed here.
321
* All functions registered with the callback converter
322
* must expect arguments of the same size as XtPointer.
323
* This means that chars and shorts must be "widened"
324
* to longs. Also, arguments of type double are not
329
call->arguments[i] = (XtPointer)(long)*(char *)to.addr;
332
/* XXX signed vs. unsigned??? */
333
call->arguments[i] = (XtPointer)(long)*(short *)to.addr;
336
call->arguments[i] = (XtPointer)(long)*(int *)to.addr;
339
call->arguments[i] = (XtPointer)*(long *)to.addr;
347
#if NeedFunctionPrototypes
348
static void XmtCallCallback(Widget w, XtPointer tag, XtPointer data)
350
static void XmtCallCallback(w, tag, data)
356
Callback *cb = (Callback *) tag;
358
XmtProcedureInfo *proc;
363
for(n=0; n < cb->num_calls; n++) {
364
call = &cb->calls[n];
367
XmtWarningMsg("XmtCallCallback", "badCall",
368
"not calling %s() because of previous errors.",
369
call->procedure_name);
373
/* if this is the 1st time, figure out the procedure info */
374
/* also set a flag for use below */
375
if (call->procedure == NULL) {
377
call->procedure = XmtLookupProcedure(call->procedure_name);
378
if (call->procedure == NULL) {
379
XmtWarningMsg("XmtCallCallback", "unknown",
380
"unknown procedure %s",
381
call->procedure_name);
385
else firsttime = False;
387
proc = call->procedure;
389
/* if this is the first time, check the # of arguments */
392
(i < XmtMAX_PROCEDURE_ARGS) && (call->argument_strings[i]);
395
if (i != proc->expected_args) {
396
XmtWarningMsg("XmtCallCallback", "wrongNum",
397
"procedure %s expects %d arguments.",
398
call->procedure_name, proc->expected_args);
404
/* build up the array of arguments */
406
while((i < XmtMAX_PROCEDURE_ARGS) &&
407
(proc->argument_types[i] != (String)NULLQUARK)) {
408
if ((XrmQuark)proc->argument_types[i] == _XmtQCallbackWidget)
409
call->arguments[i] = (XtPointer) w;
410
else if ((XrmQuark)proc->argument_types[i] == _XmtQCallbackData)
411
call->arguments[i] = data;
412
else if((XrmQuark)proc->argument_types[i]==_XmtQCallbackAppContext)
413
call->arguments[i] =(XtPointer)XtWidgetToApplicationContext(w);
414
else if ((XrmQuark)proc->argument_types[i] == _XmtQCallbackWindow)
415
call->arguments[i] = (XtPointer) XtWindow(w);
416
else if ((XrmQuark)proc->argument_types[i] == _XmtQCallbackDisplay)
417
call->arguments[i] = (XtPointer) XtDisplay(w);
418
else if ((XrmQuark)proc->argument_types[i] == _XmtQCallbackUnused)
419
call->arguments[i] = NULL;
422
* if this is the first time this CallInfo has been called,
423
* we've got to convert the argument string to the expected
424
* type, or to a symbol of the expected type. If the argument
425
* is a constant, then we can use it for all subsequent calls.
426
* if the argument is a symbol, we save the bound symbol,
427
* and look up its value for each subsequent call.
428
* Note we convert argument_string[j] to argument[i].
431
ConvertArg(w, call, i, j);
434
* if the arg is a symbol, get its value.
435
* Otherwise, its a constant, already converted, so do nothing.
437
if (call->symbols[i]) {
438
XmtSymbolGetValue(call->symbols[i],
439
(XtArgVal *)&call->arguments[i]);
443
if (call->error) break;
447
if (call->error) continue;
451
* If you change XmtMAX_PROCEDURE_ARGS, change this code too.
452
* Note that all functions declared this way must expect
453
* all their arguments to be the same size as XtPointer.
454
* On most (all?) architectures it is safe to pass extra arguments
455
* to functions, so we could just do case 8: here in all cases.
456
* But this is a little cleaner when using a debugger, for example.
458
switch(i) { /* number of arguments*/
460
(*((XmtProcedure0)proc->function))();
463
(*((XmtProcedure1)proc->function))(call->arguments[0]);
466
(*((XmtProcedure2)proc->function))
467
(call->arguments[0], call->arguments[1]);
470
(*((XmtProcedure3)proc->function))
471
(call->arguments[0], call->arguments[1],
475
(*((XmtProcedure4)proc->function))
476
(call->arguments[0], call->arguments[1],
477
call->arguments[2], call->arguments[3]);
480
(*((XmtProcedure5)proc->function))
481
(call->arguments[0], call->arguments[1],
482
call->arguments[2], call->arguments[3],
486
(*((XmtProcedure6)proc->function))
487
(call->arguments[0], call->arguments[1],
488
call->arguments[2], call->arguments[3],
489
call->arguments[4], call->arguments[5]);
492
(*((XmtProcedure7)proc->function))
493
(call->arguments[0], call->arguments[1],
494
call->arguments[2], call->arguments[3],
495
call->arguments[4], call->arguments[5],
499
(*((XmtProcedure8)proc->function))
500
(call->arguments[0], call->arguments[1],
501
call->arguments[2], call->arguments[3],
502
call->arguments[4], call->arguments[5],
503
call->arguments[6], call->arguments[7]);
512
#if NeedFunctionPrototypes
513
Boolean XmtConvertStringToCallback(Display *dpy,
514
XrmValue *args, Cardinal *num_args,
515
XrmValue *from, XrmValue *to,
516
XtPointer *converter_data)
518
Boolean XmtConvertStringToCallback(dpy, args, num_args, from, to,
525
XtPointer *converter_data;
531
callback = StringToCallback((char *)from->addr);
533
if (callback == NULL) { /* error, couldn't convert */
534
/* XXX print the string here, and mark where the error occured. */
538
list = (XtCallbackList)XtCalloc(sizeof(XtCallbackRec), 2);
539
list[0].callback = (XtCallbackProc) XmtCallCallback;
540
list[0].closure = (XtPointer) callback;
541
done(XtCallbackList, list);
546
#if NeedFunctionPrototypes
547
static void XmtDestroyCallback(XtAppContext app, XrmValue *to,
548
XtPointer converter_data,
549
XrmValue *args, Cardinal *num_args)
551
static void XmtDestroyCallback(app, to, converter_data, args, num_args)
554
XtPointer converter_data;
559
XtCallbackList list = *(XtCallbackList *)to->addr;
561
DestroyCallback((Callback *)list[0].closure);
562
XtFree((char *)list);
565
#if NeedFunctionPrototypes
566
void XmtRegisterCallbackConverter(void)
568
void XmtRegisterCallbackConverter()
571
static Boolean registered = False;
576
* Note that the results of this converter cannot be cached, because
577
* the callback arguments need to be converted in the context of
578
* their particular widget and thus cannot be shared. It doesn't
579
* make much sense, however, to have lots of widgets with the same
580
* callbacks and arguments, however, so this is no great loss.
582
XtSetTypeConverter(XtRString, XtRCallback,
583
XmtConvertStringToCallback, NULL, 0,
584
XtCacheNone | XtCacheRefCount,
587
/* ensure that the quarks we need will exist when the
588
* converter is called
593
* we also register the converter in variables declared in
594
* GlobalsI.h so that it can be looked up by the automatic
595
* widget creation routines. We don't want those routines to
596
* reference these directly because then they would be linked
599
_XmtCallbackConverter = XmtConvertStringToCallback;
603
#if NeedFunctionPrototypes
604
Boolean XmtCallbackCheckList(XtCallbackList list, XmtProcedure proc)
606
Boolean XmtCallbackCheckList(list, proc)
614
/* for each item in the callback list */
615
for(; list->callback != NULL; list++) {
616
/* if the procedures match exactly */
617
if (list->callback == (XtCallbackProc) proc) return True;
618
/* else if it is the result of the converter */
619
else if (list->callback == (XtCallbackProc) XmtCallCallback) {
620
/* the client data is a list of calls */
621
cb = (Callback *) list->closure;
622
for (i=0; i < cb->num_calls; i++) {
623
/* if the callback has been called once and already converted*/
624
if (cb->calls[i].procedure) {
625
if (cb->calls[i].procedure->function == proc) return True;
627
/* otherwise, we've got to look up procedures by name */
629
XmtProcedureInfo *procedure;
630
procedure =XmtLookupProcedure(cb->calls[i].procedure_name);
631
if (procedure && procedure->function == proc) return True;