Send parent_window handle to desktop portal

Sending parent_window to the portal allows it/the window manager to
better place portal dialogs in respect to the application window, for example
on top of it instead of a random position. For this use the focusWindow()
(if available) since the API in QDesktopServices does not take a QWindow
parameter. The file dialog has an explicit parent that can be used.
The introduced virtual is provided as a hook for the wayland platform
that already includes a class that inherits from QGenericUnixServices.

Change-Id: I5571f08d07e5a4e3ae32efd1f09e2727cec9e7c5
Reviewed-by: David Edmundson <davidedmundson@kde.org>
This commit is contained in:
David Redondo 2022-02-23 11:12:17 +01:00
parent f3cd571687
commit c142fd8f68
3 changed files with 45 additions and 14 deletions

View File

@ -3,6 +3,8 @@
#include "qgenericunixservices_p.h"
#include <QtGui/private/qtguiglobal_p.h>
#include "qguiapplication.h"
#include "qwindow.h"
#include <QtCore/QDebug>
#include <QtCore/QFile>
@ -152,7 +154,7 @@ static inline bool checkNeedPortalSupport()
return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, "flatpak-info"_L1).isEmpty() || qEnvironmentVariableIsSet("SNAP");
}
static inline QDBusMessage xdgDesktopPortalOpenFile(const QUrl &url)
static inline QDBusMessage xdgDesktopPortalOpenFile(const QUrl &url, const QString &parentWindow)
{
// DBus signature:
// OpenFile (IN s parent_window,
@ -176,19 +178,19 @@ static inline QDBusMessage xdgDesktopPortalOpenFile(const QUrl &url)
const QVariantMap options = {{"writable"_L1, true}};
// FIXME parent_window_id
message << QString() << QVariant::fromValue(descriptor) << options;
message << parentWindow << QVariant::fromValue(descriptor) << options;
return QDBusConnection::sessionBus().call(message);
}
#else
Q_UNUSED(url);
Q_UNUSED(parentWindow)
#endif
return QDBusMessage::createError(QDBusError::InternalError, qt_error_string());
}
static inline QDBusMessage xdgDesktopPortalOpenUrl(const QUrl &url)
static inline QDBusMessage xdgDesktopPortalOpenUrl(const QUrl &url, const QString &parentWindow)
{
// DBus signature:
// OpenURI (IN s parent_window,
@ -206,12 +208,12 @@ static inline QDBusMessage xdgDesktopPortalOpenUrl(const QUrl &url)
"org.freedesktop.portal.OpenURI"_L1,
"OpenURI"_L1);
// FIXME parent_window_id and handle writable option
message << QString() << url.toString() << QVariantMap();
message << parentWindow << url.toString() << QVariantMap();
return QDBusConnection::sessionBus().call(message);
}
static inline QDBusMessage xdgDesktopPortalSendEmail(const QUrl &url)
static inline QDBusMessage xdgDesktopPortalSendEmail(const QUrl &url, const QString &parentWindow)
{
// DBus signature:
// ComposeEmail (IN s parent_window,
@ -251,8 +253,7 @@ static inline QDBusMessage xdgDesktopPortalSendEmail(const QUrl &url)
"org.freedesktop.portal.Email"_L1,
"ComposeEmail"_L1);
// FIXME parent_window_id
message << QString() << options;
message << parentWindow << options;
return QDBusConnection::sessionBus().call(message);
}
@ -269,7 +270,10 @@ bool QGenericUnixServices::openUrl(const QUrl &url)
if (url.scheme() == "mailto"_L1) {
#if QT_CONFIG(dbus)
if (checkNeedPortalSupport()) {
QDBusError error = xdgDesktopPortalSendEmail(url);
const QString parentWindow = QGuiApplication::focusWindow()
? portalWindowIdentifier(QGuiApplication::focusWindow())
: QString();
QDBusError error = xdgDesktopPortalSendEmail(url, parentWindow);
if (!error.isValid())
return true;
@ -281,7 +285,10 @@ bool QGenericUnixServices::openUrl(const QUrl &url)
#if QT_CONFIG(dbus)
if (checkNeedPortalSupport()) {
QDBusError error = xdgDesktopPortalOpenUrl(url);
const QString parentWindow = QGuiApplication::focusWindow()
? portalWindowIdentifier(QGuiApplication::focusWindow())
: QString();
QDBusError error = xdgDesktopPortalOpenUrl(url, parentWindow);
if (!error.isValid())
return true;
}
@ -298,7 +305,10 @@ bool QGenericUnixServices::openDocument(const QUrl &url)
{
#if QT_CONFIG(dbus)
if (checkNeedPortalSupport()) {
QDBusError error = xdgDesktopPortalOpenFile(url);
const QString parentWindow = QGuiApplication::focusWindow()
? portalWindowIdentifier(QGuiApplication::focusWindow())
: QString();
QDBusError error = xdgDesktopPortalOpenFile(url, parentWindow);
if (!error.isValid())
return true;
}
@ -333,4 +343,12 @@ bool QGenericUnixServices::openDocument(const QUrl &url)
#endif // QT_NO_MULTIPROCESS
QString QGenericUnixServices::portalWindowIdentifier(QWindow *window)
{
if (QGuiApplication::platformName() == QLatin1String("xcb"))
return "x11:"_L1 + QString::number(window->winId(), 16);
return QString();
}
QT_END_NAMESPACE

View File

@ -21,6 +21,8 @@
QT_BEGIN_NAMESPACE
class QWindow;
class Q_GUI_EXPORT QGenericUnixServices : public QPlatformServices
{
public:
@ -31,6 +33,8 @@ public:
bool openUrl(const QUrl &url) override;
bool openDocument(const QUrl &url) override;
virtual QString portalWindowIdentifier(QWindow *window);
private:
QString m_webBrowser;
QString m_documentLauncher;

View File

@ -3,6 +3,10 @@
#include "qxdgdesktopportalfiledialog_p.h"
#include <private/qgenericunixservices_p.h>
#include <private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingCall>
@ -157,8 +161,6 @@ void QXdgDesktopPortalFileDialog::openPortal(Qt::WindowFlags windowFlags, Qt::Wi
"/org/freedesktop/portal/desktop"_L1,
"org.freedesktop.portal.FileChooser"_L1,
d->saveFile ? "SaveFile"_L1 : "OpenFile"_L1);
QString parentWindowId = "x11:"_L1 + QString::number(parent ? parent->winId() : 0, 16);
QVariantMap options;
if (!d->acceptLabel.isEmpty())
options.insert("accept_label"_L1, d->acceptLabel);
@ -262,7 +264,14 @@ void QXdgDesktopPortalFileDialog::openPortal(Qt::WindowFlags windowFlags, Qt::Wi
// TODO choices a(ssa(ss)s)
// List of serialized combo boxes to add to the file chooser.
message << parentWindowId << d->title << options;
auto unixServices = dynamic_cast<QGenericUnixServices *>(
QGuiApplicationPrivate::platformIntegration()->services());
if (parent && unixServices)
message << unixServices->portalWindowIdentifier(parent);
else
message << QString();
message << d->title << options;
QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);