diff --git a/CHANGES b/CHANGES index d35f35104..8aa2aad8a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,9 +1,21 @@ CHANGES IN FLTK 1.1.0b7 - - Some Win32 drivers would draw into wrong buffers - after OpenGL mode change - - Mac OS X support works 95% - More documentation updates... + - Added Fl::lock() and friends from FLTK 2.0 to + support multi-threaded applications. + - Fl_Check_Button and Fl_Round_Button now use the + FL_NO_BOX box type to show the background of the + parent widget. + - Tweeked the plastic boxtype code to draw with the + right shading for narrow, but horizontal buttons. + - Fl_Progress now shades the bounding box instead of + drawing a polygon inside it. + - Fl::warning() under WIN32 defaults to no action. This + avoids warning dialogs when an image file cannot be + loaded. + - Some Win32 drivers would draw into wrong buffers + after OpenGL mode change + - Mac OS X support works 95% - The file chooser would cause a segfault if you clicked in an empty area of the file list. - Fl_File_Icon::labeltype() would cause a segfault @@ -58,16 +70,6 @@ CHANGES IN FLTK 1.1.0b7 selection and text as Fl_Input_ and friends. - Changed the default line scrolling in Fl_Text_Display to 3 lines for the mouse wheel and scrollbar arrows. - - Fl_Check_Button and Fl_Round_Button now use the - FL_NO_BOX box type to show the background of the - parent widget. - - Tweeked the plastic boxtype code to draw with the - right shading for narrow, but horizontal buttons. - - Fl_Progress now shades the bounding box instead of - drawing a polygon inside it. - - Fl::warning() under WIN32 defaults to no action. This - avoids warning dialogs when an image file cannot be - loaded. CHANGES IN FLTK 1.1.0b6 diff --git a/FL/Fl.H b/FL/Fl.H index 2a9e606d9..0b0c99be4 100644 --- a/FL/Fl.H +++ b/FL/Fl.H @@ -1,5 +1,5 @@ // -// "$Id: Fl.H,v 1.8.2.11.2.6 2001/11/28 20:43:44 easysw Exp $" +// "$Id: Fl.H,v 1.8.2.11.2.7 2001/12/06 22:16:49 easysw Exp $" // // Main header file for the Fast Light Tool Kit (FLTK). // @@ -220,10 +220,16 @@ public: // Visible focus methods... static void visible_focus(int v) { visible_focus_ = v; } static int visible_focus() { return visible_focus_; } + + // Multithreading support: + static void lock(); + static void unlock(); + static void awake(void* message = 0); + static void* thread_message(); }; #endif // !Fl_H // -// End of "$Id: Fl.H,v 1.8.2.11.2.6 2001/11/28 20:43:44 easysw Exp $". +// End of "$Id: Fl.H,v 1.8.2.11.2.7 2001/12/06 22:16:49 easysw Exp $". // diff --git a/configure.in b/configure.in index 8008e45ed..4b8499920 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ dnl -*- sh -*- dnl the "configure" script is made from this by running GNU "autoconf" dnl -dnl "$Id: configure.in,v 1.33.2.31.2.36 2001/12/06 02:20:36 matthiaswm Exp $" +dnl "$Id: configure.in,v 1.33.2.31.2.37 2001/12/06 22:16:48 easysw Exp $" dnl dnl Configuration script for the Fast Light Tool Kit (FLTK). dnl @@ -159,6 +159,7 @@ AC_ARG_ENABLE(shared, [ --enable-shared turn on shared libraries [defau ;; esac fi]) +AC_ARG_ENABLE(threads, [ --disable-threads disable multi-threading support],,enable_threads=yes) AC_PROG_CC AC_PROG_CXX @@ -299,12 +300,23 @@ case $uname in GLDSONAME="" GLDEMOS="" fi + # Don't make symlinks because HFS+ is not case sensitive... HLINKS="#" + # Add a postbuild step after linking applications POSTBUILD="/Developer/Tools/Rez -t APPL ../FL/mac.r -o \$@" ;; *) + dnl Check for pthreads for multi-threaded apps... + if test "$enable_threads" = yes; then + AC_SEARCH_LIBS(pthread_create, pthread) + fi + + if test "x$ac_cv_search_pthread" != x; then + AC_DEFINE(HAVE_PTHREAD) + fi + dnl Check for X11... AC_PATH_XTRA @@ -592,5 +604,5 @@ AC_OUTPUT(makeinclude fltk.list fltk-config FL/Makefile) chmod +x fltk-config dnl -dnl End of "$Id: configure.in,v 1.33.2.31.2.36 2001/12/06 02:20:36 matthiaswm Exp $". +dnl End of "$Id: configure.in,v 1.33.2.31.2.37 2001/12/06 22:16:48 easysw Exp $". dnl diff --git a/src/Fl_lock.cxx b/src/Fl_lock.cxx index ebd8b420f..8f9d16378 100644 --- a/src/Fl_lock.cxx +++ b/src/Fl_lock.cxx @@ -1,80 +1,132 @@ -/* Fl_Lock.cxx +// +// "$Id: Fl_lock.cxx,v 1.13.2.1 2001/12/06 22:16:49 easysw Exp $" +// +// Multi-threading support code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2001 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to "fltk-bugs@fltk.org". +// + + +#include +#include - I would prefer that fltk contain the minimal amount of extra stuff - for doing threads. There are other portable thread wrapper libraries - out there and fltk should not be providing another. This file - is an attempt to make minimal additions and make them self-contained - in this source file. +/* + From Bill: - Fl::lock() - recursive lock. Plus you must call this before the - first call to Fl::wait()/run() to initialize the thread system. - The lock is locked all the time except when Fl::wait() is waiting - for events. + I would prefer that FLTK contain the minimal amount of extra + stuff for doing threads. There are other portable thread + wrapper libraries out there and FLTK should not be providing + another. This file is an attempt to make minimal additions + and make them self-contained in this source file. - Fl::unlock() - release the recursive lock. + Fl::lock() - recursive lock. You must call this before the + first call to Fl::wait()/run() to initialize the thread + system. The lock is locked all the time except when + Fl::wait() is waiting for events. - Fl::awake(void*) - Causes Fl::wait() to return (with the lock locked) - even if there are no events ready. + Fl::unlock() - release the recursive lock. - Fl::thread_message() - returns an argument sent to an Fl::awake call, - or returns null if none. Warning: the current implementation only - has a one-entry queue and only returns the most recent value! + Fl::awake(void*) - Causes Fl::wait() to return (with the lock + locked) even if there are no events ready. - See also the Fl_Threads.h header file, which provides convienence - functions so you can create your own threads and mutexes. + Fl::thread_message() - returns an argument sent to an + Fl::awake() call, or returns NULL if none. WARNING: the + current implementation only has a one-entry queue and only + returns the most recent value! */ -#include -#include //////////////////////////////////////////////////////////////// -#if defined(_WIN32) +// Windows threading... +#ifdef WIN32 +# include +# include -#include -#include - -// these pointers are in Fl_win32.cxx: +// These pointers are in Fl_win32.cxx: extern void (*fl_lock_function)(); extern void (*fl_unlock_function)(); +// The main thread's ID static DWORD main_thread; +// Microsoft's version of a MUTEX... CRITICAL_SECTION cs; +// +// 'unlock_function()' - Release the lock. +// + static void unlock_function() { LeaveCriticalSection(&cs); } +// +// 'lock_function()' - Get the lock. +// + static void lock_function() { EnterCriticalSection(&cs); } +// +// 'Fl::lock()' - Lock access to FLTK data structures... +// + void Fl::lock() { - if (!main_thread) - InitializeCriticalSection(&cs); + if (!main_thread) InitializeCriticalSection(&cs); + lock_function(); + if (!main_thread) { - fl_lock_function = lock_function; + fl_lock_function = lock_function; fl_unlock_function = unlock_function; - main_thread = GetCurrentThreadId(); + main_thread = GetCurrentThreadId(); } } +// +// 'Fl::unlock()' - Unlock access to FLTK data structures... +// + void Fl::unlock() { unlock_function(); } -// when called from a thread, it causes FLTK to awake from Fl::wait() + +// +// 'Fl::awake()' - Let the main thread know an update is pending. +// +// When called from a thread, it causes FLTK to awake from Fl::wait()... +// + void Fl::awake(void* msg) { PostThreadMessage( main_thread, WM_USER, (WPARAM)msg, 0); } //////////////////////////////////////////////////////////////// +// POSIX threading... #elif HAVE_PTHREAD -#include -#include +# include +# include -#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP +# ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP // Linux supports recursive locks, use them directly: static pthread_mutex_t fltk_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; @@ -90,7 +142,7 @@ void Fl::unlock() { // this is needed for the Fl_Mutex constructor: pthread_mutexattr_t Fl_Mutex_attrib = {PTHREAD_MUTEX_RECURSIVE_NP}; -#else +# else // Make a recursive lock out of the pthread mutex: static pthread_mutex_t fltk_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -99,7 +151,8 @@ static int counter; static void lock_function() { if (!counter || owner != pthread_self()) { - pthread_mutex_lock(&fltk_mutex); owner = pthread_self(); + pthread_mutex_lock(&fltk_mutex); + owner = pthread_self(); } counter++; } @@ -108,11 +161,12 @@ void Fl::unlock() { if (!--counter) pthread_mutex_unlock(&fltk_mutex); } -#endif +# endif +// Pipe for thread messaging... static int thread_filedes[2]; -// these pointers are in Fl_x.cxx: +// These pointers are in Fl_x.cxx: extern void (*fl_lock_function)(); extern void (*fl_unlock_function)(); @@ -133,7 +187,7 @@ void Fl::lock() { // Init threads communication pipe to let threads awake FLTK from wait pipe(thread_filedes); Fl::add_fd(thread_filedes[0], FL_READ, thread_awake_cb); - fl_lock_function = lock_function; + fl_lock_function = lock_function; fl_unlock_function = Fl::unlock; } } @@ -143,3 +197,7 @@ void Fl::awake(void* msg) { } #endif + +// +// End of "$Id: Fl_lock.cxx,v 1.13.2.1 2001/12/06 22:16:49 easysw Exp $". +// diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index de80c9d0a..c54687a60 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_win32.cxx,v 1.33.2.37.2.9 2001/11/30 16:10:08 easysw Exp $" +// "$Id: Fl_win32.cxx,v 1.33.2.37.2.10 2001/12/06 22:16:49 easysw Exp $" // // WIN32-specific code for the Fast Light Tool Kit (FLTK). // @@ -164,6 +164,18 @@ void Fl::remove_fd(int n) { remove_fd(n, -1); } +// these pointers are set by the Fl::lock() function: +static void nothing() {} +void (*fl_lock_function)() = nothing; +void (*fl_unlock_function)() = nothing; + +static void* thread_message_; +void* Fl::thread_message() { + void* r = thread_message_; + thread_message_ = 0; + return r; +} + MSG fl_msg; // This is never called with time_to_wait < 0.0. @@ -206,12 +218,17 @@ int fl_wait(double time_to_wait) { } #endif // USE_ASYNC_SELECT + 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) return 0; // too short to measure + 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); @@ -220,6 +237,8 @@ int fl_wait(double time_to_wait) { have_message = GetMessage(&fl_msg, NULL, 0, 0); } + fl_lock_function(); + // Execute the message we got, and all other pending messages: while (have_message) { #ifdef USE_ASYNC_SELECT @@ -233,6 +252,10 @@ int fl_wait(double time_to_wait) { // looks like it is best to do the dispatch-message anyway: } #endif + + if (fl_msg.message == WM_USER) // 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); @@ -997,5 +1020,5 @@ void Fl_Window::make_current() { } // -// End of "$Id: Fl_win32.cxx,v 1.33.2.37.2.9 2001/11/30 16:10:08 easysw Exp $". +// End of "$Id: Fl_win32.cxx,v 1.33.2.37.2.10 2001/12/06 22:16:49 easysw Exp $". // diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index 5788181d6..7572d7d02 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_x.cxx,v 1.24.2.24.2.7 2001/11/27 17:44:06 easysw Exp $" +// "$Id: Fl_x.cxx,v 1.24.2.24.2.8 2001/12/06 22:16:49 easysw Exp $" // // X specific code for the Fast Light Tool Kit (FLTK). // @@ -179,6 +179,11 @@ static void do_queued_events() { # endif } +// these pointers are set by the Fl::lock() function: +static void nothing() {} +void (*fl_lock_function)() = nothing; +void (*fl_unlock_function)() = nothing; + // 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. @@ -197,6 +202,8 @@ int fl_wait(double time_to_wait) { # endif int n; + fl_unlock_function(); + if (time_to_wait < 2147483.648) { # if USE_POLL n = ::poll(pollfds, nfds, int(time_to_wait*1000 + .5)); @@ -213,6 +220,9 @@ int fl_wait(double time_to_wait) { n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],0); # endif } + + fl_lock_function(); + if (n > 0) { for (int i=0; i