Improve and clarify documentation of timeout functions

Some functions didn't document the handling of arguments properly,
particularly Fl::has_timeout() and Fl::remove_timeout().

This is now fixed by documenting the correct behavior that was
preserved (re-implemented) from FLTK 1.3.x in the new class Fl_Timeout.

Unfortunately there have been some inconsistencies (likely unexpected
behavior) which have been preserved and which are now documented.
This commit is contained in:
Albrecht Schlosser 2022-10-20 19:36:03 +02:00
parent eca61ab98a
commit da11526bb8
4 changed files with 181 additions and 99 deletions

65
FL/Fl.H
View File

@ -90,7 +90,9 @@ typedef void (Fl_Label_Measure_F)(const Fl_Label *label, int &width, int &height
/** Signature of some box drawing functions passed as parameters */
typedef void (Fl_Box_Draw_F)(int x, int y, int w, int h, Fl_Color color);
/** Signature of some timeout callback functions passed as parameters */
/** Signature of timeout callback functions passed as parameters.
Please see Fl::add_timeout() for details.
*/
typedef void (*Fl_Timeout_Handler)(void *data);
/** Signature of some wakeup callback functions passed as parameters */
@ -451,63 +453,16 @@ public:
static void program_should_quit(int should_i) { program_should_quit_ = should_i; }
static Fl_Widget* readqueue();
/**
Adds a one-shot timeout callback. The function will be called by
Fl::wait() at <i>t</i> seconds after this function is called.
The optional void* argument is passed to the callback.
You can have multiple timeout callbacks. To remove a timeout
callback use Fl::remove_timeout().
//
// cross-platform timer support
//
If you need more accurate, repeated timeouts, use Fl::repeat_timeout() to
reschedule the subsequent timeouts.
static void add_timeout(double t, Fl_Timeout_Handler cb, void *data = 0);
static void repeat_timeout(double t, Fl_Timeout_Handler cb, void *data = 0);
static int has_timeout(Fl_Timeout_Handler cb, void *data = 0);
static void remove_timeout(Fl_Timeout_Handler cb, void *data = 0);
The following code will print "TICK" each second on
stdout with a fair degree of accuracy:
\code
#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
void callback(void*) {
printf("TICK\n");
Fl::repeat_timeout(1.0, callback); // retrigger timeout
}
int main() {
Fl_Window win(100,100);
win.show();
Fl::add_timeout(1.0, callback); // set up first timeout
return Fl::run();
}
\endcode
*/
static void add_timeout(double t, Fl_Timeout_Handler,void* = 0); // platform dependent
/**
Repeats a timeout callback from the expiration of the
previous timeout, allowing for more accurate timing.
You may only call this method inside a timeout callback of the same timer
or at least a closely related timer, otherwise the timing accuracy can't
be improved and the behavior is undefined.
The following code will print "TICK" each second on
stdout with a fair degree of accuracy:
\code
void callback(void*) {
puts("TICK");
Fl::repeat_timeout(1.0, callback);
}
int main() {
Fl::add_timeout(1.0, callback);
return Fl::run();
}
\endcode
*/
static void repeat_timeout(double t, Fl_Timeout_Handler, void* = 0); // platform dependent
static int has_timeout(Fl_Timeout_Handler, void* = 0);
static void remove_timeout(Fl_Timeout_Handler, void* = 0);
static void add_check(Fl_Timeout_Handler, void* = 0);
static int has_check(Fl_Timeout_Handler, void* = 0);
static void remove_check(Fl_Timeout_Handler, void* = 0);

View File

@ -231,33 +231,129 @@ int Fl::event_inside(const Fl_Widget *o) /*const*/ {
}
//
// cross-platform timer support
// Cross-platform timer support
//
// User (doxygen) documentation is in this file but the implementation
// of all functions is in class Fl_Timeout in Fl_Timeout.cxx.
void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *argp) {
Fl_Timeout::add_timeout(time, cb, argp);
}
/**
Adds a one-shot timeout callback.
void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp) {
Fl_Timeout::repeat_timeout(time, cb, argp);
The callback function \p cb will be called by Fl::wait() at \p time seconds
after this function is called.
The callback function must have the signature \ref Fl_Timeout_Handler.
The optional \p data argument is passed to the callback (default: NULL).
The timer is removed from the timer queue before the callback function is
called. It is safe to reschedule the timeout inside the callback function.
You can have multiple timeout callbacks, even the same timeout callback
with different timeout values and/or different \p data values. They are
all considered different timer objects.
To remove a timeout while it is active (pending) use Fl::remove_timeout().
If you need more accurate, repeated timeouts, use Fl::repeat_timeout() to
reschedule the subsequent timeouts. Please see Fl::repeat_timeout() for
an example.
\param[in] time delta time in seconds until the timer expires
\param[in] cb callback function
\param[in] data optional user data (default: \p NULL)
\see Fl_Timeout_Handler
\see Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data)
\see Fl::remove_timeout(Fl_Timeout_Handler cb, void *data)
\see Fl::has_timeout(Fl_Timeout_Handler cb, void *data)
*/
void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *data) {
Fl_Timeout::add_timeout(time, cb, data);
}
/**
Returns true if the timeout exists and has not been called yet.
*/
int Fl::has_timeout(Fl_Timeout_Handler cb, void *argp) {
return Fl_Timeout::has_timeout(cb, argp);
Repeats a timeout callback from the expiration of the previous timeout,
allowing for more accurate timing.
You should call this method only inside a timeout callback of the same or
a logically related timer from whose expiration time the new timeout shall
be scheduled. Otherwise the timing accuracy can't be improved and the
exact behavior is undefined.
If you call this outside a timeout callback the behavior is the same as
Fl::add_timeout().
Example: The following code will print "TICK" each second on stdout with
a fair degree of accuracy:
\code
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <stdio.h>
void callback(void *) {
printf("TICK\n");
Fl::repeat_timeout(1.0, callback); // retrigger timeout
}
int main() {
Fl_Window win(100, 100);
win.show();
Fl::add_timeout(1.0, callback); // set up first timeout
return Fl::run();
}
\endcode
\param[in] time delta time in seconds until the timer expires
\param[in] cb callback function
\param[in] data optional user data (default: \p NULL)
*/
void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data) {
Fl_Timeout::repeat_timeout(time, cb, data);
}
/**
Removes a timeout callback. It is harmless to remove a timeout
callback that no longer exists.
Returns true if the timeout exists and has not been called yet.
\note This version removes all matching timeouts, not just the first one.
This may change in the future.
*/
void Fl::remove_timeout(Fl_Timeout_Handler cb, void *argp) {
Fl_Timeout::remove_timeout(cb, argp);
Both arguments \p cb and \p data must match with at least one timer
in the queue of active timers to return true (1).
\note It is a known inconsistency that Fl::has_timeout() does not use
the \p data argument as a wildcard (match all) if it is zero (NULL)
which Fl::remove_timeout() does.
This is so for backwards compatibility with FLTK 1.3.x.
Therefore using 0 (zero, NULL) as the timeout \p data value is discouraged
unless you're sure that you don't need to use
<kbd>Fl::has_timeout(callback, (void *)0);</kbd> or
<kbd>Fl::remove_timeout(callback, (void *)0);</kbd>.
\param[in] cb Timer callback
\param[in] data User data
\returns whether the timer was found in the queue
\retval 0 not found
\retval 1 found
*/
int Fl::has_timeout(Fl_Timeout_Handler cb, void *data) {
return Fl_Timeout::has_timeout(cb, data);
}
/**
Removes a timeout callback from the timer queue.
This method removes all matching timeouts, not just the first one.
This may change in the future.
If the \p data argument is \p NULL (the default!) only the callback
\p cb must match, i.e. all timer entries with this callback are removed.
It is harmless to remove a timeout callback that no longer exists.
\param[in] cb Timer callback to be removed (must match)
\param[in] data Wildcard if NULL (default), must match otherwise
*/
void Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) {
Fl_Timeout::remove_timeout(cb, data);
}

View File

@ -112,29 +112,19 @@ void Fl_Timeout::insert() {
}
/**
Returns whether the given timeout is active.
This returns whether a timeout handler already exists in the queue
of active timers.
If \p data == NULL only the Fl_Timeout_Handler \p cb must match to return
true, otherwise \p data must also match.
\note It is a restriction that there is no way to look for a timeout whose
\p data is NULL (zero). Therefore using 0 (zero, NULL) as the timeout
\p data value is discouraged, unless you're sure that you will never
need to use <kbd>Fl::has_timeout(callback, (void *)0);</kbd>.
Implements Fl::has_timeout(Fl_Timeout_Handler cb, void *data)
Returns true if the timeout exists and has not been called yet.
\param[in] cb Timer callback (must match)
\param[in] data Wildcard if NULL, must match otherwise
\param[in] data Callback user data (must match)
\returns whether the timer was found in the queue
\retval 0 not found
\retval 1 found
*/
Implements Fl::has_timeout(Fl_Timeout_Handler cb, void *data)
\see Fl::has_timeout(Fl_Timeout_Handler cb, void *data)
*/
int Fl_Timeout::has_timeout(Fl_Timeout_Handler cb, void *data) {
for (Fl_Timeout *t = first_timeout; t; t = t->next) {
if (t->callback == cb && t->data == data)
@ -143,12 +133,39 @@ int Fl_Timeout::has_timeout(Fl_Timeout_Handler cb, void *data) {
return 0;
}
/**
Adds a one-shot timeout callback.
The callback function \p cb will be called by Fl::wait() at \p time seconds
after this function is called.
\param[in] time delta time in seconds until the timer expires
\param[in] cb callback function
\param[in] data optional user data (default: \p NULL)
Implements Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *data)
\see Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *data)
*/
void Fl_Timeout::add_timeout(double time, Fl_Timeout_Handler cb, void *data) {
elapse_timeouts();
Fl_Timeout *t = get(time, cb, data);
t->Fl_Timeout::insert();
t->insert();
}
/**
Repeats a timeout callback from the expiration of the previous timeout,
allowing for more accurate timing.
\param[in] time delta time in seconds until the timer expires
\param[in] cb callback function
\param[in] data optional user data (default: \p NULL)
Implements Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data)
\see Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data)
*/
void Fl_Timeout::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data) {
elapse_timeouts();
Fl_Timeout *t = (Fl_Timeout *)get(time, cb, data);
@ -162,13 +179,17 @@ void Fl_Timeout::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data)
}
/**
Remove a timeout callback. It is harmless to remove a timeout
callback that no longer exists.
Remove a timeout callback.
\note This version removes all matching timeouts, not just the first one.
This may change in the future.
This method removes all matching timeouts, not just the first one.
This may change in the future.
\param[in] cb Timer callback to be removed (must match)
\param[in] data Wildcard if NULL, must match otherwise
Implements Fl::remove_timeout(Fl_Timeout_Handler cb, void *data)
\see Fl::remove_timeout(Fl_Timeout_Handler cb, void *data)
*/
void Fl_Timeout::remove_timeout(Fl_Timeout_Handler cb, void *data) {
for (Fl_Timeout** p = &first_timeout; *p;) {

View File

@ -29,19 +29,27 @@
- Fl::add_timeout()
- Fl::repeat_timeout()
- Fl::remove_timeout()
- Fl::has_timeout()
- Fl::remove_timeout()
and related methods of class Fl_Timeout.
*/
/**
Class Fl_Timeout handles all timeout related functions.
The internal class Fl_Timeout handles all timeout related functions.
All code is platform independent except retrieving a timestamp which
requires calling a system driver function and potentially results in
different timer resolutions (from milliseconds to microseconds).
Related user documentation:
- \ref Fl_Timeout_Handler
- Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *data)
- Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data)
- Fl::has_timeout(Fl_Timeout_Handler cb, void *data)
- Fl::remove_timeout(Fl_Timeout_Handler cb, void *data)
All code is platform independent except retrieving a timestamp
which requires calling a system driver function and potentially
results in different timer resolutions (from milliseconds to
microseconds).
*/
class Fl_Timeout {
@ -62,8 +70,10 @@ protected:
skip = 0;
}
// destructor
~Fl_Timeout() {}
// get a new timer entry from the pool or allocate a new one
static Fl_Timeout *get(double time, Fl_Timeout_Handler cb, void *data);
// insert this timer into the active timer queue, sorted by expiration time