[comp.windows.x] Defining Callbacks from resource files

fidelio@guug.UUCP (Michelle Nelson) (12/19/89)

Hello.
I am having a problem setting up callback functions from a resource file.
I would like to be able to choose which function is called from a particular
menu item at run time and not compile it into the program. The error which
I get when trying to use the following resource file definition

Fbmenu*menu_item1*select:	(* purchasing)()
	or this resource file definition
Fbmenu*menu_item1*select:	purchasing
is:
X Toolkit Warning: No type converter registered for 'String' to 'Callback'
conversion.

I know that the select resource wants a pointer to a function 
and that this is a string.
There doesn't seem to be a converter from string to pointer...
I am using the hp widgets and toolkit.
Please let me know if you have any suggestions.  (i.e. if I am being
unreasonable about defining callbacks at runtime...)  I am a relative
newcomer to X windows programming. 

(e-mail would be greately appreciated as I am worried I would miss
the response on the newsgroup.)


Michelle Nelson				

swick@ATHENA.MIT.EDU (Ralph R. Swick) (12/19/89)

    I am having a problem setting up callback functions from a resource file.
    ...
    X Toolkit Warning: No type converter registered for 'String' to 'Callback'
    conversion.


Not too surprising.  While not impossible to accomplish, writing a
procedure which would permit you to specify real function names
in a resource file requires a considerable amount of operating-system-
specific support.  It has not been implemented (nor is it documented
to be implemented or likely to be implemented in the near future :-)
in any MIT release.

To allow portable specification of procedure bindings in resource
files, Xt provides another facility very similar to callbacks known
as Action procedures.  See chapter 10 of the Xt document.  While
not a replacement for callbacks, action procedures are most
definitely intended to be used to do what you want:

    I would like to be able to choose which function is called from a particular
    menu item at run time and not compile it into the program. 

-Ralph R. Swick

brianw@gazooch.Sun.COM (Brian Warkentine) (12/20/89)

In article <8912191502.AA22891@LYRE.MIT.EDU> swick@ATHENA.MIT.EDU (Ralph R. Swick) writes:
>
>    I am having a problem setting up callback functions from a resource file.
>    ...
>    X Toolkit Warning: No type converter registered for 'String' to 'Callback'
>    conversion.
>
>
>Not too surprising.  While not impossible to accomplish, writing a
>procedure which would permit you to specify real function names
>in a resource file requires a considerable amount of operating-system-
>specific support.
> [ ... ]
>To allow portable specification of procedure bindings in resource
>files, Xt provides another facility very similar to callbacks known
>as Action procedures.  
>-Ralph R. Swick


	You're contradicting yourself.  Since one can already bind action proc 
	names to "real functions", why would it be operating system dependent 
	to bind callback names to "real functions?"

	Suppose that callbacks could be registered in a fashion similar 
	to action proc registration.  The difference is subtle but its a 
	win:  A user could specify a callback in .Xdefaults (or where ever)
	without having to worry about what sequence of events are required 
	to trigger that callback.

-brian warkentine
brianw@sun.com

grunwald@foobar.colorado.edu (Dirk Grunwald) (12/20/89)

>>>>> On 19 Dec 89 18:45:23 GMT, brianw@gazooch.Sun.COM (Brian Warkentine) said:

Brian> 	You're contradicting yourself.  Since one can already bind action proc 
Brian> 	names to "real functions", why would it be operating system dependent 
Brian> 	to bind callback names to "real functions?"
---

Action procs are bound at compile time; a string -> proc converter
would need to load the symbol table to determine the function address.
This is O/S dependent. Also, if the symbol table has been striped, it
won't work.

swick@ATHENA.MIT.EDU (Ralph R. Swick) (12/20/89)

	You're contradicting yourself.  Since one can already bind action proc 
	names to "real functions", why would it be operating system dependent 
	to bind callback names to "real functions?"

Go read the manual.  There's some extra work to be done, basically
to provide an OS-independent symbol table equivalent.

	Suppose that callbacks could be registered in a fashion similar 
	to action proc registration.

That would certainly be one way to implement the String to Callback
converter.  Anyone who wants is welcome to prototype it...

brianw@gazooch.Sun.COM (Brian Warkentine) (12/20/89)

In article <15040@boulder.Colorado.EDU> grunwald@foobar.colorado.edu writes:
>>>>>> On 19 Dec 89 18:45:23 GMT, brianw@gazooch.Sun.COM (Brian Warkentine) said:
>
>Action procs are bound at compile time; a string -> proc converter
>would need to load the symbol table to determine the function address.
>This is O/S dependent. Also, if the symbol table has been striped, it
>won't work.

	You missed the point:  binding functions (aka "actions procs") to 
	function names is already being done with action procs.  What makes 
	doing it with callback procs any more system dependent?  You're 
	reading "arbitrary function binding" into what I wrote.  I agree,
	it's not portable.  Furthermore, I don't believe this is necessary or 
	even desirable.

-brian warkentine
brianw@sun.com

marbru@auto-trol.UUCP (Martin Brunecky) (12/20/89)

Writing a String to Callback converter is a trivial thing. Just look at the
Intrinsic code for an example. What may NOT be such a trivial thing is making
the converter code aware of any callback procedures that the application
provides.

A simple and portable way to do that are "registration routines". A function
called by the application (presumably BEFORE any widgets are created), which
hands the callback procedure name(String) and pointer to the converter
code (which must implement some sort of callback procedures database - but
a simple linked list would work too, unless you want to explore magics
of Xrm).

Someone may complain that using registeration routines is not very elegant.
But since a programmer has to write most of his callbacks, one registration
call per callback seems fair to me.

For really elegant solution, you need systems which support runtime binding,
such as Apollo Aegis, OS/2 - and you can do it even with VMS, and may be
(I haven't tried it) with  Sun OS. Your application must be shareable image,
VMS gives you LIB$FIND_IMAGE_SYMBOL which does exactly what we want - finds
a pointer to a named function/procedure. The same thing must be possible on
Sun - and may be it's out there, forgive my ignorance.
-- 
###############################################################################
Martin Brunecky, Auto-trol Technology Corporation,
12500 North Washington Street, Denver, CO-80241-2404
(303) 252-2499                                        ncar!ico!auto-trol!marbru

gary@CTC.CONTEL.COM (Gary Bisaga x4219) (12/21/89)

Martin Brunecky writes:
>  Someone may complain that using registeration routines is not very elegant.
>  But since a programmer has to write most of his callbacks, one registration
>  call per callback seems fair to me.

The problem here, of course, is not only that the programmer must write a
second function as an "initialization" for the callback registration,
but also that this function must be called essentially automatically at
process startup time.  This type of thing is a pain to remember, especially
when there are multiple programmers and many such functions -- it's
exceedingly easy to forget to do consistently.

With C++, there is a simple and automatic way of doing this.  Define a
class called, for example, XXX as follows:

    class XXX
    {
        int dummy;
    public:
        XXX(void (*callbackFunction)(), char *registrationName)
           {registerCallback(callbackFunction, registrationName);}
    };

The registerCallback function, invoked from the constructor, should make
an entry into a table (linked list, hashed table, fill in the blank)
registering the connection between the function and string.  Then define
a macro DEFINE_CALLBACK which calls the XXX constructor as follows:

    #define DEFINE_CALLBACK(functionName) \
        void functionName(); \
        static class XXX functionName_Callback(functionName, "functionName"); \
        void functionName

Every function which must be registered as a callback should be defined
using the DEFINE_CALLBACK macro.  Usage is as follows:

    DEFINE_CALLBACK(MyCallbackFunc)(int firstArg, void *secondArg)
    {
        ...
    }

This works, of course, because of C++'s automatic calls to constructors at
the beginning of the scope of the variable, which in this case is process
startup.

Gary Bisaga (gary@ctc.contel.com)