Bug 1166741 - Workaround for GTK3 bug where file choosers' delegate refcount is not incremented. r=karlt

This commit is contained in:
Andrew Comminos 2015-05-22 06:36:00 +02:00
parent 738c61b043
commit bc21a07a15
3 changed files with 41 additions and 1 deletions

View File

@ -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)

View File

@ -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<GtkFileChooserWidget**>(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;

View File

@ -73,6 +73,8 @@ protected:
private:
static nsIFile *mPrevDisplayDirectory;
GtkFileChooserWidget *mFileChooserDelegate;
};
#endif