diff options
| author | Albrecht Schlosser <albrechts.fltk@online.de> | 2022-01-31 22:27:17 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-01-31 22:27:17 +0100 |
| commit | 29d9e31c51e6c11d6e33abf9bc4551afd9de3836 (patch) | |
| tree | 82dcb5f84dde9bb6cbfe50983094baa12215e57e /src/drivers | |
| parent | cf4a832e6a801b46c38f6236369c74056e8f89ec (diff) | |
Consolidate timeout handling across platforms (#379)
Add Fl_Timeout class
Move platform independent code of Fl::wait() to main part
- basic timeout handling
- Fl::run_checks()
- Fl::run_idle()
- Fl::idle()
- waiting time calculation (next timeout)
- remove platform dependent "screen driver" stuff
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H | 7 | ||||
| -rw-r--r-- | src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx | 142 | ||||
| -rw-r--r-- | src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H | 10 | ||||
| -rw-r--r-- | src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx | 145 | ||||
| -rw-r--r-- | src/drivers/X11/Fl_X11_Screen_Driver.H | 5 | ||||
| -rw-r--r-- | src/drivers/X11/Fl_X11_Screen_Driver.cxx | 161 |
6 files changed, 14 insertions, 456 deletions
diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H index dcd5c4f57..7dd6fc14a 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H @@ -2,7 +2,7 @@ // Definition of Apple Cocoa Screen interface // for the Fast Light Tool Kit (FLTK). // -// Copyright 2010-2018 by Bill Spitzak and others. +// Copyright 2010-2022 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 @@ -80,11 +80,6 @@ public: virtual void grab(Fl_Window* win); // --- global colors virtual void get_system_colors(); - // --- global timers - virtual void add_timeout(double time, Fl_Timeout_Handler cb, void *argp); - virtual void repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp); - virtual int has_timeout(Fl_Timeout_Handler cb, void *argp); - virtual void remove_timeout(Fl_Timeout_Handler cb, void *argp); virtual int has_marked_text() const; static void reset_marked_text(); static void insertion_point_location(int x, int y, int height); diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx index 1a36149e2..e213e5fd0 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx @@ -1,7 +1,7 @@ // // Definition of Apple Cocoa Screen interface. // -// Copyright 1998-2018 by Bill Spitzak and others. +// Copyright 1998-2022 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 @@ -401,143 +401,3 @@ Fl_RGB_Image *Fl_Cocoa_Screen_Driver::read_win_rectangle(int X, int Y, int w, in rgb->alloc_array = 1; return rgb; } - -// -// MacOS X timers -// - -struct MacTimeout { - Fl_Timeout_Handler callback; - void* data; - CFRunLoopTimerRef timer; - char pending; - CFAbsoluteTime next_timeout; // scheduled time for this timer -}; -static MacTimeout* mac_timers; -static int mac_timer_alloc; -static int mac_timer_used; -static MacTimeout* current_timer; // the timer that triggered its callback function - -static void realloc_timers() -{ - if (mac_timer_alloc == 0) { - mac_timer_alloc = 8; - fl_open_display(); // needed because the timer creates an event - } - mac_timer_alloc *= 2; - MacTimeout* new_timers = new MacTimeout[mac_timer_alloc]; - memset(new_timers, 0, sizeof(MacTimeout)*mac_timer_alloc); - memcpy(new_timers, mac_timers, sizeof(MacTimeout) * mac_timer_used); - if (current_timer) { - MacTimeout* newCurrent = new_timers + (current_timer - mac_timers); - current_timer = newCurrent; - } - MacTimeout* delete_me = mac_timers; - mac_timers = new_timers; - delete [] delete_me; -} - -static void delete_timer(MacTimeout& t) -{ - if (t.timer) { - CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), - t.timer, - kCFRunLoopDefaultMode); - CFRelease(t.timer); - memset(&t, 0, sizeof(MacTimeout)); - } -} - -static void do_timer(CFRunLoopTimerRef timer, void* data) -{ - fl_lock_function(); - fl_intptr_t timerId = (fl_intptr_t)data; - current_timer = &mac_timers[timerId]; - current_timer->pending = 0; - (current_timer->callback)(current_timer->data); - if (current_timer && current_timer->pending == 0) - delete_timer(*current_timer); - current_timer = NULL; - - Fl_Cocoa_Screen_Driver::breakMacEventLoop(); - fl_unlock_function(); -} - -void Fl_Cocoa_Screen_Driver::add_timeout(double time, Fl_Timeout_Handler cb, void* data) -{ - // always create a new timer entry - fl_intptr_t timer_id = -1; - // find an empty slot in the timer array - for (int i = 0; i < mac_timer_used; ++i) { - if ( !mac_timers[i].timer ) { - timer_id = i; - break; - } - } - // if there was no empty slot, append a new timer - if (timer_id == -1) { - // make space if needed - if (mac_timer_used == mac_timer_alloc) { - realloc_timers(); - } - timer_id = mac_timer_used++; - } - // now install a brand new timer - MacTimeout& t = mac_timers[timer_id]; - CFRunLoopTimerContext context = {0, (void*)timer_id, NULL,NULL,NULL}; - CFRunLoopTimerRef timerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, - CFAbsoluteTimeGetCurrent() + time, - 1E30, - 0, - 0, - do_timer, - &context - ); - if (timerRef) { - CFRunLoopAddTimer(CFRunLoopGetCurrent(), - timerRef, - kCFRunLoopDefaultMode); - t.callback = cb; - t.data = data; - t.timer = timerRef; - t.pending = 1; - t.next_timeout = CFRunLoopTimerGetNextFireDate(timerRef); - } -} - -void Fl_Cocoa_Screen_Driver::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data) -{ - if (!current_timer) { - add_timeout(time, cb, data); - return; - } - // k = how many times 'time' seconds after the last scheduled timeout until the future - double k = ceil( (CFAbsoluteTimeGetCurrent() - current_timer->next_timeout) / time); - if (k < 1) k = 1; - current_timer->next_timeout += k * time; - CFRunLoopTimerSetNextFireDate(current_timer->timer, current_timer->next_timeout ); - current_timer->callback = cb; - current_timer->data = data; - current_timer->pending = 1; -} - -int Fl_Cocoa_Screen_Driver::has_timeout(Fl_Timeout_Handler cb, void* data) -{ - for (int i = 0; i < mac_timer_used; ++i) { - MacTimeout& t = mac_timers[i]; - if (t.callback == cb && t.data == data && t.pending) { - return 1; - } - } - return 0; -} - -void Fl_Cocoa_Screen_Driver::remove_timeout(Fl_Timeout_Handler cb, void* data) -{ - for (int i = 0; i < mac_timer_used; ++i) { - MacTimeout& t = mac_timers[i]; - if (t.callback == cb && ( t.data == data || data == NULL)) { - delete_timer(t); - } - } -} diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H index 9bd8485a3..c621f7e5e 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H @@ -1,8 +1,7 @@ // -// Definition of Windows screen interface -// for the Fast Light Tool Kit (FLTK). +// Windows screen interface for the Fast Light Tool Kit (FLTK). // -// Copyright 2010-2018 by Bill Spitzak and others. +// Copyright 2010-2022 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 @@ -67,11 +66,6 @@ public: virtual void grab(Fl_Window* win); // --- global colors virtual void get_system_colors(); - // --- global timers - virtual void add_timeout(double time, Fl_Timeout_Handler cb, void *argp); - virtual void repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp); - virtual int has_timeout(Fl_Timeout_Handler cb, void *argp); - virtual void remove_timeout(Fl_Timeout_Handler cb, void *argp); virtual int dnd(int unused); virtual int compose(int &del); virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, bool may_capture_subwins, bool *did_capture_subwins); diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx index 5747f16a4..489e7fe8d 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx @@ -1,7 +1,7 @@ // // Windows screen interface for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2018 by Bill Spitzak and others. +// Copyright 1998-2022 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 @@ -328,149 +328,6 @@ void Fl_WinAPI_Screen_Driver::get_system_colors() } -// ---- timers - - -struct Win32Timer -{ - UINT_PTR handle; - Fl_Timeout_Handler callback; - void *data; -}; -static Win32Timer* win32_timers; -static int win32_timer_alloc; -static int win32_timer_used; -static HWND s_TimerWnd; - - -static void realloc_timers() -{ - if (win32_timer_alloc == 0) { - win32_timer_alloc = 8; - } - win32_timer_alloc *= 2; - Win32Timer* new_timers = new Win32Timer[win32_timer_alloc]; - memset(new_timers, 0, sizeof(Win32Timer) * win32_timer_used); - memcpy(new_timers, win32_timers, sizeof(Win32Timer) * win32_timer_used); - Win32Timer* delete_me = win32_timers; - win32_timers = new_timers; - delete [] delete_me; -} - - -static void delete_timer(Win32Timer& t) -{ - KillTimer(s_TimerWnd, t.handle); - memset(&t, 0, sizeof(Win32Timer)); -} - - -static LRESULT CALLBACK s_TimerProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_TIMER: - { - unsigned int id = (unsigned) (wParam - 1); - if (id < (unsigned int)win32_timer_used && win32_timers[id].handle) { - Fl_Timeout_Handler cb = win32_timers[id].callback; - void* data = win32_timers[id].data; - delete_timer(win32_timers[id]); - if (cb) { - (*cb)(data); - } - } - } - return 0; - - default: - break; - } - return DefWindowProc(hwnd, msg, wParam, lParam); -} - - -void Fl_WinAPI_Screen_Driver::add_timeout(double time, Fl_Timeout_Handler cb, void* data) -{ - repeat_timeout(time, cb, data); -} - - -void Fl_WinAPI_Screen_Driver::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data) -{ - int timer_id = -1; - for (int i = 0; i < win32_timer_used; ++i) { - if ( !win32_timers[i].handle ) { - timer_id = i; - break; - } - } - if (timer_id == -1) { - if (win32_timer_used == win32_timer_alloc) { - realloc_timers(); - } - timer_id = win32_timer_used++; - } - unsigned int elapsed = (unsigned int)(time * 1000); - - if ( !s_TimerWnd ) { - const char* timer_class = "FLTimer"; - WNDCLASSEX wc; - memset(&wc, 0, sizeof(wc)); - wc.cbSize = sizeof (wc); - wc.style = CS_CLASSDC; - wc.lpfnWndProc = (WNDPROC)s_TimerProc; - wc.hInstance = fl_display; - wc.lpszClassName = timer_class; - /*ATOM atom =*/ RegisterClassEx(&wc); - // create a zero size window to handle timer events - s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW, - timer_class, "", - WS_POPUP, - 0, 0, 0, 0, - NULL, NULL, fl_display, NULL); - // just in case this OS won't let us create a 0x0 size window: - if (!s_TimerWnd) - s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW, - timer_class, "", - WS_POPUP, - 0, 0, 1, 1, - NULL, NULL, fl_display, NULL); - ShowWindow(s_TimerWnd, SW_SHOWNOACTIVATE); - } - - win32_timers[timer_id].callback = cb; - win32_timers[timer_id].data = data; - - win32_timers[timer_id].handle = - SetTimer(s_TimerWnd, timer_id + 1, elapsed, NULL); -} - - -int Fl_WinAPI_Screen_Driver::has_timeout(Fl_Timeout_Handler cb, void* data) -{ - for (int i = 0; i < win32_timer_used; ++i) { - Win32Timer& t = win32_timers[i]; - if (t.handle && t.callback == cb && t.data == data) { - return 1; - } - } - return 0; -} - - -void Fl_WinAPI_Screen_Driver::remove_timeout(Fl_Timeout_Handler cb, void* data) -{ - int i; - for (i = 0; i < win32_timer_used; ++i) { - Win32Timer& t = win32_timers[i]; - if (t.handle && t.callback == cb && - (t.data == data || data == NULL)) { - delete_timer(t); - } - } -} - int Fl_WinAPI_Screen_Driver::compose(int &del) { unsigned char ascii = (unsigned char)Fl::e_text[0]; int condition = (Fl::e_state & (FL_ALT | FL_META)) && !(ascii & 128) ; diff --git a/src/drivers/X11/Fl_X11_Screen_Driver.H b/src/drivers/X11/Fl_X11_Screen_Driver.H index 7d665dbb4..c8676f347 100644 --- a/src/drivers/X11/Fl_X11_Screen_Driver.H +++ b/src/drivers/X11/Fl_X11_Screen_Driver.H @@ -85,11 +85,6 @@ public: virtual int parse_color(const char* p, uchar& r, uchar& g, uchar& b); virtual void get_system_colors(); virtual const char *get_system_scheme(); - // --- global timers - virtual void add_timeout(double time, Fl_Timeout_Handler cb, void *argp); - virtual void repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp); - virtual int has_timeout(Fl_Timeout_Handler cb, void *argp); - virtual void remove_timeout(Fl_Timeout_Handler cb, void *argp); virtual int dnd(int unused); virtual int compose(int &del); virtual void compose_reset(); diff --git a/src/drivers/X11/Fl_X11_Screen_Driver.cxx b/src/drivers/X11/Fl_X11_Screen_Driver.cxx index beb30df83..3e7edf872 100644 --- a/src/drivers/X11/Fl_X11_Screen_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Screen_Driver.cxx @@ -31,6 +31,8 @@ #include <FL/filename.H> #include <sys/time.h> +#include "../../Fl_Timeout.h" + #if HAVE_XINERAMA # include <X11/extensions/Xinerama.h> #endif @@ -55,52 +57,6 @@ extern const char *fl_bg; extern const char *fl_bg2; // end of extern additions workaround -// -// X11 timers -// - - -//////////////////////////////////////////////////////////////////////// -// Timeouts are stored in a sorted list (*first_timeout), so only the -// first one needs to be checked to see if any should be called. -// Allocated, but unused (free) Timeout structs are stored in another -// linked list (*free_timeout). - -struct Timeout { - double time; - void (*cb)(void*); - void* arg; - Timeout* next; -}; -static Timeout* first_timeout, *free_timeout; - -// I avoid the overhead of getting the current time when we have no -// timeouts by setting this flag instead of getting the time. -// In this case calling elapse_timeouts() does nothing, but records -// the current time, and the next call will actually elapse time. -static char reset_clock = 1; - -static void elapse_timeouts() { - static struct timeval prevclock; - struct timeval newclock; - gettimeofday(&newclock, NULL); - double elapsed = newclock.tv_sec - prevclock.tv_sec + - (newclock.tv_usec - prevclock.tv_usec)/1000000.0; - prevclock.tv_sec = newclock.tv_sec; - prevclock.tv_usec = newclock.tv_usec; - if (reset_clock) { - reset_clock = 0; - } else if (elapsed > 0) { - for (Timeout* t = first_timeout; t; t = t->next) t->time -= elapsed; - } -} - - -// Continuously-adjusted error value, this is a number <= 0 for how late -// we were at calling the last timeout. This appears to make repeat_timeout -// very accurate even when processing takes a significant portion of the -// time interval: -static double missed_timeout_by; /** Creates a driver that manages all screen and display related calls. @@ -411,39 +367,6 @@ void Fl_X11_Screen_Driver::flush() double Fl_X11_Screen_Driver::wait(double time_to_wait) { - static char in_idle; - - if (first_timeout) { - elapse_timeouts(); - Timeout *t; - while ((t = first_timeout)) { - if (t->time > 0) break; - // The first timeout in the array has expired. - missed_timeout_by = t->time; - // We must remove timeout from array before doing the callback: - void (*cb)(void*) = t->cb; - void *argp = t->arg; - first_timeout = t->next; - t->next = free_timeout; - free_timeout = t; - // Now it is safe for the callback to do add_timeout: - cb(argp); - } - } else { - reset_clock = 1; // we are not going to check the clock - } - Fl::run_checks(); - if (Fl::idle) { - if (!in_idle) { - in_idle = 1; - Fl::idle(); - in_idle = 0; - } - // the idle function may turn off idle, we can then wait: - if (Fl::idle) time_to_wait = 0.0; - } - if (first_timeout && first_timeout->time < time_to_wait) - time_to_wait = first_timeout->time; if (time_to_wait <= 0.0) { // do flush second so that the results of events are visible: int ret = this->poll_or_select_with_delay(0.0); @@ -452,25 +375,20 @@ double Fl_X11_Screen_Driver::wait(double time_to_wait) } else { // do flush first so that user sees the display: Fl::flush(); - if (Fl::idle && !in_idle) // 'idle' may have been set within flush() + if (Fl::idle) // 'idle' may have been set within flush() time_to_wait = 0.0; - else if (first_timeout && first_timeout->time < time_to_wait) { - // another timeout may have been queued within flush(), see STR #3188 - time_to_wait = first_timeout->time >= 0.0 ? first_timeout->time : 0.0; + else { + Fl_Timeout::elapse_timeouts(); + time_to_wait = Fl_Timeout::time_to_wait(time_to_wait); } return this->poll_or_select_with_delay(time_to_wait); } } -int Fl_X11_Screen_Driver::ready() -{ - if (first_timeout) { - elapse_timeouts(); - if (first_timeout->time <= 0) return 1; - } else { - reset_clock = 1; - } +int Fl_X11_Screen_Driver::ready() { + Fl_Timeout::elapse_timeouts(); + if (Fl_Timeout::time_to_wait(1.0) <= 0.0) return 1; return this->poll_or_select(); } @@ -598,67 +516,6 @@ const char *Fl_X11_Screen_Driver::get_system_scheme() return s; } -// ###################### *FIXME* ######################## -// ###################### *FIXME* ######################## -// ###################### *FIXME* ######################## - - -// -// X11 timers -// - -void Fl_X11_Screen_Driver::add_timeout(double time, Fl_Timeout_Handler cb, void *argp) { - elapse_timeouts(); - missed_timeout_by = 0; - repeat_timeout(time, cb, argp); -} - -void Fl_X11_Screen_Driver::repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp) { - time += missed_timeout_by; if (time < -.05) time = 0; - Timeout* t = free_timeout; - if (t) { - free_timeout = t->next; - } else { - t = new Timeout; - } - t->time = time; - t->cb = cb; - t->arg = argp; - // insert-sort the new timeout: - Timeout** p = &first_timeout; - while (*p && (*p)->time <= time) p = &((*p)->next); - t->next = *p; - *p = t; -} - -/** - Returns true if the timeout exists and has not been called yet. -*/ -int Fl_X11_Screen_Driver::has_timeout(Fl_Timeout_Handler cb, void *argp) { - for (Timeout* t = first_timeout; t; t = t->next) - if (t->cb == cb && t->arg == argp) return 1; - return 0; -} - -/** - Removes a timeout callback. It is harmless to remove a timeout - callback that no longer exists. - - \note This version removes all matching timeouts, not just the first one. - This may change in the future. -*/ -void Fl_X11_Screen_Driver::remove_timeout(Fl_Timeout_Handler cb, void *argp) { - for (Timeout** p = &first_timeout; *p;) { - Timeout* t = *p; - if (t->cb == cb && (t->arg == argp || !argp)) { - *p = t->next; - t->next = free_timeout; - free_timeout = t; - } else { - p = &(t->next); - } - } -} int Fl_X11_Screen_Driver::compose(int& del) { int condition; |
