Moved timer code to screen drivers. Not sure if this should be in System Drivers instead.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11253 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Matthias Melcher 2016-03-01 00:54:21 +00:00
parent 6521bb2562
commit 95824506fe
8 changed files with 178 additions and 262 deletions

View File

@ -21,6 +21,7 @@
#include <FL/Fl_Device.H>
#include <FL/x.H>
#include <FL/Fl.H>
// TODO: add text composition?
// TODO: add Fl::display
@ -84,6 +85,11 @@ public:
virtual int parse_color(const char* p, uchar& r, uchar& g, uchar& b) = 0;
virtual void get_system_colors() = 0;
virtual const char *get_system_scheme();
// --- global timers
virtual void add_timeout(double time, Fl_Timeout_Handler cb, void *argp) = 0;
virtual void repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp) = 0;
virtual int has_timeout(Fl_Timeout_Handler cb, void *argp) = 0;
virtual void remove_timeout(Fl_Timeout_Handler cb, void *argp) = 0;
};

View File

@ -334,125 +334,35 @@ int Fl::event_inside(const Fl_Widget *o) /*const*/ {
//
// timer support
//
#ifdef WIN32
// implementation in Fl_win32.cxx
#elif defined(__APPLE__) // PORTME: Fl_Screen_Driver - core stuff from screen, platform, and window driver
// implementation in Fl_cocoa.mm (was Fl_mac.cxx)
#elif defined(FL_PORTING)
# pragma message "FL_PORTING: implement timers in your platform specific core file"
#else
//
// X11 timers
//
#if (0) // *FIXME* moved to src/drivers/X11/Fl_X11_Screen_Driver.cxx
////////////////////////////////////////////////////////////////////////
// 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;
#include <sys/time.h>
// 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;
void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *argp) {
elapse_timeouts();
repeat_timeout(time, cb, argp);
Fl::screen_driver()->add_timeout(time, cb, argp);
}
void Fl::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;
Fl::screen_driver()->repeat_timeout(time, cb, argp);
}
/**
Returns true if the timeout exists and has not been called yet.
*/
Returns true if the timeout exists and has not been called yet.
*/
int Fl::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;
return Fl::screen_driver()->has_timeout(cb, argp);
}
/**
Removes a timeout callback. It is harmless to remove a timeout
callback that no longer exists.
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.
\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) {
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);
}
}
Fl::screen_driver()->remove_timeout(cb, argp);
}
#endif // *FIXME* moved to src/drivers/X11/Fl_X11_Screen_Driver.cxx
#endif
////////////////////////////////////////////////////////////////
// Checks are just stored in a list. They are called in the reverse

View File

@ -554,7 +554,7 @@ static void do_timer(CFRunLoopTimerRef timer, void* data)
fl_unlock_function();
}
void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
void Fl_Cocoa_Screen_Driver::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
{
// check, if this timer slot exists already
for (int i = 0; i < mac_timer_used; ++i) {
@ -607,7 +607,7 @@ void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
}
}
void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data)
void Fl_Cocoa_Screen_Driver::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data)
{
if (current_timer) {
// k = how many times 'time' seconds after the last scheduled timeout until the future
@ -623,7 +623,7 @@ void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data)
add_timeout(time, cb, data);
}
int Fl::has_timeout(Fl_Timeout_Handler cb, void* data)
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];
@ -634,7 +634,7 @@ int Fl::has_timeout(Fl_Timeout_Handler cb, void* data)
return 0;
}
void Fl::remove_timeout(Fl_Timeout_Handler cb, void* data)
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];

View File

@ -1037,44 +1037,6 @@ extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx
#endif
/////////////////////////////////////////////////////////////////////////////
/// Win32 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));
}
/// END TIMERS
/////////////////////////////////////////////////////////////////////////////
static Fl_Window* resize_bug_fix;
extern void fl_save_pen(void);
@ -1984,121 +1946,6 @@ Fl_X* Fl_X::make(Fl_Window* w) {
}
/////////////////////////////////////////////////////////////////////////////
/// Win32 timers
///
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::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
{
repeat_timeout(time, cb, data);
}
void Fl::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::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::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);
}
}
}
/// END TIMERS
/////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
HINSTANCE fl_display = GetModuleHandle(NULL);

View File

@ -26,7 +26,7 @@
#define FL_COCOA_SCREEN_DRIVER_H
#include <FL/Fl_Screen_Driver.H>
#include <FL/x.H>
/*
Move everything here that manages the native screen interface.
@ -71,6 +71,11 @@ 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);
};

View File

@ -367,6 +367,149 @@ const char *Fl_WinAPI_Screen_Driver::get_system_scheme()
}
// ---- 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);
}
}
}
//

View File

@ -68,6 +68,11 @@ 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);
};

View File

@ -554,12 +554,12 @@ const char *Fl_X11_Screen_Driver::get_system_scheme()
// X11 timers
//
void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *argp) {
void Fl_X11_Screen_Driver::add_timeout(double time, Fl_Timeout_Handler cb, void *argp) {
elapse_timeouts();
repeat_timeout(time, cb, argp);
}
void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *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) {
@ -580,7 +580,7 @@ void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp) {
/**
Returns true if the timeout exists and has not been called yet.
*/
int Fl::has_timeout(Fl_Timeout_Handler cb, void *argp) {
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;
@ -593,7 +593,7 @@ int Fl::has_timeout(Fl_Timeout_Handler cb, void *argp) {
\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) {
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)) {