[neon/qt/qtwayland/Neon/release] debian: Add patches from KDE's Qt 5 Patch Collection up to 2022-05-14.

Dmitry Shachnev null at kde.org
Fri Jul 15 12:22:55 BST 2022


Git commit d5955f471ef19686137b4f5f835d45fedc0eaa08 by Dmitry Shachnev.
Committed on 14/05/2022 at 12:29.
Pushed by jriddell into branch 'Neon/release'.

Add patches from KDE's Qt 5 Patch Collection up to 2022-05-14.

M  +2    -0    debian/changelog
A  +139  -0    debian/patches/0001-Client-Announce-an-output-after-receiving-more-compl.patch
A  +51   -0    debian/patches/0002-Fix-issue-with-repeated-window-size-changes.patch
A  +26   -0    debian/patches/0003-Include-locale.h-for-setlocale-LC_CTYPE.patch
A  +34   -0    debian/patches/0004-Client-Connect-drags-being-accepted-to-updating-the-.patch
A  +42   -0    debian/patches/0005-Client-Disconnect-registry-listener-on-destruction.patch
A  +51   -0    debian/patches/0006-Client-Set-XdgShell-size-hints-before-the-first-comm.patch
A  +39   -0    debian/patches/0007-Fix-build.patch
A  +28   -0    debian/patches/0008-Fix-remove-listener.patch
A  +48   -0    debian/patches/0009-Hook-up-queryKeyboardModifers.patch
A  +39   -0    debian/patches/0010-Do-not-update-the-mask-if-we-do-not-have-a-surface.patch
A  +62   -0    debian/patches/0011-Correctly-detect-if-image-format-is-supported-by-QIm.patch
A  +26   -0    debian/patches/0012-Wayland-client-Fix-crash-when-windows-are-shown-hidd.patch
A  +70   -0    debian/patches/0013-Client-Don-t-always-recreate-frame-callbacks.patch
A  +52   -0    debian/patches/0014-Client-Always-destroy-frame-callback-in-the-actual-c.patch
A  +35   -0    debian/patches/0015-Fix-the-logic-for-decoding-modifiers-map-in-Wayland-.patch
A  +311  -0    debian/patches/0016-Wayland-client-use-wl_keyboard-to-determine-active-s.patch
A  +61   -0    debian/patches/0017-Client-do-not-empty-clipboard-when-a-new-popup-windo.patch
A  +24   -0    debian/patches/0018-Set-preedit-cursor-when-cursor-equals-to-0.patch
A  +486  -0    debian/patches/0019-Client-Implement-DataDeviceV3.patch
A  +60   -0    debian/patches/0020-Client-Delay-deletion-of-QDrag-object-until-after-we.patch
A  +33   -0    debian/patches/0021-Client-Avoid-processing-of-events-when-showing-windo.patch
A  +76   -0    debian/patches/0022-Handle-registry_global-out-of-constructor.patch
A  +42   -0    debian/patches/0023-Connect-flushRequest-after-forceRoundTrip.patch
A  +560  -0    debian/patches/0024-Move-the-wayland-socket-polling-to-a-separate-event-.patch
A  +25   -0    debian/patches/0025-Check-pointer-for-null-before-use-in-ASSERT.patch
A  +33   -0    debian/patches/0026-Do-not-create-decorations-when-the-shellSurface-is-n.patch
A  +116  -0    debian/patches/0027-Use-wl_surface.damage_buffer-on-the-client-side.patch
A  +24   -0    debian/patches/0028-Fix-crash-if-no-input-method-module-could-be-loaded.patch
A  +72   -0    debian/patches/0029-Client-Remove-mWaitingForUpdateDelivery.patch
A  +30   -0    debian/patches/0030-Cursor-position-0-should-still-show-the-cursor.patch
A  +83   -0    debian/patches/0031-Update-the-preedit-styling-mapping.patch
A  +77   -0    debian/patches/0032-client-Simplify-round-trip-behavior.patch
A  +26   -0    debian/patches/0033-Client-Fix-opaque-region-setter.patch
A  +119  -0    debian/patches/0034-Use-proper-dependencies-in-compile-tests.patch
A  +45   -0    debian/patches/0035-client-update-button-state-and-etc-in-pointer_leave.patch
A  +52   -0    debian/patches/0036-Revert-Client-Remove-mWaitingForUpdateDelivery.patch
A  +52   -0    debian/patches/0037-Fix-race-condition-on-mWaitingForUpdateDelivery.patch
A  +43   -0    debian/patches/0038-use-poll-2-when-reading-from-clipboard.patch
M  +38   -0    debian/patches/series

https://invent.kde.org/neon/qt/qtwayland/commit/d5955f471ef19686137b4f5f835d45fedc0eaa08

diff --git a/debian/changelog b/debian/changelog
index 60d4f9b..89dd46c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,6 +5,8 @@ qtwayland-opensource-src (5.15.4-1) UNRELEASED; urgency=medium
   * Bump Qt build-dependencies to 5.15.4.
   * Bump ABI version to 5-15-4.
   * Drop fix_dead_keys.diff, included in the new release.
+  * Add patches from KDE's Qt 5 Patch Collection up to 2022-05-14
+    (LP: #1967659).
 
  -- Debian Qt/KDE Maintainers <debian-qt-kde at lists.debian.org>  Fri, 13 May 2022 00:26:35 +0300
 
diff --git a/debian/patches/0001-Client-Announce-an-output-after-receiving-more-compl.patch b/debian/patches/0001-Client-Announce-an-output-after-receiving-more-compl.patch
new file mode 100644
index 0000000..0502226
--- /dev/null
+++ b/debian/patches/0001-Client-Announce-an-output-after-receiving-more-compl.patch
@@ -0,0 +1,139 @@
+From eca0516905c3f88aba876d18742c9102da2319db Mon Sep 17 00:00:00 2001
+From: Vlad Zahorodnii <vlad.zahorodnii at kde.org>
+Date: Wed, 5 May 2021 20:49:26 +0300
+Subject: [PATCH] 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 at 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(-)
+
+--- 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()
+--- 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)
diff --git a/debian/patches/0002-Fix-issue-with-repeated-window-size-changes.patch b/debian/patches/0002-Fix-issue-with-repeated-window-size-changes.patch
new file mode 100644
index 0000000..120d218
--- /dev/null
+++ b/debian/patches/0002-Fix-issue-with-repeated-window-size-changes.patch
@@ -0,0 +1,51 @@
+From 95a139413337bb92a9dbbbd95f61e52cc1f43649 Mon Sep 17 00:00:00 2001
+From: Jaeyoon Jung <jaeyoon.jung at lge.com>
+Date: Mon, 15 Feb 2021 08:31:06 +0900
+Subject: [PATCH] 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 at 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(-)
+
+--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
++++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
+@@ -131,14 +131,16 @@ void QWaylandEglWindow::updateSurface(bool create)
+             if (!disableResizeCheck) {
+                 wl_egl_window_get_attached_size(m_waylandEglWindow, &current_width, &current_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) {
+--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
++++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
+@@ -88,6 +88,7 @@ private:
+     mutable QOpenGLFramebufferObject *m_contentFBO = nullptr;
+ 
+     QSurfaceFormat m_format;
++    QSize m_requestedSize;
+ };
+ 
+ }
diff --git a/debian/patches/0003-Include-locale.h-for-setlocale-LC_CTYPE.patch b/debian/patches/0003-Include-locale.h-for-setlocale-LC_CTYPE.patch
new file mode 100644
index 0000000..1a0db4b
--- /dev/null
+++ b/debian/patches/0003-Include-locale.h-for-setlocale-LC_CTYPE.patch
@@ -0,0 +1,26 @@
+From 4f5bef9e6e0d16bb859e7a99ef5ebfca2ac93f45 Mon Sep 17 00:00:00 2001
+From: Albert Astals Cid <albert.astals.cid at kdab.com>
+Date: Mon, 10 May 2021 14:38:49 +0200
+Subject: [PATCH] Include locale.h for setlocale/LC_CTYPE
+
+Pick-to: 5.15
+Change-Id: Iced32a31a63cec71008549c1e0961d59ffc45a37
+Reviewed-by: Aleix Pol Gonzalez <aleixpol at kde.org>
+(cherry picked from commit e9522eda46028f351d87311d898ab985856970b0)
+---
+ src/client/qwaylandinputcontext.cpp | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/src/client/qwaylandinputcontext.cpp
++++ b/src/client/qwaylandinputcontext.cpp
+@@ -51,6 +51,10 @@
+ #include "qwaylandinputmethodeventbuilder_p.h"
+ #include "qwaylandwindow_p.h"
+ 
++#if QT_CONFIG(xkbcommon)
++#include <locale.h>
++#endif
++
+ QT_BEGIN_NAMESPACE
+ 
+ Q_LOGGING_CATEGORY(qLcQpaInputMethods, "qt.qpa.input.methods")
diff --git a/debian/patches/0004-Client-Connect-drags-being-accepted-to-updating-the-.patch b/debian/patches/0004-Client-Connect-drags-being-accepted-to-updating-the-.patch
new file mode 100644
index 0000000..72735f8
--- /dev/null
+++ b/debian/patches/0004-Client-Connect-drags-being-accepted-to-updating-the-.patch
@@ -0,0 +1,34 @@
+From 58f7e6cfb61e4f170ab7ced2e01b6222036f934d Mon Sep 17 00:00:00 2001
+From: David Edmundson <davidedmundson at kde.org>
+Date: Tue, 9 Feb 2021 16:09:21 +0000
+Subject: [PATCH] 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 at kde.org>
+Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt at qt.io>
+(cherry picked from commit 08e478448a97a440d5a968a5d797f0d7302140c2)
+---
+ src/client/qwaylanddatadevice.cpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- 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;
diff --git a/debian/patches/0005-Client-Disconnect-registry-listener-on-destruction.patch b/debian/patches/0005-Client-Disconnect-registry-listener-on-destruction.patch
new file mode 100644
index 0000000..e64272c
--- /dev/null
+++ b/debian/patches/0005-Client-Disconnect-registry-listener-on-destruction.patch
@@ -0,0 +1,42 @@
+From 0b8b965626c7d02ce885187fa46fe6c69af3ede3 Mon Sep 17 00:00:00 2001
+From: David Edmundson <davidedmundson at kde.org>
+Date: Fri, 14 May 2021 13:23:24 +0100
+Subject: [PATCH] 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(+)
+
+--- 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);
+--- 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;
diff --git a/debian/patches/0006-Client-Set-XdgShell-size-hints-before-the-first-comm.patch b/debian/patches/0006-Client-Set-XdgShell-size-hints-before-the-first-comm.patch
new file mode 100644
index 0000000..ca6d7cf
--- /dev/null
+++ b/debian/patches/0006-Client-Set-XdgShell-size-hints-before-the-first-comm.patch
@@ -0,0 +1,51 @@
+From 71de867aab030a9f48bd73e4090d301da75e4102 Mon Sep 17 00:00:00 2001
+From: David Edmundson <davidedmundson at kde.org>
+Date: Mon, 3 May 2021 23:01:53 +0100
+Subject: [PATCH] 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 at kde.org>
+Reviewed-by: Aleix Pol Gonzalez <aleixpol at 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(-)
+
+--- 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;
+ }
+@@ -257,6 +255,7 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *s
+                 m_toplevel->set_parent(parentXdgSurface->m_toplevel->object());
+         }
+     }
++    setSizeHints();
+ }
+ 
+ QWaylandXdgSurface::~QWaylandXdgSurface()
+--- 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));
diff --git a/debian/patches/0007-Fix-build.patch b/debian/patches/0007-Fix-build.patch
new file mode 100644
index 0000000..72b3f07
--- /dev/null
+++ b/debian/patches/0007-Fix-build.patch
@@ -0,0 +1,39 @@
+From 342e5b7d0b45db4ed6679af4b40b05b4bd96de09 Mon Sep 17 00:00:00 2001
+From: David Edmundson <davidedmundson at kde.org>
+Date: Mon, 14 Jun 2021 12:45:37 +0100
+Subject: [PATCH] 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(-)
+
+--- 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)
+--- 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
diff --git a/debian/patches/0008-Fix-remove-listener.patch b/debian/patches/0008-Fix-remove-listener.patch
new file mode 100644
index 0000000..7fa56b5
--- /dev/null
+++ b/debian/patches/0008-Fix-remove-listener.patch
@@ -0,0 +1,28 @@
+From 7d6a8aa51603e39a5da5b87af2acd0433a265987 Mon Sep 17 00:00:00 2001
+From: Zhang Liang <zhanglianga at uniontech.com>
+Date: Mon, 1 Feb 2021 19:29:43 +0800
+Subject: [PATCH] Fix: remove listener
+
+Add the operation for removing the listener form listener list
+
+Change-Id: Ief2ff1303b607eee499543303fe80e51f8f10cc5
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+(cherry picked from commit 16760280fd04cf70255bab16d9acecad254fdd8f)
+---
+ src/client/qwaylanddisplay.cpp | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/src/client/qwaylanddisplay.cpp
++++ b/src/client/qwaylanddisplay.cpp
+@@ -452,9 +452,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()
diff --git a/debian/patches/0009-Hook-up-queryKeyboardModifers.patch b/debian/patches/0009-Hook-up-queryKeyboardModifers.patch
new file mode 100644
index 0000000..57ec476
--- /dev/null
+++ b/debian/patches/0009-Hook-up-queryKeyboardModifers.patch
@@ -0,0 +1,48 @@
+From bea49655add94c2ab77ec39dfe33bf6c7f5ce927 Mon Sep 17 00:00:00 2001
+From: David Redondo <qt at david-redondo.de>
+Date: Wed, 26 May 2021 14:49:40 +0200
+Subject: [PATCH] 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 at kde.org>
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+
+
+(cherry picked from commit 4fa2baba8181ade4958a94e9531ec4f6919438a9)
+---
+ src/client/qwaylandintegration.cpp | 8 ++++++++
+ src/client/qwaylandintegration_p.h | 2 ++
+ 2 files changed, 10 insertions(+)
+
+--- 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())
+--- 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;
diff --git a/debian/patches/0010-Do-not-update-the-mask-if-we-do-not-have-a-surface.patch b/debian/patches/0010-Do-not-update-the-mask-if-we-do-not-have-a-surface.patch
new file mode 100644
index 0000000..d4acd5f
--- /dev/null
+++ b/debian/patches/0010-Do-not-update-the-mask-if-we-do-not-have-a-surface.patch
@@ -0,0 +1,39 @@
+From c7022c1c0107781993b1d13e7aa11dd3f7486249 Mon Sep 17 00:00:00 2001
+From: Aleix Pol <aleixpol at kde.org>
+Date: Tue, 13 Jul 2021 13:32:15 +0200
+Subject: [PATCH] Do not update the mask if we do not have a surface
+
+mMask serves as a cache to remember what we've sent, the source of truth
+for the value is window()->mask().
+No need to store values that we are going to discard, because it will
+confuse the state of newly created windows.
+
+Change-Id: I6aa3da82c7f09c7ef90d0f7060f292fb042730f0
+Pick-to: 5.15 6.2
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+(cherry picked from commit 962f87190c682562b369c5ebd93dc9ce0915ed7a)
+---
+ src/client/qwaylandwindow.cpp | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/src/client/qwaylandwindow.cpp
++++ b/src/client/qwaylandwindow.cpp
+@@ -464,14 +464,15 @@ void QWaylandWindow::lower()
+ 
+ void QWaylandWindow::setMask(const QRegion &mask)
+ {
++    QReadLocker locker(&mSurfaceLock);
++    if (!mSurface)
++        return;
++
+     if (mMask == mask)
+         return;
+ 
+     mMask = mask;
+ 
+-    if (!mSurface)
+-        return;
+-
+     if (mMask.isEmpty()) {
+         mSurface->set_input_region(nullptr);
+ 
diff --git a/debian/patches/0011-Correctly-detect-if-image-format-is-supported-by-QIm.patch b/debian/patches/0011-Correctly-detect-if-image-format-is-supported-by-QIm.patch
new file mode 100644
index 0000000..c882020
--- /dev/null
+++ b/debian/patches/0011-Correctly-detect-if-image-format-is-supported-by-QIm.patch
@@ -0,0 +1,62 @@
+From 83a5e079e4bdf567010abc0b7d67eff052b76249 Mon Sep 17 00:00:00 2001
+From: Jan Blackquill <uhhadd at gmail.com>
+Date: Tue, 24 Aug 2021 14:36:34 -0400
+Subject: [PATCH] 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 at kde.org>
+Reviewed-by: Qt CI Bot <qt_ci_bot at qt-project.org>
+(cherry picked from commit 6072c1dc87e185f30c014f764737ac97b906640f)
+---
+ src/shared/qwaylandmimehelper.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- 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;
+             }
diff --git a/debian/patches/0012-Wayland-client-Fix-crash-when-windows-are-shown-hidd.patch b/debian/patches/0012-Wayland-client-Fix-crash-when-windows-are-shown-hidd.patch
new file mode 100644
index 0000000..f57806c
--- /dev/null
+++ b/debian/patches/0012-Wayland-client-Fix-crash-when-windows-are-shown-hidd.patch
@@ -0,0 +1,26 @@
+From 19d0878e56094b5cced1154ce07f566f2b147e2a Mon Sep 17 00:00:00 2001
+From: Paul Olav Tvete <paul.tvete at qt.io>
+Date: Tue, 14 Sep 2021 11:56:23 +0200
+Subject: [PATCH] Wayland client: Fix crash when windows are shown/hidden
+ during drag
+
+Fixes: QTBUG-87624
+Pick-to: 6.2 5.15
+Change-Id: I1b9443df091878abcd4fbe9c55927cb819aebd59
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+(cherry picked from commit c64c5d3849b40617e1de0295f8690f354cab2b3a)
+---
+ src/client/qwaylanddatadevice.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/src/client/qwaylanddatadevice.cpp
++++ b/src/client/qwaylanddatadevice.cpp
+@@ -169,7 +169,7 @@ void QWaylandDataDevice::data_device_drop()
+ 
+ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface, wl_fixed_t x, wl_fixed_t y, wl_data_offer *id)
+ {
+-    auto *dragWaylandWindow = QWaylandWindow::fromWlSurface(surface);
++    auto *dragWaylandWindow = surface ? QWaylandWindow::fromWlSurface(surface) : nullptr;
+     if (!dragWaylandWindow)
+         return; // Ignore foreign surfaces
+ 
diff --git a/debian/patches/0013-Client-Don-t-always-recreate-frame-callbacks.patch b/debian/patches/0013-Client-Don-t-always-recreate-frame-callbacks.patch
new file mode 100644
index 0000000..0e7f926
--- /dev/null
+++ b/debian/patches/0013-Client-Don-t-always-recreate-frame-callbacks.patch
@@ -0,0 +1,70 @@
+From abaa0b1765551533112944e624ac5989df7d7b6c Mon Sep 17 00:00:00 2001
+From: Georges Basile Stavracas Neto <gbsneto at gnome.org>
+Date: Thu, 27 May 2021 19:55:04 -0300
+Subject: [PATCH] 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 at qt-project.org>
+Reviewed-by: Georges Basile Stavracas Neto <gbsneto at gnome.org>
+Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt at 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(+)
+
+--- a/src/client/qwaylandwindow.cpp
++++ b/src/client/qwaylandwindow.cpp
+@@ -1170,6 +1170,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)
+--- 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()
diff --git a/debian/patches/0014-Client-Always-destroy-frame-callback-in-the-actual-c.patch b/debian/patches/0014-Client-Always-destroy-frame-callback-in-the-actual-c.patch
new file mode 100644
index 0000000..1359e27
--- /dev/null
+++ b/debian/patches/0014-Client-Always-destroy-frame-callback-in-the-actual-c.patch
@@ -0,0 +1,52 @@
+From 1428e39b6e686faf4d25ab4f8506662bcc23e6f9 Mon Sep 17 00:00:00 2001
+From: Georges Basile Stavracas Neto <gbsneto at gnome.org>
+Date: Thu, 27 May 2021 20:02:53 -0300
+Subject: [PATCH] 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 at qt.io>
+(cherry picked from commit 42cdc61a93cf2acb09936aebb5e431fdbc0a26c6)
+---
+ src/client/qwaylandwindow.cpp | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+--- a/src/client/qwaylandwindow.cpp
++++ b/src/client/qwaylandwindow.cpp
+@@ -622,9 +622,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();
+     }
+ };
+@@ -1179,11 +1183,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);
diff --git a/debian/patches/0015-Fix-the-logic-for-decoding-modifiers-map-in-Wayland-.patch b/debian/patches/0015-Fix-the-logic-for-decoding-modifiers-map-in-Wayland-.patch
new file mode 100644
index 0000000..c6d40ac
--- /dev/null
+++ b/debian/patches/0015-Fix-the-logic-for-decoding-modifiers-map-in-Wayland-.patch
@@ -0,0 +1,35 @@
+From 132be08e4d81c1e05b93f31a6e2b6a6bd65d5726 Mon Sep 17 00:00:00 2001
+From: Rodney Dawes <dobey.pwns at gmail.com>
+Date: Fri, 15 Oct 2021 12:55:33 -0400
+Subject: [PATCH] Fix the logic for decoding modifiers map in Wayland text
+ input protocol
+
+Correctly check for the flags in the modifiers map when we get it from
+the compositor, instead of modifying the map in the for loop conditional.
+
+[ChangeLog][QWaylandInputContext] Fix modifiers map decoding
+logic when receiving the map from the compositor.
+
+Fixes: QTBUG-97094
+Pick-to: 6.2 5.15 5.12
+Change-Id: Idad19f7b1f4560d40abbb5b31032360cfe915261
+Reviewed-by: Paul Olav Tvete <paul.tvete at qt.io>
+---
+ src/client/qwaylandinputcontext.cpp | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/src/client/qwaylandinputcontext.cpp
++++ b/src/client/qwaylandinputcontext.cpp
+@@ -387,8 +387,10 @@ void QWaylandTextInput::zwp_text_input_v2_input_method_changed(uint32_t serial,
+ Qt::KeyboardModifiers QWaylandTextInput::modifiersToQtModifiers(uint32_t modifiers)
+ {
+     Qt::KeyboardModifiers ret = Qt::NoModifier;
+-    for (int i = 0; modifiers >>= 1; ++i) {
+-        ret |= m_modifiersMap[i];
++    for (int i = 0; i < m_modifiersMap.size(); ++i) {
++        if (modifiers & (1 << i)) {
++            ret |= m_modifiersMap[i];
++        }
+     }
+     return ret;
+ }
diff --git a/debian/patches/0016-Wayland-client-use-wl_keyboard-to-determine-active-s.patch b/debian/patches/0016-Wayland-client-use-wl_keyboard-to-determine-active-s.patch
new file mode 100644
index 0000000..3504642
--- /dev/null
+++ b/debian/patches/0016-Wayland-client-use-wl_keyboard-to-determine-active-s.patch
@@ -0,0 +1,311 @@
+From f73a3ec466eb30e554f918d6d2da2c5d1b0e23bd Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?M=C3=A9ven=20Car?= <meven.car at enioka.com>
+Date: Wed, 18 Aug 2021 18:28:20 +0200
+Subject: [PATCH] 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 at 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(-)
+
+--- a/src/client/qwaylanddisplay.cpp
++++ b/src/client/qwaylanddisplay.cpp
+@@ -575,14 +575,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;
+ }
+@@ -627,6 +623,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()
+--- a/src/client/qwaylanddisplay_p.h
++++ b/src/client/qwaylanddisplay_p.h
+@@ -215,6 +215,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();
+--- 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)
+@@ -1083,10 +1084,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;
+ }
+ 
+--- 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;
+--- 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);
+--- 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
+--- 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;
+--- 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
+--- 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;
+--- 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
+--- 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
+--- 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;
+--- 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([=] {
diff --git a/debian/patches/0017-Client-do-not-empty-clipboard-when-a-new-popup-windo.patch b/debian/patches/0017-Client-do-not-empty-clipboard-when-a-new-popup-windo.patch
new file mode 100644
index 0000000..6c6a3e0
--- /dev/null
+++ b/debian/patches/0017-Client-do-not-empty-clipboard-when-a-new-popup-windo.patch
@@ -0,0 +1,61 @@
+From 83440ae9e002f0c7bdec6b54db6b382d2e28bf7d Mon Sep 17 00:00:00 2001
+From: Jan Grulich <jgrulich at redhat.com>
+Date: Fri, 16 Jul 2021 13:00:03 +0200
+Subject: [PATCH] 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 at qt-project.org>
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+
+Cherry-pick: 1e57ebd501cfc2255300392cd4565cd034efeed8
+---
+ src/client/qwaylanddisplay.cpp     | 13 +++++++++++++
+ src/client/qwaylandinputdevice.cpp |  8 --------
+ 2 files changed, 13 insertions(+), 8 deletions(-)
+
+--- a/src/client/qwaylanddisplay.cpp
++++ b/src/client/qwaylanddisplay.cpp
+@@ -597,6 +597,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 = {
+--- a/src/client/qwaylandinputdevice.cpp
++++ b/src/client/qwaylandinputdevice.cpp
+@@ -1300,14 +1300,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();
+ }
diff --git a/debian/patches/0018-Set-preedit-cursor-when-cursor-equals-to-0.patch b/debian/patches/0018-Set-preedit-cursor-when-cursor-equals-to-0.patch
new file mode 100644
index 0000000..4f5496d
--- /dev/null
+++ b/debian/patches/0018-Set-preedit-cursor-when-cursor-equals-to-0.patch
@@ -0,0 +1,24 @@
+From 1a476429c2d9034322d5b3366ce53375e484353a Mon Sep 17 00:00:00 2001
+From: Weng Xuetian <wengxt at gmail.com>
+Date: Sat, 18 Dec 2021 23:42:49 -0800
+Subject: [PATCH] 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 at qt.io>
+(cherry picked from commit 719a55be13bdadfa659a732755f280e276a894bd)
+---
+ src/shared/qwaylandinputmethodeventbuilder.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- 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()));
diff --git a/debian/patches/0019-Client-Implement-DataDeviceV3.patch b/debian/patches/0019-Client-Implement-DataDeviceV3.patch
new file mode 100644
index 0000000..1746de1
--- /dev/null
+++ b/debian/patches/0019-Client-Implement-DataDeviceV3.patch
@@ -0,0 +1,486 @@
+From 8afae71a44d0d5a0be477863da791dd2dfe2027d Mon Sep 17 00:00:00 2001
+From: David Edmundson <davidedmundson at kde.org>
+Date: Tue, 16 Feb 2021 09:51:47 +0000
+Subject: [PATCH] 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 at 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(-)
+
+--- 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)
+ 
+ }
+--- 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;
+--- 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.
+--- 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);
+--- 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)
+ {
+--- 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;
+ };
+ 
+ 
+--- 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);
+ }
+ 
+ }
+--- 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;
+ };
+ 
+ }
+--- 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));
+--- 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);
+ }
+--- 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;
+--- 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:
diff --git a/debian/patches/0020-Client-Delay-deletion-of-QDrag-object-until-after-we.patch b/debian/patches/0020-Client-Delay-deletion-of-QDrag-object-until-after-we.patch
new file mode 100644
index 0000000..0bec324
--- /dev/null
+++ b/debian/patches/0020-Client-Delay-deletion-of-QDrag-object-until-after-we.patch
@@ -0,0 +1,60 @@
+From e92aff243eca4c1e30c093692dce6f7c91d7a19c Mon Sep 17 00:00:00 2001
+From: Arjen Hiemstra <ahiemstra at heimr.nl>
+Date: Thu, 18 Nov 2021 13:05:30 +0100
+Subject: [PATCH] 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 at kde.org>
+(cherry picked from commit 39e3290efa2dd40722fa3322284cae3b01ccedf4)
+---
+ src/client/qwaylanddnd.cpp | 11 +++++++++++
+ src/client/qwaylanddnd_p.h |  1 +
+ 2 files changed, 12 insertions(+)
+
+--- 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;
+ }
+ 
+ }
+--- 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;
diff --git a/debian/patches/0021-Client-Avoid-processing-of-events-when-showing-windo.patch b/debian/patches/0021-Client-Avoid-processing-of-events-when-showing-windo.patch
new file mode 100644
index 0000000..65be7aa
--- /dev/null
+++ b/debian/patches/0021-Client-Avoid-processing-of-events-when-showing-windo.patch
@@ -0,0 +1,33 @@
+From 340e89575c93435abab78ac73603b405f1f05ceb Mon Sep 17 00:00:00 2001
+From: David Edmundson <davidedmundson at kde.org>
+Date: Sun, 14 Nov 2021 13:54:19 +0000
+Subject: [PATCH] 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 at qt-project.org>
+Reviewed-by: Aleix Pol Gonzalez <aleixpol at kde.org>
+(cherry picked from commit 46ed85a80b28d519cf5887bbdce55d1bf57886c3)
+---
+ src/client/qwaylandwindow.cpp | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- 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
diff --git a/debian/patches/0022-Handle-registry_global-out-of-constructor.patch b/debian/patches/0022-Handle-registry_global-out-of-constructor.patch
new file mode 100644
index 0000000..45eaf47
--- /dev/null
+++ b/debian/patches/0022-Handle-registry_global-out-of-constructor.patch
@@ -0,0 +1,76 @@
+From de7afd339100cac1470f875eafc22d3ee87870bd Mon Sep 17 00:00:00 2001
+From: Elvis Lee <kwangwoong.lee at lge.com>
+Date: Thu, 18 Feb 2021 15:45:49 +0900
+Subject: [PATCH] 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 at 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(-)
+
+--- 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)
+--- 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
+--- 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();
+ }
diff --git a/debian/patches/0023-Connect-flushRequest-after-forceRoundTrip.patch b/debian/patches/0023-Connect-flushRequest-after-forceRoundTrip.patch
new file mode 100644
index 0000000..1e1d40e
--- /dev/null
+++ b/debian/patches/0023-Connect-flushRequest-after-forceRoundTrip.patch
@@ -0,0 +1,42 @@
+From a5df6f67f446ed091c688336510b5da2970a0d84 Mon Sep 17 00:00:00 2001
+From: Elvis Lee <kwangwoong.lee at lge.com>
+Date: Wed, 17 Mar 2021 16:31:10 +0900
+Subject: [PATCH] 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 at qt.io>
+(cherry picked from commit 654a54755138c520c3a41210d8078196e9a2c1bf)
+---
+ src/client/qwaylandintegration.cpp | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- 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();
+ }
diff --git a/debian/patches/0024-Move-the-wayland-socket-polling-to-a-separate-event-.patch b/debian/patches/0024-Move-the-wayland-socket-polling-to-a-separate-event-.patch
new file mode 100644
index 0000000..2fef5ce
--- /dev/null
+++ b/debian/patches/0024-Move-the-wayland-socket-polling-to-a-separate-event-.patch
@@ -0,0 +1,560 @@
+From 967883d20e94183bd9cf6648297b9d76ba0e167e Mon Sep 17 00:00:00 2001
+From: Adrien Faveraux <af at brain-networks.fr>
+Date: Fri, 26 Nov 2021 09:18:58 +0100
+Subject: [PATCH] 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 at ubports.com>
+Task-number: QTBUG-66075
+Change-Id: Ibb33ad7f4193b866d1b8d7a0405a94d59dcad5eb
+Reviewed-by: Qt CI Bot <qt_ci_bot at qt-project.org>
+Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt at 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(-)
+
+--- 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
+--- 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();
+ 
+--- 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();
+--- 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);
+--- 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
diff --git a/debian/patches/0025-Check-pointer-for-null-before-use-in-ASSERT.patch b/debian/patches/0025-Check-pointer-for-null-before-use-in-ASSERT.patch
new file mode 100644
index 0000000..e069641
--- /dev/null
+++ b/debian/patches/0025-Check-pointer-for-null-before-use-in-ASSERT.patch
@@ -0,0 +1,25 @@
+From 520f58c24e0fbb33f84f329fc9879b72710c77ae Mon Sep 17 00:00:00 2001
+From: Roman Genkhel <roman.genhel at lge.com>
+Date: Thu, 12 Nov 2020 12:21:51 +0300
+Subject: [PATCH] Check pointer for null before use in ASSERT
+
+Task-number: QTBUG-85195
+Change-Id: I331e54f6e58aa9d536351a55223610c60b3cb414
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+(cherry picked from commit e235e8ddb1fc3cc5ab3b70b1fb285770b2c8c9ca)
+---
+ src/client/qwaylandwindow.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/src/client/qwaylandwindow.cpp
++++ b/src/client/qwaylandwindow.cpp
+@@ -552,8 +552,8 @@ void QWaylandWindow::sendRecursiveExposeEvent()
+ 
+ void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
+ {
+-    Q_ASSERT(!buffer->committed());
+     if (buffer) {
++        Q_ASSERT(!buffer->committed());
+         handleUpdate();
+         buffer->setBusy();
+ 
diff --git a/debian/patches/0026-Do-not-create-decorations-when-the-shellSurface-is-n.patch b/debian/patches/0026-Do-not-create-decorations-when-the-shellSurface-is-n.patch
new file mode 100644
index 0000000..48785cf
--- /dev/null
+++ b/debian/patches/0026-Do-not-create-decorations-when-the-shellSurface-is-n.patch
@@ -0,0 +1,33 @@
+From 72f64f397c72afb22df1825382e17a310517add1 Mon Sep 17 00:00:00 2001
+From: Inho Lee <inho.lee at qt.io>
+Date: Mon, 1 Nov 2021 14:23:58 +0100
+Subject: [PATCH] Do not create decorations when the shellSurface is not ready
+
+A cases reported that client windows try to make decorations
+when their shell surfaces are null.
+Since the surfaces' requests for decorations should be applied,
+those case will be failed to create decorations.
+
+This patch was modified by Paul Tvete's advice.
+(paul.tvete at qt.io)
+
+Pick-to: 6.2 5.15
+Task-number: QTBUG-97608
+Change-Id: I2563dbd73b730f81cc411857af07da99ceb2d063
+Reviewed-by: Paul Olav Tvete <paul.tvete at qt.io>
+(cherry picked from commit 246f0c0bc01dd059bf8165e81f7b49efa36e4d95)
+---
+ src/client/qwaylandwindow.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/src/client/qwaylandwindow.cpp
++++ b/src/client/qwaylandwindow.cpp
+@@ -813,7 +813,7 @@ bool QWaylandWindow::createDecoration()
+         decoration = false;
+     if (mSubSurfaceWindow)
+         decoration = false;
+-    if (mShellSurface && !mShellSurface->wantsDecorations())
++    if (!mShellSurface || !mShellSurface->wantsDecorations())
+         decoration = false;
+ 
+     bool hadDecoration = mWindowDecoration;
diff --git a/debian/patches/0027-Use-wl_surface.damage_buffer-on-the-client-side.patch b/debian/patches/0027-Use-wl_surface.damage_buffer-on-the-client-side.patch
new file mode 100644
index 0000000..9f100f9
--- /dev/null
+++ b/debian/patches/0027-Use-wl_surface.damage_buffer-on-the-client-side.patch
@@ -0,0 +1,116 @@
+From 6935647966b456e760745a6b2a13a04ba6543803 Mon Sep 17 00:00:00 2001
+From: Paul Olav Tvete <paul.tvete at qt.io>
+Date: Mon, 6 Jul 2020 14:37:35 +0200
+Subject: [PATCH] Use wl_surface.damage_buffer on the client side
+
+Prefer the newer, recommended damage_buffer when the compositor
+supports it.
+
+Fixes: QTBUG-74929
+Change-Id: I9107966910b616a666931404a7b41bfac14c22c0
+Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt at qt.io>
+(cherry picked from commit 314fd6db51277224cdc799b039ef79db1101f5cd)
+---
+ src/client/qwaylanddisplay.cpp                  |  2 +-
+ src/client/qwaylandwindow.cpp                   | 16 +++++++++++++---
+ tests/auto/client/shared/coreprotocol.h         |  2 +-
+ tests/auto/client/shared_old/mockcompositor.cpp |  2 +-
+ tests/auto/client/shared_old/mocksurface.cpp    | 10 ++++++++++
+ tests/auto/client/shared_old/mocksurface.h      |  2 ++
+ 6 files changed, 28 insertions(+), 6 deletions(-)
+
+--- a/src/client/qwaylanddisplay.cpp
++++ b/src/client/qwaylanddisplay.cpp
+@@ -488,7 +488,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
+     if (interface == QStringLiteral("wl_output")) {
+         mWaitingScreens << new QWaylandScreen(this, version, id);
+     } else if (interface == QStringLiteral("wl_compositor")) {
+-        mCompositorVersion = qMin((int)version, 3);
++        mCompositorVersion = qMin((int)version, 4);
+         mCompositor.init(registry, id, mCompositorVersion);
+     } else if (interface == QStringLiteral("wl_shm")) {
+         mShm.reset(new QWaylandShm(this, version, id));
+--- a/src/client/qwaylandwindow.cpp
++++ b/src/client/qwaylandwindow.cpp
+@@ -571,7 +571,11 @@ void QWaylandWindow::attachOffset(QWaylandBuffer *buffer)
+ 
+ void QWaylandWindow::damage(const QRect &rect)
+ {
+-    mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
++    const int s = scale();
++    if (mDisplay->compositorVersion() >= 4)
++        mSurface->damage_buffer(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height());
++    else
++        mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
+ }
+ 
+ void QWaylandWindow::safeCommit(QWaylandBuffer *buffer, const QRegion &damage)
+@@ -605,8 +609,14 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
+         return;
+ 
+     attachOffset(buffer);
+-    for (const QRect &rect: damage)
+-        mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
++    if (mDisplay->compositorVersion() >= 4) {
++        const int s = scale();
++        for (const QRect &rect: damage)
++            mSurface->damage_buffer(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height());
++    } else {
++        for (const QRect &rect: damage)
++            mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
++    }
+     Q_ASSERT(!buffer->committed());
+     buffer->setCommitted();
+     mSurface->commit();
+--- a/tests/auto/client/shared/coreprotocol.h
++++ b/tests/auto/client/shared/coreprotocol.h
+@@ -158,7 +158,7 @@ class WlCompositor : public Global, public QtWaylandServer::wl_compositor
+ {
+     Q_OBJECT
+ public:
+-    explicit WlCompositor(CoreCompositor *compositor, int version = 3)
++    explicit WlCompositor(CoreCompositor *compositor, int version = 4)
+         : QtWaylandServer::wl_compositor(compositor->m_display, version)
+         , m_compositor(compositor)
+     {}
+--- a/tests/auto/client/shared_old/mockcompositor.cpp
++++ b/tests/auto/client/shared_old/mockcompositor.cpp
+@@ -342,7 +342,7 @@ Compositor::Compositor(MockCompositor *mockCompositor)
+         exit(EXIT_FAILURE);
+     }
+ 
+-    wl_global_create(m_display, &wl_compositor_interface, 1, this, bindCompositor);
++    wl_global_create(m_display, &wl_compositor_interface, 4, this, bindCompositor);
+ 
+     m_data_device_manager.reset(new DataDeviceManager(this, m_display));
+ 
+--- a/tests/auto/client/shared_old/mocksurface.cpp
++++ b/tests/auto/client/shared_old/mocksurface.cpp
+@@ -125,6 +125,16 @@ void Surface::surface_damage(Resource *resource,
+     Q_UNUSED(height);
+ }
+ 
++void Surface::surface_damage_buffer(Resource *resource,
++                                    int32_t x, int32_t y, int32_t width, int32_t height)
++{
++    Q_UNUSED(resource);
++    Q_UNUSED(x);
++    Q_UNUSED(y);
++    Q_UNUSED(width);
++    Q_UNUSED(height);
++}
++
+ void Surface::surface_frame(Resource *resource,
+                             uint32_t callback)
+ {
+--- a/tests/auto/client/shared_old/mocksurface.h
++++ b/tests/auto/client/shared_old/mocksurface.h
+@@ -65,6 +65,8 @@ protected:
+                         struct wl_resource *buffer, int x, int y) override;
+     void surface_damage(Resource *resource,
+                         int32_t x, int32_t y, int32_t width, int32_t height) override;
++    void surface_damage_buffer(Resource *resource,
++                               int32_t x, int32_t y, int32_t width, int32_t height) override;
+     void surface_frame(Resource *resource,
+                        uint32_t callback) override;
+     void surface_commit(Resource *resource) override;
diff --git a/debian/patches/0028-Fix-crash-if-no-input-method-module-could-be-loaded.patch b/debian/patches/0028-Fix-crash-if-no-input-method-module-could-be-loaded.patch
new file mode 100644
index 0000000..236b29b
--- /dev/null
+++ b/debian/patches/0028-Fix-crash-if-no-input-method-module-could-be-loaded.patch
@@ -0,0 +1,24 @@
+From 506d0372178134f208fd08b3f6b9499fc0e14a5e Mon Sep 17 00:00:00 2001
+From: Joni Poikelin <joni.poikelin at qt.io>
+Date: Thu, 3 Feb 2022 14:01:50 +0200
+Subject: [PATCH] Fix crash if no input method module could be loaded
+
+Pick-to: 6.2 6.3 5.15
+Change-Id: I8f346def616606a6c5540856bd08a84ee7ed5ca2
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+(cherry picked from commit 49fb7248f6ab7de046e2179c7861951ea1169e9b)
+---
+ src/client/qwaylandintegration.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/src/client/qwaylandintegration.cpp
++++ b/src/client/qwaylandintegration.cpp
+@@ -491,7 +491,7 @@ void QWaylandIntegration::reconfigureInputContext()
+     }
+ #endif
+ 
+-    qCDebug(lcQpaWayland) << "using input method:" << inputContext()->metaObject()->className();
++    qCDebug(lcQpaWayland) << "using input method:" << (inputContext() ? inputContext()->metaObject()->className() : "<none>");
+ }
+ 
+ QWaylandShellIntegration *QWaylandIntegration::createShellIntegration(const QString &integrationName)
diff --git a/debian/patches/0029-Client-Remove-mWaitingForUpdateDelivery.patch b/debian/patches/0029-Client-Remove-mWaitingForUpdateDelivery.patch
new file mode 100644
index 0000000..6b923c4
--- /dev/null
+++ b/debian/patches/0029-Client-Remove-mWaitingForUpdateDelivery.patch
@@ -0,0 +1,72 @@
+From c2e56e076f0ded39b1ab34ebf07afad2f344f53f Mon Sep 17 00:00:00 2001
+From: Vlad Zahorodnii <vlad.zahorodnii at kde.org>
+Date: Tue, 1 Feb 2022 13:05:36 +0200
+Subject: [PATCH] Client: Remove mWaitingForUpdateDelivery
+
+Currently, mWaitingForUpdateDelivery is shared between the main thread
+(doHandleFrameCallback()) and the frame callback event thread
+(handleFrameCallback()), however the access to it is not synchronized
+between both threads. On the other hand, QWaylandWindow
+already ensures not to create a frame callback if there's already one
+pending.
+
+This change removes mWaitingForUpdateDelivery flag because it should be
+already covered by mWaitingForFrameCallback and to remove unsynchronized
+shared state between threads.
+
+Change-Id: I0e5a25d18d1e66c4d7683e7e972330c4d7cbbf38
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+(cherry picked from commit feb1a5c207c13d0bf87c0d8ad039279dbf8cee9e)
+---
+ src/client/qwaylandwindow.cpp | 29 ++++++++++++-----------------
+ src/client/qwaylandwindow_p.h |  1 -
+ 2 files changed, 12 insertions(+), 18 deletions(-)
+
+--- a/src/client/qwaylandwindow.cpp
++++ b/src/client/qwaylandwindow.cpp
+@@ -648,23 +648,18 @@ void QWaylandWindow::handleFrameCallback()
+     mFrameCallbackElapsedTimer.invalidate();
+ 
+     // The rest can wait until we can run it on the correct thread
+-    if (!mWaitingForUpdateDelivery) {
+-        auto doHandleExpose = [this]() {
+-            bool wasExposed = isExposed();
+-            mFrameCallbackTimedOut = false;
+-            if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
+-                sendExposeEvent(QRect(QPoint(), geometry().size()));
+-            if (wasExposed && hasPendingUpdateRequest())
+-                deliverUpdateRequest();
+-
+-            mWaitingForUpdateDelivery = false;
+-        };
+-
+-        // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
+-        // in the single-threaded case.
+-        mWaitingForUpdateDelivery = true;
+-        QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection);
+-    }
++    auto doHandleExpose = [this]() {
++        bool wasExposed = isExposed();
++        mFrameCallbackTimedOut = false;
++        if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
++            sendExposeEvent(QRect(QPoint(), geometry().size()));
++        if (wasExposed && hasPendingUpdateRequest())
++            deliverUpdateRequest();
++    };
++
++    // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
++    // in the single-threaded case.
++    QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection);
+ 
+     mFrameSyncWait.notify_all();
+ }
+--- a/src/client/qwaylandwindow_p.h
++++ b/src/client/qwaylandwindow_p.h
+@@ -228,7 +228,6 @@ protected:
+     WId mWindowId;
+     bool mWaitingForFrameCallback = false;
+     bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
+-    bool mWaitingForUpdateDelivery = false;
+     int mFrameCallbackCheckIntervalTimerId = -1;
+     QElapsedTimer mFrameCallbackElapsedTimer;
+     struct ::wl_callback *mFrameCallback = nullptr;
diff --git a/debian/patches/0030-Cursor-position-0-should-still-show-the-cursor.patch b/debian/patches/0030-Cursor-position-0-should-still-show-the-cursor.patch
new file mode 100644
index 0000000..5a8fafc
--- /dev/null
+++ b/debian/patches/0030-Cursor-position-0-should-still-show-the-cursor.patch
@@ -0,0 +1,30 @@
+From 2d0bd70b55ebde2e22d0b95e8122235f90c8f9f1 Mon Sep 17 00:00:00 2001
+From: Weng Xuetian <wengxt at gmail.com>
+Date: Tue, 8 Feb 2022 07:11:25 -0800
+Subject: [PATCH] Cursor position == 0 should still show the cursor
+
+Otherwise the cursor would be hidden even if preedit is empty.
+Amends 719a55be13bdadfa659a732755f280e276a894bd
+
+Pick-to: 5.15 6.2 6.3
+Change-Id: I320733b917779b7b51aa4a28eaea411fdb10a318
+Reviewed-by: Liang Qi <liang.qi at qt.io>
+(cherry picked from commit 31ae194e295651d9ece03408630d2358acd4f7b4)
+---
+ src/shared/qwaylandinputmethodeventbuilder.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/src/shared/qwaylandinputmethodeventbuilder.cpp
++++ b/src/shared/qwaylandinputmethodeventbuilder.cpp
+@@ -151,9 +151,9 @@ 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) {
++    } else {
+         attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, indexFromWayland(text, m_preeditCursor), 1, QVariant()));
+     }
+ 
diff --git a/debian/patches/0031-Update-the-preedit-styling-mapping.patch b/debian/patches/0031-Update-the-preedit-styling-mapping.patch
new file mode 100644
index 0000000..ee9ef41
--- /dev/null
+++ b/debian/patches/0031-Update-the-preedit-styling-mapping.patch
@@ -0,0 +1,83 @@
+From f0f7b2bea822f73ae00fcfd4ee1679596d550a20 Mon Sep 17 00:00:00 2001
+From: Weng Xuetian <wengxt at gmail.com>
+Date: Wed, 22 Dec 2021 10:42:38 -0800
+Subject: [PATCH] Update the preedit styling mapping
+
+- None mapping to no style.
+- Default/Underline mapping to underline.
+- Highlight/Selection mapping to background color/text color with highlight/highlight
+text with underline.
+- Active/Inactive mapping to bold text with underline.
+- Incorrect mapping to red wave underline.
+
+Pick-to: 5.15 6.2 6.3
+Change-Id: Iab51d671b8f83aece8596f7f7610de19343fcceb
+Reviewed-by: Aleix Pol Gonzalez <aleixpol at kde.org>
+(cherry picked from commit f1fb5d9e568a24e213ee41e82a1142cef56f1098)
+---
+ .../qwaylandinputmethodeventbuilder.cpp       | 31 ++++++++++++-------
+ 1 file changed, 20 insertions(+), 11 deletions(-)
+
+--- a/src/shared/qwaylandinputmethodeventbuilder.cpp
++++ b/src/shared/qwaylandinputmethodeventbuilder.cpp
+@@ -39,7 +39,10 @@
+ 
+ #include "qwaylandinputmethodeventbuilder_p.h"
+ 
++#include <QBrush>
++#include <QGuiApplication>
+ #include <QInputMethod>
++#include <QPalette>
+ #include <QTextCharFormat>
+ 
+ #ifdef QT_BUILD_WAYLANDCOMPOSITOR_LIB
+@@ -81,32 +84,38 @@ void QWaylandInputMethodEventBuilder::addPreeditStyling(uint32_t index, uint32_t
+     QTextCharFormat format;
+ 
+     switch (style) {
+-    case 0:
+-    case 1:
++    case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_NONE:
++        break;
++    case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_DEFAULT:
++    case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_UNDERLINE:
+         format.setFontUnderline(true);
+         format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
+         m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format));
+         break;
+-    case 2:
+-    case 3:
++    case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_ACTIVE:
++    case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_INACTIVE:
+         format.setFontWeight(QFont::Bold);
+         format.setFontUnderline(true);
+         format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
+         m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format));
+         break;
+-    case 4:
+-        format.setFontUnderline(true);
+-        format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
+-        m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format));
++    case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_HIGHLIGHT:
++    case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_SELECTION:
++        {
++            format.setFontUnderline(true);
++            format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
++            QPalette palette = qApp->palette();
++            format.setBackground(QBrush(palette.color(QPalette::Active, QPalette::Highlight)));
++            format.setForeground(QBrush(palette.color(QPalette::Active, QPalette::HighlightedText)));
++            m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format));
++        }
+         break;
+-    case 5:
++    case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_INCORRECT:
+         format.setFontUnderline(true);
+         format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+         format.setUnderlineColor(QColor(Qt::red));
+         m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format));
+         break;
+-//    case QtWayland::wl_text_input::preedit_style_selection:
+-//    case QtWayland::wl_text_input::preedit_style_none:
+     default:
+         break;
+     }
diff --git a/debian/patches/0032-client-Simplify-round-trip-behavior.patch b/debian/patches/0032-client-Simplify-round-trip-behavior.patch
new file mode 100644
index 0000000..96e368b
--- /dev/null
+++ b/debian/patches/0032-client-Simplify-round-trip-behavior.patch
@@ -0,0 +1,77 @@
+From 596ecf46bb0c2427cda2894dd2157b3f5a2cd34f Mon Sep 17 00:00:00 2001
+From: David Edmundson <davidedmundson at kde.org>
+Date: Wed, 9 Feb 2022 17:20:48 +0000
+Subject: [PATCH] client: Simplify round trip behavior
+
+The custom event queue was removed in
+302d4ffb8549214eb4028dc3e47ec4ee4e12ffbd (2015) so the comment about not
+being able to use the inbuilt round trip method no longer applies.
+
+This fixes a real world problem. Use of a blocking round trip should not
+process non wayland events. Doing so can lead to misbehaviour client
+side as things happen out of order. The move to the event thread created
+several regressions as we now get events before the QGuiApplication is
+fully constructed.
+
+Change-Id: I650481f49a47ed1a9778c7e1bc3c48db6e8f0031
+Reviewed-by: Vlad Zahorodnii <vlad.zahorodnii at kde.org>
+Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt at qt.io>
+(cherry picked from commit 62646d9122845d7bd9104b610478cebde3e769c7)
+---
+ src/client/qwaylanddisplay.cpp | 43 +---------------------------------
+ 1 file changed, 1 insertion(+), 42 deletions(-)
+
+--- a/src/client/qwaylanddisplay.cpp
++++ b/src/client/qwaylanddisplay.cpp
+@@ -611,50 +611,9 @@ uint32_t QWaylandDisplay::currentTimeMillisec()
+     return 0;
+ }
+ 
+-static void
+-sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
+-{
+-    Q_UNUSED(serial)
+-    bool *done = static_cast<bool *>(data);
+-
+-    *done = true;
+-
+-    // If the wl_callback done event is received after the condition check in the while loop in
+-    // forceRoundTrip(), but before the call to processEvents, the call to processEvents may block
+-    // forever if no more events are posted (eventhough the callback is handled in response to the
+-    // aboutToBlock signal). Hence, we wake up the event dispatcher so forceRoundTrip may return.
+-    // (QTBUG-64696)
+-    if (auto *dispatcher = QThread::currentThread()->eventDispatcher())
+-        dispatcher->wakeUp();
+-
+-    wl_callback_destroy(callback);
+-}
+-
+-static const struct wl_callback_listener sync_listener = {
+-    sync_callback
+-};
+-
+ void QWaylandDisplay::forceRoundTrip()
+ {
+-    // wl_display_roundtrip() works on the main queue only,
+-    // but we use a separate one, so basically reimplement it here
+-    int ret = 0;
+-    bool done = false;
+-    wl_callback *callback = wl_display_sync(mDisplay);
+-    wl_callback_add_listener(callback, &sync_listener, &done);
+-    flushRequests();
+-    if (QThread::currentThread()->eventDispatcher()) {
+-        while (!done && ret >= 0) {
+-            QThread::currentThread()->eventDispatcher()->processEvents(QEventLoop::WaitForMoreEvents);
+-            ret = wl_display_dispatch_pending(mDisplay);
+-        }
+-    } else {
+-        while (!done && ret >= 0)
+-            ret = wl_display_dispatch(mDisplay);
+-    }
+-
+-    if (ret == -1 && !done)
+-        wl_callback_destroy(callback);
++     wl_display_roundtrip(mDisplay);
+ }
+ 
+ bool QWaylandDisplay::supportsWindowDecoration() const
diff --git a/debian/patches/0033-Client-Fix-opaque-region-setter.patch b/debian/patches/0033-Client-Fix-opaque-region-setter.patch
new file mode 100644
index 0000000..1b33a01
--- /dev/null
+++ b/debian/patches/0033-Client-Fix-opaque-region-setter.patch
@@ -0,0 +1,26 @@
+From f7b7b39d00ae31676fc678446d7090e7a9dd95b4 Mon Sep 17 00:00:00 2001
+From: Vlad Zahorodnii <vlad.zahorodnii at kde.org>
+Date: Sat, 19 Feb 2022 17:01:04 +0200
+Subject: [PATCH] Client: Fix opaque region setter
+
+The rect is in the global coordinate system, while the opaque region
+must be in the surface local coordinate system.
+
+Change-Id: I75042b4d779dfd4dfe610aad1f0387879f11b048
+Reviewed-by: Aleix Pol Gonzalez <aleixpol at kde.org>
+(cherry picked from commit f9425f573b18c0b66fd9ad9c2805e8b8b9a3ec77)
+---
+ src/client/qwaylandwindow.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/src/client/qwaylandwindow.cpp
++++ b/src/client/qwaylandwindow.cpp
+@@ -372,7 +372,7 @@ void QWaylandWindow::setGeometry(const QRect &rect)
+         mShellSurface->setWindowGeometry(windowContentGeometry());
+ 
+     if (isOpaque() && mMask.isEmpty())
+-        setOpaqueArea(rect);
++        setOpaqueArea(QRect(QPoint(0, 0), rect.size()));
+ }
+ 
+ void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset)
diff --git a/debian/patches/0034-Use-proper-dependencies-in-compile-tests.patch b/debian/patches/0034-Use-proper-dependencies-in-compile-tests.patch
new file mode 100644
index 0000000..1658c21
--- /dev/null
+++ b/debian/patches/0034-Use-proper-dependencies-in-compile-tests.patch
@@ -0,0 +1,119 @@
+From 6a95428357872353a20ab6dcc5f8facdb520e8dc Mon Sep 17 00:00:00 2001
+From: Fabian Vogt <fabian at ritter-vogt.de>
+Date: Fri, 4 Feb 2022 11:07:36 +0100
+Subject: [PATCH] Use proper dependencies in compile tests
+
+Use the dependencies as found by the "libraries" section instead of relying
+on them being available in the default location (e.g. "-ldrm").
+
+Additionally, VK_USE_PLATFORM_WAYLAND_KHR requires <wayland-client.h>, so
+add the wayland-client dependency.
+
+This fixes those tests if e.g. wayland-client headers need to be found through
+pkgconfig.
+
+This part of the code changed completely in Qt 6, so this is a totally
+different patch and not a cherry-pick of 5fc2e1915c3a
+("CMake: Fix qtwayland feature detection").
+
+Fixes: QTBUG-100475
+---
+ src/client/configure.json     |  8 ++++----
+ src/compositor/configure.json | 34 +++++++++++++++++++++++++++++-----
+ 2 files changed, 33 insertions(+), 9 deletions(-)
+
+--- a/src/client/configure.json
++++ b/src/client/configure.json
+@@ -149,8 +149,7 @@
+                     "#endif"
+                 ]
+             },
+-            "libs": "-ldrm",
+-            "use": "egl"
++            "use": "drm egl"
+         },
+         "vulkan-server-buffer": {
+             "label": "Vulkan Buffer Sharing",
+@@ -168,7 +167,8 @@
+                     "exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;",
+                     "return 0;"
+                 ]
+-            }
++            },
++            "use": "wayland-client"
+         },
+         "egl_1_5-wayland": {
+             "label": "EGL 1.5 with Wayland Platform",
+@@ -183,7 +183,7 @@
+                     "eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_EXT, (struct wl_display *)(nullptr), nullptr);"
+                 ]
+             },
+-            "use": "egl"
++            "use": "egl wayland-client"
+         }
+     },
+ 
+--- a/src/compositor/configure.json
++++ b/src/compositor/configure.json
+@@ -7,6 +7,31 @@
+     "testDir": "../../config.tests",
+ 
+     "libraries": {
++        "wayland-client": {
++            "label": "Wayland client library",
++            "headers": "wayland-version.h",
++            "test": {
++                "main": [
++                    "#if WAYLAND_VERSION_MAJOR < 1",
++                    "# error Wayland 1.8.0 or higher required",
++                    "#endif",
++                    "#if WAYLAND_VERSION_MAJOR == 1",
++                    "# if WAYLAND_VERSION_MINOR < 8",
++                    "#  error Wayland 1.8.0 or higher required",
++                    "# endif",
++                    "# if WAYLAND_VERSION_MINOR == 8",
++                    "#  if WAYLAND_VERSION_MICRO < 0",
++                    "#   error Wayland 1.8.0 or higher required",
++                    "#  endif",
++                    "# endif",
++                    "#endif"
++                 ]
++            },
++            "sources": [
++                { "type": "pkgConfig", "args": "wayland-client" },
++                "-lwayland-client"
++            ]
++        },
+         "wayland-server": {
+             "label": "wayland-server",
+             "headers": "wayland-version.h",
+@@ -151,8 +176,7 @@
+                     "#endif"
+                 ]
+             },
+-            "libs": "-ldrm",
+-            "use": "egl"
++            "use": "drm egl"
+         },
+         "dmabuf-client-buffer": {
+             "label": "Linux Client dma-buf Buffer Sharing",
+@@ -176,8 +200,7 @@
+                     "return 0;"
+                 ]
+             },
+-            "libs": "-ldrm",
+-            "use": "egl"
++            "use": "drm egl"
+         },
+         "vulkan-server-buffer": {
+             "label": "Vulkan Buffer Sharing",
+@@ -195,7 +218,8 @@
+                     "exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;",
+                     "return 0;"
+                 ]
+-            }
++            },
++            "use": "wayland-client"
+         }
+     },
+ 
diff --git a/debian/patches/0035-client-update-button-state-and-etc-in-pointer_leave.patch b/debian/patches/0035-client-update-button-state-and-etc-in-pointer_leave.patch
new file mode 100644
index 0000000..402a86d
--- /dev/null
+++ b/debian/patches/0035-client-update-button-state-and-etc-in-pointer_leave.patch
@@ -0,0 +1,45 @@
+From 169052d99391eef62c181c8b5b107280688045d1 Mon Sep 17 00:00:00 2001
+From: Liang Qi <liang.qi at qt.io>
+Date: Wed, 9 Mar 2022 10:47:42 +0100
+Subject: [PATCH] client: update button state and etc in pointer_leave()
+
+The cleanup work needs to be done even the surface is null, for
+example, a window was closed in mouse press handler, then will not
+get a mouse release.
+
+Fixes: QTBUG-100942
+Pick-to: 5.15 6.2 6.3
+Change-Id: I637a6744909ddbe62bdeba6b21494e5a6ae7fa9f
+Reviewed-by: Tang Haixiang <tanghaixiang at uniontech.com>
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+(cherry picked from commit 409d1080f25b653b3ff3f57c9776c5c390912206)
+---
+ src/client/qwaylandinputdevice.cpp | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/src/client/qwaylandinputdevice.cpp
++++ b/src/client/qwaylandinputdevice.cpp
+@@ -685,6 +685,11 @@ public:
+ 
+ void QWaylandInputDevice::Pointer::pointer_leave(uint32_t time, struct wl_surface *surface)
+ {
++    invalidateFocus();
++    mButtons = Qt::NoButton;
++
++    mParent->mTime = time;
++
+     // The event may arrive after destroying the window, indicated by
+     // a null surface.
+     if (!surface)
+@@ -696,11 +701,6 @@ void QWaylandInputDevice::Pointer::pointer_leave(uint32_t time, struct wl_surfac
+ 
+     if (!QWaylandWindow::mouseGrab())
+         setFrameEvent(new LeaveEvent(window, mSurfacePos, mGlobalPos));
+-
+-    invalidateFocus();
+-    mButtons = Qt::NoButton;
+-
+-    mParent->mTime = time;
+ }
+ 
+ class MotionEvent : public QWaylandPointerEvent
diff --git a/debian/patches/0036-Revert-Client-Remove-mWaitingForUpdateDelivery.patch b/debian/patches/0036-Revert-Client-Remove-mWaitingForUpdateDelivery.patch
new file mode 100644
index 0000000..fbcc03a
--- /dev/null
+++ b/debian/patches/0036-Revert-Client-Remove-mWaitingForUpdateDelivery.patch
@@ -0,0 +1,52 @@
+From 36756f5d1b8891465bddd31e990c81e149dce0f1 Mon Sep 17 00:00:00 2001
+From: Paul Olav Tvete <paul.tvete at qt.io>
+Date: Tue, 15 Mar 2022 15:59:15 +0100
+Subject: [PATCH] Revert "Client: Remove mWaitingForUpdateDelivery"
+
+The reverted commit introduces a severe performance regression
+when a client window is resized while a QtQuick renderthread
+animation is running.
+
+This reverts commit feb1a5c207c13d0bf87c0d8ad039279dbf8cee9e.
+
+Fixes: QTBUG-101726
+Change-Id: Ib5b52ce06efec8c86fada1623c2af82099e57fc6
+Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt at qt.io>
+---
+ src/client/qwaylandwindow.cpp | 12 +++++++++---
+ src/client/qwaylandwindow_p.h |  1 +
+ 2 files changed, 10 insertions(+), 3 deletions(-)
+
+--- a/src/client/qwaylandwindow.cpp
++++ b/src/client/qwaylandwindow.cpp
+@@ -655,11 +655,17 @@ void QWaylandWindow::handleFrameCallback()
+             sendExposeEvent(QRect(QPoint(), geometry().size()));
+         if (wasExposed && hasPendingUpdateRequest())
+             deliverUpdateRequest();
++
++        mWaitingForUpdateDelivery = false;
+     };
+ 
+-    // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
+-    // in the single-threaded case.
+-    QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection);
++    if (!mWaitingForUpdateDelivery) {
++        // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
++        // in the single-threaded case.
++        mWaitingForUpdateDelivery = true;
++        QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection);
++    }
++
+ 
+     mFrameSyncWait.notify_all();
+ }
+--- a/src/client/qwaylandwindow_p.h
++++ b/src/client/qwaylandwindow_p.h
+@@ -228,6 +228,7 @@ protected:
+     WId mWindowId;
+     bool mWaitingForFrameCallback = false;
+     bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
++    bool mWaitingForUpdateDelivery = false;
+     int mFrameCallbackCheckIntervalTimerId = -1;
+     QElapsedTimer mFrameCallbackElapsedTimer;
+     struct ::wl_callback *mFrameCallback = nullptr;
diff --git a/debian/patches/0037-Fix-race-condition-on-mWaitingForUpdateDelivery.patch b/debian/patches/0037-Fix-race-condition-on-mWaitingForUpdateDelivery.patch
new file mode 100644
index 0000000..c9f9abf
--- /dev/null
+++ b/debian/patches/0037-Fix-race-condition-on-mWaitingForUpdateDelivery.patch
@@ -0,0 +1,52 @@
+From a83e65ddc9a965b25e435d136849a50f0b99c4ae Mon Sep 17 00:00:00 2001
+From: Paul Olav Tvete <paul.tvete at qt.io>
+Date: Tue, 15 Mar 2022 16:53:04 +0100
+Subject: [PATCH] Fix race condition on mWaitingForUpdateDelivery
+
+Change-Id: I0e91bda73722468b9339fc434fe04420b5e7d3da
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+---
+ src/client/qwaylandwindow.cpp | 7 ++-----
+ src/client/qwaylandwindow_p.h | 2 +-
+ 2 files changed, 3 insertions(+), 6 deletions(-)
+
+--- a/src/client/qwaylandwindow.cpp
++++ b/src/client/qwaylandwindow.cpp
+@@ -649,24 +649,21 @@ void QWaylandWindow::handleFrameCallback()
+ 
+     // The rest can wait until we can run it on the correct thread
+     auto doHandleExpose = [this]() {
++        mWaitingForUpdateDelivery.storeRelease(false);
+         bool wasExposed = isExposed();
+         mFrameCallbackTimedOut = false;
+         if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
+             sendExposeEvent(QRect(QPoint(), geometry().size()));
+         if (wasExposed && hasPendingUpdateRequest())
+             deliverUpdateRequest();
+-
+-        mWaitingForUpdateDelivery = false;
+     };
+ 
+-    if (!mWaitingForUpdateDelivery) {
++    if (mWaitingForUpdateDelivery.testAndSetAcquire(false, true)) {
+         // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
+         // in the single-threaded case.
+-        mWaitingForUpdateDelivery = true;
+         QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection);
+     }
+ 
+-
+     mFrameSyncWait.notify_all();
+ }
+ 
+--- a/src/client/qwaylandwindow_p.h
++++ b/src/client/qwaylandwindow_p.h
+@@ -228,7 +228,7 @@ protected:
+     WId mWindowId;
+     bool mWaitingForFrameCallback = false;
+     bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
+-    bool mWaitingForUpdateDelivery = false;
++    QAtomicInt mWaitingForUpdateDelivery = false;
+     int mFrameCallbackCheckIntervalTimerId = -1;
+     QElapsedTimer mFrameCallbackElapsedTimer;
+     struct ::wl_callback *mFrameCallback = nullptr;
diff --git a/debian/patches/0038-use-poll-2-when-reading-from-clipboard.patch b/debian/patches/0038-use-poll-2-when-reading-from-clipboard.patch
new file mode 100644
index 0000000..1f75315
--- /dev/null
+++ b/debian/patches/0038-use-poll-2-when-reading-from-clipboard.patch
@@ -0,0 +1,43 @@
+From 36659e6130ed3fc2b3f0c91423408ef5ecb7b991 Mon Sep 17 00:00:00 2001
+From: Kenneth Topp <ken at bllue.org>
+Date: Mon, 4 Apr 2022 09:36:21 -0400
+Subject: [PATCH] use poll(2) when reading from clipboard
+
+change clipboard read away from select(2) call which can fail when
+an application has large number of open files
+
+Change-Id: I6d98c6bb11cdd5b6171b01cfeb0044dd41cf9fb5
+Reviewed-by: Thiago Macieira <thiago.macieira at intel.com>
+(cherry picked from commit 829a9f62a96721c142f53e12a8812e8231b20317)
+---
+ src/client/qwaylanddataoffer.cpp | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+--- a/src/client/qwaylanddataoffer.cpp
++++ b/src/client/qwaylanddataoffer.cpp
+@@ -188,17 +188,18 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::T
+ 
+ int QWaylandMimeData::readData(int fd, QByteArray &data) const
+ {
+-    fd_set readset;
+-    FD_ZERO(&readset);
+-    FD_SET(fd, &readset);
+-    struct timeval timeout;
++    struct pollfd readset;
++    readset.fd = fd;
++    readset.events = POLLIN;
++    struct timespec timeout;
+     timeout.tv_sec = 1;
+-    timeout.tv_usec = 0;
++    timeout.tv_nsec = 0;
++
+ 
+     Q_FOREVER {
+-        int ready = select(FD_SETSIZE, &readset, nullptr, nullptr, &timeout);
++        int ready = qt_safe_poll(&readset, 1, &timeout);
+         if (ready < 0) {
+-            qWarning() << "QWaylandDataOffer: select() failed";
++            qWarning() << "QWaylandDataOffer: qt_safe_poll() failed";
+             return -1;
+         } else if (ready == 0) {
+             qWarning("QWaylandDataOffer: timeout reading from pipe");
diff --git a/debian/patches/series b/debian/patches/series
index b3c9115..5d69456 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,40 @@
+0001-Client-Announce-an-output-after-receiving-more-compl.patch
+0002-Fix-issue-with-repeated-window-size-changes.patch
+0003-Include-locale.h-for-setlocale-LC_CTYPE.patch
+0004-Client-Connect-drags-being-accepted-to-updating-the-.patch
+0005-Client-Disconnect-registry-listener-on-destruction.patch
+0006-Client-Set-XdgShell-size-hints-before-the-first-comm.patch
+0007-Fix-build.patch
+0008-Fix-remove-listener.patch
+0009-Hook-up-queryKeyboardModifers.patch
+0010-Do-not-update-the-mask-if-we-do-not-have-a-surface.patch
+0011-Correctly-detect-if-image-format-is-supported-by-QIm.patch
+0012-Wayland-client-Fix-crash-when-windows-are-shown-hidd.patch
+0013-Client-Don-t-always-recreate-frame-callbacks.patch
+0014-Client-Always-destroy-frame-callback-in-the-actual-c.patch
+0015-Fix-the-logic-for-decoding-modifiers-map-in-Wayland-.patch
+0016-Wayland-client-use-wl_keyboard-to-determine-active-s.patch
+0017-Client-do-not-empty-clipboard-when-a-new-popup-windo.patch
+0018-Set-preedit-cursor-when-cursor-equals-to-0.patch
+0019-Client-Implement-DataDeviceV3.patch
+0020-Client-Delay-deletion-of-QDrag-object-until-after-we.patch
+0021-Client-Avoid-processing-of-events-when-showing-windo.patch
+0022-Handle-registry_global-out-of-constructor.patch
+0023-Connect-flushRequest-after-forceRoundTrip.patch
+0024-Move-the-wayland-socket-polling-to-a-separate-event-.patch
+0025-Check-pointer-for-null-before-use-in-ASSERT.patch
+0026-Do-not-create-decorations-when-the-shellSurface-is-n.patch
+0027-Use-wl_surface.damage_buffer-on-the-client-side.patch
+0028-Fix-crash-if-no-input-method-module-could-be-loaded.patch
+0029-Client-Remove-mWaitingForUpdateDelivery.patch
+0030-Cursor-position-0-should-still-show-the-cursor.patch
+0031-Update-the-preedit-styling-mapping.patch
+0032-client-Simplify-round-trip-behavior.patch
+0033-Client-Fix-opaque-region-setter.patch
+0034-Use-proper-dependencies-in-compile-tests.patch
+0035-client-update-button-state-and-etc-in-pointer_leave.patch
+0036-Revert-Client-Remove-mWaitingForUpdateDelivery.patch
+0037-Fix-race-condition-on-mWaitingForUpdateDelivery.patch
+0038-use-poll-2-when-reading-from-clipboard.patch
 skip_animated_cursor_test.diff
 gcc_11.diff



More information about the Neon-commits mailing list