diff --git a/FL/Fl.H b/FL/Fl.H index 74f1a9df577eb88d31bf0d7ad0afe7eb990f3f5f..a674d61f12cc03ccb1532a2e2b89816324021626 100644 --- a/FL/Fl.H +++ b/FL/Fl.H @@ -1,5 +1,5 @@ // -// "$Id: Fl.H,v 1.8.2.9 2000/06/21 17:36:33 bill Exp $" +// "$Id: Fl.H,v 1.8.2.10 2000/12/12 08:57:29 spitzak Exp $" // // Main header file for the Fast Light Tool Kit (FLTK). // @@ -94,6 +94,9 @@ public: static FL_EXPORT void repeat_timeout(double t, Fl_Timeout_Handler,void* = 0); static FL_EXPORT int has_timeout(Fl_Timeout_Handler, void* = 0); static FL_EXPORT void remove_timeout(Fl_Timeout_Handler, void* = 0); + static FL_EXPORT void add_check(Fl_Timeout_Handler, void* = 0); + static FL_EXPORT int has_check(Fl_Timeout_Handler, void* = 0); + static FL_EXPORT void remove_check(Fl_Timeout_Handler, void* = 0); static FL_EXPORT void add_fd(int fd, int when, void (*cb)(int,void*),void* =0); static FL_EXPORT void add_fd(int fd, void (*cb)(int, void*), void* = 0); static FL_EXPORT void remove_fd(int, int when); @@ -214,5 +217,5 @@ public: #endif // -// End of "$Id: Fl.H,v 1.8.2.9 2000/06/21 17:36:33 bill Exp $". +// End of "$Id: Fl.H,v 1.8.2.10 2000/12/12 08:57:29 spitzak Exp $". // diff --git a/FL/glut.H b/FL/glut.H index 3ab680519b9bfbf30ff9c7f134a62e6cfe3ac745..d719937dc57dd34bfb7839f606f780f31a22fad8 100644 --- a/FL/glut.H +++ b/FL/glut.H @@ -1,5 +1,5 @@ // -// "$Id: glut.H,v 1.6.2.7 2000/12/06 15:45:12 easysw Exp $" +// "$Id: glut.H,v 1.6.2.8 2000/12/12 08:57:30 spitzak Exp $" // // GLUT emulation header file for the Fast Light Tool Kit (FLTK). // @@ -430,16 +430,14 @@ extern "C" { extern int APIENTRY glutExtensionSupported(char *name); -/* Stroke font opaque addresses (use constants instead in source code). */ -extern void *glutStrokeRoman; -extern void *glutStrokeMonoRoman; - /* Stroke font constants (use these in GLUT program). */ #if defined(_WIN32) || defined(WIN32) # define GLUT_STROKE_ROMAN ((void*)0) # define GLUT_STROKE_MONO_ROMAN ((void*)1) #else +extern void *glutStrokeRoman; # define GLUT_STROKE_ROMAN (&glutStrokeRoman) +extern void *glutStrokeMonoRoman; # define GLUT_STROKE_MONO_ROMAN (&glutStrokeMonoRoman) #endif @@ -472,5 +470,5 @@ extern void APIENTRY glutSolidIcosahedron(); #endif /* __glut_h__ */ // -// End of "$Id: glut.H,v 1.6.2.7 2000/12/06 15:45:12 easysw Exp $". +// End of "$Id: glut.H,v 1.6.2.8 2000/12/12 08:57:30 spitzak Exp $". // diff --git a/documentation/functions.html b/documentation/functions.html index d2a06357acc209151f6f65d7afe4925ebf09dc72..591f4edba50b28a682e46e6688110164e799cc73 100644 --- a/documentation/functions.html +++ b/documentation/functions.html @@ -326,9 +326,39 @@ fair degree of accuracy: main() { Fl::add_timeout(1.0,callback); - for (;;) Fl::wait(); + return Fl::run(); }</PRE></UL> +<h3><A name=add_timeout>static void Fl::add_check(void (*cb)(void*),void*v=0)</A></h3> + +Fltk will call this callback just before it flushes the display and +waits for events. This is different than an idle callback because it +is only called once, then fltk calls the system and tells it not to +return until an event happens. + +<p>This can be used by code that wants to monitor the +application's state, such as to keep a display up to date. The +advantage of using a check callback is that it is called only when no +events are pending. If events are coming in quickly, whole blocks of +them will be processed before this is called once. This can save +significant time and avoid the application falling behind the events. + +<p>Sample code: + +<ul><pre>bool state_changed; // anything that changes the display turns this on + +void callback(void*) { + if (!state_changed) return; + state_changed = false; + do_expensive_calculation(); + widget->redraw(); +} + +main() { + Fl::add_check(1.0,callback); + return Fl::run(); +}</pre></ul> + <h3><A name=arg>static int Fl::arg(int argc, char **argv, int &i)</A></h3> Consume a single switch from <tt>argv</tt>, starting at word i. @@ -867,6 +897,15 @@ Returns true if the timeout exists and has not been called yet. Removes a timeout callback. It is harmless to remove a timeout callback that no longer exists. +<h3><A name=has_check>static int Fl::has_check(void (*cb)(void*), void* = 0)</A></h3> + +Returns true if the check exists and has not been called yet. + +<h3><A name=remove_check>static void Fl::remove_check(void (*cb)(void*), void* = 0)</A></h3> + +Removes a check callback. It is harmless to remove a check +callback that no longer exists. + <h3><A name=run>static Fl::run()</A></h3> As long as any windows are displayed this calls <tt>Fl::wait()</tt> diff --git a/src/Fl.cxx b/src/Fl.cxx index 7a2ad174707e3c148190637cdf4e2cf0dfa5d38e..1fc52303a1787363ee2abd4f3dff25f4b7a17f8e 100644 --- a/src/Fl.cxx +++ b/src/Fl.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl.cxx,v 1.24.2.34 2000/11/20 19:02:20 easysw Exp $" +// "$Id: Fl.cxx,v 1.24.2.35 2000/12/12 08:57:30 spitzak Exp $" // // Main event handling code for the Fast Light Tool Kit (FLTK). // @@ -67,23 +67,16 @@ int Fl::event_inside(const Fl_Widget *o) /*const*/ { } //////////////////////////////////////////////////////////////// -// Timeouts and Fl::wait() - -void (*Fl::idle)(); - -// Timeouts are insert-sorted into order. This works good if there -// are only a small number: - -static struct Timeout { +// Timeouts are stored in a sorted list, so only the first one needs +// to be checked to see if any should be called. + +struct Timeout { double time; void (*cb)(void*); void* arg; -} * timeout; -static int numtimeouts; -static int timeout_array_size; - -extern int fl_wait(double time); // warning: assummes time >= 0.0 -extern int fl_ready(); + Timeout* next; +}; +static Timeout* first_timeout, *free_timeout; #ifndef WIN32 #include <sys/time.h> @@ -96,68 +89,152 @@ extern int fl_ready(); static char reset_clock = 1; static void elapse_timeouts() { - #ifdef WIN32 - unsigned long newclock = GetTickCount(); static unsigned long prevclock; - if (reset_clock) { - prevclock = newclock; - reset_clock = 0; - return; - } - if (newclock <= prevclock) return; double elapsed = (newclock-prevclock)/1000.0; prevclock = newclock; - #else - static struct timeval prevclock; struct timeval newclock; gettimeofday(&newclock, NULL); - if (reset_clock) { - prevclock.tv_sec = newclock.tv_sec; - prevclock.tv_usec = newclock.tv_usec; - reset_clock = 0; - return; - } 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 + if (reset_clock) { + reset_clock = 0; + } else if (elapsed > 0) { + for (Timeout* t = first_timeout; t; t = t->next) t->time -= elapsed; + } +} + +void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *arg) { + elapse_timeouts(); + repeat_timeout(time, cb, arg); +} + +void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *arg) { + elapse_timeouts(); + Timeout* t = free_timeout; + if (t) free_timeout = t->next; + else t = new Timeout; + t->time = time; + t->cb = cb; + t->arg = arg; + // insert-sort the new timeout: + Timeout** p = &first_timeout; + while (*p && (*p)->time <= time) p = &((*p)->next); + t->next = *p; + *p = t; +} + +int Fl::has_timeout(Fl_Timeout_Handler cb, void *arg) { + for (Timeout* t = first_timeout; t; t = t->next) + if (t->cb == cb && t->arg == arg) return 1; + return 0; +} + +void Fl::remove_timeout(Fl_Timeout_Handler cb, void *arg) { + // This version removes all matching timeouts, not just the first one. + // This may change in the future. + for (Timeout** p = &first_timeout; *p;) { + Timeout* t = *p; + if (t->cb == cb && t->arg == arg) { + *p = t->next; + t->next = free_timeout; + free_timeout = t; + } else { + p = &(t->next); + } + } +} - for (int i=0; i<numtimeouts; i++) timeout[i].time -= elapsed; +//////////////////////////////////////////////////////////////// +// Checks are just stored in a list. They are called in the reverse +// order that they were added (this may change in the future). +// This is a bit messy because I want to allow checks to be added, +// removed, and have wait() called from inside them, to do this +// next_check points at the next unprocessed one for the outermost +// call to Fl::wait(). + +struct Check { + void (*cb)(void*); + void* arg; + Check* next; +}; +static Check* first_check, *next_check, *free_check; + +void Fl::add_check(Fl_Timeout_Handler cb, void *arg) { + Check* t = free_check; + if (t) free_check = t->next; + else t = new Check; + t->cb = cb; + t->arg = arg; + t->next = first_check; + if (next_check == first_check) next_check = t; + first_check = t; +} + +void Fl::remove_check(Fl_Timeout_Handler cb, void *arg) { + for (Check** p = &first_check; *p;) { + Check* t = *p; + if (t->cb == cb && t->arg == arg) { + if (next_check == t) next_check = t->next; + *p = t->next; + t->next = free_check; + free_check = t; + } else { + p = &(t->next); + } + } } + +//////////////////////////////////////////////////////////////// +// wait/run/check/ready: + +void (*Fl::idle)(); // see Fl_add_idle.cxx for the add/remove functions + +extern int fl_wait(double time); // in Fl_x.cxx or Fl_win32.cxx static char in_idle; double Fl::wait(double time_to_wait) { - if (numtimeouts) { + if (first_timeout) { elapse_timeouts(); - if (timeout[0].time <= time_to_wait) time_to_wait = timeout[0].time; - while (numtimeouts) { - if (timeout[0].time > 0) break; + while (Timeout* t = first_timeout) { + if (t->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)); + void (*cb)(void*) = t->cb; + void *arg = 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(arg); } } 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* check = next_check; + next_check = check->next; + (check->cb)(check->arg); + } + next_check = first_check; + } 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 (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 = fl_wait(0.0); @@ -187,58 +264,18 @@ int Fl::check() { return Fl_X::first != 0; // return true if there is a window } +extern int fl_ready(); + int Fl::ready() { - if (numtimeouts) { + if (first_timeout) { elapse_timeouts(); - if (timeout[0].time <= 0) return 1; + if (first_timeout->time <= 0) return 1; } else { reset_clock = 1; } return fl_ready(); } -void Fl::add_timeout(double t, Fl_Timeout_Handler cb, void *v) { - elapse_timeouts(); - repeat_timeout(t, cb, v); -} - -void Fl::repeat_timeout(double t, Fl_Timeout_Handler cb, void *v) { - - 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(Fl_Timeout_Handler cb, 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: @@ -734,5 +771,5 @@ void Fl_Window::flush() { } // -// End of "$Id: Fl.cxx,v 1.24.2.34 2000/11/20 19:02:20 easysw Exp $". +// End of "$Id: Fl.cxx,v 1.24.2.35 2000/12/12 08:57:30 spitzak Exp $". // diff --git a/src/Fl_Gl_Window.cxx b/src/Fl_Gl_Window.cxx index f04cb7e7c3d7788146d3ab23cc56dcf737aa9be6..d8a64fd8c08e1c4c76dfdfe341915cd718b6c680 100644 --- a/src/Fl_Gl_Window.cxx +++ b/src/Fl_Gl_Window.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_Gl_Window.cxx,v 1.12.2.18 2000/12/06 15:45:13 easysw Exp $" +// "$Id: Fl_Gl_Window.cxx,v 1.12.2.19 2000/12/12 08:57:30 spitzak Exp $" // // OpenGL window code for the Fast Light Tool Kit (FLTK). // @@ -122,7 +122,7 @@ void Fl_Gl_Window::make_current() { RealizePalette(fl_gc); } #endif // USE_COLORMAP - glDrawBuffer(GL_BACK); + if (g->d) glDrawBuffer(GL_BACK); current_ = this; } @@ -337,5 +337,5 @@ void Fl_Gl_Window::draw_overlay() {} #endif // -// End of "$Id: Fl_Gl_Window.cxx,v 1.12.2.18 2000/12/06 15:45:13 easysw Exp $". +// End of "$Id: Fl_Gl_Window.cxx,v 1.12.2.19 2000/12/12 08:57:30 spitzak Exp $". // diff --git a/src/Fl_Input_.cxx b/src/Fl_Input_.cxx index ba932cf7ecc4e70d0c3c195dd10c07a0fdd2a240..7f4d40f13188666f43a75e0067b5652221b80169 100644 --- a/src/Fl_Input_.cxx +++ b/src/Fl_Input_.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_Input_.cxx,v 1.21.2.9 2000/09/19 07:21:19 spitzak Exp $" +// "$Id: Fl_Input_.cxx,v 1.21.2.10 2000/12/12 08:57:30 spitzak Exp $" // // Common input widget routines for the Fast Light Tool Kit (FLTK). // @@ -586,7 +586,7 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) { size_ += ilen; } undowidget = this; - mark_ = position_ = undoat = b+ilen; + undoat = b+ilen; #ifdef WORDWRAP // Insertions into the word at the end of the line will cause it to @@ -597,8 +597,15 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) { if (type() == FL_MULTILINE_INPUT) while (b > 0 && !isspace(index(b))) b--; #endif - + + // make sure we redraw the old selection or cursor: + if (mark_ < b) b = mark_; + if (position_ < b) b = position_; + minimal_update(b); + + mark_ = position_ = undoat; + if (when()&FL_WHEN_CHANGED) do_callback(); else set_changed(); return 1; } @@ -810,5 +817,5 @@ Fl_Input_::~Fl_Input_() { } // -// End of "$Id: Fl_Input_.cxx,v 1.21.2.9 2000/09/19 07:21:19 spitzak Exp $". +// End of "$Id: Fl_Input_.cxx,v 1.21.2.10 2000/12/12 08:57:30 spitzak Exp $". //