Index: src/Fl_Native_File_Chooser_GTK.cxx
===================================================================
--- src/Fl_Native_File_Chooser_GTK.cxx	(revision 0)
+++ src/Fl_Native_File_Chooser_GTK.cxx	(revision 0)
@@ -0,0 +1,626 @@
+// "$Id: $"
+//
+// FLTK native file chooser widget wrapper for GTK's GtkFileChooserDialog 
+//
+// Copyright 1998-2013 by Bill Spitzak and others.
+// Copyright 2012 IMM
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file.  If this
+// file is missing or damaged, see the license at:
+//
+//     http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems to:
+//
+//     http://www.fltk.org/str.php
+//
+
+#  include <dlfcn.h>   // for dlopen et al
+#  include <locale.h>  // for setlocale
+
+/* --------------------- Type definitions from GLIB and GTK --------------------- */
+/* all of this is from the public gnome API, so unlikely to change */
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+typedef void* gpointer;
+typedef int    gint;
+typedef unsigned int    guint;
+typedef unsigned long   gulong;
+typedef gint   gboolean;
+typedef char   gchar;
+typedef struct _GSList GSList;
+struct _GSList
+{
+  gpointer data;
+  GSList *next;
+};
+#define  g_slist_next(slist)	         ((slist) ? (((GSList *)(slist))->next) : NULL)
+typedef struct _GtkWidget      GtkWidget;
+typedef struct _GtkFileChooser      GtkFileChooser;
+typedef struct _GtkDialog        GtkDialog;
+typedef struct _GtkWindow          GtkWindow;
+typedef struct _GtkFileFilter     GtkFileFilter;
+typedef struct _GtkToggleButton       GtkToggleButton;
+typedef enum {
+  GTK_FILE_FILTER_FILENAME     = 1 << 0,
+  GTK_FILE_FILTER_URI          = 1 << 1,
+  GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2,
+  GTK_FILE_FILTER_MIME_TYPE    = 1 << 3
+} GtkFileFilterFlags;
+struct _GtkFileFilterInfo
+{
+  GtkFileFilterFlags contains;
+  
+  const gchar *filename;
+  const gchar *uri;
+  const gchar *display_name;
+  const gchar *mime_type;
+};
+typedef struct _GtkFileFilterInfo GtkFileFilterInfo;
+typedef gboolean (*GtkFileFilterFunc) (const GtkFileFilterInfo *filter_info, gpointer data);
+typedef void (*GDestroyNotify)(gpointer data);
+typedef enum
+{
+  GTK_FILE_CHOOSER_ACTION_OPEN,
+  GTK_FILE_CHOOSER_ACTION_SAVE,
+  GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+  GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+} GtkFileChooserAction;
+#define GTK_STOCK_CANCEL           "gtk-cancel"
+#define GTK_STOCK_SAVE             "gtk-save"
+#define GTK_STOCK_OPEN             "gtk-open"
+const int   GTK_RESPONSE_ACCEPT = -3;
+const int   GTK_RESPONSE_CANCEL = -6;
+typedef void  (*GCallback)(void);
+#define	G_CALLBACK(f)			 ((GCallback) (f))
+typedef int GConnectFlags;
+typedef struct _GClosure		 GClosure;
+typedef void  (*GClosureNotify)(gpointer data, GClosure	*closure);
+
+/* --------------------- End of Type definitions from GLIB and GTK --------------------- */
+
+int Fl_GTK_File_Chooser::did_find_GTK_libs = 0;
+
+/* These are the GTK/GLib methods we want to load, but not call by name...! */
+
+// void g_free (gpointer mem);
+typedef void (*XX_g_free)(gpointer);
+static XX_g_free fl_g_free = NULL;
+
+// gpointer g_slist_nth_data (GSList *list, guint n);
+typedef gpointer (*XX_g_slist_nth_data) (GSList *, guint);
+static XX_g_slist_nth_data fl_g_slist_nth_data = NULL;
+
+// guint g_slist_length (GSList *list);
+typedef guint (*XX_g_slist_length) (GSList *);
+static XX_g_slist_length fl_g_slist_length = NULL;
+
+// void g_slist_free (GSList *list);
+typedef void (*XX_g_slist_free) (GSList *);
+static XX_g_slist_free fl_g_slist_free = NULL;
+
+// gboolean gtk_init_check (int *argc, char ***argv);
+typedef gboolean (*XX_gtk_init_check)(int *, char ***);
+static XX_gtk_init_check fl_gtk_init_check = NULL;
+
+// void gtk_widget_destroy (GtkWidget *widget);
+typedef void (*XX_gtk_widget_destroy) (GtkWidget *);
+static XX_gtk_widget_destroy fl_gtk_widget_destroy = NULL;
+
+// void gtk_file_chooser_set_select_multiple(GtkFileChooser *chooser, gboolean select_multiple);
+typedef void (*XX_gtk_file_chooser_set_select_multiple)(GtkFileChooser *, gboolean);
+static XX_gtk_file_chooser_set_select_multiple fl_gtk_file_chooser_set_select_multiple = NULL;
+
+// void gtk_file_chooser_set_do_overwrite_confirmation(GtkFileChooser *chooser, gboolean do_overwrite_confirmation);
+typedef void (*XX_gtk_file_chooser_set_do_overwrite_confirmation)(GtkFileChooser *, gboolean);
+static XX_gtk_file_chooser_set_do_overwrite_confirmation fl_gtk_file_chooser_set_do_overwrite_confirmation = NULL;
+
+// void gtk_file_chooser_set_current_name (GtkFileChooser *chooser, const gchar *name);
+typedef void (*XX_gtk_file_chooser_set_current_name)(GtkFileChooser *, const gchar *);
+static XX_gtk_file_chooser_set_current_name fl_gtk_file_chooser_set_current_name = NULL;
+
+// void gtk_file_chooser_set_current_folder (GtkFileChooser *chooser, const gchar *name);
+typedef void (*XX_gtk_file_chooser_set_current_folder)(GtkFileChooser *, const gchar *);
+static XX_gtk_file_chooser_set_current_folder fl_gtk_file_chooser_set_current_folder = NULL;
+
+// void gtk_file_chooser_set_create_folders (GtkFileChooser *chooser, gboolean create_folders);
+typedef void (*XX_gtk_file_chooser_set_create_folders) (GtkFileChooser *, gboolean);
+static XX_gtk_file_chooser_set_create_folders fl_gtk_file_chooser_set_create_folders = NULL;
+
+// gboolean gtk_file_chooser_get_select_multiple(GtkFileChooser *chooser);
+typedef gboolean (*XX_gtk_file_chooser_get_select_multiple)(GtkFileChooser *);
+static XX_gtk_file_chooser_get_select_multiple fl_gtk_file_chooser_get_select_multiple = NULL;
+
+// void gtk_widget_hide(GtkWidget *widget);
+typedef void (*XX_gtk_widget_hide)(GtkWidget *);
+static XX_gtk_widget_hide fl_gtk_widget_hide = NULL;
+
+// gint gtk_dialog_run(GtkDialog *dialog);
+typedef gint (*XX_gtk_dialog_run)(GtkDialog *dialog);
+static XX_gtk_dialog_run fl_gtk_dialog_run = NULL;
+
+// gchar * gtk_file_chooser_get_filename(GtkFileChooser *chooser);
+typedef gchar* (*XX_gtk_file_chooser_get_filename)(GtkFileChooser *);
+static XX_gtk_file_chooser_get_filename fl_gtk_file_chooser_get_filename = NULL;
+
+// GSList * gtk_file_chooser_get_filenames(GtkFileChooser *chooser);
+typedef GSList* (*XX_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser);
+static XX_gtk_file_chooser_get_filenames fl_gtk_file_chooser_get_filenames = NULL;
+
+// gboolean gtk_main_iteration(void);
+typedef gboolean (*XX_gtk_main_iteration)(void);
+static XX_gtk_main_iteration fl_gtk_main_iteration = NULL;
+
+// gboolean gtk_events_pending(void);
+typedef gboolean (*XX_gtk_events_pending)(void);
+static XX_gtk_events_pending fl_gtk_events_pending = NULL;
+
+// GtkWidget * gtk_file_chooser_dialog_new(const gchar *title, GtkWindow *parent, GtkFileChooserAction action, const gchar *first_button_text, ...);
+typedef GtkWidget* (*XX_gtk_file_chooser_dialog_new)(const gchar *, GtkWindow *, GtkFileChooserAction, const gchar *, ...);
+static XX_gtk_file_chooser_dialog_new fl_gtk_file_chooser_dialog_new = NULL;
+
+// void gtk_file_chooser_add_filter(GtkFileChooser*, GtkFileFilter*);
+typedef void (*XX_gtk_file_chooser_add_filter)(GtkFileChooser*, GtkFileFilter*);
+static XX_gtk_file_chooser_add_filter fl_gtk_file_chooser_add_filter = NULL;
+
+// GtkFileFilter* gtk_file_chooser_get_filter(GtkFileChooser*);
+typedef GtkFileFilter* (*XX_gtk_file_chooser_get_filter)(GtkFileChooser*);
+static XX_gtk_file_chooser_get_filter fl_gtk_file_chooser_get_filter = NULL;
+
+// void gtk_file_chooser_set_filter(GtkFileChooser*, GtkFileFilter*);
+typedef void (*XX_gtk_file_chooser_set_filter)(GtkFileChooser*, GtkFileFilter*);
+static XX_gtk_file_chooser_set_filter fl_gtk_file_chooser_set_filter = NULL;
+
+// GtkFileFilter * gtk_file_filter_new();
+typedef GtkFileFilter* (*XX_gtk_file_filter_new)(void);
+static XX_gtk_file_filter_new fl_gtk_file_filter_new = NULL;
+
+// void gtk_file_filter_add_pattern(GtkFileFilter*, const gchar*);
+typedef void (*XX_gtk_file_filter_add_pattern)(GtkFileFilter*, const gchar*);
+static XX_gtk_file_filter_add_pattern fl_gtk_file_filter_add_pattern = NULL;
+
+// void gtk_file_filter_add_custom(GtkFileFilter *filter, GtkFileFilterFlags needed,
+//  GtkFileFilterFunc func, gpointer data, GDestroyNotify notify);
+typedef void (*XX_gtk_file_filter_add_custom)(GtkFileFilter *filter, GtkFileFilterFlags needed,
+					      GtkFileFilterFunc func, gpointer data, 
+					      GDestroyNotify notify);
+static XX_gtk_file_filter_add_custom fl_gtk_file_filter_add_custom = NULL;
+
+// void gtk_file_filter_set_name(GtkFileFilter*, const gchar*);
+typedef void (*XX_gtk_file_filter_set_name)(GtkFileFilter*, const gchar*);
+static XX_gtk_file_filter_set_name fl_gtk_file_filter_set_name = NULL;
+
+// const gchar* gtk_file_filter_get_name(GtkFileFilter*);
+typedef const gchar* (*XX_gtk_file_filter_get_name)(GtkFileFilter*);
+static XX_gtk_file_filter_get_name fl_gtk_file_filter_get_name = NULL;
+
+// void gtk_file_chooser_set_extra_widget(GtkFileChooser *, GtkWidget *);
+typedef void (*XX_gtk_file_chooser_set_extra_widget)(GtkFileChooser *, GtkWidget *);
+static XX_gtk_file_chooser_set_extra_widget fl_gtk_file_chooser_set_extra_widget = NULL;
+
+// void gtk_widget_show(GtkWidget *);
+typedef void (*XX_gtk_widget_show)(GtkWidget *);
+static XX_gtk_widget_show fl_gtk_widget_show = NULL;
+
+// GtkWidget *gtk_check_button_new_with_label(const gchar *);
+typedef GtkWidget* (*XX_gtk_check_button_new_with_label)(const gchar *);
+static XX_gtk_check_button_new_with_label fl_gtk_check_button_new_with_label = NULL;
+
+// gulong g_signal_connect_data(gpointer, const gchar *, GCallback, gpointer, GClosureNotify, GConnectFlags);
+typedef gulong (*XX_g_signal_connect_data)(gpointer, const gchar *, GCallback, gpointer, GClosureNotify, GConnectFlags);
+static XX_g_signal_connect_data fl_g_signal_connect_data = NULL;
+
+// gboolean gtk_toggle_button_get_active(GtkToggleButton *);
+typedef gboolean (*XX_gtk_toggle_button_get_active)(GtkToggleButton*);
+static XX_gtk_toggle_button_get_active fl_gtk_toggle_button_get_active = NULL;
+
+// void gtk_file_chooser_set_show_hidden(GtkFileChooser *, gboolean);
+typedef void (*XX_gtk_file_chooser_set_show_hidden)(GtkFileChooser *, gboolean);
+static XX_gtk_file_chooser_set_show_hidden fl_gtk_file_chooser_set_show_hidden = NULL;
+
+// gboolean gtk_file_chooser_get_show_hidden(GtkFileChooser *);
+typedef gboolean (*XX_gtk_file_chooser_get_show_hidden)(GtkFileChooser *);
+static XX_gtk_file_chooser_get_show_hidden fl_gtk_file_chooser_get_show_hidden = NULL;
+
+// void gtk_toggle_button_set_active(GtkToggleButton *, gboolean);
+typedef void (*XX_gtk_toggle_button_set_active)(GtkToggleButton *, gboolean);
+static XX_gtk_toggle_button_set_active fl_gtk_toggle_button_set_active = NULL;
+
+
+Fl_GTK_File_Chooser::Fl_GTK_File_Chooser(int val) : Fl_X11_File_Chooser(-1)
+{
+  gtkw_ptr   = NULL;    // used to hold a GtkWidget* 
+  gtkw_slist = NULL;    // will hold the returned file names in a multi-selection...
+  gtkw_count = 0;       // How many items were selected?
+  gtkw_filename = NULL; // holds the last name we read back in a single file selection...
+  gtkw_title = NULL;    // dialog title
+  _btype = val;
+}
+
+Fl_GTK_File_Chooser::~Fl_GTK_File_Chooser()
+{
+  // Should free up resources taken for...
+  if(gtkw_ptr) { 
+    fl_gtk_widget_destroy (gtkw_ptr);
+    gtkw_ptr = NULL;
+  }
+  if(gtkw_filename) {
+    fl_g_free(gtkw_filename);
+    gtkw_filename = NULL;
+  }
+  if(gtkw_slist) {
+    GSList *iter = (GSList *)gtkw_slist;
+    while(iter) {
+      if(iter->data) fl_g_free(iter->data);
+      iter = g_slist_next(iter);
+    }
+    fl_g_slist_free((GSList *)gtkw_slist);
+    gtkw_slist = NULL;
+  }
+  gtkw_count = 0; // assume we have no files selected now
+  gtkw_title = strfree(gtkw_title);
+}
+
+void Fl_GTK_File_Chooser::type(int val) {
+  _btype = val;
+}
+
+int Fl_GTK_File_Chooser::count() const {
+  return gtkw_count;
+}
+
+const char *Fl_GTK_File_Chooser::filename() const
+{
+  if(gtkw_ptr) {
+    if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtkw_ptr) == FALSE) {
+      return gtkw_filename;
+    }
+    else {
+      GSList *iter = (GSList *)gtkw_slist;
+      char *nm = (char *)iter->data;
+      return nm;
+    }
+  }
+  return("");
+}
+
+const char *Fl_GTK_File_Chooser::filename(int i) const
+{
+  if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtkw_ptr) == FALSE) {
+    return gtkw_filename;
+  }
+  else {
+    if ((unsigned)i < gtkw_count) {
+      GSList *iter = (GSList *)gtkw_slist;
+      char *nm = (char *)fl_g_slist_nth_data(iter, i);
+      return nm;
+    }
+  }
+  return("");
+}
+
+void Fl_GTK_File_Chooser::title(const char *val)
+{
+  strfree(gtkw_title);
+  gtkw_title = strnew(val);
+}
+
+const char* Fl_GTK_File_Chooser::title() const
+{
+  return gtkw_title;
+}
+
+static gboolean fl_custom_gtk_filter_function(const GtkFileFilterInfo *info, gpointer data)
+{
+  return (gboolean)fl_filename_match(info->filename, (const char*)data);
+}
+
+static void hidden_files_cb(GtkToggleButton *togglebutton, gpointer user_data)
+{
+  gboolean state = fl_gtk_toggle_button_get_active(togglebutton);
+  fl_gtk_file_chooser_set_show_hidden((GtkFileChooser*)user_data, state);
+}
+
+static const char *extract_filename(const char *in)
+{
+  const char *p = strrchr(in, '/');
+  return p ? p + 1 : in;
+}
+
+int Fl_GTK_File_Chooser::show()
+{
+  char *p, **before = new char*[20];
+  int val;
+  for (val = 0; val < 20; val++) { // memorize the state of all components of the current locale
+    if (val == LC_ALL) continue;
+    p = setlocale(val, NULL);
+    if (!p) break;
+    before[val] = strdup(p);
+  }
+  int retval = fl_gtk_chooser_wrapper(); // may change the locale
+  for (int i = 0; i < val; i++) { // set all components of the locale to their previous state
+    if (i == LC_ALL) continue;
+    if (before[i]) {
+      setlocale(i, before[i]);
+      free(before[i]);
+    }
+  }
+  delete[] before;
+  return retval;
+}
+
+int Fl_GTK_File_Chooser::fl_gtk_chooser_wrapper()
+{
+  int result = 1;
+  static int have_gtk_init = 0;
+  if(!have_gtk_init) {
+    have_gtk_init = -1;
+    int ac = 0;
+    fl_gtk_init_check(&ac, NULL);
+  }
+  
+  if(gtkw_ptr) { // discard the previous dialog widget
+    fl_gtk_widget_destroy (gtkw_ptr);
+    gtkw_ptr = NULL;
+  }
+  
+  // set the dialog action type
+  GtkFileChooserAction gtw_action_type;
+  switch (_btype) {
+    case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
+    case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY:
+      gtw_action_type = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+      break;
+      
+    case Fl_Native_File_Chooser::BROWSE_SAVE_FILE:
+      gtw_action_type = GTK_FILE_CHOOSER_ACTION_SAVE;
+      break;
+      
+    case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
+      gtw_action_type = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
+      break;
+      
+    case Fl_Native_File_Chooser::BROWSE_MULTI_FILE:
+    case Fl_Native_File_Chooser::BROWSE_FILE:
+    default:
+      gtw_action_type = GTK_FILE_CHOOSER_ACTION_OPEN;
+      break;
+  }
+  // create a new dialog
+  gtkw_ptr = fl_gtk_file_chooser_dialog_new (gtkw_title,
+					     NULL, /* parent_window */
+					     gtw_action_type,
+					     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+					     gtw_action_type == GTK_FILE_CHOOSER_ACTION_SAVE || gtw_action_type == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER ? 
+					     GTK_STOCK_SAVE : GTK_STOCK_OPEN, 
+					     GTK_RESPONSE_ACCEPT,
+					     NULL);
+  // did we create a valid dialog widget?
+  if(!gtkw_ptr) {
+    // fail
+    return -1;
+  }
+  
+  // set the dialog properties
+  switch (_btype) {
+    case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY:
+    case Fl_Native_File_Chooser::BROWSE_MULTI_FILE:
+      fl_gtk_file_chooser_set_select_multiple((GtkFileChooser *)gtkw_ptr, TRUE);
+      break;
+      
+    case Fl_Native_File_Chooser::BROWSE_SAVE_FILE:
+      if (_preset_file)fl_gtk_file_chooser_set_current_name ((GtkFileChooser *)gtkw_ptr, extract_filename(_preset_file));
+      /* FALLTHROUGH */
+    case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
+      fl_gtk_file_chooser_set_create_folders((GtkFileChooser *)gtkw_ptr, _options & Fl_Native_File_Chooser::NEW_FOLDER);
+      fl_gtk_file_chooser_set_do_overwrite_confirmation ((GtkFileChooser *)gtkw_ptr, _options & Fl_Native_File_Chooser::SAVEAS_CONFIRM);
+      break;
+      
+    case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
+    case Fl_Native_File_Chooser::BROWSE_FILE:
+    default:
+      break;
+  }
+  
+  if (_directory && _directory[0]) fl_gtk_file_chooser_set_current_folder((GtkFileChooser *)gtkw_ptr, _directory);
+  
+  GtkFileFilter **filter_tab = NULL;
+  if (_parsedfilt) {
+    filter_tab = new GtkFileFilter*[_nfilters];
+    char *filter = strdup(_parsedfilt);
+    char *p = strtok(filter, "\t");
+    int count = 0;
+    while (p) {
+      filter_tab[count] = fl_gtk_file_filter_new();
+      fl_gtk_file_filter_set_name(filter_tab[count], p);
+      p = strchr(p, '(') + 1;
+      char *q = strchr(p, ')'); *q = 0;      
+      fl_gtk_file_filter_add_custom(filter_tab[count], GTK_FILE_FILTER_FILENAME, 
+				    fl_custom_gtk_filter_function, strdup(p), free);
+      fl_gtk_file_chooser_add_filter((GtkFileChooser *)gtkw_ptr, filter_tab[count]);
+      p = strtok(NULL, "\t");
+      count++;
+    }
+    free(filter);
+    fl_gtk_file_chooser_set_filter((GtkFileChooser *)gtkw_ptr, filter_tab[_filtvalue]);
+    if (gtw_action_type == GTK_FILE_CHOOSER_ACTION_OPEN) {
+      GtkFileFilter* gfilter = fl_gtk_file_filter_new();
+      fl_gtk_file_filter_set_name(gfilter, Fl_File_Chooser::all_files_label);
+      fl_gtk_file_filter_add_pattern(gfilter, "*");
+      fl_gtk_file_chooser_add_filter((GtkFileChooser *)gtkw_ptr, gfilter);
+    }
+  }
+  
+  GtkWidget *toggle = fl_gtk_check_button_new_with_label(Fl_File_Chooser::hidden_label);
+  fl_gtk_widget_show(toggle);
+  fl_gtk_file_chooser_set_extra_widget((GtkFileChooser *)gtkw_ptr, toggle);
+  fl_g_signal_connect_data(toggle, "toggled", G_CALLBACK(hidden_files_cb), gtkw_ptr, NULL, (GConnectFlags) 0);
+  fl_gtk_widget_show(gtkw_ptr);
+  gboolean state = fl_gtk_file_chooser_get_show_hidden((GtkFileChooser *)gtkw_ptr);
+  fl_gtk_toggle_button_set_active((GtkToggleButton *)toggle, state);
+  
+  if (fl_gtk_dialog_run ((GtkDialog *)gtkw_ptr) == GTK_RESPONSE_ACCEPT) {
+    if (_parsedfilt) {
+      GtkFileFilter *gfilter = fl_gtk_file_chooser_get_filter((GtkFileChooser *)gtkw_ptr);
+      for (_filtvalue = 0; _filtvalue < _nfilters; _filtvalue++) {
+	if (filter_tab[_filtvalue] == gfilter) break;
+      }
+    }
+    
+    // discard any filenames or lists from previous calls
+    if(gtkw_filename) {
+      fl_g_free(gtkw_filename);
+      gtkw_filename = NULL;
+    }
+    if(gtkw_slist) {
+      GSList *iter = (GSList *)gtkw_slist;
+      while(iter) {
+        if(iter->data) fl_g_free(iter->data);
+        iter = g_slist_next(iter);
+      }
+      fl_g_slist_free((GSList *)gtkw_slist);
+      gtkw_slist = NULL;
+    }
+    gtkw_count = 0; // assume we have no files selected now
+    
+    if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtkw_ptr) == FALSE) {
+      gtkw_filename = fl_gtk_file_chooser_get_filename ((GtkFileChooser *)gtkw_ptr);
+      if (gtkw_filename) {
+        gtkw_count = 1;
+        result = 0;
+        //printf("single: %s\n", gtkw_filename);
+      }
+    }
+    else {
+      gtkw_slist = fl_gtk_file_chooser_get_filenames((GtkFileChooser *)gtkw_ptr);
+      gtkw_count = fl_g_slist_length((GSList *)gtkw_slist);
+      if(gtkw_count) result = 0;
+      
+      //      puts("multiple");
+      //      GSList *iter = (GSList *)gtkw_slist;
+      //      printf ("Selected %d files\n", gtkw_count);
+      //      while(iter) {
+      //        char *nm = (char *)iter->data;
+      //        printf("%s\n", nm);
+      //        iter = g_slist_next(iter);
+      //      }
+    }
+  }
+  delete[] filter_tab;
+  fl_gtk_widget_hide (gtkw_ptr);
+  
+  // I think this is analogus to doing an Fl::check() - we need this here to make sure
+  // the GtkFileChooserDialog is removed from the display correctly
+  while (fl_gtk_events_pending ()) fl_gtk_main_iteration (); 
+  
+  return result;
+} // fl_gtk_chooser_wrapper
+
+// macro to help with the symbol loading boilerplate...
+#define GET_SYM(SSS, LLL) \
+dlerror();    /* Clear any existing error */  \
+fl_##SSS = (XX_##SSS)dlsym(LLL, #SSS);        \
+if ((pc_dl_error = dlerror()) != NULL)  {     \
+fprintf(stderr, "%s\n", pc_dl_error);       \
+did_find_GTK_libs = 0;                      \
+return; }
+
+static void* fl_dlopen(const char *filename1, const char *filename2)
+{
+  void *ptr = dlopen(filename1, RTLD_LAZY | RTLD_GLOBAL);
+  if (!ptr) ptr = dlopen(filename2, RTLD_LAZY | RTLD_GLOBAL);
+  return ptr;
+}
+
+/* 
+ * Use dlopen to see if we can load the gtk dynamic libraries that
+ * will allow us to create a GtkFileChooserDialog() on the fly,
+ * without linking to the GTK libs at compile time.
+ */
+void Fl_GTK_File_Chooser::probe_for_GTK_libs(void) {
+  void *ptr_glib    = NULL;
+  void *ptr_gtk     = NULL;
+  
+#   ifdef __APPLE_CC__ // allows testing on Darwin + X11
+  ptr_glib    = dlopen("/sw/lib/libglib-2.0.dylib", RTLD_LAZY | RTLD_GLOBAL);
+#   else
+  ptr_glib    = fl_dlopen("libglib-2.0.so", "libglib-2.0.so.0");
+#   endif
+  // Try first with GTK3
+  ptr_gtk     = fl_dlopen("libgtk-3.so", "libgtk-3.so.0");
+  if (ptr_gtk && ptr_glib) {
+#ifdef DEBUG
+    puts("selected GTK-3\n");
+#endif
+  }
+  else {// Try then with GTK2
+#   ifdef __APPLE_CC__ // allows testing on Darwin + X11
+    ptr_gtk     = dlopen("/sw/lib/libgtk-x11-2.0.dylib", RTLD_LAZY | RTLD_GLOBAL);
+#else
+    ptr_gtk     = fl_dlopen("libgtk-x11-2.0.so", "libgtk-x11-2.0.so.0");
+#endif
+#ifdef DEBUG
+    if (ptr_gtk && ptr_glib) {
+      puts("selected GTK-2\n");
+    }
+#endif
+  }
+  
+  if((!ptr_glib) || (!ptr_gtk)) {
+#ifdef DEBUG
+    puts("Failure to load");
+#endif
+    did_find_GTK_libs = 0;
+    return;
+  }
+  
+  char *pc_dl_error; // used to report errors by the GET_SYM macro...
+  // items we need from GLib
+  GET_SYM(g_free, ptr_glib);
+  GET_SYM(g_slist_nth_data, ptr_glib);
+  GET_SYM(g_slist_length, ptr_glib);
+  GET_SYM(g_slist_free, ptr_glib);
+  // items we need from GTK
+  GET_SYM(gtk_init_check, ptr_gtk);
+  GET_SYM(gtk_widget_destroy, ptr_gtk);
+  GET_SYM(gtk_file_chooser_set_select_multiple, ptr_gtk);
+  GET_SYM(gtk_file_chooser_set_do_overwrite_confirmation, ptr_gtk);
+  GET_SYM(gtk_file_chooser_set_current_name, ptr_gtk);
+  GET_SYM(gtk_file_chooser_set_current_folder, ptr_gtk);
+  GET_SYM(gtk_file_chooser_set_create_folders, ptr_gtk);
+  GET_SYM(gtk_file_chooser_get_select_multiple, ptr_gtk);
+  GET_SYM(gtk_widget_hide, ptr_gtk);
+  GET_SYM(gtk_dialog_run, ptr_gtk);
+  GET_SYM(gtk_file_chooser_get_filename, ptr_gtk);
+  GET_SYM(gtk_file_chooser_get_filenames, ptr_gtk);
+  GET_SYM(gtk_main_iteration, ptr_gtk);
+  GET_SYM(gtk_events_pending, ptr_gtk);
+  GET_SYM(gtk_file_chooser_dialog_new, ptr_gtk);
+  GET_SYM(gtk_file_chooser_add_filter, ptr_gtk);
+  GET_SYM(gtk_file_chooser_get_filter, ptr_gtk);
+  GET_SYM(gtk_file_chooser_set_filter, ptr_gtk);
+  GET_SYM(gtk_file_filter_new, ptr_gtk);
+  GET_SYM(gtk_file_filter_add_pattern, ptr_gtk);
+  GET_SYM(gtk_file_filter_add_custom, ptr_gtk);
+  GET_SYM(gtk_file_filter_set_name, ptr_gtk);
+  GET_SYM(gtk_file_filter_get_name, ptr_gtk);
+  GET_SYM(gtk_file_chooser_set_extra_widget, ptr_gtk);
+  GET_SYM(gtk_widget_show, ptr_gtk);
+  GET_SYM(gtk_check_button_new_with_label, ptr_gtk);
+  GET_SYM(g_signal_connect_data, ptr_gtk);
+  GET_SYM(gtk_toggle_button_get_active, ptr_gtk);
+  GET_SYM(gtk_file_chooser_set_show_hidden, ptr_gtk);
+  GET_SYM(gtk_file_chooser_get_show_hidden, ptr_gtk);
+  GET_SYM(gtk_toggle_button_set_active, ptr_gtk);
+  
+  did_find_GTK_libs = 1;
+} // probe_for_GTK_libs
+
+//
+// End of "$Id: $".
+//
Index: src/Fl_Native_File_Chooser_FLTK.cxx
===================================================================
--- src/Fl_Native_File_Chooser_FLTK.cxx	(revision 9824)
+++ src/Fl_Native_File_Chooser_FLTK.cxx	(working copy)
@@ -1,10 +1,9 @@
 // "$Id$"
 //
-// FLTK native OS file chooser widget
+// FLTK native file chooser widget wrapper for GTK's GtkFileChooserDialog 
 //
-// Copyright 1998-2010 by Bill Spitzak and others.
-// Copyright 2004 Greg Ercolano.
-// API changes + filter improvements by Nathan Vander Wilt 2005
+// Copyright 1998-2013 by Bill Spitzak and others.
+// Copyright 2012 IMM
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
@@ -19,30 +18,25 @@
 
 #include <FL/Fl_Native_File_Chooser.H>
 #include <FL/Fl_File_Icon.H>
-#define FLTK_CHOOSER_SINGLE    Fl_File_Chooser::SINGLE
-#define FLTK_CHOOSER_DIRECTORY Fl_File_Chooser::DIRECTORY
-#define FLTK_CHOOSER_MULTI     Fl_File_Chooser::MULTI
-#define FLTK_CHOOSER_CREATE    Fl_File_Chooser::CREATE
 
 #include "Fl_Native_File_Chooser_common.cxx"
+#ifdef USE_GTK_FILE_CHOOSER
+#  include "Fl_Native_File_Chooser_GTK.cxx"
+#endif
+
 #include <sys/stat.h>
 #include <string.h>
 
+
+int Fl_Native_File_Chooser::have_looked_for_GTK_libs = 0;
+
 /**
-  The constructor. Internally allocates the native widgets.
-  Optional \p val presets the type of browser this will be, 
-  which can also be changed with type().
-*/
+ The constructor. Internally allocates the native widgets.
+ Optional \p val presets the type of browser this will be, 
+ which can also be changed with type().
+ */
 Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) {
-  //// CANT USE THIS -- MESSES UP LINKING/CREATES DEPENDENCY ON fltk_images.
-  //// Have app call this from main() instead.
-  ////
-  ////  static int init = 0;		// 'first time' initialize flag
-  ////  if ( init == 0 ) {
-  ////    // Initialize when instanced for first time
-  ////    Fl_File_Icon::load_system_icons();
-  ////    init = 1;
-  ////  }
+#if FLTK_ABI_VERSION <= 10302
   _btype       = val;
   _options     = NO_OPTIONS;
   _filter      = NULL;
@@ -52,17 +46,202 @@
   _prevvalue   = NULL;
   _directory   = NULL;
   _errmsg      = NULL;
-  _file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
-  type(val);			// do this after _file_chooser created
+#endif // FLTK_ABI_VERSION
+#ifdef USE_GTK_FILE_CHOOSER
+  if(have_looked_for_GTK_libs == 0) {
+    // First Time here, try to find the GTK libs if they are installed
+    Fl_GTK_File_Chooser::probe_for_GTK_libs();
+    have_looked_for_GTK_libs = -1;
+  }
+  
+  // if we found all the GTK functions we need, we will use the GtkFileChooserDialog
+  if (Fl_GTK_File_Chooser::did_find_GTK_libs) _gtk_file_chooser = new Fl_GTK_File_Chooser(val);
+  else 
+#endif // USE_GTK_FILE_CHOOSER
+    _x11_file_chooser = new Fl_X11_File_Chooser(val);
+}
+
+/**
+ Destructor. 
+ Deallocates any resources allocated to this widget.
+ */
+Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
+  delete _x11_file_chooser;
+}
+
+/**
+ Sets the current Fl_Native_File_Chooser::Type of browser.
+ */
+void Fl_Native_File_Chooser::type(int t) { return _x11_file_chooser->type(t); }
+/**
+ Gets the current Fl_Native_File_Chooser::Type of browser.
+ */
+int Fl_Native_File_Chooser::type() const { return _x11_file_chooser->type(); }
+/**
+ Sets the platform specific chooser options to \p val.
+ \p val is expected to be one or more Fl_Native_File_Chooser::Option flags ORed together.
+ Some platforms have OS-specific functions that can be enabled/disabled via this method.
+ <P>
+ \code
+ Flag              Description                                       Win       Mac       Other
+ --------------    -----------------------------------------------   -------   -------   -------
+ NEW_FOLDER        Shows the 'New Folder' button.                    Ignored   Used      Used
+ PREVIEW           Enables the 'Preview' mode by default.            Ignored   Ignored   Used
+ SAVEAS_CONFIRM    Confirm dialog if BROWSE_SAVE_FILE file exists.   Used      Used      Used
+ \endcode
+ */
+void Fl_Native_File_Chooser::options(int o) {  _x11_file_chooser->options(o); }
+/**
+ Gets the platform specific Fl_Native_File_Chooser::Option flags.
+ */
+int Fl_Native_File_Chooser::options() {  return _x11_file_chooser->options(); }
+
+/**
+ Returns the number of filenames (or directory names) the user selected.
+ <P>
+ \b Example:
+ \code
+ if ( fnfc->show() == 0 ) {
+ // Print all filenames user selected
+ for (int n=0; n<fnfc->count(); n++ ) {
+ printf("%d) '%s'\n", n, fnfc->filename(n));
+ }
+ }
+ \endcode
+ */
+int Fl_Native_File_Chooser::count() const { return _x11_file_chooser->count(); }
+/**
+ Return the filename the user chose.
+ Use this if only expecting a single filename.
+ If more than one filename is expected, use filename(int) instead.
+ Return value may be "" if no filename was chosen (eg. user cancelled).
+ */
+const char *Fl_Native_File_Chooser::filename() const { return _x11_file_chooser->filename(); }
+/**
+ Return one of the filenames the user selected.
+ Use count() to determine how many filenames the user selected.
+ <P>
+ \b Example:
+ \code
+ if ( fnfc->show() == 0 ) {
+ // Print all filenames user selected
+ for (int n=0; n<fnfc->count(); n++ ) {
+ printf("%d) '%s'\n", n, fnfc->filename(n));
+ }
+ }
+ \endcode
+ */
+const char *Fl_Native_File_Chooser::filename(int i) const { return _x11_file_chooser->filename(i); }
+/**
+ Preset the directory the browser will show when opened.
+ If \p val is NULL, or no directory is specified, the chooser will attempt
+ to use the last non-cancelled folder.
+ */
+void Fl_Native_File_Chooser::directory(const char *val) {  _x11_file_chooser->directory(val); }
+/**
+ Returns the current preset directory() value.
+ */
+const char *Fl_Native_File_Chooser::directory() const { return _x11_file_chooser->directory(); }
+/**
+ Set the title of the file chooser's dialog window.
+ Can be NULL if no title desired.
+ The default title varies according to the platform, so you are advised to set the title explicitly.
+ */
+void Fl_Native_File_Chooser::title(const char *t) {  _x11_file_chooser->title(t); }
+/**
+ Get the title of the file chooser's dialog window.
+ Return value may be NULL if no title was set.
+ */
+const char* Fl_Native_File_Chooser::title() const { return _x11_file_chooser->title(); }
+/**
+ Returns the filter string last set.
+ Can be NULL if no filter was set.
+ */
+const char *Fl_Native_File_Chooser::filter() const { return _x11_file_chooser->filter(); }
+/**
+ Sets the filename filters used for browsing. 
+ The default is NULL, which browses all files.
+ <P>
+ The filter string can be any of:
+ <P>
+ - A single wildcard (eg. "*.txt")
+ - Multiple wildcards (eg. "*.{cxx,h,H}")
+ - A descriptive name followed by a "\t" and a wildcard (eg. "Text Files\t*.txt")
+ - A list of separate wildcards with a "\n" between each (eg. "*.{cxx,H}\n*.txt")
+ - A list of descriptive names and wildcards (eg. "C++ Files\t*.{cxx,H}\nTxt Files\t*.txt")
+ <P>
+ The format of each filter is a wildcard, or an optional user description 
+ followed by '\\t' and the wildcard.
+ <P>
+ On most platforms, each filter is available to the user via a pulldown menu 
+ in the file chooser. The 'All Files' option is always available to the user. 
+ */
+void Fl_Native_File_Chooser::filter(const char *f) {  _x11_file_chooser->filter(f); }
+/**
+ Gets how many filters were available, not including "All Files" 
+ */
+int Fl_Native_File_Chooser::filters() const { return _x11_file_chooser->filters(); }
+/**
+ Sets which filter will be initially selected.
+ 
+ The first filter is indexed as 0. 
+ If filter_value()==filters(), then "All Files" was chosen. 
+ If filter_value() > filters(), then a custom filter was set.
+ */
+void Fl_Native_File_Chooser::filter_value(int i) {  _x11_file_chooser->filter_value(i); }
+/**
+ Returns which filter value was last selected by the user.
+ This is only valid if the chooser returns success.
+ */
+int Fl_Native_File_Chooser::filter_value() const { return _x11_file_chooser->filter_value(); }
+/**
+ Sets the default filename for the chooser.
+ Use directory() to set the default directory.
+ Mainly used to preset the filename for save dialogs, 
+ and on most platforms can be used for opening files as well. 
+ */
+void Fl_Native_File_Chooser::preset_file(const char* f) {  _x11_file_chooser->preset_file(f); }
+/**
+ Get the preset filename.
+ */
+const char* Fl_Native_File_Chooser::preset_file() const { return _x11_file_chooser->preset_file(); }
+/**
+ Returns a system dependent error message for the last method that failed. 
+ This message should at least be flagged to the user in a dialog box, or to some kind of error log. 
+ Contents will be valid only for methods that document errmsg() will have info on failures.
+ */
+const char *Fl_Native_File_Chooser::errmsg() const { return _x11_file_chooser->errmsg(); }
+/**
+ Post the chooser's dialog. Blocks until dialog has been completed or cancelled.
+ \returns
+ - 0  -- user picked a file
+ - 1  -- user cancelled
+ - -1 -- failed; errmsg() has reason
+ */
+int Fl_Native_File_Chooser::show() { return _x11_file_chooser->show(); }
+
+
+Fl_X11_File_Chooser::Fl_X11_File_Chooser(int val) {
+  _btype       = 0;
+  _options     = Fl_Native_File_Chooser::NEW_FOLDER;
+  _filter      = NULL;
+  _filtvalue   = 0;
+  _parsedfilt  = NULL;
+  _preset_file = NULL;
+  _prevvalue   = NULL;
+  _directory   = NULL;
+  _errmsg      = NULL;
+  _file_chooser= NULL;
+  if (val >= 0) {
+    _file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
+    type(val);			// do this after _file_chooser created
+    }
   _nfilters    = 0;
 } 
 
-/**
-  Destructor. 
-  Deallocates any resources allocated to this widget.
-*/
-Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
+Fl_X11_File_Chooser::~Fl_X11_File_Chooser() {
   delete _file_chooser;
+  _file_chooser = NULL;
   _filter      = strfree(_filter);
   _parsedfilt  = strfree(_parsedfilt);
   _preset_file = strfree(_preset_file);
@@ -71,285 +250,171 @@
   _errmsg      = strfree(_errmsg);
 }
 
+
 // PRIVATE: SET ERROR MESSAGE
-void Fl_Native_File_Chooser::errmsg(const char *msg) {
+void Fl_X11_File_Chooser::errmsg(const char *msg) {
   _errmsg = strfree(_errmsg);
   _errmsg = strnew(msg);
 }
 
 // PRIVATE: translate Native types to Fl_File_Chooser types
-int Fl_Native_File_Chooser::type_fl_file(int val) {
+int Fl_X11_File_Chooser::type_fl_file(int val) {
   switch (val) {
-    case BROWSE_FILE:
-      return(FLTK_CHOOSER_SINGLE);
-    case BROWSE_DIRECTORY:
-      return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_DIRECTORY);
-    case BROWSE_MULTI_FILE:
-      return(FLTK_CHOOSER_MULTI);
-    case BROWSE_MULTI_DIRECTORY:
-      return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI);
-    case BROWSE_SAVE_FILE:
-      return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_CREATE);
-    case BROWSE_SAVE_DIRECTORY:
-      return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI | FLTK_CHOOSER_CREATE);
+    case Fl_Native_File_Chooser::BROWSE_FILE:
+      return(Fl_File_Chooser::SINGLE);
+    case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
+      return(Fl_File_Chooser::SINGLE | Fl_File_Chooser::DIRECTORY);
+    case Fl_Native_File_Chooser::BROWSE_MULTI_FILE:
+      return(Fl_File_Chooser::MULTI);
+    case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY:
+      return(Fl_File_Chooser::DIRECTORY | Fl_File_Chooser::MULTI);
+    case Fl_Native_File_Chooser::BROWSE_SAVE_FILE:
+      return(Fl_File_Chooser::SINGLE | Fl_File_Chooser::CREATE);
+    case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
+      return(Fl_File_Chooser::DIRECTORY | Fl_File_Chooser::MULTI | Fl_File_Chooser::CREATE);
     default:
-      return(FLTK_CHOOSER_SINGLE);
+      return(Fl_File_Chooser::SINGLE);
   }
 }
 
-/**
-  Sets the current Fl_Native_File_Chooser::Type of browser.
- */
-void Fl_Native_File_Chooser::type(int val) {
+void Fl_X11_File_Chooser::type(int val) {
   _btype = val;
   _file_chooser->type(type_fl_file(val));
 }
 
-/**
-  Gets the current Fl_Native_File_Chooser::Type of browser.
- */
-int Fl_Native_File_Chooser::type() const {
+int Fl_X11_File_Chooser::type() const {
   return(_btype);
 }
 
-/**
-  Sets the platform specific chooser options to \p val.
-  \p val is expected to be one or more Fl_Native_File_Chooser::Option flags ORed together.
-  Some platforms have OS-specific functions that can be enabled/disabled via this method.
-  <P>
-  \code
-  Flag              Description                                       Win       Mac       Other
-  --------------    -----------------------------------------------   -------   -------   -------
-  NEW_FOLDER        Shows the 'New Folder' button.                    Ignored   Used      Used
-  PREVIEW           Enables the 'Preview' mode by default.            Ignored   Ignored   Used
-  SAVEAS_CONFIRM    Confirm dialog if BROWSE_SAVE_FILE file exists.   Used      Used      Used
-  \endcode
-*/
-void Fl_Native_File_Chooser::options(int val) {
+void Fl_X11_File_Chooser::options(int val) {
   _options = val;
 }
 
-/**
-  Gets the platform specific Fl_Native_File_Chooser::Option flags.
-*/
-int Fl_Native_File_Chooser::options() const {
+int Fl_X11_File_Chooser::options() const {
   return(_options);
 }
 
-/**
-  Post the chooser's dialog. Blocks until dialog has been completed or cancelled.
-  \returns
-     - 0  -- user picked a file
-     - 1  -- user cancelled
-     - -1 -- failed; errmsg() has reason
-*/
-int Fl_Native_File_Chooser::show() {
+int Fl_X11_File_Chooser::show() {
+
   // FILTER
-  if ( _parsedfilt ) {
-    _file_chooser->filter(_parsedfilt);
-  }
+    if ( _parsedfilt ) {
+      _file_chooser->filter(_parsedfilt);
+    }
 
-  // FILTER VALUE
-  //     Set this /after/ setting the filter
-  //
-  _file_chooser->filter_value(_filtvalue);
+    // FILTER VALUE
+    //     Set this /after/ setting the filter
+    //
+    _file_chooser->filter_value(_filtvalue);
 
-  // DIRECTORY
-  if ( _directory && _directory[0] ) {
-    _file_chooser->directory(_directory);
-  } else {
-    _file_chooser->directory(_prevvalue);
-  }
+    // DIRECTORY
+    if ( _directory && _directory[0] ) {
+      _file_chooser->directory(_directory);
+    } else {
+      _file_chooser->directory(_prevvalue);
+    }
 
-  // PRESET FILE
-  if ( _preset_file ) {
-    _file_chooser->value(_preset_file);
-  }
+    // PRESET FILE
+    if ( _preset_file ) {
+      _file_chooser->value(_preset_file);
+    }
 
-  // OPTIONS: PREVIEW
-  _file_chooser->preview( (options() & PREVIEW) ? 1 : 0);
+    // OPTIONS: PREVIEW
+    _file_chooser->preview( (options() & Fl_Native_File_Chooser::PREVIEW) ? 1 : 0);
 
-  // OPTIONS: NEW FOLDER
-  if ( options() & NEW_FOLDER )
-    _file_chooser->type(_file_chooser->type() | FLTK_CHOOSER_CREATE);	// on
+    // OPTIONS: NEW FOLDER
+    if ((_file_chooser->type() & (Fl_Native_File_Chooser::BROWSE_SAVE_FILE | 
+				  Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY)) && !(options() & 
+							  Fl_Native_File_Chooser::NEW_FOLDER) )
+      _file_chooser->newButton->hide();
+  
+    // SHOW
+    _file_chooser->show();
 
-  // SHOW
-  _file_chooser->show();
+    // BLOCK WHILE BROWSER SHOWN
+    while ( _file_chooser->shown() ) {
+      Fl::wait();
+    }
 
-  // BLOCK WHILE BROWSER SHOWN
-  while ( _file_chooser->shown() ) {
-    Fl::wait();
-  }
+    if ( _file_chooser->value() && _file_chooser->value()[0] ) {
+      _prevvalue = strfree(_prevvalue);
+      _prevvalue = strnew(_file_chooser->value());
+      _filtvalue = _file_chooser->filter_value(); // update filter value
 
-  if ( _file_chooser->value() && _file_chooser->value()[0] ) {
-    _prevvalue = strfree(_prevvalue);
-    _prevvalue = strnew(_file_chooser->value());
-    _filtvalue = _file_chooser->filter_value();	// update filter value
-
-    // HANDLE SHOWING 'SaveAs' CONFIRM
-    if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
-      struct stat buf;
-      if ( stat(_file_chooser->value(), &buf) != -1 ) {
-	if ( buf.st_mode & S_IFREG ) {		// Regular file + exists?
-	  if ( exist_dialog() == 0 ) {
-	    return(1);
-	  }
-	}
+      // HANDLE SHOWING 'SaveAs' CONFIRM
+      if ( options() & Fl_Native_File_Chooser::SAVEAS_CONFIRM && type() == Fl_Native_File_Chooser::BROWSE_SAVE_FILE ) {
+        struct stat buf;
+        if ( stat(_file_chooser->value(), &buf) != -1 ) {
+          if ( buf.st_mode & S_IFREG ) {    // Regular file + exists?
+            if ( exist_dialog() == 0 ) {
+              return(1);
+            }
+          }
+        }
       }
     }
-  }
 
-  if ( _file_chooser->count() ) return(0);
-  else return(1);
+    if ( _file_chooser->count() ) return(0);
+    else return(1);
 }
 
-/**
-  Returns a system dependent error message for the last method that failed. 
-  This message should at least be flagged to the user in a dialog box, or to some kind of error log. 
-  Contents will be valid only for methods that document errmsg() will have info on failures.
- */
-const char *Fl_Native_File_Chooser::errmsg() const {
+const char *Fl_X11_File_Chooser::errmsg() const {
   return(_errmsg ? _errmsg : "No error");
 }
 
-/**
-  Return the filename the user choose.
-  Use this if only expecting a single filename.
-  If more than one filename is expected, use filename(int) instead.
-  Return value may be "" if no filename was chosen (eg. user cancelled).
- */
-const char* Fl_Native_File_Chooser::filename() const {
-  if ( _file_chooser->count() > 0 ) return(_file_chooser->value());
+const char* Fl_X11_File_Chooser::filename() const {
+  if ( _file_chooser->count() > 0 ) {
+    return(_file_chooser->value());
+  }
   return("");
 }
 
-/**
-  Return one of the filenames the user selected.
-  Use count() to determine how many filenames the user selected.
-  <P>
-  \b Example:
-  \code
-  if ( fnfc->show() == 0 ) {
-    // Print all filenames user selected
-    for (int n=0; n<fnfc->count(); n++ ) {
-      printf("%d) '%s'\n", n, fnfc->filename(n));
-    }
-  }
-  \endcode
- */
-const char* Fl_Native_File_Chooser::filename(int i) const {
-  if ( i < _file_chooser->count() )
-    return(_file_chooser->value(i+1));	// convert fltk 1 based to our 0 based
+const char* Fl_X11_File_Chooser::filename(int i) const {
+    if ( i < _file_chooser->count() )
+        return(_file_chooser->value(i+1));  // convert fltk 1 based to our 0 based
   return("");
 }
 
-/**
-  Set the title of the file chooser's dialog window.
-  Can be NULL if no title desired.
-  The default title varies according to the platform, so you are advised to set the title explicitly.
-*/
-void Fl_Native_File_Chooser::title(const char *val) {
+void Fl_X11_File_Chooser::title(const char *val) {
   _file_chooser->label(val);
 }
 
-/**
-  Get the title of the file chooser's dialog window.
-  Return value may be NULL if no title was set.
-*/
-const char *Fl_Native_File_Chooser::title() const {
-  return(_file_chooser->label());
+const char *Fl_X11_File_Chooser::title() const {
+    return(_file_chooser->label());
 }
 
-/**
-  Sets the filename filters used for browsing. 
-  The default is NULL, which browses all files.
-  <P>
-  The filter string can be any of:
-  <P>
-    - A single wildcard (eg. "*.txt")
-    - Multiple wildcards (eg. "*.{cxx,h,H}")
-    - A descriptive name followed by a "\t" and a wildcard (eg. "Text Files\t*.txt")
-    - A list of separate wildcards with a "\n" between each (eg. "*.{cxx,H}\n*.txt")
-    - A list of descriptive names and wildcards (eg. "C++ Files\t*.{cxx,H}\nTxt Files\t*.txt")
-  <P>
-  The format of each filter is a wildcard, or an optional user description 
-  followed by '\\t' and the wildcard.
-  <P>
-  On most platforms, each filter is available to the user via a pulldown menu 
-  in the file chooser. The 'All Files' option is always available to the user. 
-*/
-void Fl_Native_File_Chooser::filter(const char *val) {
+void Fl_X11_File_Chooser::filter(const char *val) {
   _filter = strfree(_filter);
   _filter = strnew(val);
   parse_filter();
 }
 
-/**
-  Returns the filter string last set.
-  Can be NULL if no filter was set.
- */
-const char *Fl_Native_File_Chooser::filter() const {
+const char *Fl_X11_File_Chooser::filter() const {
   return(_filter);
 }
 
-/**
-Gets how many filters were available, not including "All Files" 
-*/
-int Fl_Native_File_Chooser::filters() const {
+int Fl_X11_File_Chooser::filters() const {
   return(_nfilters);
 }
 
-/**
-  Sets which filter will be initially selected.
-
-  The first filter is indexed as 0. 
-  If filter_value()==filters(), then "All Files" was chosen. 
-  If filter_value() > filters(), then a custom filter was set.
- */
-void Fl_Native_File_Chooser::filter_value(int val) {
+void Fl_X11_File_Chooser::filter_value(int val) {
   _filtvalue = val;
 }
 
-/**
-  Returns which filter value was last selected by the user.
-  This is only valid if the chooser returns success.
- */
-int Fl_Native_File_Chooser::filter_value() const {
-  return(_filtvalue);
+int Fl_X11_File_Chooser::filter_value() const {
+  return _filtvalue;
 }
 
-/**
-  Returns the number of filenames (or directory names) the user selected.
-  <P>
-  \b Example:
-  \code
-  if ( fnfc->show() == 0 ) {
-    // Print all filenames user selected
-    for (int n=0; n<fnfc->count(); n++ ) {
-      printf("%d) '%s'\n", n, fnfc->filename(n));
-    }
-  }
-  \endcode
-*/
-int Fl_Native_File_Chooser::count() const {
-  return(_file_chooser->count());
+int Fl_X11_File_Chooser::count() const {
+  return _file_chooser->count();
 }
 
-/**
-  Preset the directory the browser will show when opened.
-  If \p val is NULL, or no directory is specified, the chooser will attempt
-  to use the last non-cancelled folder.
-*/
-void Fl_Native_File_Chooser::directory(const char *val) {
+void Fl_X11_File_Chooser::directory(const char *val) {
   _directory = strfree(_directory);
   _directory = strnew(val);
 }
 
-/**
-  Returns the current preset directory() value.
-*/
-const char *Fl_Native_File_Chooser::directory() const {
-  return(_directory);
+const char *Fl_X11_File_Chooser::directory() const {
+  return _directory;
 }
 
 // PRIVATE: Convert our filter format to fltk's chooser format
@@ -362,7 +427,7 @@
 //     Returns a modified version of the filter that the caller is responsible
 //     for freeing with strfree().
 //
-void Fl_Native_File_Chooser::parse_filter() {
+void Fl_X11_File_Chooser::parse_filter() {
   _parsedfilt = strfree(_parsedfilt);	// clear previous parsed filter (if any)
   _nfilters = 0;
   char *in = _filter;
@@ -425,27 +490,17 @@
   //NOTREACHED
 }
 
-/**
-  Sets the default filename for the chooser.
-  Use directory() to set the default directory.
-  Mainly used to preset the filename for save dialogs, 
-  and on most platforms can be used for opening files as well. 
- */
-void Fl_Native_File_Chooser::preset_file(const char* val) {
+void Fl_X11_File_Chooser::preset_file(const char* val) {
   _preset_file = strfree(_preset_file);
   _preset_file = strnew(val);
 }
 
-/**
-  Get the preset filename.
-  */
-const char* Fl_Native_File_Chooser::preset_file() const {
-  return(_preset_file);
+const char* Fl_X11_File_Chooser::preset_file() const {
+  return _preset_file;
 }
 
-
-int Fl_Native_File_Chooser::exist_dialog() {
-  return(fl_choice("%s", fl_cancel, fl_ok, NULL, file_exists_message));
+int Fl_X11_File_Chooser::exist_dialog() {
+  return fl_choice("%s", fl_cancel, fl_ok, NULL, Fl_Native_File_Chooser::file_exists_message);
 }
 
 //
Index: FL/Fl_Native_File_Chooser.H
===================================================================
--- FL/Fl_Native_File_Chooser.H	(revision 9824)
+++ FL/Fl_Native_File_Chooser.H	(working copy)
@@ -23,32 +23,32 @@
 #ifndef FL_NATIVE_FILE_CHOOSER_H
 #define FL_NATIVE_FILE_CHOOSER_H
 
-/* \file
- Fl_Native_File_Chooser widget. */
+#define USE_GTK_FILE_CHOOSER 1 /* forces use of GTK file chooser when available */
 
 // Use Windows' chooser
 #ifdef WIN32
 // #define _WIN32_WINNT	0x0501	// needed for OPENFILENAME's 'FlagsEx'
-#include <stdio.h>
-#include <stdlib.h>		// malloc
-#include <windows.h>
-#include <commdlg.h>		// OPENFILENAME, GetOpenFileName()
-#include <shlobj.h>		// BROWSEINFO, SHBrowseForFolder()
+#  include <stdio.h>
+#  include <stdlib.h>		// malloc
+#  include <windows.h>
+#  include <commdlg.h>		// OPENFILENAME, GetOpenFileName()
+#  include <shlobj.h>		// BROWSEINFO, SHBrowseForFolder()
 #endif
 
 // Use Apple's chooser
 #ifdef __APPLE__
-#define MAXFILTERS	80
+#  define MAXFILTERS	80
 #endif
 
 // All else falls back to FLTK's own chooser
 #if ! defined(__APPLE__) && !defined(WIN32)
-#include <FL/Fl_File_Chooser.H>
-#include <unistd.h>		// _POSIX_NAME_MAX
+#  include <FL/Fl_File_Chooser.H>
 #else
-#include <FL/filename.H>	// FL_EXPORT
+#  include <FL/filename.H>	// FL_EXPORT
 #endif
 
+class Fl_X11_File_Chooser;
+class Fl_GTK_File_Chooser;
 
 /**
  This class lets an FLTK application easily and consistently access 
@@ -126,26 +126,26 @@
   ~Fl_Native_File_Chooser();
   
   // Public methods
-  void type(int);
-  int type() const;
-  void options(int);
-  int options() const;
+  void type(int t);
+  int type() const ;
+  void options(int o);
+  int options();
   int count() const;
-  const char *filename() const;
-  const char *filename(int i) const;
-  void directory(const char *val);
+  const char *filename() const ;
+  const char *filename(int i) const ;
+  void directory(const char *val) ;
   const char *directory() const;
-  void title(const char *);
+  void title(const char *t);
   const char* title() const;
-  const char *filter() const;
-  void filter(const char *);
-  int filters() const;
-  void filter_value(int i);
-  int filter_value() const;
-  void preset_file(const char*);
+  const char *filter() const ;
+  void filter(const char *f);
+  int filters() const ;
+  void filter_value(int i) ;
+  int filter_value() const ;
+  void preset_file(const char*f) ;
   const char* preset_file() const;
-  const char *errmsg() const;
-  int show();
+  const char *errmsg() const ;
+  int show() ;
   
 #ifdef WIN32
 private:
@@ -196,10 +196,10 @@
   char           *_preset_file;	        // the 'save as' filename
   
   char           *_filter;		// user-side search filter, eg:
-					// C Files\t*.[ch]\nText Files\t*.txt"
+  // C Files\t*.[ch]\nText Files\t*.txt"
   
   char           *_filt_names;		// filter names (tab delimited)
-					// eg. "C Files\tText Files"
+  // eg. "C Files\tText Files"
   
   char           *_filt_patt[MAXFILTERS];
   // array of filter patterns, eg:
@@ -224,6 +224,7 @@
 
 #if ! defined(__APPLE__) && !defined(WIN32)
 private:
+#if FLTK_ABI_VERSION <= 10302
   int   _btype;			// kind-of browser to show()
   int   _options;		// general options
   int   _nfilters;
@@ -234,17 +235,83 @@
   char *_prevvalue;		// Returned filename
   char *_directory;
   char *_errmsg;		// error message
-  Fl_File_Chooser *_file_chooser;
-  
-  // Private methods
+#endif
+  static int have_looked_for_GTK_libs;
+  union {
+    Fl_X11_File_Chooser *_x11_file_chooser;
+    Fl_GTK_File_Chooser *_gtk_file_chooser;
+  };
+#endif
+};
+
+#if !defined(__APPLE__) && !defined(WIN32)
+class Fl_X11_File_Chooser {
+  friend class Fl_Native_File_Chooser;
+protected:
+  int   _btype;			// kind-of browser to show()
+  int   _options;		// general options
+  int   _nfilters;
+  char *_filter;		// user supplied filter
+  char *_parsedfilt;		// parsed filter
+  int   _filtvalue;		// selected filter
+  char *_preset_file;
+  char *_prevvalue;		// Returned filename
+  char *_directory;
+  char *_errmsg;		// error message
+  Fl_X11_File_Chooser(int val);
+  virtual ~Fl_X11_File_Chooser();
   void errmsg(const char *msg);
   int type_fl_file(int);
   void parse_filter();
-  void keeplocation();
   int exist_dialog();
-#endif
+  Fl_File_Chooser *_file_chooser;
+  virtual void type(int);
+  int type() const;
+  void options(int);
+  int options() const;
+  virtual int count() const;
+  virtual const char *filename() const;
+  virtual const char *filename(int i) const;
+  void directory(const char *val);
+  const char *directory() const;
+  virtual void title(const char *);
+  virtual const char* title() const;
+  const char *filter() const;
+  void filter(const char *);
+  int filters() const;
+  void filter_value(int i);
+  int filter_value() const;
+  void preset_file(const char*);
+  const char* preset_file() const;
+  const char *errmsg() const;
+  virtual int show();
 };
 
+#ifdef USE_GTK_FILE_CHOOSER
+class Fl_GTK_File_Chooser : public Fl_X11_File_Chooser {
+  friend class Fl_Native_File_Chooser;
+private:
+  typedef struct _GtkWidget GtkWidget;
+  GtkWidget *gtkw_ptr; // used to hold a GtkWidget* without pulling GTK into everything...
+  void *gtkw_slist; // used to hold a GLib GSList...
+  unsigned gtkw_count; // number of files read back - if any
+  mutable char *gtkw_filename; // last name we read back
+  char *gtkw_title; // the title to be applied to the dialog
+  int fl_gtk_chooser_wrapper(); // method that wraps the GTK widget
+  Fl_GTK_File_Chooser(int val);
+  virtual ~Fl_GTK_File_Chooser();
+  static int did_find_GTK_libs;
+  static void probe_for_GTK_libs(void);
+  virtual void type(int);
+  virtual int count() const;
+  virtual const char *filename() const;
+  virtual const char *filename(int i) const;
+  virtual void title(const char *);
+  virtual const char* title() const;
+  virtual int show();
+};
+#endif // USE_GTK_FILE_CHOOSER
+#endif // !defined(__APPLE__) && !defined(WIN32)
 
 #endif /*FL_NATIVE_FILE_CHOOSER_H*/
 
Index: test/native-filechooser.cxx
===================================================================
--- test/native-filechooser.cxx	(revision 9824)
+++ test/native-filechooser.cxx	(working copy)
@@ -3,7 +3,7 @@
 //
 // Simple test of the Fl_Native_File_Chooser.
 //
-// Copyright 1998-2010 by Bill Spitzak and others.
+// Copyright 1998-2013 by Bill Spitzak and others.
 // Copyright 2004 Greg Ercolano.
 //
 // This library is free software. Distribution and use rights are outlined in
@@ -28,14 +28,68 @@
 // GLOBALS
 Fl_Input *G_filename = NULL;
 
-void Butt_CB(Fl_Widget*, void*) {
+void Butt_CB(Fl_Widget* butt, void*) {
   // Create native chooser
+  static int test_mode = 0;
   Fl_Native_File_Chooser native;
-  native.title("Pick a file");
-  native.type(Fl_Native_File_Chooser::BROWSE_FILE);
+
+  native.options(Fl_Native_File_Chooser::NO_OPTIONS);
+
+  switch(test_mode) {
+    default:
+    case 0:
+      native.title("Open Single file");
+      native.type(Fl_Native_File_Chooser::BROWSE_FILE);
+      break;
+
+    case 1:
+      native.title("Open Single Directory");
+      native.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY);
+      break;
+
+    case 2:
+      native.title("BROWSE_MULTI_FILE");
+      native.type(Fl_Native_File_Chooser::BROWSE_MULTI_FILE);
+      break;
+
+    case 3:
+      native.title("BROWSE_MULTI_DIRECTORY");
+      native.type(Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY);
+      break;
+
+    case 4:
+      native.title("BROWSE_SAVE_FILE");
+      native.options(Fl_Native_File_Chooser::NEW_FOLDER);
+      native.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
+      break;
+
+    case 5:
+      native.title("BROWSE_SAVE_FILE - warn overwrite");
+      native.options(Fl_Native_File_Chooser::NEW_FOLDER | Fl_Native_File_Chooser::SAVEAS_CONFIRM);
+      native.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
+      break;
+
+    case 6:
+      native.title("BROWSE_SAVE_DIRECTORY");
+      native.options(Fl_Native_File_Chooser::NEW_FOLDER);
+      native.type(Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY);
+      break;
+
+    case 7:
+      native.title("BROWSE_SAVE_DIRECTORY - warn overwrite");
+      native.options(Fl_Native_File_Chooser::NEW_FOLDER | Fl_Native_File_Chooser::SAVEAS_CONFIRM);
+      native.type(Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY);
+      break;
+
+  }
+  test_mode ++;
+  if(test_mode > 7) test_mode = 0;
+  
+  butt->label("Pick File again");
+
   native.filter("Text\t*.txt\n"
                 "C Files\t*.{cxx,h,c}\n"
-                "Apps\t*.{app}\n");		// TODO: need to add kNavSupportPackages to non-cocoa <FNFC>_MAC.cxx
+                "PDF\t*.{pdf}\n");
   native.preset_file(G_filename->value());
   // Show native chooser
   switch ( native.show() ) {
@@ -49,6 +103,14 @@
       }
       break;
   }
+
+  int items_selected = native.count();
+  if(items_selected) {
+    printf("\nRead %d items\n", items_selected);
+    for(int idx = 0; idx < items_selected; idx++) {
+        puts(native.filename(idx));
+    }
+  }
 }
 
 int main(int argc, char **argv) {
@@ -78,7 +140,7 @@
     G_filename->value(argc <= argn ? "." : argv[argn]);
     G_filename->tooltip("Default filename");
     y += G_filename->h() + 5;
-    Fl_Button *but = new Fl_Button(win->w()-80-10, win->h()-25-10, 80, 25, "Pick File");
+    Fl_Button *but = new Fl_Button(win->w()-110-10, win->h()-25-10, 110, 25, "Pick File");
     but->callback(Butt_CB);
     Fl_Box *dummy = new Fl_Box(80, 0, 430, 100);
     dummy->hide();
