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_open_uri.cxx b/common/fltk/src/fl_open_uri.cxx
new file mode 100644
index 0000000..adeb4cb
--- /dev/null
+++ b/common/fltk/src/fl_open_uri.cxx
@@ -0,0 +1,383 @@
+//
+// "$Id: fl_open_uri.cxx 8063 2010-12-19 21:20:10Z matt $"
+//
+// fl_open_uri() code for FLTK.
+//
+// Test with:
+//
+//    gcc -I/fltk/dir -I/fltk/dir/src -DTEST -o fl_open_uri fl_open_uri.cxx -lfltk
+//
+// Copyright 2003-2010 by Michael R Sweet
+//
+// 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.
+//
+
+//
+// Include necessary headers...
+//
+
+#include <FL/filename.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include "flstring.h"
+#ifdef WIN32
+#  include <windows.h>
+#  include <shellapi.h>
+#else
+#  include <sys/wait.h>
+#  include <signal.h>
+#  include <fcntl.h>
+#  include <unistd.h>
+#endif // WIN32
+
+
+//
+// Local functions...
+//
+
+#if !defined(WIN32) && !defined(__APPLE__)
+static char	*path_find(const char *program, char *filename, int filesize);
+#endif // !WIN32 && !__APPLE__
+#ifndef WIN32
+static int	run_program(const char *program, char **argv, char *msg, int msglen);
+#endif // !WIN32
+
+/** \addtogroup filenames
+ @{ */
+
+/**
+ * Opens the specified Uniform Resource Identifier (URI).
+ * Uses an operating-system dependent program or interface. For URIs
+ * using the "ftp", "http", or "https" schemes, the system default web
+ * browser is used to open the URI, while "mailto" and "news" URIs are
+ * typically opened using the system default mail reader and "file" URIs
+ * are opened using the file system navigator.
+ *
+ * On success, the (optional) msg buffer is filled with the command that
+ * was run to open the URI; on Windows, this will always be "open uri".
+ *
+ * On failure, the msg buffer is filled with an English error message.
+ *
+ * \b Example
+ * \code
+ * #include <FL/filename.H>
+ * [..]
+ * char errmsg[512];
+ * if ( !fl_open_uri("http://google.com/", errmsg, sizeof(errmsg)) ) {
+ *     char warnmsg[768];
+ *     sprintf(warnmsg, "Error: %s", errmsg);
+ *     fl_alert(warnmsg);
+ * }
+ * \endcode
+ *
+ * @param uri The URI to open
+ * @param msg Optional buffer which contains the command or error message
+ * @param msglen Length of optional buffer
+ * @return 1 on success, 0 on failure
+ */
+
+int
+fl_open_uri(const char *uri, char *msg, int msglen) {
+  // Supported URI schemes...
+  static const char * const schemes[] = {
+    "file://",
+    "ftp://",
+    "http://",
+    "https://",
+    "mailto:",
+    "news://",
+    NULL
+  };
+
+  // Validate the URI scheme...
+  int i;
+  for (i = 0; schemes[i]; i ++)
+    if (!strncmp(uri, schemes[i], strlen(schemes[i])))
+      break;
+
+  if (!schemes[i]) {
+    if (msg) {
+      char scheme[255];
+      if (sscanf(uri, "%254[^:]", scheme) == 1) {
+        snprintf(msg, msglen, "URI scheme \"%s\" not supported.", scheme);
+      } else {
+        snprintf(msg, msglen, "Bad URI \"%s\"", uri);
+      }
+    }
+
+    return 0;
+  }
+
+#ifdef WIN32
+  if (msg) snprintf(msg, msglen, "open %s", uri);
+
+  return (int)(ShellExecute(HWND_DESKTOP, "open", uri, NULL, NULL, SW_SHOW) > (void *)32);
+
+#elif defined(__APPLE__)
+  char	*argv[3];			// Command-line arguments
+
+  argv[0] = (char*)"open";
+  argv[1] = (char*)uri;
+  argv[2] = (char*)0;
+
+  if (msg) snprintf(msg, msglen, "open %s", uri);
+
+  return run_program("/usr/bin/open", argv, msg, msglen) != 0;
+
+#else // !WIN32 && !__APPLE__
+  // Run any of several well-known commands to open the URI.
+  //
+  // We give preference to the Portland group's xdg-utils
+  // programs which run the user's preferred web browser, etc.
+  // based on the current desktop environment in use.  We fall
+  // back on older standards and then finally test popular programs
+  // until we find one we can use.
+  //
+  // Note that we specifically do not support the MAILER and
+  // BROWSER environment variables because we have no idea whether
+  // we need to run the listed commands in a terminal program.
+
+  char	command[FL_PATH_MAX],		// Command to run...
+	*argv[4],			// Command-line arguments
+	remote[1024];			// Remote-mode command...
+  const char * const *commands;		// Array of commands to check...
+  static const char * const browsers[] = {
+    "xdg-open", // Portland
+    "htmlview", // Freedesktop.org
+    "firefox",
+    "mozilla",
+    "netscape",
+    "konqueror", // KDE
+    "opera",
+    "hotjava", // Solaris
+    "mosaic",
+    NULL
+  };
+  static const char * const readers[] = {
+    "xdg-email", // Portland
+    "thunderbird",
+    "mozilla",
+    "netscape",
+    "evolution", // GNOME
+    "kmailservice", // KDE
+    NULL
+  };
+  static const char * const managers[] = {
+    "xdg-open", // Portland
+    "fm", // IRIX
+    "dtaction", // CDE
+    "nautilus", // GNOME
+    "konqueror", // KDE
+    NULL
+  };
+
+  // Figure out which commands to check for...
+  if (!strncmp(uri, "file://", 7)) commands = managers;
+  else if (!strncmp(uri, "mailto:", 7) ||
+           !strncmp(uri, "news:", 5)) commands = readers;
+  else commands = browsers;
+
+  // Find the command to run...
+  for (i = 0; commands[i]; i ++)
+    if (path_find(commands[i], command, sizeof(command))) break;
+
+  if (!commands[i]) {
+    if (msg) {
+      snprintf(msg, msglen, "No helper application found for \"%s\"", uri);
+    }
+
+    return 0;
+  }
+
+  // Handle command-specific arguments...
+  argv[0] = (char *)commands[i];
+
+  if (!strcmp(commands[i], "firefox") ||
+      !strcmp(commands[i], "mozilla") ||
+      !strcmp(commands[i], "netscape") ||
+      !strcmp(commands[i], "thunderbird")) {
+    // program -remote openURL(uri)
+    snprintf(remote, sizeof(remote), "openURL(%s)", uri);
+
+    argv[1] = (char *)"-remote";
+    argv[2] = remote;
+    argv[3] = 0;
+  } else if (!strcmp(commands[i], "dtaction")) {
+    // dtaction open uri
+    argv[1] = (char *)"open";
+    argv[2] = (char *)uri;
+    argv[3] = 0;
+  } else {
+    // program uri
+    argv[1] = (char *)uri;
+    argv[2] = 0;
+  }
+
+  if (msg) {
+    strlcpy(msg, argv[0], msglen);
+
+    for (i = 1; argv[i]; i ++) {
+      strlcat(msg, " ", msglen);
+      strlcat(msg, argv[i], msglen);
+    }
+  }
+
+  return run_program(command, argv, msg, msglen) != 0;
+#endif // WIN32
+}
+
+/**   @} */
+
+#if !defined(WIN32) && !defined(__APPLE__)
+// Find a program in the path...
+static char *path_find(const char *program, char *filename, int filesize) {
+  const char	*path;			// Search path
+  char		*ptr,			// Pointer into filename
+		*end;			// End of filename buffer
+
+
+  if ((path = getenv("PATH")) == NULL) path = "/bin:/usr/bin";
+
+  for (ptr = filename, end = filename + filesize - 1; *path; path ++) {
+    if (*path == ':') {
+      if (ptr > filename && ptr[-1] != '/' && ptr < end) *ptr++ = '/';
+
+      strlcpy(ptr, program, end - ptr + 1);
+
+      if (!access(filename, X_OK)) return filename;
+
+      ptr = filename;
+    } else if (ptr < end) *ptr++ = *path;
+  }
+
+  if (ptr > filename) {
+    if (ptr[-1] != '/' && ptr < end) *ptr++ = '/';
+
+    strlcpy(ptr, program, end - ptr + 1);
+
+    if (!access(filename, X_OK)) return filename;
+  }
+
+  return 0;
+}
+#endif // !WIN32 && !__APPLE__
+
+
+#ifndef WIN32
+// Run the specified program, returning 1 on success and 0 on failure
+static int
+run_program(const char *program, char **argv, char *msg, int msglen) {
+  pid_t	pid;				// Process ID of first child
+  int status;				// Exit status from first child
+  sigset_t set, oldset;			// Signal masks
+
+
+  // Block SIGCHLD while we run the program...
+  //
+  // Note that I only use the POSIX signal APIs, however older operating
+  // systems may either not support POSIX signals or have side effects.
+  // IRIX, for example, provides three separate and incompatible signal
+  // APIs, so it is possible that an application setting a signal handler
+  // via signal() or sigset() will not have its SIGCHLD signals blocked...
+
+  sigemptyset(&set);
+  sigaddset(&set, SIGCHLD);
+  sigprocmask(SIG_BLOCK, &set, &oldset);
+
+  // Create child processes that actually run the program for us...
+  if ((pid = fork()) == 0) {
+    // First child comes here, fork a second child and exit...
+    if (!fork()) {
+      // Second child comes here, redirect stdin/out/err to /dev/null...
+      close(0);
+      open("/dev/null", O_RDONLY);
+
+      close(1);
+      open("/dev/null", O_WRONLY);
+
+      close(2);
+      open("/dev/null", O_WRONLY);
+
+      // Detach from the current process group...
+      setsid();
+
+      // Run the program...
+      execv(program, argv);
+      _exit(0);
+    } else {
+      // First child gets here, exit immediately...
+      _exit(0);
+    }
+  } else if (pid < 0) {
+    // Restore signal handling...
+    sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+    // Return indicating failure...
+    return 0;
+  }
+
+  // Wait for the first child to exit...
+  while (waitpid(pid, &status, 0) < 0) {
+    if (errno != EINTR) {
+      // Someone else grabbed the child status...
+      if (msg) snprintf(msg, msglen, "waitpid(%ld) failed: %s", (long)pid,
+                        strerror(errno));
+
+      // Restore signal handling...
+      sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+      // Return indicating failure...
+      return 0;
+    }
+  }
+
+  // Restore signal handling...
+  sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+  // Return indicating success...
+  return 1;
+}
+#endif // !WIN32
+
+
+#ifdef TEST
+//
+// Test code...
+//
+
+// Open the URI on the command-line...
+int main(int argc, char **argv) {
+  char msg[1024];
+
+
+  if (argc != 2) {
+    puts("Usage: fl_open_uri URI");
+    return 1;
+  }
+
+  if (!fl_open_uri(argv[1], msg, sizeof(msg))) {
+    puts(msg);
+    return 1;
+  } else return 0;
+}
+#endif // TEST
+
+
+//
+// End of "$Id: fl_open_uri.cxx 8063 2010-12-19 21:20:10Z matt $".
+//