Use xdg-desktop-portal for file selection dialogs on Linux.
This commit is contained in:
parent
9998b2436a
commit
aee84ebc64
|
@ -4019,6 +4019,12 @@ pref("autocomplete.ungrab_during_mode_switch", true);
|
|||
// toggling to use the XUL filepicker
|
||||
pref("ui.allow_platform_file_picker", true);
|
||||
|
||||
// Allow for using the native GTK file picker. If the application is not run
|
||||
// with GTK_USE_PORTAL=1 this pref has no effect.
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
pref("widget.allow-gtk-native-file-chooser", false);
|
||||
#endif
|
||||
|
||||
pref("helpers.global_mime_types_file", "/etc/mime.types");
|
||||
pref("helpers.global_mailcap_file", "/etc/mailcap");
|
||||
pref("helpers.private_mime_types_file", "~/.mime.types");
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "nsNetUtil.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "mozcontainer.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "nsFilePicker.h"
|
||||
|
||||
|
@ -175,6 +176,7 @@ nsFilePicker::nsFilePicker()
|
|||
, mFileChooserDelegate(nullptr)
|
||||
#endif
|
||||
{
|
||||
mUseNativeFileChooser = Preferences::GetBool("widget.allow-gtk-native-file-chooser", false);
|
||||
}
|
||||
|
||||
nsFilePicker::~nsFilePicker()
|
||||
|
@ -197,7 +199,7 @@ ReadMultipleFiles(gpointer filename, gpointer array)
|
|||
}
|
||||
|
||||
void
|
||||
nsFilePicker::ReadValuesFromFileChooser(GtkWidget *file_chooser)
|
||||
nsFilePicker::ReadValuesFromFileChooser(void *file_chooser)
|
||||
{
|
||||
mFiles.Clear();
|
||||
|
||||
|
@ -389,19 +391,10 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback)
|
|||
if (!mOkButtonLabel.IsEmpty()) {
|
||||
accept_button = buttonLabel.get();
|
||||
} else {
|
||||
accept_button = (action == GTK_FILE_CHOOSER_ACTION_SAVE) ?
|
||||
GTK_STOCK_SAVE : GTK_STOCK_OPEN;
|
||||
accept_button = nullptr;
|
||||
}
|
||||
|
||||
GtkWidget *file_chooser =
|
||||
gtk_file_chooser_dialog_new(title, parent_widget, action,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
accept_button, GTK_RESPONSE_ACCEPT,
|
||||
nullptr);
|
||||
gtk_dialog_set_alternative_button_order(GTK_DIALOG(file_chooser),
|
||||
GTK_RESPONSE_ACCEPT,
|
||||
GTK_RESPONSE_CANCEL,
|
||||
-1);
|
||||
void *file_chooser = GtkFileChooserNew(title.get(), parent_widget, action, accept_button);
|
||||
if (mAllowURLs) {
|
||||
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), FALSE);
|
||||
}
|
||||
|
@ -412,11 +405,7 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback)
|
|||
g_signal_connect(file_chooser, "update-preview", G_CALLBACK(UpdateFilePreviewWidget), img_preview);
|
||||
}
|
||||
|
||||
GtkWindow *window = GTK_WINDOW(file_chooser);
|
||||
gtk_window_set_modal(window, TRUE);
|
||||
if (parent_widget) {
|
||||
gtk_window_set_destroy_with_parent(window, TRUE);
|
||||
}
|
||||
GtkFileChooserSetModal(file_chooser, parent_widget, TRUE);
|
||||
|
||||
NS_ConvertUTF16toUTF8 defaultName(mDefault);
|
||||
switch (mMode) {
|
||||
|
@ -454,18 +443,21 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback)
|
|||
// 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 (GTK_IS_DIALOG(file_chooser)) {
|
||||
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);
|
||||
if (mFileChooserDelegate) {
|
||||
g_object_ref(mFileChooserDelegate);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser),
|
||||
|
@ -473,7 +465,9 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback)
|
|||
}
|
||||
}
|
||||
|
||||
gtk_dialog_set_default_response(GTK_DIALOG(file_chooser), GTK_RESPONSE_ACCEPT);
|
||||
if (GTK_IS_DIALOG(file_chooser)) {
|
||||
gtk_dialog_set_default_response(GTK_DIALOG(file_chooser), GTK_RESPONSE_ACCEPT);
|
||||
}
|
||||
|
||||
int32_t count = mFilters.Length();
|
||||
for (int32_t i = 0; i < count; ++i) {
|
||||
|
@ -517,14 +511,13 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback)
|
|||
mCallback = aCallback;
|
||||
NS_ADDREF_THIS();
|
||||
g_signal_connect(file_chooser, "response", G_CALLBACK(OnResponse), this);
|
||||
g_signal_connect(file_chooser, "destroy", G_CALLBACK(OnDestroy), this);
|
||||
gtk_widget_show(file_chooser);
|
||||
GtkFileChooserShow(file_chooser);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsFilePicker::OnResponse(GtkWidget* file_chooser, gint response_id,
|
||||
nsFilePicker::OnResponse(void* file_chooser, gint response_id,
|
||||
gpointer user_data)
|
||||
{
|
||||
static_cast<nsFilePicker*>(user_data)->
|
||||
|
@ -539,7 +532,7 @@ nsFilePicker::OnDestroy(GtkWidget* file_chooser, gpointer user_data)
|
|||
}
|
||||
|
||||
void
|
||||
nsFilePicker::Done(GtkWidget* file_chooser, gint response)
|
||||
nsFilePicker::Done(void* file_chooser, gint response)
|
||||
{
|
||||
mRunning = false;
|
||||
|
||||
|
@ -583,7 +576,7 @@ nsFilePicker::Done(GtkWidget* file_chooser, gint response)
|
|||
// requests that any remaining references be released, but the reference
|
||||
// count will not be decremented again if GtkWindow's reference has already
|
||||
// been released.
|
||||
gtk_widget_destroy(file_chooser);
|
||||
GtkFileChooserDestroy(file_chooser);
|
||||
|
||||
#if (MOZ_WIDGET_GTK == 3)
|
||||
if (mFileChooserDelegate) {
|
||||
|
@ -608,3 +601,73 @@ nsFilePicker::Done(GtkWidget* file_chooser, gint response)
|
|||
}
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
|
||||
// All below functions available as of GTK 3.20+
|
||||
|
||||
void *
|
||||
nsFilePicker::GtkFileChooserNew(
|
||||
const gchar *title, GtkWindow *parent,
|
||||
GtkFileChooserAction action,
|
||||
const gchar *accept_label)
|
||||
{
|
||||
static auto sGtkFileChooserNativeNewPtr = (void * (*)(
|
||||
const gchar *, GtkWindow *,
|
||||
GtkFileChooserAction,
|
||||
const gchar *, const gchar *))
|
||||
dlsym(RTLD_DEFAULT, "gtk_file_chooser_native_new");
|
||||
if (mUseNativeFileChooser && sGtkFileChooserNativeNewPtr != nullptr) {
|
||||
return (*sGtkFileChooserNativeNewPtr)(title, parent, action, accept_label, nullptr);
|
||||
}
|
||||
if (accept_label == nullptr) {
|
||||
accept_label = (action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
? GTK_STOCK_SAVE : GTK_STOCK_OPEN;
|
||||
}
|
||||
GtkWidget *file_chooser = gtk_file_chooser_dialog_new(title, parent, action,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
accept_label, GTK_RESPONSE_ACCEPT, nullptr);
|
||||
gtk_dialog_set_alternative_button_order(GTK_DIALOG(file_chooser),
|
||||
GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1);
|
||||
return file_chooser;
|
||||
}
|
||||
|
||||
void
|
||||
nsFilePicker::GtkFileChooserShow(void *file_chooser)
|
||||
{
|
||||
static auto sGtkNativeDialogShowPtr = (void (*)(void *))
|
||||
dlsym(RTLD_DEFAULT, "gtk_native_dialog_show");
|
||||
if (mUseNativeFileChooser && sGtkNativeDialogShowPtr != nullptr) {
|
||||
(*sGtkNativeDialogShowPtr)(file_chooser);
|
||||
} else {
|
||||
g_signal_connect(file_chooser, "destroy", G_CALLBACK(OnDestroy), this);
|
||||
gtk_widget_show(GTK_WIDGET(file_chooser));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsFilePicker::GtkFileChooserDestroy(void *file_chooser)
|
||||
{
|
||||
static auto sGtkNativeDialogDestroyPtr = (void (*)(void *))
|
||||
dlsym(RTLD_DEFAULT, "gtk_native_dialog_destroy");
|
||||
if (mUseNativeFileChooser && sGtkNativeDialogDestroyPtr != nullptr) {
|
||||
(*sGtkNativeDialogDestroyPtr)(file_chooser);
|
||||
} else {
|
||||
gtk_widget_destroy(GTK_WIDGET(file_chooser));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsFilePicker::GtkFileChooserSetModal(void *file_chooser,
|
||||
GtkWindow *parent_widget, gboolean modal)
|
||||
{
|
||||
static auto sGtkNativeDialogSetModalPtr = (void (*)(void *, gboolean))
|
||||
dlsym(RTLD_DEFAULT, "gtk_native_dialog_set_modal");
|
||||
if (mUseNativeFileChooser && sGtkNativeDialogSetModalPtr != nullptr) {
|
||||
(*sGtkNativeDialogSetModalPtr)(file_chooser, modal);
|
||||
} else {
|
||||
GtkWindow *window = GTK_WINDOW(file_chooser);
|
||||
gtk_window_set_modal(window, modal);
|
||||
if (parent_widget != nullptr) {
|
||||
gtk_window_set_destroy_with_parent(window, modal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,12 +48,12 @@ public:
|
|||
protected:
|
||||
virtual ~nsFilePicker();
|
||||
|
||||
void ReadValuesFromFileChooser(GtkWidget *file_chooser);
|
||||
void ReadValuesFromFileChooser(void *file_chooser);
|
||||
|
||||
static void OnResponse(GtkWidget* dialog, gint response_id,
|
||||
static void OnResponse(void* dialog, gint response_id,
|
||||
gpointer user_data);
|
||||
static void OnDestroy(GtkWidget* dialog, gpointer user_data);
|
||||
void Done(GtkWidget* dialog, gint response_id);
|
||||
static void OnDestroy(GtkWidget* file_chooser, gpointer user_data);
|
||||
void Done(void* file_chooser, gint response_id);
|
||||
|
||||
nsCOMPtr<nsIWidget> mParentWidget;
|
||||
nsCOMPtr<nsIFilePickerShownCallback> mCallback;
|
||||
|
@ -74,9 +74,19 @@ protected:
|
|||
private:
|
||||
static nsIFile *mPrevDisplayDirectory;
|
||||
|
||||
void *GtkFileChooserNew(
|
||||
const gchar *title, GtkWindow *parent,
|
||||
GtkFileChooserAction action,
|
||||
const gchar *accept_label);
|
||||
void GtkFileChooserShow(void *file_chooser);
|
||||
void GtkFileChooserDestroy(void *file_chooser);
|
||||
void GtkFileChooserSetModal(void *file_chooser, GtkWindow* parent_widget,
|
||||
gboolean modal);
|
||||
|
||||
#if (MOZ_WIDGET_GTK == 3)
|
||||
GtkFileChooserWidget *mFileChooserDelegate;
|
||||
#endif
|
||||
bool mUseNativeFileChooser;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue