diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Fl.cxx | 276 | ||||
| -rw-r--r-- | src/Fl_win32.cxx | 96 | ||||
| -rw-r--r-- | src/Fl_x.cxx | 114 |
3 files changed, 242 insertions, 244 deletions
diff --git a/src/Fl.cxx b/src/Fl.cxx index 4792db339..d67235e9f 100644 --- a/src/Fl.cxx +++ b/src/Fl.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl.cxx,v 1.24.2.26 2000/06/16 07:28:02 bill Exp $" +// "$Id: Fl.cxx,v 1.24.2.27 2000/06/18 00:38:39 bill Exp $" // // Main event handling code for the Fast Light Tool Kit (FLTK). // @@ -50,8 +50,6 @@ int Fl::damage_, char *Fl::e_text = ""; int Fl::e_length; -static double fl_elapsed(); - // // 'Fl:event_inside()' - Return whether or not the mouse event is inside // the given rectangle. @@ -67,6 +65,11 @@ int Fl::event_inside(const Fl_Widget *o) /*const*/ { return event_inside(o->x(),o->y(),o->w(),o->h()); } +//////////////////////////////////////////////////////////////// +// Timeouts and Fl::wait() + +void (*Fl::idle)(); + // Timeouts are insert-sorted into order. This works good if there // are only a small number: @@ -78,104 +81,32 @@ static struct Timeout { static int numtimeouts; static int timeout_array_size; -void Fl::add_timeout(double t, Fl_Timeout_Handler cb, void *v) { - - fl_elapsed(); - - if (numtimeouts >= timeout_array_size) { - timeout_array_size = 2*timeout_array_size+1; - timeout = (Timeout*)realloc(timeout, timeout_array_size*sizeof(Timeout)); - } - - // insert-sort the new timeout: - int i; - for (i=0; i<numtimeouts; i++) { - if (timeout[i].time > t) { - for (int j=numtimeouts; j>i; j--) timeout[j] = timeout[j-1]; - break; - } - } - timeout[i].time = t; - timeout[i].cb = cb; - timeout[i].arg = v; - - numtimeouts++; -} - -int Fl::has_timeout(void (*cb)(void *), void *v) { - for (int i=0; i<numtimeouts; i++) - if (timeout[i].cb == cb && timeout[i].arg==v) return 1; - return 0; -} - -void Fl::remove_timeout(Fl_Timeout_Handler cb, void *v) { - int i,j; - for (i=j=0; i<numtimeouts; i++) { - if (timeout[i].cb == cb && timeout[i].arg==v) ; - else {if (j<i) timeout[j]=timeout[i]; j++;} - } - numtimeouts = j; -} - -static int call_timeouts() { - int expired = 0; - while (numtimeouts) { - if (timeout[0].time > 0) break; - // we must remove timeout from array before doing the callback: - void (*cb)(void*) = timeout[0].cb; - void *arg = timeout[0].arg; - numtimeouts--; expired++; - if (numtimeouts) memmove(timeout, timeout+1, numtimeouts*sizeof(Timeout)); - // now it is safe for the callback to do add_timeout: - cb(arg); - } - return expired; -} - -void Fl::flush() { - if (damage()) { - damage_ = 0; - for (Fl_X* x = Fl_X::first; x; x = x->next) { - if (x->w->damage() && x->w->visible_r()) { - if (x->wait_for_expose) { - // leave Fl::damage() set so programs can tell damage still exists - damage_ = 1; - } else { - x->flush(); - x->w->clear_damage(); - } - } - } - } -#ifndef WIN32 - if (fl_display) XFlush(fl_display); -#endif -} - -extern double fl_wait(int timeout_flag, double timeout); +extern int fl_wait(double time); // warning: assummes time >= 0.0 extern int fl_ready(); -static int initclock; // if false we didn't call fl_elapsed() last time - #ifndef WIN32 #include <sys/time.h> #endif -// fl_elapsed must return the amount of time since the last time it was -// called. To reduce the number of system calls to get the -// current time, the "initclock" symbol is turned on by an indefinite -// wait. This should then reset the measured-from time and return zero -static double fl_elapsed() { +// 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 actualy elapse time. +static char reset_clock = 1; + +static void elapse_timeouts() { #ifdef WIN32 unsigned long newclock = GetTickCount(); - const int TICKS_PER_SECOND = 1000; // divisor of the value to get seconds static unsigned long prevclock; - if (!initclock) {prevclock = newclock; initclock = 1; return 0.0;} - else if (newclock < prevclock) return 0.0; - - double t = double(newclock-prevclock)/TICKS_PER_SECOND; + if (reset_clock) { + prevclock = newclock; + reset_clock = 0; + return; + } + if (newclock <= prevclock) return; + double elapsed = (newclock-prevclock)/1000.0; prevclock = newclock; #else @@ -183,79 +114,134 @@ static double fl_elapsed() { static struct timeval prevclock; struct timeval newclock; gettimeofday(&newclock, NULL); - if (!initclock) { + if (reset_clock) { prevclock.tv_sec = newclock.tv_sec; prevclock.tv_usec = newclock.tv_usec; - initclock = 1; - return 0.0; + reset_clock = 0; + return; } - double t = newclock.tv_sec - prevclock.tv_sec + + 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 (elapsed <= 0) return; #endif - // expire any timeouts: - if (t > 0.0) for (int i=0; i<numtimeouts; i++) timeout[i].time -= t; - return t; + for (int i=0; i<numtimeouts; i++) timeout[i].time -= elapsed; } -void (*Fl::idle)(); static char in_idle; -static void callidle() { - if (!Fl::idle || in_idle) return; - in_idle = 1; - Fl::idle(); - in_idle = 0; -} - -int Fl::wait() { - callidle(); - int expired = 0; - if (numtimeouts) {fl_elapsed(); expired = call_timeouts();} - flush(); - if ((idle && !in_idle) || expired) { - fl_wait(1,0.0); - } else if (numtimeouts) { - fl_wait(1, timeout[0].time); +static char in_timeout; + +double Fl::wait(double time_to_wait) { + if (numtimeouts) { + elapse_timeouts(); + if (timeout[0].time <= time_to_wait) time_to_wait = timeout[0].time; + while (numtimeouts) { + if (timeout[0].time > 0) break; + // The first timeout in the array has expired. + // We must remove timeout from array before doing the callback: + void (*cb)(void*) = timeout[0].cb; + void *arg = timeout[0].arg; + numtimeouts--; + if (numtimeouts) + memmove(timeout, timeout+1, numtimeouts*sizeof(Timeout)); + // Now it is safe for the callback to do add_timeout: + in_timeout = 1; + cb(arg); + in_timeout = 0; + } } else { - initclock = 0; - fl_wait(0,0); + reset_clock = 1; // we are not going to check the clock + } + if (idle) { + if (!in_idle) {in_idle = 1; idle(); in_idle = 0;} + // the idle function may turn off idle, we can then wait: + if (idle) time_to_wait = 0.0; + } + if (time_to_wait <= 0.0) { + // do flush second so that the results of events are visible: + int ret = fl_wait(0.0); + flush(); + return ret; + } else { + // do flush first so that user sees the display: + flush(); + return fl_wait(time_to_wait); } - return Fl_X::first != 0; // return true if there is a window } -double Fl::wait(double time) { - callidle(); - int expired = 0; - if (numtimeouts) {time -= fl_elapsed(); expired = call_timeouts();} - flush(); - double wait_time = (idle && !in_idle) || expired ? 0.0 : time; - if (numtimeouts && timeout[0].time < wait_time) wait_time = timeout[0].time; - fl_wait(1, wait_time); - return time - fl_elapsed(); +#define FOREVER 1e20 + +int Fl::run() { + while (Fl_X::first) wait(FOREVER); + return 0; +} + +int Fl::wait() { + wait(FOREVER); + return Fl_X::first != 0; // return true if there is a window } int Fl::check() { - callidle(); - if (numtimeouts) {fl_elapsed(); call_timeouts();} - fl_wait(1, 0.0); - flush(); + wait(0.0); return Fl_X::first != 0; // return true if there is a window } int Fl::ready() { - // if (idle && !in_idle) return 1; // should it do this? - if (numtimeouts) {fl_elapsed(); if (timeout[0].time <= 0) return 1;} + if (numtimeouts) { + elapse_timeouts(); + if (timeout[0].time <= 0) return 1; + } else { + reset_clock = 1; + } return fl_ready(); } -int Fl::run() { - while (wait()); +void Fl::add_timeout(double t, Fl_Timeout_Handler cb, void *v) { + + // This little test gets rid of about half the calls to get the time + // and has the added advantage of making timeouts that think they + // are happening at regular intervals actually happen at regular + // intervals: + if (!in_timeout) elapse_timeouts(); + + if (numtimeouts >= timeout_array_size) { + timeout_array_size = 2*timeout_array_size+1; + timeout = (Timeout*)realloc(timeout, timeout_array_size*sizeof(Timeout)); + } + + // insert-sort the new timeout: + int i; + for (i=0; i<numtimeouts; i++) { + if (timeout[i].time > t) { + for (int j=numtimeouts; j>i; j--) timeout[j] = timeout[j-1]; + break; + } + } + timeout[i].time = t; + timeout[i].cb = cb; + timeout[i].arg = v; + + numtimeouts++; +} + +int Fl::has_timeout(void (*cb)(void *), void *v) { + for (int i=0; i<numtimeouts; i++) + if (timeout[i].cb == cb && timeout[i].arg==v) return 1; return 0; } +void Fl::remove_timeout(Fl_Timeout_Handler cb, void *v) { + int i,j; + for (i=j=0; i<numtimeouts; i++) { + if (timeout[i].cb == cb && timeout[i].arg==v) ; + else {if (j<i) timeout[j]=timeout[i]; j++;} + } + numtimeouts = j; +} + //////////////////////////////////////////////////////////////// // Window list management: @@ -296,6 +282,26 @@ void Fl::redraw() { for (Fl_X* x = Fl_X::first; x; x = x->next) x->w->redraw(); } +void Fl::flush() { + if (damage()) { + damage_ = 0; + for (Fl_X* x = Fl_X::first; x; x = x->next) { + if (x->w->damage() && x->w->visible_r()) { + if (x->wait_for_expose) { + // leave Fl::damage() set so programs can tell damage still exists + damage_ = 1; + } else { + x->flush(); + x->w->clear_damage(); + } + } + } + } +#ifndef WIN32 + if (fl_display) XFlush(fl_display); +#endif +} + //////////////////////////////////////////////////////////////// // Event handlers: @@ -727,5 +733,5 @@ void Fl_Window::flush() { } // -// End of "$Id: Fl.cxx,v 1.24.2.26 2000/06/16 07:28:02 bill Exp $". +// End of "$Id: Fl.cxx,v 1.24.2.27 2000/06/18 00:38:39 bill Exp $". // diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index 4e4d5afb2..982044ab3 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_win32.cxx,v 1.33.2.26 2000/06/05 21:21:02 mike Exp $" +// "$Id: Fl_win32.cxx,v 1.33.2.27 2000/06/18 00:38:40 bill Exp $" // // WIN32-specific code for the Fast Light Tool Kit (FLTK). // @@ -151,24 +151,14 @@ void Fl::remove_fd(int n) { MSG fl_msg; -int fl_ready() { - if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) return 1; - -#ifdef USE_ASYNC_SELECT - return (0); -#else - timeval t; - t.tv_sec = 0; - t.tv_usec = 0; - fd_set fdt[3]; - fdt[0] = fdsets[0]; - fdt[1] = fdsets[1]; - fdt[2] = fdsets[2]; - return ::select(0,&fdt[0],&fdt[1],&fdt[2],&t); -#endif // USE_ASYNC_SELECT -} +#define FOREVER 1e20 -double fl_wait(int timeout_flag, double time) { +// This is never called with time_to_wait < 0.0. +// It *should* return negative on error, 0 if nothing happens before +// timeout, and >0 if any callbacks were done. This version only +// returns zero if nothing happens during a 0.0 timeout, otherwise +// it returns 1. +int fl_wait(double time_to_wait) { int have_message = 0; int timerid; @@ -195,46 +185,29 @@ double fl_wait(int timeout_flag, double time) { if (FD_ISSET(f,&fdt[2])) revents |= POLLERR; if (fd[i].events & revents) fd[i].cb(f, fd[i].arg); } + time_to_wait = 0.0; // just peek for any messages + } else { + // we need to check them periodically, so set a short timeout: + if (time_to_wait > .001) time_to_wait = .001; } } #endif // USE_ASYNC_SELECT - // get the first message by waiting the correct amount of time: - if (!timeout_flag) { -#ifdef USE_ASYNC_SELECT - // Wait for a message... - have_message = GetMessage(&fl_msg, NULL, 0, 0); -#else - // If we are monitoring sockets we need to check them periodically, - // so set a timer in this case... - if (nfds) { - // First see if there is a message waiting... - have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); - if (!have_message) { - // If not then set a 1ms timer... - timerid = SetTimer(NULL, 0, 1, NULL); - GetMessage(&fl_msg, NULL, 0, 0); - KillTimer(NULL, timerid); - } - } else { - // Wait for a message... - GetMessage(&fl_msg, NULL, 0, 0); - } - have_message = 1; -#endif // USE_ASYNC_SELECT - } else { + if (time_to_wait < 2147483.648) { // Perform the requested timeout... have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); - if (!have_message && time > 0.0) { - int t = (int)(time * 1000.0); - if (t <= 0) t = 1; + if (!have_message) { + int t = (int)(time_to_wait * 1000.0 + .5); + if (t <= 0) return 0; // too short to measure timerid = SetTimer(NULL, 0, t, NULL); have_message = GetMessage(&fl_msg, NULL, 0, 0); KillTimer(NULL, timerid); } + } else { + have_message = GetMessage(&fl_msg, NULL, 0, 0); } - // execute it, them execute any other messages that become ready during it: + // Execute the message we got, and all other pending messages: while (have_message) { #ifdef USE_ASYNC_SELECT if (fl_msg.message == WM_FLSELECT) { @@ -244,20 +217,33 @@ double fl_wait(int timeout_flag, double time) { (fd[i].cb)(fd[i].fd, fd[i].arg); break; } - } else { - // Some other message... - TranslateMessage(&fl_msg); - DispatchMessage(&fl_msg); + // looks like it is best to do the dispatch-message anyway: } -#else +#endif TranslateMessage(&fl_msg); DispatchMessage(&fl_msg); -#endif // USE_ASYNC_SELECT - have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); } - return time; + // This should return 0 if only timer events were handled: + return 1; +} + +// fl_ready() is just like fl_wait(0.0) except no callbacks are done: +int fl_ready() { + if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) return 1; +#ifdef USE_ASYNC_SELECT + return (0); +#else + timeval t; + t.tv_sec = 0; + t.tv_usec = 0; + fd_set fdt[3]; + fdt[0] = fdsets[0]; + fdt[1] = fdsets[1]; + fdt[2] = fdsets[2]; + return ::select(0,&fdt[0],&fdt[1],&fdt[2],&t); +#endif // USE_ASYNC_SELECT } //////////////////////////////////////////////////////////////// @@ -967,5 +953,5 @@ void Fl_Window::make_current() { } // -// End of "$Id: Fl_win32.cxx,v 1.33.2.26 2000/06/05 21:21:02 mike Exp $". +// End of "$Id: Fl_win32.cxx,v 1.33.2.27 2000/06/18 00:38:40 bill Exp $". // diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index 1819254d0..3828cde8f 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_x.cxx,v 1.24.2.17 2000/06/05 21:21:03 mike Exp $" +// "$Id: Fl_x.cxx,v 1.24.2.18 2000/06/18 00:38:41 bill Exp $" // // X specific code for the Fast Light Tool Kit (FLTK). // @@ -45,7 +45,7 @@ //////////////////////////////////////////////////////////////// // interface to poll/select call: -#if HAVE_POLL +#if USE_POLL #include <poll.h> static pollfd *pollfds = 0; @@ -65,13 +65,15 @@ static int maxfd; #define POLLOUT 4 #define POLLERR 8 -#endif /* HAVE_POLL */ +#endif /* USE_POLL */ static int nfds = 0; static int fd_array_size = 0; static struct FD { +#if !USE_POLL int fd; short events; +#endif void (*cb)(int, void*); void* arg; } *fd = 0; @@ -82,18 +84,18 @@ void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) { if (i >= fd_array_size) { fd_array_size = 2*fd_array_size+1; fd = (FD*)realloc(fd, fd_array_size*sizeof(FD)); -#if HAVE_POLL +#if USE_POLL pollfds = (pollfd*)realloc(pollfds, fd_array_size*sizeof(pollfd)); #endif } - fd[i].fd = n; - fd[i].events = events; fd[i].cb = cb; fd[i].arg = v; -#if HAVE_POLL - fds[i].fd = n; - fds[i].events = events; +#if USE_POLL + pollfds[i].fd = n; + pollfds[i].events = events; #else + fd[i].fd = n; + fd[i].events = events; if (events & POLLIN) FD_SET(n, &fdsets[0]); if (events & POLLOUT) FD_SET(n, &fdsets[1]); if (events & POLLERR) FD_SET(n, &fdsets[2]); @@ -108,25 +110,30 @@ void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) { void Fl::remove_fd(int n, int events) { int i,j; for (i=j=0; i<nfds; i++) { +#if USE_POLL + if (pollfds[i].fd == n) { + int e = pollfds[i].events & ~events; + if (!e) continue; // if no events left, delete this fd + pollfds[j].events = e; + } +#else if (fd[i].fd == n) { int e = fd[i].events & ~events; if (!e) continue; // if no events left, delete this fd fd[i].events = e; -#if HAVE_POLL - fds[j].events = e; -#endif } +#endif // move it down in the array if necessary: if (j<i) { - fd[j]=fd[i]; -#if HAVE_POLL - fds[j]=fds[i]; + fd[j] = fd[i]; +#if USE_POLL + pollfds[j] = pollfds[i]; #endif } j++; } nfds = j; -#if !HAVE_POLL +#if !USE_POLL if (events & POLLIN) FD_CLR(n, &fdsets[0]); if (events & POLLOUT) FD_CLR(n, &fdsets[1]); if (events & POLLERR) FD_CLR(n, &fdsets[2]); @@ -138,22 +145,6 @@ void Fl::remove_fd(int n) { remove_fd(n, -1); } -int fl_ready() { - if (XQLength(fl_display)) return 1; -#if HAVE_POLL - return ::poll(fds, nfds, 0); -#else - timeval t; - t.tv_sec = 0; - t.tv_usec = 0; - fd_set fdt[3]; - fdt[0] = fdsets[0]; - fdt[1] = fdsets[1]; - fdt[2] = fdsets[2]; - return ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t); -#endif -} - #if CONSOLIDATE_MOTION static Fl_Window* send_motion; extern Fl_Window* fl_xmousewin; @@ -172,14 +163,17 @@ static void do_queued_events() { #endif } -double fl_wait(int timeout_flag, double time) { +// This is never called with time_to_wait < 0.0: +// It should return negative on error, 0 if nothing happens before +// timeout, and >0 if any callbacks were done. +int fl_wait(double time_to_wait) { // OpenGL and other broken libraries call XEventsQueued // unnecessarily and thus cause the file descriptor to not be ready, // so we must check for already-read events: - if (XQLength(fl_display)) {do_queued_events(); return time;} + if (fl_display && XQLength(fl_display)) {do_queued_events(); return 1;} -#if !HAVE_POLL +#if !USE_POLL fd_set fdt[3]; fdt[0] = fdsets[0]; fdt[1] = fdsets[1]; @@ -187,31 +181,26 @@ double fl_wait(int timeout_flag, double time) { #endif int n; - if (!timeout_flag) { -#if HAVE_POLL - n = ::poll(fds, nfds, -1); + if (time_to_wait < 2147483.648) { +#if USE_POLL + n = ::poll(pollfds, nfds, int(time_to_wait*1000 + .5)); #else - n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],0); + timeval t; + t.tv_sec = int(time_to_wait); + t.tv_usec = int(1000000 * (time_to_wait-t.tv_sec)); + n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t); #endif } else { -#if HAVE_POLL - int n = ::poll(fds, nfds, time > 0.0 ? int(time*1000) : 0); +#if USE_POLL + n = ::poll(pollfds, nfds, -1); #else - timeval t; - if (time <= 0.0) { - t.tv_sec = 0; - t.tv_usec = 0; - } else { - t.tv_sec = int(time); - t.tv_usec = int(1000000 * (time-t.tv_sec)); - } - n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t); + n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],0); #endif } if (n > 0) { for (int i=0; i<nfds; i++) { -#if HAVE_POLL - if (fds[i].revents) fd[i].cb(fd[i].fd, fd[i].arg); +#if USE_POLL + if (pollfds[i].revents) fd[i].cb(pollfds[i].fd, fd[i].arg); #else int f = fd[i].fd; short revents = 0; @@ -222,7 +211,24 @@ double fl_wait(int timeout_flag, double time) { #endif } } - return time; + return n; +} + +// fl_ready() is just like fl_wait(0.0) except no callbacks are done: +int fl_ready() { + if (XQLength(fl_display)) return 1; +#if USE_POLL + return ::poll(pollfds, nfds, 0); +#else + timeval t; + t.tv_sec = 0; + t.tv_usec = 0; + fd_set fdt[3]; + fdt[0] = fdsets[0]; + fdt[1] = fdsets[1]; + fdt[2] = fdsets[2]; + return ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t); +#endif } //////////////////////////////////////////////////////////////// @@ -890,5 +896,5 @@ void Fl_Window::make_current() { #endif // -// End of "$Id: Fl_x.cxx,v 1.24.2.17 2000/06/05 21:21:03 mike Exp $". +// End of "$Id: Fl_x.cxx,v 1.24.2.18 2000/06/18 00:38:41 bill Exp $". // |
