From de87b9d9e9d25e9a11b42149ab17553d3289f764 Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Wed, 1 Jun 2022 15:40:56 +0400 Subject: [PATCH 047/147] Fallback to another file dialog implementation when XDP is inaccessible Fixes: QTBUG-98988 Pick-to: 6.4 6.3 6.2 5.15 Change-Id: Idca1ab4cae0e9eabebc599f3c8efa136a7973918 Reviewed-by: Jan Grulich <jgrulich@redhat.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit fb981a0954119ed0dfa4a402fdef78e7257ffc96) * asturmlechner 2022-06-11: Fix conflict with dev branch commit ceaa7d6341e666f6fe0d071ea34cad9877961a0e --- .../qxdgdesktopportalfiledialog.cpp | 68 +++++++++++-------- .../qxdgdesktopportalfiledialog_p.h | 11 ++- .../qxdgdesktopportaltheme.cpp | 7 +- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp index 3ab19afea6..b2301c8c15 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp @@ -102,15 +102,12 @@ const QDBusArgument &operator >>(const QDBusArgument &arg, QXdgDesktopPortalFile class QXdgDesktopPortalFileDialogPrivate { public: - QXdgDesktopPortalFileDialogPrivate(QPlatformFileDialogHelper *nativeFileDialog) + QXdgDesktopPortalFileDialogPrivate(QPlatformFileDialogHelper *nativeFileDialog, uint fileChooserPortalVersion) : nativeFileDialog(nativeFileDialog) + , fileChooserPortalVersion(fileChooserPortalVersion) { } - WId winId = 0; - bool directoryMode = false; - bool modal = false; - bool multipleFiles = false; - bool saveFile = false; + QEventLoop loop; QString acceptLabel; QString directory; QString title; @@ -122,11 +119,16 @@ public: QString selectedNameFilter; QStringList selectedFiles; std::unique_ptr<QPlatformFileDialogHelper> nativeFileDialog; + uint fileChooserPortalVersion = 0; + bool failedToOpen = false; + bool directoryMode = false; + bool multipleFiles = false; + bool saveFile = false; }; -QXdgDesktopPortalFileDialog::QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog) +QXdgDesktopPortalFileDialog::QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog, uint fileChooserPortalVersion) : QPlatformFileDialogHelper() - , d_ptr(new QXdgDesktopPortalFileDialogPrivate(nativeFileDialog)) + , d_ptr(new QXdgDesktopPortalFileDialogPrivate(nativeFileDialog, fileChooserPortalVersion)) { Q_D(QXdgDesktopPortalFileDialog); @@ -134,6 +136,9 @@ QXdgDesktopPortalFileDialog::QXdgDesktopPortalFileDialog(QPlatformFileDialogHelp connect(d->nativeFileDialog.get(), SIGNAL(accept()), this, SIGNAL(accept())); connect(d->nativeFileDialog.get(), SIGNAL(reject()), this, SIGNAL(reject())); } + + d->loop.connect(this, SIGNAL(accept()), SLOT(quit())); + d->loop.connect(this, SIGNAL(reject()), SLOT(quit())); } QXdgDesktopPortalFileDialog::~QXdgDesktopPortalFileDialog() @@ -177,7 +182,7 @@ void QXdgDesktopPortalFileDialog::initializeDialog() setDirectory(options()->initialDirectory()); } -void QXdgDesktopPortalFileDialog::openPortal() +void QXdgDesktopPortalFileDialog::openPortal(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) { Q_D(QXdgDesktopPortalFileDialog); @@ -185,13 +190,13 @@ void QXdgDesktopPortalFileDialog::openPortal() QLatin1String("/org/freedesktop/portal/desktop"), QLatin1String("org.freedesktop.portal.FileChooser"), d->saveFile ? QLatin1String("SaveFile") : QLatin1String("OpenFile")); - QString parentWindowId = QLatin1String("x11:") + QString::number(d->winId, 16); + QString parentWindowId = QLatin1String("x11:") + QString::number(parent ? parent->winId() : 0, 16); QVariantMap options; if (!d->acceptLabel.isEmpty()) options.insert(QLatin1String("accept_label"), d->acceptLabel); - options.insert(QLatin1String("modal"), d->modal); + options.insert(QLatin1String("modal"), windowModality != Qt::NonModal); options.insert(QLatin1String("multiple"), d->multipleFiles); options.insert(QLatin1String("directory"), d->directoryMode); @@ -290,10 +295,18 @@ void QXdgDesktopPortalFileDialog::openPortal() QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall); - connect(watcher, &QDBusPendingCallWatcher::finished, this, [this] (QDBusPendingCallWatcher *watcher) { + connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] (QDBusPendingCallWatcher *watcher) { QDBusPendingReply<QDBusObjectPath> reply = *watcher; - if (reply.isError()) { - Q_EMIT reject(); + // Any error means the dialog is not shown and we need to fallback + d->failedToOpen = reply.isError(); + if (d->failedToOpen) { + if (d->nativeFileDialog) { + d->nativeFileDialog->show(windowFlags, windowModality, parent); + if (d->loop.isRunning()) + d->nativeFileDialog->exec(); + } else { + Q_EMIT reject(); + } } else { QDBusConnection::sessionBus().connect(nullptr, reply.value().path(), @@ -410,10 +423,7 @@ void QXdgDesktopPortalFileDialog::exec() } // HACK we have to avoid returning until we emit that the dialog was accepted or rejected - QEventLoop loop; - loop.connect(this, SIGNAL(accept()), SLOT(quit())); - loop.connect(this, SIGNAL(reject()), SLOT(quit())); - loop.exec(); + d->loop.exec(); } void QXdgDesktopPortalFileDialog::hide() @@ -430,13 +440,10 @@ bool QXdgDesktopPortalFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowMo initializeDialog(); - d->modal = windowModality != Qt::NonModal; - d->winId = parent ? parent->winId() : 0; - - if (d->nativeFileDialog && useNativeFileDialog()) + if (d->nativeFileDialog && useNativeFileDialog(OpenFallback)) return d->nativeFileDialog->show(windowFlags, windowModality, parent); - openPortal(); + openPortal(windowFlags, windowModality, parent); return true; } @@ -466,13 +473,20 @@ void QXdgDesktopPortalFileDialog::gotResponse(uint response, const QVariantMap & } } -bool QXdgDesktopPortalFileDialog::useNativeFileDialog() const +bool QXdgDesktopPortalFileDialog::useNativeFileDialog(QXdgDesktopPortalFileDialog::FallbackType fallbackType) const { - if (options()->fileMode() == QFileDialogOptions::Directory) - return true; - else if (options()->fileMode() == QFileDialogOptions::DirectoryOnly) + Q_D(const QXdgDesktopPortalFileDialog); + + if (d->failedToOpen && fallbackType != OpenFallback) return true; + if (d->fileChooserPortalVersion < 3) { + if (options()->fileMode() == QFileDialogOptions::Directory) + return true; + else if (options()->fileMode() == QFileDialogOptions::DirectoryOnly) + return true; + } + return false; } diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h index 5c1231bb54..65e22a5cf2 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h @@ -51,6 +51,11 @@ class QXdgDesktopPortalFileDialog : public QPlatformFileDialogHelper Q_OBJECT Q_DECLARE_PRIVATE(QXdgDesktopPortalFileDialog) public: + enum FallbackType { + GenericFallback, + OpenFallback + }; + enum ConditionType : uint { GlobalPattern = 0, MimeType = 1 @@ -69,7 +74,7 @@ public: }; typedef QVector<Filter> FilterList; - QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog = nullptr); + QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog = nullptr, uint fileChooserPortalVersion = 0); ~QXdgDesktopPortalFileDialog(); bool defaultNameFilterDisables() const override; @@ -92,8 +97,8 @@ private Q_SLOTS: private: void initializeDialog(); - void openPortal(); - bool useNativeFileDialog() const; + void openPortal(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent); + bool useNativeFileDialog(FallbackType fallbackType = GenericFallback) const; QScopedPointer<QXdgDesktopPortalFileDialogPrivate> d_ptr; }; diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp index 2fc3167fd5..b809503122 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp @@ -153,11 +153,12 @@ QPlatformDialogHelper* QXdgDesktopPortalTheme::createPlatformDialogHelper(Dialog { Q_D(const QXdgDesktopPortalTheme); - if (type == FileDialog) { + if (type == FileDialog && d->fileChooserPortalVersion) { // Older versions of FileChooser portal don't support opening directories, therefore we fallback // to native file dialog opened inside the sandbox to open a directory. - if (d->fileChooserPortalVersion < 3 && d->baseTheme->usePlatformNativeDialog(type)) - return new QXdgDesktopPortalFileDialog(static_cast<QPlatformFileDialogHelper*>(d->baseTheme->createPlatformDialogHelper(type))); + if (d->baseTheme->usePlatformNativeDialog(type)) + return new QXdgDesktopPortalFileDialog(static_cast<QPlatformFileDialogHelper*>(d->baseTheme->createPlatformDialogHelper(type)), + d->fileChooserPortalVersion); return new QXdgDesktopPortalFileDialog; } -- 2.40.1