summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorManolo Gouy <Manolo>2014-06-07 12:01:59 +0000
committerManolo Gouy <Manolo>2014-06-07 12:01:59 +0000
commitbaebff2227400ef54a92638d297fc0c23a4bd521 (patch)
tree88b6efae852185634761c2503844385f4ac826f8 /src
parent460544455d9f449ce80abdab22e0244698444158 (diff)
STR #3088: make Fl_Native_File_Chooser use the standard GTK file dialog when available.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10186 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src')
-rw-r--r--src/Fl.cxx4
-rw-r--r--src/Fl_Native_File_Chooser_FLTK.cxx546
-rw-r--r--src/Fl_Native_File_Chooser_GTK.cxx700
3 files changed, 1003 insertions, 247 deletions
diff --git a/src/Fl.cxx b/src/Fl.cxx
index 9d64b95fb..c3b935987 100644
--- a/src/Fl.cxx
+++ b/src/Fl.cxx
@@ -2069,6 +2069,8 @@ bool Fl::option(Fl_Option opt)
options_[OPTION_DND_TEXT] = tmp;
opt_prefs.get("ShowTooltips", tmp, 1); // default: on
options_[OPTION_SHOW_TOOLTIPS] = tmp;
+ opt_prefs.get("FNFCUsesGTK", tmp, 1); // default: on
+ options_[OPTION_FNFC_USES_GTK] = tmp;
}
{ // next, check the user preferences
// override system options only, if the option is set ( >= 0 )
@@ -2086,6 +2088,8 @@ bool Fl::option(Fl_Option opt)
if (tmp >= 0) options_[OPTION_DND_TEXT] = tmp;
opt_prefs.get("ShowTooltips", tmp, -1);
if (tmp >= 0) options_[OPTION_SHOW_TOOLTIPS] = tmp;
+ opt_prefs.get("FNFCUsesGTK", tmp, -1);
+ if (tmp >= 0) options_[OPTION_FNFC_USES_GTK] = tmp;
}
{ // now, if the developer has registered this app, we could as for per-application preferences
}
diff --git a/src/Fl_Native_File_Chooser_FLTK.cxx b/src/Fl_Native_File_Chooser_FLTK.cxx
index 6c5f359b5..3fb62ad10 100644
--- a/src/Fl_Native_File_Chooser_FLTK.cxx
+++ b/src/Fl_Native_File_Chooser_FLTK.cxx
@@ -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-2014 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
@@ -25,24 +24,20 @@
#define FLTK_CHOOSER_CREATE Fl_File_Chooser::CREATE
#include "Fl_Native_File_Chooser_common.cxx"
+#include "Fl_Native_File_Chooser_GTK.cxx"
+
#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 +47,201 @@ Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) {
_prevvalue = NULL;
_directory = NULL;
_errmsg = NULL;
- _file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
- type(val); // do this after _file_chooser created
- _nfilters = 0;
-}
+#endif // FLTK_ABI_VERSION
+ if (have_looked_for_GTK_libs == 0) {
+ // First Time here, try to find the GTK libs if they are installed
+ if (Fl::option(Fl::OPTION_FNFC_USES_GTK)) {
+ 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 _x11_file_chooser = new Fl_FLTK_File_Chooser(val);
+}
/**
- Destructor.
- Deallocates any resources allocated to this widget.
-*/
+ 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
+ USE_FILTER_EXT Chooser filter pilots the output file extension. Ignored Used Ignored
+\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() const { 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_FLTK_File_Chooser::Fl_FLTK_File_Chooser(int val) {
+ _btype = 0;
+ _options = 0;
+ _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;
+}
+
+Fl_FLTK_File_Chooser::~Fl_FLTK_File_Chooser() {
delete _file_chooser;
+ _file_chooser = NULL;
_filter = strfree(_filter);
_parsedfilt = strfree(_parsedfilt);
_preset_file = strfree(_preset_file);
@@ -71,286 +250,169 @@ Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
_errmsg = strfree(_errmsg);
}
+
// PRIVATE: SET ERROR MESSAGE
-void Fl_Native_File_Chooser::errmsg(const char *msg) {
+void Fl_FLTK_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_FLTK_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_FLTK_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_FLTK_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
- USE_FILTER_EXT Chooser filter pilots the output file extension. Ignored Used Ignored
- \endcode
-*/
-void Fl_Native_File_Chooser::options(int val) {
+void Fl_FLTK_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_FLTK_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() {
- // FILTER
- if ( _parsedfilt ) {
- _file_chooser->filter(_parsedfilt);
- }
+int Fl_FLTK_File_Chooser::show() {
- // FILTER VALUE
- // Set this /after/ setting the filter
- //
- _file_chooser->filter_value(_filtvalue);
+ // FILTER
+ if ( _parsedfilt ) {
+ _file_chooser->filter(_parsedfilt);
+ }
- // DIRECTORY
- if ( _directory && _directory[0] ) {
- _file_chooser->directory(_directory);
- } else {
- _file_chooser->directory(_prevvalue);
- }
+ // FILTER VALUE
+ // Set this /after/ setting the filter
+ //
+ _file_chooser->filter_value(_filtvalue);
- // PRESET FILE
- if ( _preset_file ) {
- _file_chooser->value(_preset_file);
- }
+ // DIRECTORY
+ if ( _directory && _directory[0] ) {
+ _file_chooser->directory(_directory);
+ } else {
+ _file_chooser->directory(_prevvalue);
+ }
- // OPTIONS: PREVIEW
- _file_chooser->preview( (options() & PREVIEW) ? 1 : 0);
+ // PRESET FILE
+ if ( _preset_file ) {
+ _file_chooser->value(_preset_file);
+ }
- // OPTIONS: NEW FOLDER
- if ( options() & NEW_FOLDER )
- _file_chooser->type(_file_chooser->type() | FLTK_CHOOSER_CREATE); // on
+ // OPTIONS: PREVIEW
+ _file_chooser->preview( (options() & Fl_Native_File_Chooser::PREVIEW) ? 1 : 0);
- // SHOW
- _file_chooser->show();
+ // OPTIONS: NEW FOLDER
+ if ( options() & Fl_Native_File_Chooser::NEW_FOLDER )
+ _file_chooser->type(_file_chooser->type() | Fl_File_Chooser::CREATE); // on
+
+ // 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
-
- // 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);
- }
- }
+ 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() & 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_FLTK_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_FLTK_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_FLTK_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_FLTK_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_FLTK_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_FLTK_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_FLTK_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_FLTK_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_FLTK_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_FLTK_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_FLTK_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_FLTK_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_FLTK_File_Chooser::directory() const {
+ return _directory;
}
// PRIVATE: Convert our filter format to fltk's chooser format
@@ -363,7 +425,7 @@ const char *Fl_Native_File_Chooser::directory() const {
// 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_FLTK_File_Chooser::parse_filter() {
_parsedfilt = strfree(_parsedfilt); // clear previous parsed filter (if any)
_nfilters = 0;
char *in = _filter;
@@ -426,27 +488,17 @@ void Fl_Native_File_Chooser::parse_filter() {
//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_FLTK_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_FLTK_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_FLTK_File_Chooser::exist_dialog() {
+ return fl_choice("%s", fl_cancel, fl_ok, NULL, Fl_Native_File_Chooser::file_exists_message);
}
//
diff --git a/src/Fl_Native_File_Chooser_GTK.cxx b/src/Fl_Native_File_Chooser_GTK.cxx
new file mode 100644
index 000000000..6464198ea
--- /dev/null
+++ b/src/Fl_Native_File_Chooser_GTK.cxx
@@ -0,0 +1,700 @@
+// "$Id$"
+//
+// FLTK native file chooser widget wrapper for GTK's GtkFileChooserDialog
+//
+// Copyright 1998-2014 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 <FL/x.H>
+#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 _GdkDrawable GdkWindow;
+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_NONE = -1;
+const int GTK_RESPONSE_ACCEPT = -3;
+const int GTK_RESPONSE_DELETE_EVENT = -4;
+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;
+
+// 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_now(GtkWidget *);
+typedef void (*XX_gtk_widget_show_now)(GtkWidget *);
+static XX_gtk_widget_show_now fl_gtk_widget_show_now = NULL;
+
+// GdkWindow* gtk_widget_get_window(GtkWidget *);
+typedef GdkWindow* (*XX_gtk_widget_get_window)(GtkWidget *);
+static XX_gtk_widget_get_window fl_gtk_widget_get_window = NULL;
+
+// Window gdk_x11_drawable_get_xid(GdkWindow *);
+typedef Window (*XX_gdk_x11_drawable_get_xid)(GdkWindow *);
+static XX_gdk_x11_drawable_get_xid fl_gdk_x11_drawable_get_xid = 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_FLTK_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;
+ previous_filter = NULL;
+}
+
+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;
+}
+
+/* changes the extension of the outfile in the chooser according to newly selected filter */
+void Fl_GTK_File_Chooser::changed_output_type(const char *filter)
+{
+ if ( !(options()&Fl_Native_File_Chooser::USE_FILTER_EXT) ) return;
+ if (strchr(filter, '(') || strchr(filter, '{') || strchr(filter+1, '*') || strncmp(filter, "*.", 2)) return;
+ const char *p = fl_gtk_file_chooser_get_filename((GtkFileChooser*)gtkw_ptr);
+ if (!p) return;
+ p = fl_filename_name(p);
+ const char *q = strrchr(p, '.');
+ if (!q) q = p + strlen(p);
+ char *r = new char[strlen(p) + strlen(filter)];
+ strcpy(r, p);
+ strcpy(r + (q - p), filter + 1);
+ fl_gtk_file_chooser_set_current_name((GtkFileChooser*)gtkw_ptr, r);
+ delete[] r;
+}
+
+/* Filters files before display in chooser.
+ Also used to detect when the filter just changed */
+gboolean Fl_GTK_File_Chooser::custom_gtk_filter_function(const GtkFileFilterInfo *info, Fl_GTK_File_Chooser::pair* p)
+{
+ if (p->running->previous_filter != p->filter) {
+ p->running->changed_output_type(p->filter);
+ p->running->previous_filter = p->filter;
+ }
+ return (gboolean)fl_filename_match(info->filename, p->filter);
+}
+
+void Fl_GTK_File_Chooser::free_pair(Fl_GTK_File_Chooser::pair *p)
+{
+ delete p;
+}
+
+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);
+}
+
+int Fl_GTK_File_Chooser::show()
+{
+ // The point here is that after running a GTK dialog, the calling program's current locale is modified.
+ // To avoid that, we memorize the calling program's current locale, and the locale as modified
+ // by GTK after the first dialog use. We restore the calling program's current locale
+ // before returning, and we set the locale as modified by GTK before subsequent GTK dialog uses.
+ static bool first = true;
+ char *p;
+ char *before = NULL;
+ static char *gtk_wants = NULL;
+ // record in before the calling program's current locale
+ p = setlocale(LC_ALL, NULL);
+ if (p) before = strdup(p);
+ if (gtk_wants) { // set the locale as GTK 'wants it'
+ setlocale(LC_ALL, gtk_wants);
+ }
+ int retval = fl_gtk_chooser_wrapper(); // may change the locale
+ if (first) {
+ first = false;
+ // record in gtk_wants the locale as modified by the GTK dialog
+ p = setlocale(LC_ALL, NULL);
+ if (p) gtk_wants = strdup(p);
+ }
+ if (before) {
+ setlocale(LC_ALL, before); // restore calling program's current locale
+ free(before);
+ }
+ return retval;
+}
+
+
+static void run_response_handler(GtkDialog *dialog, gint response_id, gpointer data)
+{
+ gint *ri = (gint *)data;
+ *ri = response_id;
+}
+
+
+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, fl_filename_name(_preset_file));
+ /* FALLTHROUGH */
+ case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
+ fl_gtk_file_chooser_set_create_folders((GtkFileChooser *)gtkw_ptr, TRUE);
+ fl_gtk_file_chooser_set_do_overwrite_confirmation ((GtkFileChooser *)gtkw_ptr, (_options & Fl_Native_File_Chooser::SAVEAS_CONFIRM)?TRUE:FALSE);
+ 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,
+ (GtkFileFilterFunc)Fl_GTK_File_Chooser::custom_gtk_filter_function,
+ new Fl_GTK_File_Chooser::pair(this, p),
+ (GDestroyNotify)Fl_GTK_File_Chooser::free_pair);
+ 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]);
+ previous_filter = NULL;
+ 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_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_Window* firstw = Fl::first_window();
+ fl_gtk_widget_show_now(gtkw_ptr); // map the GTK window on screen
+ if (firstw) {
+ GdkWindow* gdkw = fl_gtk_widget_get_window(gtkw_ptr);
+ Window xw = fl_gdk_x11_drawable_get_xid(gdkw); // get the X11 ref of the GTK window
+ XSetTransientForHint(fl_display, xw, fl_xid(firstw)); // set the GTK window transient for the last FLTK win
+ }
+ gboolean state = fl_gtk_file_chooser_get_show_hidden((GtkFileChooser *)gtkw_ptr);
+ fl_gtk_toggle_button_set_active((GtkToggleButton *)toggle, state);
+
+ gint response_id = GTK_RESPONSE_NONE;
+ fl_g_signal_connect_data(gtkw_ptr, "response", G_CALLBACK(run_response_handler), &response_id, NULL, (GConnectFlags) 0);
+ while (response_id == GTK_RESPONSE_NONE) { // loop that shows the GTK dialog window
+ fl_gtk_main_iteration(); // one iteration of the GTK event loop
+ while (XEventsQueued(fl_display, QueuedAfterReading)) { // emulate modal dialog
+ XEvent xevent;
+ XNextEvent(fl_display, &xevent);
+ Window xid = xevent.xany.window;
+ if (xevent.type == ConfigureNotify) xid = xevent.xmaprequest.window;
+ if (!fl_find(xid)) continue; // skip events to non-FLTK windows
+ // process Expose and ConfigureNotify events
+ if ( xevent.type == Expose || xevent.type == ConfigureNotify ) fl_handle(xevent);
+ }
+ Fl::flush(); // do the drawings needed after Expose events
+ }
+
+ if (response_id == 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;
+ if ( response_id == GTK_RESPONSE_DELETE_EVENT) gtkw_ptr = NULL;
+ else 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 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
+ if (ptr_gtk && ptr_glib) {
+#ifdef DEBUG
+ puts("selected GTK-2\n");
+#endif
+ }
+ else {// Try then with GTK3
+ ptr_gtk = fl_dlopen("libgtk-3.so", "libgtk-3.so.0");
+#ifdef DEBUG
+ if (ptr_gtk && ptr_glib) {
+ puts("selected GTK-3\n");
+ }
+#endif
+ }
+
+ if((!ptr_glib) || (!ptr_gtk)) {
+#ifdef DEBUG
+ puts("Failure to load libglib or libgtk");
+#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_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_now, ptr_gtk);
+ GET_SYM(gtk_widget_get_window, ptr_gtk);
+ GET_SYM(gdk_x11_drawable_get_xid, 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$".
+//