From bc21a07a15f43bcc45d3820e8de02fcbe64056c4 Mon Sep 17 00:00:00 2001 From: Andrew Comminos Date: Fri, 22 May 2015 06:36:00 +0200 Subject: [PATCH] Bug 1166741 - Workaround for GTK3 bug where file choosers' delegate refcount is not incremented. r=karlt --- widget/gtk/mozgtk/mozgtk.c | 1 + widget/gtk/nsFilePicker.cpp | 39 ++++++++++++++++++++++++++++++++++++- widget/gtk/nsFilePicker.h | 2 ++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/widget/gtk/mozgtk/mozgtk.c b/widget/gtk/mozgtk/mozgtk.c index 19822e23592..de7b3773796 100644 --- a/widget/gtk/mozgtk/mozgtk.c +++ b/widget/gtk/mozgtk/mozgtk.c @@ -209,6 +209,7 @@ STUB(gtk_file_chooser_set_local_only) STUB(gtk_file_chooser_set_preview_widget) STUB(gtk_file_chooser_set_preview_widget_active) STUB(gtk_file_chooser_set_select_multiple) +STUB(gtk_file_chooser_widget_get_type) STUB(gtk_file_filter_add_pattern) STUB(gtk_file_filter_new) STUB(gtk_file_filter_set_name) diff --git a/widget/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp index 0b5a8dcc4b2..7aeefac1f28 100644 --- a/widget/gtk/nsFilePicker.cpp +++ b/widget/gtk/nsFilePicker.cpp @@ -165,7 +165,8 @@ NS_IMPL_ISUPPORTS(nsFilePicker, nsIFilePicker) nsFilePicker::nsFilePicker() : mSelectedType(0), mRunning(false), - mAllowURLs(false) + mAllowURLs(false), + mFileChooserDelegate(nullptr) { } @@ -431,6 +432,27 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback) } else { nsAutoCString directory; defaultPath->GetNativePath(directory); + +#if (MOZ_WIDGET_GTK == 3) + // Workaround for problematic refcounting in GTK3 before 3.16. + // We need to keep a reference to the dialog's internal delegate. + // Otherwise, if our dialog gets destroyed, we'll lose the dialog's + // delegate by the time this gets processed in the event loop. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1166741 + GtkDialog *dialog = GTK_DIALOG(file_chooser); + GtkContainer *area = GTK_CONTAINER(gtk_dialog_get_content_area(dialog)); + gtk_container_forall(area, [](GtkWidget *widget, + gpointer data) { + if (GTK_IS_FILE_CHOOSER_WIDGET(widget)) { + auto result = static_cast(data); + *result = GTK_FILE_CHOOSER_WIDGET(widget); + } + }, &mFileChooserDelegate); + + if (mFileChooserDelegate) + g_object_ref(mFileChooserDelegate); +#endif + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), directory.get()); } @@ -548,6 +570,21 @@ nsFilePicker::Done(GtkWidget* file_chooser, gint response) // been released. gtk_widget_destroy(file_chooser); +#if (MOZ_WIDGET_GTK == 3) + if (mFileChooserDelegate) { + // Properly deref our acquired reference. We call this after + // gtk_widget_destroy() to try and ensure that pending file info + // queries caused by updating the current folder have been cancelled. + // However, we do not know for certain when the callback will run after + // cancelled. + g_idle_add([](gpointer data) -> gboolean { + g_object_unref(data); + return G_SOURCE_REMOVE; + }, mFileChooserDelegate); + mFileChooserDelegate = nullptr; + } +#endif + if (mCallback) { mCallback->Done(result); mCallback = nullptr; diff --git a/widget/gtk/nsFilePicker.h b/widget/gtk/nsFilePicker.h index 452ebf7ce4a..fbd1ae68925 100644 --- a/widget/gtk/nsFilePicker.h +++ b/widget/gtk/nsFilePicker.h @@ -73,6 +73,8 @@ protected: private: static nsIFile *mPrevDisplayDirectory; + + GtkFileChooserWidget *mFileChooserDelegate; }; #endif