diff --git a/0008-Fix-memory-leak-in-QWaylandGLContext.patch b/0008-Fix-memory-leak-in-QWaylandGLContext.patch new file mode 100644 index 0000000..47e9c91 --- /dev/null +++ b/0008-Fix-memory-leak-in-QWaylandGLContext.patch @@ -0,0 +1,38 @@ +From 9df11e79b46c77d8c83f765b2a8e85b639fd55a2 Mon Sep 17 00:00:00 2001 +From: Eskil Abrahamsen Blomfeldt +Date: Tue, 5 Jan 2021 09:08:50 +0100 +Subject: [PATCH 08/18] Fix memory leak in QWaylandGLContext + +We were leaking an EGL context with every GL context created, +which lead to rapid OOM errors in stress tests. + +[ChangeLog][Qt Wayland Client] Fixed a memory leak when creating +QOpenGLContexts on Wayland and using the wayland-egl backend. + +Fixes: QTBUG-85608 +Pick-to: 5.15 +Pick-to: 6.0 +Change-Id: I8426b5df36ec7ab9e66ce15f9e02edad3aca60b9 +Reviewed-by: David Edmundson +--- + .../client/wayland-egl/qwaylandglcontext.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +index 681f82f4..befadedc 100644 +--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp ++++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +@@ -406,7 +406,9 @@ void QWaylandGLContext::updateGLFormat() + QWaylandGLContext::~QWaylandGLContext() + { + delete m_blitter; +- eglDestroyContext(m_eglDisplay, m_context); ++ m_blitter = nullptr; ++ if (m_decorationsContext != EGL_NO_CONTEXT) ++ eglDestroyContext(eglDisplay(), m_decorationsContext); + } + + bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface) +-- +2.25.1 + diff --git a/0009-Client-Send-set_window_geometry-only-once-configured.patch b/0009-Client-Send-set_window_geometry-only-once-configured.patch new file mode 100644 index 0000000..05316ce --- /dev/null +++ b/0009-Client-Send-set_window_geometry-only-once-configured.patch @@ -0,0 +1,41 @@ +From 7db4f83c39d2a0c709bc0b9c0de3946d3b4ebfd5 Mon Sep 17 00:00:00 2001 +From: David Edmundson +Date: Mon, 16 Nov 2020 14:57:36 +0000 +Subject: [PATCH 09/18] Client: Send set_window_geometry only once configured + +The geometry only makes sense when a buffer exists, our currently send +value is somewhat meaningless, but till now harmless. + +A specification clarification implies that it is an error if the +calculated effective window geometry is null, rather than just checking +the sent value. This is the case if set_window_geometry is sent before a +buffer is attached. + +On our first configure call we enter resizeFromApplyConfigure which will +hit this path and send the initial state. + +Pick-to: 5.15 +Pick-to: 6.1 +Pick-to: 6.0 +Change-Id: Ib57ebe8b64210eae86e79dfdd6b5cb8a986b020b +Reviewed-by: Eskil Abrahamsen Blomfeldt +--- + src/client/qwaylandwindow.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index 9b343702..e875af3a 100644 +--- a/src/client/qwaylandwindow.cpp ++++ b/src/client/qwaylandwindow.cpp +@@ -365,7 +365,7 @@ void QWaylandWindow::setGeometry(const QRect &rect) + if (isExposed() && !mInResizeFromApplyConfigure && exposeGeometry != mLastExposeGeometry) + sendExposeEvent(exposeGeometry); + +- if (mShellSurface) ++ if (mShellSurface && isExposed()) + mShellSurface->setWindowGeometry(windowContentGeometry()); + + if (isOpaque() && mMask.isEmpty()) +-- +2.25.1 + diff --git a/0010-Translate-opaque-area-with-frame-margins.patch b/0010-Translate-opaque-area-with-frame-margins.patch new file mode 100644 index 0000000..6092779 --- /dev/null +++ b/0010-Translate-opaque-area-with-frame-margins.patch @@ -0,0 +1,40 @@ +From a3e3ac1c86a956b25b1dc24f14518b6e6c96bcfc Mon Sep 17 00:00:00 2001 +From: Jan Grulich +Date: Wed, 10 Feb 2021 17:11:27 +0100 +Subject: [PATCH 10/18] Translate opaque area with frame margins + +The opaque area doesn't take window decorations into account, which may +result into possible graphical artefacts. + +Pick-to: 5.15 6.0 6.1 +Change-Id: I1606e8256e7e204dad927931eb1221b576e227fd +Reviewed-by: David Edmundson +--- + src/client/qwaylandwindow.cpp | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index e875af3a..2af39977 100644 +--- a/src/client/qwaylandwindow.cpp ++++ b/src/client/qwaylandwindow.cpp +@@ -1234,12 +1234,14 @@ bool QWaylandWindow::isOpaque() const + + void QWaylandWindow::setOpaqueArea(const QRegion &opaqueArea) + { +- if (opaqueArea == mOpaqueArea || !mSurface) ++ const QRegion translatedOpaqueArea = opaqueArea.translated(frameMargins().left(), frameMargins().top()); ++ ++ if (translatedOpaqueArea == mOpaqueArea || !mSurface) + return; + +- mOpaqueArea = opaqueArea; ++ mOpaqueArea = translatedOpaqueArea; + +- struct ::wl_region *region = mDisplay->createRegion(opaqueArea); ++ struct ::wl_region *region = mDisplay->createRegion(translatedOpaqueArea); + mSurface->set_opaque_region(region); + wl_region_destroy(region); + } +-- +2.25.1 + diff --git a/0011-Client-Send-exposeEvent-to-parent-on-subsurface-posi.patch b/0011-Client-Send-exposeEvent-to-parent-on-subsurface-posi.patch new file mode 100644 index 0000000..c590a31 --- /dev/null +++ b/0011-Client-Send-exposeEvent-to-parent-on-subsurface-posi.patch @@ -0,0 +1,97 @@ +From 2073ff99e62d4f99ed3f1f45559c5b68a61c5f66 Mon Sep 17 00:00:00 2001 +From: David Edmundson +Date: Mon, 14 Sep 2020 17:08:39 +0100 +Subject: [PATCH 11/18] Client: Send exposeEvent to parent on subsurface + position changes + +When a subsurface is moved, we need the parent window to commit to apply +that move. Ideally we want this in sync with any potential rendering on +the parent window. + +Currently the code calls requestUpdate() which acts more like a frame +callback; it will only do something if the main QWindow considers itself +dirty. + +We want to force a repaint, which is semantically more similar to an +ExposeEvent. + +Fixes: QTBUG-86177 +Pick-to: 5.15 +Change-Id: I30bdfa357beee860ce2b00a256eaea6d040dd55c +Reviewed-by: Eskil Abrahamsen Blomfeldt +--- + src/client/qwaylandwindow.cpp | 7 ++++- + tests/auto/client/surface/tst_surface.cpp | 33 +++++++++++++++++++---- + 2 files changed, 34 insertions(+), 6 deletions(-) + +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index 2af39977..e96d8fe9 100644 +--- a/src/client/qwaylandwindow.cpp ++++ b/src/client/qwaylandwindow.cpp +@@ -342,7 +342,12 @@ void QWaylandWindow::setGeometry_helper(const QRect &rect) + if (mSubSurfaceWindow) { + QMargins m = QPlatformWindow::parent()->frameMargins(); + mSubSurfaceWindow->set_position(rect.x() + m.left(), rect.y() + m.top()); +- mSubSurfaceWindow->parent()->window()->requestUpdate(); ++ ++ QWaylandWindow *parentWindow = mSubSurfaceWindow->parent(); ++ if (parentWindow && parentWindow->isExposed()) { ++ QRect parentExposeGeometry(QPoint(), parentWindow->geometry().size()); ++ parentWindow->sendExposeEvent(parentExposeGeometry); ++ } + } + } + +diff --git a/tests/auto/client/surface/tst_surface.cpp b/tests/auto/client/surface/tst_surface.cpp +index b8a65f15..95e4e609 100644 +--- a/tests/auto/client/surface/tst_surface.cpp ++++ b/tests/auto/client/surface/tst_surface.cpp +@@ -167,17 +167,40 @@ void tst_surface::negotiateShmFormat() + void tst_surface::createSubsurface() + { + QRasterWindow window; +- window.resize(64, 64); +- window.show(); +- QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); +- exec([=] { xdgToplevel()->sendCompleteConfigure(); }); +- QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial); ++ window.setObjectName("main"); ++ window.resize(200, 200); + + QRasterWindow subWindow; ++ subWindow.setObjectName("subwindow"); + subWindow.setParent(&window); + subWindow.resize(64, 64); ++ ++ window.show(); + subWindow.show(); ++ + QCOMPOSITOR_TRY_VERIFY(subSurface()); ++ QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); ++ exec([=] { xdgToplevel()->sendCompleteConfigure(); }); ++ QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial); ++ ++ const Surface *mainSurface = exec([=] {return surface(0);}); ++ const Surface *childSurface = exec([=] {return surface(1);}); ++ QSignalSpy mainSurfaceCommitSpy(mainSurface, &Surface::commit); ++ QSignalSpy childSurfaceCommitSpy(childSurface, &Surface::commit); ++ ++ // Move subsurface. The parent should redraw and commit ++ subWindow.setGeometry(100, 100, 64, 64); ++ // the toplevel should commit to indicate the subsurface moved ++ QCOMPOSITOR_TRY_COMPARE(mainSurfaceCommitSpy.count(), 1); ++ mainSurfaceCommitSpy.clear(); ++ childSurfaceCommitSpy.clear(); ++ ++ // Move and resize the subSurface. The parent should redraw and commit ++ // The child should also redraw ++ subWindow.setGeometry(50, 50, 80, 80); ++ QCOMPOSITOR_TRY_COMPARE(mainSurfaceCommitSpy.count(), 1); ++ QCOMPOSITOR_TRY_COMPARE(childSurfaceCommitSpy.count(), 1); ++ + } + + // Used to cause a crash in libwayland (QTBUG-79674) +-- +2.25.1 + diff --git a/0012-Get-correct-decoration-margins-region.patch b/0012-Get-correct-decoration-margins-region.patch new file mode 100644 index 0000000..a05ee73 --- /dev/null +++ b/0012-Get-correct-decoration-margins-region.patch @@ -0,0 +1,39 @@ +From 6810b0f66a34056bfe0da7299d7a768e700e58f5 Mon Sep 17 00:00:00 2001 +From: Jan Grulich +Date: Thu, 11 Feb 2021 15:12:32 +0100 +Subject: [PATCH 12/18] Get correct decoration margins region + +Size we use to calculate margins region already contains size including +margins. This resulted into bigger region and not properly damaging +region we need to update. + +Pick-to: 5.15 6.0 6.1 +Change-Id: Id1b7f4cd2a7b894b82db09c5af2b2d1f1f43fa2a +Reviewed-by: David Edmundson +--- + src/client/qwaylandabstractdecoration.cpp | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/client/qwaylandabstractdecoration.cpp b/src/client/qwaylandabstractdecoration.cpp +index 87dd6cea..b6ee43c9 100644 +--- a/src/client/qwaylandabstractdecoration.cpp ++++ b/src/client/qwaylandabstractdecoration.cpp +@@ -108,11 +108,11 @@ void QWaylandAbstractDecoration::setWaylandWindow(QWaylandWindow *window) + static QRegion marginsRegion(const QSize &size, const QMargins &margins) + { + QRegion r; +- const int widthWithMargins = margins.left() + size.width() + margins.right(); +- r += QRect(0, 0, widthWithMargins, margins.top()); // top +- r += QRect(0, size.height()+margins.top(), widthWithMargins, margins.bottom()); //bottom ++ ++ r += QRect(0, 0, size.width(), margins.top()); // top ++ r += QRect(0, size.height()-margins.bottom(), size.width(), margins.bottom()); //bottom + r += QRect(0, margins.top(), margins.left(), size.height()); //left +- r += QRect(size.width()+margins.left(), margins.top(), margins.right(), size.height()); // right ++ r += QRect(size.width()-margins.left(), margins.top(), margins.right(), size.height()-margins.top()); // right + return r; + } + +-- +2.25.1 + diff --git a/0013-xdgshell-Tell-the-compositor-the-screen-we-re-expect.patch b/0013-xdgshell-Tell-the-compositor-the-screen-we-re-expect.patch new file mode 100644 index 0000000..2a2bfb4 --- /dev/null +++ b/0013-xdgshell-Tell-the-compositor-the-screen-we-re-expect.patch @@ -0,0 +1,41 @@ +From cea69b8adec1e61adc1fa04cbf46b77c0d72c75e Mon Sep 17 00:00:00 2001 +From: Aleix Pol +Date: Mon, 23 Nov 2020 20:07:02 +0100 +Subject: [PATCH 13/18] xdgshell: Tell the compositor the screen we're + expecting to fill + +The xdgshell protocol allows us to tell the output to fill. This makes +it possible to use fullscreen confidently on systems with multiple +screens knowing that our windows won't be overlapping one another by +calling setScreen accordingly before QWindow::showFullScreen. + +Pick-to: 6.1 6.0 5.15 +Change-Id: I757854c3698639472f3a25ef298ddcca031e1ed5 +Reviewed-by: David Edmundson +--- + .../shellintegration/xdg-shell/qwaylandxdgshell.cpp | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +index 1c762944..3a1569f7 100644 +--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp ++++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +@@ -178,9 +178,12 @@ void QWaylandXdgSurface::Toplevel::requestWindowStates(Qt::WindowStates states) + } + + if (changedStates & Qt::WindowFullScreen) { +- if (states & Qt::WindowFullScreen) +- set_fullscreen(nullptr); +- else ++ if (states & Qt::WindowFullScreen) { ++ auto screen = m_xdgSurface->window()->waylandScreen(); ++ if (screen) { ++ set_fullscreen(screen->output()); ++ } ++ } else + unset_fullscreen(); + } + +-- +2.25.1 + diff --git a/0014-Fix-compilation.patch b/0014-Fix-compilation.patch new file mode 100644 index 0000000..65e3eb0 --- /dev/null +++ b/0014-Fix-compilation.patch @@ -0,0 +1,26 @@ +From 2f84a874da064069461284db1da36dc818949ec1 Mon Sep 17 00:00:00 2001 +From: Albert Astals Cid +Date: Sat, 10 Apr 2021 12:10:16 +0200 +Subject: [PATCH 14/18] Fix compilation + +9df11e79b46c77d8c83f765b2a8e85b639fd55a2 can't be backported 1:1 +--- + .../client/wayland-egl/qwaylandglcontext.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +index befadedc..95d1049c 100644 +--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp ++++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +@@ -408,7 +408,7 @@ QWaylandGLContext::~QWaylandGLContext() + delete m_blitter; + m_blitter = nullptr; + if (m_decorationsContext != EGL_NO_CONTEXT) +- eglDestroyContext(eglDisplay(), m_decorationsContext); ++ eglDestroyContext(m_eglDisplay, m_decorationsContext); + } + + bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface) +-- +2.25.1 + diff --git a/0015-client-Allow-QWaylandInputContext-to-accept-composed.patch b/0015-client-Allow-QWaylandInputContext-to-accept-composed.patch new file mode 100644 index 0000000..ab82ba2 --- /dev/null +++ b/0015-client-Allow-QWaylandInputContext-to-accept-composed.patch @@ -0,0 +1,257 @@ +From 91c48320633e493b4cd519e5d73b836a878b2b77 Mon Sep 17 00:00:00 2001 +From: Aleix Pol +Date: Wed, 10 Mar 2021 01:09:13 +0100 +Subject: [PATCH 15/18] client: Allow QWaylandInputContext to accept composed + key combinations + +At the moment, we are forcing user to choose to either compose or use +the text-input channel. This patch brings some of the QComposeInputContext +functionality in order to let applications understand dead key +combinations like they are supposed to. + +Having it in QWaylandInputContext rather than in QWaylandInputDevice +should solve the problems 3aedd01271dc4f4a13103d632df224971ab2b6df had +with 57c4af2b18c0fb1d266b245a107fa6cb876b9d9e, because we are doing it +in the input context rather than before. This way, if the user is +overriding the input method (e.g. by setting QT_IM_MODULE), all the key +strokes will still be properly forwarded to the module to use. + +This in turn allows us to solve https://bugs.kde.org/show_bug.cgi?id=411729 +and https://bugs.kde.org/show_bug.cgi?id=405388 since we don't need to +choose anymore between physical and virual keyboards anymore. + +Pick-to: 5.15 +Change-Id: I8601f5d7ae21edf4b3a1191fa75877286e505588 +Reviewed-by: David Edmundson +--- + src/client/qwaylanddisplay_p.h | 3 - + src/client/qwaylandinputcontext.cpp | 95 ++++++++++++++++++++++++++++- + src/client/qwaylandinputcontext_p.h | 21 +++++++ + src/client/qwaylandinputdevice.cpp | 2 +- + src/client/qwaylandintegration.cpp | 8 +-- + 5 files changed, 119 insertions(+), 10 deletions(-) + +diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h +index 188e9131..3b092bc8 100644 +--- a/src/client/qwaylanddisplay_p.h ++++ b/src/client/qwaylanddisplay_p.h +@@ -175,8 +175,6 @@ public: + QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); } + QWaylandXdgOutputManagerV1 *xdgOutputManager() const { return mXdgOutputManager.data(); } + +- bool usingInputContextFromCompositor() const { return mUsingInputContextFromCompositor; } +- + struct RegistryGlobal { + uint32_t id; + QString interface; +@@ -282,7 +280,6 @@ private: + QReadWriteLock m_frameQueueLock; + + bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull(); +- bool mUsingInputContextFromCompositor = false; + + void registry_global(uint32_t id, const QString &interface, uint32_t version) override; + void registry_global_remove(uint32_t id) override; +diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp +index e9afe05e..ef5aa375 100644 +--- a/src/client/qwaylandinputcontext.cpp ++++ b/src/client/qwaylandinputcontext.cpp +@@ -406,6 +406,8 @@ bool QWaylandInputContext::isValid() const + void QWaylandInputContext::reset() + { + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; ++ if (m_composeState) ++ xkb_compose_state_reset(m_composeState); + + QPlatformInputContext::reset(); + +@@ -526,9 +528,14 @@ Qt::LayoutDirection QWaylandInputContext::inputDirection() const + return textInput()->inputDirection(); + } + +-void QWaylandInputContext::setFocusObject(QObject *) ++void QWaylandInputContext::setFocusObject(QObject *object) + { + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; ++#if QT_CONFIG(xkbcommon) ++ m_focusObject = object; ++#else ++ Q_UNUSED(object); ++#endif + + if (!textInput()) + return; +@@ -561,6 +568,92 @@ QWaylandTextInput *QWaylandInputContext::textInput() const + return mDisplay->defaultInputDevice()->textInput(); + } + ++#if QT_CONFIG(xkbcommon) ++ ++void QWaylandInputContext::ensureInitialized() ++{ ++ if (m_initialized) ++ return; ++ ++ if (!m_XkbContext) { ++ qCWarning(qLcQpaInputMethods) << "error: xkb context has not been set on" << metaObject()->className(); ++ return; ++ } ++ ++ m_initialized = true; ++ const char *locale = setlocale(LC_CTYPE, ""); ++ if (!locale) ++ locale = setlocale(LC_CTYPE, nullptr); ++ qCDebug(qLcQpaInputMethods) << "detected locale (LC_CTYPE):" << locale; ++ ++ m_composeTable = xkb_compose_table_new_from_locale(m_XkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); ++ if (m_composeTable) ++ m_composeState = xkb_compose_state_new(m_composeTable, XKB_COMPOSE_STATE_NO_FLAGS); ++ ++ if (!m_composeTable) { ++ qCWarning(qLcQpaInputMethods, "failed to create compose table"); ++ return; ++ } ++ if (!m_composeState) { ++ qCWarning(qLcQpaInputMethods, "failed to create compose state"); ++ return; ++ } ++} ++ ++bool QWaylandInputContext::filterEvent(const QEvent *event) ++{ ++ auto keyEvent = static_cast(event); ++ if (keyEvent->type() != QEvent::KeyPress) ++ return false; ++ ++ if (!inputMethodAccepted()) ++ return false; ++ ++ // lazy initialization - we don't want to do this on an app startup ++ ensureInitialized(); ++ ++ if (!m_composeTable || !m_composeState) ++ return false; ++ ++ xkb_compose_state_feed(m_composeState, keyEvent->nativeVirtualKey()); ++ ++ switch (xkb_compose_state_get_status(m_composeState)) { ++ case XKB_COMPOSE_COMPOSING: ++ return true; ++ case XKB_COMPOSE_CANCELLED: ++ reset(); ++ return false; ++ case XKB_COMPOSE_COMPOSED: ++ { ++ const int size = xkb_compose_state_get_utf8(m_composeState, nullptr, 0); ++ QVarLengthArray buffer(size + 1); ++ xkb_compose_state_get_utf8(m_composeState, buffer.data(), buffer.size()); ++ QString composedText = QString::fromUtf8(buffer.constData()); ++ ++ QInputMethodEvent event; ++ event.setCommitString(composedText); ++ ++ if (!m_focusObject && qApp) ++ m_focusObject = qApp->focusObject(); ++ ++ if (m_focusObject) ++ QCoreApplication::sendEvent(m_focusObject, &event); ++ else ++ qCWarning(qLcQpaInputMethods, "no focus object"); ++ ++ reset(); ++ return true; ++ } ++ case XKB_COMPOSE_NOTHING: ++ return false; ++ default: ++ Q_UNREACHABLE(); ++ return false; ++ } ++} ++ ++#endif ++ + } + + QT_END_NAMESPACE +diff --git a/src/client/qwaylandinputcontext_p.h b/src/client/qwaylandinputcontext_p.h +index 10132dfe..50db6344 100644 +--- a/src/client/qwaylandinputcontext_p.h ++++ b/src/client/qwaylandinputcontext_p.h +@@ -61,6 +61,10 @@ + + #include + #include ++#include ++#if QT_CONFIG(xkbcommon) ++#include ++#endif + + struct wl_callback; + struct wl_callback_listener; +@@ -155,11 +159,28 @@ public: + + void setFocusObject(QObject *object) override; + ++#if QT_CONFIG(xkbcommon) ++ bool filterEvent(const QEvent *event) override; ++ ++ // This invokable is called from QXkbCommon::setXkbContext(). ++ Q_INVOKABLE void setXkbContext(struct xkb_context *context) { m_XkbContext = context; } ++#endif ++ + private: + QWaylandTextInput *textInput() const; + + QWaylandDisplay *mDisplay = nullptr; + QPointer mCurrentWindow; ++ ++#if QT_CONFIG(xkbcommon) ++ void ensureInitialized(); ++ ++ bool m_initialized = false; ++ QObject *m_focusObject = nullptr; ++ xkb_compose_table *m_composeTable = nullptr; ++ xkb_compose_state *m_composeState = nullptr; ++ struct xkb_context *m_XkbContext = nullptr; ++#endif + }; + + } +diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp +index ed4a0eb4..ae045f4f 100644 +--- a/src/client/qwaylandinputdevice.cpp ++++ b/src/client/qwaylandinputdevice.cpp +@@ -1201,7 +1201,7 @@ void QWaylandInputDevice::Keyboard::handleKey(ulong timestamp, QEvent::Type type + QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); + bool filtered = false; + +- if (inputContext && !mParent->mQDisplay->usingInputContextFromCompositor()) { ++ if (inputContext) { + QKeyEvent event(type, key, modifiers, nativeScanCode, nativeVirtualKey, + nativeModifiers, text, autorepeat, count); + event.setTimestamp(timestamp); +diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp +index 7ad8e05e..c53ccb78 100644 +--- a/src/client/qwaylandintegration.cpp ++++ b/src/client/qwaylandintegration.cpp +@@ -474,13 +474,11 @@ void QWaylandIntegration::reconfigureInputContext() + + #if QT_CONFIG(xkbcommon) + QXkbCommon::setXkbContext(mInputContext.data(), mDisplay->xkbContext()); ++ if (QWaylandInputContext* waylandInput = qobject_cast(mInputContext.get())) { ++ waylandInput->setXkbContext(mDisplay->xkbContext()); ++ } + #endif + +- // Even if compositor-side input context handling has been requested, we fallback to +- // client-side handling if compositor does not provide the text-input extension. This +- // is why we need to check here which input context actually is being used. +- mDisplay->mUsingInputContextFromCompositor = qobject_cast(mInputContext.data()); +- + qCDebug(lcQpaWayland) << "using input method:" << inputContext()->metaObject()->className(); + } + +-- +2.25.1 + diff --git a/0016-Client-Announce-an-output-after-receiving-more-compl.patch b/0016-Client-Announce-an-output-after-receiving-more-compl.patch new file mode 100644 index 0000000..3f549a1 --- /dev/null +++ b/0016-Client-Announce-an-output-after-receiving-more-compl.patch @@ -0,0 +1,146 @@ +From d5186701e27ad6f09f3944809cec2a25c5328026 Mon Sep 17 00:00:00 2001 +From: Vlad Zahorodnii +Date: Wed, 5 May 2021 20:49:26 +0300 +Subject: [PATCH 16/18] 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 +(cherry picked from commit 69ea480f2e53ad4a5bbca78cde044eb8d4c48896) + +Original Ticket: https://codereview.qt-project.org/c/qt/qtwayland/+/347774 +CCBUG: 435124 +--- + src/client/qwaylandscreen.cpp | 32 +++++++++++++++++++++++--------- + src/client/qwaylandscreen_p.h | 10 ++++++++-- + 2 files changed, 31 insertions(+), 11 deletions(-) + +diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp +index 6cb337de..7c2d9be3 100644 +--- a/src/client/qwaylandscreen.cpp ++++ b/src/client/qwaylandscreen.cpp +@@ -72,7 +72,7 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uin + qCWarning(lcQpaWayland) << "wl_output done event not supported by compositor," + << "QScreen may not work correctly"; + mWaylandDisplay->forceRoundTrip(); // Give the compositor a chance to send geometry etc. +- mOutputDone = true; // Fake the done event ++ mProcessedEvents |= OutputDoneEvent; // Fake the done event + maybeInitialize(); + } + } +@@ -83,14 +83,25 @@ QWaylandScreen::~QWaylandScreen() + zxdg_output_v1::destroy(); + } + ++uint QWaylandScreen::requiredEvents() const ++{ ++ uint ret = OutputDoneEvent; ++ ++ if (mWaylandDisplay->xdgOutputManager()) { ++ ret |= XdgOutputNameEvent; ++ ++ if (mWaylandDisplay->xdgOutputManager()->version() < 3) ++ ret |= XdgOutputDoneEvent; ++ } ++ return ret; ++} ++ + void QWaylandScreen::maybeInitialize() + { + Q_ASSERT(!mInitialized); + +- if (!mOutputDone) +- return; +- +- if (mWaylandDisplay->xdgOutputManager() && !mXdgOutputDone) ++ const uint requiredEvents = this->requiredEvents(); ++ if ((mProcessedEvents & requiredEvents) != requiredEvents) + return; + + mInitialized = true; +@@ -276,9 +287,8 @@ void QWaylandScreen::output_scale(int32_t factor) + + void QWaylandScreen::output_done() + { +- mOutputDone = true; +- if (zxdg_output_v1::isInitialized() && mWaylandDisplay->xdgOutputManager()->version() >= 3) +- mXdgOutputDone = true; ++ mProcessedEvents |= OutputDoneEvent; ++ + if (mInitialized) { + updateOutputProperties(); + if (zxdg_output_v1::isInitialized()) +@@ -339,7 +349,7 @@ void QWaylandScreen::zxdg_output_v1_done() + if (Q_UNLIKELY(mWaylandDisplay->xdgOutputManager()->version() >= 3)) + qWarning(lcQpaWayland) << "zxdg_output_v1.done received on version 3 or newer, this is most likely a bug in the compositor"; + +- mXdgOutputDone = true; ++ mProcessedEvents |= XdgOutputDoneEvent; + if (mInitialized) + updateXdgOutputProperties(); + else +@@ -348,7 +358,11 @@ void QWaylandScreen::zxdg_output_v1_done() + + void QWaylandScreen::zxdg_output_v1_name(const QString &name) + { ++ if (Q_UNLIKELY(mInitialized)) ++ qWarning(lcQpaWayland) << "zxdg_output_v1.name received after output has been initialized, this is most likely a bug in the compositor"; ++ + mOutputName = name; ++ mProcessedEvents |= XdgOutputNameEvent; + } + + void QWaylandScreen::updateXdgOutputProperties() +diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h +index df1c94f2..050cfdc0 100644 +--- a/src/client/qwaylandscreen_p.h ++++ b/src/client/qwaylandscreen_p.h +@@ -116,6 +116,13 @@ public: + static QWaylandScreen *fromWlOutput(::wl_output *output); + + private: ++ enum Event : uint { ++ XdgOutputDoneEvent = 0x1, ++ OutputDoneEvent = 0x2, ++ XdgOutputNameEvent = 0x4, ++ }; ++ uint requiredEvents() const; ++ + void output_mode(uint32_t flags, int width, int height, int refresh) override; + void output_geometry(int32_t x, int32_t y, + int32_t width, int32_t height, +@@ -148,8 +155,7 @@ private: + QSize mPhysicalSize; + QString mOutputName; + Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; +- bool mOutputDone = false; +- bool mXdgOutputDone = false; ++ uint mProcessedEvents = 0; + bool mInitialized = false; + + #if QT_CONFIG(cursor) +-- +2.25.1 + diff --git a/0017-Fix-issue-with-repeated-window-size-changes.patch b/0017-Fix-issue-with-repeated-window-size-changes.patch new file mode 100644 index 0000000..8d9caf8 --- /dev/null +++ b/0017-Fix-issue-with-repeated-window-size-changes.patch @@ -0,0 +1,58 @@ +From 62494312db0f58053d1342bfacc7984186fdf3a6 Mon Sep 17 00:00:00 2001 +From: Jaeyoon Jung +Date: Mon, 15 Feb 2021 08:31:06 +0900 +Subject: [PATCH 17/18] 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 +(cherry picked from commit 14d066c61025e548227ccd8d655e80ffa31fa15e) +--- + .../client/wayland-egl/qwaylandeglwindow.cpp | 4 +++- + .../client/wayland-egl/qwaylandeglwindow.h | 1 + + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp +index 7889f575..201b583b 100644 +--- 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, ¤t_width, ¤t_height); + } +- if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height())) { ++ if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height()) || m_requestedSize != sizeWithMargins) { + wl_egl_window_resize(m_waylandEglWindow, sizeWithMargins.width(), sizeWithMargins.height(), mOffset.x(), mOffset.y()); ++ m_requestedSize = sizeWithMargins; + mOffset = QPoint(); + + m_resize = true; + } + } else if (create && wlSurface()) { + m_waylandEglWindow = wl_egl_window_create(wlSurface(), sizeWithMargins.width(), sizeWithMargins.height()); ++ m_requestedSize = sizeWithMargins; + } + + if (!m_eglSurface && m_waylandEglWindow && create) { +diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h +index 5b1f4d56..0079dfef 100644 +--- 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; + }; + + } +-- +2.25.1 + diff --git a/0018-Include-locale.h-for-setlocale-LC_CTYPE.patch b/0018-Include-locale.h-for-setlocale-LC_CTYPE.patch new file mode 100644 index 0000000..74b7092 --- /dev/null +++ b/0018-Include-locale.h-for-setlocale-LC_CTYPE.patch @@ -0,0 +1,31 @@ +From 1ccebbab3a42690a0812e2c4c76016799bf6cf1f Mon Sep 17 00:00:00 2001 +From: Albert Astals Cid +Date: Mon, 10 May 2021 14:38:49 +0200 +Subject: [PATCH 18/18] Include locale.h for setlocale/LC_CTYPE + +Pick-to: 5.15 +Change-Id: Iced32a31a63cec71008549c1e0961d59ffc45a37 +Reviewed-by: Aleix Pol Gonzalez +(cherry picked from commit e9522eda46028f351d87311d898ab985856970b0) +--- + src/client/qwaylandinputcontext.cpp | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp +index ef5aa375..503fd735 100644 +--- 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 ++#endif ++ + QT_BEGIN_NAMESPACE + + Q_LOGGING_CATEGORY(qLcQpaInputMethods, "qt.qpa.input.methods") +-- +2.25.1 + diff --git a/libqt5-qtwayland.changes b/libqt5-qtwayland.changes index 2cbec04..36460d8 100644 --- a/libqt5-qtwayland.changes +++ b/libqt5-qtwayland.changes @@ -1,3 +1,22 @@ +------------------------------------------------------------------- +Sun May 16 18:22:15 UTC 2021 - Fabian Vogt + +- Add more commits from KDE's 5.15 branch: + * 0008-Fix-memory-leak-in-QWaylandGLContext.patch (QTBUG-85608) + * 0009-Client-Send-set_window_geometry-only-once-configured.patch + * 0010-Translate-opaque-area-with-frame-margins.patch + * 0011-Client-Send-exposeEvent-to-parent-on-subsurface-posi.patch + (QTBUG-86177) + * 0012-Get-correct-decoration-margins-region.patch + * 0013-xdgshell-Tell-the-compositor-the-screen-we-re-expect.patch + * 0014-Fix-compilation.patch + * 0015-client-Allow-QWaylandInputContext-to-accept-composed.patch + (kde#405388) + * 0016-Client-Announce-an-output-after-receiving-more-compl.patch + (kde#435124) + * 0017-Fix-issue-with-repeated-window-size-changes.patch + * 0018-Include-locale.h-for-setlocale-LC_CTYPE.patch + ------------------------------------------------------------------- Wed Apr 7 06:55:22 UTC 2021 - Fabian Vogt diff --git a/libqt5-qtwayland.spec b/libqt5-qtwayland.spec index 8e30002..3e56c18 100644 --- a/libqt5-qtwayland.spec +++ b/libqt5-qtwayland.spec @@ -43,6 +43,17 @@ Patch4: 0004-Make-setting-QT_SCALE_FACTOR-work-on-Wayland.patch Patch5: 0005-Ensure-that-grabbing-is-performed-in-correct-context.patch Patch6: 0006-Fix-leaked-subsurface-wayland-items.patch Patch7: 0007-Use-qWarning-and-_exit-instead-of-qFatal-for-wayland.patch +Patch8: 0008-Fix-memory-leak-in-QWaylandGLContext.patch +Patch9: 0009-Client-Send-set_window_geometry-only-once-configured.patch +Patch10: 0010-Translate-opaque-area-with-frame-margins.patch +Patch11: 0011-Client-Send-exposeEvent-to-parent-on-subsurface-posi.patch +Patch12: 0012-Get-correct-decoration-margins-region.patch +Patch13: 0013-xdgshell-Tell-the-compositor-the-screen-we-re-expect.patch +Patch14: 0014-Fix-compilation.patch +Patch15: 0015-client-Allow-QWaylandInputContext-to-accept-composed.patch +Patch16: 0016-Client-Announce-an-output-after-receiving-more-compl.patch +Patch17: 0017-Fix-issue-with-repeated-window-size-changes.patch +Patch18: 0018-Include-locale.h-for-setlocale-LC_CTYPE.patch BuildRequires: fdupes BuildRequires: libqt5-qtbase-private-headers-devel >= %{version} BuildRequires: libqt5-qtdeclarative-private-headers-devel >= %{version}