diff options
| -rw-r--r-- | CHANGES | 12 | ||||
| -rw-r--r-- | documentation/Fl_Menu_.html | 15 | ||||
| -rw-r--r-- | fluid/align_widget.cxx | 14 | ||||
| -rw-r--r-- | src/Fl_Text_Display.cxx | 19 | ||||
| -rw-r--r-- | src/Fl_mac.cxx | 461 |
5 files changed, 292 insertions, 229 deletions
@@ -1,7 +1,17 @@ CHANGES IN FLTK 1.1.5rc1 - Documentation updates (STR #245, STR #250, STR #277, - STR #281) + STR #281, STR #328, STR #338) + - FLUID's Layout->Center In Group functionality did not + properly handle widgets that were children of a + Fl_Window widget (STR #318) + - The Fl_Text_Display destructor did not remove the + predelete callback associated with the current buffer + (STR #332) + - Fixed several bugs in the MacOS X Fl::add_fd() + handling (STR #333, STR #337) + - The Fl_Text_Display widget did not display selections + set by the application (STR #322) - FLUID crashed if you did layout with a window widget (STR #317) - Fl_Scroll::clear() didn't remove the child widget from diff --git a/documentation/Fl_Menu_.html b/documentation/Fl_Menu_.html index 5aee92324..f9734599f 100644 --- a/documentation/Fl_Menu_.html +++ b/documentation/Fl_Menu_.html @@ -45,7 +45,7 @@ be "private": a dynamically allocated array managed by the Fl_Menu_. <LI><A href=#Fl_Menu_.copy>copy</A></LI> <LI><A href=#Fl_Menu_.down_box>down_box</A></LI> <LI><A href=#Fl_Menu_.global>global</A></LI> -<LI><A href=#Fl_Menu_.item_pathname>global</A></LI> +<LI><A href=#Fl_Menu_.item_pathname>item_pathname</A></LI> <LI><A href=#Fl_Menu_.menu>menu</A></LI> </UL> </TD><TD align=left valign=top> @@ -146,12 +146,13 @@ that the new entry was placed at.</P> FL_CTRL+'A') or a string describing the shortcut in one of two ways:</p> <pre> - [#+^]<ascii_value>Â Â Â Â eg. "97", "^97", "+97", "#97" - [#+^]<ascii_char>Â Â Â Â Â eg. "a", "^a", "+a", "#a" + [#+^]<ascii_value> eg. "97", "^97", "+97", "#97" + [#+^]<ascii_char> eg. "a", "^a", "+a", "#a" </pre> -..where <ascii_value> is a decimal value representing an ascii character -(eg. 97 is the ascii for 'a'), and the optional prefixes enhance the value -that follows. Multiple prefixes must appear in the above order. +..where <ascii_value> is a decimal value representing an +ascii character (eg. 97 is the ascii for 'a'), and the optional +prefixes enhance the value that follows. Multiple prefixes must +appear in the above order. <pre> # - Alt + - Shift @@ -215,7 +216,7 @@ not have to be put in a window at all). one will replace the old one. There is no way to remove the <TT> global()</TT> setting (so don't destroy the widget!)</P> -<h4><a name='Fl_Menu_.item_pathnaem'>int Fl_Menu_::item_pathname(char *name, int namelen ) const;</a><br> +<h4><a name=Fl_Menu_.item_pathname>int Fl_Menu_::item_pathname(char *name, int namelen ) const;</a><br> int Fl_Menu_::item_pathname(char *name, int namelen, const Fl_Menu_Item *finditem) const;</h4> diff --git a/fluid/align_widget.cxx b/fluid/align_widget.cxx index 6f90424e5..ad5544610 100644 --- a/fluid/align_widget.cxx +++ b/fluid/align_widget.cxx @@ -1,5 +1,5 @@ // -// "$Id: align_widget.cxx,v 1.1.2.4 2004/04/06 02:47:25 easysw Exp $" +// "$Id: align_widget.cxx,v 1.1.2.5 2004/04/06 17:38:36 easysw Exp $" // // alignment code for the Fast Light Tool Kit (FLTK). // @@ -303,7 +303,10 @@ void align_widget_cb(Fl_Widget*, long how) { Fl_Widget *w = ((Fl_Widget_Type *)o)->o; Fl_Widget *p = ((Fl_Widget_Type *)o->parent)->o; - int center2 = 2*p->x()+p->w(); + int center2; + + if (w->window() == p) center2 = p->w(); + else center2 = 2*p->x()+p->w(); w->resize((center2-w->w())/2, w->y(), w->w(), w->h()); w->redraw(); if (w->window()) w->window()->redraw(); @@ -315,7 +318,10 @@ void align_widget_cb(Fl_Widget*, long how) { Fl_Widget *w = ((Fl_Widget_Type *)o)->o; Fl_Widget *p = ((Fl_Widget_Type *)o->parent)->o; - int center2 = 2*p->y()+p->h(); + int center2; + + if (w->window() == p) center2 = p->h(); + else center2 = 2*p->y()+p->h(); w->resize(w->x(), (center2-w->h())/2, w->w(), w->h()); w->redraw(); if (w->window()) w->window()->redraw(); @@ -326,6 +332,6 @@ void align_widget_cb(Fl_Widget*, long how) // -// End of "$Id: align_widget.cxx,v 1.1.2.4 2004/04/06 02:47:25 easysw Exp $". +// End of "$Id: align_widget.cxx,v 1.1.2.5 2004/04/06 17:38:36 easysw Exp $". // diff --git a/src/Fl_Text_Display.cxx b/src/Fl_Text_Display.cxx index 9ec01939d..623efe5ec 100644 --- a/src/Fl_Text_Display.cxx +++ b/src/Fl_Text_Display.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_Text_Display.cxx,v 1.12.2.49 2004/03/01 02:05:02 easysw Exp $" +// "$Id: Fl_Text_Display.cxx,v 1.12.2.50 2004/04/06 17:38:36 easysw Exp $" // // Copyright 2001-2003 by Bill Spitzak and others. // Original code Copyright Mark Edel. Permission to distribute under @@ -143,7 +143,10 @@ Fl_Text_Display::Fl_Text_Display(int X, int Y, int W, int H, const char* l) ** freed, nor are the style buffer or style table. */ Fl_Text_Display::~Fl_Text_Display() { - if (mBuffer) mBuffer->remove_modify_callback(buffer_modified_cb, this); + if (mBuffer) { + mBuffer->remove_modify_callback(buffer_modified_cb, this); + mBuffer->remove_predelete_callback(buffer_predelete_cb, this); + } if (mLineStarts) delete[] mLineStarts; } @@ -1583,13 +1586,15 @@ void Fl_Text_Display::draw_string( int style, int X, int Y, int toX, font = styleRec->font; fsize = styleRec->size; - if ( style & (HIGHLIGHT_MASK | PRIMARY_MASK) && Fl::focus() == this) { - background = selection_color(); + if (style & (HIGHLIGHT_MASK | PRIMARY_MASK)) { + if (Fl::focus() == this) background = selection_color(); + else background = fl_color_average(color(), selection_color(), 0.5f); } else background = color(); foreground = fl_contrast(styleRec->color, background); - } else if ( style & (HIGHLIGHT_MASK | PRIMARY_MASK) && Fl::focus() == this ) { - background = selection_color(); + } else if (style & (HIGHLIGHT_MASK | PRIMARY_MASK)) { + if (Fl::focus() == this) background = selection_color(); + else background = fl_color_average(color(), selection_color(), 0.5f); foreground = fl_contrast(textcolor(), background); } else { foreground = textcolor(); @@ -3061,5 +3066,5 @@ int Fl_Text_Display::handle(int event) { // -// End of "$Id: Fl_Text_Display.cxx,v 1.12.2.49 2004/03/01 02:05:02 easysw Exp $". +// End of "$Id: Fl_Text_Display.cxx,v 1.12.2.50 2004/04/06 17:38:36 easysw Exp $". // diff --git a/src/Fl_mac.cxx b/src/Fl_mac.cxx index 2b9e528a0..b925a0008 100644 --- a/src/Fl_mac.cxx +++ b/src/Fl_mac.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_mac.cxx,v 1.1.2.52 2004/03/11 05:17:12 easysw Exp $" +// "$Id: Fl_mac.cxx,v 1.1.2.53 2004/04/06 17:38:36 easysw Exp $" // // MacOS specific code for the Fast Light Tool Kit (FLTK). // @@ -57,13 +57,15 @@ extern "C" { // #define DEBUG_SELECT // UNCOMMENT FOR SELECT()/THREAD DEBUGGING #ifdef DEBUG_SELECT -#include <stdio.h> // testing -#define DEBUGMSG(msg) fprintf(stderr, msg); -#define DEBUGPERRORMSG(msg) perror(msg) +#include <stdio.h> // testing +#define DEBUGMSG(msg) if ( msg ) fprintf(stderr, msg); +#define DEBUGPERRORMSG(msg) if ( msg ) perror(msg) +#define DEBUGTEXT(txt) txt #else #define DEBUGMSG(msg) #define DEBUGPERRORMSG(msg) -#endif /*DEBUGSELECT*/ +#define DEBUGTEXT(txt) NULL +#endif /*DEBUG_SELECT*/ // external functions extern Fl_Window* fl_find(Window); @@ -141,169 +143,278 @@ static void nothing() {} void (*fl_lock_function)() = nothing; void (*fl_unlock_function)() = nothing; - -// -// Select interface // +// Select interface -- how it's implemented: +// When the user app configures one or more file descriptors to monitor +// with Fl::add_fd(), we start a separate thread to select() the data, +// sending a custom OSX 'FLTK data ready event' to the parent thread's +// RunApplicationLoop(), so that it triggers the data ready callbacks +// in the parent thread. -erco 04/04/04 +// #define POLLIN 1 #define POLLOUT 4 #define POLLERR 8 -struct FD + +// Class to handle select() 'data ready' +class DataReady { - int fd; - short events; - void (*cb)(int, void*); - void* arg; + struct FD + { + int fd; + short events; + void (*cb)(int, void*); + void* arg; + }; + int nfds, fd_array_size; + FD *fds; + pthread_t tid; // select()'s thread id + + // Data that needs to be locked (all start with '_') + pthread_mutex_t _datalock; // data lock + fd_set _fdsets[3]; // r/w/x sets user wants to monitor + int _maxfd; // max fd count to monitor + int _cancelpipe[2]; // pipe used to help cancel thread + void *_userdata; // thread's userdata + +public: + DataReady() + { + nfds = 0; + fd_array_size = 0; + fds = 0; + tid = 0; + + pthread_mutex_init(&_datalock, NULL); + FD_ZERO(&_fdsets[0]); FD_ZERO(&_fdsets[1]); FD_ZERO(&_fdsets[2]); + _cancelpipe[0] = _cancelpipe[1] = 0; + _userdata = 0; + _maxfd = 0; + } + + ~DataReady() + { + CancelThread(DEBUGTEXT("DESTRUCTOR\n")); + if (fds) { free(fds); fds = 0; } + nfds = 0; + } + + // Locks + // The convention for locks: volatile vars start with '_', + // and must be locked before use. Locked code is prefixed + // with /*LOCK*/ to make painfully obvious esp. in debuggers. -erco + // + void DataLock() { pthread_mutex_lock(&_datalock); } + void DataUnlock() { pthread_mutex_unlock(&_datalock); } + + // Accessors + int IsThreadRunning() { return(tid ? 1 : 0); } + int GetNfds() { return(nfds); } + int GetCancelPipe(int ix) { return(_cancelpipe[ix]); } + fd_set GetFdset(int ix) { return(_fdsets[ix]); } + + // Methods + void AddFD(int n, int events, void (*cb)(int, void*), void *v); + void RemoveFD(int n, int events); + int CheckData(fd_set& r, fd_set& w, fd_set& x); + void HandleData(fd_set& r, fd_set& w, fd_set& x); + static void* DataReadyThread(void *self); + void StartThread(void *userdata); + void CancelThread(const char *reason); }; -static int nfds = 0; -static int fd_array_size = 0; -static FD *fd = 0; -static int G_pipe[2] = { 0,0 }; // work around pthread_cancel() problem -enum GetSet { GET = 1, SET = 2 }; -static pthread_mutex_t select_mutex; // global data lock - -// MAXFD ACCESSOR (HANDLES LOCKING) -static void MaxFD(GetSet which, int& val) -{ - static int maxfd = 0; - pthread_mutex_lock(&select_mutex); - if ( which == GET ) { val = maxfd; } - else { maxfd = val; } - pthread_mutex_unlock(&select_mutex); -} -// FDSET ACCESSOR (HANDLES LOCKING) -static void Fdset(GetSet which, fd_set& r, fd_set &w, fd_set &x) -{ - static fd_set fdsets[3]; - pthread_mutex_lock(&select_mutex); - if ( which == GET ) { r = fdsets[0]; w = fdsets[1]; x = fdsets[2]; } - else { fdsets[0] = r; fdsets[1] = w; fdsets[2] = x; } - pthread_mutex_unlock(&select_mutex); -} +static DataReady dataready; -void Fl::add_fd( int n, int events, void (*cb)(int, void*), void *v ) +void DataReady::AddFD(int n, int events, void (*cb)(int, void*), void *v) { - remove_fd(n, events); - + RemoveFD(n, events); int i = nfds++; - - if (i >= fd_array_size) { + if (i >= fd_array_size) + { FD *temp; fd_array_size = 2*fd_array_size+1; - - if (!fd) { temp = (FD*)malloc(fd_array_size*sizeof(FD)); } - else { temp = (FD*)realloc(fd, fd_array_size*sizeof(FD)); } - + if (!fds) { temp = (FD*)malloc(fd_array_size*sizeof(FD)); } + else { temp = (FD*)realloc(fds, fd_array_size*sizeof(FD)); } if (!temp) return; - fd = temp; - } - - fd[i].cb = cb; - fd[i].arg = v; - fd[i].fd = n; - fd[i].events = events; - - { - int maxfd; - fd_set r, w, x; - MaxFD(GET, maxfd); - Fdset(GET, r, w, x); - if (events & POLLIN) FD_SET(n, &r); - if (events & POLLOUT) FD_SET(n, &w); - if (events & POLLERR) FD_SET(n, &x); - if (n > maxfd) maxfd = n; - Fdset(SET, r, w, x); - MaxFD(SET, maxfd); + fds = temp; } + fds[i].cb = cb; + fds[i].arg = v; + fds[i].fd = n; + fds[i].events = events; + DataLock(); + /*LOCK*/ if (events & POLLIN) FD_SET(n, &_fdsets[0]); + /*LOCK*/ if (events & POLLOUT) FD_SET(n, &_fdsets[1]); + /*LOCK*/ if (events & POLLERR) FD_SET(n, &_fdsets[2]); + /*LOCK*/ if (n > _maxfd) _maxfd = n; + DataUnlock(); } -void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) -{ - Fl::add_fd(fd, POLLIN, cb, v); -} - -void Fl::remove_fd(int n, int events) +// Remove an FD from the array +void DataReady::RemoveFD(int n, int events) { int i,j; - - for (i=j=0; i<nfds; i++) { - - if (fd[i].fd == n) { - int e = fd[i].events & ~events; + for (i=j=0; i<nfds; i++) + { + if (fds[i].fd == n) + { + int e = fds[i].events & ~events; if (!e) continue; // if no events left, delete this fd - fd[i].events = e; + fds[i].events = e; } - // move it down in the array if necessary: if (j<i) - { fd[j] = fd[i]; } - + { fds[j] = fds[i]; } j++; } - nfds = j; - - { - int maxfd; - fd_set r, w, x; - MaxFD(GET, maxfd); - Fdset(GET, r, w, x); - if (events & POLLIN) FD_CLR(n, &r); - if (events & POLLOUT) FD_CLR(n, &w); - if (events & POLLERR) FD_CLR(n, &x); - if (n == maxfd) maxfd--; - Fdset(SET, r, w, x); - MaxFD(SET, maxfd); - } + DataLock(); + /*LOCK*/ if (events & POLLIN) FD_CLR(n, &_fdsets[0]); + /*LOCK*/ if (events & POLLOUT) FD_CLR(n, &_fdsets[1]); + /*LOCK*/ if (events & POLLERR) FD_CLR(n, &_fdsets[2]); + /*LOCK*/ if (n == _maxfd) _maxfd--; + DataUnlock(); } -void Fl::remove_fd(int n) +// CHECK IF USER DATA READY, RETURNS r/w/x INDICATING WHICH IF ANY +int DataReady::CheckData(fd_set& r, fd_set& w, fd_set& x) { - remove_fd(n, -1); -} - -/** - * Check if there is actually a message pending! - */ -int fl_ready() -{ - if (GetNumEventsInQueue(GetCurrentEventQueue()) > 0) return 1; - return 0; -} - -// CHECK IF USER DATA READY -static int CheckDataReady(fd_set& r, fd_set& w, fd_set& x) -{ - int maxfd; - MaxFD(GET, maxfd); - timeval t = { 0, 1 }; // quick check - int ret = ::select(maxfd+1, &r, &w, &x, &t); + int ret; + DataLock(); + /*LOCK*/ timeval t = { 0, 1 }; // quick check + /*LOCK*/ r = _fdsets[0], w = _fdsets[1], x = _fdsets[2]; + /*LOCK*/ ret = ::select(_maxfd+1, &r, &w, &x, &t); + DataUnlock(); if ( ret == -1 ) - { DEBUGPERRORMSG("CheckDataReady(): select()"); } + { DEBUGPERRORMSG("CheckData(): select()"); } return(ret); } // HANDLE DATA READY CALLBACKS -static void HandleDataReady(fd_set& r, fd_set& w, fd_set& x) +void DataReady::HandleData(fd_set& r, fd_set& w, fd_set& x) { for (int i=0; i<nfds; i++) { - // fprintf(stderr, "CHECKING FD %d OF %d (%d)\n", i, nfds, fd[i].fd); - int f = fd[i].fd; + int f = fds[i].fd; short revents = 0; if (FD_ISSET(f, &r)) revents |= POLLIN; if (FD_ISSET(f, &w)) revents |= POLLOUT; if (FD_ISSET(f, &x)) revents |= POLLERR; - if (fd[i].events & revents) + if (fds[i].events & revents) { DEBUGMSG("DOING CALLBACK: "); - fd[i].cb(f, fd[i].arg); + fds[i].cb(f, fds[i].arg); DEBUGMSG("DONE\n"); } } } +// DATA READY THREAD +// This thread watches for changes in user's file descriptors. +// Sends a 'data ready event' to the main thread if any change. +// +void* DataReady::DataReadyThread(void *o) +{ + DataReady *self = (DataReady*)o; + while ( 1 ) // loop until thread cancel or error + { + // Thread safe local copies of data before each select() + self->DataLock(); + /*LOCK*/ int maxfd = self->_maxfd; + /*LOCK*/ fd_set r = self->GetFdset(0); + /*LOCK*/ fd_set w = self->GetFdset(1); + /*LOCK*/ fd_set x = self->GetFdset(2); + /*LOCK*/ void *userdata = self->_userdata; + /*LOCK*/ int cancelpipe = self->GetCancelPipe(0); + /*LOCK*/ if ( cancelpipe > maxfd ) maxfd = cancelpipe; + /*LOCK*/ FD_SET(cancelpipe, &r); // add cancelpipe to fd's to watch + /*LOCK*/ FD_SET(cancelpipe, &x); + self->DataUnlock(); + // timeval t = { 1000, 0 }; // 1000 seconds; + timeval t = { 2, 0 }; // HACK: 2 secs prevents 'hanging' problem + int ret = ::select(maxfd+1, &r, &w, &x, &t); + pthread_testcancel(); // OSX 10.0.4 and older: needed for parent to cancel + switch ( ret ) + { + case 0: // NO DATA + continue; + case -1: // ERROR + { + DEBUGPERRORMSG("CHILD THREAD: select() failed"); + return(NULL); // error? exit thread + } + default: // DATA READY + { + if (FD_ISSET(cancelpipe, &r) || FD_ISSET(cancelpipe, &x)) // cancel? + { return(NULL); } // just exit + DEBUGMSG("CHILD THREAD: DATA IS READY\n"); + EventRef drEvent; + CreateEvent( 0, kEventClassFLTK, kEventFLTKDataReady, + 0, kEventAttributeUserEvent, &drEvent); + EventQueueRef eventqueue = (EventQueueRef)userdata; + PostEventToQueue(eventqueue, drEvent, kEventPriorityStandard ); + ReleaseEvent( drEvent ); + return(NULL); // done with thread + } + } + } +} + +// START 'DATA READY' THREAD RUNNING, CREATE INTER-THREAD PIPE +void DataReady::StartThread(void *new_userdata) +{ + CancelThread(DEBUGTEXT("STARTING NEW THREAD\n")); + DataLock(); + /*LOCK*/ pipe(_cancelpipe); // pipe for sending cancel msg to thread + /*LOCK*/ _userdata = new_userdata; + DataUnlock(); + DEBUGMSG("*** START THREAD\n"); + pthread_create(&tid, NULL, DataReadyThread, (void*)this); +} + +// CANCEL 'DATA READY' THREAD, CLOSE PIPE +void DataReady::CancelThread(const char *reason) +{ + if ( tid ) + { + DEBUGMSG("*** CANCEL THREAD: "); + DEBUGMSG(reason); + if ( pthread_cancel(tid) == 0 ) // cancel first + { + DataLock(); + /*LOCK*/ write(_cancelpipe[1], "x", 1); // wake thread from select + DataUnlock(); + pthread_join(tid, NULL); // wait for thread to finish + } + tid = 0; + DEBUGMSG("(JOINED) OK\n"); + } + // Close pipe if open + DataLock(); + /*LOCK*/ if ( _cancelpipe[0] ) { close(_cancelpipe[0]); _cancelpipe[0] = 0; } + /*LOCK*/ if ( _cancelpipe[1] ) { close(_cancelpipe[1]); _cancelpipe[1] = 0; } + DataUnlock(); +} + +void Fl::add_fd( int n, int events, void (*cb)(int, void*), void *v ) + { dataready.AddFD(n, events, cb, v); } + +void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) + { dataready.AddFD(fd, POLLIN, cb, v); } + +void Fl::remove_fd(int n, int events) + { dataready.RemoveFD(n, events); } + +void Fl::remove_fd(int n) + { dataready.RemoveFD(n, -1); } + +/** + * Check if there is actually a message pending! + */ +int fl_ready() +{ + if (GetNumEventsInQueue(GetCurrentEventQueue()) > 0) return 1; + return 0; +} /** * handle Apple Menu items (can be created using the Fl_Sys_Menu_Bar @@ -401,24 +512,21 @@ static pascal OSStatus carbonDispatchHandler( EventHandlerCallRef nextHandler, E break; case kEventFLTKDataReady: { - DEBUGMSG("DATA READY EVENT: RECEIVED\n"); + dataready.CancelThread(DEBUGTEXT("DATA READY EVENT\n")); // CHILD THREAD TELLS US DATA READY // Check to see what's ready, and invoke user's cb's // - fd_set r, w, x; - Fdset(GET, r, w, x); - switch ( CheckDataReady(r, w, x) ) + fd_set r,w,x; + switch(dataready.CheckData(r,w,x)) { - case 0: // NO DATA - break; - - case -1: // ERROR - break; - - default: // DATA READY - HandleDataReady(r, w, x); - break; + case 0: // NO DATA + break; + case -1: // ERROR + break; + default: // DATA READY + dataready.HandleData(r,w,x); + break; } } ret = noErr; @@ -447,55 +555,6 @@ static pascal void timerProcCB( EventLoopTimerRef, void* ) fl_unlock_function(); } - -// DATA READY THREAD -// Separate thread, watches for changes in user's file descriptors. -// Sends a 'data ready event' to the main thread if any change. -// -static void *dataready_thread(void *userdata) -{ - EventRef drEvent; - CreateEvent( 0, kEventClassFLTK, kEventFLTKDataReady, - 0, kEventAttributeUserEvent, &drEvent); - EventQueueRef eventqueue = (EventQueueRef)userdata; - - // Thread safe local copy - int maxfd; - fd_set r, w, x; - MaxFD(GET, maxfd); - Fdset(GET, r, w, x); - - // TACK ON FD'S FOR 'CANCEL PIPE' - FD_SET(G_pipe[0], &r); - if ( G_pipe[0] > maxfd ) maxfd = G_pipe[0]; - - // FOREVER UNTIL THREAD CANCEL OR ERROR - while ( 1 ) - { - timeval t = { 1000, 0 }; // 1000 seconds; - int ret = ::select(maxfd+1, &r, &w, &x, &t); - pthread_testcancel(); // OSX 10.0.4 and under: need to do this - // so parent can cancel us :( - switch ( ret ) - { - case 0: // NO DATA - continue; - case -1: // ERROR - { - DEBUGPERRORMSG("CHILD THREAD: select() failed"); - return(NULL); // error? exit thread - } - default: // DATA READY - { - DEBUGMSG("DATA READY EVENT: SENDING\n"); - PostEventToQueue(eventqueue, drEvent, kEventPriorityStandard ); - return(NULL); // done with thread - } - } - } -} - - /** * break the current event loop */ @@ -566,38 +625,20 @@ static double do_queued_events( double time = 0.0 ) got_events = 0; - // START A THREAD TO WATCH FOR DATA READY - static pthread_t dataready_tid = 0; - if ( nfds ) - { - void *userdata = (void*)GetCurrentEventQueue(); - - // PREPARE INTER-THREAD DATA - pthread_mutex_init(&select_mutex, NULL); + // Check for re-entrant condition + if ( dataready.IsThreadRunning() ) + { dataready.CancelThread(DEBUGTEXT("AVOID REENTRY\n")); } - if ( G_pipe[0] ) { close(G_pipe[0]); G_pipe[0] = 0; } - if ( G_pipe[1] ) { close(G_pipe[1]); G_pipe[1] = 0; } - pipe(G_pipe); - - DEBUGMSG("*** START THREAD\n"); - pthread_create(&dataready_tid, NULL, dataready_thread, userdata); - } + // Start thread to watch for data ready + if ( dataready.GetNfds() ) + { dataready.StartThread((void*)GetCurrentEventQueue()); } fl_unlock_function(); SetEventLoopTimerNextFireTime( timer, time ); RunApplicationEventLoop(); // will return after the previously set time - if ( dataready_tid != 0 ) - { - DEBUGMSG("*** CANCEL THREAD: "); - pthread_cancel(dataready_tid); // cancel first - write(G_pipe[1], "x", 1); // then wakeup thread from select - pthread_join(dataready_tid, NULL); // wait for thread to finish - if ( G_pipe[0] ) { close(G_pipe[0]); G_pipe[0] = 0; } - if ( G_pipe[1] ) { close(G_pipe[1]); G_pipe[1] = 0; } - dataready_tid = 0; - DEBUGMSG("OK\n"); - } + if ( dataready.IsThreadRunning() ) + { dataready.CancelThread(DEBUGTEXT("APPEVENTLOOP DONE\n")); } fl_lock_function(); @@ -1879,6 +1920,6 @@ void Fl::paste(Fl_Widget &receiver, int clipboard) { // -// End of "$Id: Fl_mac.cxx,v 1.1.2.52 2004/03/11 05:17:12 easysw Exp $". +// End of "$Id: Fl_mac.cxx,v 1.1.2.53 2004/04/06 17:38:36 easysw Exp $". // |
