From 456d53c403c478dd7a5eaf08abead6a7ac2808a0 Mon Sep 17 00:00:00 2001 From: Albrecht Schlosser Date: Fri, 21 Jun 2024 17:35:01 +0200 Subject: [PATCH] Add Fl::remove_next_timeout(...) to remove only one timeout (#992) This method also returns the data pointer of the removed timeout. This new method is generally useful for user code and particularly necessary to fix issue #991. Co-authored-by: Albrecht Schlosser --- FL/Fl.H | 1 + src/Fl.cxx | 55 ++++++++++++++++++++++++++++++++++++++---- src/Fl_Timeout.cxx | 59 ++++++++++++++++++++++++++++++++++++++++++---- src/Fl_Timeout.h | 5 +++- 4 files changed, 110 insertions(+), 10 deletions(-) diff --git a/FL/Fl.H b/FL/Fl.H index fef27fa93..c855eb754 100644 --- a/FL/Fl.H +++ b/FL/Fl.H @@ -479,6 +479,7 @@ public: 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); + static int remove_next_timeout(Fl_Timeout_Handler cb, void *data = 0, void **data_return = 0); static void add_check(Fl_Timeout_Handler, void* = 0); static int has_check(Fl_Timeout_Handler, void* = 0); diff --git a/src/Fl.cxx b/src/Fl.cxx index 6d59aa9b5..7be3fe39e 100644 --- a/src/Fl.cxx +++ b/src/Fl.cxx @@ -1,7 +1,7 @@ // // Main event handling code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -344,24 +344,69 @@ int Fl::has_timeout(Fl_Timeout_Handler cb, void *data) { } /** - Removes a timeout callback from the timer queue. + Remove one or more matching timeout callbacks from the timer queue. - This method removes all matching timeouts, not just the first one. - This may change in the future. + This method removes \b all matching timeouts, not just the first one. 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. + If you want to remove only the next matching timeout you can use + Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) + (available since FLTK 1.4.0). + \param[in] cb Timer callback to be removed (must match) \param[in] data Wildcard if NULL (default), must match otherwise + + \see Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) */ void Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) { Fl_Timeout::remove_timeout(cb, data); } +/** + Remove the next matching timeout callback and return its \p data pointer. + + This method removes only the next matching timeout and returns in + \p data_return (if non-NULL) the \p data member given when the timeout + was scheduled. + + This method is useful if you remove a timeout before it is scheduled + and you need to get and use its data value, for instance to free() or + delete the data associated with the timeout. + + This method returns non-zero if a matching timeout was found and zero + if no timeout matched the request. + + If the return value is \c N \> 1 then there are N - 1 more matching + timeouts pending. + + If you need to remove all timeouts with a particular callback \p cb + you must repeat this call until it returns 1 (all timeouts removed) + or zero (no matching timeout), whichever occurs first. + + + \param[in] cb Timer callback to be removed (must match) + \param[in] data Wildcard if NULL, must match otherwise + \param[inout] data_return Pointer to (void *) to receive the data value + + \return non-zero if a timer was found and removed + \retval 0 no matching timer was found + \retval 1 the last matching timeout was found and removed + \retval N>1 a matching timeout was removed and there are \n + (N - 1) matching timeouts pending + + \see Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) + + \since 1.4.0 +*/ +int Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) { + return Fl_Timeout::remove_next_timeout(cb, data, data_return); +} + //////////////////////////////////////////////////////////////// // Checks are just stored in a list. They are called in the reverse @@ -1979,7 +2024,7 @@ void Fl::clear_widget_pointer(Fl_Widget const *w) { ..off.. } \endcode - \note Options can be managed with the \c fltk-options program, new in + \note Options can be managed with the \c fltk-options program, new in FLTK 1.4.0. In 1.3.x, options can be set in FLUID. \param opt which option diff --git a/src/Fl_Timeout.cxx b/src/Fl_Timeout.cxx index 3c04cae17..9aa89b839 100644 --- a/src/Fl_Timeout.cxx +++ b/src/Fl_Timeout.cxx @@ -210,7 +210,9 @@ void Fl_Timeout::insert() { \retval 0 not found \retval 1 found - Implements Fl::has_timeout(Fl_Timeout_Handler cb, void *data) + Implements: + + int Fl::has_timeout(Fl_Timeout_Handler cb, void *data) \see Fl::has_timeout(Fl_Timeout_Handler cb, void *data) */ @@ -232,7 +234,9 @@ int Fl_Timeout::has_timeout(Fl_Timeout_Handler cb, void *data) { \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) + Implements: + + void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *data) \see Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *data) */ @@ -250,7 +254,9 @@ void Fl_Timeout::add_timeout(double time, Fl_Timeout_Handler cb, void *data) { \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) + Implements: + + void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data) \see Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data) */ @@ -276,7 +282,9 @@ void Fl_Timeout::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data) \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) + Implements: + + void Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) \see Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) */ @@ -293,6 +301,49 @@ void Fl_Timeout::remove_timeout(Fl_Timeout_Handler cb, void *data) { } } +/** + Remove the next matching timeout callback and return its \p data pointer. + + Implements: + + int Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) + + \param[in] cb Timer callback to be removed (must match) + \param[in] data Wildcard if NULL, must match otherwise + \param[inout] data_return pointer to void * to receive the data value + + \return non-zero if a timer was found and removed + \retval 0 no matching timer was found + \retval 1 the last matching timeout was found and removed + \retval N>1 a matching timeout was removed and there are\n + (N - 1) matching timeouts pending + + For details + \see Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) +*/ +int Fl_Timeout::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) { + int ret = 0; + for (Fl_Timeout** p = &first_timeout; *p;) { // scan all timeouts + Fl_Timeout* t = *p; + if (t->callback == cb && (t->data == data || !data)) { // timeout matches + ret++; + if (ret == 1) { // first timeout: remove + if (data_return) + *data_return = t->data; + *p = t->next; + t->next = free_timeout; + free_timeout = t; + continue; + } + p = &(t->next); + } // timeout matches + else { // no match + p = &(t->next); + } + } // scan all timeouts + return ret; +} + /** Remove the timeout from the active timer queue and push it onto the stack of currently running callbacks. diff --git a/src/Fl_Timeout.h b/src/Fl_Timeout.h index f6a54a7a6..9d9cc2337 100644 --- a/src/Fl_Timeout.h +++ b/src/Fl_Timeout.h @@ -2,7 +2,7 @@ // Header for timeout support functions for the Fast Light Tool Kit (FLTK). // // Author: Albrecht Schlosser -// Copyright 2021-2022 by Bill Spitzak and others. +// Copyright 2021-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -31,6 +31,7 @@ - Fl::repeat_timeout() - Fl::has_timeout() - Fl::remove_timeout() + - Fl::remove_next_timeout() and related methods of class Fl_Timeout. */ @@ -49,6 +50,7 @@ - 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) + - Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) */ class Fl_Timeout { @@ -106,6 +108,7 @@ public: static void add_timeout(double time, Fl_Timeout_Handler cb, void *data); static void repeat_timeout(double time, Fl_Timeout_Handler cb, void *data); static void remove_timeout(Fl_Timeout_Handler cb, void *data); + static int remove_next_timeout(Fl_Timeout_Handler cb, void *data = NULL, void **data_return = NULL); // Elapse timeouts, i.e. calculate new delay time of all timers. // This does not call the timer callbacks.