summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Redondo <qt@david-redondo.de>2022-02-22 16:11:22 +0100
committerDavid Redondo <qt@david-redondo.de>2022-07-29 15:07:10 +0200
commitd93a817e21bbf4e12693baa6a7f0e1c0f0547d21 (patch)
tree5fb8599d085137ec212a2493710c186fbf160f2c /src
parent14c0293fe6e55317e8a645f6a156b5973190cd8e (diff)
downloadqtwayland-d93a817e21bbf4e12693baa6a7f0e1c0f0547d21.tar.gz
Provide a handle for desktop portal via xdg-exporter
Change-Id: I6b2034c1833ae497ef05af7c377e4bfd3747b6fe Reviewed-by: David Edmundson <davidedmundson@kde.org>
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/protocol/qt_attribution.json19
-rw-r--r--src/3rdparty/protocol/xdg-foreign-unstable-v2.xml200
-rw-r--r--src/client/qwaylandshellsurface_p.h2
-rw-r--r--src/client/qwaylandwindowmanagerintegration.cpp12
-rw-r--r--src/client/qwaylandwindowmanagerintegration_p.h1
-rw-r--r--src/plugins/shellintegration/xdg-shell/CMakeLists.txt2
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2.cpp47
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2_p.h50
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp19
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h8
10 files changed, 359 insertions, 1 deletions
diff --git a/src/3rdparty/protocol/qt_attribution.json b/src/3rdparty/protocol/qt_attribution.json
index f51599de..76d8d3f0 100644
--- a/src/3rdparty/protocol/qt_attribution.json
+++ b/src/3rdparty/protocol/qt_attribution.json
@@ -301,5 +301,22 @@
"License": "MIT License",
"LicenseFile": "MIT_LICENSE.txt",
"Copyright": "Copyright © 2013, 2014 Collabora, Ltd."
- }
+ },
+
+ {
+ "Id": "xdg-foreign-unstable-v2",
+ "Name": "Wayland XDG Foreign Protocol",
+ "QDocModule": "qtwaylandcompositor",
+ "QtUsage": "Used in the Qt Wayland platform plugin",
+ "Files": "xdg-foreign-unstable-v2.xml",
+
+ "Description": "Allows referencing surfaces of different clients",
+ "Homepage": "https://wayland.freedesktop.org",
+ "Version": "1",
+ "DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/raw/1.25/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
+ "Copyright": "Copyright © 2015-2016 Red Hat Inc."
+ },
]
diff --git a/src/3rdparty/protocol/xdg-foreign-unstable-v2.xml b/src/3rdparty/protocol/xdg-foreign-unstable-v2.xml
new file mode 100644
index 00000000..cc3271dc
--- /dev/null
+++ b/src/3rdparty/protocol/xdg-foreign-unstable-v2.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_foreign_unstable_v2">
+
+ <copyright>
+ Copyright © 2015-2016 Red Hat Inc.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <description summary="Protocol for exporting xdg surface handles">
+ This protocol specifies a way for making it possible to reference a surface
+ of a different client. With such a reference, a client can, by using the
+ interfaces provided by this protocol, manipulate the relationship between
+ its own surfaces and the surface of some other client. For example, stack
+ some of its own surface above the other clients surface.
+
+ In order for a client A to get a reference of a surface of client B, client
+ B must first export its surface using xdg_exporter.export_toplevel. Upon
+ doing this, client B will receive a handle (a unique string) that it may
+ share with client A in some way (for example D-Bus). After client A has
+ received the handle from client B, it may use xdg_importer.import_toplevel
+ to create a reference to the surface client B just exported. See the
+ corresponding requests for details.
+
+ A possible use case for this is out-of-process dialogs. For example when a
+ sandboxed client without file system access needs the user to select a file
+ on the file system, given sandbox environment support, it can export its
+ surface, passing the exported surface handle to an unsandboxed process that
+ can show a file browser dialog and stack it above the sandboxed client's
+ surface.
+
+ Warning! The protocol described in this file is experimental and backward
+ incompatible changes may be made. Backward compatible changes may be added
+ together with the corresponding interface version bump. Backward
+ incompatible changes are done by bumping the version number in the protocol
+ and interface names and resetting the interface version. Once the protocol
+ is to be declared stable, the 'z' prefix and the version number in the
+ protocol and interface names are removed and the interface version number is
+ reset.
+ </description>
+
+ <interface name="zxdg_exporter_v2" version="1">
+ <description summary="interface for exporting surfaces">
+ A global interface used for exporting surfaces that can later be imported
+ using xdg_importer.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the xdg_exporter object">
+ Notify the compositor that the xdg_exporter object will no longer be
+ used.
+ </description>
+ </request>
+
+ <enum name="error">
+ <description summary="error values">
+ These errors can be emitted in response to invalid xdg_exporter
+ requests.
+ </description>
+ <entry name="invalid_surface" value="0" summary="surface is not an xdg_toplevel"/>
+ </enum>
+
+ <request name="export_toplevel">
+ <description summary="export a toplevel surface">
+ The export_toplevel request exports the passed surface so that it can later be
+ imported via xdg_importer. When called, a new xdg_exported object will
+ be created and xdg_exported.handle will be sent immediately. See the
+ corresponding interface and event for details.
+
+ A surface may be exported multiple times, and each exported handle may
+ be used to create an xdg_imported multiple times. Only xdg_toplevel
+ equivalent surfaces may be exported, otherwise an invalid_surface
+ protocol error is sent.
+ </description>
+ <arg name="id" type="new_id" interface="zxdg_exported_v2"
+ summary="the new xdg_exported object"/>
+ <arg name="surface" type="object" interface="wl_surface"
+ summary="the surface to export"/>
+ </request>
+ </interface>
+
+ <interface name="zxdg_importer_v2" version="1">
+ <description summary="interface for importing surfaces">
+ A global interface used for importing surfaces exported by xdg_exporter.
+ With this interface, a client can create a reference to a surface of
+ another client.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the xdg_importer object">
+ Notify the compositor that the xdg_importer object will no longer be
+ used.
+ </description>
+ </request>
+
+ <request name="import_toplevel">
+ <description summary="import a toplevel surface">
+ The import_toplevel request imports a surface from any client given a handle
+ retrieved by exporting said surface using xdg_exporter.export_toplevel.
+ When called, a new xdg_imported object will be created. This new object
+ represents the imported surface, and the importing client can
+ manipulate its relationship using it. See xdg_imported for details.
+ </description>
+ <arg name="id" type="new_id" interface="zxdg_imported_v2"
+ summary="the new xdg_imported object"/>
+ <arg name="handle" type="string"
+ summary="the exported surface handle"/>
+ </request>
+ </interface>
+
+ <interface name="zxdg_exported_v2" version="1">
+ <description summary="an exported surface handle">
+ An xdg_exported object represents an exported reference to a surface. The
+ exported surface may be referenced as long as the xdg_exported object not
+ destroyed. Destroying the xdg_exported invalidates any relationship the
+ importer may have established using xdg_imported.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="unexport the exported surface">
+ Revoke the previously exported surface. This invalidates any
+ relationship the importer may have set up using the xdg_imported created
+ given the handle sent via xdg_exported.handle.
+ </description>
+ </request>
+
+ <event name="handle">
+ <description summary="the exported surface handle">
+ The handle event contains the unique handle of this exported surface
+ reference. It may be shared with any client, which then can use it to
+ import the surface by calling xdg_importer.import_toplevel. A handle
+ may be used to import the surface multiple times.
+ </description>
+ <arg name="handle" type="string" summary="the exported surface handle"/>
+ </event>
+ </interface>
+
+ <interface name="zxdg_imported_v2" version="1">
+ <description summary="an imported surface handle">
+ An xdg_imported object represents an imported reference to surface exported
+ by some client. A client can use this interface to manipulate
+ relationships between its own surfaces and the imported surface.
+ </description>
+
+ <enum name="error">
+ <description summary="error values">
+ These errors can be emitted in response to invalid xdg_imported
+ requests.
+ </description>
+ <entry name="invalid_surface" value="0" summary="surface is not an xdg_toplevel"/>
+ </enum>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the xdg_imported object">
+ Notify the compositor that it will no longer use the xdg_imported
+ object. Any relationship that may have been set up will at this point
+ be invalidated.
+ </description>
+ </request>
+
+ <request name="set_parent_of">
+ <description summary="set as the parent of some surface">
+ Set the imported surface as the parent of some surface of the client.
+ The passed surface must be an xdg_toplevel equivalent, otherwise an
+ invalid_surface protocol error is sent. Calling this function sets up
+ a surface to surface relation with the same stacking and positioning
+ semantics as xdg_toplevel.set_parent.
+ </description>
+ <arg name="surface" type="object" interface="wl_surface"
+ summary="the child surface"/>
+ </request>
+
+ <event name="destroyed">
+ <description summary="the imported surface handle has been destroyed">
+ The imported surface handle has been destroyed and any relationship set
+ up has been invalidated. This may happen for various reasons, for
+ example if the exported surface or the exported surface handle has been
+ destroyed, if the handle used for importing was invalid.
+ </description>
+ </event>
+ </interface>
+
+</protocol>
diff --git a/src/client/qwaylandshellsurface_p.h b/src/client/qwaylandshellsurface_p.h
index c133269a..5e269510 100644
--- a/src/client/qwaylandshellsurface_p.h
+++ b/src/client/qwaylandshellsurface_p.h
@@ -71,6 +71,8 @@ public:
virtual void setXdgActivationToken(const QString &token);
virtual void requestXdgActivationToken(quint32 serial);
+ virtual QString externWindowHandle() { return QString(); }
+
inline QWaylandWindow *window() { return m_window; }
QPlatformWindow *platformWindow();
struct wl_surface *wlSurface();
diff --git a/src/client/qwaylandwindowmanagerintegration.cpp b/src/client/qwaylandwindowmanagerintegration.cpp
index b394d69b..dababe7c 100644
--- a/src/client/qwaylandwindowmanagerintegration.cpp
+++ b/src/client/qwaylandwindowmanagerintegration.cpp
@@ -5,6 +5,7 @@
#include "qwaylandscreen_p.h"
#include "qwaylandwindow_p.h"
#include "qwaylanddisplay_p.h"
+#include "qwaylandshellsurface_p.h"
#include <stdint.h>
#include <QtCore/QEvent>
@@ -106,6 +107,17 @@ bool QWaylandWindowManagerIntegration::openDocument(const QUrl &url)
return QGenericUnixServices::openDocument(url);
}
+QString QWaylandWindowManagerIntegration::portalWindowIdentifier(QWindow *window)
+{
+ if (window && window->handle()) {
+ auto shellSurface = static_cast<QWaylandWindow *>(window->handle())->shellSurface();
+ if (shellSurface) {
+ const QString handle = shellSurface->externWindowHandle();
+ return QLatin1String("wayland:") + handle;
+ }
+ }
+ return QString();
+}
}
QT_END_NAMESPACE
diff --git a/src/client/qwaylandwindowmanagerintegration_p.h b/src/client/qwaylandwindowmanagerintegration_p.h
index ea57911f..18eb171b 100644
--- a/src/client/qwaylandwindowmanagerintegration_p.h
+++ b/src/client/qwaylandwindowmanagerintegration_p.h
@@ -42,6 +42,7 @@ public:
bool openUrl(const QUrl &url) override;
bool openDocument(const QUrl &url) override;
+ QString portalWindowIdentifier(QWindow *window) override;
bool showIsFullScreen() const;
diff --git a/src/plugins/shellintegration/xdg-shell/CMakeLists.txt b/src/plugins/shellintegration/xdg-shell/CMakeLists.txt
index 1ae0d5ff..df691d55 100644
--- a/src/plugins/shellintegration/xdg-shell/CMakeLists.txt
+++ b/src/plugins/shellintegration/xdg-shell/CMakeLists.txt
@@ -16,6 +16,7 @@ qt_internal_add_plugin(QWaylandXdgShellIntegrationPlugin
qwaylandxdgactivationv1.cpp qwaylandxdgactivationv1_p.h
qwaylandxdgshell.cpp qwaylandxdgshell_p.h
qwaylandxdgshellintegration.cpp qwaylandxdgshellintegration_p.h
+ qwaylandxdgexporterv2.cpp qwaylandxdgexporterv2_p.h
LIBRARIES
Qt::Core
Qt::Gui
@@ -29,6 +30,7 @@ qt6_generate_wayland_protocol_client_sources(QWaylandXdgShellIntegrationPlugin
${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/protocol/xdg-decoration-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/protocol/xdg-shell.xml
${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/protocol/xdg-activation-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/protocol/xdg-foreign-unstable-v2.xml
)
#### Keys ignored in scope 1:.:.:xdg-shell.pro:<TRUE>:
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2.cpp
new file mode 100644
index 00000000..58baad02
--- /dev/null
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 David Reondo <kde@david-redondo.de>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwaylandxdgexporterv2_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandXdgExportedV2::QWaylandXdgExportedV2(::zxdg_exported_v2 *object)
+ : QtWayland::zxdg_exported_v2(object)
+{
+}
+
+QWaylandXdgExportedV2::~QWaylandXdgExportedV2()
+{
+ destroy();
+}
+
+void QWaylandXdgExportedV2::zxdg_exported_v2_handle(const QString &handle)
+{
+ mHandle = handle;
+}
+
+QString QWaylandXdgExportedV2::handle() const
+{
+ return mHandle;
+}
+
+QWaylandXdgExporterV2::QWaylandXdgExporterV2(wl_registry *registry, uint32_t id, int version)
+ : QtWayland::zxdg_exporter_v2(registry, id, qMin(version, 1))
+{
+}
+
+QWaylandXdgExporterV2::~QWaylandXdgExporterV2()
+{
+ destroy();
+}
+
+QtWaylandClient::QWaylandXdgExportedV2 *QWaylandXdgExporterV2::exportToplevel(wl_surface *surface)
+{
+ return new QWaylandXdgExportedV2(export_toplevel(surface));
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2_p.h
new file mode 100644
index 00000000..b260dbac
--- /dev/null
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2_p.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 David Reondo <kde@david-redondo.de>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWAYLANDXDGEXPORTERV2_H
+#define QWAYLANDXDGEXPORTERV2_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qwayland-xdg-foreign-unstable-v2.h>
+
+#include <QtWaylandClient/qtwaylandclientglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandXdgExportedV2 : public QtWayland::zxdg_exported_v2
+{
+public:
+ explicit QWaylandXdgExportedV2(::zxdg_exported_v2 *object);
+ ~QWaylandXdgExportedV2() override;
+ QString handle() const;
+
+private:
+ void zxdg_exported_v2_handle(const QString &handle) override;
+ QString mHandle;
+};
+
+class QWaylandXdgExporterV2 : public QtWayland::zxdg_exporter_v2
+{
+public:
+ QWaylandXdgExporterV2(wl_registry *registry, uint32_t id, int version);
+ ~QWaylandXdgExporterV2() override;
+ QWaylandXdgExportedV2 *exportToplevel(wl_surface *surface);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDXDGEXPORTERV2_H
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
index c4b1942b..87152fbd 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
@@ -4,6 +4,8 @@
#include "qwaylandxdgshell_p.h"
+#include "qwaylandxdgexporterv2_p.h"
+
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <QtWaylandClient/private/qwaylandinputdevice_p.h>
@@ -537,6 +539,19 @@ void QWaylandXdgSurface::setXdgActivationToken(const QString &token)
}
}
+QString QWaylandXdgSurface::externWindowHandle()
+{
+ if (!m_toplevel || !m_shell->exporter()) {
+ return QString();
+ }
+ if (!m_toplevel->m_exported) {
+ m_toplevel->m_exported.reset(m_shell->exporter()->exportToplevel(m_window->wlSurface()));
+ // handle events is sent immediately
+ m_shell->display()->forceRoundTrip();
+ }
+ return m_toplevel->m_exported->handle();
+}
+
QWaylandXdgShell::QWaylandXdgShell(QWaylandDisplay *display, uint32_t id, uint32_t availableVersion)
: QtWayland::xdg_wm_base(display->wl_registry(), id, qMin(availableVersion, 2u))
, m_display(display)
@@ -570,6 +585,10 @@ void QWaylandXdgShell::handleRegistryGlobal(void *data, wl_registry *registry, u
if (interface == QLatin1String(QWaylandXdgActivationV1::interface()->name)) {
xdgShell->m_xdgActivation.reset(new QWaylandXdgActivationV1(registry, id, version));
}
+
+ if (interface == QLatin1String(QWaylandXdgExporterV2::interface()->name)) {
+ xdgShell->m_xdgExporter.reset(new QWaylandXdgExporterV2(registry, id, version));
+ }
}
}
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
index 8410253c..d3cdb9d4 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
@@ -37,6 +37,8 @@ namespace QtWaylandClient {
class QWaylandDisplay;
class QWaylandInputDevice;
class QWaylandXdgShell;
+class QWaylandXdgExportedV2;
+class QWaylandXdgExporterV2;
class Q_WAYLANDCLIENT_EXPORT QWaylandXdgSurface : public QWaylandShellSurface, public QtWayland::xdg_surface
{
@@ -62,6 +64,7 @@ public:
bool requestActivate() override;
void setXdgActivationToken(const QString &token) override;
void requestXdgActivationToken(quint32 serial) override;
+ QString externWindowHandle() override;
void setSizeHints();
@@ -98,6 +101,7 @@ private:
QWaylandXdgSurface *m_xdgSurface = nullptr;
QWaylandXdgToplevelDecorationV1 *m_decoration = nullptr;
+ QScopedPointer<QWaylandXdgExportedV2> m_exported;
};
class Popup : public QtWayland::xdg_popup {
@@ -138,8 +142,11 @@ public:
QWaylandXdgShell(QWaylandDisplay *display, uint32_t id, uint32_t availableVersion);
~QWaylandXdgShell() override;
+ QWaylandDisplay *display() const { return m_display; }
+
QWaylandXdgDecorationManagerV1 *decorationManager() { return m_xdgDecorationManager.data(); }
QWaylandXdgActivationV1 *activation() const { return m_xdgActivation.data(); }
+ QWaylandXdgExporterV2 *exporter() const { return m_xdgExporter.data(); }
QWaylandXdgSurface *getXdgSurface(QWaylandWindow *window);
protected:
@@ -152,6 +159,7 @@ private:
QWaylandDisplay *m_display = nullptr;
QScopedPointer<QWaylandXdgDecorationManagerV1> m_xdgDecorationManager;
QScopedPointer<QWaylandXdgActivationV1> m_xdgActivation;
+ QScopedPointer<QWaylandXdgExporterV2> m_xdgExporter;
QWaylandXdgSurface::Popup *m_topmostGrabbingPopup = nullptr;
friend class QWaylandXdgSurface;