Audacity 3.2.0
gtk/FileDialogPrivate.cpp
Go to the documentation of this file.
1//
2// Copied from wxWidgets 3.0.2 and modified for Audacity
3//
5// Name: src/gtk/filedlg.cpp
6// Purpose: native implementation of wxFileDialog
7// Author: Robert Roebling, Zbigniew Zagorski, Mart Raudsepp
8// Copyright: (c) 1998 Robert Roebling, 2004 Zbigniew Zagorski, 2005 Mart Raudsepp
9// Licence: wxWindows licence
11
12#include <gtk/gtk.h>
13
14#include "Internat.h"
16#include "../FileDialog.h"
17
18#ifdef __UNIX__
19#include <unistd.h> // chdir
20#endif
21
22#include <wx/filename.h> // wxFilename
23#include <wx/tokenzr.h> // wxStringTokenizer
24#include <wx/filefn.h> // ::wxGetCwd
25#include <wx/modalhook.h>
26#include <wx/sizer.h>
27
28#define wxGTK_CONV(s) (s).utf8_str()
29#define wxGTK_CONV_FN(s) (s).fn_str()
30
31// ----------------------------------------------------------------------------
32// Convenience class for g_freeing a gchar* on scope exit automatically
33// ----------------------------------------------------------------------------
34
36{
37public:
38 explicit wxGtkString(gchar *s) : m_str(s) { }
39 ~wxGtkString() { g_free(m_str); }
40
41 const gchar *c_str() const { return m_str; }
42
43 operator gchar *() const { return m_str; }
44
45private:
46 gchar *m_str;
47
49};
50
51//-----------------------------------------------------------------------------
52// "clicked" for OK-button
53//-----------------------------------------------------------------------------
54
55extern "C" {
56static void gtk_filedialog_ok_callback(GtkWidget *widget, FileDialog *dialog)
57{
58 int style = dialog->GetWindowStyle();
59 wxGtkString filename(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)));
60
61 // gtk version numbers must be identical with the one in ctor (that calls set_do_overwrite_confirmation)
62#ifndef __WXGTK3__
63#if GTK_CHECK_VERSION(2,7,3)
64 if (gtk_check_version(2, 7, 3) != NULL)
65#endif
66 {
67 if ((style & wxFD_SAVE) && (style & wxFD_OVERWRITE_PROMPT))
68 {
69 if ( g_file_test(filename, G_FILE_TEST_EXISTS) )
70 {
71 int result = AudacityMessageBox(
72 XO("File '%s' already exists, do you really want to overwrite it?")
73 .Format(wxString::FromUTF8(filename)),
74 XO("Confirm"),
75 wxYES_NO | wxICON_QUESTION);
76 if (result != wxID_YES)
77 {
78 return;
79 }
80 }
81 }
82 }
83#endif
84
85 if (style & wxFD_FILE_MUST_EXIST)
86 {
87 if ( !g_file_test(filename, G_FILE_TEST_EXISTS) )
88 {
89 AudacityMessageBox(XO("Please choose an existing file."),
90 XO("Error"),
91 wxOK | wxICON_ERROR);
92 return;
93 }
94 }
95
96 // change to the directory where the user went if asked
97 if (style & wxFD_CHANGE_DIR)
98 {
99 // Use chdir to not care about filename encodings
100 wxGtkString folder(g_path_get_dirname(filename));
101 chdir(folder);
102 }
103
104 wxCommandEvent event(wxEVT_BUTTON, wxID_OK);
105 event.SetEventObject(dialog);
106 dialog->HandleWindowEvent(event);
107}
108}
109
110//-----------------------------------------------------------------------------
111// "clicked" for Cancel-button
112//-----------------------------------------------------------------------------
113
114extern "C"
115{
116
117static void
118gtk_filedialog_cancel_callback(GtkWidget * WXUNUSED(w), FileDialog *dialog)
119{
120 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
121 event.SetEventObject(dialog);
122 dialog->HandleWindowEvent(event);
123}
124
125static void gtk_filedialog_response_callback(GtkWidget *w,
126 gint response,
127 FileDialog *dialog)
128{
129 if (response == GTK_RESPONSE_ACCEPT)
131 else // GTK_RESPONSE_CANCEL or GTK_RESPONSE_NONE
133}
134
135static void gtk_filedialog_selchanged_callback(GtkFileChooser *chooser,
136 FileDialog *dialog)
137{
138 wxGtkString filename(gtk_file_chooser_get_preview_filename(chooser));
139
140 dialog->GTKSelectionChanged(wxString::FromUTF8(filename));
141}
142
143static void gtk_filedialog_update_preview_callback(GtkFileChooser *chooser,
144 gpointer user_data)
145{
146 GtkWidget *preview = GTK_WIDGET(user_data);
147
148 wxGtkString filename(gtk_file_chooser_get_preview_filename(chooser));
149
150 if ( !filename )
151 return;
152
153 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size(filename, 128, 128, NULL);
154 gboolean have_preview = pixbuf != NULL;
155
156 gtk_image_set_from_pixbuf(GTK_IMAGE(preview), pixbuf);
157 if ( pixbuf )
158 g_object_unref (pixbuf);
159
160 gtk_file_chooser_set_preview_widget_active(chooser, have_preview);
161}
162
163static void gtk_filedialog_folderchanged_callback(GtkFileChooser *chooser,
164 FileDialog *dialog)
165{
166 dialog->GTKFolderChanged();
167}
168
169static void gtk_filedialog_filterchanged_callback(GtkFileChooser *chooser,
170 GParamSpec *pspec,
171 FileDialog *dialog)
172{
173 dialog->GTKFilterChanged();
174}
175
176static GtkWidget* find_widget(GtkWidget* parent, const gchar* name, int depth)
177{
178 // printf("%*.*c%s\n", depth, depth, ' ', gtk_widget_get_name(parent));
179
180 GtkWidget *widget = NULL;
181 if (g_ascii_strncasecmp(gtk_widget_get_name(parent), name, strlen(name)) == 0)
182 {
183 return parent;
184 }
185
186 if (GTK_IS_BIN(parent))
187 {
188 return find_widget(gtk_bin_get_child(GTK_BIN(parent)), name, depth + 1);
189 }
190
191 if (GTK_IS_CONTAINER(parent))
192 {
193 GList *list = gtk_container_get_children(GTK_CONTAINER(parent));
194 for (GList *node = list; node; node = node->next)
195 {
196 widget = find_widget(GTK_WIDGET(node->data), name, depth + 1);
197 if (widget)
198 {
199 break;
200 }
201 }
202 g_list_free(list);
203 }
204
205 return widget;
206}
207
208} // extern "C"
209
210void FileDialog::AddChildGTK(wxWindowGTK* child)
211{
212 // allow dialog to be resized smaller horizontally
213 gtk_widget_set_size_request(
214 child->m_widget, child->GetMinWidth(), child->m_height);
215
216// In GTK 3+, adding our container as the extra widget can cause the
217// the filter combo to grow to the same height as our container. This
218// makes for a very odd looking filter combo. So, we manually add our
219// container below the action bar.
220#if GTK_CHECK_VERSION(3,0,0)
221 GtkWidget *actionbar = find_widget(m_widget, "GtkActionBar", 0);
222 if (actionbar)
223 {
224 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
225 gtk_container_add(GTK_CONTAINER(vbox), child->m_widget);
226 gtk_box_set_child_packing(GTK_BOX(vbox), child->m_widget, TRUE, TRUE, 0, GTK_PACK_START);
227 gtk_widget_show(vbox);
228
229 GtkWidget *abparent = gtk_widget_get_parent(actionbar);
230 gtk_container_add(GTK_CONTAINER(abparent), vbox);
231 gtk_box_set_child_packing(GTK_BOX(abparent), vbox, FALSE, FALSE, 0, GTK_PACK_END);
232 gtk_box_reorder_child(GTK_BOX(abparent), actionbar, -2);
233 }
234#else
235 gtk_file_chooser_set_extra_widget(
236 GTK_FILE_CHOOSER(m_widget), child->m_widget);
237#endif
238}
239
240//-----------------------------------------------------------------------------
241// FileDialog
242//-----------------------------------------------------------------------------
243
245
246BEGIN_EVENT_TABLE(FileDialog,FileDialogBase)
248 EVT_SIZE(FileDialog::OnSize)
250
251FileDialog::FileDialog(wxWindow *parent, const wxString& message,
252 const wxString& defaultDir,
253 const wxString& defaultFileName,
254 const wxString& wildCard,
255 long style, const wxPoint& pos,
256 const wxSize& sz,
257 const wxString& name)
259{
260 Create(parent, message, defaultDir, defaultFileName, wildCard, style, pos, sz, name);
261}
262
263bool FileDialog::Create(wxWindow *parent, const wxString& message,
264 const wxString& defaultDir,
265 const wxString& defaultFileName,
266 const wxString& wildCard,
267 long style, const wxPoint& pos,
268 const wxSize& sz,
269 const wxString& name)
270{
271 parent = GetParentForModalDialog(parent, style);
272
273 if (!FileDialogBase::Create(parent, message, defaultDir, defaultFileName,
274 wildCard, style, pos, sz, name))
275 {
276 return false;
277 }
278
279 if (!PreCreation(parent, pos, wxDefaultSize) ||
280 !CreateBase(parent, wxID_ANY, pos, wxDefaultSize, style,
281 wxDefaultValidator, wxT("filedialog")))
282 {
283 wxFAIL_MSG( wxT("FileDialog creation failed") );
284 return false;
285 }
286
287 GtkFileChooserAction gtk_action;
288 GtkWindow* gtk_parent = NULL;
289 if (parent)
290 gtk_parent = GTK_WINDOW( gtk_widget_get_toplevel(parent->m_widget) );
291
292 const gchar* ok_btn_stock;
293 if ( style & wxFD_SAVE )
294 {
295 gtk_action = GTK_FILE_CHOOSER_ACTION_SAVE;
296 ok_btn_stock = GTK_STOCK_SAVE;
297 }
298 else
299 {
300 gtk_action = GTK_FILE_CHOOSER_ACTION_OPEN;
301 ok_btn_stock = GTK_STOCK_OPEN;
302 }
303
304 m_widget = gtk_file_chooser_dialog_new(
305 wxGTK_CONV(m_message),
306 gtk_parent,
307 gtk_action,
308 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
309 ok_btn_stock, GTK_RESPONSE_ACCEPT,
310 NULL);
311 g_object_ref(m_widget);
312 GtkFileChooser* file_chooser = GTK_FILE_CHOOSER(m_widget);
313
314 m_fc.SetWidget(file_chooser);
315
316 gtk_dialog_set_default_response(GTK_DIALOG(m_widget), GTK_RESPONSE_ACCEPT);
317
318 if ( style & wxFD_MULTIPLE )
319 gtk_file_chooser_set_select_multiple(file_chooser, true);
320
321 // local-only property could be set to false to allow non-local files to be
322 // loaded. In that case get/set_uri(s) should be used instead of
323 // get/set_filename(s) everywhere and the GtkFileChooserDialog should
324 // probably also be created with a backend, e.g. "gnome-vfs", "default", ...
325 // (gtk_file_chooser_dialog_new_with_backend). Currently local-only is kept
326 // as the default - true:
327 // gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(m_widget), true);
328
329 g_signal_connect (m_widget, "response",
330 G_CALLBACK (gtk_filedialog_response_callback), this);
331
332 g_signal_connect (m_widget, "selection-changed",
333 G_CALLBACK (gtk_filedialog_selchanged_callback), this);
334
335 g_signal_connect (m_widget, "current-folder-changed",
336 G_CALLBACK (gtk_filedialog_folderchanged_callback), this);
337
338 g_signal_connect (m_widget, "notify::filter",
339 G_CALLBACK (gtk_filedialog_filterchanged_callback), this);
340
341 // deal with extensions/filters
342 SetWildcard(wildCard);
343
344 wxString defaultFileNameWithExt = defaultFileName;
345 if ( !wildCard.empty() && !defaultFileName.empty() &&
346 !wxFileName(defaultFileName).HasExt() )
347 {
348 // append the default extension, if any, to the initial file name: GTK
349 // won't do it for us by default (unlike e.g. MSW)
350 const wxFileName fnWC(m_fc.GetCurrentWildCard());
351 if ( fnWC.HasExt() )
352 {
353 // Notice that we shouldn't append the extension if it's a wildcard
354 // because this is not useful: the user would need to change it to use
355 // some fixed extension anyhow.
356 const wxString& ext = fnWC.GetExt();
357 if ( ext.find_first_of("?*") == wxString::npos )
358 defaultFileNameWithExt << "." << ext;
359 }
360 }
361
362
363 // if defaultDir is specified it should contain the directory and
364 // defaultFileName should contain the default name of the file, however if
365 // directory is not given, defaultFileName contains both
366 wxFileName fn;
367 if ( defaultDir.empty() )
368 fn.Assign(defaultFileNameWithExt);
369 else if ( !defaultFileNameWithExt.empty() )
370 fn.Assign(defaultDir, defaultFileNameWithExt);
371 else
372 fn.AssignDir(defaultDir);
373
374 // set the initial file name and/or directory
375 fn.MakeAbsolute(); // GTK+ needs absolute path
376 const wxString dir = fn.GetPath();
377 if ( !dir.empty() )
378 {
379 gtk_file_chooser_set_current_folder(file_chooser, wxGTK_CONV_FN(dir));
380 }
381
382 const wxString fname = fn.GetFullName();
383 if ( style & wxFD_SAVE )
384 {
385 if ( !fname.empty() )
386 {
387 gtk_file_chooser_set_current_name(file_chooser, wxGTK_CONV_FN(fname));
388 }
389
390#if GTK_CHECK_VERSION(2,7,3)
391 if ((style & wxFD_OVERWRITE_PROMPT)
392#ifndef __WXGTK3__
393 && gtk_check_version(2,7,3) == NULL
394#endif
395 )
396 {
397 gtk_file_chooser_set_do_overwrite_confirmation(file_chooser, true);
398 }
399#endif
400 }
401 else // wxFD_OPEN
402 {
403 if ( !fname.empty() )
404 {
405 gtk_file_chooser_set_filename(file_chooser,
406 wxGTK_CONV_FN(fn.GetFullPath()));
407 }
408 }
409
410 if ( style & wxFD_PREVIEW )
411 {
412 GtkWidget *previewImage = gtk_image_new();
413
414 gtk_file_chooser_set_preview_widget(file_chooser, previewImage);
415 g_signal_connect(m_widget, "update-preview",
417 previewImage);
418 }
419
420 return true;
421}
422
424{
425 if (m_extraControl)
426 {
427 // get chooser to drop its reference right now, allowing wxWindow dtor
428 // to verify that ref count drops to zero
429 gtk_file_chooser_set_extra_widget(
430 GTK_FILE_CHOOSER(m_widget), NULL);
431 }
432}
433
434void FileDialog::OnFakeOk(wxCommandEvent& WXUNUSED(event))
435{
436 // Update the current directory from here, accessing it later may not work
437 // due to the strange way GtkFileChooser works.
439 str(gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(m_widget)));
440 m_dir = wxString::FromUTF8(str);
441
442 EndDialog(wxID_OK);
443}
444
446{
447 WX_HOOK_MODAL_DIALOG();
448
449 // Create the root window
450 wxBoxSizer *verticalSizer = new wxBoxSizer(wxVERTICAL);
451 wxPanel *root = new wxPanel(this, wxID_ANY);
452
453 if (HasUserPaneCreator())
454 {
455 wxPanel *userpane = new wxPanel(root, wxID_ANY);
456 CreateUserPane(userpane);
457
458 wxBoxSizer *horizontalSizer = new wxBoxSizer(wxHORIZONTAL);
459 horizontalSizer->Add(userpane, 1, wxEXPAND, 0);
460 verticalSizer->Add(horizontalSizer, 1, wxEXPAND|wxALL, 0);
461 }
462
463 root->SetSizer(verticalSizer);
464 root->Layout();
465 verticalSizer->SetSizeHints(root);
466
467 // Send an initial filter changed event
469
470 return wxDialog::ShowModal();
471}
472
473// Change the currently displayed extension
474void FileDialog::SetFileExtension(const wxString& extension)
475{
476 wxString filename;
477
478#if defined(__WXGTK3__)
479 filename = wxString::FromUTF8(gtk_file_chooser_get_current_name(GTK_FILE_CHOOSER(m_widget)));
480#else
481 GtkWidget *entry = find_widget(m_widget, "GtkFileChooserEntry", 0);
482 if (entry)
483 {
484 filename = wxString::FromUTF8(gtk_entry_get_text(GTK_ENTRY(entry)));
485 }
486#endif
487
488 if (filename == wxEmptyString)
489 {
490 filename = m_fc.GetFilename();
491 }
492
493 if (filename != wxEmptyString)
494 {
495 wxFileName fn(filename);
496 fn.SetExt(extension);
497
498 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget), fn.GetFullName().utf8_str());
499 }
500}
501
502void FileDialog::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
503 int WXUNUSED(width), int WXUNUSED(height),
504 int WXUNUSED(sizeFlags))
505{
506}
507
508void FileDialog::OnSize(wxSizeEvent&)
509{
510 // avoid calling DoLayout(), which will set the (wrong) size of
511 // m_extraControl, its size is managed by GtkFileChooser
512}
513
514wxString FileDialog::GetPath() const
515{
516 return m_fc.GetPath();
517}
518
519void FileDialog::GetFilenames(wxArrayString& files) const
520{
521 m_fc.GetFilenames( files );
522}
523
524void FileDialog::GetPaths(wxArrayString& paths) const
525{
526 m_fc.GetPaths( paths );
527}
528
529void FileDialog::SetMessage(const wxString& message)
530{
531 m_message = message;
532 SetTitle(message);
533}
534
535void FileDialog::SetPath(const wxString& path)
536{
537 FileDialogBase::SetPath(path);
538
539 // Don't do anything if no path is specified, in particular don't set the
540 // path to m_dir below as this would result in opening the dialog in the
541 // parent directory of this one instead of m_dir itself.
542 if ( path.empty() )
543 return;
544
545 // we need an absolute path for GTK native chooser so ensure that we have
546 // it: use the initial directory if it was set or just CWD otherwise (this
547 // is the default behaviour if m_dir is empty)
548 wxFileName fn(path);
549 fn.MakeAbsolute(m_dir);
550 m_fc.SetPath(fn.GetFullPath());
551}
552
553void FileDialog::SetDirectory(const wxString& dir)
554{
555 FileDialogBase::SetDirectory(dir);
556
557 m_fc.SetDirectory(dir);
558}
559
560void FileDialog::SetFilename(const wxString& name)
561{
562 FileDialogBase::SetFilename(name);
563
564 if (HasFdFlag(wxFD_SAVE))
565 {
566 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget), wxGTK_CONV(name));
567 }
568
569 else
570 {
571 wxString path( GetDirectory() );
572 if (path.empty())
573 {
574 // SetPath() fires an assert if fed other than filepaths
575 return;
576 }
577 SetPath(wxFileName(path, name).GetFullPath());
578 }
579}
580
582{
583 wxString currentFilename( m_fc.GetFilename() );
584 if (currentFilename.empty())
585 {
586 // m_fc.GetFilename() will return empty until the dialog has been shown
587 // in which case use any previously provided value
588 currentFilename = m_fileName;
589 }
590 return currentFilename;
591}
592
593void FileDialog::SetWildcard(const wxString& wildCard)
594{
595 FileDialogBase::SetWildcard(wildCard);
596 m_fc.SetWildcard( GetWildcard() );
597}
598
599void FileDialog::SetFilterIndex(int filterIndex)
600{
601 m_fc.SetFilterIndex( filterIndex );
602}
603
605{
606 return m_fc.GetFilterIndex();
607}
608
609void FileDialog::GTKSelectionChanged(const wxString& filename)
610{
611 m_currentlySelectedFilename = filename;
612
613 wxFileCtrlEvent event(wxEVT_FILECTRL_SELECTIONCHANGED, this, GetId());
614
615 wxArrayString filenames;
616 GetFilenames(filenames);
617
618 event.SetDirectory(GetDirectory());
619 event.SetFiles(filenames);
620
621 GetEventHandler()->ProcessEvent(event);
622}
623
625{
626 wxFileCtrlEvent event(wxEVT_FILECTRL_FOLDERCHANGED, this, GetId());
627
628 event.SetDirectory(GetDirectory());
629
630 GetEventHandler()->ProcessEvent(event);
631}
632
634{
635 wxFileName filename;
636
637#if defined(__WXGTK3__)
638 filename.SetFullName(wxString::FromUTF8(gtk_file_chooser_get_current_name(GTK_FILE_CHOOSER(m_widget))));
639#else
640 GtkWidget *entry = find_widget(m_widget, "GtkFileChooserEntry", 0);
641 if (entry)
642 {
643 filename.SetFullName(wxString::FromUTF8(gtk_entry_get_text(GTK_ENTRY(entry))));
644 }
645#endif
646
647 if (filename.HasName())
648 {
649 wxString ext = m_fc.GetCurrentWildCard().AfterLast(wxT('.')).Lower();
650 if (!ext.empty() && ext != wxT("*") && ext != filename.GetExt())
651 {
652 SetFileExtension(ext);
653 }
654 }
655
656 wxFileCtrlEvent event(wxEVT_FILECTRL_FILTERCHANGED, this, GetId());
657
658 event.SetFilterIndex(GetFilterIndex());
659
660 GetEventHandler()->ProcessEvent(event);
661}
662
wxEVT_COMMAND_BUTTON_CLICKED
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
END_EVENT_TABLE()
#define str(a)
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
Definition: Distortion.cpp:82
#define XO(s)
Definition: Internat.h:31
IMPLEMENT_DYNAMIC_CLASS(PluginHostModule, wxModule)
static ProjectFileIORegistry::AttributeWriterEntry entry
static const auto fn
void CreateUserPane(wxWindow *parent)
Definition: FileDialog.cpp:36
virtual bool HasUserPaneCreator() const
Definition: FileDialog.cpp:25
Dialog used to present platform specific "Save As" dialog with custom controls.
virtual void SetDirectory(const wxString &dir)
virtual int GetFilterIndex() const
virtual wxString GetPath() const
virtual wxString GetFilename() const
virtual void SetFileExtension(const wxString &extension)
virtual void SetPath(const wxString &path)
wxString GetFullPath(HWND hwnd, int itm)
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags=wxSIZE_AUTO)
virtual void GetFilenames(wxArrayString &files) const
virtual void GetPaths(wxArrayString &paths) const
void OnSize(wxSizeEvent &)
void GTKSelectionChanged(const wxString &filename)
virtual void SetMessage(const wxString &message)
virtual void SetFilename(const wxString &name)
void OnFakeOk(wxCommandEvent &event)
virtual void SetFilterIndex(int filterIndex)
wxGtkFileChooser m_fc
virtual void AddChildGTK(wxWindowGTK *child)
virtual void SetWildcard(const wxString &wildCard)
virtual int ShowModal()
bool Create(wxWindow *parent, const wxString &message=wxFileSelectorPromptStr, const wxString &defaultDir=wxEmptyString, const wxString &defaultFile=wxEmptyString, const wxString &wildCard=wxFileSelectorDefaultWildcardStr, long style=wxFD_DEFAULT_STYLE, const wxPoint &pos=wxDefaultPosition, const wxSize &sz=wxDefaultSize, const wxString &name=wxFileDialogNameStr)
Abstract base class used in importing a file.
const gchar * c_str() const
wxDECLARE_NO_COPY_CLASS(wxGtkString)
static void gtk_filedialog_response_callback(GtkWidget *w, gint response, FileDialog *dialog)
#define wxGTK_CONV_FN(s)
static void gtk_filedialog_update_preview_callback(GtkFileChooser *chooser, gpointer user_data)
static void gtk_filedialog_folderchanged_callback(GtkFileChooser *chooser, FileDialog *dialog)
static void gtk_filedialog_ok_callback(GtkWidget *widget, FileDialog *dialog)
static void gtk_filedialog_selchanged_callback(GtkFileChooser *chooser, FileDialog *dialog)
static GtkWidget * find_widget(GtkWidget *parent, const gchar *name, int depth)
#define wxGTK_CONV(s)
static void gtk_filedialog_filterchanged_callback(GtkFileChooser *chooser, GParamSpec *pspec, FileDialog *dialog)
static void gtk_filedialog_cancel_callback(GtkWidget *WXUNUSED(w), FileDialog *dialog)