Author: spitzak
Date: 2007-07-03 16:46:33 -0400 (Tue, 03 Jul 2007)
New Revision: 5923
Log:
Made it so if you don't show() any windows, you can still call fltk::run
or wait() or check() on OSX even if you are rsh'd in and don't have
administrator privledges. This is similar to how the X version works if
DISPLAY is not set, and allows a gui program to have a "command line"
mode without lots of if statements. This required changing the awake()
call back to a pipe and some checks inside the fltk calls to avoid
calling apparently illegal Carbon functions.
Modified:
trunk/src/lock.cxx
trunk/src/osx/run.cxx
Modified: trunk/src/lock.cxx
===================================================================
--- trunk/src/lock.cxx 2007-07-03 20:44:12 UTC (rev 5922)
+++ trunk/src/lock.cxx 2007-07-03 20:46:33 UTC (rev 5923)
@@ -202,22 +202,18 @@
static pthread_t main_thread_id;
-#if !USE_QUARTZ
static void* thread_message_;
static void thread_awake_cb(int fd, void*) {
while (read(fd, &thread_message_, sizeof(void*)) > 0);
}
static int thread_filedes[2];
-#endif
static void init_function() {
// Init threads communication pipe to let threads awake FLTK from wait
main_thread_id = pthread_self();
-#if !USE_QUARTZ
pipe(thread_filedes);
fcntl(thread_filedes[0], F_SETFL, O_NONBLOCK);
fltk::add_fd(thread_filedes[0], fltk::READ, thread_awake_cb);
-#endif
fl_lock_function = init_or_lock_function = lock_function;
fl_unlock_function = unlock_function;
lock_function();
@@ -231,20 +227,18 @@
return init_or_lock_function == init_function || pthread_self() ==
main_thread_id;
}
-#if !USE_QUARTZ
void fltk::awake(void* msg) {
write(thread_filedes[1], &msg, sizeof(void*));
}
// the following is already defined in CYGWIN
// for the common win32/run.cxx part
-# if !defined(__CYGWIN__)
+#if !defined(__CYGWIN__)
void* fltk::thread_message() {
void* r = thread_message_;
thread_message_ = 0;
return r;
}
-# endif
#endif
#else
Modified: trunk/src/osx/run.cxx
===================================================================
--- trunk/src/osx/run.cxx 2007-07-03 20:44:12 UTC (rev 5922)
+++ trunk/src/osx/run.cxx 2007-07-03 20:46:33 UTC (rev 5923)
@@ -77,6 +77,11 @@
}
#endif
+// these pointers are set by the lock() function:
+static void nothing() {}
+void (*fl_lock_function)() = nothing;
+void (*fl_unlock_function)() = nothing;
+
////////////////////////////////////////////////////////////////
// interface to select call:
//
@@ -166,6 +171,59 @@
enum { kEventClassFLTK = 'fltk' };
enum { kEventFLTKBreakLoop = 1, kEventFLTKDataReady };
+// Run select() and do the callbacks:
+static int run_select(double time_to_wait, bool in_thread, bool callbacks) {
+ // Thread safe local copy
+ pthread_mutex_lock(&select_mutex);
+ int maxfd = ::maxfd;
+ fd_set r = fdsets[0];
+ fd_set w = fdsets[1];
+ fd_set x = fdsets[2];
+ pthread_mutex_unlock(&select_mutex);
+ // TACK ON FD'S FOR 'CANCEL PIPE'
+ if (in_thread) {
+ FD_SET(G_pipe[0], &r);
+ if ( G_pipe[0] > maxfd ) maxfd = G_pipe[0];
+ }
+ DEBUGMSG("Calling select\n");
+ int ret;
+ if (time_to_wait < 2147483.648f) {
+ timeval t;
+ t.tv_sec = int(time_to_wait);
+ t.tv_usec = int(1000000 * (time_to_wait-t.tv_sec));
+ ret = ::select(maxfd+1, &r, &w, &x, &t);
+ } else {
+ ret = ::select(maxfd+1, &r, &w, &x, 0);
+ }
+ if (ret > 0) {
+ DEBUGMSG("Select returned non-zero\n");
+ if (!callbacks) return ret;
+ 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;
+ 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) {
+ DEBUGMSG("DOING CALLBACK: ");
+ fl_lock_function();
+ fd[i].cb(f, fd[i].arg);
+ fl_unlock_function();
+ DEBUGMSG("DONE\n");
+ }
+ }
+ // see if we need to copy fd_sets again:
+ if (in_thread && FD_ISSET(G_pipe[0], &r)) {
+ DEBUGMSG("reading from G_pipe\n");
+ char buf[1]; read(G_pipe[0],buf,1);
+ }
+ return ret;
+ } else {
+ return 0;
+ }
+}
+
// select_thread
// Separate thread, watches for changes in user's file descriptors.
// Sends a 'data ready event' to the main thread if any change.
@@ -177,65 +235,18 @@
EventQueueRef eventqueue = (EventQueueRef)userdata;
while (1) {
- // Thread safe local copy
- pthread_mutex_lock(&select_mutex);
- int maxfd = ::maxfd;
- fd_set r = fdsets[0];
- fd_set w = fdsets[1];
- fd_set x = fdsets[2];
- pthread_mutex_unlock(&select_mutex);
- // TACK ON FD'S FOR 'CANCEL PIPE'
- FD_SET(G_pipe[0], &r);
- if ( G_pipe[0] > maxfd ) maxfd = G_pipe[0];
-
- DEBUGMSG("Calling select\n");
- // timeval t = { 1000, 0 }; // 1000 seconds;
- int ret = ::select(maxfd+1, &r, &w, &x, 0 /*&t*/);
+ if (run_select(1e20, true, true)) {
+ // wake up the main thread with a message:
+ EventRef drEvent;
+ CreateEvent( 0, kEventClassFLTK, kEventFLTKDataReady,
+ 0, kEventAttributeUserEvent, &drEvent);
+ PostEventToQueue(GetCurrentEventQueue(), drEvent,
kEventPriorityStandard);
+ }
//pthread_testcancel(); // OSX 10.0.4 and under: need to do this
// so parent can cancel us :(
- if (ret > 0) {
- DEBUGMSG("Select returned non-zero\n");
- 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;
- 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) {
- DEBUGMSG("DOING CALLBACK: ");
- fltk::lock();
- fd[i].cb(f, fd[i].arg);
- fltk::unlock();
- DEBUGMSG("DONE\n");
- }
- }
- // see if we need to copy fd_sets again:
- if (FD_ISSET(G_pipe[0], &r)) {
- DEBUGMSG("reading from G_pipe\n");
- char buf[1]; read(G_pipe[0],buf,1);
- }
- fltk::awake();
- }
}
}
-static void* thread_message_;
-void fltk::awake(void* msg) {
- thread_message_ = msg;
- // wake up the main thread with a message:
- EventRef drEvent;
- CreateEvent( 0, kEventClassFLTK, kEventFLTKDataReady,
- 0, kEventAttributeUserEvent, &drEvent);
- PostEventToQueue(GetCurrentEventQueue(), drEvent, kEventPriorityStandard);
-}
-
-void* fltk::thread_message() {
- void* r = thread_message_;
- thread_message_ = 0;
- return r;
-}
-
// Main thread calls this when it gets the above data-ready message:
// This does nothing right now because above code did the callbacks:
static void HandleDataReady()
@@ -266,11 +277,6 @@
#endif
}
-// these pointers are set by the lock() function:
-static void nothing() {}
-void (*fl_lock_function)() = nothing;
-void (*fl_unlock_function)() = nothing;
-
////////////////////////////////////////////////////////////////
// public variables
@@ -402,10 +408,19 @@
* do the callbacks for the events and sockets. Returns non-zero if
* anything happened during the time period.
*/
-//+++ verify port to FLTK2
static inline int fl_wait(double time)
{
- OSStatus ret;
+ if (!CreatedWindow::first && !select_thread) {
+ // If there are no windows, avoid calling event handler stuff. This
+ // allows the program to work on a headless render farm or when
+ // ssh'd in without admin privledges.
+ // Also similar to how the X11 version works when DISPLAY is not set.
+ fl_unlock_function();
+ int ret = run_select(time, false, true);
+ fl_lock_function();
+ return ret;
+ }
+
static EventTargetRef target = 0;
if ( !target ) {
target = GetEventDispatcherTarget();
@@ -428,6 +443,7 @@
{ kEventClassMouse, kEventMouseDragged },
{ kEventClassFLTK, kEventFLTKBreakLoop },
{ kEventClassFLTK, kEventFLTKDataReady } };
+ OSStatus ret;
ret = InstallEventHandler( target, dispatchHandler,
GetEventTypeCount(dispatchEvents),
dispatchEvents, 0, 0L );
@@ -500,6 +516,9 @@
* ready() is just like wait(0.0) except no callbacks are done.
*/
static inline int fl_ready() {
+ if (!CreatedWindow::first && !select_thread) {
+ return run_select(0.0, false, false);
+ }
EventRef event;
return !ReceiveNextEvent(0, NULL, 0.0, false, &event);
}
_______________________________________________
fltk-commit mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-commit