diff options
| -rw-r--r-- | src/Fl.cxx | 191 | ||||
| -rw-r--r-- | src/Fl_win32.cxx | 224 | ||||
| -rw-r--r-- | src/Fl_x.cxx | 4 |
3 files changed, 352 insertions, 67 deletions
diff --git a/src/Fl.cxx b/src/Fl.cxx index d8201ba8b..b822e2d7a 100644 --- a/src/Fl.cxx +++ b/src/Fl.cxx @@ -35,6 +35,7 @@ #include <FL/x.H> #include <FL/Fl_Tooltip.H> #include <ctype.h> +#include <stdio.h> #include <stdlib.h> #include "flstring.h" @@ -104,6 +105,124 @@ int Fl::event_inside(const Fl_Widget *o) /*const*/ { return (mx >= 0 && mx < o->w() && my >= 0 && my < o->h()); } +// +// +// timer support +// + +#ifdef WIN32 + +/// implementation in Fl_win32.cxx + +#elif defined(__APPLE__) + +// +// MacOS X timers +// + +struct MacTimeout { + Fl_Timeout_Handler callback; + void* data; + EventLoopTimerRef timer; +}; +static MacTimeout* mac_timers; +static int mac_timer_alloc; +static int mac_timer_used; + + +static void realloc_timers() +{ + if (mac_timer_alloc == 0) { + mac_timer_alloc = 8; + } + MacTimeout* new_timers = new MacTimeout[mac_timer_alloc * 2]; + memmove(new_timers, mac_timers, sizeof(MacTimeout) * mac_timer_used); + MacTimeout* delete_me = mac_timers; + mac_timers = new_timers; + delete [] delete_me; + mac_timer_alloc *= 2; +} + +static void delete_timer(MacTimeout& t) +{ + RemoveEventLoopTimer(t.timer); + memset(&t, 0, sizeof(MacTimeout)); +} + + +static pascal void do_timer(EventLoopTimerRef timer, void* data) +{ + for (int i = 0; i < mac_timer_used; ++i) { + MacTimeout& t = mac_timers[i]; + if (t.timer == timer && t.data == data) { + return (*t.callback)(data); + } + } +} + + +void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data) +{ + int timer_id = -1; + for (int i = 0; i < mac_timer_used; ++i) { + if ( !mac_timers[i].timer ) { + timer_id = i; + break; + } + } + if (timer_id == -1) { + if (mac_timer_used == mac_timer_alloc) { + realloc_timers(); + } + timer_id = mac_timer_used++; + } + + EventTimerInterval fireDelay = (EventTimerInterval) time; + EventLoopTimerUPP timerUPP = NewEventLoopTimerUPP(do_timer); + EventLoopTimerRef timerRef; + OSStatus err = InstallEventLoopTimer(GetMainEventLoop(), fireDelay, 0, timerUPP, data, &timerRef); + if (err == noErr) { + mac_timers[timer_id].callback = cb; + mac_timers[timer_id].data = data; + mac_timers[timer_id].timer = timerRef; + } +} + +void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data) +{ + remove_timeout(cb, data); + add_timeout(time, cb, data); +} + +int Fl::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) { + return 1; + } + } + return 0; +} + +void Fl::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); + } + } +} + + +#else + +// +// X11 timers +// + + //////////////////////////////////////////////////////////////// // Timeouts are stored in a sorted list, so only the first one needs // to be checked to see if any should be called. @@ -115,10 +234,9 @@ struct Timeout { Timeout* next; }; static Timeout* first_timeout, *free_timeout; +static int first_timeout_count, free_timeout_count; -#ifndef WIN32 -# include <sys/time.h> -#endif +#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. @@ -127,12 +245,6 @@ static Timeout* first_timeout, *free_timeout; static char reset_clock = 1; static void elapse_timeouts() { -#ifdef WIN32 - unsigned long newclock = GetTickCount(); - static unsigned long prevclock; - double elapsed = (newclock-prevclock)/1000.0; - prevclock = newclock; -#else static struct timeval prevclock; struct timeval newclock; gettimeofday(&newclock, NULL); @@ -140,7 +252,6 @@ static void elapse_timeouts() { (newclock.tv_usec - prevclock.tv_usec)/1000000.0; prevclock.tv_sec = newclock.tv_sec; prevclock.tv_usec = newclock.tv_usec; -#endif if (reset_clock) { reset_clock = 0; } else if (elapsed > 0) { @@ -162,8 +273,12 @@ void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *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; + if (t) { + free_timeout = t->next; + --free_timeout_count; + } else { + t = new Timeout; + } t->time = time; t->cb = cb; t->arg = argp; @@ -195,6 +310,8 @@ void Fl::remove_timeout(Fl_Timeout_Handler cb, void *argp) { } } +#endif + //////////////////////////////////////////////////////////////// // Checks are just stored in a list. They are called in the reverse // order that they were added (this may change in the future). @@ -208,7 +325,7 @@ struct Check { void* arg; Check* next; }; -static Check* first_check, *next_check, *free_check; +static Check *first_check, *next_check, *free_check; void Fl::add_check(Fl_Timeout_Handler cb, void *argp) { Check* t = free_check; @@ -235,6 +352,20 @@ void Fl::remove_check(Fl_Timeout_Handler cb, void *argp) { } } +static void run_checks() +{ + // checks are a bit messy so that add/remove and wait may be called + // from inside them without causing an infinite loop: + if (next_check == first_check) { + while (next_check) { + Check* checkp = next_check; + next_check = checkp->next; + (checkp->cb)(checkp->arg); + } + next_check = first_check; + } +} + //////////////////////////////////////////////////////////////// // wait/run/check/ready: @@ -249,6 +380,17 @@ double Fl::wait(double time_to_wait) { // delete all widgets that were listed during callbacks do_widget_deletion(); +#ifdef WIN32 + + return fl_wait(time_to_wait); + +#elif defined(__APPLE__) + + flush(); + return fl_wait(time_to_wait); + +#else + if (first_timeout) { elapse_timeouts(); Timeout *t; @@ -262,22 +404,15 @@ double Fl::wait(double time_to_wait) { first_timeout = t->next; t->next = free_timeout; free_timeout = t; + ++free_timeout_count; + --first_timeout_count; // 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 } - // checks are a bit messy so that add/remove and wait may be called - // from inside them without causing an infinite loop: - if (next_check == first_check) { - while (next_check) { - Check* checkp = next_check; - next_check = checkp->next; - (checkp->cb)(checkp->arg); - } - next_check = first_check; - } + run_checks(); // if (idle && !fl_ready()) { if (idle) { if (!in_idle) { @@ -300,9 +435,10 @@ double Fl::wait(double time_to_wait) { flush(); return fl_wait(time_to_wait); } +#endif } -#define FOREVER 1e20 +#define FOREVER 0.01 //1e20 int Fl::run() { while (Fl_X::first) wait(FOREVER); @@ -327,12 +463,14 @@ int Fl::check() { } int Fl::ready() { +#if ! defined( WIN32 ) && ! defined(__APPLE__) if (first_timeout) { elapse_timeouts(); if (first_timeout->time <= 0) return 1; } else { reset_clock = 1; } +#endif return fl_ready(); } @@ -1099,6 +1237,11 @@ void Fl_Window::flush() { draw(); } +#ifdef WIN32 +# include "Fl_win32.cxx" +#elif defined(__APPLE__) +# include "Fl_mac.cxx" +#endif // // The following methods allow callbacks to schedule the deletion of diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index ebeed9d67..345d76ea9 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -222,7 +222,6 @@ MSG fl_msg; // it returns 1. int fl_wait(double time_to_wait) { int have_message = 0; - int timerid; #ifndef USE_ASYNC_SELECT if (nfds) { @@ -260,52 +259,48 @@ int fl_wait(double time_to_wait) { fl_unlock_function(); - if (time_to_wait < 2147483.648) { - // Perform the requested timeout... - have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); - if (!have_message) { - int t = (int)(time_to_wait * 1000.0 + .5); - if (t <= 0) { // too short to measure - fl_lock_function(); - return 0; - } - timerid = SetTimer(NULL, 0, t, NULL); - have_message = GetMessage(&fl_msg, NULL, 0, 0); - KillTimer(NULL, timerid); - } - } else { - // make sure that we don't lock up if there are no more windows - // that could receive messages, but still handle pending messages. - if (!Fl_X::first) - have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); - else - have_message = GetMessage(&fl_msg, NULL, 0, 0); - } + time_to_wait = (time_to_wait > 10000 ? 10000 : time_to_wait); + int t_msec = (int) (time_to_wait * 1000.0 + 0.5); + int ret_val = MsgWaitForMultipleObjects(0, NULL, FALSE, t_msec, QS_ALLINPUT); fl_lock_function(); // Execute the message we got, and all other pending messages: - while (have_message) { + have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); + if (have_message > 0) { + while (have_message != 0 && have_message != -1) { #ifdef USE_ASYNC_SELECT - if (fl_msg.message == WM_FLSELECT) { - // Got notification for socket - for (int i = 0; i < nfds; i ++) - if (fd[i].fd == (int)fl_msg.wParam) { - (fd[i].cb)(fd[i].fd, fd[i].arg); - break; - } - // looks like it is best to do the dispatch-message anyway: - } + if (fl_msg.message == WM_FLSELECT) { + // Got notification for socket + for (int i = 0; i < nfds; i ++) + if (fd[i].fd == (int)fl_msg.wParam) { + (fd[i].cb)(fd[i].fd, fd[i].arg); + break; + } + // looks like it is best to do the dispatch-message anyway: + } #endif - if (fl_msg.message == fl_wake_msg) // Used for awaking wait() from another thread - thread_message_ = (void*)fl_msg.wParam; + if (fl_msg.message == fl_wake_msg) // Used for awaking wait() from another thread + thread_message_ = (void*)fl_msg.wParam; + + TranslateMessage(&fl_msg); + DispatchMessage(&fl_msg); + have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); + } + Fl::flush(); + } - TranslateMessage(&fl_msg); - DispatchMessage(&fl_msg); - have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); + // idle processing + static char in_idle; + if (Fl::idle && !in_idle) { + in_idle = 1; + Fl::idle(); + in_idle = 0; } + run_checks(); + // This should return 0 if only timer events were handled: return 1; } @@ -619,6 +614,45 @@ static int ms2fltk(int vk, int extended) { 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; + } + size_t size = sizeof(Win32Timer); + Win32Timer* new_timers = new Win32Timer[win32_timer_alloc * 2]; + memmove(new_timers, win32_timers, sizeof(Win32Timer) * win32_timer_used); + Win32Timer* delete_me = win32_timers; + win32_timers = new_timers; + delete [] delete_me; + win32_timer_alloc *= 2; +} + +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); @@ -646,6 +680,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar case WM_CLOSE: // user clicked close box Fl::handle(FL_CLOSE, window); + PostQuitMessage(0); return 0; case WM_SYNCPAINT : @@ -1149,13 +1184,14 @@ Fl_X* Fl_X::make(Fl_Window* w) { if (!class_name_list.has_name(class_name)) { WNDCLASSEX wc; + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(WNDCLASSEX); // Documentation states a device context consumes about 800 bytes // of memory... so who cares? If 800 bytes per window is what it // takes to speed things up, I'm game. //wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; wc.lpfnWndProc = (WNDPROC)WndProc; - wc.cbClsExtra = wc.cbWndExtra = 0; wc.hInstance = fl_display; if (!w->icon()) w->icon((void *)LoadIcon(NULL, IDI_APPLICATION)); @@ -1163,10 +1199,7 @@ Fl_X* Fl_X::make(Fl_Window* w) { wc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW); //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b); //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b)); - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; wc.lpszClassName = class_name; - wc.cbSize = sizeof(WNDCLASSEX); RegisterClassEx(&wc); class_name_list.add_name(class_name); } @@ -1285,6 +1318,115 @@ Fl_X* Fl_X::make(Fl_Window* w) { return x; } + + + +///////////////////////////////////////////////////////////////////////////// +/// Win32 timers +/// + + +static LRESULT CALLBACK s_TimerProc(HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_TIMER: + { + unsigned int id = wParam - 1; + if (id < 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); + + s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW, + timer_class, "", + WS_POPUP, + CW_USEDEFAULT, CW_USEDEFAULT, 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); diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index c7444fc41..f4eb3fdc6 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -26,9 +26,9 @@ // #ifdef WIN32 -# include "Fl_win32.cxx" +//# include "Fl_win32.cxx" #elif defined(__APPLE__) -# include "Fl_mac.cxx" +//# include "Fl_mac.cxx" #else # define CONSOLIDATE_MOTION 1 |
