From 429548bcc59341374e7c5b13f2845c6a9f26f04b Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 10 2022 07:10:50 +0000 Subject: import qt5-qtwayland-5.15.2-3.el8 --- diff --git a/SOURCES/0005-Scanner-Avoid-accessing-dangling-pointers-in-destroy.patch b/SOURCES/0005-Scanner-Avoid-accessing-dangling-pointers-in-destroy.patch new file mode 100644 index 0000000..cde64df --- /dev/null +++ b/SOURCES/0005-Scanner-Avoid-accessing-dangling-pointers-in-destroy.patch @@ -0,0 +1,38 @@ +From e5c272423d1bba2825086b82fd97499237a6fa4b Mon Sep 17 00:00:00 2001 +From: Vlad Zahorodnii +Date: Fri, 30 Oct 2020 16:55:30 +0200 +Subject: [PATCH 05/36] Scanner: Avoid accessing dangling pointers in + destroy_func() + +Usually, the object associated with the resource gets destroyed in the +destroy_resource() function. + +Therefore, we need to double-check that the object is still alive before +trying to reset its m_resource. + +Change-Id: I26408228f58919db17eb29584a1cbd4a9427d25c +Reviewed-by: Eskil Abrahamsen Blomfeldt +(cherry picked from commit 735164b5c2a2637a8d53a8803a2401e4ef477ff0) +Reviewed-by: Qt Cherry-pick Bot +--- + src/qtwaylandscanner/qtwaylandscanner.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/qtwaylandscanner/qtwaylandscanner.cpp b/src/qtwaylandscanner/qtwaylandscanner.cpp +index 1d635f06..e2f87bbd 100644 +--- a/src/qtwaylandscanner/qtwaylandscanner.cpp ++++ b/src/qtwaylandscanner/qtwaylandscanner.cpp +@@ -814,7 +814,9 @@ bool Scanner::process() + printf(" if (Q_LIKELY(that)) {\n"); + printf(" that->m_resource_map.remove(resource->client(), resource);\n"); + printf(" that->%s_destroy_resource(resource);\n", interfaceNameStripped); +- printf(" if (that->m_resource == resource)\n"); ++ printf("\n"); ++ printf(" that = resource->%s_object;\n", interfaceNameStripped); ++ printf(" if (that && that->m_resource == resource)\n"); + printf(" that->m_resource = nullptr;\n"); + printf(" }\n"); + printf(" delete resource;\n"); +-- +2.33.1 + diff --git a/SOURCES/0006-Make-setting-QT_SCALE_FACTOR-work-on-Wayland.patch b/SOURCES/0006-Make-setting-QT_SCALE_FACTOR-work-on-Wayland.patch new file mode 100644 index 0000000..acfbf99 --- /dev/null +++ b/SOURCES/0006-Make-setting-QT_SCALE_FACTOR-work-on-Wayland.patch @@ -0,0 +1,38 @@ +From a825fb5f714fd79d16cc3ebbdd327e7961b07d0a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= +Date: Mon, 16 Nov 2020 19:37:33 +0100 +Subject: [PATCH 06/36] Make setting QT_SCALE_FACTOR work on Wayland + +Follow-up to 8cb1b07aea12d50b4fecc45c903705dfd368022a, +fixes one additional case (Use of minimum/maximum size). + +Fixes: QTBUG-87762 +Change-Id: I73e0df2529b0cadf25ad50ea7459cdbb92caf424 +Reviewed-by: Eskil Abrahamsen Blomfeldt +(cherry picked from commit 6ed363e3665f17d935f8636d9c958154c898f5c5) +Reviewed-by: Qt Cherry-pick Bot +--- + src/client/qwaylandwindow.cpp | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index bc031ed5..eb053406 100644 +--- a/src/client/qwaylandwindow.cpp ++++ b/src/client/qwaylandwindow.cpp +@@ -332,9 +332,11 @@ void QWaylandWindow::setWindowIcon(const QIcon &icon) + + void QWaylandWindow::setGeometry_helper(const QRect &rect) + { ++ QSize minimum = windowMinimumSize(); ++ QSize maximum = windowMaximumSize(); + QPlatformWindow::setGeometry(QRect(rect.x(), rect.y(), +- qBound(window()->minimumWidth(), rect.width(), window()->maximumWidth()), +- qBound(window()->minimumHeight(), rect.height(), window()->maximumHeight()))); ++ qBound(minimum.width(), rect.width(), maximum.width()), ++ qBound(minimum.height(), rect.height(), maximum.height()))); + + if (mSubSurfaceWindow) { + QMargins m = QPlatformWindow::parent()->frameMargins(); +-- +2.33.1 + diff --git a/SOURCES/0007-Do-not-try-to-eglMakeCurrent-for-unintended-case.patch b/SOURCES/0007-Do-not-try-to-eglMakeCurrent-for-unintended-case.patch new file mode 100644 index 0000000..dd1eb8c --- /dev/null +++ b/SOURCES/0007-Do-not-try-to-eglMakeCurrent-for-unintended-case.patch @@ -0,0 +1,62 @@ +From 2c0a03e9aea13831d05ac03996949f888afd5085 Mon Sep 17 00:00:00 2001 +From: Jaehak Lee +Date: Sun, 8 Nov 2020 11:40:06 +0900 +Subject: [PATCH 07/36] Do not try to eglMakeCurrent for unintended case + +The QSGThreadedRenderLoop::hide can be called at twice, +when the QWindowPrivate::setVisible(false) is called. + +The eglSurface is EGL_NO_SURFACE when the second QSGThreadedRenderLoop::hide is +called. And if EGL_KHR_surfaceless_context is supported, the eglMakeCurrent +don't return the false. + +But this case is not intended. So, add the defence code for above case. + +Fixes: QTBUG-88277 +Change-Id: Ia9e5990303e98f0eedc48531e5af62ff9961f419 +Reviewed-by: Laszlo Agocs +Reviewed-by: Eskil Abrahamsen Blomfeldt +--- + .../client/wayland-egl/qwaylandglcontext.cpp | 6 ++++++ + .../client/wayland-egl/qwaylandglcontext.h | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +index ccebf43d..681f82f4 100644 +--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp ++++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +@@ -336,6 +336,8 @@ QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *dis + << "It may also cause the event loop to freeze in some situations"; + } + ++ m_supportSurfaceLessContext = q_hasEglExtension(m_eglDisplay, "EGL_KHR_surfaceless_context"); ++ + updateGLFormat(); + } + +@@ -439,6 +441,10 @@ bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface) + eglSurface = window->eglSurface(); + } + ++ if (eglSurface == EGL_NO_SURFACE && m_supportSurfaceLessContext) { ++ return false; ++ } ++ + if (!eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_context)) { + qWarning("QWaylandGLContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this); + window->setCanResize(true); +diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h +index 46c7bb76..93edaec0 100644 +--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h ++++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h +@@ -93,6 +93,7 @@ private: + DecorationsBlitter *m_blitter = nullptr; + uint m_api; + bool m_supportNonBlockingSwap = true; ++ bool m_supportSurfaceLessContext = false; + }; + + } +-- +2.33.1 + diff --git a/SOURCES/0008-Make-setting-QT_SCALE_FACTOR-work-on-Wayland.patch b/SOURCES/0008-Make-setting-QT_SCALE_FACTOR-work-on-Wayland.patch new file mode 100644 index 0000000..4e10015 --- /dev/null +++ b/SOURCES/0008-Make-setting-QT_SCALE_FACTOR-work-on-Wayland.patch @@ -0,0 +1,112 @@ +From 10005185e06857ce119c50fe710f9eedde06ec5e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= +Date: Fri, 13 Nov 2020 11:21:50 +0100 +Subject: [PATCH 08/36] Make setting QT_SCALE_FACTOR work on Wayland + +QWindow geometry accessors return geometry in device +independent pixels. Normally this coordinate system +is equivalent to the Wayland native coordinate system, +but this is not the case when QT_SCALE_FACTOR is set. + +Replace QWindow geometry calls with the helpers from +QPlatformWindow which return geometry in the native +coordinate system: + +QWindow::geometry() -> QPlatformWindow::windowGeometry() +QWindow::frameGeometry() -> QPlatformWindow::windowFrameGeometry() + +Task-number: QTBUG-87762 +Fixes: QTBUG-88064 +(cherry-picked from commit 8cb1b07aea12d50b4fecc45c903705dfd368022a) +Change-Id: I6e2029bc6210f12441ae7c9d8b678271e9922dde +Reviewed-by: Eskil Abrahamsen Blomfeldt +--- + src/client/qwaylandwindow.cpp | 7 ++++--- + .../shellintegration/wl-shell/qwaylandwlshellsurface.cpp | 2 +- + .../shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp | 2 +- + .../shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp | 2 +- + .../shellintegration/xdg-shell/qwaylandxdgshell.cpp | 2 +- + 5 files changed, 8 insertions(+), 7 deletions(-) + +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index eb053406..9b343702 100644 +--- a/src/client/qwaylandwindow.cpp ++++ b/src/client/qwaylandwindow.cpp +@@ -194,10 +194,11 @@ void QWaylandWindow::initWindow() + if (QScreen *s = window()->screen()) + setOrientationMask(s->orientationUpdateMask()); + setWindowFlags(window()->flags()); +- if (window()->geometry().isEmpty()) ++ QRect geometry = windowGeometry(); ++ if (geometry.isEmpty()) + setGeometry_helper(QRect(QPoint(), QSize(500,500))); + else +- setGeometry_helper(window()->geometry()); ++ setGeometry_helper(geometry); + setMask(window()->mask()); + if (mShellSurface) + mShellSurface->requestWindowStates(window()->windowStates()); +@@ -431,7 +432,7 @@ void QWaylandWindow::setVisible(bool visible) + initWindow(); + mDisplay->flushRequests(); + +- setGeometry(window()->geometry()); ++ setGeometry(windowGeometry()); + // Don't flush the events here, or else the newly visible window may start drawing, but since + // there was no frame before it will be stuck at the waitForFrameSync() in + // QWaylandShmBackingStore::beginPaint(). +diff --git a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp +index 245fec19..8f41118d 100644 +--- a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp ++++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp +@@ -134,7 +134,7 @@ void QWaylandWlShellSurface::applyConfigure() + { + if ((m_pending.states & (Qt::WindowMaximized|Qt::WindowFullScreen)) + && !(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen))) { +- m_normalSize = m_window->window()->frameGeometry().size(); ++ m_normalSize = m_window->windowFrameGeometry().size(); + } + + if (m_pending.states != m_applied.states) +diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp +index 770fad7e..73aba1ee 100644 +--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp ++++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp +@@ -157,7 +157,7 @@ void QWaylandXdgSurfaceV5::applyConfigure() + if (m_pending.isResizing) + m_normalSize = m_pending.size; + else if (!(m_acked.states & (Qt::WindowMaximized|Qt::WindowFullScreen))) +- m_normalSize = m_window->window()->frameGeometry().size(); ++ m_normalSize = m_window->windowFrameGeometry().size(); + + if ((m_pending.states & Qt::WindowActive) && !(m_acked.states & Qt::WindowActive)) + m_window->display()->handleWindowActivated(m_window); +diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp +index c137b308..8c371661 100644 +--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp ++++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp +@@ -72,7 +72,7 @@ QWaylandXdgSurfaceV6::Toplevel::~Toplevel() + void QWaylandXdgSurfaceV6::Toplevel::applyConfigure() + { + if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen))) +- m_normalSize = m_xdgSurface->m_window->window()->frameGeometry().size(); ++ m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size(); + + if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive)) + m_xdgSurface->m_window->display()->handleWindowActivated(m_xdgSurface->m_window); +diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +index b6d23ac1..1c762944 100644 +--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp ++++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +@@ -83,7 +83,7 @@ QWaylandXdgSurface::Toplevel::~Toplevel() + void QWaylandXdgSurface::Toplevel::applyConfigure() + { + if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen))) +- m_normalSize = m_xdgSurface->m_window->window()->frameGeometry().size(); ++ m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size(); + + if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive)) + m_xdgSurface->m_window->display()->handleWindowActivated(m_xdgSurface->m_window); +-- +2.33.1 + diff --git a/SOURCES/0009-Ensure-that-grabbing-is-performed-in-correct-context.patch b/SOURCES/0009-Ensure-that-grabbing-is-performed-in-correct-context.patch new file mode 100644 index 0000000..1a98f8e --- /dev/null +++ b/SOURCES/0009-Ensure-that-grabbing-is-performed-in-correct-context.patch @@ -0,0 +1,35 @@ +From dba4bc4f1d6dfee9fe9433c55b15653d703bed4f Mon Sep 17 00:00:00 2001 +From: Andreas Cord-Landwehr +Date: Wed, 2 Dec 2020 20:55:52 +0100 +Subject: [PATCH 09/36] Ensure that grabbing is performed in correct context + +For multi-display rendering on EGL, it is mandatory that the grabbing of +the surface happens in the same EGL context as the surface belongs to. +By adding the grabbing to the rendering stage of the image, this +relation is forced. + +Task-number: QTBUG-87597 +Change-Id: I50f40df1215aa771d714065e942c5a738ba6269f +Reviewed-by: Eskil Abrahamsen Blomfeldt +(cherry picked from commit ab3a1a07f3d1e0d5a9e9d97b6b3b587180e2f4c8) +Reviewed-by: Qt Cherry-pick Bot +--- + src/compositor/compositor_api/qwaylandquickcompositor.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/compositor/compositor_api/qwaylandquickcompositor.cpp b/src/compositor/compositor_api/qwaylandquickcompositor.cpp +index 49f0860e..db1cf00f 100644 +--- a/src/compositor/compositor_api/qwaylandquickcompositor.cpp ++++ b/src/compositor/compositor_api/qwaylandquickcompositor.cpp +@@ -161,7 +161,7 @@ void QWaylandQuickCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const + GrabState *state = new GrabState; + state->grabber = grabber; + state->buffer = buffer; +- static_cast(output->window())->scheduleRenderJob(state, QQuickWindow::NoStage); ++ static_cast(output->window())->scheduleRenderJob(state, QQuickWindow::AfterRenderingStage); + #else + emit grabber->failed(QWaylandSurfaceGrabber::UnknownBufferType); + #endif +-- +2.33.1 + diff --git a/SOURCES/0010-Fix-leaked-subsurface-wayland-items.patch b/SOURCES/0010-Fix-leaked-subsurface-wayland-items.patch new file mode 100644 index 0000000..fbfaf41 --- /dev/null +++ b/SOURCES/0010-Fix-leaked-subsurface-wayland-items.patch @@ -0,0 +1,36 @@ +From a8d35b3c18bdb05a0da3ed50a554a7b7bd4ebed3 Mon Sep 17 00:00:00 2001 +From: Eskil Abrahamsen Blomfeldt +Date: Mon, 30 Nov 2020 13:13:18 +0100 +Subject: [PATCH 10/36] Fix leaked subsurface wayland items + +Whenever a subsurface was added we would create a QWaylandQuickItem, +but this was never deleted. It is one-to-one with the surface, so it +should be deleted at the same time. + +[ChangeLog][QtWaylandCompositor] Fixed a memory leak when creating +subsurfaces. + +Task-number: QTBUG-88782 +Change-Id: If4b3f15200ce3bd123ff73847d3593d174a39229 +Reviewed-by: Paul Olav Tvete +(cherry picked from commit 38fc568b30bf916165324c2cd2db127d2a9aa68c) +Reviewed-by: Qt Cherry-pick Bot +--- + src/compositor/compositor_api/qwaylandquickitem.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp +index 15f0195c..2218f43a 100644 +--- a/src/compositor/compositor_api/qwaylandquickitem.cpp ++++ b/src/compositor/compositor_api/qwaylandquickitem.cpp +@@ -737,6 +737,7 @@ void QWaylandQuickItem::handleSubsurfaceAdded(QWaylandSurface *childSurface) + childItem->setVisible(true); + childItem->setParentItem(this); + connect(childSurface, &QWaylandSurface::subsurfacePositionChanged, childItem, &QWaylandQuickItem::handleSubsurfacePosition); ++ connect(childSurface, &QWaylandSurface::destroyed, childItem, &QObject::deleteLater); + } else { + bool success = QMetaObject::invokeMethod(d->subsurfaceHandler, "handleSubsurfaceAdded", Q_ARG(QWaylandSurface *, childSurface)); + if (!success) +-- +2.33.1 + diff --git a/SOURCES/0011-Use-qWarning-and-_exit-instead-of-qFatal-for-wayland.patch b/SOURCES/0011-Use-qWarning-and-_exit-instead-of-qFatal-for-wayland.patch new file mode 100644 index 0000000..5860630 --- /dev/null +++ b/SOURCES/0011-Use-qWarning-and-_exit-instead-of-qFatal-for-wayland.patch @@ -0,0 +1,38 @@ +From 9ee2ea141adc7765f6c212e63839ef23a4494b30 Mon Sep 17 00:00:00 2001 +From: Weng Xuetian +Date: Tue, 9 Mar 2021 10:43:59 -0800 +Subject: [PATCH 11/36] Use qWarning and _exit() instead of qFatal for wayland + error + +This type of error is likely to happen upon system logout. qFatal would +trigger sigabrt and leave unnecessary coredump on the system. Using +qWarning here would make it consistent with xcb's io error. + +Pick-to: 5.15 6.0 6.1 +Change-Id: I571ba007bf2453486b81837cccdbefa5f181b63d +Reviewed-by: David Edmundson +--- + src/client/qwaylanddisplay.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp +index fe094f6f..f10c1f79 100644 +--- a/src/client/qwaylanddisplay.cpp ++++ b/src/client/qwaylanddisplay.cpp +@@ -206,10 +206,11 @@ void QWaylandDisplay::checkError() const + int ecode = wl_display_get_error(mDisplay); + if ((ecode == EPIPE || ecode == ECONNRESET)) { + // special case this to provide a nicer error +- qFatal("The Wayland connection broke. Did the Wayland compositor die?"); ++ qWarning("The Wayland connection broke. Did the Wayland compositor die?"); + } else { +- qFatal("The Wayland connection experienced a fatal error: %s", strerror(ecode)); ++ qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode)); + } ++ _exit(1); + } + + void QWaylandDisplay::flushRequests() +-- +2.33.1 + diff --git a/SOURCES/0012-Fix-memory-leak-in-QWaylandGLContext.patch b/SOURCES/0012-Fix-memory-leak-in-QWaylandGLContext.patch new file mode 100644 index 0000000..114570b --- /dev/null +++ b/SOURCES/0012-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 12/36] 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.33.1 + diff --git a/SOURCES/0013-Client-Send-set_window_geometry-only-once-configured.patch b/SOURCES/0013-Client-Send-set_window_geometry-only-once-configured.patch new file mode 100644 index 0000000..5b88f17 --- /dev/null +++ b/SOURCES/0013-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 13/36] 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.33.1 + diff --git a/SOURCES/0014-Translate-opaque-area-with-frame-margins.patch b/SOURCES/0014-Translate-opaque-area-with-frame-margins.patch new file mode 100644 index 0000000..6cc32a4 --- /dev/null +++ b/SOURCES/0014-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 14/36] 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.33.1 + diff --git a/SOURCES/0015-Client-Send-exposeEvent-to-parent-on-subsurface-posi.patch b/SOURCES/0015-Client-Send-exposeEvent-to-parent-on-subsurface-posi.patch new file mode 100644 index 0000000..d342e82 --- /dev/null +++ b/SOURCES/0015-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 15/36] 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.33.1 + diff --git a/SOURCES/0016-Get-correct-decoration-margins-region.patch b/SOURCES/0016-Get-correct-decoration-margins-region.patch new file mode 100644 index 0000000..8d827bf --- /dev/null +++ b/SOURCES/0016-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 16/36] 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.33.1 + diff --git a/SOURCES/0017-xdgshell-Tell-the-compositor-the-screen-we-re-expect.patch b/SOURCES/0017-xdgshell-Tell-the-compositor-the-screen-we-re-expect.patch new file mode 100644 index 0000000..ab9600c --- /dev/null +++ b/SOURCES/0017-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 17/36] 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.33.1 + diff --git a/SOURCES/0018-Fix-compilation.patch b/SOURCES/0018-Fix-compilation.patch new file mode 100644 index 0000000..edbb55f --- /dev/null +++ b/SOURCES/0018-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 18/36] 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.33.1 + diff --git a/SOURCES/0019-client-Allow-QWaylandInputContext-to-accept-composed.patch b/SOURCES/0019-client-Allow-QWaylandInputContext-to-accept-composed.patch new file mode 100644 index 0000000..ff39a0b --- /dev/null +++ b/SOURCES/0019-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 19/36] 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.33.1 + diff --git a/SOURCES/0020-Client-Announce-an-output-after-receiving-more-compl.patch b/SOURCES/0020-Client-Announce-an-output-after-receiving-more-compl.patch new file mode 100644 index 0000000..3249a69 --- /dev/null +++ b/SOURCES/0020-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 20/36] 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.33.1 + diff --git a/SOURCES/0021-Fix-issue-with-repeated-window-size-changes.patch b/SOURCES/0021-Fix-issue-with-repeated-window-size-changes.patch new file mode 100644 index 0000000..9c7ebde --- /dev/null +++ b/SOURCES/0021-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 21/36] 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.33.1 + diff --git a/SOURCES/0022-Include-locale.h-for-setlocale-LC_CTYPE.patch b/SOURCES/0022-Include-locale.h-for-setlocale-LC_CTYPE.patch new file mode 100644 index 0000000..fcb0973 --- /dev/null +++ b/SOURCES/0022-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 22/36] 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.33.1 + diff --git a/SOURCES/0023-Client-Connect-drags-being-accepted-to-updating-the-.patch b/SOURCES/0023-Client-Connect-drags-being-accepted-to-updating-the-.patch new file mode 100644 index 0000000..5780e26 --- /dev/null +++ b/SOURCES/0023-Client-Connect-drags-being-accepted-to-updating-the-.patch @@ -0,0 +1,39 @@ +From fcc2f57cefa66339c8cb6632f45a47fbb99bb60d Mon Sep 17 00:00:00 2001 +From: David Edmundson +Date: Tue, 9 Feb 2021 16:09:21 +0000 +Subject: [PATCH 23/36] 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 +Reviewed-by: Eskil Abrahamsen Blomfeldt +(cherry picked from commit 08e478448a97a440d5a968a5d797f0d7302140c2) +--- + src/client/qwaylanddatadevice.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp +index 19944a34..54a69c3c 100644 +--- a/src/client/qwaylanddatadevice.cpp ++++ b/src/client/qwaylanddatadevice.cpp +@@ -124,6 +124,7 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon) + + m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData)); + connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled); ++ connect(m_dragSource.data(), &QWaylandDataSource::targetChanged, this, &QWaylandDataDevice::dragSourceTargetChanged); + + start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial()); + return true; +-- +2.33.1 + diff --git a/SOURCES/0024-Client-Disconnect-registry-listener-on-destruction.patch b/SOURCES/0024-Client-Disconnect-registry-listener-on-destruction.patch new file mode 100644 index 0000000..a2afc6b --- /dev/null +++ b/SOURCES/0024-Client-Disconnect-registry-listener-on-destruction.patch @@ -0,0 +1,49 @@ +From 1b5e43a593e917610e6245f7a272ac081c508ba4 Mon Sep 17 00:00:00 2001 +From: David Edmundson +Date: Fri, 14 May 2021 13:23:24 +0100 +Subject: [PATCH 24/36] Client: Disconnect registry listener on destruction + +If a display outlives a QWaylandClientExtension and a new global is +announced we end up delivering an event to a now deleted extension which +will crash. + +Change-Id: Idc0de40be61a2f7627ab4963e1fe29b22fbf3f04 +(cherry picked from commit c4ba37cd2f8cb81b9438b56ac604fc2f3e45083c) +--- + src/client/global/qwaylandclientextension.cpp | 7 +++++++ + src/client/global/qwaylandclientextension.h | 1 + + 2 files changed, 8 insertions(+) + +diff --git a/src/client/global/qwaylandclientextension.cpp b/src/client/global/qwaylandclientextension.cpp +index 125b1e19..797b06fe 100644 +--- a/src/client/global/qwaylandclientextension.cpp ++++ b/src/client/global/qwaylandclientextension.cpp +@@ -88,6 +88,13 @@ QWaylandClientExtension::QWaylandClientExtension(const int ver) + QMetaObject::invokeMethod(this, "addRegistryListener", Qt::QueuedConnection); + } + ++QWaylandClientExtension::~QWaylandClientExtension() ++{ ++ Q_D(QWaylandClientExtension); ++ if (d->registered && !QCoreApplication::closingDown()) ++ d->waylandIntegration->display()->removeListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this); ++} ++ + QtWaylandClient::QWaylandIntegration *QWaylandClientExtension::integration() const + { + Q_D(const QWaylandClientExtension); +diff --git a/src/client/global/qwaylandclientextension.h b/src/client/global/qwaylandclientextension.h +index 98272e57..5bd28398 100644 +--- a/src/client/global/qwaylandclientextension.h ++++ b/src/client/global/qwaylandclientextension.h +@@ -63,6 +63,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtension : public QObject + Q_PROPERTY(bool active READ isActive NOTIFY activeChanged) + public: + QWaylandClientExtension(const int version); ++ ~QWaylandClientExtension(); + + QtWaylandClient::QWaylandIntegration *integration() const; + int version() const; +-- +2.33.1 + diff --git a/SOURCES/0025-Client-Set-XdgShell-size-hints-before-the-first-comm.patch b/SOURCES/0025-Client-Set-XdgShell-size-hints-before-the-first-comm.patch new file mode 100644 index 0000000..84ef091 --- /dev/null +++ b/SOURCES/0025-Client-Set-XdgShell-size-hints-before-the-first-comm.patch @@ -0,0 +1,58 @@ +From 36a552fa530be57091e986ebd1468d75d3061743 Mon Sep 17 00:00:00 2001 +From: David Edmundson +Date: Mon, 3 May 2021 23:01:53 +0100 +Subject: [PATCH 25/36] 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 +Reviewed-by: Aleix Pol Gonzalez +(cherry picked from commit d6e074d0d35221b0fac14c94fc79c98363f2f6c3) +--- + src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp | 3 +-- + tests/auto/client/xdgshell/tst_xdgshell.cpp | 2 +- + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +index 3a1569f7..7d33dabd 100644 +--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp ++++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +@@ -105,8 +105,6 @@ void QWaylandXdgSurface::Toplevel::applyConfigure() + m_xdgSurface->m_window->resizeFromApplyConfigure(m_pending.size); + } + +- m_xdgSurface->setSizeHints(); +- + m_applied = m_pending; + qCDebug(lcQpaWayland) << "Applied pending xdg_toplevel configure event:" << m_applied.size << m_applied.states; + } +@@ -257,6 +255,7 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *s + m_toplevel->set_parent(parentXdgSurface->m_toplevel->object()); + } + } ++ setSizeHints(); + } + + QWaylandXdgSurface::~QWaylandXdgSurface() +diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp +index 2277bbb8..2fdd0a7c 100644 +--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp ++++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp +@@ -505,7 +505,7 @@ void tst_xdgshell::minMaxSize() + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + +- exec([=] { xdgToplevel()->sendCompleteConfigure(); }); ++ // we don't roundtrip with our configuration the initial commit should be correct + + QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(100, 100)); + QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(1000, 1000)); +-- +2.33.1 + diff --git a/SOURCES/0026-Fix-build.patch b/SOURCES/0026-Fix-build.patch new file mode 100644 index 0000000..d401d84 --- /dev/null +++ b/SOURCES/0026-Fix-build.patch @@ -0,0 +1,46 @@ +From a8ddf1a7296e2d28b36231a391807226a7329ae4 Mon Sep 17 00:00:00 2001 +From: David Edmundson +Date: Mon, 14 Jun 2021 12:45:37 +0100 +Subject: [PATCH 26/36] Fix build + +1b5e43a593e917610e6245f7a272ac081c508ba4 relied on a patch that we can't +backport. + +This adds that extra internal boolean backporting just the tiny part of +d6ac8cf6. +--- + src/client/global/qwaylandclientextension.cpp | 5 ++++- + src/client/global/qwaylandclientextension_p.h | 1 + + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/client/global/qwaylandclientextension.cpp b/src/client/global/qwaylandclientextension.cpp +index 797b06fe..edccfe63 100644 +--- a/src/client/global/qwaylandclientextension.cpp ++++ b/src/client/global/qwaylandclientextension.cpp +@@ -74,7 +74,10 @@ void QWaylandClientExtensionPrivate::handleRegistryGlobal(void *data, ::wl_regis + void QWaylandClientExtension::addRegistryListener() + { + Q_D(QWaylandClientExtension); +- d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this); ++ if (!d->registered) { ++ d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this); ++ d->registered = true; ++ } + } + + QWaylandClientExtension::QWaylandClientExtension(const int ver) +diff --git a/src/client/global/qwaylandclientextension_p.h b/src/client/global/qwaylandclientextension_p.h +index 69cc46a0..9091efbe 100644 +--- a/src/client/global/qwaylandclientextension_p.h ++++ b/src/client/global/qwaylandclientextension_p.h +@@ -68,6 +68,7 @@ public: + QtWaylandClient::QWaylandIntegration *waylandIntegration = nullptr; + int version = -1; + bool active = false; ++ bool registered = false; + }; + + class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtensionTemplatePrivate : public QWaylandClientExtensionPrivate +-- +2.33.1 + diff --git a/SOURCES/0027-Fix-remove-listener.patch b/SOURCES/0027-Fix-remove-listener.patch new file mode 100644 index 0000000..fbe2342 --- /dev/null +++ b/SOURCES/0027-Fix-remove-listener.patch @@ -0,0 +1,33 @@ +From d1c4a459faa1d514026c4834828cb33024ac2ceb Mon Sep 17 00:00:00 2001 +From: Zhang Liang +Date: Mon, 1 Feb 2021 19:29:43 +0800 +Subject: [PATCH 27/36] Fix: remove listener + +Add the operation for removing the listener form listener list + +Change-Id: Ief2ff1303b607eee499543303fe80e51f8f10cc5 +Reviewed-by: David Edmundson +(cherry picked from commit 16760280fd04cf70255bab16d9acecad254fdd8f) +--- + src/client/qwaylanddisplay.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp +index f10c1f79..e0dfe8b2 100644 +--- 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() +-- +2.33.1 + diff --git a/SOURCES/0028-Hook-up-queryKeyboardModifers.patch b/SOURCES/0028-Hook-up-queryKeyboardModifers.patch new file mode 100644 index 0000000..7e074c9 --- /dev/null +++ b/SOURCES/0028-Hook-up-queryKeyboardModifers.patch @@ -0,0 +1,55 @@ +From a6476d1a1c78eb7f17408241b268404e27b3e161 Mon Sep 17 00:00:00 2001 +From: David Redondo +Date: Wed, 26 May 2021 14:49:40 +0200 +Subject: [PATCH 28/36] 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 +Reviewed-by: David Edmundson + + +(cherry picked from commit 4fa2baba8181ade4958a94e9531ec4f6919438a9) +--- + src/client/qwaylandintegration.cpp | 8 ++++++++ + src/client/qwaylandintegration_p.h | 2 ++ + 2 files changed, 10 insertions(+) + +diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp +index c53ccb78..e5e7dd42 100644 +--- a/src/client/qwaylandintegration.cpp ++++ b/src/client/qwaylandintegration.cpp +@@ -262,6 +262,14 @@ QWaylandDisplay *QWaylandIntegration::display() const + return mDisplay.data(); + } + ++Qt::KeyboardModifiers QWaylandIntegration::queryKeyboardModifiers() const ++{ ++ if (auto *seat = mDisplay->currentInputDevice()) { ++ return seat->modifiers(); ++ } ++ return Qt::NoModifier; ++} ++ + QList QWaylandIntegration::possibleKeys(const QKeyEvent *event) const + { + if (auto *seat = mDisplay->currentInputDevice()) +diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h +index ff70ae25..73b80658 100644 +--- a/src/client/qwaylandintegration_p.h ++++ b/src/client/qwaylandintegration_p.h +@@ -107,6 +107,8 @@ public: + + QWaylandDisplay *display() const; + ++ Qt::KeyboardModifiers queryKeyboardModifiers() const override; ++ + QList possibleKeys(const QKeyEvent *event) const override; + + QStringList themeNames() const override; +-- +2.33.1 + diff --git a/SOURCES/0029-Do-not-update-the-mask-if-we-do-not-have-a-surface.patch b/SOURCES/0029-Do-not-update-the-mask-if-we-do-not-have-a-surface.patch new file mode 100644 index 0000000..9764d9b --- /dev/null +++ b/SOURCES/0029-Do-not-update-the-mask-if-we-do-not-have-a-surface.patch @@ -0,0 +1,44 @@ +From d4c41797b61a5a8da47c5821711aca72e756dcbf Mon Sep 17 00:00:00 2001 +From: Aleix Pol +Date: Tue, 13 Jul 2021 13:32:15 +0200 +Subject: [PATCH 29/36] 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 +(cherry picked from commit 962f87190c682562b369c5ebd93dc9ce0915ed7a) +--- + src/client/qwaylandwindow.cpp | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index e96d8fe9..bd70f4af 100644 +--- 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); + +-- +2.33.1 + diff --git a/SOURCES/0030-Correctly-detect-if-image-format-is-supported-by-QIm.patch b/SOURCES/0030-Correctly-detect-if-image-format-is-supported-by-QIm.patch new file mode 100644 index 0000000..ceea624 --- /dev/null +++ b/SOURCES/0030-Correctly-detect-if-image-format-is-supported-by-QIm.patch @@ -0,0 +1,68 @@ +From 3c420cd180397e3f42c8a436a7f1b11465925bdd Mon Sep 17 00:00:00 2001 +From: Jan Blackquill +Date: Tue, 24 Aug 2021 14:36:34 -0400 +Subject: [PATCH 30/36] 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 +Reviewed-by: Qt CI Bot +(cherry picked from commit 6072c1dc87e185f30c014f764737ac97b906640f) +--- + src/shared/qwaylandmimehelper.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/qwaylandmimehelper.cpp b/src/shared/qwaylandmimehelper.cpp +index a5fdd34d..051a91dc 100644 +--- a/src/shared/qwaylandmimehelper.cpp ++++ b/src/shared/qwaylandmimehelper.cpp +@@ -60,7 +60,7 @@ QByteArray QWaylandMimeHelper::getByteArray(QMimeData *mimeData, const QString & + buf.open(QIODevice::ReadWrite); + QByteArray fmt = "BMP"; + if (mimeType.startsWith(QLatin1String("image/"))) { +- QByteArray imgFmt = mimeType.mid(6).toUpper().toLatin1(); ++ QByteArray imgFmt = mimeType.mid(6).toLower().toLatin1(); + if (QImageWriter::supportedImageFormats().contains(imgFmt)) + fmt = imgFmt; + } +-- +2.33.1 + diff --git a/SOURCES/0031-Wayland-client-Fix-crash-when-windows-are-shown-hidd.patch b/SOURCES/0031-Wayland-client-Fix-crash-when-windows-are-shown-hidd.patch new file mode 100644 index 0000000..b5df11c --- /dev/null +++ b/SOURCES/0031-Wayland-client-Fix-crash-when-windows-are-shown-hidd.patch @@ -0,0 +1,31 @@ +From 1c53ba6dfebbf1d6e87c9ad1f2bbda94e3d45bf7 Mon Sep 17 00:00:00 2001 +From: Paul Olav Tvete +Date: Tue, 14 Sep 2021 11:56:23 +0200 +Subject: [PATCH 31/36] 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 +(cherry picked from commit c64c5d3849b40617e1de0295f8690f354cab2b3a) +--- + src/client/qwaylanddatadevice.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp +index 54a69c3c..bbd2d568 100644 +--- 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 + +-- +2.33.1 + diff --git a/SOURCES/0032-Client-Don-t-always-recreate-frame-callbacks.patch b/SOURCES/0032-Client-Don-t-always-recreate-frame-callbacks.patch new file mode 100644 index 0000000..4789fe8 --- /dev/null +++ b/SOURCES/0032-Client-Don-t-always-recreate-frame-callbacks.patch @@ -0,0 +1,77 @@ +From 3be586cd8b6c8313cb6b8b7d61be17706f79590e Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Thu, 27 May 2021 19:55:04 -0300 +Subject: [PATCH 32/36] 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 +Reviewed-by: Georges Basile Stavracas Neto +Reviewed-by: Eskil Abrahamsen Blomfeldt +(cherry picked from commit cbc74ba6d7186457d8d07183272e952dee5f34f9) +--- + src/client/qwaylandwindow.cpp | 4 ++++ + tests/auto/client/xdgshell/tst_xdgshell.cpp | 2 ++ + 2 files changed, 6 insertions(+) + +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index bd70f4af..85307875 100644 +--- 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) +diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp +index 2fdd0a7c..e2593314 100644 +--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp ++++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp +@@ -138,6 +138,7 @@ void tst_xdgshell::configureSize() + + void tst_xdgshell::configureStates() + { ++ QVERIFY(qputenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT", "0")); + QRasterWindow window; + window.resize(64, 48); + window.show(); +@@ -186,6 +187,7 @@ void tst_xdgshell::configureStates() + QCOMPARE(window.windowStates(), Qt::WindowNoState); + QCOMPARE(window.frameGeometry().size(), windowedSize); + // QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled ++ QVERIFY(qunsetenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT")); + } + + void tst_xdgshell::popup() +-- +2.33.1 + diff --git a/SOURCES/0033-Client-Always-destroy-frame-callback-in-the-actual-c.patch b/SOURCES/0033-Client-Always-destroy-frame-callback-in-the-actual-c.patch new file mode 100644 index 0000000..8446b4e --- /dev/null +++ b/SOURCES/0033-Client-Always-destroy-frame-callback-in-the-actual-c.patch @@ -0,0 +1,58 @@ +From efe6edcaf8eba601dff99ec6ad4457c8a4442f86 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Thu, 27 May 2021 20:02:53 -0300 +Subject: [PATCH 33/36] 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 +(cherry picked from commit 42cdc61a93cf2acb09936aebb5e431fdbc0a26c6) +--- + src/client/qwaylandwindow.cpp | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index 85307875..c020a58f 100644 +--- 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(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(wl_proxy_create_wrapper(mSurface->object())); + wl_proxy_set_queue(reinterpret_cast(wrappedSurface), mFrameQueue.queue); +-- +2.33.1 + diff --git a/SOURCES/0034-Fix-the-logic-for-decoding-modifiers-map-in-Wayland-.patch b/SOURCES/0034-Fix-the-logic-for-decoding-modifiers-map-in-Wayland-.patch new file mode 100644 index 0000000..47ac957 --- /dev/null +++ b/SOURCES/0034-Fix-the-logic-for-decoding-modifiers-map-in-Wayland-.patch @@ -0,0 +1,40 @@ +From 02f9585ca19c17ae0978b864195533dc527d825e Mon Sep 17 00:00:00 2001 +From: Rodney Dawes +Date: Fri, 15 Oct 2021 12:55:33 -0400 +Subject: [PATCH 34/36] 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 +--- + src/client/qwaylandinputcontext.cpp | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp +index 503fd735..e290baa2 100644 +--- 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; + } +-- +2.33.1 + diff --git a/SOURCES/0035-Wayland-client-use-wl_keyboard-to-determine-active-s.patch b/SOURCES/0035-Wayland-client-use-wl_keyboard-to-determine-active-s.patch new file mode 100644 index 0000000..b8d1207 --- /dev/null +++ b/SOURCES/0035-Wayland-client-use-wl_keyboard-to-determine-active-s.patch @@ -0,0 +1,341 @@ +From 5c180bdc1042e7cb1555e188051f09e219b00ec9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?M=C3=A9ven=20Car?= +Date: Wed, 18 Aug 2021 18:28:20 +0200 +Subject: [PATCH 35/36] 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 +--- + src/client/qwaylanddisplay.cpp | 19 +++++++++++-------- + src/client/qwaylanddisplay_p.h | 1 + + src/client/qwaylandwindow.cpp | 13 +++++++++++-- + src/client/qwaylandwindow_p.h | 1 + + .../qwaylandshellintegration_p.h | 7 +++---- + .../qwaylandxdgshellv5integration.cpp | 7 ------- + .../qwaylandxdgshellv5integration_p.h | 1 - + .../qwaylandxdgshellv6integration.cpp | 14 -------------- + .../qwaylandxdgshellv6integration_p.h | 1 - + .../xdg-shell/qwaylandxdgshell.cpp | 16 +++++----------- + .../xdg-shell/qwaylandxdgshellintegration.cpp | 14 -------------- + .../xdg-shell/qwaylandxdgshellintegration_p.h | 1 - + tests/auto/client/xdgshell/tst_xdgshell.cpp | 10 +++++++--- + 13 files changed, 39 insertions(+), 66 deletions(-) + +diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp +index e0dfe8b2..27303110 100644 +--- 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() +diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h +index 3b092bc8..09a1736a 100644 +--- 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 condition, int timeout = -1); + ++ bool isKeyboardAvailable() const; + public slots: + void blockingReadEvents(); + void flushRequests(); +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index c020a58f..ba881cb3 100644 +--- a/src/client/qwaylandwindow.cpp ++++ b/src/client/qwaylandwindow.cpp +@@ -96,7 +96,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display) + QWaylandWindow::~QWaylandWindow() + { + mDisplay->destroyFrameQueue(mFrameQueue); +- mDisplay->handleWindowDestroyed(this); + + delete mWindowDecoration; + +@@ -266,6 +265,8 @@ void QWaylandWindow::reset() + + mMask = QRegion(); + mQueuedBuffer = nullptr; ++ ++ mDisplay->handleWindowDestroyed(this); + } + + QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface) +@@ -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; + } + +diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h +index 6cc1664b..e0687962 100644 +--- a/src/client/qwaylandwindow_p.h ++++ b/src/client/qwaylandwindow_p.h +@@ -148,6 +148,7 @@ public: + void setWindowState(Qt::WindowStates states) override; + void setWindowFlags(Qt::WindowFlags flags) override; + void handleWindowStatesChanged(Qt::WindowStates states); ++ Qt::WindowStates windowStates() const; + + void raise() override; + void lower() override; +diff --git a/src/client/shellintegration/qwaylandshellintegration_p.h b/src/client/shellintegration/qwaylandshellintegration_p.h +index ccad0048..4cc9b3b8 100644 +--- a/src/client/shellintegration/qwaylandshellintegration_p.h ++++ b/src/client/shellintegration/qwaylandshellintegration_p.h +@@ -73,11 +73,10 @@ public: + return true; + } + virtual QWaylandShellSurface *createShellSurface(QWaylandWindow *window) = 0; ++ // kept for binary compat with layer-shell-qt + virtual void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) { +- if (newFocus) +- m_display->handleWindowActivated(newFocus); +- if (oldFocus) +- m_display->handleWindowDeactivated(oldFocus); ++ Q_UNUSED(newFocus); ++ Q_UNUSED(oldFocus); + } + virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) { + Q_UNUSED(resource); +diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp +index 4e25949f..cfc60939 100644 +--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp ++++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp +@@ -85,13 +85,6 @@ QWaylandShellSurface *QWaylandXdgShellV5Integration::createShellSurface(QWayland + return m_xdgShell->createXdgSurface(window); + } + +-void QWaylandXdgShellV5Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) { +- if (newFocus && qobject_cast(newFocus->shellSurface())) +- m_display->handleWindowActivated(newFocus); +- if (oldFocus && qobject_cast(oldFocus->shellSurface())) +- m_display->handleWindowDeactivated(oldFocus); +-} +- + } + + QT_END_NAMESPACE +diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h +index ce6bdb9e..aed88670 100644 +--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h ++++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h +@@ -67,7 +67,6 @@ public: + QWaylandXdgShellV5Integration() {} + bool initialize(QWaylandDisplay *display) override; + QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override; +- void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override; + + private: + QScopedPointer m_xdgShell; +diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp +index 03164316..e8da8ba1 100644 +--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp ++++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp +@@ -68,20 +68,6 @@ QWaylandShellSurface *QWaylandXdgShellV6Integration::createShellSurface(QWayland + return m_xdgShell->getXdgSurface(window); + } + +-void QWaylandXdgShellV6Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) +-{ +- if (newFocus) { +- auto *xdgSurface = qobject_cast(newFocus->shellSurface()); +- if (xdgSurface && !xdgSurface->handlesActiveState()) +- m_display->handleWindowActivated(newFocus); +- } +- if (oldFocus && qobject_cast(oldFocus->shellSurface())) { +- auto *xdgSurface = qobject_cast(oldFocus->shellSurface()); +- if (xdgSurface && !xdgSurface->handlesActiveState()) +- m_display->handleWindowDeactivated(oldFocus); +- } +-} +- + } + + QT_END_NAMESPACE +diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h +index 261f8cbb..c1bcd5c6 100644 +--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h ++++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h +@@ -65,7 +65,6 @@ public: + QWaylandXdgShellV6Integration() {} + bool initialize(QWaylandDisplay *display) override; + QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override; +- void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override; + + private: + QScopedPointer m_xdgShell; +diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +index 7d33dabd..d7d0ddf7 100644 +--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp ++++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +@@ -67,11 +67,6 @@ QWaylandXdgSurface::Toplevel::Toplevel(QWaylandXdgSurface *xdgSurface) + + QWaylandXdgSurface::Toplevel::~Toplevel() + { +- if (m_applied.states & Qt::WindowActive) { +- QWaylandWindow *window = m_xdgSurface->window(); +- window->display()->handleWindowDeactivated(window); +- } +- + // The protocol spec requires that the decoration object is deleted before xdg_toplevel. + delete m_decoration; + m_decoration = nullptr; +@@ -85,16 +80,15 @@ void QWaylandXdgSurface::Toplevel::applyConfigure() + if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen))) + m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size(); + +- if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive)) ++ if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive) ++ && !m_xdgSurface->m_window->display()->isKeyboardAvailable()) + m_xdgSurface->m_window->display()->handleWindowActivated(m_xdgSurface->m_window); + +- if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive)) ++ if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive) ++ && !m_xdgSurface->m_window->display()->isKeyboardAvailable()) + m_xdgSurface->m_window->display()->handleWindowDeactivated(m_xdgSurface->m_window); + +- // TODO: none of the other plugins send WindowActive either, but is it on purpose? +- Qt::WindowStates statesWithoutActive = m_pending.states & ~Qt::WindowActive; +- +- m_xdgSurface->m_window->handleWindowStatesChanged(statesWithoutActive); ++ m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states); + + if (m_pending.size.isEmpty()) { + // An empty size in the configure means it's up to the client to choose the size +diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp +index 8769d971..da0dd6a7 100644 +--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp ++++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp +@@ -69,20 +69,6 @@ QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWi + return m_xdgShell->getXdgSurface(window); + } + +-void QWaylandXdgShellIntegration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) +-{ +- if (newFocus) { +- auto *xdgSurface = qobject_cast(newFocus->shellSurface()); +- if (xdgSurface && !xdgSurface->handlesActiveState()) +- m_display->handleWindowActivated(newFocus); +- } +- if (oldFocus && qobject_cast(oldFocus->shellSurface())) { +- auto *xdgSurface = qobject_cast(oldFocus->shellSurface()); +- if (xdgSurface && !xdgSurface->handlesActiveState()) +- m_display->handleWindowDeactivated(oldFocus); +- } +-} +- + } + + QT_END_NAMESPACE +diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h +index b6caa6c9..2f929f98 100644 +--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h ++++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h +@@ -65,7 +65,6 @@ public: + QWaylandXdgShellIntegration() {} + bool initialize(QWaylandDisplay *display) override; + QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override; +- void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override; + + private: + QScopedPointer m_xdgShell; +diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp +index e2593314..73d1eb9c 100644 +--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp ++++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + 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(window.handle()); ++ Q_ASSERT(waylandWindow); ++ QTRY_VERIFY(waylandWindow->windowStates().testFlag( ++ Qt::WindowActive)); // Just make sure it eventually get's set correctly + + const QSize screenSize(640, 480); + const uint maximizedSerial = exec([=] { +-- +2.33.1 + diff --git a/SOURCES/0036-Client-do-not-empty-clipboard-when-a-new-popup-windo.patch b/SOURCES/0036-Client-do-not-empty-clipboard-when-a-new-popup-windo.patch new file mode 100644 index 0000000..c0cbefc --- /dev/null +++ b/SOURCES/0036-Client-do-not-empty-clipboard-when-a-new-popup-windo.patch @@ -0,0 +1,68 @@ +From 992833ca741efe8f533c61abfaf129a1d8bfcfee Mon Sep 17 00:00:00 2001 +From: Jan Grulich +Date: Fri, 16 Jul 2021 13:00:03 +0200 +Subject: [PATCH 36/36] 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 +Reviewed-by: David Edmundson + +Cherry-pick: 1e57ebd501cfc2255300392cd4565cd034efeed8 +--- + src/client/qwaylanddisplay.cpp | 13 +++++++++++++ + src/client/qwaylandinputdevice.cpp | 8 -------- + 2 files changed, 13 insertions(+), 8 deletions(-) + +diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp +index 27303110..9f595af3 100644 +--- 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 = { +diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp +index ae045f4f..514457e9 100644 +--- 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(); + } +-- +2.33.1 + diff --git a/SOURCES/0037-Fix-backport-context-destruction-was-omitted.patch b/SOURCES/0037-Fix-backport-context-destruction-was-omitted.patch new file mode 100644 index 0000000..6fd052d --- /dev/null +++ b/SOURCES/0037-Fix-backport-context-destruction-was-omitted.patch @@ -0,0 +1,29 @@ +From eb422ab5e07498a7a8d086f6a942ee35ab3c9776 Mon Sep 17 00:00:00 2001 +From: Aleix Pol +Date: Thu, 9 Dec 2021 17:35:24 +0100 +Subject: [PATCH 37/41] Fix backport, context destruction was omitted + +When cherry-picking for 9df11e79b46c77d8c83f765b2a8e85b639fd55a2, this +line got removed when rebasing the patch, which created a leak. + +BUG: 442844 +Change-Id: Id00e8b194dcd910c5f01ce9d2cc318f96a4129a2 +--- + src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +index 95d1049c..683fe123 100644 +--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp ++++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +@@ -407,6 +407,7 @@ QWaylandGLContext::~QWaylandGLContext() + { + delete m_blitter; + m_blitter = nullptr; ++ eglDestroyContext(m_eglDisplay, m_context); + if (m_decorationsContext != EGL_NO_CONTEXT) + eglDestroyContext(m_eglDisplay, m_decorationsContext); + } +-- +2.34.1 + diff --git a/SOURCES/0038-Set-preedit-cursor-when-cursor-equals-to-0.patch b/SOURCES/0038-Set-preedit-cursor-when-cursor-equals-to-0.patch new file mode 100644 index 0000000..352d13d --- /dev/null +++ b/SOURCES/0038-Set-preedit-cursor-when-cursor-equals-to-0.patch @@ -0,0 +1,29 @@ +From e0646f531e1e73a90a93faaa45d933ae40769985 Mon Sep 17 00:00:00 2001 +From: Weng Xuetian +Date: Sat, 18 Dec 2021 23:42:49 -0800 +Subject: [PATCH 38/41] Set preedit cursor when cursor equals to 0 + +Pick-to: 6.3 6.2 5.15 +Change-Id: I832fbb22d973b36ac4ab51570fc53bc2e4c3ed58 +Reviewed-by: Liang Qi +(cherry picked from commit 719a55be13bdadfa659a732755f280e276a894bd) +--- + src/shared/qwaylandinputmethodeventbuilder.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/qwaylandinputmethodeventbuilder.cpp b/src/shared/qwaylandinputmethodeventbuilder.cpp +index 526d0ef4..25be2509 100644 +--- a/src/shared/qwaylandinputmethodeventbuilder.cpp ++++ b/src/shared/qwaylandinputmethodeventbuilder.cpp +@@ -151,7 +151,7 @@ QInputMethodEvent QWaylandInputMethodEventBuilder::buildPreedit(const QString &t + { + QList attributes; + +- if (m_preeditCursor < 0) { ++ if (m_preeditCursor <= 0) { + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant())); + } else if (m_preeditCursor > 0) { + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, indexFromWayland(text, m_preeditCursor), 1, QVariant())); +-- +2.34.1 + diff --git a/SOURCES/0039-Client-Implement-DataDeviceV3.patch b/SOURCES/0039-Client-Implement-DataDeviceV3.patch new file mode 100644 index 0000000..0efe269 --- /dev/null +++ b/SOURCES/0039-Client-Implement-DataDeviceV3.patch @@ -0,0 +1,513 @@ +From 2044603ebb5ae70c785d50968ac620b842c2b14e Mon Sep 17 00:00:00 2001 +From: David Edmundson +Date: Tue, 16 Feb 2021 09:51:47 +0000 +Subject: [PATCH 39/41] Client: Implement DataDeviceV3 + +DataDeviceV2 fixes a leak of DataDevice resources. + +DataDeviceV3 brings multiple improvements: + +Action negotiation. The source announces which actions are supported, +the target then announces which subset of those action the target +supports and a preferred action. After negotiation both the source and +target are notified of which action is to be performed. + +Drag sources are now notified when contents are dropped and when a +client has finished with the drag and drop operation. + +A good test is the draggableicons example in QtBase. + +Change-Id: I55e9759ca5a2e4218d02d863144a64ade53ef764 +Reviewed-by: Eskil Abrahamsen Blomfeldt +(cherry picked from commit 283a2d61d03315495a52d82f356e7cb5292f4bb4) +--- + src/client/qwaylanddatadevice.cpp | 84 ++++++++++++++----- + src/client/qwaylanddatadevice_p.h | 8 +- + src/client/qwaylanddatadevicemanager.cpp | 4 +- + src/client/qwaylanddatadevicemanager_p.h | 2 +- + src/client/qwaylanddataoffer.cpp | 25 ++++++ + src/client/qwaylanddataoffer_p.h | 4 + + src/client/qwaylanddatasource.cpp | 27 +++++- + src/client/qwaylanddatasource_p.h | 10 ++- + src/client/qwaylanddisplay.cpp | 2 +- + src/client/qwaylanddnd.cpp | 24 +++--- + src/client/qwaylanddnd_p.h | 7 +- + .../client/datadevicev1/tst_datadevicev1.cpp | 2 +- + 12 files changed, 153 insertions(+), 46 deletions(-) + +diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp +index bbd2d568..fbb5aa91 100644 +--- a/src/client/qwaylanddatadevice.cpp ++++ b/src/client/qwaylanddatadevice.cpp +@@ -72,6 +72,8 @@ QWaylandDataDevice::QWaylandDataDevice(QWaylandDataDeviceManager *manager, QWayl + + QWaylandDataDevice::~QWaylandDataDevice() + { ++ if (wl_data_device_get_version(object()) >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION) ++ release(); + } + + QWaylandDataOffer *QWaylandDataDevice::selectionOffer() const +@@ -110,7 +112,7 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const + return m_dragOffer.data(); + } + +-bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon) ++bool QWaylandDataDevice::startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon) + { + auto *seat = m_display->currentInputDevice(); + auto *origin = seat->pointerFocus(); +@@ -123,8 +125,28 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon) + } + + m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData)); ++ ++ if (wl_data_device_get_version(object()) >= 3) ++ m_dragSource->set_actions(dropActionsToWl(supportedActions)); ++ + connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled); +- connect(m_dragSource.data(), &QWaylandDataSource::targetChanged, this, &QWaylandDataDevice::dragSourceTargetChanged); ++ connect(m_dragSource.data(), &QWaylandDataSource::dndResponseUpdated, this, [this](bool accepted, Qt::DropAction action) { ++ auto drag = static_cast(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(QGuiApplicationPrivate::platformIntegration()->drag())->setDropResponse(response); ++ }); ++ connect(m_dragSource.data(), &QWaylandDataSource::finished, this, []() { ++ static_cast(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(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag(response); ++ auto drag = static_cast(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(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(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(QGuiApplicationPrivate::platformIntegration()->drag())->updateTarget(mimeType); +-} +- + QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) const + { + QPoint pnt(wl_fixed_to_int(x), wl_fixed_to_int(y)); +@@ -298,6 +311,33 @@ QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) con + } + return pnt; + } ++ ++void QWaylandDataDevice::sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response) ++{ ++ if (response.isAccepted()) { ++ if (wl_data_device_get_version(object()) >= 3) ++ m_dragOffer->set_actions(dropActionsToWl(supportedActions), dropActionsToWl(response.acceptedAction())); ++ ++ m_dragOffer->accept(m_enterSerial, m_dragOffer->firstFormat()); ++ } else { ++ m_dragOffer->accept(m_enterSerial, QString()); ++ } ++} ++ ++int QWaylandDataDevice::dropActionsToWl(Qt::DropActions actions) ++{ ++ ++ int wlActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; ++ if (actions & Qt::CopyAction) ++ wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; ++ if (actions & (Qt::MoveAction | Qt::TargetMoveAction)) ++ wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; ++ ++ // wayland does not support LinkAction at the time of writing ++ return wlActions; ++} ++ ++ + #endif // QT_CONFIG(draganddrop) + + } +diff --git a/src/client/qwaylanddatadevice_p.h b/src/client/qwaylanddatadevice_p.h +index 16c3ad28..801dcc2c 100644 +--- a/src/client/qwaylanddatadevice_p.h ++++ b/src/client/qwaylanddatadevice_p.h +@@ -64,6 +64,7 @@ QT_REQUIRE_CONFIG(wayland_datadevice); + QT_BEGIN_NAMESPACE + + class QMimeData; ++class QPlatformDragQtResponse; + class QWindow; + + namespace QtWaylandClient { +@@ -89,7 +90,7 @@ public: + + #if QT_CONFIG(draganddrop) + QWaylandDataOffer *dragOffer() const; +- bool startDrag(QMimeData *mimeData, QWaylandWindow *icon); ++ bool startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon); + void cancelDrag(); + #endif + +@@ -109,13 +110,16 @@ private Q_SLOTS: + + #if QT_CONFIG(draganddrop) + void dragSourceCancelled(); +- void dragSourceTargetChanged(const QString &mimeType); + #endif + + private: + #if QT_CONFIG(draganddrop) + QPoint calculateDragPosition(int x, int y, QWindow *wnd) const; + #endif ++ void sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response); ++ ++ static int dropActionsToWl(Qt::DropActions dropActions); ++ + + QWaylandDisplay *m_display = nullptr; + QWaylandInputDevice *m_inputDevice = nullptr; +diff --git a/src/client/qwaylanddatadevicemanager.cpp b/src/client/qwaylanddatadevicemanager.cpp +index 35d67307..6dc4f77f 100644 +--- a/src/client/qwaylanddatadevicemanager.cpp ++++ b/src/client/qwaylanddatadevicemanager.cpp +@@ -50,8 +50,8 @@ QT_BEGIN_NAMESPACE + + namespace QtWaylandClient { + +-QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id) +- : wl_data_device_manager(display->wl_registry(), id, 1) ++QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id) ++ : wl_data_device_manager(display->wl_registry(), id, qMin(version, 3)) + , m_display(display) + { + // Create transfer devices for all input devices. +diff --git a/src/client/qwaylanddatadevicemanager_p.h b/src/client/qwaylanddatadevicemanager_p.h +index bd05c0fb..510d9be4 100644 +--- a/src/client/qwaylanddatadevicemanager_p.h ++++ b/src/client/qwaylanddatadevicemanager_p.h +@@ -68,7 +68,7 @@ class QWaylandInputDevice; + class Q_WAYLAND_CLIENT_EXPORT QWaylandDataDeviceManager : public QtWayland::wl_data_device_manager + { + public: +- QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id); ++ QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id); + ~QWaylandDataDeviceManager() override; + + QWaylandDataDevice *getDataDevice(QWaylandInputDevice *inputDevice); +diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp +index 2297e8a1..c9e158cc 100644 +--- a/src/client/qwaylanddataoffer.cpp ++++ b/src/client/qwaylanddataoffer.cpp +@@ -82,6 +82,15 @@ QMimeData *QWaylandDataOffer::mimeData() + return m_mimeData.data(); + } + ++Qt::DropActions QWaylandDataOffer::supportedActions() const ++{ ++ if (wl_data_offer_get_version(const_cast<::wl_data_offer*>(object())) < 3) { ++ return Qt::MoveAction | Qt::CopyAction; ++ } ++ ++ return m_supportedActions; ++} ++ + void QWaylandDataOffer::startReceiving(const QString &mimeType, int fd) + { + receive(mimeType, fd); +@@ -93,6 +102,22 @@ void QWaylandDataOffer::data_offer_offer(const QString &mime_type) + m_mimeData->appendFormat(mime_type); + } + ++void QWaylandDataOffer::data_offer_action(uint32_t dnd_action) ++{ ++ Q_UNUSED(dnd_action); ++ // This is the compositor telling the drag target what action it should perform ++ // It does not map nicely into Qt final drop semantics, other than pretending there is only one supported action? ++} ++ ++void QWaylandDataOffer::data_offer_source_actions(uint32_t source_actions) ++{ ++ m_supportedActions = Qt::DropActions(); ++ if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) ++ m_supportedActions |= Qt::MoveAction; ++ if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) ++ m_supportedActions |= Qt::CopyAction; ++} ++ + QWaylandMimeData::QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer) + : m_dataOffer(dataOffer) + { +diff --git a/src/client/qwaylanddataoffer_p.h b/src/client/qwaylanddataoffer_p.h +index 9cf1483c..6f667398 100644 +--- a/src/client/qwaylanddataoffer_p.h ++++ b/src/client/qwaylanddataoffer_p.h +@@ -82,6 +82,7 @@ public: + explicit QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer); + ~QWaylandDataOffer() override; + QMimeData *mimeData() override; ++ Qt::DropActions supportedActions() const; + + QString firstFormat() const; + +@@ -89,10 +90,13 @@ public: + + protected: + void data_offer_offer(const QString &mime_type) override; ++ void data_offer_source_actions(uint32_t source_actions) override; ++ void data_offer_action(uint32_t dnd_action) override; + + private: + QWaylandDisplay *m_display = nullptr; + QScopedPointer m_mimeData; ++ Qt::DropActions m_supportedActions; + }; + + +diff --git a/src/client/qwaylanddatasource.cpp b/src/client/qwaylanddatasource.cpp +index f45122fb..5599cbd4 100644 +--- a/src/client/qwaylanddatasource.cpp ++++ b/src/client/qwaylanddatasource.cpp +@@ -101,7 +101,32 @@ void QWaylandDataSource::data_source_send(const QString &mime_type, int32_t fd) + + void QWaylandDataSource::data_source_target(const QString &mime_type) + { +- Q_EMIT targetChanged(mime_type); ++ m_accepted = !mime_type.isEmpty(); ++ Q_EMIT dndResponseUpdated(m_accepted, m_dropAction); ++} ++ ++void QWaylandDataSource::data_source_action(uint32_t action) ++{ ++ Qt::DropAction qtAction = Qt::IgnoreAction; ++ ++ if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) ++ qtAction = Qt::MoveAction; ++ else if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) ++ qtAction = Qt::CopyAction; ++ ++ m_dropAction = qtAction; ++ Q_EMIT dndResponseUpdated(m_accepted, m_dropAction); ++} ++ ++void QWaylandDataSource::data_source_dnd_finished() ++{ ++ Q_EMIT finished(); ++} ++ ++void QWaylandDataSource::data_source_dnd_drop_performed() ++{ ++ ++ Q_EMIT dndDropped(m_accepted, m_dropAction); + } + + } +diff --git a/src/client/qwaylanddatasource_p.h b/src/client/qwaylanddatasource_p.h +index 25afff79..96f07bc3 100644 +--- a/src/client/qwaylanddatasource_p.h ++++ b/src/client/qwaylanddatasource_p.h +@@ -77,17 +77,25 @@ public: + QMimeData *mimeData() const; + + Q_SIGNALS: +- void targetChanged(const QString &mime_type); + void cancelled(); ++ void finished(); ++ ++ void dndResponseUpdated(bool accepted, Qt::DropAction action); ++ void dndDropped(bool accepted, Qt::DropAction action); + + protected: + void data_source_cancelled() override; + void data_source_send(const QString &mime_type, int32_t fd) override; + void data_source_target(const QString &mime_type) override; ++ void data_source_dnd_drop_performed() override; ++ void data_source_dnd_finished() override; ++ void data_source_action(uint32_t action) override; + + private: + QWaylandDisplay *m_display = nullptr; + QMimeData *m_mime_data = nullptr; ++ bool m_accepted = false; ++ Qt::DropAction m_dropAction = Qt::IgnoreAction; + }; + + } +diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp +index 9f595af3..ea344c61 100644 +--- a/src/client/qwaylanddisplay.cpp ++++ b/src/client/qwaylanddisplay.cpp +@@ -354,7 +354,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin + mInputDevices.append(inputDevice); + #if QT_CONFIG(wayland_datadevice) + } else if (interface == QStringLiteral("wl_data_device_manager")) { +- mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id)); ++ mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, version, id)); + #endif + } else if (interface == QStringLiteral("qt_surface_extension")) { + mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1)); +diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp +index 6535aa16..97ee5b2e 100644 +--- a/src/client/qwaylanddnd.cpp ++++ b/src/client/qwaylanddnd.cpp +@@ -66,7 +66,7 @@ void QWaylandDrag::startDrag() + { + QBasicDrag::startDrag(); + QWaylandWindow *icon = static_cast(shapedPixmapWindow()->handle()); +- if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) { ++ if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), drag()->supportedActions(), icon)) { + icon->addAttachOffset(-drag()->hotSpot()); + } else { + // Cancelling immediately does not work, since the event loop for QDrag::exec is started +@@ -103,31 +103,31 @@ void QWaylandDrag::endDrag() + m_display->currentInputDevice()->handleEndDrag(); + } + +-void QWaylandDrag::updateTarget(const QString &mimeType) ++void QWaylandDrag::setResponse(bool accepted) + { +- setCanDrop(!mimeType.isEmpty()); +- +- if (canDrop()) { +- updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers())); +- } else { +- updateCursor(Qt::IgnoreAction); +- } ++ // This method is used for old DataDevices where the drag action is not communicated ++ Qt::DropAction action = defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()); ++ setResponse(QPlatformDropQtResponse(accepted, action)); + } + +-void QWaylandDrag::setResponse(const QPlatformDragQtResponse &response) ++void QWaylandDrag::setResponse(const QPlatformDropQtResponse &response) + { + setCanDrop(response.isAccepted()); + + if (canDrop()) { +- updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers())); ++ updateCursor(response.acceptedAction()); + } else { + updateCursor(Qt::IgnoreAction); + } + } + +-void QWaylandDrag::finishDrag(const QPlatformDropQtResponse &response) ++void QWaylandDrag::setDropResponse(const QPlatformDropQtResponse &response) + { + setExecutedDropAction(response.acceptedAction()); ++} ++ ++void QWaylandDrag::finishDrag() ++{ + QKeyEvent event(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier); + eventFilter(shapedPixmapWindow(), &event); + } +diff --git a/src/client/qwaylanddnd_p.h b/src/client/qwaylanddnd_p.h +index 474fe2ab..747f0190 100644 +--- a/src/client/qwaylanddnd_p.h ++++ b/src/client/qwaylanddnd_p.h +@@ -71,9 +71,10 @@ public: + QWaylandDrag(QWaylandDisplay *display); + ~QWaylandDrag() override; + +- void updateTarget(const QString &mimeType); +- void setResponse(const QPlatformDragQtResponse &response); +- void finishDrag(const QPlatformDropQtResponse &response); ++ void setResponse(bool accepted); ++ void setResponse(const QPlatformDropQtResponse &response); ++ void setDropResponse(const QPlatformDropQtResponse &response); ++ void finishDrag(); + + protected: + void startDrag() override; +diff --git a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp +index 1568b3b9..067410d0 100644 +--- a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp ++++ b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp +@@ -35,7 +35,7 @@ + + using namespace MockCompositor; + +-constexpr int dataDeviceVersion = 1; ++constexpr int dataDeviceVersion = 3; + + class DataDeviceCompositor : public DefaultCompositor { + public: +-- +2.34.1 + diff --git a/SOURCES/0040-Client-Delay-deletion-of-QDrag-object-until-after-we.patch b/SOURCES/0040-Client-Delay-deletion-of-QDrag-object-until-after-we.patch new file mode 100644 index 0000000..537286a --- /dev/null +++ b/SOURCES/0040-Client-Delay-deletion-of-QDrag-object-until-after-we.patch @@ -0,0 +1,67 @@ +From 0b15df7e9e26a4edfc2277eb3ec7b3d5c58a5dcd Mon Sep 17 00:00:00 2001 +From: Arjen Hiemstra +Date: Thu, 18 Nov 2021 13:05:30 +0100 +Subject: [PATCH 40/41] 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 +(cherry picked from commit 39e3290efa2dd40722fa3322284cae3b01ccedf4) +--- + src/client/qwaylanddnd.cpp | 11 +++++++++++ + src/client/qwaylanddnd_p.h | 1 + + 2 files changed, 12 insertions(+) + +diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp +index 97ee5b2e..7c53f5fa 100644 +--- a/src/client/qwaylanddnd.cpp ++++ b/src/client/qwaylanddnd.cpp +@@ -80,6 +80,9 @@ void QWaylandDrag::cancel() + QBasicDrag::cancel(); + + m_display->currentInputDevice()->dataDevice()->cancelDrag(); ++ ++ if (drag()) ++ drag()->deleteLater(); + } + + void QWaylandDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +@@ -130,6 +133,14 @@ void QWaylandDrag::finishDrag() + { + QKeyEvent event(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier); + eventFilter(shapedPixmapWindow(), &event); ++ ++ if (drag()) ++ drag()->deleteLater(); ++} ++ ++bool QWaylandDrag::ownsDragObject() const ++{ ++ return true; + } + + } +diff --git a/src/client/qwaylanddnd_p.h b/src/client/qwaylanddnd_p.h +index 747f0190..46f629ac 100644 +--- a/src/client/qwaylanddnd_p.h ++++ b/src/client/qwaylanddnd_p.h +@@ -83,6 +83,7 @@ protected: + void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override; + void endDrag() override; + ++ bool ownsDragObject() const override; + + private: + QWaylandDisplay *m_display = nullptr; +-- +2.34.1 + diff --git a/SOURCES/0041-Client-Avoid-processing-of-events-when-showing-windo.patch b/SOURCES/0041-Client-Avoid-processing-of-events-when-showing-windo.patch new file mode 100644 index 0000000..7e683b8 --- /dev/null +++ b/SOURCES/0041-Client-Avoid-processing-of-events-when-showing-windo.patch @@ -0,0 +1,38 @@ +From 867540b9d913760a847ff67c8694d817c821f2c2 Mon Sep 17 00:00:00 2001 +From: David Edmundson +Date: Sun, 14 Nov 2021 13:54:19 +0000 +Subject: [PATCH 41/41] 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 +Reviewed-by: Aleix Pol Gonzalez +(cherry picked from commit 46ed85a80b28d519cf5887bbdce55d1bf57886c3) +--- + src/client/qwaylandwindow.cpp | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index ba881cb3..1597f67e 100644 +--- a/src/client/qwaylandwindow.cpp ++++ b/src/client/qwaylandwindow.cpp +@@ -436,7 +436,6 @@ void QWaylandWindow::setVisible(bool visible) + if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip) + activePopups << this; + initWindow(); +- mDisplay->flushRequests(); + + setGeometry(windowGeometry()); + // Don't flush the events here, or else the newly visible window may start drawing, but since +-- +2.34.1 + diff --git a/SOURCES/qtwayland-fix-issue-with-repeated-window-size-changes.patch b/SOURCES/qtwayland-fix-issue-with-repeated-window-size-changes.patch deleted file mode 100644 index 7e6dee7..0000000 --- a/SOURCES/qtwayland-fix-issue-with-repeated-window-size-changes.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 14d066c61025e548227ccd8d655e80ffa31fa15e Mon Sep 17 00:00:00 2001 -From: Jaeyoon Jung -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 ---- - .../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 1e8dc06f7..355aca864 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 5b1f4d56f..0079dfef8 100644 ---- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h -+++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h -@@ -88,6 +88,7 @@ class QWaylandEglWindow : public QWaylandWindow - mutable QOpenGLFramebufferObject *m_contentFBO = nullptr; - - QSurfaceFormat m_format; -+ QSize m_requestedSize; - }; - - } diff --git a/SOURCES/qtwayland-get-correct-margins-decoration-region.patch b/SOURCES/qtwayland-get-correct-margins-decoration-region.patch deleted file mode 100644 index 1f87e2e..0000000 --- a/SOURCES/qtwayland-get-correct-margins-decoration-region.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 14cf9f0e45c7617d787eba8d81bf9fd1cd66754b Mon Sep 17 00:00:00 2001 -From: Jan Grulich -Date: Thu, 11 Feb 2021 15:12:32 +0100 -Subject: [PATCH] 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 -Change-Id: Id1b7f4cd2a7b894b82db09c5af2b2d1f1f43fa2a ---- - -diff --git a/src/client/qwaylandabstractdecoration.cpp b/src/client/qwaylandabstractdecoration.cpp -index 87dd6ce..b6ee43c 100644 ---- a/src/client/qwaylandabstractdecoration.cpp -+++ b/src/client/qwaylandabstractdecoration.cpp -@@ -108,11 +108,11 @@ - 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; - } - diff --git a/SOURCES/qtwayland-scanner-avoid-accessing-dangling-pointers-in-destroy-func.patch b/SOURCES/qtwayland-scanner-avoid-accessing-dangling-pointers-in-destroy-func.patch deleted file mode 100644 index 823f648..0000000 --- a/SOURCES/qtwayland-scanner-avoid-accessing-dangling-pointers-in-destroy-func.patch +++ /dev/null @@ -1,32 +0,0 @@ -From e5c272423d1bba2825086b82fd97499237a6fa4b Mon Sep 17 00:00:00 2001 -From: Vlad Zahorodnii -Date: Fri, 30 Oct 2020 16:55:30 +0200 -Subject: [PATCH] Scanner: Avoid accessing dangling pointers in destroy_func() - -Usually, the object associated with the resource gets destroyed in the -destroy_resource() function. - -Therefore, we need to double-check that the object is still alive before -trying to reset its m_resource. - -Change-Id: I26408228f58919db17eb29584a1cbd4a9427d25c -Reviewed-by: Eskil Abrahamsen Blomfeldt -(cherry picked from commit 735164b5c2a2637a8d53a8803a2401e4ef477ff0) -Reviewed-by: Qt Cherry-pick Bot ---- - -diff --git a/src/qtwaylandscanner/qtwaylandscanner.cpp b/src/qtwaylandscanner/qtwaylandscanner.cpp -index 1d635f0..e2f87bb 100644 ---- a/src/qtwaylandscanner/qtwaylandscanner.cpp -+++ b/src/qtwaylandscanner/qtwaylandscanner.cpp -@@ -814,7 +814,9 @@ - printf(" if (Q_LIKELY(that)) {\n"); - printf(" that->m_resource_map.remove(resource->client(), resource);\n"); - printf(" that->%s_destroy_resource(resource);\n", interfaceNameStripped); -- printf(" if (that->m_resource == resource)\n"); -+ printf("\n"); -+ printf(" that = resource->%s_object;\n", interfaceNameStripped); -+ printf(" if (that && that->m_resource == resource)\n"); - printf(" that->m_resource = nullptr;\n"); - printf(" }\n"); - printf(" delete resource;\n"); diff --git a/SOURCES/qtwayland-send-exposeevent-to-parent-on-subsurface-position.patch b/SOURCES/qtwayland-send-exposeevent-to-parent-on-subsurface-position.patch deleted file mode 100644 index 980e223..0000000 --- a/SOURCES/qtwayland-send-exposeevent-to-parent-on-subsurface-position.patch +++ /dev/null @@ -1,94 +0,0 @@ -From b36a345d727eab37ee4ec4c2dc4674d5971c81d8 Mon Sep 17 00:00:00 2001 -From: David Edmundson -Date: Mon, 14 Sep 2020 17:08:39 +0100 -Subject: [PATCH] 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 3e26384..3cf1326 100644 ---- a/src/client/qwaylandwindow.cpp -+++ b/src/client/qwaylandwindow.cpp -@@ -339,7 +339,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 b8a65f1..95e4e60 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) diff --git a/SOURCES/qtwayland-send-set-window-geometry-only-once-configured.patch b/SOURCES/qtwayland-send-set-window-geometry-only-once-configured.patch deleted file mode 100644 index 40d32be..0000000 --- a/SOURCES/qtwayland-send-set-window-geometry-only-once-configured.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 2555663c9f59b93f5fcc5d3ead233bee280e36f8 Mon Sep 17 00:00:00 2001 -From: David Edmundson -Date: Mon, 16 Nov 2020 14:57:36 +0000 -Subject: [PATCH] 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 3e26384..80e9ffc 100644 ---- a/src/client/qwaylandwindow.cpp -+++ b/src/client/qwaylandwindow.cpp -@@ -362,7 +362,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()) diff --git a/SOURCES/qtwayland-tell-compositor-screen-we-are-expecting-to-fill.patch b/SOURCES/qtwayland-tell-compositor-screen-we-are-expecting-to-fill.patch deleted file mode 100644 index 5a6f1e2..0000000 --- a/SOURCES/qtwayland-tell-compositor-screen-we-are-expecting-to-fill.patch +++ /dev/null @@ -1,38 +0,0 @@ -From f915e53eaa596654ee1b9726a4767a1cba11336f Mon Sep 17 00:00:00 2001 -From: Aleix Pol -Date: Mon, 23 Nov 2020 20:07:02 +0100 -Subject: [PATCH] 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 b7253de2b..af8bd9264 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(); - } - diff --git a/SOURCES/qtwayland-translate-opaque-area-for-decorations.patch b/SOURCES/qtwayland-translate-opaque-area-for-decorations.patch deleted file mode 100644 index b897b55..0000000 --- a/SOURCES/qtwayland-translate-opaque-area-for-decorations.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 1e0862acdc2e6ccf77bf3a1436b877d3af5e5fe7 Mon Sep 17 00:00:00 2001 -From: Jan Grulich -Date: Wed, 10 Feb 2021 17:11:27 +0100 -Subject: [PATCH] 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 -Change-Id: I1606e8256e7e204dad927931eb1221b576e227fd ---- - -diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp -index 04c2dbd..b29edfa 100644 ---- a/src/client/qwaylandwindow.cpp -+++ b/src/client/qwaylandwindow.cpp -@@ -1242,12 +1242,14 @@ - - 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); - } diff --git a/SPECS/qt5-qtwayland.spec b/SPECS/qt5-qtwayland.spec index b58590a..249539d 100644 --- a/SPECS/qt5-qtwayland.spec +++ b/SPECS/qt5-qtwayland.spec @@ -5,20 +5,59 @@ Summary: Qt5 - Wayland platform support and QtCompositor module Name: qt5-%{qt_module} Version: 5.15.2 -Release: 2%{?dist} +Release: 3%{?dist} License: LGPLv3 Url: http://www.qt.io %global majmin %(echo %{version} | cut -d. -f1-2) Source0: https://download.qt.io/official_releases/qt/%{majmin}/%{version}/submodules/%{qt_module}-everywhere-src-%{version}.tar.xz -Patch0: qtwayland-scanner-avoid-accessing-dangling-pointers-in-destroy-func.patch -Patch1: qtwayland-fix-issue-with-repeated-window-size-changes.patch -Patch2: qtwayland-get-correct-margins-decoration-region.patch -Patch3: qtwayland-send-exposeevent-to-parent-on-subsurface-position.patch -Patch4: qtwayland-send-set-window-geometry-only-once-configured.patch -Patch5: qtwayland-tell-compositor-screen-we-are-expecting-to-fill.patch -Patch6: qtwayland-translate-opaque-area-for-decorations.patch +## Upstream patches +## repo: https://invent.kde.org/qt/qt/qtwayland +## branch: kde/5.15 +## git format-patch v5.15.2 +## These are already included in stock 5.15.2 tarball, referenced here for completeness +#Patch1: 0001-Bump-version.patch +#Patch2: 0002-Replace-remaining-LGPLv3-headers-in-QtWaylandComposi.patch +#Patch3: 0003-Doc-List-correct-license-information-for-the-module.patch +#Patch4: 0004-Add-changes-file-for-Qt-5.15.2.patch +Patch5: 0005-Scanner-Avoid-accessing-dangling-pointers-in-destroy.patch +Patch6: 0006-Make-setting-QT_SCALE_FACTOR-work-on-Wayland.patch +Patch7: 0007-Do-not-try-to-eglMakeCurrent-for-unintended-case.patch +Patch8: 0008-Make-setting-QT_SCALE_FACTOR-work-on-Wayland.patch +Patch9: 0009-Ensure-that-grabbing-is-performed-in-correct-context.patch +Patch10: 0010-Fix-leaked-subsurface-wayland-items.patch +Patch11: 0011-Use-qWarning-and-_exit-instead-of-qFatal-for-wayland.patch +Patch12: 0012-Fix-memory-leak-in-QWaylandGLContext.patch +Patch13: 0013-Client-Send-set_window_geometry-only-once-configured.patch +Patch14: 0014-Translate-opaque-area-with-frame-margins.patch +Patch15: 0015-Client-Send-exposeEvent-to-parent-on-subsurface-posi.patch +Patch16: 0016-Get-correct-decoration-margins-region.patch +Patch17: 0017-xdgshell-Tell-the-compositor-the-screen-we-re-expect.patch +Patch18: 0018-Fix-compilation.patch +Patch19: 0019-client-Allow-QWaylandInputContext-to-accept-composed.patch +Patch20: 0020-Client-Announce-an-output-after-receiving-more-compl.patch +Patch21: 0021-Fix-issue-with-repeated-window-size-changes.patch +Patch22: 0022-Include-locale.h-for-setlocale-LC_CTYPE.patch +Patch23: 0023-Client-Connect-drags-being-accepted-to-updating-the-.patch +Patch24: 0024-Client-Disconnect-registry-listener-on-destruction.patch +Patch25: 0025-Client-Set-XdgShell-size-hints-before-the-first-comm.patch +Patch26: 0026-Fix-build.patch +Patch27: 0027-Fix-remove-listener.patch +Patch28: 0028-Hook-up-queryKeyboardModifers.patch +Patch29: 0029-Do-not-update-the-mask-if-we-do-not-have-a-surface.patch +Patch30: 0030-Correctly-detect-if-image-format-is-supported-by-QIm.patch +Patch31: 0031-Wayland-client-Fix-crash-when-windows-are-shown-hidd.patch +Patch32: 0032-Client-Don-t-always-recreate-frame-callbacks.patch +Patch33: 0033-Client-Always-destroy-frame-callback-in-the-actual-c.patch +Patch34: 0034-Fix-the-logic-for-decoding-modifiers-map-in-Wayland-.patch +Patch35: 0035-Wayland-client-use-wl_keyboard-to-determine-active-s.patch +Patch36: 0036-Client-do-not-empty-clipboard-when-a-new-popup-windo.patch +Patch37: 0037-Fix-backport-context-destruction-was-omitted.patch +Patch38: 0038-Set-preedit-cursor-when-cursor-equals-to-0.patch +Patch39: 0039-Client-Implement-DataDeviceV3.patch +Patch40: 0040-Client-Delay-deletion-of-QDrag-object-until-after-we.patch +Patch41: 0041-Client-Avoid-processing-of-events-when-showing-windo.patch # filter qml provides %global __provides_exclude_from ^%{_qt5_archdatadir}/qml/.*\\.so$ @@ -151,6 +190,10 @@ popd %endif %changelog +* Tue Jan 18 2022 Jan Grulich - 5.15.2-3 +- Pull in latest kde/5.15 branch fixes + Resolves: bz#2021761 + * Wed Apr 28 2021 Jan Grulich - 5.15.2-2 - Rebuild (binutils) Resolves: bz#1930058