[comp.windows.open-look] Passing member functions

pete@TIRS.oz.au (Peter Bartel) (05/24/91)

When writing an XView program with C++, you can specify a function to
be called when a button is pressed by:
    
    class my_class {
	virtual void member_func1(void);
    }; 

    void my_class::member_func1(void)
    {
	extern void callback_routine(Panel_item, Event*);
	xv_set(button, PANEL_NOTIFY_PROC, callback_routine);
    }

In the above case, callback_routine is an ordinary function; not a member 
of any class. My question is: how do I tell XView to use a member function
as the panel notify procedure? What I want is something similar to the
following (which doesn't work).

    class my_class {
	virtual void member_func1(void);
	virtual void member_func2(Panel_item, Event*);
    };

    void my_class::member_func1(void)
    {
	xv_set(button, PANEL_NOTIFY_PROC, member_func2);
    }

    void my_class::member_func2(Panel_item item, Event *event)
    {
	fprintf(stderr, "hello");
    } 
_______________________________________________________________________
Peter Bartel	Senior Software Engineer	International
Phone:		+61-8-232-1740			Railroad
Faxstream:	+61-8-232-2274			Systems
E-mail:		pete@TIRS.oz.au			(Electronics)
Snail:		209-217 Wakefield St, Adelaide, South Australia, 5000

warsaw@nlm.nih.gov (Barry A. Warsaw) (05/25/91)

>>>>> "Peter" == Peter Bartel <pete@TIRS.oz.au> writes:

	Peter> In the above case, callback_routine is an ordinary
	Peter> function; not a member of any class. My question is: how do
	Peter> I tell XView to use a member function as the panel notify
	Peter> procedure? What I want is something similar to the
	Peter> following (which doesn't work).

[Example deleted for brevity]

The problem with using a (non-static) member function for a callback
is that it implicitly requires a `this' pointer, but the XView
notifier can't put one on the stack before calling your member
function.  Fortunately, there's a very simple workaround (and this is
what makes using XView with C++ fairly nice).  When you're setting up
the PANEL_NOTIFY_PROC, you want to use XV_KEY_DATA to attach the
`this' pointer to the XView object.

Next make the PANEL_NOTIFY_PROC a *static* member function (which does
not require an implicit `this') and in this function, extract the key
data placed on the object. Then use this object to call the member
function that does the guts of your callback. Something similar to the
following should do the trick.  One caveat: I don't use this code
fragment verbatim, but I do things along these lines.  Just be aware
that I haven't tested this exact example out, but it *should* work. ;-}

Hope this helps.

-Barry

NAME:  Barry A. Warsaw         INET: warsaw@nlm.nih.gov
TELE:  (301) 496-1936          UUCP: uunet!nlm.nih.gov!warsaw

==================== example ====================

class my_class
{
public:
	void btn_set_callback( void );

private:
	void do_btn_callback( Panel_item item, Event* event );
	static void btn_callback( Panel_item item, Event* event );

	Panel_item btn;
	static Attr_attribute INSTANCE;
};


Attr_attribute my_class::INSTANCE = xv_unique_key();


void my_class::btn_set_callback( void )
{
	xv_set( btn,
		PANEL_NOTIFY_PROC, &my_class::btn_callback,
		XV_KEY_DATA, INSTANCE, this,
		NULL );
};


void my_class::btn_callback( Panel_item item, Event* event )
{
	my_class* obj = (my_class*)xv_get( item, XV_KEY_DATA, INSTANCE );
	obj->do_btn_callback( item, event );
};


void my_class::do_btn_callback( Panel_item, Event* event )
{
	// implicit `this' is now set correctly, so you can access any
	// member of my_class you want.
};