Re: XForms: FW: fl_idle_callback() usage

Steve Lamont (spl@szechuan.ucsd.edu)
Tue, 5 Aug 97 06:31:05 PDT

To subscribers of the xforms list from spl@szechuan.ucsd.edu (Steve Lamont) :

> I'm new to c programming and very new to XForms, so please be
> patient with me. I am confused as to how the fl_idle_callback()
> function works. I want to call a function when the application
> is idle. I've read the manual but I'm still hazy. could
> somebody give me some skeleton code for its usage, especial how
> to deal with FB_APPEVENT (it is a structure isn't it). ...

There is no such thing in XForms as FB_APPEVENT. I presume you're
referring to FL_APPEVENT_CB. This is a pointer to a function
returning int, defined in forms.h as

typedef int (*FL_APPEVENT_CB) (XEvent *, void *);

and it's used in the call to fl_set_idle_callback() to tell XForms
what function you want to call. fl_set_idle_callback() returns a
pointer to the current idle callback function which you may wish to
keep track of or ignore if you know there is to be only one idle callback.

Note that only one idle callback may be in effect at any time. They
do not stack. If you need some sort of stacking or queuing mechanism,
you'll have to concoct it yourself.

Here's a short, skeletal, example:

{

int my_idle_callback_cb( XEvent *event, void *data );
MyOwnStructure *my_data_ptr;

[...]

fl_set_idle_callback( my_idle_callback_cb, ( void *) my_data_ptr );

[...]

}

int my_idle_callback_cb( XEvent *event, void *data )

{

MyOwnStructure *my_data_ptr = ( MyOwnStructure *) data;

/*
* Do something very brief here -- no more than about 0.1 second
* of wall clock time's worth.
*/

[...]

if ( done_with_work )
fl_set_idle_callback( NULL, NULL );

return 0; /* XForms doesn't use the return value */

}

The function my_idle_callback_cb will be called whenever XForms has
nothing else useful to do. The callback should perfrom some small
quantum of work that should last no more than 0.1 seconds (TC says in
the manual 300 milliseconds -- 0.3 seconds -- but I've found that
amount of delay can be perceptible to the user -- you certainly should
not exceed 300 milliseconds).

If you are doing some long running computation, you will have to save
or maintain some sort of state at the end of each little quantum of
work. You can do this with (in order of my personal preference) the
data structure passed as the pointer to void `data' in the callback
parameter list, static variables, or global variables. I've
considered using the longjmp() function as well but have never worked
out the details on how it might be used -- I suspect it would not be
the Right Thing for a novice C programmer to attempt to use, first
crack out of the box.

How you determine the amount of time spent in the function is up to
you. You can simply use loop counters which, of course, will mean
that the amount of time spent in the loop will vary depending upon
what machine the client runs. If you know your target audience, this
is probably the easiest thing to do.

Otherwise you can use the gettimeofday() system call to time your
loop. I do something like:

#include <sys/time.h>

[...]

{

struct timeval tv0;
struct timeval tv1;

gettimeofday( &tv0, NULL );

/* Setup and establish context here */

[...]

do {

/* Do a very small chunk of work */

gettimeofday( &tv1, NULL );

} while ( ( tv1.tv_sec - tv0.tv_sec ) +
( ( tv1.tv_usec - tv0.tv_usec ) * 1.0e-6 ) < QUANTUM );

/* Cleanup and save context here */

[...]

}

All of this above requires a certain amount of careful design of the
computational loop in order to handle the context, break the
computations into small chunks, etc. This level of design complexity
may be more than a novice programmer might wish upon h{er,im}self.

An alternative is to avoid idle callbacks altogether and use another
XForms function, fl_check_forms(), in your computational loop. This
could be used in a regular callback function which is connected to a
button that says "do the computation:"

void do_computation_callback_cb( FL_OBJECT *obj, long data )

{

int i;

/* Setup */

[...]

for ( i = 0; i < gazillion; i++ ) {

/* Do a loop of computational work */

[...]

fl_check_forms();

}

/* Tear down */

[...]

}

fl_check_forms() is the moral equivalent of fl_do_forms() except that
it returns instantly if there is nothing for XForms to do.

I like to think of this design as more or less the idle callback model
turned inside out. While IMHO it is less elegant and flexible than
the idle callback model and has its own set of problems (for instance,
do you allow a recursive entry into the function if the luser presses
the "do the computation button" while the function is running? If
not, don't forget to disable the calling object and, if appropriate,
enable it when you're done), it is popular and has a number of
proponents on this list.

spl (the p stands for
promises not to mention
browsers or HTML
ever again)
_________________________________________________
To unsubscribe, send the message "unsubscribe" to
xforms-request@bob.usuf2.usuhs.mil or see
http://bob.usuf2.usuhs.mil/mailserv/xforms.html
Xforms Home Page: http://bragg.phys.uwm.edu/xforms
List Archive: http://bob.usuf2.usuhs.mil/mailserv/list-archives/