FLTK 1.3.9: Fl_Native_File_Chooser_GTK.cxx Source File

FLTK 1.3.9

Loading...
Searching...
No Matches
Fl_Native_File_Chooser_GTK.cxx
1// "$Id$"
2//
3// FLTK native file chooser widget wrapper for GTK's GtkFileChooserDialog
4//
5// Copyright 1998-2014 by Bill Spitzak and others.
6// Copyright 2012 IMM
7//
8// This library is free software. Distribution and use rights are outlined in
9// the file "COPYING" which should have been included with this file. If this
10// file is missing or damaged, see the license at:
11//
12// http://www.fltk.org/COPYING.php
13//
14// Please report all bugs and problems to:
15//
16// http://www.fltk.org/str.php
17//
18
19#include <FL/x.H>
20#if HAVE_DLSYM && HAVE_DLFCN_H
21#include <dlfcn.h> // for dlopen et al
22#endif
23#include <locale.h> // for setlocale
24
25/* --------------------- Type definitions from GLIB and GTK --------------------- */
26/* all of this is from the public gnome API, so unlikely to change */
27#ifndef FALSE
28#define FALSE (0)
29#endif
30#ifndef TRUE
31#define TRUE (!FALSE)
32#endif
33typedef void* gpointer;
34typedef int gint;
35typedef unsigned int guint;
36typedef unsigned long gulong;
37typedef gint gboolean;
38typedef char gchar;
39typedef struct _GSList GSList;
40struct _GSList
41{
42 gpointer data;
43 GSList *next;
44};
45#define g_slist_next(slist) ((slist) ? (((GSList *)(slist))->next) : NULL)
46typedef struct _GtkWidget GtkWidget;
47typedef struct _GtkFileChooser GtkFileChooser;
48typedef struct _GtkDialog GtkDialog;
49typedef struct _GtkWindow GtkWindow;
50typedef struct _GdkDrawable GdkWindow;
51typedef struct _GtkFileFilter GtkFileFilter;
52typedef struct _GtkToggleButton GtkToggleButton;
53typedef enum {
54 GTK_FILE_FILTER_FILENAME = 1 << 0,
55 GTK_FILE_FILTER_URI = 1 << 1,
56 GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2,
57 GTK_FILE_FILTER_MIME_TYPE = 1 << 3
58} GtkFileFilterFlags;
59struct _GtkFileFilterInfo
60{
61 GtkFileFilterFlags contains;
62
63 const gchar *filename;
64 const gchar *uri;
65 const gchar *display_name;
66 const gchar *mime_type;
67};
68typedef struct _GtkFileFilterInfo GtkFileFilterInfo;
69typedef gboolean (*GtkFileFilterFunc) (const GtkFileFilterInfo *filter_info, gpointer data);
70typedef void (*GDestroyNotify)(gpointer data);
71typedef enum
72{
73 GTK_FILE_CHOOSER_ACTION_OPEN,
74 GTK_FILE_CHOOSER_ACTION_SAVE,
75 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
76 GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
77} GtkFileChooserAction;
78#define GTK_STOCK_CANCEL "gtk-cancel"
79#define GTK_STOCK_SAVE "gtk-save"
80#define GTK_STOCK_OPEN "gtk-open"
81const int GTK_RESPONSE_NONE = -1;
82const int GTK_RESPONSE_ACCEPT = -3;
83const int GTK_RESPONSE_DELETE_EVENT = -4;
84const int GTK_RESPONSE_CANCEL = -6;
85typedef void (*GCallback)(void);
86#define G_CALLBACK(f) ((GCallback) (f))
87typedef int GConnectFlags;
88typedef struct _GClosure GClosure;
89typedef void (*GClosureNotify)(gpointer data, GClosure *closure);
90
91/* --------------------- End of Type definitions from GLIB and GTK --------------------- */
92
93int Fl_GTK_File_Chooser::did_find_GTK_libs = 0;
94
95/* These are the GTK/GLib methods we want to load, but not call by name...! */
96
97// void g_free (gpointer mem);
98typedef void (*XX_g_free)(gpointer);
99static XX_g_free fl_g_free = NULL;
100
101// gpointer g_slist_nth_data (GSList *list, guint n);
102typedef gpointer (*XX_g_slist_nth_data) (GSList *, guint);
103static XX_g_slist_nth_data fl_g_slist_nth_data = NULL;
104
105// guint g_slist_length (GSList *list);
106typedef guint (*XX_g_slist_length) (GSList *);
107static XX_g_slist_length fl_g_slist_length = NULL;
108
109// void g_slist_free (GSList *list);
110typedef void (*XX_g_slist_free) (GSList *);
111static XX_g_slist_free fl_g_slist_free = NULL;
112
113// gboolean gtk_init_check (int *argc, char ***argv);
114typedef gboolean (*XX_gtk_init_check)(int *, char ***);
115static XX_gtk_init_check fl_gtk_init_check = NULL;
116
117// void gtk_widget_destroy (GtkWidget *widget);
118typedef void (*XX_gtk_widget_destroy) (GtkWidget *);
119static XX_gtk_widget_destroy fl_gtk_widget_destroy = NULL;
120
121// void gtk_file_chooser_set_select_multiple(GtkFileChooser *chooser, gboolean select_multiple);
122typedef void (*XX_gtk_file_chooser_set_select_multiple)(GtkFileChooser *, gboolean);
123static XX_gtk_file_chooser_set_select_multiple fl_gtk_file_chooser_set_select_multiple = NULL;
124
125// void gtk_file_chooser_set_do_overwrite_confirmation(GtkFileChooser *chooser, gboolean do_overwrite_confirmation);
126typedef void (*XX_gtk_file_chooser_set_do_overwrite_confirmation)(GtkFileChooser *, gboolean);
127static XX_gtk_file_chooser_set_do_overwrite_confirmation fl_gtk_file_chooser_set_do_overwrite_confirmation = NULL;
128
129// void gtk_file_chooser_set_current_name (GtkFileChooser *chooser, const gchar *name);
130typedef void (*XX_gtk_file_chooser_set_current_name)(GtkFileChooser *, const gchar *);
131static XX_gtk_file_chooser_set_current_name fl_gtk_file_chooser_set_current_name = NULL;
132
133// void gtk_file_chooser_set_current_folder (GtkFileChooser *chooser, const gchar *name);
134typedef void (*XX_gtk_file_chooser_set_current_folder)(GtkFileChooser *, const gchar *);
135static XX_gtk_file_chooser_set_current_folder fl_gtk_file_chooser_set_current_folder = NULL;
136
137// void gtk_file_chooser_set_create_folders (GtkFileChooser *chooser, gboolean create_folders);
138typedef void (*XX_gtk_file_chooser_set_create_folders) (GtkFileChooser *, gboolean);
139static XX_gtk_file_chooser_set_create_folders fl_gtk_file_chooser_set_create_folders = NULL;
140
141// gboolean gtk_file_chooser_get_select_multiple(GtkFileChooser *chooser);
142typedef gboolean (*XX_gtk_file_chooser_get_select_multiple)(GtkFileChooser *);
143static XX_gtk_file_chooser_get_select_multiple fl_gtk_file_chooser_get_select_multiple = NULL;
144
145// void gtk_widget_hide(GtkWidget *widget);
146typedef void (*XX_gtk_widget_hide)(GtkWidget *);
147static XX_gtk_widget_hide fl_gtk_widget_hide = NULL;
148
149// gchar * gtk_file_chooser_get_filename(GtkFileChooser *chooser);
150typedef gchar* (*XX_gtk_file_chooser_get_filename)(GtkFileChooser *);
151static XX_gtk_file_chooser_get_filename fl_gtk_file_chooser_get_filename = NULL;
152
153// GSList * gtk_file_chooser_get_filenames(GtkFileChooser *chooser);
154typedef GSList* (*XX_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser);
155static XX_gtk_file_chooser_get_filenames fl_gtk_file_chooser_get_filenames = NULL;
156
157// gboolean gtk_main_iteration(void);
158typedef gboolean (*XX_gtk_main_iteration)(void);
159static XX_gtk_main_iteration fl_gtk_main_iteration = NULL;
160
161// gboolean gtk_events_pending(void);
162typedef gboolean (*XX_gtk_events_pending)(void);
163static XX_gtk_events_pending fl_gtk_events_pending = NULL;
164
165// GtkWidget * gtk_file_chooser_dialog_new(const gchar *title, GtkWindow *parent, GtkFileChooserAction action, const gchar *first_button_text, ...);
166typedef GtkWidget* (*XX_gtk_file_chooser_dialog_new)(const gchar *, GtkWindow *, GtkFileChooserAction, const gchar *, ...);
167static XX_gtk_file_chooser_dialog_new fl_gtk_file_chooser_dialog_new = NULL;
168
169// void gtk_file_chooser_add_filter(GtkFileChooser*, GtkFileFilter*);
170typedef void (*XX_gtk_file_chooser_add_filter)(GtkFileChooser*, GtkFileFilter*);
171static XX_gtk_file_chooser_add_filter fl_gtk_file_chooser_add_filter = NULL;
172
173// GtkFileFilter* gtk_file_chooser_get_filter(GtkFileChooser*);
174typedef GtkFileFilter* (*XX_gtk_file_chooser_get_filter)(GtkFileChooser*);
175static XX_gtk_file_chooser_get_filter fl_gtk_file_chooser_get_filter = NULL;
176
177// void gtk_file_chooser_set_filter(GtkFileChooser*, GtkFileFilter*);
178typedef void (*XX_gtk_file_chooser_set_filter)(GtkFileChooser*, GtkFileFilter*);
179static XX_gtk_file_chooser_set_filter fl_gtk_file_chooser_set_filter = NULL;
180
181// GtkFileFilter * gtk_file_filter_new();
182typedef GtkFileFilter* (*XX_gtk_file_filter_new)(void);
183static XX_gtk_file_filter_new fl_gtk_file_filter_new = NULL;
184
185// void gtk_file_filter_add_pattern(GtkFileFilter*, const gchar*);
186typedef void (*XX_gtk_file_filter_add_pattern)(GtkFileFilter*, const gchar*);
187static XX_gtk_file_filter_add_pattern fl_gtk_file_filter_add_pattern = NULL;
188
189// void gtk_file_filter_add_custom(GtkFileFilter *filter, GtkFileFilterFlags needed,
190// GtkFileFilterFunc func, gpointer data, GDestroyNotify notify);
191typedef void (*XX_gtk_file_filter_add_custom)(GtkFileFilter *filter, GtkFileFilterFlags needed,
192 GtkFileFilterFunc func, gpointer data,
193 GDestroyNotify notify);
194static XX_gtk_file_filter_add_custom fl_gtk_file_filter_add_custom = NULL;
195
196// void gtk_file_filter_set_name(GtkFileFilter*, const gchar*);
197typedef void (*XX_gtk_file_filter_set_name)(GtkFileFilter*, const gchar*);
198static XX_gtk_file_filter_set_name fl_gtk_file_filter_set_name = NULL;
199
200// const gchar* gtk_file_filter_get_name(GtkFileFilter*);
201typedef const gchar* (*XX_gtk_file_filter_get_name)(GtkFileFilter*);
202static XX_gtk_file_filter_get_name fl_gtk_file_filter_get_name = NULL;
203
204// void gtk_file_chooser_set_extra_widget(GtkFileChooser *, GtkWidget *);
205typedef void (*XX_gtk_file_chooser_set_extra_widget)(GtkFileChooser *, GtkWidget *);
206static XX_gtk_file_chooser_set_extra_widget fl_gtk_file_chooser_set_extra_widget = NULL;
207
208// void gtk_widget_show_now(GtkWidget *);
209typedef void (*XX_gtk_widget_show_now)(GtkWidget *);
210static XX_gtk_widget_show_now fl_gtk_widget_show_now = NULL;
211
212// GdkWindow* gtk_widget_get_window(GtkWidget *);
213typedef GdkWindow* (*XX_gtk_widget_get_window)(GtkWidget *);
214static XX_gtk_widget_get_window fl_gtk_widget_get_window = NULL;
215
216// Window gdk_x11_drawable_get_xid(GdkWindow *);
217typedef Window (*XX_gdk_x11_drawable_get_xid)(GdkWindow *);
218static XX_gdk_x11_drawable_get_xid fl_gdk_x11_drawable_get_xid = NULL;
219
220// GtkWidget *gtk_check_button_new_with_label(const gchar *);
221typedef GtkWidget* (*XX_gtk_check_button_new_with_label)(const gchar *);
222static XX_gtk_check_button_new_with_label fl_gtk_check_button_new_with_label = NULL;
223
224// gulong g_signal_connect_data(gpointer, const gchar *, GCallback, gpointer, GClosureNotify, GConnectFlags);
225typedef gulong (*XX_g_signal_connect_data)(gpointer, const gchar *, GCallback, gpointer, GClosureNotify, GConnectFlags);
226static XX_g_signal_connect_data fl_g_signal_connect_data = NULL;
227
228// gboolean gtk_toggle_button_get_active(GtkToggleButton *);
229typedef gboolean (*XX_gtk_toggle_button_get_active)(GtkToggleButton*);
230static XX_gtk_toggle_button_get_active fl_gtk_toggle_button_get_active = NULL;
231
232// void gtk_file_chooser_set_show_hidden(GtkFileChooser *, gboolean);
233typedef void (*XX_gtk_file_chooser_set_show_hidden)(GtkFileChooser *, gboolean);
234static XX_gtk_file_chooser_set_show_hidden fl_gtk_file_chooser_set_show_hidden = NULL;
235
236// gboolean gtk_file_chooser_get_show_hidden(GtkFileChooser *);
237typedef gboolean (*XX_gtk_file_chooser_get_show_hidden)(GtkFileChooser *);
238static XX_gtk_file_chooser_get_show_hidden fl_gtk_file_chooser_get_show_hidden = NULL;
239
240// void gtk_toggle_button_set_active(GtkToggleButton *, gboolean);
241typedef void (*XX_gtk_toggle_button_set_active)(GtkToggleButton *, gboolean);
242static XX_gtk_toggle_button_set_active fl_gtk_toggle_button_set_active = NULL;
243
244
245Fl_GTK_File_Chooser::Fl_GTK_File_Chooser(int val) : Fl_FLTK_File_Chooser(-1)
246{
247 gtkw_ptr = NULL; // used to hold a GtkWidget*
248 gtkw_slist = NULL; // will hold the returned file names in a multi-selection...
249 gtkw_count = 0; // How many items were selected?
250 gtkw_filename = NULL; // holds the last name we read back in a single file selection...
251 gtkw_title = NULL; // dialog title
252 _btype = val;
253 previous_filter = NULL;
254}
255
256Fl_GTK_File_Chooser::~Fl_GTK_File_Chooser()
257{
258 // Should free up resources taken for...
259 if(gtkw_ptr) {
260 fl_gtk_widget_destroy (gtkw_ptr);
261 gtkw_ptr = NULL;
262 }
263 if(gtkw_filename) {
264 fl_g_free(gtkw_filename);
265 gtkw_filename = NULL;
266 }
267 if(gtkw_slist) {
268 GSList *iter = (GSList *)gtkw_slist;
269 while(iter) {
270 if(iter->data) fl_g_free(iter->data);
271 iter = g_slist_next(iter);
272 }
273 fl_g_slist_free((GSList *)gtkw_slist);
274 gtkw_slist = NULL;
275 }
276 gtkw_count = 0; // assume we have no files selected now
277 gtkw_title = strfree(gtkw_title);
278}
279
280void Fl_GTK_File_Chooser::type(int val) {
281 _btype = val;
282}
283
284int Fl_GTK_File_Chooser::count() const {
285 return gtkw_count;
286}
287
288const char *Fl_GTK_File_Chooser::filename() const
289{
290 if(gtkw_ptr) {
291 if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtkw_ptr) == FALSE) {
292 return gtkw_filename;
293 }
294 else {
295 GSList *iter = (GSList *)gtkw_slist;
296 char *nm = (char *)iter->data;
297 return nm;
298 }
299 }
300 return("");
301}
302
303const char *Fl_GTK_File_Chooser::filename(int i) const
304{
305 if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtkw_ptr) == FALSE) {
306 return gtkw_filename;
307 }
308 else {
309 if ((unsigned)i < gtkw_count) {
310 GSList *iter = (GSList *)gtkw_slist;
311 char *nm = (char *)fl_g_slist_nth_data(iter, i);
312 return nm;
313 }
314 }
315 return("");
316}
317
318void Fl_GTK_File_Chooser::title(const char *val)
319{
320 strfree(gtkw_title);
321 gtkw_title = strnew(val);
322}
323
324const char* Fl_GTK_File_Chooser::title() const
325{
326 return gtkw_title;
327}
328
329/* changes the extension of the outfile in the chooser according to newly selected filter */
330void Fl_GTK_File_Chooser::changed_output_type(const char *filter)
331{
332 if ( !(options()&Fl_Native_File_Chooser::USE_FILTER_EXT) ) return;
333 if (strchr(filter, '(') || strchr(filter, '{') || strchr(filter+1, '*') || strncmp(filter, "*.", 2)) return;
334 const char *p = fl_gtk_file_chooser_get_filename((GtkFileChooser*)gtkw_ptr);
335 if (!p) return;
336 p = fl_filename_name(p);
337 const char *q = strrchr(p, '.');
338 if (!q) q = p + strlen(p);
339 char *r = new char[strlen(p) + strlen(filter)];
340 strcpy(r, p);
341 strcpy(r + (q - p), filter + 1);
342 fl_gtk_file_chooser_set_current_name((GtkFileChooser*)gtkw_ptr, r);
343 delete[] r;
344}
345
346/* Filters files before display in chooser.
347 Also used to detect when the filter just changed */
348gboolean Fl_GTK_File_Chooser::custom_gtk_filter_function(const GtkFileFilterInfo *info, Fl_GTK_File_Chooser::pair* p)
349{
350 if (p->running->previous_filter != p->filter) {
351 p->running->changed_output_type(p->filter);
352 p->running->previous_filter = p->filter;
353 }
354 return (gboolean)fl_filename_match(fl_filename_name(info->filename), p->filter);
355}
356
357void Fl_GTK_File_Chooser::free_pair(Fl_GTK_File_Chooser::pair *p)
358{
359 delete p;
360}
361
362static void hidden_files_cb(GtkToggleButton *togglebutton, gpointer user_data)
363{
364 gboolean state = fl_gtk_toggle_button_get_active(togglebutton);
365 fl_gtk_file_chooser_set_show_hidden((GtkFileChooser*)user_data, state);
366}
367
368int Fl_GTK_File_Chooser::show()
369{
370 // The point here is that after running a GTK dialog, the calling program's current locale is modified.
371 // To avoid that, we memorize the calling program's current locale, and the locale as modified
372 // by GTK after the first dialog use. We restore the calling program's current locale
373 // before returning, and we set the locale as modified by GTK before subsequent GTK dialog uses.
374 static bool first = true;
375 char *p;
376 char *before = NULL;
377 static char *gtk_wants = NULL;
378 fl_open_display();
379 // record in before the calling program's current locale
380 p = setlocale(LC_ALL, NULL);
381 if (p) before = strdup(p);
382 if (gtk_wants) { // set the locale as GTK 'wants it'
383 setlocale(LC_ALL, gtk_wants);
384 }
385 int retval = fl_gtk_chooser_wrapper(); // may change the locale
386 if (first) {
387 first = false;
388 // record in gtk_wants the locale as modified by the GTK dialog
389 p = setlocale(LC_ALL, NULL);
390 if (p) gtk_wants = strdup(p);
391 }
392 if (before) {
393 setlocale(LC_ALL, before); // restore calling program's current locale
394 free(before);
395 }
396 return retval;
397}
398
399static char *extract_dir_from_path(const char *path)
400{
401 static char *dir = NULL;
402 if (fl_filename_isdir(path)) {
403 return (char*)path;
404 }
405 if (*path != '/') return NULL;
406 if (dir) free(dir);
407 dir = strdup(path);
408 do {
409 char *p = strrchr(dir, '/');
410 if (p == dir) p++;
411 *p = 0;
412 }
413 while (!fl_filename_isdir(dir));
414 return dir;
415}
416
417static void run_response_handler(GtkDialog *dialog, gint response_id, gpointer data)
418{
419 gint *ri = (gint *)data;
420 *ri = response_id;
421}
422
423
424int Fl_GTK_File_Chooser::fl_gtk_chooser_wrapper()
425{
426 int result = 1;
427 static int have_gtk_init = 0;
428 char *p;
429
430 if(!have_gtk_init) {
431 have_gtk_init = -1;
432 int ac = 0;
433 fl_gtk_init_check(&ac, NULL);
434 }
435
436 if(gtkw_ptr) { // discard the previous dialog widget
437 fl_gtk_widget_destroy (gtkw_ptr);
438 gtkw_ptr = NULL;
439 }
440
441 // set the dialog action type
442 GtkFileChooserAction gtw_action_type;
443 switch (_btype) {
444 case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
445 case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY:
446 gtw_action_type = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
447 break;
448
449 case Fl_Native_File_Chooser::BROWSE_SAVE_FILE:
450 gtw_action_type = GTK_FILE_CHOOSER_ACTION_SAVE;
451 break;
452
453 case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
454 gtw_action_type = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
455 break;
456
457 case Fl_Native_File_Chooser::BROWSE_MULTI_FILE:
458 case Fl_Native_File_Chooser::BROWSE_FILE:
459 default:
460 gtw_action_type = GTK_FILE_CHOOSER_ACTION_OPEN;
461 break;
462 }
463 // create a new dialog
464 gtkw_ptr = fl_gtk_file_chooser_dialog_new (gtkw_title,
465 NULL, /* parent_window */
466 gtw_action_type,
467 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
468 gtw_action_type == GTK_FILE_CHOOSER_ACTION_SAVE || gtw_action_type == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER ?
469 GTK_STOCK_SAVE : GTK_STOCK_OPEN,
470 GTK_RESPONSE_ACCEPT,
471 NULL);
472 // did we create a valid dialog widget?
473 if(!gtkw_ptr) {
474 // fail
475 return -1;
476 }
477
478 // set the dialog properties
479 switch (_btype) {
480 case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY:
481 case Fl_Native_File_Chooser::BROWSE_MULTI_FILE:
482 fl_gtk_file_chooser_set_select_multiple((GtkFileChooser *)gtkw_ptr, TRUE);
483 break;
484
485 case Fl_Native_File_Chooser::BROWSE_SAVE_FILE:
486 if (_preset_file)fl_gtk_file_chooser_set_current_name ((GtkFileChooser *)gtkw_ptr, fl_filename_name(_preset_file));
487 /* FALLTHROUGH */
488 case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
489 fl_gtk_file_chooser_set_create_folders((GtkFileChooser *)gtkw_ptr, TRUE);
490 fl_gtk_file_chooser_set_do_overwrite_confirmation ((GtkFileChooser *)gtkw_ptr, (_options & Fl_Native_File_Chooser::SAVEAS_CONFIRM)?TRUE:FALSE);
491 break;
492
493 case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
494 case Fl_Native_File_Chooser::BROWSE_FILE:
495 default:
496 break;
497 }
498
499 if (_directory && _directory[0]) {
500 p = extract_dir_from_path(_directory);
501 if (p) fl_gtk_file_chooser_set_current_folder((GtkFileChooser *)gtkw_ptr, p);
502 }
503 else if (_preset_file) {
504 p = extract_dir_from_path(_preset_file);
505 if (p) fl_gtk_file_chooser_set_current_folder((GtkFileChooser *)gtkw_ptr, p);
506 }
507
508 GtkFileFilter **filter_tab = NULL;
509 if (_parsedfilt) {
510 filter_tab = new GtkFileFilter*[_nfilters];
511 char *filter = strdup(_parsedfilt);
512 p = strtok(filter, "\t");
513 int count = 0;
514 while (p) {
515 filter_tab[count] = fl_gtk_file_filter_new();
516 fl_gtk_file_filter_set_name(filter_tab[count], p);
517 p = strchr(p, '(') + 1;
518 char *q = strchr(p, ')'); *q = 0;
519 fl_gtk_file_filter_add_custom(filter_tab[count],
520 GTK_FILE_FILTER_FILENAME,
521 (GtkFileFilterFunc)Fl_GTK_File_Chooser::custom_gtk_filter_function,
522 new Fl_GTK_File_Chooser::pair(this, p),
523 (GDestroyNotify)Fl_GTK_File_Chooser::free_pair);
524 fl_gtk_file_chooser_add_filter((GtkFileChooser *)gtkw_ptr, filter_tab[count]);
525 p = strtok(NULL, "\t");
526 count++;
527 }
528 free(filter);
529 fl_gtk_file_chooser_set_filter((GtkFileChooser *)gtkw_ptr, filter_tab[_filtvalue < _nfilters?_filtvalue:0]);
530 previous_filter = NULL;
531 if (gtw_action_type == GTK_FILE_CHOOSER_ACTION_OPEN) {
532 GtkFileFilter* gfilter = fl_gtk_file_filter_new();
533 fl_gtk_file_filter_set_name(gfilter, Fl_File_Chooser::all_files_label);
534 fl_gtk_file_filter_add_pattern(gfilter, "*");
535 fl_gtk_file_chooser_add_filter((GtkFileChooser *)gtkw_ptr, gfilter);
536 }
537 }
538
539 GtkWidget *toggle = fl_gtk_check_button_new_with_label(Fl_File_Chooser::hidden_label);
540 fl_gtk_file_chooser_set_extra_widget((GtkFileChooser *)gtkw_ptr, toggle);
541 fl_g_signal_connect_data(toggle, "toggled", G_CALLBACK(hidden_files_cb), gtkw_ptr, NULL, (GConnectFlags) 0);
542 Fl_Window* firstw = Fl::first_window();
543 fl_gtk_widget_show_now(gtkw_ptr); // map the GTK window on screen
544 if (firstw) {
545 GdkWindow* gdkw = fl_gtk_widget_get_window(gtkw_ptr);
546 Window xw = fl_gdk_x11_drawable_get_xid(gdkw); // get the X11 ref of the GTK window
547 XSetTransientForHint(fl_display, xw, fl_xid(firstw)); // set the GTK window transient for the last FLTK win
548 }
549 gboolean state = fl_gtk_file_chooser_get_show_hidden((GtkFileChooser *)gtkw_ptr);
550 fl_gtk_toggle_button_set_active((GtkToggleButton *)toggle, state);
551
552 gint response_id = GTK_RESPONSE_NONE;
553 fl_g_signal_connect_data(gtkw_ptr, "response", G_CALLBACK(run_response_handler), &response_id, NULL, (GConnectFlags) 0);
554 while (response_id == GTK_RESPONSE_NONE) { // loop that shows the GTK dialog window
555 fl_gtk_main_iteration(); // one iteration of the GTK event loop
556 while (XEventsQueued(fl_display, QueuedAfterReading)) { // emulate modal dialog
557 XEvent xevent;
558 XNextEvent(fl_display, &xevent);
559 Window xid = xevent.xany.window;
560 if (xevent.type == ConfigureNotify) xid = xevent.xmaprequest.window;
561 if (!fl_find(xid)) continue; // skip events to non-FLTK windows
562 // process Expose and ConfigureNotify events
563 if ( xevent.type == Expose || xevent.type == ConfigureNotify ) fl_handle(xevent);
564 }
565 Fl::flush(); // do the drawings needed after Expose events
566 }
567
568 if (response_id == GTK_RESPONSE_ACCEPT) {
569 if (_parsedfilt) {
570 GtkFileFilter *gfilter = fl_gtk_file_chooser_get_filter((GtkFileChooser *)gtkw_ptr);
571 for (_filtvalue = 0; _filtvalue < _nfilters; _filtvalue++) {
572 if (filter_tab[_filtvalue] == gfilter) break;
573 }
574 }
575
576 // discard any filenames or lists from previous calls
577 if(gtkw_filename) {
578 fl_g_free(gtkw_filename);
579 gtkw_filename = NULL;
580 }
581 if(gtkw_slist) {
582 GSList *iter = (GSList *)gtkw_slist;
583 while(iter) {
584 if(iter->data) fl_g_free(iter->data);
585 iter = g_slist_next(iter);
586 }
587 fl_g_slist_free((GSList *)gtkw_slist);
588 gtkw_slist = NULL;
589 }
590 gtkw_count = 0; // assume we have no files selected now
591
592 if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtkw_ptr) == FALSE) {
593 gtkw_filename = fl_gtk_file_chooser_get_filename ((GtkFileChooser *)gtkw_ptr);
594 if (gtkw_filename) {
595 gtkw_count = 1;
596 result = 0;
597 //printf("single: %s\n", gtkw_filename);
598 }
599 }
600 else {
601 gtkw_slist = fl_gtk_file_chooser_get_filenames((GtkFileChooser *)gtkw_ptr);
602 gtkw_count = fl_g_slist_length((GSList *)gtkw_slist);
603 if(gtkw_count) result = 0;
604
605 // puts("multiple");
606 // GSList *iter = (GSList *)gtkw_slist;
607 // printf ("Selected %d files\n", gtkw_count);
608 // while(iter) {
609 // char *nm = (char *)iter->data;
610 // printf("%s\n", nm);
611 // iter = g_slist_next(iter);
612 // }
613 }
614 }
615 delete[] filter_tab;
616 if ( response_id == GTK_RESPONSE_DELETE_EVENT) gtkw_ptr = NULL;
617 else fl_gtk_widget_hide (gtkw_ptr);
618
619 // I think this is analogus to doing an Fl::check() - we need this here to make sure
620 // the GtkFileChooserDialog is removed from the display correctly
621 while (fl_gtk_events_pending ()) fl_gtk_main_iteration ();
622
623 return result;
624} // fl_gtk_chooser_wrapper
625
626#if HAVE_DLSYM && HAVE_DLFCN_H
627// macro to help with the symbol loading boilerplate...
628# define GET_SYM(SSS, LLL) \
629dlerror(); /* Clear any existing error */ \
630fl_##SSS = (XX_##SSS)dlsym(LLL, #SSS); \
631if ((pc_dl_error = dlerror()) != NULL) { \
632fprintf(stderr, "%s\n", pc_dl_error); \
633did_find_GTK_libs = 0; \
634return; }
635
636static void* fl_dlopen(const char *filename1, const char *filename2)
637{
638 void *ptr = dlopen(filename1, RTLD_LAZY | RTLD_GLOBAL);
639 if (!ptr) ptr = dlopen(filename2, RTLD_LAZY | RTLD_GLOBAL);
640 return ptr;
641}
642#endif
643
644/*
645 * Use dlopen to see if we can load the gtk dynamic libraries that
646 * will allow us to create a GtkFileChooserDialog() on the fly,
647 * without linking to the GTK libs at compile time.
648 */
649void Fl_GTK_File_Chooser::probe_for_GTK_libs(void) {
650#if HAVE_DLSYM && HAVE_DLFCN_H
651 void *ptr_glib = NULL;
652 void *ptr_gtk = NULL;
653
654# ifdef __APPLE_CC__ // allows testing on Darwin + X11
655 ptr_glib = dlopen("/sw/lib/libglib-2.0.dylib", RTLD_LAZY | RTLD_GLOBAL);
656# else
657 ptr_glib = fl_dlopen("libglib-2.0.so", "libglib-2.0.so.0");
658# endif
659 // Try first with GTK2
660# ifdef __APPLE_CC__ // allows testing on Darwin + X11
661 ptr_gtk = dlopen("/sw/lib/libgtk-x11-2.0.dylib", RTLD_LAZY | RTLD_GLOBAL);
662#else
663 ptr_gtk = fl_dlopen("libgtk-x11-2.0.so", "libgtk-x11-2.0.so.0");
664#endif
665 if (ptr_gtk && ptr_glib) {
666#ifdef DEBUG
667 puts("selected GTK-2\n");
668#endif
669 }
670 else {// Try then with GTK3
671 ptr_gtk = fl_dlopen("libgtk-3.so", "libgtk-3.so.0");
672#ifdef DEBUG
673 if (ptr_gtk && ptr_glib) {
674 puts("selected GTK-3\n");
675 }
676#endif
677 }
678
679 if((!ptr_glib) || (!ptr_gtk)) {
680#ifdef DEBUG
681 puts("Failure to load libglib or libgtk");
682#endif
683 did_find_GTK_libs = 0;
684 return;
685 }
686
687 char *pc_dl_error; // used to report errors by the GET_SYM macro...
688 // items we need from GLib
689 GET_SYM(g_free, ptr_glib);
690 GET_SYM(g_slist_nth_data, ptr_glib);
691 GET_SYM(g_slist_length, ptr_glib);
692 GET_SYM(g_slist_free, ptr_glib);
693 // items we need from GTK
694 GET_SYM(gtk_init_check, ptr_gtk);
695 GET_SYM(gtk_widget_destroy, ptr_gtk);
696 GET_SYM(gtk_file_chooser_set_select_multiple, ptr_gtk);
697 GET_SYM(gtk_file_chooser_set_do_overwrite_confirmation, ptr_gtk);
698 GET_SYM(gtk_file_chooser_set_current_name, ptr_gtk);
699 GET_SYM(gtk_file_chooser_set_current_folder, ptr_gtk);
700 GET_SYM(gtk_file_chooser_set_create_folders, ptr_gtk);
701 GET_SYM(gtk_file_chooser_get_select_multiple, ptr_gtk);
702 GET_SYM(gtk_widget_hide, ptr_gtk);
703 GET_SYM(gtk_file_chooser_get_filename, ptr_gtk);
704 GET_SYM(gtk_file_chooser_get_filenames, ptr_gtk);
705 GET_SYM(gtk_main_iteration, ptr_gtk);
706 GET_SYM(gtk_events_pending, ptr_gtk);
707 GET_SYM(gtk_file_chooser_dialog_new, ptr_gtk);
708 GET_SYM(gtk_file_chooser_add_filter, ptr_gtk);
709 GET_SYM(gtk_file_chooser_get_filter, ptr_gtk);
710 GET_SYM(gtk_file_chooser_set_filter, ptr_gtk);
711 GET_SYM(gtk_file_filter_new, ptr_gtk);
712 GET_SYM(gtk_file_filter_add_pattern, ptr_gtk);
713 GET_SYM(gtk_file_filter_add_custom, ptr_gtk);
714 GET_SYM(gtk_file_filter_set_name, ptr_gtk);
715 GET_SYM(gtk_file_filter_get_name, ptr_gtk);
716 GET_SYM(gtk_file_chooser_set_extra_widget, ptr_gtk);
717 GET_SYM(gtk_widget_show_now, ptr_gtk);
718 GET_SYM(gtk_widget_get_window, ptr_gtk);
719 GET_SYM(gdk_x11_drawable_get_xid, ptr_gtk);
720 GET_SYM(gtk_check_button_new_with_label, ptr_gtk);
721 GET_SYM(g_signal_connect_data, ptr_gtk);
722 GET_SYM(gtk_toggle_button_get_active, ptr_gtk);
723 GET_SYM(gtk_file_chooser_set_show_hidden, ptr_gtk);
724 GET_SYM(gtk_file_chooser_get_show_hidden, ptr_gtk);
725 GET_SYM(gtk_toggle_button_set_active, ptr_gtk);
726
727 did_find_GTK_libs = 1;
728#endif
729} // probe_for_GTK_libs
730
731//
732// End of "$Id$".
733//
Fl_FLTK_File_Chooser
Definition Fl_Native_File_Chooser.H:259
Fl_File_Chooser::hidden_label
static const char * hidden_label
[standard text may be customized at run-time]
Definition Fl_File_Chooser.H:226
Fl_File_Chooser::all_files_label
static const char * all_files_label
[standard text may be customized at run-time]
Definition Fl_File_Chooser.H:178
Fl_Native_File_Chooser::BROWSE_DIRECTORY
@ BROWSE_DIRECTORY
browse directories (lets user choose one directory)
Definition Fl_Native_File_Chooser.H:115
Fl_Native_File_Chooser::BROWSE_MULTI_FILE
@ BROWSE_MULTI_FILE
browse files (lets user choose multiple files)
Definition Fl_Native_File_Chooser.H:116
Fl_Native_File_Chooser::BROWSE_SAVE_FILE
@ BROWSE_SAVE_FILE
browse to save a file
Definition Fl_Native_File_Chooser.H:118
Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY
@ BROWSE_SAVE_DIRECTORY
browse to save a directory
Definition Fl_Native_File_Chooser.H:119
Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY
@ BROWSE_MULTI_DIRECTORY
browse directories (lets user choose multiple directories)
Definition Fl_Native_File_Chooser.H:117
Fl_Native_File_Chooser::BROWSE_FILE
@ BROWSE_FILE
browse files (lets user choose one file)
Definition Fl_Native_File_Chooser.H:114
Fl_Native_File_Chooser::USE_FILTER_EXT
@ USE_FILTER_EXT
Chooser filter pilots the output file extension (if supported)
Definition Fl_Native_File_Chooser.H:126
Fl_Native_File_Chooser::SAVEAS_CONFIRM
@ SAVEAS_CONFIRM
Show native 'Save As' overwrite confirm dialog.
Definition Fl_Native_File_Chooser.H:123
Fl_Window
This widget produces an actual window.
Definition Fl_Window.H:57
Fl::flush
static void flush()
Causes all the windows that need it to be redrawn and graphics forced out through the pipes.
Definition Fl.cxx:801
fl_filename_name
FL_EXPORT const char * fl_filename_name(const char *filename)
Gets the file name from a path.
fl_filename_match
FL_EXPORT int fl_filename_match(const char *name, const char *pattern)
Checks if a string s matches a pattern p.
Definition filename_match.cxx:44
fl_filename_isdir
FL_EXPORT int fl_filename_isdir(const char *name)
Determines if a file exists and is a directory from its filename.
Definition filename_isdir.cxx:52
Fl::first_window
static Fl_Window * first_window()
Returns the first top-level window in the list of shown() windows.
Definition Fl.cxx:755