qt5-qtwayland package is retired on branch c10s for BAKERY-412
This commit is contained in:
parent
2ff721c9b7
commit
39378799ad
21
.gitignore
vendored
21
.gitignore
vendored
@ -1,21 +0,0 @@
|
|||||||
/qtwayland-everywhere-src-5.11.0.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.11.1.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.11.2.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.11.3.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.12.1.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.12.3.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.12.4.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.12.5.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.13.2.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.14.2.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.15.1.tar.xz
|
|
||||||
/qtwayland-everywhere-src-5.15.2.tar.xz
|
|
||||||
/qtwayland-everywhere-opensource-src-5.15.3.tar.xz
|
|
||||||
/qtwayland-everywhere-opensource-src-5.15.4.tar.xz
|
|
||||||
/qtwayland-everywhere-opensource-src-5.15.5.tar.xz
|
|
||||||
/qtwayland-everywhere-opensource-src-5.15.6.tar.xz
|
|
||||||
/qtwayland-everywhere-opensource-src-5.15.7.tar.xz
|
|
||||||
/qtwayland-everywhere-opensource-src-5.15.8.tar.xz
|
|
||||||
/qtwayland-everywhere-opensource-src-5.15.9.tar.xz
|
|
||||||
/qtwayland-everywhere-opensource-src-5.15.10.tar.xz
|
|
||||||
/qtwayland-everywhere-opensource-src-5.15.11.tar.xz
|
|
@ -1,146 +0,0 @@
|
|||||||
From ec085b69839e85b4543afb2009d519da21ffd782 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
|
||||||
Date: Wed, 5 May 2021 20:49:26 +0300
|
|
||||||
Subject: [PATCH 01/59] Client: Announce an output after receiving more
|
|
||||||
complete state
|
|
||||||
|
|
||||||
Output initialization is not atomic, meaning that the compositor may
|
|
||||||
process a wl_output bind request in one event loop cycle, and the
|
|
||||||
xdg_output_manager.get_xdg_output in another event loop cycle.
|
|
||||||
|
|
||||||
This means that xdg_output properties may arrive in another wl_output
|
|
||||||
done frame. Prior to xdg-output v3, that wasn't an issue because the
|
|
||||||
compositor is required to send an xdg_output.done event after sending
|
|
||||||
xdg_output properties.
|
|
||||||
|
|
||||||
Starting with v3, the compositor may choose not to send an
|
|
||||||
xdg_output.done event after sending xdg_output properties. Therefore,
|
|
||||||
as is, QtWayland may announce an output with bad logical geometry or
|
|
||||||
even worse without name assigned by the compositor.
|
|
||||||
|
|
||||||
Unfortunately, that breaks applications such as plasmashell. Plasma uses
|
|
||||||
output names as a criterion to determine what kind of contents should be
|
|
||||||
displayed on a particular output.
|
|
||||||
|
|
||||||
In order to fix the initialization sequence, this change makes every
|
|
||||||
QWaylandScreen track processed events. After all required events have
|
|
||||||
been received, the screen can be announced to the rest of Qt.
|
|
||||||
|
|
||||||
Change-Id: If5da747edd7af277ec1364cbea105c6994f47402
|
|
||||||
Reviewed-by: David Edmundson <davidedmundson@kde.org>
|
|
||||||
(cherry picked from commit 69ea480f2e53ad4a5bbca78cde044eb8d4c48896)
|
|
||||||
|
|
||||||
Original Ticket: https://codereview.qt-project.org/c/qt/qtwayland/+/347774
|
|
||||||
CCBUG: 435124
|
|
||||||
---
|
|
||||||
src/client/qwaylandscreen.cpp | 32 +++++++++++++++++++++++---------
|
|
||||||
src/client/qwaylandscreen_p.h | 10 ++++++++--
|
|
||||||
2 files changed, 31 insertions(+), 11 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp
|
|
||||||
index 6cb337de..7c2d9be3 100644
|
|
||||||
--- a/src/client/qwaylandscreen.cpp
|
|
||||||
+++ b/src/client/qwaylandscreen.cpp
|
|
||||||
@@ -72,7 +72,7 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uin
|
|
||||||
qCWarning(lcQpaWayland) << "wl_output done event not supported by compositor,"
|
|
||||||
<< "QScreen may not work correctly";
|
|
||||||
mWaylandDisplay->forceRoundTrip(); // Give the compositor a chance to send geometry etc.
|
|
||||||
- mOutputDone = true; // Fake the done event
|
|
||||||
+ mProcessedEvents |= OutputDoneEvent; // Fake the done event
|
|
||||||
maybeInitialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -83,14 +83,25 @@ QWaylandScreen::~QWaylandScreen()
|
|
||||||
zxdg_output_v1::destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
+uint QWaylandScreen::requiredEvents() const
|
|
||||||
+{
|
|
||||||
+ uint ret = OutputDoneEvent;
|
|
||||||
+
|
|
||||||
+ if (mWaylandDisplay->xdgOutputManager()) {
|
|
||||||
+ ret |= XdgOutputNameEvent;
|
|
||||||
+
|
|
||||||
+ if (mWaylandDisplay->xdgOutputManager()->version() < 3)
|
|
||||||
+ ret |= XdgOutputDoneEvent;
|
|
||||||
+ }
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void QWaylandScreen::maybeInitialize()
|
|
||||||
{
|
|
||||||
Q_ASSERT(!mInitialized);
|
|
||||||
|
|
||||||
- if (!mOutputDone)
|
|
||||||
- return;
|
|
||||||
-
|
|
||||||
- if (mWaylandDisplay->xdgOutputManager() && !mXdgOutputDone)
|
|
||||||
+ const uint requiredEvents = this->requiredEvents();
|
|
||||||
+ if ((mProcessedEvents & requiredEvents) != requiredEvents)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mInitialized = true;
|
|
||||||
@@ -276,9 +287,8 @@ void QWaylandScreen::output_scale(int32_t factor)
|
|
||||||
|
|
||||||
void QWaylandScreen::output_done()
|
|
||||||
{
|
|
||||||
- mOutputDone = true;
|
|
||||||
- if (zxdg_output_v1::isInitialized() && mWaylandDisplay->xdgOutputManager()->version() >= 3)
|
|
||||||
- mXdgOutputDone = true;
|
|
||||||
+ mProcessedEvents |= OutputDoneEvent;
|
|
||||||
+
|
|
||||||
if (mInitialized) {
|
|
||||||
updateOutputProperties();
|
|
||||||
if (zxdg_output_v1::isInitialized())
|
|
||||||
@@ -339,7 +349,7 @@ void QWaylandScreen::zxdg_output_v1_done()
|
|
||||||
if (Q_UNLIKELY(mWaylandDisplay->xdgOutputManager()->version() >= 3))
|
|
||||||
qWarning(lcQpaWayland) << "zxdg_output_v1.done received on version 3 or newer, this is most likely a bug in the compositor";
|
|
||||||
|
|
||||||
- mXdgOutputDone = true;
|
|
||||||
+ mProcessedEvents |= XdgOutputDoneEvent;
|
|
||||||
if (mInitialized)
|
|
||||||
updateXdgOutputProperties();
|
|
||||||
else
|
|
||||||
@@ -348,7 +358,11 @@ void QWaylandScreen::zxdg_output_v1_done()
|
|
||||||
|
|
||||||
void QWaylandScreen::zxdg_output_v1_name(const QString &name)
|
|
||||||
{
|
|
||||||
+ if (Q_UNLIKELY(mInitialized))
|
|
||||||
+ qWarning(lcQpaWayland) << "zxdg_output_v1.name received after output has been initialized, this is most likely a bug in the compositor";
|
|
||||||
+
|
|
||||||
mOutputName = name;
|
|
||||||
+ mProcessedEvents |= XdgOutputNameEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWaylandScreen::updateXdgOutputProperties()
|
|
||||||
diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h
|
|
||||||
index df1c94f2..050cfdc0 100644
|
|
||||||
--- a/src/client/qwaylandscreen_p.h
|
|
||||||
+++ b/src/client/qwaylandscreen_p.h
|
|
||||||
@@ -116,6 +116,13 @@ public:
|
|
||||||
static QWaylandScreen *fromWlOutput(::wl_output *output);
|
|
||||||
|
|
||||||
private:
|
|
||||||
+ enum Event : uint {
|
|
||||||
+ XdgOutputDoneEvent = 0x1,
|
|
||||||
+ OutputDoneEvent = 0x2,
|
|
||||||
+ XdgOutputNameEvent = 0x4,
|
|
||||||
+ };
|
|
||||||
+ uint requiredEvents() const;
|
|
||||||
+
|
|
||||||
void output_mode(uint32_t flags, int width, int height, int refresh) override;
|
|
||||||
void output_geometry(int32_t x, int32_t y,
|
|
||||||
int32_t width, int32_t height,
|
|
||||||
@@ -148,8 +155,7 @@ private:
|
|
||||||
QSize mPhysicalSize;
|
|
||||||
QString mOutputName;
|
|
||||||
Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation;
|
|
||||||
- bool mOutputDone = false;
|
|
||||||
- bool mXdgOutputDone = false;
|
|
||||||
+ uint mProcessedEvents = 0;
|
|
||||||
bool mInitialized = false;
|
|
||||||
|
|
||||||
#if QT_CONFIG(cursor)
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
|||||||
From 09b0405d8dd413c34ab03b3c9a288f3e11765ec1 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Jaeyoon Jung <jaeyoon.jung@lge.com>
|
|
||||||
Date: Mon, 15 Feb 2021 08:31:06 +0900
|
|
||||||
Subject: [PATCH 02/59] Fix issue with repeated window size changes
|
|
||||||
|
|
||||||
Check if the new window size is different from the size requested
|
|
||||||
previously before calling wl_egl_window_resize. It addresses the issue
|
|
||||||
where repeated setGeometry calls between two sizes might not work as
|
|
||||||
expected. The problem occurs when wl_egl_window_get_attached_size does
|
|
||||||
not get the same size that was requested by the previous setGeometry
|
|
||||||
call. If the returned size happened to match the new size instead,
|
|
||||||
we would mistakenly skip the resize.
|
|
||||||
|
|
||||||
Change-Id: Iafe4a91cc707f854b9099b6109b6be1423d7bd29
|
|
||||||
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
|
||||||
(cherry picked from commit 14d066c61025e548227ccd8d655e80ffa31fa15e)
|
|
||||||
---
|
|
||||||
.../client/wayland-egl/qwaylandeglwindow.cpp | 4 +++-
|
|
||||||
.../client/wayland-egl/qwaylandeglwindow.h | 1 +
|
|
||||||
2 files changed, 4 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
|
|
||||||
index e00c28c3..64f7caeb 100644
|
|
||||||
--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
|
|
||||||
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
|
|
||||||
@@ -122,14 +122,16 @@ void QWaylandEglWindow::updateSurface(bool create)
|
|
||||||
if (!disableResizeCheck) {
|
|
||||||
wl_egl_window_get_attached_size(m_waylandEglWindow, ¤t_width, ¤t_height);
|
|
||||||
}
|
|
||||||
- if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height())) {
|
|
||||||
+ if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height()) || m_requestedSize != sizeWithMargins) {
|
|
||||||
wl_egl_window_resize(m_waylandEglWindow, sizeWithMargins.width(), sizeWithMargins.height(), mOffset.x(), mOffset.y());
|
|
||||||
+ m_requestedSize = sizeWithMargins;
|
|
||||||
mOffset = QPoint();
|
|
||||||
|
|
||||||
m_resize = true;
|
|
||||||
}
|
|
||||||
} else if (create && wlSurface()) {
|
|
||||||
m_waylandEglWindow = wl_egl_window_create(wlSurface(), sizeWithMargins.width(), sizeWithMargins.height());
|
|
||||||
+ m_requestedSize = sizeWithMargins;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_eglSurface && m_waylandEglWindow && create) {
|
|
||||||
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
|
|
||||||
index 2fccbcea..ad1e5ee9 100644
|
|
||||||
--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
|
|
||||||
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
|
|
||||||
@@ -85,6 +85,7 @@ private:
|
|
||||||
mutable QOpenGLFramebufferObject *m_contentFBO = nullptr;
|
|
||||||
|
|
||||||
QSurfaceFormat m_format;
|
|
||||||
+ QSize m_requestedSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
From 1cdb21c2e739aabb6793cf90029e76921b67d975 Mon Sep 17 00:00:00 2001
|
|
||||||
From: David Edmundson <davidedmundson@kde.org>
|
|
||||||
Date: Tue, 9 Feb 2021 16:09:21 +0000
|
|
||||||
Subject: [PATCH 03/59] Client: Connect drags being accepted to updating the
|
|
||||||
source drag icon
|
|
||||||
|
|
||||||
Currently in a multi-process drag and drop when the other client accepts
|
|
||||||
a given mimetype for dropping it calls accept, which is received by the
|
|
||||||
client, but the drag cursor is never updated.
|
|
||||||
|
|
||||||
Instead the drag cursor was updated in the data_device_enter events
|
|
||||||
which only works if we are operating within one process.
|
|
||||||
|
|
||||||
The code existed to handle this existed but both the targetChanged
|
|
||||||
signal and the dragSourceTargetChanged were unused.
|
|
||||||
|
|
||||||
Change-Id: I443f31f1b2ef72d4b5eadaf7115f97544dac883a
|
|
||||||
Reviewed-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
|
||||||
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
|
||||||
(cherry picked from commit 08e478448a97a440d5a968a5d797f0d7302140c2)
|
|
||||||
---
|
|
||||||
src/client/qwaylanddatadevice.cpp | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp
|
|
||||||
index 1e2db786..0124b890 100644
|
|
||||||
--- a/src/client/qwaylanddatadevice.cpp
|
|
||||||
+++ b/src/client/qwaylanddatadevice.cpp
|
|
||||||
@@ -124,6 +124,7 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
|
|
||||||
|
|
||||||
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
|
|
||||||
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
|
|
||||||
+ connect(m_dragSource.data(), &QWaylandDataSource::targetChanged, this, &QWaylandDataDevice::dragSourceTargetChanged);
|
|
||||||
|
|
||||||
start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial());
|
|
||||||
return true;
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
|||||||
From 4bce11a39578ed43d7efd61e2140704e84386cb9 Mon Sep 17 00:00:00 2001
|
|
||||||
From: David Edmundson <davidedmundson@kde.org>
|
|
||||||
Date: Fri, 14 May 2021 13:23:24 +0100
|
|
||||||
Subject: [PATCH 04/59] Client: Disconnect registry listener on destruction
|
|
||||||
|
|
||||||
If a display outlives a QWaylandClientExtension and a new global is
|
|
||||||
announced we end up delivering an event to a now deleted extension which
|
|
||||||
will crash.
|
|
||||||
|
|
||||||
Change-Id: Idc0de40be61a2f7627ab4963e1fe29b22fbf3f04
|
|
||||||
(cherry picked from commit c4ba37cd2f8cb81b9438b56ac604fc2f3e45083c)
|
|
||||||
---
|
|
||||||
src/client/global/qwaylandclientextension.cpp | 7 +++++++
|
|
||||||
src/client/global/qwaylandclientextension.h | 1 +
|
|
||||||
2 files changed, 8 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/src/client/global/qwaylandclientextension.cpp b/src/client/global/qwaylandclientextension.cpp
|
|
||||||
index 966096a8..2dc61b77 100644
|
|
||||||
--- a/src/client/global/qwaylandclientextension.cpp
|
|
||||||
+++ b/src/client/global/qwaylandclientextension.cpp
|
|
||||||
@@ -88,6 +88,13 @@ QWaylandClientExtension::QWaylandClientExtension(const int ver)
|
|
||||||
QMetaObject::invokeMethod(this, "addRegistryListener", Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
+QWaylandClientExtension::~QWaylandClientExtension()
|
|
||||||
+{
|
|
||||||
+ Q_D(QWaylandClientExtension);
|
|
||||||
+ if (d->registered && !QCoreApplication::closingDown())
|
|
||||||
+ d->waylandIntegration->display()->removeListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
QtWaylandClient::QWaylandIntegration *QWaylandClientExtension::integration() const
|
|
||||||
{
|
|
||||||
Q_D(const QWaylandClientExtension);
|
|
||||||
diff --git a/src/client/global/qwaylandclientextension.h b/src/client/global/qwaylandclientextension.h
|
|
||||||
index 98272e57..5bd28398 100644
|
|
||||||
--- a/src/client/global/qwaylandclientextension.h
|
|
||||||
+++ b/src/client/global/qwaylandclientextension.h
|
|
||||||
@@ -63,6 +63,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtension : public QObject
|
|
||||||
Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
|
|
||||||
public:
|
|
||||||
QWaylandClientExtension(const int version);
|
|
||||||
+ ~QWaylandClientExtension();
|
|
||||||
|
|
||||||
QtWaylandClient::QWaylandIntegration *integration() const;
|
|
||||||
int version() const;
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
|||||||
From 668ebf5792f1eb0910245465e5407fcab86ce98b Mon Sep 17 00:00:00 2001
|
|
||||||
From: David Edmundson <davidedmundson@kde.org>
|
|
||||||
Date: Mon, 3 May 2021 23:01:53 +0100
|
|
||||||
Subject: [PATCH 05/59] Client: Set XdgShell size hints before the first commit
|
|
||||||
|
|
||||||
propagateSizeHints is only called in QWindow we have platform window and
|
|
||||||
minimumSizeHint is then sent. We also need to send existing hints when
|
|
||||||
we create the shell window.
|
|
||||||
|
|
||||||
Sending them when we apply configure is too late, we need these hints
|
|
||||||
available for the compositor to correctly configure the window.
|
|
||||||
|
|
||||||
Change-Id: I6cbb294b11db06ecd87535fa4816bb8ad34a29c6
|
|
||||||
Reviewed-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
|
||||||
Reviewed-by: Aleix Pol Gonzalez <aleixpol@kde.org>
|
|
||||||
(cherry picked from commit d6e074d0d35221b0fac14c94fc79c98363f2f6c3)
|
|
||||||
---
|
|
||||||
src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp | 3 +--
|
|
||||||
tests/auto/client/xdgshell/tst_xdgshell.cpp | 2 +-
|
|
||||||
2 files changed, 2 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
|
|
||||||
index 94ea573e..699a75eb 100644
|
|
||||||
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
|
|
||||||
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
|
|
||||||
@@ -105,8 +105,6 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
|
|
||||||
m_xdgSurface->m_window->resizeFromApplyConfigure(m_pending.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
- m_xdgSurface->setSizeHints();
|
|
||||||
-
|
|
||||||
m_applied = m_pending;
|
|
||||||
qCDebug(lcQpaWayland) << "Applied pending xdg_toplevel configure event:" << m_applied.size << m_applied.states;
|
|
||||||
}
|
|
||||||
@@ -267,6 +265,7 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *s
|
|
||||||
m_toplevel->set_parent(parentXdgSurface->m_toplevel->object());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ setSizeHints();
|
|
||||||
}
|
|
||||||
|
|
||||||
QWaylandXdgSurface::~QWaylandXdgSurface()
|
|
||||||
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
|
||||||
index 2277bbb8..2fdd0a7c 100644
|
|
||||||
--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
|
||||||
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
|
||||||
@@ -505,7 +505,7 @@ void tst_xdgshell::minMaxSize()
|
|
||||||
window.show();
|
|
||||||
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
|
|
||||||
|
|
||||||
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
|
|
||||||
+ // we don't roundtrip with our configuration the initial commit should be correct
|
|
||||||
|
|
||||||
QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(100, 100));
|
|
||||||
QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(1000, 1000));
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
|||||||
From bc07f9d8083f9f731fefb0f1180a18d2172eb57d Mon Sep 17 00:00:00 2001
|
|
||||||
From: David Edmundson <davidedmundson@kde.org>
|
|
||||||
Date: Mon, 14 Jun 2021 12:45:37 +0100
|
|
||||||
Subject: [PATCH 06/59] Fix build
|
|
||||||
|
|
||||||
1b5e43a593e917610e6245f7a272ac081c508ba4 relied on a patch that we can't
|
|
||||||
backport.
|
|
||||||
|
|
||||||
This adds that extra internal boolean backporting just the tiny part of
|
|
||||||
d6ac8cf6.
|
|
||||||
---
|
|
||||||
src/client/global/qwaylandclientextension.cpp | 5 ++++-
|
|
||||||
src/client/global/qwaylandclientextension_p.h | 1 +
|
|
||||||
2 files changed, 5 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/global/qwaylandclientextension.cpp b/src/client/global/qwaylandclientextension.cpp
|
|
||||||
index 2dc61b77..36609c08 100644
|
|
||||||
--- a/src/client/global/qwaylandclientextension.cpp
|
|
||||||
+++ b/src/client/global/qwaylandclientextension.cpp
|
|
||||||
@@ -74,7 +74,10 @@ void QWaylandClientExtensionPrivate::handleRegistryGlobal(void *data, ::wl_regis
|
|
||||||
void QWaylandClientExtension::addRegistryListener()
|
|
||||||
{
|
|
||||||
Q_D(QWaylandClientExtension);
|
|
||||||
- d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
|
|
||||||
+ if (!d->registered) {
|
|
||||||
+ d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
|
|
||||||
+ d->registered = true;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
QWaylandClientExtension::QWaylandClientExtension(const int ver)
|
|
||||||
diff --git a/src/client/global/qwaylandclientextension_p.h b/src/client/global/qwaylandclientextension_p.h
|
|
||||||
index 69cc46a0..9091efbe 100644
|
|
||||||
--- a/src/client/global/qwaylandclientextension_p.h
|
|
||||||
+++ b/src/client/global/qwaylandclientextension_p.h
|
|
||||||
@@ -68,6 +68,7 @@ public:
|
|
||||||
QtWaylandClient::QWaylandIntegration *waylandIntegration = nullptr;
|
|
||||||
int version = -1;
|
|
||||||
bool active = false;
|
|
||||||
+ bool registered = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtensionTemplatePrivate : public QWaylandClientExtensionPrivate
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
|||||||
From cfbb11da7f7ecbf6372967f01015d269d832dccf Mon Sep 17 00:00:00 2001
|
|
||||||
From: Zhang Liang <zhanglianga@uniontech.com>
|
|
||||||
Date: Mon, 1 Feb 2021 19:29:43 +0800
|
|
||||||
Subject: [PATCH 07/59] Fix: remove listener
|
|
||||||
|
|
||||||
Add the operation for removing the listener form listener list
|
|
||||||
|
|
||||||
Change-Id: Ief2ff1303b607eee499543303fe80e51f8f10cc5
|
|
||||||
Reviewed-by: David Edmundson <davidedmundson@kde.org>
|
|
||||||
(cherry picked from commit 16760280fd04cf70255bab16d9acecad254fdd8f)
|
|
||||||
---
|
|
||||||
src/client/qwaylanddisplay.cpp | 3 ++-
|
|
||||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
|
|
||||||
index 8a6d5db1..16f8ca1a 100644
|
|
||||||
--- a/src/client/qwaylanddisplay.cpp
|
|
||||||
+++ b/src/client/qwaylanddisplay.cpp
|
|
||||||
@@ -456,9 +456,10 @@ void QWaylandDisplay::addRegistryListener(RegistryListener listener, void *data)
|
|
||||||
|
|
||||||
void QWaylandDisplay::removeListener(RegistryListener listener, void *data)
|
|
||||||
{
|
|
||||||
- std::remove_if(mRegistryListeners.begin(), mRegistryListeners.end(), [=](Listener l){
|
|
||||||
+ auto iter = std::remove_if(mRegistryListeners.begin(), mRegistryListeners.end(), [=](Listener l){
|
|
||||||
return (l.listener == listener && l.data == data);
|
|
||||||
});
|
|
||||||
+ mRegistryListeners.erase(iter, mRegistryListeners.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t QWaylandDisplay::currentTimeMillisec()
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
|||||||
From 25218285ed45d32a93d10e354975ccbbd98cdb77 Mon Sep 17 00:00:00 2001
|
|
||||||
From: David Redondo <qt@david-redondo.de>
|
|
||||||
Date: Wed, 26 May 2021 14:49:40 +0200
|
|
||||||
Subject: [PATCH 08/59] Hook up queryKeyboardModifers
|
|
||||||
|
|
||||||
Can be useful when upon enter a modifiers event is received but no key
|
|
||||||
event so no QKeyEvent is generated.
|
|
||||||
|
|
||||||
Fixes: QTBUG-62786
|
|
||||||
Change-Id: I30b57fc78ce6d54d8f644ca95ba40e7e26eb24ed
|
|
||||||
Reviewed-by: Marco Martin <mart@kde.org>
|
|
||||||
Reviewed-by: David Edmundson <davidedmundson@kde.org>
|
|
||||||
|
|
||||||
|
|
||||||
(cherry picked from commit 4fa2baba8181ade4958a94e9531ec4f6919438a9)
|
|
||||||
---
|
|
||||||
src/client/qwaylandintegration.cpp | 8 ++++++++
|
|
||||||
src/client/qwaylandintegration_p.h | 2 ++
|
|
||||||
2 files changed, 10 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
|
|
||||||
index d257e2e3..cd8569b1 100644
|
|
||||||
--- a/src/client/qwaylandintegration.cpp
|
|
||||||
+++ b/src/client/qwaylandintegration.cpp
|
|
||||||
@@ -262,6 +262,14 @@ QWaylandDisplay *QWaylandIntegration::display() const
|
|
||||||
return mDisplay.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
+Qt::KeyboardModifiers QWaylandIntegration::queryKeyboardModifiers() const
|
|
||||||
+{
|
|
||||||
+ if (auto *seat = mDisplay->currentInputDevice()) {
|
|
||||||
+ return seat->modifiers();
|
|
||||||
+ }
|
|
||||||
+ return Qt::NoModifier;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
QList<int> QWaylandIntegration::possibleKeys(const QKeyEvent *event) const
|
|
||||||
{
|
|
||||||
if (auto *seat = mDisplay->currentInputDevice())
|
|
||||||
diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h
|
|
||||||
index ff70ae25..73b80658 100644
|
|
||||||
--- a/src/client/qwaylandintegration_p.h
|
|
||||||
+++ b/src/client/qwaylandintegration_p.h
|
|
||||||
@@ -107,6 +107,8 @@ public:
|
|
||||||
|
|
||||||
QWaylandDisplay *display() const;
|
|
||||||
|
|
||||||
+ Qt::KeyboardModifiers queryKeyboardModifiers() const override;
|
|
||||||
+
|
|
||||||
QList<int> possibleKeys(const QKeyEvent *event) const override;
|
|
||||||
|
|
||||||
QStringList themeNames() const override;
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
|||||||
From d9d5f69f5619dbaa40ca9b97981721467424947b Mon Sep 17 00:00:00 2001
|
|
||||||
From: Jan Blackquill <uhhadd@gmail.com>
|
|
||||||
Date: Tue, 24 Aug 2021 14:36:34 -0400
|
|
||||||
Subject: [PATCH 09/59] Correctly detect if image format is supported by
|
|
||||||
QImageWriter
|
|
||||||
|
|
||||||
The code queries potential image formats by stripping a mimetype of its
|
|
||||||
'image/' prefix and making the rest of the mimetype capitalised, such as
|
|
||||||
'image/png' -> 'PNG'. The problem is that this is then searched for in
|
|
||||||
QImageWriter::supportedImageFormats() by simple equality. The method
|
|
||||||
returns a list of lowercase byte arrays, not uppercase. As the codepath
|
|
||||||
can never match due to checking for an uppercase word in an array of
|
|
||||||
lowercase words, this means that images are effectively always sent as
|
|
||||||
BMP format, even if they should be sent in other formats, such as PNG
|
|
||||||
or JPEG.
|
|
||||||
|
|
||||||
A simple inspection with GDB (or a qDebug) reveals this:
|
|
||||||
|
|
||||||
```
|
|
||||||
(gdb) p QImageWriter::supportedImageFormats()
|
|
||||||
$31 = {"bmp" = {...}, "bw" = {...}, "cur" = {...}, "eps" = {...},
|
|
||||||
"epsf" = {...}, "epsi" = {...}, "icns" = {...},
|
|
||||||
"ico" = {...}, "jp2" = {...}, "jpeg" = {...}, "jpg" = {...},
|
|
||||||
"pbm" = {...}, "pcx" = {...}, "pgm" = {...},
|
|
||||||
"pic" = {...}, "png" = {...}, "ppm" = {...},
|
|
||||||
"rgb" = {...}, "rgba" = {...}, "sgi" = {...},
|
|
||||||
"tga" = {...}, "tif" = {...}, "tiff" = {...},
|
|
||||||
"wbmp" = {...}, "webp" = {...}, "xbm" = {...}, "xpm" = {...}}
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
(gdb) p QImageWriter::supportedImageFormats().contains("PNG")
|
|
||||||
$32 = false
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
(gdb) p QImageWriter::supportedImageFormats().contains("png")
|
|
||||||
$33 = true
|
|
||||||
```
|
|
||||||
|
|
||||||
The fix for this is simple: lowercase the remainder of the mimetype,
|
|
||||||
instead of uppercasing it, and we can start hitting the codepath that's
|
|
||||||
supposed to write non-BMP formats.
|
|
||||||
|
|
||||||
Change-Id: Id3e9b730b7edcabcb2f1b04d8ef0a4c1fb9c9159
|
|
||||||
Reviewed-by: David Edmundson <davidedmundson@kde.org>
|
|
||||||
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
|
||||||
(cherry picked from commit 6072c1dc87e185f30c014f764737ac97b906640f)
|
|
||||||
---
|
|
||||||
src/shared/qwaylandmimehelper.cpp | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/shared/qwaylandmimehelper.cpp b/src/shared/qwaylandmimehelper.cpp
|
|
||||||
index c5266ab3..e2fe1928 100644
|
|
||||||
--- a/src/shared/qwaylandmimehelper.cpp
|
|
||||||
+++ b/src/shared/qwaylandmimehelper.cpp
|
|
||||||
@@ -60,7 +60,7 @@ QByteArray QWaylandMimeHelper::getByteArray(QMimeData *mimeData, const QString &
|
|
||||||
buf.open(QIODevice::ReadWrite);
|
|
||||||
QByteArray fmt = "BMP";
|
|
||||||
if (mimeType.startsWith(QLatin1String("image/"))) {
|
|
||||||
- QByteArray imgFmt = mimeType.mid(6).toUpper().toLatin1();
|
|
||||||
+ QByteArray imgFmt = mimeType.mid(6).toLower().toLatin1();
|
|
||||||
if (QImageWriter::supportedImageFormats().contains(imgFmt))
|
|
||||||
fmt = imgFmt;
|
|
||||||
}
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
|||||||
From d2992d985306a8bec6298c5238a85ade1ae0c611 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
|
||||||
Date: Thu, 27 May 2021 19:55:04 -0300
|
|
||||||
Subject: [PATCH 10/59] Client: Don't always recreate frame callbacks
|
|
||||||
|
|
||||||
The main QWaylandWindow method that is executed when handling updates is
|
|
||||||
QWaylandWindow::handleUpdate(). This method always, unconditionally queues
|
|
||||||
a frame callback, regardless of whether any other one is already queued.
|
|
||||||
|
|
||||||
On some circumstances, e.g. when a window is hidden or completely obscured
|
|
||||||
by other windows, it stops receiving frame callbacks from the compositor.
|
|
||||||
However, QWaylandWindow would continue to request for them, which eventually
|
|
||||||
fills up the Wayland socket, and causes the application to crash.
|
|
||||||
|
|
||||||
This can be avoided by checking if the platform window is already waiting
|
|
||||||
for a frame callback, before queueing another one.
|
|
||||||
|
|
||||||
In QWaylandWindow::handleUpdate(), check if mWaitingForFrameCallback is true
|
|
||||||
before queueing frame callbacks, and early return if that's the case.
|
|
||||||
|
|
||||||
The XDG-shell test needed to be updated for this: The mock compositor is
|
|
||||||
not responding to any frame callbacks, so the window will be unexposed,
|
|
||||||
no longer get paint events and therefore not trigger any commit. This
|
|
||||||
worked by accident before because we were issuing updates quickly enough
|
|
||||||
to reset the timer before it had a chance to unexpose the window. The
|
|
||||||
easiest fix is just to disable the dependency on frame callbacks in
|
|
||||||
this test, since that is clearly not what it's testing.
|
|
||||||
|
|
||||||
Task-number: QTBUG-81504
|
|
||||||
Change-Id: Ieacb05c7d5a5fcf662243d9177ebcc308cb9ca84
|
|
||||||
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
|
||||||
Reviewed-by: Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
|
||||||
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
|
||||||
(cherry picked from commit cbc74ba6d7186457d8d07183272e952dee5f34f9)
|
|
||||||
---
|
|
||||||
src/client/qwaylandwindow.cpp | 4 ++++
|
|
||||||
tests/auto/client/xdgshell/tst_xdgshell.cpp | 2 ++
|
|
||||||
2 files changed, 6 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
|
|
||||||
index 5a390434..2dce02f0 100644
|
|
||||||
--- a/src/client/qwaylandwindow.cpp
|
|
||||||
+++ b/src/client/qwaylandwindow.cpp
|
|
||||||
@@ -1196,6 +1196,10 @@ void QWaylandWindow::requestUpdate()
|
|
||||||
void QWaylandWindow::handleUpdate()
|
|
||||||
{
|
|
||||||
qCDebug(lcWaylandBackingstore) << "handleUpdate" << QThread::currentThread();
|
|
||||||
+
|
|
||||||
+ if (mWaitingForFrameCallback)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
// TODO: Should sync subsurfaces avoid requesting frame callbacks?
|
|
||||||
QReadLocker lock(&mSurfaceLock);
|
|
||||||
if (!mSurface)
|
|
||||||
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
|
||||||
index 2fdd0a7c..e2593314 100644
|
|
||||||
--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
|
||||||
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
|
||||||
@@ -138,6 +138,7 @@ void tst_xdgshell::configureSize()
|
|
||||||
|
|
||||||
void tst_xdgshell::configureStates()
|
|
||||||
{
|
|
||||||
+ QVERIFY(qputenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT", "0"));
|
|
||||||
QRasterWindow window;
|
|
||||||
window.resize(64, 48);
|
|
||||||
window.show();
|
|
||||||
@@ -186,6 +187,7 @@ void tst_xdgshell::configureStates()
|
|
||||||
QCOMPARE(window.windowStates(), Qt::WindowNoState);
|
|
||||||
QCOMPARE(window.frameGeometry().size(), windowedSize);
|
|
||||||
// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
|
|
||||||
+ QVERIFY(qunsetenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void tst_xdgshell::popup()
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
|||||||
From cc3fbf3c1d36d5d997082927f895a88ea6d17474 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
|
||||||
Date: Thu, 27 May 2021 20:02:53 -0300
|
|
||||||
Subject: [PATCH 11/59] Client: Always destroy frame callback in the actual
|
|
||||||
callback
|
|
||||||
|
|
||||||
It's good hygiene to destroy all frame callbacks. Destroy the
|
|
||||||
frame callback and cleanup the mFrameCallback class member in
|
|
||||||
the callback itself. The callback destruction happens before
|
|
||||||
calling handleFrameCallback() to avoid the theoretical case
|
|
||||||
where another frame callback is queued by handleFrameCallback(),
|
|
||||||
and then immediately destroyed in the callback handler.
|
|
||||||
|
|
||||||
* asturmlechner 2021-09-27:
|
|
||||||
Conflict resolved from non-backported commit in dev branch:
|
|
||||||
93058de8d7e7c2f320c22b3bd898aa06cf5babcd
|
|
||||||
|
|
||||||
Change-Id: Ide6dc95e3402932c58bfc088a9d471fda821e9a1
|
|
||||||
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
|
||||||
(cherry picked from commit 42cdc61a93cf2acb09936aebb5e431fdbc0a26c6)
|
|
||||||
---
|
|
||||||
src/client/qwaylandwindow.cpp | 11 +++++------
|
|
||||||
1 file changed, 5 insertions(+), 6 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
|
|
||||||
index 2dce02f0..c532b44a 100644
|
|
||||||
--- a/src/client/qwaylandwindow.cpp
|
|
||||||
+++ b/src/client/qwaylandwindow.cpp
|
|
||||||
@@ -635,9 +635,13 @@ void QWaylandWindow::commit()
|
|
||||||
|
|
||||||
const wl_callback_listener QWaylandWindow::callbackListener = {
|
|
||||||
[](void *data, wl_callback *callback, uint32_t time) {
|
|
||||||
- Q_UNUSED(callback);
|
|
||||||
Q_UNUSED(time);
|
|
||||||
auto *window = static_cast<QWaylandWindow*>(data);
|
|
||||||
+
|
|
||||||
+ Q_ASSERT(callback == window->mFrameCallback);
|
|
||||||
+ wl_callback_destroy(callback);
|
|
||||||
+ window->mFrameCallback = nullptr;
|
|
||||||
+
|
|
||||||
window->handleFrameCallback();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1205,11 +1209,6 @@ void QWaylandWindow::handleUpdate()
|
|
||||||
if (!mSurface)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- if (mFrameCallback) {
|
|
||||||
- wl_callback_destroy(mFrameCallback);
|
|
||||||
- mFrameCallback = nullptr;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
QMutexLocker locker(mFrameQueue.mutex);
|
|
||||||
struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object()));
|
|
||||||
wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mFrameQueue.queue);
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,341 +0,0 @@
|
|||||||
From 2a68cb54a8a07a59e140fe8acd966ca6bb485afd Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?M=C3=A9ven=20Car?= <meven.car@enioka.com>
|
|
||||||
Date: Wed, 18 Aug 2021 18:28:20 +0200
|
|
||||||
Subject: [PATCH 12/59] Wayland client: use wl_keyboard to determine active
|
|
||||||
state
|
|
||||||
|
|
||||||
Commit f497a5bb87270174b8e0106b7eca1992d44ff15d made QWaylandDisplay
|
|
||||||
use the xdgshell's active state for QWindow::isActive(), instead of
|
|
||||||
using wl_keyboard activate/deactivate events.
|
|
||||||
|
|
||||||
That seems to have been a misunderstanding, since xdgshell activation
|
|
||||||
is only supposed to be used to determine visual appearance, and there
|
|
||||||
is an explicit warning not to assume it means focus.
|
|
||||||
|
|
||||||
This commit reverts this logic back to listening to wl_keyboard.
|
|
||||||
It adds a fallback when there is no wl_keyboard available to handle
|
|
||||||
activated/deactivated events through xdg-shell, in order to fix
|
|
||||||
QTBUG-53702.
|
|
||||||
|
|
||||||
windowStates is handled so that we're not using the Xdg hint for
|
|
||||||
anything with QWindowSystemInterface::handleWindowStateChanged or
|
|
||||||
anything where we need to track only having one active.
|
|
||||||
|
|
||||||
We are still exposing it for decorations, which is the only reason to
|
|
||||||
use the Xdghint over keyboard focus - so you can keep the toplevel
|
|
||||||
active whilst you show a popup.
|
|
||||||
|
|
||||||
cherry-pick 40036a1b80e5234e6db7d5cbeff122aa7ee13e20
|
|
||||||
|
|
||||||
Change-Id: I4343d2ed9fb5b066cde95628ed0b4ccc84a424db
|
|
||||||
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
|
||||||
---
|
|
||||||
src/client/qwaylanddisplay.cpp | 19 +++++++++++--------
|
|
||||||
src/client/qwaylanddisplay_p.h | 1 +
|
|
||||||
src/client/qwaylandwindow.cpp | 13 +++++++++++--
|
|
||||||
src/client/qwaylandwindow_p.h | 1 +
|
|
||||||
.../qwaylandshellintegration_p.h | 7 +++----
|
|
||||||
.../qwaylandxdgshellv5integration.cpp | 7 -------
|
|
||||||
.../qwaylandxdgshellv5integration_p.h | 1 -
|
|
||||||
.../qwaylandxdgshellv6integration.cpp | 14 --------------
|
|
||||||
.../qwaylandxdgshellv6integration_p.h | 1 -
|
|
||||||
.../xdg-shell/qwaylandxdgshell.cpp | 16 +++++-----------
|
|
||||||
.../xdg-shell/qwaylandxdgshellintegration.cpp | 14 --------------
|
|
||||||
.../xdg-shell/qwaylandxdgshellintegration_p.h | 1 -
|
|
||||||
tests/auto/client/xdgshell/tst_xdgshell.cpp | 10 +++++++---
|
|
||||||
13 files changed, 39 insertions(+), 66 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
|
|
||||||
index 16f8ca1a..d1ca0274 100644
|
|
||||||
--- a/src/client/qwaylanddisplay.cpp
|
|
||||||
+++ b/src/client/qwaylanddisplay.cpp
|
|
||||||
@@ -579,14 +579,10 @@ void QWaylandDisplay::handleKeyboardFocusChanged(QWaylandInputDevice *inputDevic
|
|
||||||
if (mLastKeyboardFocus == keyboardFocus)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- if (mWaylandIntegration->mShellIntegration) {
|
|
||||||
- mWaylandIntegration->mShellIntegration->handleKeyboardFocusChanged(keyboardFocus, mLastKeyboardFocus);
|
|
||||||
- } else {
|
|
||||||
- if (keyboardFocus)
|
|
||||||
- handleWindowActivated(keyboardFocus);
|
|
||||||
- if (mLastKeyboardFocus)
|
|
||||||
- handleWindowDeactivated(mLastKeyboardFocus);
|
|
||||||
- }
|
|
||||||
+ if (keyboardFocus)
|
|
||||||
+ handleWindowActivated(keyboardFocus);
|
|
||||||
+ if (mLastKeyboardFocus)
|
|
||||||
+ handleWindowDeactivated(mLastKeyboardFocus);
|
|
||||||
|
|
||||||
mLastKeyboardFocus = keyboardFocus;
|
|
||||||
}
|
|
||||||
@@ -631,6 +627,13 @@ QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const
|
|
||||||
return mInputDevices.isEmpty() ? 0 : mInputDevices.first();
|
|
||||||
}
|
|
||||||
|
|
||||||
+bool QWaylandDisplay::isKeyboardAvailable() const
|
|
||||||
+{
|
|
||||||
+ return std::any_of(
|
|
||||||
+ mInputDevices.constBegin(), mInputDevices.constEnd(),
|
|
||||||
+ [this](const QWaylandInputDevice *device) { return device->keyboard() != nullptr; });
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
#if QT_CONFIG(cursor)
|
|
||||||
|
|
||||||
QWaylandCursor *QWaylandDisplay::waylandCursor()
|
|
||||||
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
|
|
||||||
index 1bad8b67..15104d65 100644
|
|
||||||
--- a/src/client/qwaylanddisplay_p.h
|
|
||||||
+++ b/src/client/qwaylanddisplay_p.h
|
|
||||||
@@ -219,6 +219,7 @@ public:
|
|
||||||
void destroyFrameQueue(const FrameQueue &q);
|
|
||||||
void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1);
|
|
||||||
|
|
||||||
+ bool isKeyboardAvailable() const;
|
|
||||||
public slots:
|
|
||||||
void blockingReadEvents();
|
|
||||||
void flushRequests();
|
|
||||||
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
|
|
||||||
index c532b44a..fdffe584 100644
|
|
||||||
--- a/src/client/qwaylandwindow.cpp
|
|
||||||
+++ b/src/client/qwaylandwindow.cpp
|
|
||||||
@@ -96,7 +96,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
|
|
||||||
QWaylandWindow::~QWaylandWindow()
|
|
||||||
{
|
|
||||||
mDisplay->destroyFrameQueue(mFrameQueue);
|
|
||||||
- mDisplay->handleWindowDestroyed(this);
|
|
||||||
|
|
||||||
delete mWindowDecoration;
|
|
||||||
|
|
||||||
@@ -266,6 +265,8 @@ void QWaylandWindow::reset()
|
|
||||||
|
|
||||||
mMask = QRegion();
|
|
||||||
mQueuedBuffer = nullptr;
|
|
||||||
+
|
|
||||||
+ mDisplay->handleWindowDestroyed(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface)
|
|
||||||
@@ -1109,10 +1110,18 @@ bool QWaylandWindow::setMouseGrabEnabled(bool grab)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
+Qt::WindowStates QWaylandWindow::windowStates() const
|
|
||||||
+{
|
|
||||||
+ return mLastReportedWindowStates;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void QWaylandWindow::handleWindowStatesChanged(Qt::WindowStates states)
|
|
||||||
{
|
|
||||||
createDecoration();
|
|
||||||
- QWindowSystemInterface::handleWindowStateChanged(window(), states, mLastReportedWindowStates);
|
|
||||||
+ Qt::WindowStates statesWithoutActive = states & ~Qt::WindowActive;
|
|
||||||
+ Qt::WindowStates lastStatesWithoutActive = mLastReportedWindowStates & ~Qt::WindowActive;
|
|
||||||
+ QWindowSystemInterface::handleWindowStateChanged(window(), statesWithoutActive,
|
|
||||||
+ lastStatesWithoutActive);
|
|
||||||
mLastReportedWindowStates = states;
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
|
|
||||||
index 01337cff..fb3ed606 100644
|
|
||||||
--- a/src/client/qwaylandwindow_p.h
|
|
||||||
+++ b/src/client/qwaylandwindow_p.h
|
|
||||||
@@ -148,6 +148,7 @@ public:
|
|
||||||
void setWindowState(Qt::WindowStates states) override;
|
|
||||||
void setWindowFlags(Qt::WindowFlags flags) override;
|
|
||||||
void handleWindowStatesChanged(Qt::WindowStates states);
|
|
||||||
+ Qt::WindowStates windowStates() const;
|
|
||||||
|
|
||||||
void raise() override;
|
|
||||||
void lower() override;
|
|
||||||
diff --git a/src/client/shellintegration/qwaylandshellintegration_p.h b/src/client/shellintegration/qwaylandshellintegration_p.h
|
|
||||||
index ccad0048..4cc9b3b8 100644
|
|
||||||
--- a/src/client/shellintegration/qwaylandshellintegration_p.h
|
|
||||||
+++ b/src/client/shellintegration/qwaylandshellintegration_p.h
|
|
||||||
@@ -73,11 +73,10 @@ public:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual QWaylandShellSurface *createShellSurface(QWaylandWindow *window) = 0;
|
|
||||||
+ // kept for binary compat with layer-shell-qt
|
|
||||||
virtual void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
|
|
||||||
- if (newFocus)
|
|
||||||
- m_display->handleWindowActivated(newFocus);
|
|
||||||
- if (oldFocus)
|
|
||||||
- m_display->handleWindowDeactivated(oldFocus);
|
|
||||||
+ Q_UNUSED(newFocus);
|
|
||||||
+ Q_UNUSED(oldFocus);
|
|
||||||
}
|
|
||||||
virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) {
|
|
||||||
Q_UNUSED(resource);
|
|
||||||
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
|
|
||||||
index 4e25949f..cfc60939 100644
|
|
||||||
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
|
|
||||||
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
|
|
||||||
@@ -85,13 +85,6 @@ QWaylandShellSurface *QWaylandXdgShellV5Integration::createShellSurface(QWayland
|
|
||||||
return m_xdgShell->createXdgSurface(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
-void QWaylandXdgShellV5Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
|
|
||||||
- if (newFocus && qobject_cast<QWaylandXdgPopupV5 *>(newFocus->shellSurface()))
|
|
||||||
- m_display->handleWindowActivated(newFocus);
|
|
||||||
- if (oldFocus && qobject_cast<QWaylandXdgPopupV5 *>(oldFocus->shellSurface()))
|
|
||||||
- m_display->handleWindowDeactivated(oldFocus);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
}
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
|
|
||||||
index ce6bdb9e..aed88670 100644
|
|
||||||
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
|
|
||||||
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
|
|
||||||
@@ -67,7 +67,6 @@ public:
|
|
||||||
QWaylandXdgShellV5Integration() {}
|
|
||||||
bool initialize(QWaylandDisplay *display) override;
|
|
||||||
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
|
|
||||||
- void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QScopedPointer<QWaylandXdgShellV5> m_xdgShell;
|
|
||||||
diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
|
|
||||||
index 03164316..e8da8ba1 100644
|
|
||||||
--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
|
|
||||||
+++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
|
|
||||||
@@ -68,20 +68,6 @@ QWaylandShellSurface *QWaylandXdgShellV6Integration::createShellSurface(QWayland
|
|
||||||
return m_xdgShell->getXdgSurface(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
-void QWaylandXdgShellV6Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
|
|
||||||
-{
|
|
||||||
- if (newFocus) {
|
|
||||||
- auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(newFocus->shellSurface());
|
|
||||||
- if (xdgSurface && !xdgSurface->handlesActiveState())
|
|
||||||
- m_display->handleWindowActivated(newFocus);
|
|
||||||
- }
|
|
||||||
- if (oldFocus && qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface())) {
|
|
||||||
- auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface());
|
|
||||||
- if (xdgSurface && !xdgSurface->handlesActiveState())
|
|
||||||
- m_display->handleWindowDeactivated(oldFocus);
|
|
||||||
- }
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
}
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
|
|
||||||
index 261f8cbb..c1bcd5c6 100644
|
|
||||||
--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
|
|
||||||
+++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
|
|
||||||
@@ -65,7 +65,6 @@ public:
|
|
||||||
QWaylandXdgShellV6Integration() {}
|
|
||||||
bool initialize(QWaylandDisplay *display) override;
|
|
||||||
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
|
|
||||||
- void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QScopedPointer<QWaylandXdgShellV6> m_xdgShell;
|
|
||||||
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
|
|
||||||
index 699a75eb..888bab77 100644
|
|
||||||
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
|
|
||||||
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
|
|
||||||
@@ -67,11 +67,6 @@ QWaylandXdgSurface::Toplevel::Toplevel(QWaylandXdgSurface *xdgSurface)
|
|
||||||
|
|
||||||
QWaylandXdgSurface::Toplevel::~Toplevel()
|
|
||||||
{
|
|
||||||
- if (m_applied.states & Qt::WindowActive) {
|
|
||||||
- QWaylandWindow *window = m_xdgSurface->window();
|
|
||||||
- window->display()->handleWindowDeactivated(window);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
// The protocol spec requires that the decoration object is deleted before xdg_toplevel.
|
|
||||||
delete m_decoration;
|
|
||||||
m_decoration = nullptr;
|
|
||||||
@@ -85,16 +80,15 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
|
|
||||||
if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen)))
|
|
||||||
m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size();
|
|
||||||
|
|
||||||
- if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive))
|
|
||||||
+ if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive)
|
|
||||||
+ && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
|
|
||||||
m_xdgSurface->m_window->display()->handleWindowActivated(m_xdgSurface->m_window);
|
|
||||||
|
|
||||||
- if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive))
|
|
||||||
+ if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive)
|
|
||||||
+ && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
|
|
||||||
m_xdgSurface->m_window->display()->handleWindowDeactivated(m_xdgSurface->m_window);
|
|
||||||
|
|
||||||
- // TODO: none of the other plugins send WindowActive either, but is it on purpose?
|
|
||||||
- Qt::WindowStates statesWithoutActive = m_pending.states & ~Qt::WindowActive;
|
|
||||||
-
|
|
||||||
- m_xdgSurface->m_window->handleWindowStatesChanged(statesWithoutActive);
|
|
||||||
+ m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states);
|
|
||||||
|
|
||||||
if (m_pending.size.isEmpty()) {
|
|
||||||
// An empty size in the configure means it's up to the client to choose the size
|
|
||||||
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
|
|
||||||
index 8769d971..da0dd6a7 100644
|
|
||||||
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
|
|
||||||
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
|
|
||||||
@@ -69,20 +69,6 @@ QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWi
|
|
||||||
return m_xdgShell->getXdgSurface(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
-void QWaylandXdgShellIntegration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
|
|
||||||
-{
|
|
||||||
- if (newFocus) {
|
|
||||||
- auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(newFocus->shellSurface());
|
|
||||||
- if (xdgSurface && !xdgSurface->handlesActiveState())
|
|
||||||
- m_display->handleWindowActivated(newFocus);
|
|
||||||
- }
|
|
||||||
- if (oldFocus && qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface())) {
|
|
||||||
- auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface());
|
|
||||||
- if (xdgSurface && !xdgSurface->handlesActiveState())
|
|
||||||
- m_display->handleWindowDeactivated(oldFocus);
|
|
||||||
- }
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
}
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
|
|
||||||
index b6caa6c9..2f929f98 100644
|
|
||||||
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
|
|
||||||
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
|
|
||||||
@@ -65,7 +65,6 @@ public:
|
|
||||||
QWaylandXdgShellIntegration() {}
|
|
||||||
bool initialize(QWaylandDisplay *display) override;
|
|
||||||
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
|
|
||||||
- void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QScopedPointer<QWaylandXdgShell> m_xdgShell;
|
|
||||||
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
|
||||||
index e2593314..73d1eb9c 100644
|
|
||||||
--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
|
||||||
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
|
||||||
@@ -31,6 +31,7 @@
|
|
||||||
#include <QtGui/QOpenGLWindow>
|
|
||||||
#include <QtGui/qpa/qplatformnativeinterface.h>
|
|
||||||
#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
|
|
||||||
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
|
|
||||||
|
|
||||||
using namespace MockCompositor;
|
|
||||||
|
|
||||||
@@ -155,9 +156,12 @@ void tst_xdgshell::configureStates()
|
|
||||||
// Toplevel windows don't know their position on xdg-shell
|
|
||||||
// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
|
|
||||||
|
|
||||||
-// QEXPECT_FAIL("", "configure has already been acked, we shouldn't have to wait for isActive", Continue);
|
|
||||||
-// QVERIFY(window.isActive());
|
|
||||||
- QTRY_VERIFY(window.isActive()); // Just make sure it eventually get's set correctly
|
|
||||||
+ // window.windowstate() is driven by keyboard focus, however for decorations we want to follow
|
|
||||||
+ // XDGShell this is internal to QtWayland so it is queried directly
|
|
||||||
+ auto waylandWindow = static_cast<QtWaylandClient::QWaylandWindow *>(window.handle());
|
|
||||||
+ Q_ASSERT(waylandWindow);
|
|
||||||
+ QTRY_VERIFY(waylandWindow->windowStates().testFlag(
|
|
||||||
+ Qt::WindowActive)); // Just make sure it eventually get's set correctly
|
|
||||||
|
|
||||||
const QSize screenSize(640, 480);
|
|
||||||
const uint maximizedSerial = exec([=] {
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
|||||||
From 888f3c6eca8e807a3ca870067e080349a76a5703 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Jan Grulich <jgrulich@redhat.com>
|
|
||||||
Date: Fri, 16 Jul 2021 13:00:03 +0200
|
|
||||||
Subject: [PATCH 13/59] Client: do not empty clipboard when a new popup/window
|
|
||||||
is opened
|
|
||||||
|
|
||||||
If we open a new popup or a window within the same app we have to avoid
|
|
||||||
invalidating selection offer when losing focus, because it's still the
|
|
||||||
same client who has the focus and we might not get a new selection offer
|
|
||||||
by the compositor and therefore we would lose clipboard content.
|
|
||||||
|
|
||||||
Fixes: QTBUG-93474
|
|
||||||
Change-Id: Ia2ef826c2967b1daf1cdeb085e8dae66d090dbcf
|
|
||||||
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
|
||||||
Reviewed-by: David Edmundson <davidedmundson@kde.org>
|
|
||||||
|
|
||||||
Cherry-pick: 1e57ebd501cfc2255300392cd4565cd034efeed8
|
|
||||||
---
|
|
||||||
src/client/qwaylanddisplay.cpp | 13 +++++++++++++
|
|
||||||
src/client/qwaylandinputdevice.cpp | 8 --------
|
|
||||||
2 files changed, 13 insertions(+), 8 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
|
|
||||||
index d1ca0274..7560bf41 100644
|
|
||||||
--- a/src/client/qwaylanddisplay.cpp
|
|
||||||
+++ b/src/client/qwaylanddisplay.cpp
|
|
||||||
@@ -601,6 +601,19 @@ void QWaylandDisplay::handleWaylandSync()
|
|
||||||
QWindow *activeWindow = mActiveWindows.empty() ? nullptr : mActiveWindows.last()->window();
|
|
||||||
if (activeWindow != QGuiApplication::focusWindow())
|
|
||||||
QWindowSystemInterface::handleWindowActivated(activeWindow);
|
|
||||||
+
|
|
||||||
+ if (!activeWindow) {
|
|
||||||
+ if (lastInputDevice()) {
|
|
||||||
+#if QT_CONFIG(clipboard)
|
|
||||||
+ if (auto *dataDevice = lastInputDevice()->dataDevice())
|
|
||||||
+ dataDevice->invalidateSelectionOffer();
|
|
||||||
+#endif
|
|
||||||
+#if QT_CONFIG(wayland_client_primary_selection)
|
|
||||||
+ if (auto *device = lastInputDevice()->primarySelectionDevice())
|
|
||||||
+ device->invalidateSelectionOffer();
|
|
||||||
+#endif
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
const wl_callback_listener QWaylandDisplay::syncCallbackListener = {
|
|
||||||
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
|
|
||||||
index 08e8adb8..e1111124 100644
|
|
||||||
--- a/src/client/qwaylandinputdevice.cpp
|
|
||||||
+++ b/src/client/qwaylandinputdevice.cpp
|
|
||||||
@@ -1304,14 +1304,6 @@ void QWaylandInputDevice::Keyboard::handleFocusDestroyed()
|
|
||||||
void QWaylandInputDevice::Keyboard::handleFocusLost()
|
|
||||||
{
|
|
||||||
mFocus = nullptr;
|
|
||||||
-#if QT_CONFIG(clipboard)
|
|
||||||
- if (auto *dataDevice = mParent->dataDevice())
|
|
||||||
- dataDevice->invalidateSelectionOffer();
|
|
||||||
-#endif
|
|
||||||
-#if QT_CONFIG(wayland_client_primary_selection)
|
|
||||||
- if (auto *device = mParent->primarySelectionDevice())
|
|
||||||
- device->invalidateSelectionOffer();
|
|
||||||
-#endif
|
|
||||||
mParent->mQDisplay->handleKeyboardFocusChanged(mParent);
|
|
||||||
mRepeatTimer.stop();
|
|
||||||
}
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,512 +0,0 @@
|
|||||||
From 23c698917e0fdac0d9519334b7c375cf226e36c7 Mon Sep 17 00:00:00 2001
|
|
||||||
From: David Edmundson <davidedmundson@kde.org>
|
|
||||||
Date: Tue, 16 Feb 2021 09:51:47 +0000
|
|
||||||
Subject: [PATCH 14/59] Client: Implement DataDeviceV3
|
|
||||||
|
|
||||||
DataDeviceV2 fixes a leak of DataDevice resources.
|
|
||||||
|
|
||||||
DataDeviceV3 brings multiple improvements:
|
|
||||||
|
|
||||||
Action negotiation. The source announces which actions are supported,
|
|
||||||
the target then announces which subset of those action the target
|
|
||||||
supports and a preferred action. After negotiation both the source and
|
|
||||||
target are notified of which action is to be performed.
|
|
||||||
|
|
||||||
Drag sources are now notified when contents are dropped and when a
|
|
||||||
client has finished with the drag and drop operation.
|
|
||||||
|
|
||||||
A good test is the draggableicons example in QtBase.
|
|
||||||
|
|
||||||
Change-Id: I55e9759ca5a2e4218d02d863144a64ade53ef764
|
|
||||||
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
|
||||||
(cherry picked from commit 283a2d61d03315495a52d82f356e7cb5292f4bb4)
|
|
||||||
---
|
|
||||||
src/client/qwaylanddatadevice.cpp | 84 ++++++++++++++-----
|
|
||||||
src/client/qwaylanddatadevice_p.h | 8 +-
|
|
||||||
src/client/qwaylanddatadevicemanager.cpp | 4 +-
|
|
||||||
src/client/qwaylanddatadevicemanager_p.h | 2 +-
|
|
||||||
src/client/qwaylanddataoffer.cpp | 25 ++++++
|
|
||||||
src/client/qwaylanddataoffer_p.h | 4 +
|
|
||||||
src/client/qwaylanddatasource.cpp | 27 +++++-
|
|
||||||
src/client/qwaylanddatasource_p.h | 10 ++-
|
|
||||||
src/client/qwaylanddisplay.cpp | 2 +-
|
|
||||||
src/client/qwaylanddnd.cpp | 24 +++---
|
|
||||||
src/client/qwaylanddnd_p.h | 7 +-
|
|
||||||
.../client/datadevicev1/tst_datadevicev1.cpp | 2 +-
|
|
||||||
12 files changed, 153 insertions(+), 46 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp
|
|
||||||
index 0124b890..d154c695 100644
|
|
||||||
--- a/src/client/qwaylanddatadevice.cpp
|
|
||||||
+++ b/src/client/qwaylanddatadevice.cpp
|
|
||||||
@@ -72,6 +72,8 @@ QWaylandDataDevice::QWaylandDataDevice(QWaylandDataDeviceManager *manager, QWayl
|
|
||||||
|
|
||||||
QWaylandDataDevice::~QWaylandDataDevice()
|
|
||||||
{
|
|
||||||
+ if (wl_data_device_get_version(object()) >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION)
|
|
||||||
+ release();
|
|
||||||
}
|
|
||||||
|
|
||||||
QWaylandDataOffer *QWaylandDataDevice::selectionOffer() const
|
|
||||||
@@ -110,7 +112,7 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const
|
|
||||||
return m_dragOffer.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
-bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
|
|
||||||
+bool QWaylandDataDevice::startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon)
|
|
||||||
{
|
|
||||||
auto *seat = m_display->currentInputDevice();
|
|
||||||
auto *origin = seat->pointerFocus();
|
|
||||||
@@ -123,8 +125,28 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
|
|
||||||
}
|
|
||||||
|
|
||||||
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
|
|
||||||
+
|
|
||||||
+ if (wl_data_device_get_version(object()) >= 3)
|
|
||||||
+ m_dragSource->set_actions(dropActionsToWl(supportedActions));
|
|
||||||
+
|
|
||||||
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
|
|
||||||
- connect(m_dragSource.data(), &QWaylandDataSource::targetChanged, this, &QWaylandDataDevice::dragSourceTargetChanged);
|
|
||||||
+ connect(m_dragSource.data(), &QWaylandDataSource::dndResponseUpdated, this, [this](bool accepted, Qt::DropAction action) {
|
|
||||||
+ auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
|
|
||||||
+ // in old versions drop action is not set, so we guess
|
|
||||||
+ if (wl_data_source_get_version(m_dragSource->object()) < 3) {
|
|
||||||
+ drag->setResponse(accepted);
|
|
||||||
+ } else {
|
|
||||||
+ QPlatformDropQtResponse response(accepted, action);
|
|
||||||
+ drag->setResponse(response);
|
|
||||||
+ }
|
|
||||||
+ });
|
|
||||||
+ connect(m_dragSource.data(), &QWaylandDataSource::dndDropped, this, [](bool accepted, Qt::DropAction action) {
|
|
||||||
+ QPlatformDropQtResponse response(accepted, action);
|
|
||||||
+ static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setDropResponse(response);
|
|
||||||
+ });
|
|
||||||
+ connect(m_dragSource.data(), &QWaylandDataSource::finished, this, []() {
|
|
||||||
+ static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag();
|
|
||||||
+ });
|
|
||||||
|
|
||||||
start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial());
|
|
||||||
return true;
|
|
||||||
@@ -153,7 +175,7 @@ void QWaylandDataDevice::data_device_drop()
|
|
||||||
supportedActions = drag->supportedActions();
|
|
||||||
} else if (m_dragOffer) {
|
|
||||||
dragData = m_dragOffer->mimeData();
|
|
||||||
- supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
|
|
||||||
+ supportedActions = m_dragOffer->supportedActions();
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
@@ -163,7 +185,11 @@ void QWaylandDataDevice::data_device_drop()
|
|
||||||
QGuiApplication::keyboardModifiers());
|
|
||||||
|
|
||||||
if (drag) {
|
|
||||||
- static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag(response);
|
|
||||||
+ auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
|
|
||||||
+ drag->setDropResponse(response);
|
|
||||||
+ drag->finishDrag();
|
|
||||||
+ } else if (m_dragOffer) {
|
|
||||||
+ m_dragOffer->finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -187,7 +213,7 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
|
|
||||||
supportedActions = drag->supportedActions();
|
|
||||||
} else if (m_dragOffer) {
|
|
||||||
dragData = m_dragOffer->mimeData();
|
|
||||||
- supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
|
|
||||||
+ supportedActions = m_dragOffer->supportedActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QPlatformDragQtResponse &response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
|
|
||||||
@@ -198,11 +224,7 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
|
|
||||||
static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (response.isAccepted()) {
|
|
||||||
- wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData());
|
|
||||||
- } else {
|
|
||||||
- wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr);
|
|
||||||
- }
|
|
||||||
+ sendResponse(supportedActions, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWaylandDataDevice::data_device_leave()
|
|
||||||
@@ -236,10 +258,10 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
|
|
||||||
supportedActions = drag->supportedActions();
|
|
||||||
} else {
|
|
||||||
dragData = m_dragOffer->mimeData();
|
|
||||||
- supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
|
|
||||||
+ supportedActions = m_dragOffer->supportedActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
- QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
|
|
||||||
+ const QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
|
|
||||||
QGuiApplication::mouseButtons(),
|
|
||||||
QGuiApplication::keyboardModifiers());
|
|
||||||
|
|
||||||
@@ -247,11 +269,7 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
|
|
||||||
static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (response.isAccepted()) {
|
|
||||||
- wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData());
|
|
||||||
- } else {
|
|
||||||
- wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr);
|
|
||||||
- }
|
|
||||||
+ sendResponse(supportedActions, response);
|
|
||||||
}
|
|
||||||
#endif // QT_CONFIG(draganddrop)
|
|
||||||
|
|
||||||
@@ -281,11 +299,6 @@ void QWaylandDataDevice::dragSourceCancelled()
|
|
||||||
m_dragSource.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
-void QWaylandDataDevice::dragSourceTargetChanged(const QString &mimeType)
|
|
||||||
-{
|
|
||||||
- static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->updateTarget(mimeType);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) const
|
|
||||||
{
|
|
||||||
QPoint pnt(wl_fixed_to_int(x), wl_fixed_to_int(y));
|
|
||||||
@@ -298,6 +311,33 @@ QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) con
|
|
||||||
}
|
|
||||||
return pnt;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+void QWaylandDataDevice::sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response)
|
|
||||||
+{
|
|
||||||
+ if (response.isAccepted()) {
|
|
||||||
+ if (wl_data_device_get_version(object()) >= 3)
|
|
||||||
+ m_dragOffer->set_actions(dropActionsToWl(supportedActions), dropActionsToWl(response.acceptedAction()));
|
|
||||||
+
|
|
||||||
+ m_dragOffer->accept(m_enterSerial, m_dragOffer->firstFormat());
|
|
||||||
+ } else {
|
|
||||||
+ m_dragOffer->accept(m_enterSerial, QString());
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+int QWaylandDataDevice::dropActionsToWl(Qt::DropActions actions)
|
|
||||||
+{
|
|
||||||
+
|
|
||||||
+ int wlActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
|
|
||||||
+ if (actions & Qt::CopyAction)
|
|
||||||
+ wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
|
||||||
+ if (actions & (Qt::MoveAction | Qt::TargetMoveAction))
|
|
||||||
+ wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
|
||||||
+
|
|
||||||
+ // wayland does not support LinkAction at the time of writing
|
|
||||||
+ return wlActions;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
#endif // QT_CONFIG(draganddrop)
|
|
||||||
|
|
||||||
}
|
|
||||||
diff --git a/src/client/qwaylanddatadevice_p.h b/src/client/qwaylanddatadevice_p.h
|
|
||||||
index 16c3ad28..801dcc2c 100644
|
|
||||||
--- a/src/client/qwaylanddatadevice_p.h
|
|
||||||
+++ b/src/client/qwaylanddatadevice_p.h
|
|
||||||
@@ -64,6 +64,7 @@ QT_REQUIRE_CONFIG(wayland_datadevice);
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
class QMimeData;
|
|
||||||
+class QPlatformDragQtResponse;
|
|
||||||
class QWindow;
|
|
||||||
|
|
||||||
namespace QtWaylandClient {
|
|
||||||
@@ -89,7 +90,7 @@ public:
|
|
||||||
|
|
||||||
#if QT_CONFIG(draganddrop)
|
|
||||||
QWaylandDataOffer *dragOffer() const;
|
|
||||||
- bool startDrag(QMimeData *mimeData, QWaylandWindow *icon);
|
|
||||||
+ bool startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon);
|
|
||||||
void cancelDrag();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -109,13 +110,16 @@ private Q_SLOTS:
|
|
||||||
|
|
||||||
#if QT_CONFIG(draganddrop)
|
|
||||||
void dragSourceCancelled();
|
|
||||||
- void dragSourceTargetChanged(const QString &mimeType);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if QT_CONFIG(draganddrop)
|
|
||||||
QPoint calculateDragPosition(int x, int y, QWindow *wnd) const;
|
|
||||||
#endif
|
|
||||||
+ void sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response);
|
|
||||||
+
|
|
||||||
+ static int dropActionsToWl(Qt::DropActions dropActions);
|
|
||||||
+
|
|
||||||
|
|
||||||
QWaylandDisplay *m_display = nullptr;
|
|
||||||
QWaylandInputDevice *m_inputDevice = nullptr;
|
|
||||||
diff --git a/src/client/qwaylanddatadevicemanager.cpp b/src/client/qwaylanddatadevicemanager.cpp
|
|
||||||
index 35d67307..6dc4f77f 100644
|
|
||||||
--- a/src/client/qwaylanddatadevicemanager.cpp
|
|
||||||
+++ b/src/client/qwaylanddatadevicemanager.cpp
|
|
||||||
@@ -50,8 +50,8 @@ QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
namespace QtWaylandClient {
|
|
||||||
|
|
||||||
-QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id)
|
|
||||||
- : wl_data_device_manager(display->wl_registry(), id, 1)
|
|
||||||
+QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id)
|
|
||||||
+ : wl_data_device_manager(display->wl_registry(), id, qMin(version, 3))
|
|
||||||
, m_display(display)
|
|
||||||
{
|
|
||||||
// Create transfer devices for all input devices.
|
|
||||||
diff --git a/src/client/qwaylanddatadevicemanager_p.h b/src/client/qwaylanddatadevicemanager_p.h
|
|
||||||
index bd05c0fb..510d9be4 100644
|
|
||||||
--- a/src/client/qwaylanddatadevicemanager_p.h
|
|
||||||
+++ b/src/client/qwaylanddatadevicemanager_p.h
|
|
||||||
@@ -68,7 +68,7 @@ class QWaylandInputDevice;
|
|
||||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandDataDeviceManager : public QtWayland::wl_data_device_manager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
- QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id);
|
|
||||||
+ QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id);
|
|
||||||
~QWaylandDataDeviceManager() override;
|
|
||||||
|
|
||||||
QWaylandDataDevice *getDataDevice(QWaylandInputDevice *inputDevice);
|
|
||||||
diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp
|
|
||||||
index 2297e8a1..c9e158cc 100644
|
|
||||||
--- a/src/client/qwaylanddataoffer.cpp
|
|
||||||
+++ b/src/client/qwaylanddataoffer.cpp
|
|
||||||
@@ -82,6 +82,15 @@ QMimeData *QWaylandDataOffer::mimeData()
|
|
||||||
return m_mimeData.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
+Qt::DropActions QWaylandDataOffer::supportedActions() const
|
|
||||||
+{
|
|
||||||
+ if (wl_data_offer_get_version(const_cast<::wl_data_offer*>(object())) < 3) {
|
|
||||||
+ return Qt::MoveAction | Qt::CopyAction;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return m_supportedActions;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void QWaylandDataOffer::startReceiving(const QString &mimeType, int fd)
|
|
||||||
{
|
|
||||||
receive(mimeType, fd);
|
|
||||||
@@ -93,6 +102,22 @@ void QWaylandDataOffer::data_offer_offer(const QString &mime_type)
|
|
||||||
m_mimeData->appendFormat(mime_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
+void QWaylandDataOffer::data_offer_action(uint32_t dnd_action)
|
|
||||||
+{
|
|
||||||
+ Q_UNUSED(dnd_action);
|
|
||||||
+ // This is the compositor telling the drag target what action it should perform
|
|
||||||
+ // It does not map nicely into Qt final drop semantics, other than pretending there is only one supported action?
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void QWaylandDataOffer::data_offer_source_actions(uint32_t source_actions)
|
|
||||||
+{
|
|
||||||
+ m_supportedActions = Qt::DropActions();
|
|
||||||
+ if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
|
|
||||||
+ m_supportedActions |= Qt::MoveAction;
|
|
||||||
+ if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
|
|
||||||
+ m_supportedActions |= Qt::CopyAction;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
QWaylandMimeData::QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer)
|
|
||||||
: m_dataOffer(dataOffer)
|
|
||||||
{
|
|
||||||
diff --git a/src/client/qwaylanddataoffer_p.h b/src/client/qwaylanddataoffer_p.h
|
|
||||||
index 9cf1483c..6f667398 100644
|
|
||||||
--- a/src/client/qwaylanddataoffer_p.h
|
|
||||||
+++ b/src/client/qwaylanddataoffer_p.h
|
|
||||||
@@ -82,6 +82,7 @@ public:
|
|
||||||
explicit QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer);
|
|
||||||
~QWaylandDataOffer() override;
|
|
||||||
QMimeData *mimeData() override;
|
|
||||||
+ Qt::DropActions supportedActions() const;
|
|
||||||
|
|
||||||
QString firstFormat() const;
|
|
||||||
|
|
||||||
@@ -89,10 +90,13 @@ public:
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void data_offer_offer(const QString &mime_type) override;
|
|
||||||
+ void data_offer_source_actions(uint32_t source_actions) override;
|
|
||||||
+ void data_offer_action(uint32_t dnd_action) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QWaylandDisplay *m_display = nullptr;
|
|
||||||
QScopedPointer<QWaylandMimeData> m_mimeData;
|
|
||||||
+ Qt::DropActions m_supportedActions;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylanddatasource.cpp b/src/client/qwaylanddatasource.cpp
|
|
||||||
index 9b17cdfa..9610366d 100644
|
|
||||||
--- a/src/client/qwaylanddatasource.cpp
|
|
||||||
+++ b/src/client/qwaylanddatasource.cpp
|
|
||||||
@@ -101,7 +101,32 @@ void QWaylandDataSource::data_source_send(const QString &mime_type, int32_t fd)
|
|
||||||
|
|
||||||
void QWaylandDataSource::data_source_target(const QString &mime_type)
|
|
||||||
{
|
|
||||||
- Q_EMIT targetChanged(mime_type);
|
|
||||||
+ m_accepted = !mime_type.isEmpty();
|
|
||||||
+ Q_EMIT dndResponseUpdated(m_accepted, m_dropAction);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void QWaylandDataSource::data_source_action(uint32_t action)
|
|
||||||
+{
|
|
||||||
+ Qt::DropAction qtAction = Qt::IgnoreAction;
|
|
||||||
+
|
|
||||||
+ if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
|
|
||||||
+ qtAction = Qt::MoveAction;
|
|
||||||
+ else if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
|
|
||||||
+ qtAction = Qt::CopyAction;
|
|
||||||
+
|
|
||||||
+ m_dropAction = qtAction;
|
|
||||||
+ Q_EMIT dndResponseUpdated(m_accepted, m_dropAction);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void QWaylandDataSource::data_source_dnd_finished()
|
|
||||||
+{
|
|
||||||
+ Q_EMIT finished();
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void QWaylandDataSource::data_source_dnd_drop_performed()
|
|
||||||
+{
|
|
||||||
+
|
|
||||||
+ Q_EMIT dndDropped(m_accepted, m_dropAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
diff --git a/src/client/qwaylanddatasource_p.h b/src/client/qwaylanddatasource_p.h
|
|
||||||
index 3003da1b..b6a9e06b 100644
|
|
||||||
--- a/src/client/qwaylanddatasource_p.h
|
|
||||||
+++ b/src/client/qwaylanddatasource_p.h
|
|
||||||
@@ -77,16 +77,24 @@ public:
|
|
||||||
QMimeData *mimeData() const;
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
- void targetChanged(const QString &mime_type);
|
|
||||||
void cancelled();
|
|
||||||
+ void finished();
|
|
||||||
+
|
|
||||||
+ void dndResponseUpdated(bool accepted, Qt::DropAction action);
|
|
||||||
+ void dndDropped(bool accepted, Qt::DropAction action);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void data_source_cancelled() override;
|
|
||||||
void data_source_send(const QString &mime_type, int32_t fd) override;
|
|
||||||
void data_source_target(const QString &mime_type) override;
|
|
||||||
+ void data_source_dnd_drop_performed() override;
|
|
||||||
+ void data_source_dnd_finished() override;
|
|
||||||
+ void data_source_action(uint32_t action) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QMimeData *m_mime_data = nullptr;
|
|
||||||
+ bool m_accepted = false;
|
|
||||||
+ Qt::DropAction m_dropAction = Qt::IgnoreAction;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
|
|
||||||
index 7560bf41..7f28d01c 100644
|
|
||||||
--- a/src/client/qwaylanddisplay.cpp
|
|
||||||
+++ b/src/client/qwaylanddisplay.cpp
|
|
||||||
@@ -356,7 +356,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
|
|
||||||
mInputDevices.append(inputDevice);
|
|
||||||
#if QT_CONFIG(wayland_datadevice)
|
|
||||||
} else if (interface == QStringLiteral("wl_data_device_manager")) {
|
|
||||||
- mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id));
|
|
||||||
+ mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, version, id));
|
|
||||||
#endif
|
|
||||||
} else if (interface == QStringLiteral("qt_surface_extension")) {
|
|
||||||
mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1));
|
|
||||||
diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp
|
|
||||||
index 6535aa16..97ee5b2e 100644
|
|
||||||
--- a/src/client/qwaylanddnd.cpp
|
|
||||||
+++ b/src/client/qwaylanddnd.cpp
|
|
||||||
@@ -66,7 +66,7 @@ void QWaylandDrag::startDrag()
|
|
||||||
{
|
|
||||||
QBasicDrag::startDrag();
|
|
||||||
QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle());
|
|
||||||
- if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) {
|
|
||||||
+ if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), drag()->supportedActions(), icon)) {
|
|
||||||
icon->addAttachOffset(-drag()->hotSpot());
|
|
||||||
} else {
|
|
||||||
// Cancelling immediately does not work, since the event loop for QDrag::exec is started
|
|
||||||
@@ -103,31 +103,31 @@ void QWaylandDrag::endDrag()
|
|
||||||
m_display->currentInputDevice()->handleEndDrag();
|
|
||||||
}
|
|
||||||
|
|
||||||
-void QWaylandDrag::updateTarget(const QString &mimeType)
|
|
||||||
+void QWaylandDrag::setResponse(bool accepted)
|
|
||||||
{
|
|
||||||
- setCanDrop(!mimeType.isEmpty());
|
|
||||||
-
|
|
||||||
- if (canDrop()) {
|
|
||||||
- updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()));
|
|
||||||
- } else {
|
|
||||||
- updateCursor(Qt::IgnoreAction);
|
|
||||||
- }
|
|
||||||
+ // This method is used for old DataDevices where the drag action is not communicated
|
|
||||||
+ Qt::DropAction action = defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers());
|
|
||||||
+ setResponse(QPlatformDropQtResponse(accepted, action));
|
|
||||||
}
|
|
||||||
|
|
||||||
-void QWaylandDrag::setResponse(const QPlatformDragQtResponse &response)
|
|
||||||
+void QWaylandDrag::setResponse(const QPlatformDropQtResponse &response)
|
|
||||||
{
|
|
||||||
setCanDrop(response.isAccepted());
|
|
||||||
|
|
||||||
if (canDrop()) {
|
|
||||||
- updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()));
|
|
||||||
+ updateCursor(response.acceptedAction());
|
|
||||||
} else {
|
|
||||||
updateCursor(Qt::IgnoreAction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-void QWaylandDrag::finishDrag(const QPlatformDropQtResponse &response)
|
|
||||||
+void QWaylandDrag::setDropResponse(const QPlatformDropQtResponse &response)
|
|
||||||
{
|
|
||||||
setExecutedDropAction(response.acceptedAction());
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void QWaylandDrag::finishDrag()
|
|
||||||
+{
|
|
||||||
QKeyEvent event(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier);
|
|
||||||
eventFilter(shapedPixmapWindow(), &event);
|
|
||||||
}
|
|
||||||
diff --git a/src/client/qwaylanddnd_p.h b/src/client/qwaylanddnd_p.h
|
|
||||||
index 474fe2ab..747f0190 100644
|
|
||||||
--- a/src/client/qwaylanddnd_p.h
|
|
||||||
+++ b/src/client/qwaylanddnd_p.h
|
|
||||||
@@ -71,9 +71,10 @@ public:
|
|
||||||
QWaylandDrag(QWaylandDisplay *display);
|
|
||||||
~QWaylandDrag() override;
|
|
||||||
|
|
||||||
- void updateTarget(const QString &mimeType);
|
|
||||||
- void setResponse(const QPlatformDragQtResponse &response);
|
|
||||||
- void finishDrag(const QPlatformDropQtResponse &response);
|
|
||||||
+ void setResponse(bool accepted);
|
|
||||||
+ void setResponse(const QPlatformDropQtResponse &response);
|
|
||||||
+ void setDropResponse(const QPlatformDropQtResponse &response);
|
|
||||||
+ void finishDrag();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void startDrag() override;
|
|
||||||
diff --git a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
|
|
||||||
index 1568b3b9..067410d0 100644
|
|
||||||
--- a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
|
|
||||||
+++ b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
|
|
||||||
@@ -35,7 +35,7 @@
|
|
||||||
|
|
||||||
using namespace MockCompositor;
|
|
||||||
|
|
||||||
-constexpr int dataDeviceVersion = 1;
|
|
||||||
+constexpr int dataDeviceVersion = 3;
|
|
||||||
|
|
||||||
class DataDeviceCompositor : public DefaultCompositor {
|
|
||||||
public:
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
|||||||
From bfc5a684b3f8aa38f28267513872376e04bda8b6 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arjen Hiemstra <ahiemstra@heimr.nl>
|
|
||||||
Date: Thu, 18 Nov 2021 13:05:30 +0100
|
|
||||||
Subject: [PATCH 15/59] Client: Delay deletion of QDrag object until after
|
|
||||||
we're done with it
|
|
||||||
|
|
||||||
In certain cases, most notably when performing drag and drop operations
|
|
||||||
with touch, the QDrag object gets deleted before data_source_send is
|
|
||||||
executed. This then tries to access a deleted data_source, crashing the
|
|
||||||
client.
|
|
||||||
|
|
||||||
To avoid this, we indicate we want the QDrag object to stay around and
|
|
||||||
then delete it in QWaylandDrag::finishDrag, which with data_device v3 is
|
|
||||||
guaranteed to be called after everyone is done with the data source.
|
|
||||||
|
|
||||||
Change-Id: I6a2f5a219f58d1b721a9fec33c57d26d2c522ec9
|
|
||||||
Reviewed-by: David Edmundson <davidedmundson@kde.org>
|
|
||||||
(cherry picked from commit 39e3290efa2dd40722fa3322284cae3b01ccedf4)
|
|
||||||
---
|
|
||||||
src/client/qwaylanddnd.cpp | 11 +++++++++++
|
|
||||||
src/client/qwaylanddnd_p.h | 1 +
|
|
||||||
2 files changed, 12 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp
|
|
||||||
index 97ee5b2e..7c53f5fa 100644
|
|
||||||
--- a/src/client/qwaylanddnd.cpp
|
|
||||||
+++ b/src/client/qwaylanddnd.cpp
|
|
||||||
@@ -80,6 +80,9 @@ void QWaylandDrag::cancel()
|
|
||||||
QBasicDrag::cancel();
|
|
||||||
|
|
||||||
m_display->currentInputDevice()->dataDevice()->cancelDrag();
|
|
||||||
+
|
|
||||||
+ if (drag())
|
|
||||||
+ drag()->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWaylandDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
|
|
||||||
@@ -130,6 +133,14 @@ void QWaylandDrag::finishDrag()
|
|
||||||
{
|
|
||||||
QKeyEvent event(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier);
|
|
||||||
eventFilter(shapedPixmapWindow(), &event);
|
|
||||||
+
|
|
||||||
+ if (drag())
|
|
||||||
+ drag()->deleteLater();
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+bool QWaylandDrag::ownsDragObject() const
|
|
||||||
+{
|
|
||||||
+ return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
diff --git a/src/client/qwaylanddnd_p.h b/src/client/qwaylanddnd_p.h
|
|
||||||
index 747f0190..46f629ac 100644
|
|
||||||
--- a/src/client/qwaylanddnd_p.h
|
|
||||||
+++ b/src/client/qwaylanddnd_p.h
|
|
||||||
@@ -83,6 +83,7 @@ protected:
|
|
||||||
void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
|
|
||||||
void endDrag() override;
|
|
||||||
|
|
||||||
+ bool ownsDragObject() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QWaylandDisplay *m_display = nullptr;
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
|||||||
From 4d4eb8e543f688c9d5c9e1083f5e46ddf42b9786 Mon Sep 17 00:00:00 2001
|
|
||||||
From: David Edmundson <davidedmundson@kde.org>
|
|
||||||
Date: Sun, 14 Nov 2021 13:54:19 +0000
|
|
||||||
Subject: [PATCH 16/59] Client: Avoid processing of events when showing windows
|
|
||||||
|
|
||||||
The only time we want to dispatch events from the wayland socket is when
|
|
||||||
the application is waiting for external events. Doing so at any other
|
|
||||||
time will cause unpredictable behavior in client code.
|
|
||||||
|
|
||||||
This caused a crash downstream where we had outputs get altered whilst
|
|
||||||
itterating through outputs, which shouldn't happen.
|
|
||||||
|
|
||||||
There is no benefit to flushing here, it won't make anything appear
|
|
||||||
faster as we haven't attached the buffer yet.
|
|
||||||
|
|
||||||
Change-Id: Ie13eae4012dab96a93d8810f468d1343402b8c28
|
|
||||||
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
|
||||||
Reviewed-by: Aleix Pol Gonzalez <aleixpol@kde.org>
|
|
||||||
(cherry picked from commit 46ed85a80b28d519cf5887bbdce55d1bf57886c3)
|
|
||||||
---
|
|
||||||
src/client/qwaylandwindow.cpp | 1 -
|
|
||||||
1 file changed, 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
|
|
||||||
index fdffe584..83a394c4 100644
|
|
||||||
--- a/src/client/qwaylandwindow.cpp
|
|
||||||
+++ b/src/client/qwaylandwindow.cpp
|
|
||||||
@@ -437,7 +437,6 @@ void QWaylandWindow::setVisible(bool visible)
|
|
||||||
if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip)
|
|
||||||
activePopups << this;
|
|
||||||
initWindow();
|
|
||||||
- mDisplay->flushRequests();
|
|
||||||
|
|
||||||
setGeometry(windowGeometry());
|
|
||||||
// Don't flush the events here, or else the newly visible window may start drawing, but since
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
|||||||
From 359bc440082f7876a51c12a0db4e9399006726f2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Elvis Lee <kwangwoong.lee@lge.com>
|
|
||||||
Date: Thu, 18 Feb 2021 15:45:49 +0900
|
|
||||||
Subject: [PATCH 17/59] Handle registry_global out of constructor
|
|
||||||
|
|
||||||
Factory functions in QWaylandDisplay::registry_global() can be overridden.
|
|
||||||
Later, other classes instantiated in the registry_global can support
|
|
||||||
platform specific implementation with inheritance and some factory function.
|
|
||||||
|
|
||||||
Change-Id: I92ce574e049b8c91587687cc7c30611f3dfdbe56
|
|
||||||
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
|
||||||
(cherry picked from commit 3793a82038682db77966ea5daf8e75964e4250fe)
|
|
||||||
---
|
|
||||||
src/client/qwaylanddisplay.cpp | 19 ++++++++++++-------
|
|
||||||
src/client/qwaylanddisplay_p.h | 2 ++
|
|
||||||
src/client/qwaylandintegration.cpp | 3 +++
|
|
||||||
3 files changed, 17 insertions(+), 7 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
|
|
||||||
index 7f28d01c..c2482030 100644
|
|
||||||
--- a/src/client/qwaylanddisplay.cpp
|
|
||||||
+++ b/src/client/qwaylanddisplay.cpp
|
|
||||||
@@ -160,13 +160,6 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
|
|
||||||
if (!mXkbContext)
|
|
||||||
qCWarning(lcQpaWayland, "failed to create xkb context");
|
|
||||||
#endif
|
|
||||||
-
|
|
||||||
- forceRoundTrip();
|
|
||||||
-
|
|
||||||
- if (!mWaitingScreens.isEmpty()) {
|
|
||||||
- // Give wl_output.done and zxdg_output_v1.done events a chance to arrive
|
|
||||||
- forceRoundTrip();
|
|
||||||
- }
|
|
||||||
}
|
|
||||||
|
|
||||||
QWaylandDisplay::~QWaylandDisplay(void)
|
|
||||||
@@ -191,6 +184,18 @@ QWaylandDisplay::~QWaylandDisplay(void)
|
|
||||||
wl_display_disconnect(mDisplay);
|
|
||||||
}
|
|
||||||
|
|
||||||
+// Steps which is called just after constructor. This separates registry_global() out of the constructor
|
|
||||||
+// so that factory functions in integration can be overridden.
|
|
||||||
+void QWaylandDisplay::initialize()
|
|
||||||
+{
|
|
||||||
+ forceRoundTrip();
|
|
||||||
+
|
|
||||||
+ if (!mWaitingScreens.isEmpty()) {
|
|
||||||
+ // Give wl_output.done and zxdg_output_v1.done events a chance to arrive
|
|
||||||
+ forceRoundTrip();
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void QWaylandDisplay::ensureScreen()
|
|
||||||
{
|
|
||||||
if (!mScreens.empty() || mPlaceholderScreen)
|
|
||||||
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
|
|
||||||
index 15104d65..49820255 100644
|
|
||||||
--- a/src/client/qwaylanddisplay_p.h
|
|
||||||
+++ b/src/client/qwaylanddisplay_p.h
|
|
||||||
@@ -131,6 +131,8 @@ public:
|
|
||||||
QWaylandDisplay(QWaylandIntegration *waylandIntegration);
|
|
||||||
~QWaylandDisplay(void) override;
|
|
||||||
|
|
||||||
+ void initialize();
|
|
||||||
+
|
|
||||||
#if QT_CONFIG(xkbcommon)
|
|
||||||
struct xkb_context *xkbContext() const { return mXkbContext.get(); }
|
|
||||||
#endif
|
|
||||||
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
|
|
||||||
index cd8569b1..8afecb31 100644
|
|
||||||
--- a/src/client/qwaylandintegration.cpp
|
|
||||||
+++ b/src/client/qwaylandintegration.cpp
|
|
||||||
@@ -200,6 +200,9 @@ void QWaylandIntegration::initialize()
|
|
||||||
QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, mDisplay.data());
|
|
||||||
QObject::connect(sn, SIGNAL(activated(QSocketDescriptor)), mDisplay.data(), SLOT(flushRequests()));
|
|
||||||
|
|
||||||
+ // Call after eventDispatcher is fully connected, for QWaylandDisplay::forceRoundTrip()
|
|
||||||
+ mDisplay->initialize();
|
|
||||||
+
|
|
||||||
// Qt does not support running with no screens
|
|
||||||
mDisplay->ensureScreen();
|
|
||||||
}
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
From 3430f8812afa51b5b6fb139361b45fbfe6cff5d0 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Elvis Lee <kwangwoong.lee@lge.com>
|
|
||||||
Date: Wed, 17 Mar 2021 16:31:10 +0900
|
|
||||||
Subject: [PATCH 18/59] Connect flushRequest after forceRoundTrip
|
|
||||||
|
|
||||||
If flushRequest is connected with aboutToBlock, the flushRequest
|
|
||||||
may consumes all events so that processEvents might be blocked in forceRoundTrip.
|
|
||||||
|
|
||||||
Change-Id: I12b2c506e8442bf0e75f6ab6e418d3e1eea6d68c
|
|
||||||
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
|
||||||
(cherry picked from commit 654a54755138c520c3a41210d8078196e9a2c1bf)
|
|
||||||
---
|
|
||||||
src/client/qwaylandintegration.cpp | 11 +++++++----
|
|
||||||
1 file changed, 7 insertions(+), 4 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
|
|
||||||
index 8afecb31..661cea53 100644
|
|
||||||
--- a/src/client/qwaylandintegration.cpp
|
|
||||||
+++ b/src/client/qwaylandintegration.cpp
|
|
||||||
@@ -192,10 +192,6 @@ QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const
|
|
||||||
|
|
||||||
void QWaylandIntegration::initialize()
|
|
||||||
{
|
|
||||||
- QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
|
|
||||||
- QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay.data(), SLOT(flushRequests()));
|
|
||||||
- QObject::connect(dispatcher, SIGNAL(awake()), mDisplay.data(), SLOT(flushRequests()));
|
|
||||||
-
|
|
||||||
int fd = wl_display_get_fd(mDisplay->wl_display());
|
|
||||||
QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, mDisplay.data());
|
|
||||||
QObject::connect(sn, SIGNAL(activated(QSocketDescriptor)), mDisplay.data(), SLOT(flushRequests()));
|
|
||||||
@@ -203,6 +199,13 @@ void QWaylandIntegration::initialize()
|
|
||||||
// Call after eventDispatcher is fully connected, for QWaylandDisplay::forceRoundTrip()
|
|
||||||
mDisplay->initialize();
|
|
||||||
|
|
||||||
+ // But the aboutToBlock() and awake() should be connected after initializePlatform().
|
|
||||||
+ // Otherwise the connected flushRequests() may consumes up all events before processEvents starts to wait,
|
|
||||||
+ // so that processEvents(QEventLoop::WaitForMoreEvents) may be blocked in the forceRoundTrip().
|
|
||||||
+ QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
|
|
||||||
+ QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay.data(), SLOT(flushRequests()));
|
|
||||||
+ QObject::connect(dispatcher, SIGNAL(awake()), mDisplay.data(), SLOT(flushRequests()));
|
|
||||||
+
|
|
||||||
// Qt does not support running with no screens
|
|
||||||
mDisplay->ensureScreen();
|
|
||||||
}
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
@ -1,576 +0,0 @@
|
|||||||
From 1fe2895d2e3ccae0ae0abb2760e1714ac296c3ea Mon Sep 17 00:00:00 2001
|
|
||||||
From: Adrien Faveraux <af@brain-networks.fr>
|
|
||||||
Date: Fri, 26 Nov 2021 09:18:58 +0100
|
|
||||||
Subject: [PATCH 19/59] Move the wayland socket polling to a separate event
|
|
||||||
thread
|
|
||||||
|
|
||||||
New event threads is introduced which calls poll() on the wayland fd,
|
|
||||||
instead of relying on the event dispatcher by using the QSocketNotifier.
|
|
||||||
This allows to call in the proper order the wl_display_prepare_read(),
|
|
||||||
poll() and wl_display_read_events() functions.
|
|
||||||
|
|
||||||
One thread is responsible for the default queue; when needed, it emit
|
|
||||||
a signal so that the main thread can dispatch the queue. Another thread
|
|
||||||
is responsible for the dedicated queue for frame callbacks; this thread
|
|
||||||
will dispatch events on the thread itself.
|
|
||||||
|
|
||||||
QWaylandWindow is updated to, instead of each window's dedicated event
|
|
||||||
queue, use this queue for frame callbacks.
|
|
||||||
|
|
||||||
Co-authored-by: Ratchanan Srirattanamet <ratchanan@ubports.com>
|
|
||||||
Task-number: QTBUG-66075
|
|
||||||
Change-Id: Ibb33ad7f4193b866d1b8d7a0405a94d59dcad5eb
|
|
||||||
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
|
||||||
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
|
||||||
(cherry picked from commit 92a7904d9651348b0c307e84251c8440c6f75b22)
|
|
||||||
---
|
|
||||||
src/client/qwaylanddisplay.cpp | 302 +++++++++++++++++++++--------
|
|
||||||
src/client/qwaylanddisplay_p.h | 21 +-
|
|
||||||
src/client/qwaylandintegration.cpp | 4 +-
|
|
||||||
src/client/qwaylandwindow.cpp | 34 +++-
|
|
||||||
src/client/qwaylandwindow_p.h | 2 +-
|
|
||||||
5 files changed, 255 insertions(+), 108 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
|
|
||||||
index c2482030..c38f6f82 100644
|
|
||||||
--- a/src/client/qwaylanddisplay.cpp
|
|
||||||
+++ b/src/client/qwaylanddisplay.cpp
|
|
||||||
@@ -87,10 +87,203 @@
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
+#include <tuple> // for std::tie
|
|
||||||
+
|
|
||||||
+static void checkWaylandError(struct wl_display *display)
|
|
||||||
+{
|
|
||||||
+ int ecode = wl_display_get_error(display);
|
|
||||||
+ if ((ecode == EPIPE || ecode == ECONNRESET)) {
|
|
||||||
+ // special case this to provide a nicer error
|
|
||||||
+ qWarning("The Wayland connection broke. Did the Wayland compositor die?");
|
|
||||||
+ } else {
|
|
||||||
+ qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
|
|
||||||
+ }
|
|
||||||
+ _exit(1);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
namespace QtWaylandClient {
|
|
||||||
|
|
||||||
+class EventThread : public QThread
|
|
||||||
+{
|
|
||||||
+ Q_OBJECT
|
|
||||||
+public:
|
|
||||||
+ enum OperatingMode {
|
|
||||||
+ EmitToDispatch, // Emit the signal, allow dispatching in a differnt thread.
|
|
||||||
+ SelfDispatch, // Dispatch the events inside this thread.
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ EventThread(struct wl_display * wl, struct wl_event_queue * ev_queue,
|
|
||||||
+ OperatingMode mode)
|
|
||||||
+ : m_fd(wl_display_get_fd(wl))
|
|
||||||
+ , m_pipefd{ -1, -1 }
|
|
||||||
+ , m_wldisplay(wl)
|
|
||||||
+ , m_wlevqueue(ev_queue)
|
|
||||||
+ , m_mode(mode)
|
|
||||||
+ , m_reading(true)
|
|
||||||
+ , m_quitting(false)
|
|
||||||
+ {
|
|
||||||
+ setObjectName(QStringLiteral("WaylandEventThread"));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ void readAndDispatchEvents()
|
|
||||||
+ {
|
|
||||||
+ /*
|
|
||||||
+ * Dispatch pending events and flush the requests at least once. If the event thread
|
|
||||||
+ * is not reading, try to call _prepare_read() to allow the event thread to poll().
|
|
||||||
+ * If that fails, re-try dispatch & flush again until _prepare_read() is successful.
|
|
||||||
+ *
|
|
||||||
+ * This allow any call to readAndDispatchEvents() to start event thread's polling,
|
|
||||||
+ * not only the one issued from event thread's waitForReading(), which means functions
|
|
||||||
+ * called from dispatch_pending() can safely spin an event loop.
|
|
||||||
+ */
|
|
||||||
+ for (;;) {
|
|
||||||
+ if (dispatchQueuePending() < 0) {
|
|
||||||
+ checkWaylandError(m_wldisplay);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wl_display_flush(m_wldisplay);
|
|
||||||
+
|
|
||||||
+ // We have to check if event thread is reading every time we dispatch
|
|
||||||
+ // something, as that may recursively call this function.
|
|
||||||
+ if (m_reading.loadAcquire())
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ if (prepareReadQueue() == 0) {
|
|
||||||
+ QMutexLocker l(&m_mutex);
|
|
||||||
+ m_reading.storeRelease(true);
|
|
||||||
+ m_cond.wakeOne();
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ void stop()
|
|
||||||
+ {
|
|
||||||
+ // We have to both write to the pipe and set the flag, as the thread may be
|
|
||||||
+ // either in the poll() or waiting for _prepare_read().
|
|
||||||
+ if (m_pipefd[1] != -1 && write(m_pipefd[1], "\0", 1) == -1)
|
|
||||||
+ qWarning("Failed to write to the pipe: %s.", strerror(errno));
|
|
||||||
+
|
|
||||||
+ {
|
|
||||||
+ QMutexLocker l(&m_mutex);
|
|
||||||
+ m_quitting = true;
|
|
||||||
+ m_cond.wakeOne();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wait();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+Q_SIGNALS:
|
|
||||||
+ void needReadAndDispatch();
|
|
||||||
+
|
|
||||||
+protected:
|
|
||||||
+ void run() override
|
|
||||||
+ {
|
|
||||||
+ // we use this pipe to make the loop exit otherwise if we simply used a flag on the loop condition, if stop() gets
|
|
||||||
+ // called while poll() is blocking the thread will never quit since there are no wayland messages coming anymore.
|
|
||||||
+ struct Pipe
|
|
||||||
+ {
|
|
||||||
+ Pipe(int *fds)
|
|
||||||
+ : fds(fds)
|
|
||||||
+ {
|
|
||||||
+ if (qt_safe_pipe(fds) != 0)
|
|
||||||
+ qWarning("Pipe creation failed. Quitting may hang.");
|
|
||||||
+ }
|
|
||||||
+ ~Pipe()
|
|
||||||
+ {
|
|
||||||
+ if (fds[0] != -1) {
|
|
||||||
+ close(fds[0]);
|
|
||||||
+ close(fds[1]);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ int *fds;
|
|
||||||
+ } pipe(m_pipefd);
|
|
||||||
+
|
|
||||||
+ // Make the main thread call wl_prepare_read(), dispatch the pending messages and flush the
|
|
||||||
+ // outbound ones. Wait until it's done before proceeding, unless we're told to quit.
|
|
||||||
+ while (waitForReading()) {
|
|
||||||
+ pollfd fds[2] = { { m_fd, POLLIN, 0 }, { m_pipefd[0], POLLIN, 0 } };
|
|
||||||
+ poll(fds, 2, -1);
|
|
||||||
+
|
|
||||||
+ if (fds[1].revents & POLLIN) {
|
|
||||||
+ // we don't really care to read the byte that was written here since we're closing down
|
|
||||||
+ wl_display_cancel_read(m_wldisplay);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (fds[0].revents & POLLIN)
|
|
||||||
+ wl_display_read_events(m_wldisplay);
|
|
||||||
+ // The polll was succesfull and the event thread did the wl_display_read_events(). On the next iteration of the loop
|
|
||||||
+ // the event sent to the main thread will cause it to dispatch the messages just read, unless the loop exits in which
|
|
||||||
+ // case we don't care anymore about them.
|
|
||||||
+ else
|
|
||||||
+ wl_display_cancel_read(m_wldisplay);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+private:
|
|
||||||
+ bool waitForReading()
|
|
||||||
+ {
|
|
||||||
+ Q_ASSERT(QThread::currentThread() == this);
|
|
||||||
+
|
|
||||||
+ m_reading.storeRelease(false);
|
|
||||||
+
|
|
||||||
+ if (m_mode == SelfDispatch) {
|
|
||||||
+ readAndDispatchEvents();
|
|
||||||
+ } else {
|
|
||||||
+ Q_EMIT needReadAndDispatch();
|
|
||||||
+
|
|
||||||
+ QMutexLocker lock(&m_mutex);
|
|
||||||
+ // m_reading might be set from our emit or some other invocation of
|
|
||||||
+ // readAndDispatchEvents().
|
|
||||||
+ while (!m_reading.loadRelaxed() && !m_quitting)
|
|
||||||
+ m_cond.wait(&m_mutex);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return !m_quitting;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ int dispatchQueuePending()
|
|
||||||
+ {
|
|
||||||
+ if (m_wlevqueue)
|
|
||||||
+ return wl_display_dispatch_queue_pending(m_wldisplay, m_wlevqueue);
|
|
||||||
+ else
|
|
||||||
+ return wl_display_dispatch_pending(m_wldisplay);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ int prepareReadQueue()
|
|
||||||
+ {
|
|
||||||
+ if (m_wlevqueue)
|
|
||||||
+ return wl_display_prepare_read_queue(m_wldisplay, m_wlevqueue);
|
|
||||||
+ else
|
|
||||||
+ return wl_display_prepare_read(m_wldisplay);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ int m_fd;
|
|
||||||
+ int m_pipefd[2];
|
|
||||||
+ wl_display *m_wldisplay;
|
|
||||||
+ wl_event_queue *m_wlevqueue;
|
|
||||||
+ OperatingMode m_mode;
|
|
||||||
+
|
|
||||||
+ /* Concurrency note when operating in EmitToDispatch mode:
|
|
||||||
+ * m_reading is set to false inside event thread's waitForReading(), and is
|
|
||||||
+ * set to true inside main thread's readAndDispatchEvents().
|
|
||||||
+ * The lock is not taken when setting m_reading to false, as the main thread
|
|
||||||
+ * is not actively waiting for it to turn false. However, the lock is taken
|
|
||||||
+ * inside readAndDispatchEvents() before setting m_reading to true,
|
|
||||||
+ * as the event thread is actively waiting for it under the wait condition.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+ QAtomicInteger<bool> m_reading;
|
|
||||||
+ bool m_quitting;
|
|
||||||
+ QMutex m_mutex;
|
|
||||||
+ QWaitCondition m_cond;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland"); // for general (uncategorized) Wayland platform logging
|
|
||||||
|
|
||||||
struct wl_surface *QWaylandDisplay::createSurface(void *handle)
|
|
||||||
@@ -164,6 +357,12 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
|
|
||||||
|
|
||||||
QWaylandDisplay::~QWaylandDisplay(void)
|
|
||||||
{
|
|
||||||
+ if (m_eventThread)
|
|
||||||
+ m_eventThread->stop();
|
|
||||||
+
|
|
||||||
+ if (m_frameEventQueueThread)
|
|
||||||
+ m_frameEventQueueThread->stop();
|
|
||||||
+
|
|
||||||
if (mSyncCallback)
|
|
||||||
wl_callback_destroy(mSyncCallback);
|
|
||||||
|
|
||||||
@@ -210,98 +409,37 @@ void QWaylandDisplay::ensureScreen()
|
|
||||||
|
|
||||||
void QWaylandDisplay::checkError() const
|
|
||||||
{
|
|
||||||
- int ecode = wl_display_get_error(mDisplay);
|
|
||||||
- if ((ecode == EPIPE || ecode == ECONNRESET)) {
|
|
||||||
- // special case this to provide a nicer error
|
|
||||||
- qWarning("The Wayland connection broke. Did the Wayland compositor die?");
|
|
||||||
- } else {
|
|
||||||
- qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
|
|
||||||
- }
|
|
||||||
- _exit(1);
|
|
||||||
+ checkWaylandError(mDisplay);
|
|
||||||
}
|
|
||||||
|
|
||||||
+// Called in main thread, either from queued signal or directly.
|
|
||||||
void QWaylandDisplay::flushRequests()
|
|
||||||
{
|
|
||||||
- if (wl_display_prepare_read(mDisplay) == 0) {
|
|
||||||
- wl_display_read_events(mDisplay);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (wl_display_dispatch_pending(mDisplay) < 0)
|
|
||||||
- checkError();
|
|
||||||
-
|
|
||||||
- {
|
|
||||||
- QReadLocker locker(&m_frameQueueLock);
|
|
||||||
- for (const FrameQueue &q : mExternalQueues) {
|
|
||||||
- QMutexLocker locker(q.mutex);
|
|
||||||
- while (wl_display_prepare_read_queue(mDisplay, q.queue) != 0)
|
|
||||||
- wl_display_dispatch_queue_pending(mDisplay, q.queue);
|
|
||||||
- wl_display_read_events(mDisplay);
|
|
||||||
- wl_display_dispatch_queue_pending(mDisplay, q.queue);
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- wl_display_flush(mDisplay);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-void QWaylandDisplay::blockingReadEvents()
|
|
||||||
-{
|
|
||||||
- if (wl_display_dispatch(mDisplay) < 0)
|
|
||||||
- checkError();
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-void QWaylandDisplay::destroyFrameQueue(const QWaylandDisplay::FrameQueue &q)
|
|
||||||
-{
|
|
||||||
- QWriteLocker locker(&m_frameQueueLock);
|
|
||||||
- auto it = std::find_if(mExternalQueues.begin(),
|
|
||||||
- mExternalQueues.end(),
|
|
||||||
- [&q] (const QWaylandDisplay::FrameQueue &other){ return other.queue == q.queue; });
|
|
||||||
- Q_ASSERT(it != mExternalQueues.end());
|
|
||||||
- mExternalQueues.erase(it);
|
|
||||||
- if (q.queue != nullptr)
|
|
||||||
- wl_event_queue_destroy(q.queue);
|
|
||||||
- delete q.mutex;
|
|
||||||
+ m_eventThread->readAndDispatchEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
-QWaylandDisplay::FrameQueue QWaylandDisplay::createFrameQueue()
|
|
||||||
+// We have to wait until we have an eventDispatcher before creating the eventThread,
|
|
||||||
+// otherwise forceRoundTrip() may block inside _events_read() because eventThread is
|
|
||||||
+// polling.
|
|
||||||
+void QWaylandDisplay::initEventThread()
|
|
||||||
{
|
|
||||||
- QWriteLocker locker(&m_frameQueueLock);
|
|
||||||
- FrameQueue q{createEventQueue()};
|
|
||||||
- mExternalQueues.append(q);
|
|
||||||
- return q;
|
|
||||||
-}
|
|
||||||
+ m_eventThread.reset(
|
|
||||||
+ new EventThread(mDisplay, /* default queue */ nullptr, EventThread::EmitToDispatch));
|
|
||||||
+ connect(m_eventThread.get(), &EventThread::needReadAndDispatch, this,
|
|
||||||
+ &QWaylandDisplay::flushRequests, Qt::QueuedConnection);
|
|
||||||
+ m_eventThread->start();
|
|
||||||
|
|
||||||
-wl_event_queue *QWaylandDisplay::createEventQueue()
|
|
||||||
-{
|
|
||||||
- return wl_display_create_queue(mDisplay);
|
|
||||||
+ // wl_display_disconnect() free this.
|
|
||||||
+ m_frameEventQueue = wl_display_create_queue(mDisplay);
|
|
||||||
+ m_frameEventQueueThread.reset(
|
|
||||||
+ new EventThread(mDisplay, m_frameEventQueue, EventThread::SelfDispatch));
|
|
||||||
+ m_frameEventQueueThread->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
-void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function<bool ()> condition, int timeout)
|
|
||||||
+void QWaylandDisplay::blockingReadEvents()
|
|
||||||
{
|
|
||||||
- if (!condition())
|
|
||||||
- return;
|
|
||||||
-
|
|
||||||
- QElapsedTimer timer;
|
|
||||||
- timer.start();
|
|
||||||
- struct pollfd pFd = qt_make_pollfd(wl_display_get_fd(mDisplay), POLLIN);
|
|
||||||
- while (timeout == -1 || timer.elapsed() < timeout) {
|
|
||||||
- while (wl_display_prepare_read_queue(mDisplay, queue) != 0)
|
|
||||||
- wl_display_dispatch_queue_pending(mDisplay, queue);
|
|
||||||
-
|
|
||||||
- wl_display_flush(mDisplay);
|
|
||||||
-
|
|
||||||
- const int remaining = qMax(timeout - timer.elapsed(), 0ll);
|
|
||||||
- const int pollTimeout = timeout == -1 ? -1 : remaining;
|
|
||||||
- if (qt_poll_msecs(&pFd, 1, pollTimeout) > 0)
|
|
||||||
- wl_display_read_events(mDisplay);
|
|
||||||
- else
|
|
||||||
- wl_display_cancel_read(mDisplay);
|
|
||||||
-
|
|
||||||
- if (wl_display_dispatch_queue_pending(mDisplay, queue) < 0)
|
|
||||||
- checkError();
|
|
||||||
-
|
|
||||||
- if (!condition())
|
|
||||||
- break;
|
|
||||||
- }
|
|
||||||
+ if (wl_display_dispatch(mDisplay) < 0)
|
|
||||||
+ checkWaylandError(mDisplay);
|
|
||||||
}
|
|
||||||
|
|
||||||
QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
|
|
||||||
@@ -678,6 +816,8 @@ QWaylandCursorTheme *QWaylandDisplay::loadCursorTheme(const QString &name, int p
|
|
||||||
|
|
||||||
} // namespace QtWaylandClient
|
|
||||||
|
|
||||||
+#include "qwaylanddisplay.moc"
|
|
||||||
+
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
#include "moc_qwaylanddisplay_p.cpp"
|
|
||||||
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
|
|
||||||
index 49820255..cf91b924 100644
|
|
||||||
--- a/src/client/qwaylanddisplay_p.h
|
|
||||||
+++ b/src/client/qwaylanddisplay_p.h
|
|
||||||
@@ -111,6 +111,7 @@ class QWaylandSurface;
|
|
||||||
class QWaylandShellIntegration;
|
|
||||||
class QWaylandCursor;
|
|
||||||
class QWaylandCursorTheme;
|
|
||||||
+class EventThread;
|
|
||||||
|
|
||||||
typedef void (*RegistryListener)(void *data,
|
|
||||||
struct wl_registry *registry,
|
|
||||||
@@ -122,12 +123,6 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandDisplay : public QObject, public QtWayland
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
- struct FrameQueue {
|
|
||||||
- FrameQueue(wl_event_queue *q = nullptr) : queue(q), mutex(new QMutex) {}
|
|
||||||
- wl_event_queue *queue;
|
|
||||||
- QMutex *mutex;
|
|
||||||
- };
|
|
||||||
-
|
|
||||||
QWaylandDisplay(QWaylandIntegration *waylandIntegration);
|
|
||||||
~QWaylandDisplay(void) override;
|
|
||||||
|
|
||||||
@@ -216,12 +211,11 @@ public:
|
|
||||||
void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice);
|
|
||||||
void handleWindowDestroyed(QWaylandWindow *window);
|
|
||||||
|
|
||||||
- wl_event_queue *createEventQueue();
|
|
||||||
- FrameQueue createFrameQueue();
|
|
||||||
- void destroyFrameQueue(const FrameQueue &q);
|
|
||||||
- void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1);
|
|
||||||
+ wl_event_queue *frameEventQueue() { return m_frameEventQueue; };
|
|
||||||
|
|
||||||
bool isKeyboardAvailable() const;
|
|
||||||
+
|
|
||||||
+ void initEventThread();
|
|
||||||
public slots:
|
|
||||||
void blockingReadEvents();
|
|
||||||
void flushRequests();
|
|
||||||
@@ -244,6 +238,9 @@ private:
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wl_display *mDisplay = nullptr;
|
|
||||||
+ QScopedPointer<EventThread> m_eventThread;
|
|
||||||
+ wl_event_queue *m_frameEventQueue = nullptr;
|
|
||||||
+ QScopedPointer<EventThread> m_frameEventQueueThread;
|
|
||||||
QtWayland::wl_compositor mCompositor;
|
|
||||||
QScopedPointer<QWaylandShm> mShm;
|
|
||||||
QList<QWaylandScreen *> mWaitingScreens;
|
|
||||||
@@ -282,11 +279,9 @@ private:
|
|
||||||
QWaylandInputDevice *mLastInputDevice = nullptr;
|
|
||||||
QPointer<QWaylandWindow> mLastInputWindow;
|
|
||||||
QPointer<QWaylandWindow> mLastKeyboardFocus;
|
|
||||||
- QVector<QWaylandWindow *> mActiveWindows;
|
|
||||||
- QVector<FrameQueue> mExternalQueues;
|
|
||||||
+ QList<QWaylandWindow *> mActiveWindows;
|
|
||||||
struct wl_callback *mSyncCallback = nullptr;
|
|
||||||
static const wl_callback_listener syncCallbackListener;
|
|
||||||
- QReadWriteLock m_frameQueueLock;
|
|
||||||
|
|
||||||
bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull();
|
|
||||||
|
|
||||||
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
|
|
||||||
index 661cea53..fbf00c6b 100644
|
|
||||||
--- a/src/client/qwaylandintegration.cpp
|
|
||||||
+++ b/src/client/qwaylandintegration.cpp
|
|
||||||
@@ -192,9 +192,7 @@ QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const
|
|
||||||
|
|
||||||
void QWaylandIntegration::initialize()
|
|
||||||
{
|
|
||||||
- int fd = wl_display_get_fd(mDisplay->wl_display());
|
|
||||||
- QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, mDisplay.data());
|
|
||||||
- QObject::connect(sn, SIGNAL(activated(QSocketDescriptor)), mDisplay.data(), SLOT(flushRequests()));
|
|
||||||
+ mDisplay->initEventThread();
|
|
||||||
|
|
||||||
// Call after eventDispatcher is fully connected, for QWaylandDisplay::forceRoundTrip()
|
|
||||||
mDisplay->initialize();
|
|
||||||
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
|
|
||||||
index 83a394c4..3d9741d2 100644
|
|
||||||
--- a/src/client/qwaylandwindow.cpp
|
|
||||||
+++ b/src/client/qwaylandwindow.cpp
|
|
||||||
@@ -76,7 +76,6 @@ QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
|
|
||||||
QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
|
|
||||||
: QPlatformWindow(window)
|
|
||||||
, mDisplay(display)
|
|
||||||
- , mFrameQueue(mDisplay->createFrameQueue())
|
|
||||||
, mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
|
|
||||||
{
|
|
||||||
{
|
|
||||||
@@ -95,8 +94,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
|
|
||||||
|
|
||||||
QWaylandWindow::~QWaylandWindow()
|
|
||||||
{
|
|
||||||
- mDisplay->destroyFrameQueue(mFrameQueue);
|
|
||||||
-
|
|
||||||
delete mWindowDecoration;
|
|
||||||
|
|
||||||
if (mSurface)
|
|
||||||
@@ -648,6 +645,8 @@ const wl_callback_listener QWaylandWindow::callbackListener = {
|
|
||||||
|
|
||||||
void QWaylandWindow::handleFrameCallback()
|
|
||||||
{
|
|
||||||
+ QMutexLocker locker(&mFrameSyncMutex);
|
|
||||||
+
|
|
||||||
mWaitingForFrameCallback = false;
|
|
||||||
mFrameCallbackElapsedTimer.invalidate();
|
|
||||||
|
|
||||||
@@ -669,12 +668,16 @@ void QWaylandWindow::handleFrameCallback()
|
|
||||||
mWaitingForUpdateDelivery = true;
|
|
||||||
QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ mFrameSyncWait.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QWaylandWindow::waitForFrameSync(int timeout)
|
|
||||||
{
|
|
||||||
- QMutexLocker locker(mFrameQueue.mutex);
|
|
||||||
- mDisplay->dispatchQueueWhile(mFrameQueue.queue, [&]() { return mWaitingForFrameCallback; }, timeout);
|
|
||||||
+ QMutexLocker locker(&mFrameSyncMutex);
|
|
||||||
+
|
|
||||||
+ QDeadlineTimer deadline(timeout);
|
|
||||||
+ while (mWaitingForFrameCallback && mFrameSyncWait.wait(&mFrameSyncMutex, deadline)) { }
|
|
||||||
|
|
||||||
if (mWaitingForFrameCallback) {
|
|
||||||
qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
|
|
||||||
@@ -1183,8 +1186,11 @@ void QWaylandWindow::requestUpdate()
|
|
||||||
Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA
|
|
||||||
|
|
||||||
// If we have a frame callback all is good and will be taken care of there
|
|
||||||
- if (mWaitingForFrameCallback)
|
|
||||||
- return;
|
|
||||||
+ {
|
|
||||||
+ QMutexLocker locker(&mFrameSyncMutex);
|
|
||||||
+ if (mWaitingForFrameCallback)
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
// If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet
|
|
||||||
// This is a somewhat redundant behavior and might indicate a bug in the calling code, so log
|
|
||||||
@@ -1197,7 +1203,12 @@ void QWaylandWindow::requestUpdate()
|
|
||||||
// so use invokeMethod to delay the delivery a bit.
|
|
||||||
QMetaObject::invokeMethod(this, [this] {
|
|
||||||
// Things might have changed in the meantime
|
|
||||||
- if (hasPendingUpdateRequest() && !mWaitingForFrameCallback)
|
|
||||||
+ {
|
|
||||||
+ QMutexLocker locker(&mFrameSyncMutex);
|
|
||||||
+ if (mWaitingForFrameCallback)
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+ if (hasPendingUpdateRequest())
|
|
||||||
deliverUpdateRequest();
|
|
||||||
}, Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
@@ -1217,9 +1228,10 @@ void QWaylandWindow::handleUpdate()
|
|
||||||
if (!mSurface)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- QMutexLocker locker(mFrameQueue.mutex);
|
|
||||||
+ QMutexLocker locker(&mFrameSyncMutex);
|
|
||||||
+
|
|
||||||
struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object()));
|
|
||||||
- wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mFrameQueue.queue);
|
|
||||||
+ wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mDisplay->frameEventQueue());
|
|
||||||
mFrameCallback = wl_surface_frame(wrappedSurface);
|
|
||||||
wl_proxy_wrapper_destroy(wrappedSurface);
|
|
||||||
wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this);
|
|
||||||
@@ -1229,6 +1241,8 @@ void QWaylandWindow::handleUpdate()
|
|
||||||
// Start a timer for handling the case when the compositor stops sending frame callbacks.
|
|
||||||
if (mFrameCallbackTimeout > 0) {
|
|
||||||
QMetaObject::invokeMethod(this, [this] {
|
|
||||||
+ QMutexLocker locker(&mFrameSyncMutex);
|
|
||||||
+
|
|
||||||
if (mWaitingForFrameCallback) {
|
|
||||||
if (mFrameCallbackCheckIntervalTimerId < 0)
|
|
||||||
mFrameCallbackCheckIntervalTimerId = startTimer(mFrameCallbackTimeout);
|
|
||||||
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
|
|
||||||
index fb3ed606..54ac67a9 100644
|
|
||||||
--- a/src/client/qwaylandwindow_p.h
|
|
||||||
+++ b/src/client/qwaylandwindow_p.h
|
|
||||||
@@ -232,7 +232,7 @@ protected:
|
|
||||||
int mFrameCallbackCheckIntervalTimerId = -1;
|
|
||||||
QElapsedTimer mFrameCallbackElapsedTimer;
|
|
||||||
struct ::wl_callback *mFrameCallback = nullptr;
|
|
||||||
- QWaylandDisplay::FrameQueue mFrameQueue;
|
|
||||||
+ QMutex mFrameSyncMutex;
|
|
||||||
QWaitCondition mFrameSyncWait;
|
|
||||||
|
|
||||||
// True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer
|
|
||||||
--
|
|
||||||
2.41.0
|
|
||||||
|
|
1
dead.package
Normal file
1
dead.package
Normal file
@ -0,0 +1 @@
|
|||||||
|
qt5-qtwayland package is retired on branch c10s for BAKERY-412
|
Loading…
Reference in New Issue
Block a user