diff --git a/FL/Fl.H b/FL/Fl.H index 8c07365e6..547a8f35a 100644 --- a/FL/Fl.H +++ b/FL/Fl.H @@ -46,6 +46,7 @@ typedef void (Fl_Label_Measure_F)(const Fl_Label*, int&, int&); typedef void (Fl_Box_Draw_F)(int,int,int,int, Fl_Color); typedef void (*Fl_Timeout_Handler)(void*); +typedef void (*Fl_Awake_Handler)(void*); class FL_EXPORT Fl { Fl() {}; // no constructor! @@ -79,6 +80,14 @@ public: // should be private! static void (*idle)(); static void (*awake_cb)(void *); + static Fl_Awake_Handler *awake_ring_; + static void **awake_data_; + static int awake_ring_size_; + static int awake_ring_head_; + static int awake_ring_tail_; + + static int add_awake_handler_(Fl_Awake_Handler, void*); + static int get_awake_handler_(Fl_Awake_Handler&, void*&); static const char* scheme_; static Fl_Image* scheme_bg_; @@ -267,6 +276,7 @@ public: static void lock(); static void unlock(); static void awake(void* message = 0); + static int awake(Fl_Awake_Handler cb, void* message = 0); static void set_awake_cb(void (*cb)(void *)) { awake_cb = cb; } static void* thread_message(); diff --git a/src/Fl_lock.cxx b/src/Fl_lock.cxx index 31206c8e7..7541a0cae 100644 --- a/src/Fl_lock.cxx +++ b/src/Fl_lock.cxx @@ -29,6 +29,8 @@ #include #include +#include + /* From Bill: @@ -68,6 +70,62 @@ void (*Fl::awake_cb)(void *); +Fl_Awake_Handler *Fl::awake_ring_; +void **Fl::awake_data_; +int Fl::awake_ring_size_; +int Fl::awake_ring_head_; +int Fl::awake_ring_tail_; +const int AWAKE_RING_SIZE = 1024; + +int Fl::add_awake_handler_(Fl_Awake_Handler func, void *data) +{ + int ret = 0; + Fl::lock(); + if (!awake_ring_) { + awake_ring_size_ = AWAKE_RING_SIZE; + awake_ring_ = (Fl_Awake_Handler*)malloc(awake_ring_size_*sizeof(Fl_Awake_Handler)); + awake_data_ = (void**)malloc(awake_ring_size_*sizeof(void*)); + } + if (awake_ring_head_==awake_ring_tail_-1 || awake_ring_head_+1==awake_ring_tail_) { + // ring is full. Return -1 as ann error indicator. + ret = -1; + } else { + awake_ring_[awake_ring_head_] = func; + awake_data_[awake_ring_head_] = data; + ++awake_ring_head_; + if (awake_ring_head_ == awake_ring_size_) + awake_ring_head_ = 0; + } + Fl::unlock(); + return ret; +} + +int Fl::get_awake_handler_(Fl_Awake_Handler &func, void *&data) +{ + // this function must only be called from within the event + // loop which is locked, so don't bother creating any locks + if (!awake_ring_) + return -1; + if (awake_ring_head_ == awake_ring_tail_) + return -1; + func = awake_ring_[awake_ring_tail_]; + data = awake_data_[awake_ring_tail_]; + ++awake_ring_tail_; + if (awake_ring_tail_ == awake_ring_size_) + awake_ring_tail_ = 0; + return 0; +} + +// +// 'Fl::awake()' - Let the main thread know an update is pending +// and have it cal a specific function +// +int Fl::awake(Fl_Awake_Handler func, void *data) { + int ret = add_awake_handler_(func, data); + Fl::awake(); + return ret; +} + //////////////////////////////////////////////////////////////// // Windows threading... #ifdef WIN32 @@ -203,6 +261,11 @@ void* Fl::thread_message() { static void thread_awake_cb(int fd, void*) { read(fd, &thread_message_, sizeof(void*)); if (Fl::awake_cb) (*Fl::awake_cb)(thread_message_); + Fl_Awake_Handler *func; + void *data; + while (Fl::get_awake_handler_(func, data)==0) { + (*func)(data); + } } // These pointers are in Fl_x.cxx: diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index 6fc64c778..4df22baae 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -300,6 +300,11 @@ int fl_wait(double time_to_wait) { // Used for awaking wait() from another thread thread_message_ = (void*)fl_msg.wParam; if (Fl::awake_cb) (*Fl::awake_cb)(thread_message_); + Fl_Awake_Handler func; + void *data; + while (Fl::get_awake_handler_(func, data)==0) { + func(data); + } } TranslateMessage(&fl_msg); diff --git a/test/threads.cxx b/test/threads.cxx index fdd2f553c..c7107c235 100644 --- a/test/threads.cxx +++ b/test/threads.cxx @@ -32,6 +32,7 @@ # include # include # include +# include # include "threads.h" # include # include @@ -42,12 +43,20 @@ Fl_Browser *browser1, *browser2; Fl_Value_Output *value1, *value2; int start2 = 3; +void magic_number_cb(void *p) +{ + Fl_Value_Output *w = (Fl_Value_Output*)p; + w->labelcolor(FL_RED); + w->redraw_label(); +} + void* prime_func(void* p) { Fl_Browser* browser = (Fl_Browser*) p; Fl_Value_Output *value; int n; int step; + char proud = 0; if (browser == browser2) { n = start2; @@ -86,6 +95,10 @@ void* prime_func(void* p) // message we pass here isn't used for anything, so we could also // just pass NULL. Fl::awake(p); + if (n>10000 && !proud) { + proud = 1; + Fl::awake(magic_number_cb, value); + } } else { // This should not be necessary since "n" and "step" are local variables, // however it appears that at least MacOS X has some threading issues