Include a stripped-down version of FLTK in tree and add a USE_INCLUDED_FLTK option to build against it.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4603 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/fltk/src/Fl_lock.cxx b/common/fltk/src/Fl_lock.cxx
new file mode 100644
index 0000000..e95bceb
--- /dev/null
+++ b/common/fltk/src/Fl_lock.cxx
@@ -0,0 +1,418 @@
+//
+// "$Id: Fl_lock.cxx 8393 2011-02-06 19:46:11Z manolo $"
+//
+// Multi-threading support code for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2010 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 on the following page:
+//
+//     http://www.fltk.org/str.php
+//
+
+
+#include <FL/Fl.H>
+#include <config.h>
+
+#include <stdlib.h>
+
+/*
+   From Bill:
+
+   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 Mike:
+
+   Starting with 1.1.8, we now have a callback so that you can
+   process awake() messages as they come in.
+
+
+   The API:
+
+   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::unlock() - release the recursive lock.
+
+   Fl::awake(void*) - Causes Fl::wait() to return (with the lock
+   locked) even if there are no events ready.
+
+   Fl::awake(void (*cb)(void *), void*) - Call a function
+   in the main thread from within another thread of execution.
+
+   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!
+*/
+
+#ifndef FL_DOXYGEN
+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_;
+#endif
+
+static const int AWAKE_RING_SIZE = 1024;
+static void lock_ring();
+static void unlock_ring();
+
+
+/** Adds an awake handler for use in awake(). */
+int Fl::add_awake_handler_(Fl_Awake_Handler func, void *data)
+{
+  int ret = 0;
+  lock_ring();
+  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 an 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;
+  }
+  unlock_ring();
+  return ret;
+}
+/** Gets the last stored awake handler for use in awake(). */
+int Fl::get_awake_handler_(Fl_Awake_Handler &func, void *&data)
+{
+  int ret = 0;
+  lock_ring();
+  if (!awake_ring_ || awake_ring_head_ == awake_ring_tail_) {
+    ret = -1;
+  } else {
+    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;
+  }
+  unlock_ring();
+  return ret;
+}
+
+/**
+ Let the main thread know an update is pending and have it call a specific function.
+ Registers a function that will be 
+ called by the main thread during the next message handling cycle. 
+ Returns 0 if the callback function was registered, 
+ and -1 if registration failed. Over a thousand awake callbacks can be
+ registered simultaneously.
+ 
+ \see Fl::awake(void* message=0)
+*/
+int Fl::awake(Fl_Awake_Handler func, void *data) {
+  int ret = add_awake_handler_(func, data);
+  Fl::awake();
+  return ret;
+}
+
+////////////////////////////////////////////////////////////////
+// Windows threading...
+/** \fn int Fl::lock()
+    The lock() method blocks the current thread until it
+    can safely access FLTK widgets and data. Child threads should
+    call this method prior to updating any widgets or accessing
+    data. The main thread must call lock() to initialize
+    the threading support in FLTK. lock() will return non-zero
+    if threading is not available on the platform.
+    
+    Child threads must call unlock() when they are done
+    accessing FLTK.
+    
+    When the wait() method is waiting
+    for input or timeouts, child threads are given access to FLTK.
+    Similarly, when the main thread needs to do processing, it will
+    wait until all child threads have called unlock() before processing
+    additional data.
+ 
+    \return 0 if threading is available on the platform; non-zero
+    otherwise.
+    
+    See also: \ref advanced_multithreading
+*/
+/** \fn void Fl::unlock()
+    The unlock() method releases the lock that was set
+    using the lock() method. Child
+    threads should call this method as soon as they are finished
+    accessing FLTK.
+    
+    See also: \ref advanced_multithreading
+*/
+/** \fn void Fl::awake(void* msg)
+    Sends a message pointer to the main thread, 
+    causing any pending Fl::wait() call to 
+    terminate so that the main thread can retrieve the message and any pending 
+    redraws can be processed.
+    
+    Multiple calls to Fl::awake() will queue multiple pointers 
+    for the main thread to process, up to a system-defined (typically several 
+    thousand) depth. The default message handler saves the last message which 
+    can be accessed using the 
+    Fl::thread_message() function.
+
+    In the context of a threaded application, a call to Fl::awake() with no
+    argument will trigger event loop handling in the main thread. Since
+    it is not possible to call Fl::flush() from a subsidiary thread,
+    Fl::awake() is the best (and only, really) substitute.
+    
+    See also: \ref advanced_multithreading
+*/
+#ifdef WIN32
+#  include <windows.h>
+#  include <process.h>
+#  include <FL/x.H>
+
+// 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;
+CRITICAL_SECTION *cs_ring;
+
+void unlock_ring() {
+  LeaveCriticalSection(cs_ring);
+}
+
+void lock_ring() {
+  if (!cs_ring) {
+    cs_ring = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION));
+    InitializeCriticalSection(cs_ring);
+  }
+  EnterCriticalSection(cs_ring);
+}
+
+//
+// 'unlock_function()' - Release the lock.
+//
+
+static void unlock_function() {
+  LeaveCriticalSection(&cs);
+}
+
+//
+// 'lock_function()' - Get the lock.
+//
+
+static void lock_function() {
+  EnterCriticalSection(&cs);
+}
+
+int Fl::lock() {
+  if (!main_thread) InitializeCriticalSection(&cs);
+
+  lock_function();
+
+  if (!main_thread) {
+    fl_lock_function   = lock_function;
+    fl_unlock_function = unlock_function;
+    main_thread        = GetCurrentThreadId();
+  }
+  return 0;
+}
+
+void Fl::unlock() {
+  unlock_function();
+}
+
+void Fl::awake(void* msg) {
+  PostThreadMessage( main_thread, fl_wake_msg, (WPARAM)msg, 0);
+}
+
+////////////////////////////////////////////////////////////////
+// POSIX threading...
+#elif HAVE_PTHREAD
+#  include <unistd.h>
+#  include <fcntl.h>
+#  include <pthread.h>
+
+// Pipe for thread messaging via Fl::awake()...
+static int thread_filedes[2];
+
+// Mutex and state information for Fl::lock() and Fl::unlock()...
+static pthread_mutex_t fltk_mutex;
+static pthread_t owner;
+static int counter;
+
+static void lock_function_init_std() {
+  pthread_mutex_init(&fltk_mutex, NULL);
+}
+
+static void lock_function_std() {
+  if (!counter || owner != pthread_self()) {
+    pthread_mutex_lock(&fltk_mutex);
+    owner = pthread_self();
+  }
+  counter++;
+}
+
+static void unlock_function_std() {
+  if (!--counter) pthread_mutex_unlock(&fltk_mutex);
+}
+
+#  ifdef PTHREAD_MUTEX_RECURSIVE
+static bool lock_function_init_rec() {
+  pthread_mutexattr_t attrib;
+  pthread_mutexattr_init(&attrib);
+  if (pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE)) {
+    pthread_mutexattr_destroy(&attrib);
+    return true;
+  }
+
+  pthread_mutex_init(&fltk_mutex, &attrib);
+  return false;
+}
+
+static void lock_function_rec() {
+  pthread_mutex_lock(&fltk_mutex);
+}
+
+static void unlock_function_rec() {
+  pthread_mutex_unlock(&fltk_mutex);
+}
+#  endif // PTHREAD_MUTEX_RECURSIVE
+
+void Fl::awake(void* msg) {
+  if (write(thread_filedes[1], &msg, sizeof(void*))==0) { /* ignore */ }
+}
+
+static void* thread_message_;
+void* Fl::thread_message() {
+  void* r = thread_message_;
+  thread_message_ = 0;
+  return r;
+}
+
+static void thread_awake_cb(int fd, void*) {
+  if (read(fd, &thread_message_, sizeof(void*))==0) { 
+    /* This should never happen */
+  }
+  Fl_Awake_Handler func;
+  void *data;
+  while (Fl::get_awake_handler_(func, data)==0) {
+    (*func)(data);
+  }
+}
+
+// These pointers are in Fl_x.cxx:
+extern void (*fl_lock_function)();
+extern void (*fl_unlock_function)();
+
+int Fl::lock() {
+  if (!thread_filedes[1]) {
+    // Initialize thread communication pipe to let threads awake FLTK
+    // from Fl::wait()
+    if (pipe(thread_filedes)==-1) {
+      /* this should not happen */
+    }
+
+    // Make the write side of the pipe non-blocking to avoid deadlock
+    // conditions (STR #1537)
+    fcntl(thread_filedes[1], F_SETFL,
+          fcntl(thread_filedes[1], F_GETFL) | O_NONBLOCK);
+
+    // Monitor the read side of the pipe so that messages sent via
+    // Fl::awake() from a thread will "wake up" the main thread in
+    // Fl::wait().
+    Fl::add_fd(thread_filedes[0], FL_READ, thread_awake_cb);
+
+    // Set lock/unlock functions for this system, using a system-supplied
+    // recursive mutex if supported...
+#  ifdef PTHREAD_MUTEX_RECURSIVE
+    if (!lock_function_init_rec()) {
+      fl_lock_function   = lock_function_rec;
+      fl_unlock_function = unlock_function_rec;
+    } else {
+#  endif // PTHREAD_MUTEX_RECURSIVE
+      lock_function_init_std();
+      fl_lock_function   = lock_function_std;
+      fl_unlock_function = unlock_function_std;
+#  ifdef PTHREAD_MUTEX_RECURSIVE
+    }
+#  endif // PTHREAD_MUTEX_RECURSIVE
+  }
+
+  fl_lock_function();
+  return 0;
+}
+
+void Fl::unlock() {
+  fl_unlock_function();
+}
+
+// Mutex code for the awake ring buffer
+static pthread_mutex_t *ring_mutex;
+
+void unlock_ring() {
+  pthread_mutex_unlock(ring_mutex);
+}
+
+void lock_ring() {
+  if (!ring_mutex) {
+    ring_mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+    pthread_mutex_init(ring_mutex, NULL);
+  }
+  pthread_mutex_lock(ring_mutex);
+}
+
+#else
+
+void unlock_ring() {
+}
+
+void lock_ring() {
+}
+
+void Fl::awake(void*) {
+}
+
+int Fl::lock() {
+  return 1;
+}
+
+void Fl::unlock() {
+}
+
+void* Fl::thread_message() {
+  return NULL;
+}
+
+#endif // WIN32
+
+//
+// End of "$Id: Fl_lock.cxx 8393 2011-02-06 19:46:11Z manolo $".
+//