summaryrefslogtreecommitdiff
path: root/gtk/gtkfilechoosernativewin32.c
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2015-10-29 15:06:57 +0100
committerAlexander Larsson <alexl@redhat.com>2015-11-05 16:54:07 +0100
commit5094900180ac97e6bba2f86ee702d0649e019e6a (patch)
tree7527ba2439f350f7c0c75ce7af0c52ff038c9ded /gtk/gtkfilechoosernativewin32.c
parent693db082a158952efd5a326a62814490c3c8f6ad (diff)
downloadgtk+-5094900180ac97e6bba2f86ee702d0649e019e6a.tar.gz
GtkFileChooserNative: Fallback and win32 implementation
This is a subclass on GtkNativeDialog that uses GtkFileChooserDialog as a fallback, but also has support for the win32 file chooser dialog.
Diffstat (limited to 'gtk/gtkfilechoosernativewin32.c')
-rw-r--r--gtk/gtkfilechoosernativewin32.c778
1 files changed, 778 insertions, 0 deletions
diff --git a/gtk/gtkfilechoosernativewin32.c b/gtk/gtkfilechoosernativewin32.c
new file mode 100644
index 0000000000..9e60e276d4
--- /dev/null
+++ b/gtk/gtkfilechoosernativewin32.c
@@ -0,0 +1,778 @@
+/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
+/* GTK - The GIMP Toolkit
+ * gtkfilechoosernativewin32.c: Win32 Native File selector dialog
+ * Copyright (C) 2015, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gtkfilechoosernativeprivate.h"
+#include "gtknativedialogprivate.h"
+
+#include "gtkprivate.h"
+#include "gtkfilechooserdialog.h"
+#include "gtkfilechooserprivate.h"
+#include "gtkfilechooserwidget.h"
+#include "gtkfilechooserwidgetprivate.h"
+#include "gtkfilechooserutils.h"
+#include "gtkfilechooserembed.h"
+#include "gtkfilesystem.h"
+#include "gtksizerequest.h"
+#include "gtktypebuiltins.h"
+#include "gtkintl.h"
+#include "gtksettings.h"
+#include "gtktogglebutton.h"
+#include "gtkstylecontext.h"
+#include "gtkheaderbar.h"
+#include "gtklabel.h"
+#include "gtkfilechooserentry.h"
+#include "gtkfilefilterprivate.h"
+
+/* Vista or newer */
+#define _WIN32_WINNT 0x0600
+#define WINVER _WIN32_WINNT
+#define NTDDI_VERSION NTDDI_VISTA
+#define COBJMACROS
+
+#include "win32/gdkwin32.h"
+#include <shlobj.h>
+#include <windows.h>
+
+typedef struct {
+ GtkFileChooserNative *self;
+ IFileDialogEvents *events;
+
+ HWND parent;
+ gboolean skip_response;
+ gboolean save;
+ gboolean folder;
+ gboolean modal;
+ gboolean overwrite_confirmation;
+ gboolean select_multiple;
+ gboolean show_hidden;
+
+ char *accept_label;
+ char *cancel_label;
+ char *title;
+
+ GSList *shortcut_uris;
+
+ GFile *current_folder;
+ GFile *current_file;
+ char *current_name;
+
+ COMDLG_FILTERSPEC *filters;
+
+ GSList *files;
+ int response;
+} FilechooserWin32ThreadData;
+
+static void
+g_warning_hr (const char *msg, HRESULT hr)
+{
+ char *errmsg;
+ errmsg = g_win32_error_message (hr);
+ g_warning ("%s: %s\n", msg, errmsg);
+ g_free (errmsg);
+}
+
+/* {3CAFD12E-82AE-4184-8309-848C0104B4DC} */
+static const GUID myIID_IFileDialogEvents =
+{ 0x3cafd12e, 0x82ae, 0x4184, { 0x83, 0x9, 0x84, 0x8c, 0x1, 0x4, 0xb4, 0xdc } };
+
+/* Protects access to dialog_hwnd, do_close and ref_count */
+G_LOCK_DEFINE_STATIC(FileDialogEvents);
+
+typedef struct {
+ IFileDialogEvents iFileDialogEvents;
+ int ref_count;
+ gboolean enable_owner;
+ gboolean got_hwnd;
+ HWND dialog_hwnd;
+ gboolean do_close; /* Set if hide was called before dialog_hwnd was set */
+} FileDialogEvents;
+
+
+static ULONG STDMETHODCALLTYPE
+ifiledialogevents_AddRef (IFileDialogEvents *self)
+{
+ FileDialogEvents *events = (FileDialogEvents *)self;
+ ULONG ref_count;
+
+ G_LOCK (FileDialogEvents);
+ ref_count = ++events->ref_count;
+ G_UNLOCK (FileDialogEvents);
+
+ return ref_count;
+}
+
+static ULONG STDMETHODCALLTYPE
+ifiledialogevents_Release (IFileDialogEvents *self)
+{
+ FileDialogEvents *events = (FileDialogEvents *)self;
+ int ref_count;
+
+ G_LOCK (FileDialogEvents);
+ ref_count = --events->ref_count;
+ G_UNLOCK (FileDialogEvents);
+
+ if (ref_count == 0)
+ g_free (self);
+
+ return ref_count;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ifiledialogevents_QueryInterface (IFileDialogEvents *self,
+ REFIID riid,
+ LPVOID *ppvObject)
+{
+ if (IsEqualIID (riid, &IID_IUnknown) ||
+ IsEqualIID (riid, &myIID_IFileDialogEvents))
+ {
+ *ppvObject = self;
+ IUnknown_AddRef ((IUnknown *)self);
+ return NOERROR;
+ }
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+static HRESULT STDMETHODCALLTYPE
+ifiledialogevents_OnFileOk (IFileDialogEvents *self,
+ IFileDialog *pfd)
+{
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ifiledialogevents_OnFolderChanging (IFileDialogEvents *self,
+ IFileDialog *pfd,
+ IShellItem *psiFolder)
+{
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ifiledialogevents_OnFolderChange (IFileDialogEvents *self,
+ IFileDialog *pfd)
+{
+ FileDialogEvents *events = (FileDialogEvents *)self;
+ IOleWindow *olew = NULL;
+ HWND dialog_hwnd;
+ HRESULT hr;
+
+ if (!events->got_hwnd)
+ {
+ events->got_hwnd = TRUE;
+
+ hr = IFileDialog_QueryInterface (pfd, &IID_IOleWindow, &olew);
+ if (SUCCEEDED (hr))
+ {
+ hr = IOleWindow_GetWindow (olew, &dialog_hwnd);
+ if (SUCCEEDED (hr))
+ {
+ G_LOCK (FileDialogEvents);
+ events->dialog_hwnd = dialog_hwnd;
+ if (events->do_close)
+ SendMessage (events->dialog_hwnd, WM_CLOSE, 0, 0);
+ G_UNLOCK (FileDialogEvents);
+ }
+ else
+ g_warning_hr ("Can't get HWND", hr);
+
+ hr = IOleWindow_Release (olew);
+ if (FAILED (hr))
+ g_warning_hr ("Can't unref IOleWindow", hr);
+ }
+ else
+ g_warning_hr ("Can't get IOleWindow", hr);
+
+ if (events->enable_owner && events->dialog_hwnd)
+ {
+ HWND owner = GetWindow (events->dialog_hwnd, GW_OWNER);
+ if (owner)
+ EnableWindow (owner, TRUE);
+ }
+ }
+
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ifiledialogevents_OnSelectionChange (IFileDialogEvents * self,
+ IFileDialog *pfd)
+{
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ifiledialogevents_OnShareViolation (IFileDialogEvents * self,
+ IFileDialog *pfd,
+ IShellItem *psi,
+ FDE_SHAREVIOLATION_RESPONSE *pResponse)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ifiledialogevents_OnTypeChange (IFileDialogEvents * self,
+ IFileDialog *pfd)
+{
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ifiledialogevents_OnOverwrite (IFileDialogEvents * self,
+ IFileDialog *pfd,
+ IShellItem *psi,
+ FDE_OVERWRITE_RESPONSE *pResponse)
+{
+ return E_NOTIMPL;
+}
+
+static IFileDialogEventsVtbl ifde_vtbl = {
+ ifiledialogevents_QueryInterface,
+ ifiledialogevents_AddRef,
+ ifiledialogevents_Release,
+ ifiledialogevents_OnFileOk,
+ ifiledialogevents_OnFolderChanging,
+ ifiledialogevents_OnFolderChange,
+ ifiledialogevents_OnSelectionChange,
+ ifiledialogevents_OnShareViolation,
+ ifiledialogevents_OnTypeChange,
+ ifiledialogevents_OnOverwrite
+};
+
+file_dialog_events_send_close (IFileDialogEvents *self)
+{
+ FileDialogEvents *events = (FileDialogEvents *)self;
+
+ G_LOCK (FileDialogEvents);
+
+ if (events->dialog_hwnd)
+ SendMessage (events->dialog_hwnd, WM_CLOSE, 0, 0);
+ else
+ events->do_close = TRUE;
+
+ G_UNLOCK (FileDialogEvents);
+}
+
+static IFileDialogEvents *
+file_dialog_events_new (gboolean enable_owner)
+{
+ FileDialogEvents *events;
+
+ events = g_new0 (FileDialogEvents, 1);
+ events->iFileDialogEvents.lpVtbl = &ifde_vtbl;
+ events->ref_count = 1;
+ events->enable_owner = enable_owner;
+
+ return &events->iFileDialogEvents;
+}
+
+static void
+filechooser_win32_thread_data_free (FilechooserWin32ThreadData *data)
+{
+ int i;
+ if (data->filters)
+ {
+ for (i = 0; data->filters[i].pszName != NULL; i++)
+ {
+ g_free ((char *)data->filters[i].pszName);
+ g_free ((char *)data->filters[i].pszSpec);
+ }
+ g_free (data->filters);
+ }
+
+ if (data->events)
+ IFileDialogEvents_Release (data->events);
+
+ g_clear_object (&data->current_folder);
+ g_clear_object (&data->current_file);
+ g_free (data->current_name);
+
+ g_slist_free_full (data->shortcut_uris, g_free);
+ g_slist_free_full (data->files, g_object_unref);
+ if (data->self)
+ g_object_unref (data->self);
+ g_free (data->accept_label);
+ g_free (data->cancel_label);
+ g_free (data->title);
+ g_free (data);
+}
+
+static gboolean
+filechooser_win32_thread_done (gpointer _data)
+{
+ FilechooserWin32ThreadData *data = _data;
+ GtkFileChooserNative *self = data->self;
+
+ self->mode_data = NULL;
+
+ if (!data->skip_response)
+ {
+ g_slist_free_full (self->custom_files, g_object_unref);
+ self->custom_files = data->files;
+ data->files = NULL;
+
+ _gtk_native_dialog_emit_response (GTK_NATIVE_DIALOG (data->self),
+ data->response);
+ }
+
+ filechooser_win32_thread_data_free (data);
+
+ return FALSE;
+}
+
+static void
+data_add_shell_item (FilechooserWin32ThreadData *data,
+ IShellItem *item)
+{
+ HRESULT hr;
+ PWSTR urlw = NULL;
+ char *url;
+
+ hr = IShellItem_GetDisplayName (item, SIGDN_URL, &urlw);
+ if (SUCCEEDED (hr))
+ {
+ url = g_utf16_to_utf8 (urlw, -1, NULL, NULL, NULL);
+ CoTaskMemFree (urlw);
+ data->files = g_slist_prepend (data->files, g_file_new_for_uri (url));
+ data->response = GTK_RESPONSE_ACCEPT;
+ g_free (url);
+ }
+}
+
+static IShellItem *
+get_shell_item_for_uri (const char *uri)
+{
+ IShellItem *item;
+ HRESULT hr;
+ gunichar2 *uri_w = g_utf8_to_utf16 (uri, -1, NULL, NULL, NULL);
+
+ hr = SHCreateItemFromParsingName(uri_w, 0, &IID_IShellItem, &item);
+ if (SUCCEEDED (hr))
+ return item;
+ else
+ g_warning_hr ("Can't create shell item from shortcut", hr);
+
+ return NULL;
+}
+
+static IShellItem *
+get_shell_item_for_file (GFile *file)
+{
+ char *uri;
+ IShellItem *item;
+
+ uri = g_file_get_uri (file);
+ item = get_shell_item_for_uri (uri);
+ g_free (uri);
+
+ return item;
+}
+
+static gpointer
+filechooser_win32_thread (gpointer _data)
+{
+ FilechooserWin32ThreadData *data = _data;
+ HRESULT hr;
+ IFileDialog *pfd = NULL;
+ IFileDialog2 *pfd2 = NULL;
+ gboolean res = FALSE;
+ DWORD flags;
+ HWND parent = NULL;
+ HWND dialog_hwnd;
+ GtkWindow *transient_for;
+ DWORD cookie;
+ GSList *l;
+
+ CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
+
+ if (data->save && !data->folder)
+ hr = CoCreateInstance (&CLSID_FileSaveDialog,
+ NULL, CLSCTX_INPROC_SERVER,
+ &IID_IFileSaveDialog, &pfd);
+ else
+ hr = CoCreateInstance (&CLSID_FileOpenDialog,
+ NULL, CLSCTX_INPROC_SERVER,
+ &IID_IFileOpenDialog, &pfd);
+
+ if (FAILED (hr))
+ g_error ("Can't create FileOpenDialog: %s\n", g_win32_error_message (hr));
+
+ hr = IFileDialog_GetOptions (pfd, &flags);
+ if (FAILED (hr))
+ g_error ("Can't get FileDialog options: %s\n", g_win32_error_message (hr));
+
+ flags |= FOS_FORCEFILESYSTEM;
+
+ if (data->folder)
+ flags |= FOS_PICKFOLDERS;
+
+ if (data->folder && data->save)
+ flags &= ~(FOS_FILEMUSTEXIST);
+
+ if (data->select_multiple)
+ flags |= FOS_ALLOWMULTISELECT;
+
+ if (data->show_hidden)
+ flags |= FOS_FORCESHOWHIDDEN;
+
+ if (data->overwrite_confirmation)
+ flags |= FOS_OVERWRITEPROMPT;
+ else
+ flags &= ~(FOS_OVERWRITEPROMPT);
+
+ hr = IFileDialog_SetOptions (pfd, flags);
+ if (FAILED (hr))
+ g_error ("Can't set FileDialog options: %s\n", g_win32_error_message (hr));
+
+ if (data->title)
+ {
+ gunichar2 *label = g_utf8_to_utf16 (data->title, -1,
+ NULL, NULL, NULL);
+ IFileDialog_SetTitle (pfd, label);
+ g_free (label);
+ }
+
+ if (data->accept_label)
+ {
+ gunichar2 *label = g_utf8_to_utf16 (data->accept_label, -1,
+ NULL, NULL, NULL);
+ IFileDialog_SetOkButtonLabel (pfd, label);
+ g_free (label);
+ }
+
+ if (data->cancel_label)
+ {
+ gunichar2 *label = g_utf8_to_utf16 (data->cancel_label, -1,
+ NULL, NULL, NULL);
+ hr = IFileDialog_QueryInterface (pfd, &IID_IFileDialog2, &pfd2);
+ if (SUCCEEDED (hr))
+ {
+ IFileDialog2_SetCancelButtonLabel (pfd2, label);
+ IFileDialog2_Release (pfd2);
+ }
+ g_free (label);
+ }
+
+ for (l = data->shortcut_uris; l != NULL; l = l->next)
+ {
+ IShellItem *item = get_shell_item_for_uri (l->data);
+ if (item)
+ {
+ hr = IFileDialog_AddPlace (pfd, item, FDAP_BOTTOM);
+ if (FAILED (hr))
+ g_warning_hr ("Can't add dialog shortcut", hr);
+ IShellItem_Release (item);
+ }
+ }
+
+ if (data->current_file)
+ {
+ IFileSaveDialog *pfsd;
+ hr = IFileDialog_QueryInterface (pfd, &IID_IFileSaveDialog, &pfsd);
+ if (SUCCEEDED (hr))
+ {
+ IShellItem *item = get_shell_item_for_file (data->current_file);
+ if (item)
+ {
+ hr = IFileSaveDialog_SetSaveAsItem (pfsd, item);
+ if (FAILED (hr))
+ g_warning_hr ("Can't set save as item", hr);
+ IShellItem_Release (item);
+ }
+ IFileSaveDialog_Release (pfsd);
+ }
+ }
+
+ if (data->current_folder)
+ {
+ IShellItem *item = get_shell_item_for_file (data->current_folder);
+ if (item)
+ {
+ hr = IFileDialog_SetFolder (pfd, item);
+ if (FAILED (hr))
+ g_warning_hr ("Can't set folder", hr);
+ IShellItem_Release (item);
+ }
+ }
+
+ if (data->current_name)
+ {
+ gunichar2 *name = g_utf8_to_utf16 (data->current_name, -1, NULL, NULL, NULL);
+ hr = IFileDialog_SetFileName (pfd, name);
+ if (FAILED (hr))
+ g_warning_hr ("Can't set file name", hr);
+ g_free (name);
+ }
+
+ if (data->filters)
+ {
+ int n;
+ for (n = 0; data->filters[n].pszName != NULL; n++)
+ {}
+ hr = IFileDialog_SetFileTypes (pfd, n, data->filters);
+ if (FAILED (hr))
+ g_warning_hr ("Can't set file types", hr);
+ }
+
+ data->response = GTK_RESPONSE_CANCEL;
+
+ hr = IFileDialog_Advise (pfd, data->events, &cookie);
+ if (FAILED (hr))
+ g_error ("Can't Advise FileDialog: %s\n", g_win32_error_message (hr));
+
+ hr = IFileDialog_Show (pfd, data->parent);
+ if (SUCCEEDED (hr))
+ {
+ IFileOpenDialog *pfod = NULL;
+ hr = IFileDialog_QueryInterface (pfd,&IID_IFileOpenDialog, &pfod);
+
+ if (SUCCEEDED (hr))
+ {
+ IShellItemArray *res;
+ DWORD i, count;
+
+ hr = IFileOpenDialog_GetResults (pfod, &res);
+ if (FAILED (hr))
+ g_error ("Can't get FileOpenDialog results: %s\n", g_win32_error_message (hr));
+
+ hr = IShellItemArray_GetCount (res, &count);
+ if (FAILED (hr))
+ g_error ("Can't get FileOpenDialog count: %s\n", g_win32_error_message (hr));
+
+ for (i = 0; i < count; i++)
+ {
+ IShellItem *item;
+ hr = IShellItemArray_GetItemAt (res, i, &item);
+ if (FAILED (hr))
+ g_error ("Can't get item at %d: %s\n", i, g_win32_error_message (hr));
+ data_add_shell_item (data, item);
+ IShellItem_Release (item);
+ }
+ IShellItemArray_Release (res);
+
+ IFileOpenDialog_Release (pfod);
+ }
+ else
+ {
+ IShellItem *item;
+ hr = IFileDialog_GetResult (pfd, &item);
+ if (FAILED (hr))
+ g_error ("Can't get FileDialog result: %s\n", g_win32_error_message (hr));
+
+ data_add_shell_item (data, item);
+ IShellItem_Release (item);
+ }
+ }
+
+ hr = IFileDialog_Unadvise (pfd, cookie);
+ if (FAILED (hr))
+ g_error ("Can't Unadvise FileDialog: %s\n", g_win32_error_message (hr));
+
+ IFileDialog_Release ((IUnknown *)pfd);
+
+ g_main_context_invoke (NULL,
+ filechooser_win32_thread_done,
+ data);
+
+ return NULL;
+}
+
+static gboolean
+file_filter_to_win32 (GtkFileFilter *filter,
+ COMDLG_FILTERSPEC *spec)
+{
+ const char *name;
+ char **patterns;
+ char *pattern_list;
+
+ patterns = _gtk_file_filter_get_as_patterns (filter);
+ if (patterns == NULL)
+ return FALSE;
+
+ pattern_list = g_strjoinv (";", patterns);
+ g_strfreev (patterns);
+
+ name = gtk_file_filter_get_name (filter);
+ if (name == NULL)
+ name = pattern_list;
+ spec->pszName = g_utf8_to_utf16 (name, -1, NULL, NULL, NULL);
+ spec->pszSpec = g_utf8_to_utf16 (pattern_list, -1, NULL, NULL, NULL);
+
+ g_free (pattern_list);
+
+ return TRUE;
+}
+
+static char *
+translate_mnemonics (const char *src)
+{
+ GString *s;
+ const char *p;
+ char c;
+
+ if (src == NULL)
+ return NULL;
+
+ s = g_string_sized_new (strlen (src));
+
+ for (p = src; *p; p++)
+ {
+ c = *p;
+ switch (c)
+ {
+ case '_':
+ /* __ is _ escaped */
+ if (*(p+1) == '_')
+ {
+ g_string_append_c (s, '_');
+ p++;
+ }
+ else
+ g_string_append_c (s, '&');
+ break;
+ case '&':
+ /* Win32 needs ampersands escaped */
+ g_string_append (s, "&&");
+ default:
+ g_string_append_c (s, c);
+ }
+ }
+
+ return g_string_free (s, FALSE);
+}
+
+gboolean
+gtk_file_chooser_native_win32_show (GtkFileChooserNative *self)
+{
+ GThread *thread;
+ FilechooserWin32ThreadData *data;
+ GtkWindow *transient_for;
+ GtkFileChooserAction action;
+ guint update_preview_signal;
+ GSList *filters, *l;
+ int n_filters, i;
+ COMDLG_FILTERSPEC *win32_filters;
+
+ if (gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (self)) != NULL)
+ return FALSE;
+
+ update_preview_signal = g_signal_lookup ("update-preview", GTK_TYPE_FILE_CHOOSER);
+ if (g_signal_has_handler_pending (self, update_preview_signal, 0, TRUE))
+ return FALSE;
+
+ data = g_new0 (FilechooserWin32ThreadData, 1);
+
+ filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self));
+ n_filters = g_slist_length (filters);
+ if (n_filters > 0)
+ {
+ data->filters = g_new0 (COMDLG_FILTERSPEC, n_filters + 1);
+
+ for (l = filters, i = 0; l != NULL; l = l->next, i++)
+ {
+ if (!file_filter_to_win32 (l->data, &data->filters[i]))
+ {
+ filechooser_win32_thread_data_free (data);
+ return FALSE;
+ }
+ }
+ }
+
+ self->mode_data = data;
+ data->self = g_object_ref (self);
+
+ data->shortcut_uris =
+ gtk_file_chooser_list_shortcut_folder_uris (GTK_FILE_CHOOSER (self->dialog));
+
+ data->accept_label = translate_mnemonics (self->accept_label);
+ data->cancel_label = translate_mnemonics (self->cancel_label);
+
+ action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (self->dialog));
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE ||
+ action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ data->save = TRUE;
+
+ if (action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+ action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ data->folder = TRUE;
+
+ if ((action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+ action == GTK_FILE_CHOOSER_ACTION_OPEN) &&
+ gtk_file_chooser_get_select_multiple (GTK_FILE_CHOOSER (self->dialog)))
+ data->select_multiple = TRUE;
+
+ if (gtk_file_chooser_get_do_overwrite_confirmation (GTK_FILE_CHOOSER (self->dialog)))
+ data->overwrite_confirmation = TRUE;
+
+ if (gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (self->dialog)))
+ data->show_hidden = TRUE;
+
+ transient_for = gtk_native_dialog_get_transient_for (GTK_NATIVE_DIALOG (self));
+ if (transient_for)
+ {
+ gtk_widget_realize (GTK_WIDGET (transient_for));
+ data->parent = gdk_win32_window_get_handle (gtk_widget_get_window (GTK_WIDGET (transient_for)));
+
+ if (gtk_native_dialog_get_modal (GTK_NATIVE_DIALOG (self)))
+ data->modal = TRUE;
+ }
+
+ data->title =
+ g_strdup (gtk_native_dialog_get_title (GTK_NATIVE_DIALOG (self)));
+
+ if (self->current_file)
+ data->current_file = g_object_ref (self->current_file);
+ else
+ {
+ if (self->current_folder)
+ data->current_folder = g_object_ref (self->current_folder);
+
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE ||
+ action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ data->current_name = g_strdup (self->current_name);
+ }
+
+ data->events = file_dialog_events_new (!data->modal);
+
+ thread = g_thread_new ("win32 filechooser", filechooser_win32_thread, data);
+ if (thread == NULL)
+ {
+ filechooser_win32_thread_data_free (data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+gtk_file_chooser_native_win32_hide (GtkFileChooserNative *self)
+{
+ FilechooserWin32ThreadData *data = self->mode_data;
+
+ /* This is always set while dialog visible */
+ g_assert (data != NULL);
+
+ data->skip_response = TRUE;
+ file_dialog_events_send_close (data->events);
+}