Sync with Fedora
Resolves: bz#2044169
This commit is contained in:
parent
b398e27a3e
commit
3aef25cacc
29
0037-Fix-backport-context-destruction-was-omitted.patch
Normal file
29
0037-Fix-backport-context-destruction-was-omitted.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From eb422ab5e07498a7a8d086f6a942ee35ab3c9776 Mon Sep 17 00:00:00 2001
|
||||
From: Aleix Pol <aleixpol@kde.org>
|
||||
Date: Thu, 9 Dec 2021 17:35:24 +0100
|
||||
Subject: [PATCH 37/41] Fix backport, context destruction was omitted
|
||||
|
||||
When cherry-picking for 9df11e79b46c77d8c83f765b2a8e85b639fd55a2, this
|
||||
line got removed when rebasing the patch, which created a leak.
|
||||
|
||||
BUG: 442844
|
||||
Change-Id: Id00e8b194dcd910c5f01ce9d2cc318f96a4129a2
|
||||
---
|
||||
src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
|
||||
index 95d1049c..683fe123 100644
|
||||
--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
|
||||
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
|
||||
@@ -407,6 +407,7 @@ QWaylandGLContext::~QWaylandGLContext()
|
||||
{
|
||||
delete m_blitter;
|
||||
m_blitter = nullptr;
|
||||
+ eglDestroyContext(m_eglDisplay, m_context);
|
||||
if (m_decorationsContext != EGL_NO_CONTEXT)
|
||||
eglDestroyContext(m_eglDisplay, m_decorationsContext);
|
||||
}
|
||||
--
|
||||
2.34.1
|
||||
|
29
0038-Set-preedit-cursor-when-cursor-equals-to-0.patch
Normal file
29
0038-Set-preedit-cursor-when-cursor-equals-to-0.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From e0646f531e1e73a90a93faaa45d933ae40769985 Mon Sep 17 00:00:00 2001
|
||||
From: Weng Xuetian <wengxt@gmail.com>
|
||||
Date: Sat, 18 Dec 2021 23:42:49 -0800
|
||||
Subject: [PATCH 38/41] Set preedit cursor when cursor equals to 0
|
||||
|
||||
Pick-to: 6.3 6.2 5.15
|
||||
Change-Id: I832fbb22d973b36ac4ab51570fc53bc2e4c3ed58
|
||||
Reviewed-by: Liang Qi <liang.qi@qt.io>
|
||||
(cherry picked from commit 719a55be13bdadfa659a732755f280e276a894bd)
|
||||
---
|
||||
src/shared/qwaylandinputmethodeventbuilder.cpp | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/shared/qwaylandinputmethodeventbuilder.cpp b/src/shared/qwaylandinputmethodeventbuilder.cpp
|
||||
index 526d0ef4..25be2509 100644
|
||||
--- a/src/shared/qwaylandinputmethodeventbuilder.cpp
|
||||
+++ b/src/shared/qwaylandinputmethodeventbuilder.cpp
|
||||
@@ -151,7 +151,7 @@ QInputMethodEvent QWaylandInputMethodEventBuilder::buildPreedit(const QString &t
|
||||
{
|
||||
QList<QInputMethodEvent::Attribute> attributes;
|
||||
|
||||
- if (m_preeditCursor < 0) {
|
||||
+ if (m_preeditCursor <= 0) {
|
||||
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant()));
|
||||
} else if (m_preeditCursor > 0) {
|
||||
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, indexFromWayland(text, m_preeditCursor), 1, QVariant()));
|
||||
--
|
||||
2.34.1
|
||||
|
513
0039-Client-Implement-DataDeviceV3.patch
Normal file
513
0039-Client-Implement-DataDeviceV3.patch
Normal file
@ -0,0 +1,513 @@
|
||||
From 2044603ebb5ae70c785d50968ac620b842c2b14e Mon Sep 17 00:00:00 2001
|
||||
From: David Edmundson <davidedmundson@kde.org>
|
||||
Date: Tue, 16 Feb 2021 09:51:47 +0000
|
||||
Subject: [PATCH 39/41] 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 bbd2d568..fbb5aa91 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 f45122fb..5599cbd4 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 25afff79..96f07bc3 100644
|
||||
--- a/src/client/qwaylanddatasource_p.h
|
||||
+++ b/src/client/qwaylanddatasource_p.h
|
||||
@@ -77,17 +77,25 @@ 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:
|
||||
QWaylandDisplay *m_display = nullptr;
|
||||
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 9f595af3..ea344c61 100644
|
||||
--- a/src/client/qwaylanddisplay.cpp
|
||||
+++ b/src/client/qwaylanddisplay.cpp
|
||||
@@ -354,7 +354,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.34.1
|
||||
|
@ -0,0 +1,67 @@
|
||||
From 0b15df7e9e26a4edfc2277eb3ec7b3d5c58a5dcd Mon Sep 17 00:00:00 2001
|
||||
From: Arjen Hiemstra <ahiemstra@heimr.nl>
|
||||
Date: Thu, 18 Nov 2021 13:05:30 +0100
|
||||
Subject: [PATCH 40/44] 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.34.1
|
||||
|
@ -0,0 +1,38 @@
|
||||
From 867540b9d913760a847ff67c8694d817c821f2c2 Mon Sep 17 00:00:00 2001
|
||||
From: David Edmundson <davidedmundson@kde.org>
|
||||
Date: Sun, 14 Nov 2021 13:54:19 +0000
|
||||
Subject: [PATCH 41/44] 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 ba881cb3..1597f67e 100644
|
||||
--- a/src/client/qwaylandwindow.cpp
|
||||
+++ b/src/client/qwaylandwindow.cpp
|
||||
@@ -436,7 +436,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.34.1
|
||||
|
85
0042-Handle-registry_global-out-of-constructor.patch
Normal file
85
0042-Handle-registry_global-out-of-constructor.patch
Normal file
@ -0,0 +1,85 @@
|
||||
From bc5a8d24f63181a36759723a4d1b39b59b3b53e6 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 42/44] 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 ea344c61..0f75cb7e 100644
|
||||
--- a/src/client/qwaylanddisplay.cpp
|
||||
+++ b/src/client/qwaylanddisplay.cpp
|
||||
@@ -158,13 +158,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)
|
||||
@@ -189,6 +182,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 09a1736a..d9c8849f 100644
|
||||
--- a/src/client/qwaylanddisplay_p.h
|
||||
+++ b/src/client/qwaylanddisplay_p.h
|
||||
@@ -129,6 +129,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 e5e7dd42..f5632982 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.34.1
|
||||
|
47
0043-Connect-flushRequest-after-forceRoundTrip.patch
Normal file
47
0043-Connect-flushRequest-after-forceRoundTrip.patch
Normal file
@ -0,0 +1,47 @@
|
||||
From 98dc33fdc66f15a0e69f3024fcef046f11adc58c 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 43/44] 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 f5632982..3a6fa651 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.34.1
|
||||
|
574
0044-Move-the-wayland-socket-polling-to-a-separate-event-.patch
Normal file
574
0044-Move-the-wayland-socket-polling-to-a-separate-event-.patch
Normal file
@ -0,0 +1,574 @@
|
||||
From 4644d51f4b52e83fc1b4d02b380d80d9d57e76fa 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 44/44] 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 0f75cb7e..a7ce280a 100644
|
||||
--- a/src/client/qwaylanddisplay.cpp
|
||||
+++ b/src/client/qwaylanddisplay.cpp
|
||||
@@ -85,10 +85,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)
|
||||
@@ -162,6 +355,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);
|
||||
|
||||
@@ -208,98 +407,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
|
||||
@@ -674,4 +812,6 @@ QWaylandCursorTheme *QWaylandDisplay::loadCursorTheme(const QString &name, int p
|
||||
|
||||
} // namespace QtWaylandClient
|
||||
|
||||
+#include "qwaylanddisplay.moc"
|
||||
+
|
||||
QT_END_NAMESPACE
|
||||
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
|
||||
index d9c8849f..42bc661d 100644
|
||||
--- a/src/client/qwaylanddisplay_p.h
|
||||
+++ b/src/client/qwaylanddisplay_p.h
|
||||
@@ -109,6 +109,7 @@ class QWaylandSurface;
|
||||
class QWaylandShellIntegration;
|
||||
class QWaylandCursor;
|
||||
class QWaylandCursorTheme;
|
||||
+class EventThread;
|
||||
|
||||
typedef void (*RegistryListener)(void *data,
|
||||
struct wl_registry *registry,
|
||||
@@ -120,12 +121,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;
|
||||
|
||||
@@ -212,12 +207,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();
|
||||
@@ -240,6 +234,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;
|
||||
@@ -276,11 +273,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 3a6fa651..3b876047 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 1597f67e..7de19a74 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)
|
||||
@@ -635,6 +632,8 @@ const wl_callback_listener QWaylandWindow::callbackListener = {
|
||||
|
||||
void QWaylandWindow::handleFrameCallback()
|
||||
{
|
||||
+ QMutexLocker locker(&mFrameSyncMutex);
|
||||
+
|
||||
mWaitingForFrameCallback = false;
|
||||
mFrameCallbackElapsedTimer.invalidate();
|
||||
|
||||
@@ -656,12 +655,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";
|
||||
@@ -1157,8 +1160,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
|
||||
@@ -1171,7 +1177,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);
|
||||
}
|
||||
@@ -1191,9 +1202,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);
|
||||
@@ -1203,6 +1215,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 e0687962..d45980a8 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.34.1
|
||||
|
@ -5,7 +5,7 @@
|
||||
Summary: Qt5 - Wayland platform support and QtCompositor module
|
||||
Name: qt5-%{qt_module}
|
||||
Version: 5.15.2
|
||||
Release: 13%{?dist}
|
||||
Release: 14%{?dist}
|
||||
|
||||
License: LGPLv3
|
||||
Url: http://www.qt.io
|
||||
@ -53,6 +53,14 @@ Patch33: 0033-Client-Always-destroy-frame-callback-in-the-actual-c.patch
|
||||
Patch34: 0034-Fix-the-logic-for-decoding-modifiers-map-in-Wayland-.patch
|
||||
Patch35: 0035-Wayland-client-use-wl_keyboard-to-determine-active-s.patch
|
||||
Patch36: 0036-Client-do-not-empty-clipboard-when-a-new-popup-windo.patch
|
||||
Patch37: 0037-Fix-backport-context-destruction-was-omitted.patch
|
||||
Patch38: 0038-Set-preedit-cursor-when-cursor-equals-to-0.patch
|
||||
Patch39: 0039-Client-Implement-DataDeviceV3.patch
|
||||
Patch40: 0040-Client-Delay-deletion-of-QDrag-object-until-after-we.patch
|
||||
Patch41: 0041-Client-Avoid-processing-of-events-when-showing-windo.patch
|
||||
Patch42: 0042-Handle-registry_global-out-of-constructor.patch
|
||||
Patch43: 0043-Connect-flushRequest-after-forceRoundTrip.patch
|
||||
Patch44: 0044-Move-the-wayland-socket-polling-to-a-separate-event-.patch
|
||||
|
||||
# Disable for now, there is a Qt bug making this broken
|
||||
# Patch52: qtwayland-decoration-support-backports-from-qt6.patch
|
||||
@ -182,6 +190,10 @@ popd
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Mon Jan 24 2022 Jan Grulich <jgrulich@redhat.com> - 5.15.2-14
|
||||
- Sync with Fedora
|
||||
Resolves: bz#2044169
|
||||
|
||||
* Wed Dec 08 2021 Jan Grulich <jgrulich@redhat.com> - 5.15.2-13
|
||||
- Sync with Fedora
|
||||
Resolves: bz#2028778
|
||||
|
Loading…
Reference in New Issue
Block a user