summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES12
-rw-r--r--documentation/Fl_Menu_.html15
-rw-r--r--fluid/align_widget.cxx14
-rw-r--r--src/Fl_Text_Display.cxx19
-rw-r--r--src/Fl_mac.cxx461
5 files changed, 292 insertions, 229 deletions
diff --git a/CHANGES b/CHANGES
index dbe83f348..7ffcde77f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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"
+ [#+^]&lt;ascii_value&gt;  eg. "97", "^97", "+97", "#97"
+ [#+^]&lt;ascii_char&gt;  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 &lt;ascii_value&gt; 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 $".
//