Compare commits

..

1 commit

Author SHA1 Message Date
Jan Grulich
e511e91dea HTTP2: Delay any communication until encrypted() can be responded to
Resolves: CVE-2024-39936
2024-07-10 10:58:02 +02:00
12 changed files with 472 additions and 1182 deletions

13
.gitignore vendored
View file

@ -26,16 +26,3 @@
/qtbase-everywhere-src-6.6.0.tar.xz
/qtbase-everywhere-src-6.6.1.tar.xz
/qtbase-everywhere-src-6.6.2.tar.xz
/qtbase-everywhere-src-6.7.0.tar.xz
/qtbase-everywhere-src-6.7.1.tar.xz
/qtbase-everywhere-src-6.7.2.tar.xz
/qtbase-everywhere-src-6.8.0.tar.xz
/qtbase-everywhere-src-6.8.1.tar.xz
/qtbase-everywhere-src-6.8.2.tar.xz
/qtbase-everywhere-src-6.9.0-rc.tar.xz
/qtbase-everywhere-src-6.9.0.tar.xz
/qtbase-everywhere-src-6.9.1.tar.xz
/qtbase-everywhere-src-6.9.2.tar.xz
/qtbase-everywhere-src-6.10.0-rc.tar.xz
/qtbase-everywhere-src-6.10.0.tar.xz
/qtbase-everywhere-src-6.10.1.tar.xz

232
CVE-2024-39936.patch Normal file
View file

@ -0,0 +1,232 @@
From b1e75376cc3adfc7da5502a277dfe9711f3e0536 Mon Sep 17 00:00:00 2001
From: Mårten Nordheim <marten.nordheim@qt.io>
Date: Tue, 25 Jun 2024 17:09:35 +0200
Subject: [PATCH] HTTP2: Delay any communication until encrypted() can be responded to
We have the encrypted() signal that lets users do extra checks on the
established connection. It is emitted as BlockingQueued, so the HTTP
thread stalls until it is done emitting. Users can potentially call
abort() on the QNetworkReply at that point, which is passed as a Queued
call back to the HTTP thread. That means that any currently queued
signal emission will be processed before the abort() call is processed.
In the case of HTTP2 it is a little special since it is multiplexed and
the code is built to start requests as they are available. This means
that, while the code worked fine for HTTP1, since one connection only
has one request, it is not working for HTTP2, since we try to send more
requests in-between the encrypted() signal and the abort() call.
This patch changes the code to delay any communication until the
encrypted() signal has been emitted and processed, for HTTP2 only.
It's done by adding a few booleans, both to know that we have to return
early and so we can keep track of what events arose and what we need to
resume once enough time has passed that any abort() call must have been
processed.
Fixes: QTBUG-126610
Pick-to: 6.8 6.7 6.5 6.2 5.15 5.12
Change-Id: Ic25a600c278203256e35f541026f34a8783235ae
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
---
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index 484f18de..d62529a3 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -339,12 +339,12 @@ bool QHttp2ProtocolHandler::sendRequest()
}
}
- if (!prefaceSent && !sendClientPreface())
- return false;
-
if (!requests.size())
return true;
+ if (!prefaceSent && !sendClientPreface())
+ return false;
+
m_channel->state = QHttpNetworkConnectionChannel::WritingState;
// Check what was promised/pushed, maybe we do not have to send a request
// and have a response already?
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 14b5b861..c01d4623 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -209,6 +209,10 @@ void QHttpNetworkConnectionChannel::abort()
bool QHttpNetworkConnectionChannel::sendRequest()
{
Q_ASSERT(protocolHandler);
+ if (waitingForPotentialAbort) {
+ needInvokeSendRequest = true;
+ return false; // this return value is unused
+ }
return protocolHandler->sendRequest();
}
@@ -221,21 +225,28 @@ bool QHttpNetworkConnectionChannel::sendRequest()
void QHttpNetworkConnectionChannel::sendRequestDelayed()
{
QMetaObject::invokeMethod(this, [this] {
- Q_ASSERT(protocolHandler);
if (reply)
- protocolHandler->sendRequest();
+ sendRequest();
}, Qt::ConnectionType::QueuedConnection);
}
void QHttpNetworkConnectionChannel::_q_receiveReply()
{
Q_ASSERT(protocolHandler);
+ if (waitingForPotentialAbort) {
+ needInvokeReceiveReply = true;
+ return;
+ }
protocolHandler->_q_receiveReply();
}
void QHttpNetworkConnectionChannel::_q_readyRead()
{
Q_ASSERT(protocolHandler);
+ if (waitingForPotentialAbort) {
+ needInvokeReadyRead = true;
+ return;
+ }
protocolHandler->_q_readyRead();
}
@@ -1241,7 +1252,18 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
// Similar to HTTP/1.1 counterpart below:
const auto &h2Pairs = h2RequestsToSend.values(); // (request, reply)
const auto &pair = h2Pairs.first();
+ waitingForPotentialAbort = true;
emit pair.second->encrypted();
+
+ // We don't send or handle any received data until any effects from
+ // emitting encrypted() have been processed. This is necessary
+ // because the user may have called abort(). We may also abort the
+ // whole connection if the request has been aborted and there is
+ // no more requests to send.
+ QMetaObject::invokeMethod(this,
+ &QHttpNetworkConnectionChannel::checkAndResumeCommunication,
+ Qt::QueuedConnection);
+
// In case our peer has sent us its settings (window size, max concurrent streams etc.)
// let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
}
@@ -1259,6 +1281,28 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
+
+void QHttpNetworkConnectionChannel::checkAndResumeCommunication()
+{
+ Q_ASSERT(connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
+ || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct);
+
+ // Because HTTP/2 requires that we send a SETTINGS frame as the first thing we do, and respond
+ // to a SETTINGS frame with an ACK, we need to delay any handling until we can ensure that any
+ // effects from emitting encrypted() have been processed.
+ // This function is called after encrypted() was emitted, so check for changes.
+
+ if (!reply && h2RequestsToSend.isEmpty())
+ abort();
+ waitingForPotentialAbort = false;
+ if (needInvokeReadyRead)
+ _q_readyRead();
+ if (needInvokeReceiveReply)
+ _q_receiveReply();
+ if (needInvokeSendRequest)
+ sendRequest();
+}
+
void QHttpNetworkConnectionChannel::requeueHttp2Requests()
{
QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 0772a445..2a5336ca 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -73,6 +73,10 @@ public:
QAbstractSocket *socket;
bool ssl;
bool isInitialized;
+ bool waitingForPotentialAbort = false;
+ bool needInvokeReceiveReply = false;
+ bool needInvokeReadyRead = false;
+ bool needInvokeSendRequest = false;
ChannelState state;
QHttpNetworkRequest request; // current request, only used for HTTP
QHttpNetworkReply *reply; // current reply for this request, only used for HTTP
@@ -145,6 +149,8 @@ public:
void closeAndResendCurrentRequest();
void resendCurrentRequest();
+ void checkAndResumeCommunication();
+
bool isSocketBusy() const;
bool isSocketWriting() const;
bool isSocketWaiting() const;
diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp
index b6f66942..7f135bf6 100644
--- a/tests/auto/network/access/http2/tst_http2.cpp
+++ b/tests/auto/network/access/http2/tst_http2.cpp
@@ -103,6 +103,8 @@ private slots:
void duplicateRequestsWithAborts();
+ void abortOnEncrypted();
+
protected slots:
// Slots to listen to our in-process server:
void serverStarted(quint16 port);
@@ -1393,6 +1395,48 @@ void tst_Http2::duplicateRequestsWithAborts()
QCOMPARE(finishedCount, ExpectedSuccessfulRequests);
}
+void tst_Http2::abortOnEncrypted()
+{
+#if !QT_CONFIG(ssl)
+ QSKIP("TLS support is needed for this test");
+#else
+ clearHTTP2State();
+ serverPort = 0;
+
+ ServerPtr targetServer(newServer(defaultServerSettings, H2Type::h2Direct));
+
+ QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection);
+ runEventLoop();
+
+ nRequests = 1;
+ nSentRequests = 0;
+
+ const auto url = requestUrl(H2Type::h2Direct);
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::Http2DirectAttribute, true);
+
+ std::unique_ptr<QNetworkReply> reply{manager->get(request)};
+ reply->ignoreSslErrors();
+ connect(reply.get(), &QNetworkReply::encrypted, reply.get(), [reply = reply.get()](){
+ reply->abort();
+ });
+ connect(reply.get(), &QNetworkReply::errorOccurred, this, &tst_Http2::replyFinishedWithError);
+
+ runEventLoop();
+ STOP_ON_FAILURE
+
+ QCOMPARE(nRequests, 0);
+ QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError);
+
+ const bool res = QTest::qWaitFor(
+ [this, server = targetServer.get()]() {
+ return serverGotSettingsACK || prefaceOK || nSentRequests > 0;
+ },
+ 500);
+ QVERIFY(!res);
+#endif // QT_CONFIG(ssl)
+}
+
void tst_Http2::serverStarted(quint16 port)
{
serverPort = port;

View file

@ -2,7 +2,7 @@
%global multilib_archs x86_64 %{ix86} %{?mips} ppc64 ppc s390x s390 sparc64 sparcv9
%global multilib_basearchs x86_64 %{?mips64} ppc64 s390x sparc64
%ifarch s390x ppc64le aarch64 armv7hl riscv64
%ifarch s390x ppc64le aarch64 armv7hl
%global no_sse2 1
%endif
@ -12,14 +12,6 @@
%endif
%endif
%if 0%{?rhel} >= 10
# Use mutter on RHEL 10+ since it's the only shipped compositor
%global wlheadless_compositor mutter
%else
# Use the simple reference compositor to simplify dependencies
%global wlheadless_compositor weston
%endif
%global platform linux-g++
%if 0%{?use_clang}
@ -41,14 +33,12 @@ BuildRequires: pkgconfig(libsystemd)
#global tests 1
#global unstable 0
%if 0%{?unstable}
%global prerelease rc
%endif
%global prerelease rc2
Name: qt6-qtbase
Summary: Qt6 - QtBase components
Version: 6.10.1
Release: 3%{?dist}
Version: 6.6.2
Release: 2%{?dist}
License: LGPL-3.0-only OR GPL-3.0-only WITH Qt-GPL-exception-1.0
Url: http://qt-project.org/
@ -75,8 +65,8 @@ Source6: 10-qt6-check-opengl2.sh
# macros
Source10: macros.qt6-qtbase
Patch1: qtbase-CMake-Install-objects-files-into-ARCHDATADIR.patch
Patch2: qtbase-use-only-major-minor-for-private-api-tag.patch
Patch1: qtbase-tell-the-truth-about-private-API.patch
Patch2: qtbase-CMake-Install-objects-files-into-ARCHDATADIR.patch
# upstreamable patches
# namespace QT_VERSION_CHECK to workaround major/minor being pre-defined (#1396755)
@ -97,12 +87,17 @@ Patch56: qtbase-mysql.patch
# fix FTBFS against libglvnd-1.3.4+
Patch58: qtbase-libglvnd.patch
# upstream patches
Patch100: qtbase-wayland-convey-preference-for-server-side-decorations.patch
Patch101: qtbase-wayland-compress-high-frequency-mouse-events.patch
Patch102: qtbase-wayland-optimize-scroll-operations.patch
Patch103: qtbase-wayland-enable-event-compression-and-fix-scroll-end-event.patch
Patch104: qtbase-wayland-fix-crash-in-qwaylandshmbackingstore-scroll.patch
# Bug 1954359 - Many emoji don't show up in Qt apps because qt does not handle 'emoji' font family
# FIXME: this change seems to completely break font rendering for some people
# Patch60: qtbase-cache-emoji-font.patch
%if 0%{?fedora} < 39
# Latest QGnomePlatform needs to be specified to be used
Patch100: qtbase-use-qgnomeplatform-as-default-platform-theme-on-gnome.patch
%endif
## upstream patches
Patch200: CVE-2024-39936.patch
# Do not check any files in %%{_qt6_plugindir}/platformthemes/ for requires.
# Those themes are there for platform integration. If the required libraries are
@ -123,17 +118,12 @@ BuildRequires: ninja-build
BuildRequires: cups-devel
BuildRequires: desktop-file-utils
BuildRequires: findutils
%if 0%{?fedora} || 0%{?epel}
BuildRequires: double-conversion-devel
%else
Provides: bundled(double-conversion)
%endif
%if 0%{?fedora} || 0%{?epel}
BuildRequires: libb2-devel
%else
Provides: bundled(libb2)
%endif
Provides: bundled(emoji-segmenter)
BuildRequires: libjpeg-devel
BuildRequires: libmng-devel
BuildRequires: libtiff-devel
@ -170,16 +160,13 @@ BuildRequires: pkgconfig(xkeyboard-config)
%global vulkan 1
BuildRequires: pkgconfig(vulkan)
%global egl 1
BuildRequires: mesa-libEGL-devel
BuildRequires: pkgconfig(egl)
BuildRequires: pkgconfig(gbm)
BuildRequires: pkgconfig(libglvnd)
BuildRequires: pkgconfig(xrender)
BuildRequires: pkgconfig(x11)
BuildRequires: pkgconfig(wayland-scanner)
BuildRequires: pkgconfig(wayland-server)
BuildRequires: pkgconfig(wayland-client)
BuildRequires: pkgconfig(wayland-cursor)
BuildRequires: pkgconfig(wayland-egl)
# only needed for GLES2 and GLES3 builds
#BuildRequires: pkgconfig(glesv2)
%global sqlite 1
BuildRequires: pkgconfig(sqlite3) >= 3.7
@ -192,6 +179,7 @@ BuildRequires: pkgconfig(xcb) pkgconfig(xcb-glx) pkgconfig(xcb-icccm) pkgconfig(
BuildRequires: pkgconfig(zlib)
BuildRequires: perl
BuildRequires: perl-generators
# see patch68
BuildRequires: python3
BuildRequires: qt6-rpm-macros
@ -199,11 +187,9 @@ BuildRequires: qt6-rpm-macros
BuildRequires: dbus-x11
BuildRequires: mesa-dri-drivers
BuildRequires: time
BuildRequires: (wlheadless-run and %{wlheadless_compositor})
BuildRequires: xorg-x11-server-Xvfb
%endif
Requires: qt6-filesystem
Requires: %{name}-common = %{version}-%{release}
## Sql drivers
@ -221,8 +207,6 @@ handling.
%package common
Summary: Common files for Qt6
Requires: %{name} = %{version}-%{release}
Obsoletes: qgnomeplatform-common <= 0.9.3
Provides: qgnomeplatform-common = %{version}-%{release}
BuildArch: noarch
%description common
%{summary}.
@ -232,7 +216,7 @@ Summary: Development files for %{name}
Requires: %{name}%{?_isa} = %{version}-%{release}
Requires: %{name}-gui%{?_isa}
%if 0%{?egl}
Requires: pkgconfig(egl)
Requires: libEGL-devel
%endif
Requires: pkgconfig(gl)
%if 0%{?vulkan}
@ -319,12 +303,9 @@ Requires: %{name}%{?_isa} = %{version}-%{release}
Summary: Qt6 GUI-related libraries
Requires: %{name}%{?_isa} = %{version}-%{release}
Recommends: mesa-dri-drivers%{?_isa}
Recommends: qt6-qtwayland%{?_isa}
# Required for some locales: https://pagure.io/fedora-kde/SIG/issue/311
Recommends: qt6-qttranslations
Obsoletes: adwaita-qt6 <= 1.4.2
Obsoletes: libadwaita-qt6 <= 1.4.2
Obsoletes: qgnomeplatform-qt6 <= 0.9.3
Provides: qgnomeplatform-qt6 = %{version}-%{release}
# for Source6: 10-qt6-check-opengl2.sh:
# glxinfo
Requires: glx-utils
@ -374,41 +355,41 @@ export LDFLAGS="$LDFLAGS $RPM_LD_FLAGS"
export MAKEFLAGS="%{?_smp_mflags}"
%cmake_qt6 \
-DFEATURE_accessibility=ON \
-DFEATURE_fontconfig=ON \
-DFEATURE_glib=ON \
-DFEATURE_sse2=%{?no_sse2:OFF}%{!?no_sse2:ON} \
-DFEATURE_icu=ON \
-DFEATURE_enable_new_dtags=ON \
-DFEATURE_emojisegmenter=ON \
-DFEATURE_journald=%{?journald:ON}%{!?journald:OFF} \
-DFEATURE_openssl_linked=ON \
-DFEATURE_openssl_hash=ON \
-DFEATURE_libproxy=ON \
-DFEATURE_sctp=ON \
-DFEATURE_separate_debug_info=OFF \
-DFEATURE_reduce_relocations=OFF \
-DFEATURE_relocatable=OFF \
-DFEATURE_system_jpeg=ON \
-DFEATURE_system_png=ON \
-DFEATURE_system_zlib=ON \
%{?ibase:-DFEATURE_sql_ibase=ON} \
-DFEATURE_sql_odbc=ON \
-DFEATURE_sql_mysql=ON \
-DFEATURE_sql_psql=ON \
-DFEATURE_sql_sqlite=ON \
-DFEATURE_rpath=OFF \
-DFEATURE_zstd=ON \
-DFEATURE_elf_private_full_version=ON \
%{?dbus_linked:-DFEATURE_dbus_linked=ON} \
%{?pcre:-DFEATURE_system_pcre2=ON} \
%{?sqlite:-DFEATURE_system_sqlite=ON} \
-DQT_FEATURE_accessibility=ON \
-DQT_FEATURE_fontconfig=ON \
-DQT_FEATURE_glib=ON \
-DQT_FEATURE_sse2=%{?no_sse2:OFF}%{!?no_sse2:ON} \
-DQT_FEATURE_icu=ON \
-DQT_FEATURE_enable_new_dtags=ON \
-DQT_FEATURE_journald=%{?journald:ON}%{!?journald:OFF} \
-DQT_FEATURE_openssl_linked=ON \
-DQT_FEATURE_openssl_hash=ON \
-DQT_FEATURE_libproxy=ON \
-DQT_FEATURE_sctp=ON \
-DQT_FEATURE_separate_debug_info=OFF \
-DQT_FEATURE_reduce_relocations=OFF \
-DQT_FEATURE_relocatable=OFF \
-DQT_FEATURE_system_jpeg=ON \
-DQT_FEATURE_system_png=ON \
-DQT_FEATURE_system_zlib=ON \
%{?ibase:-DQT_FEATURE_sql_ibase=ON} \
-DQT_FEATURE_sql_odbc=ON \
-DQT_FEATURE_sql_mysql=ON \
-DQT_FEATURE_sql_psql=ON \
-DQT_FEATURE_sql_sqlite=ON \
-DQT_FEATURE_rpath=OFF \
-DQT_FEATURE_zstd=ON \
%{?dbus_linked:-DQT_FEATURE_dbus_linked=ON} \
%{?pcre:-DQT_FEATURE_system_pcre2=ON} \
%{?sqlite:-DQT_FEATURE_system_sqlite=ON} \
-DBUILD_SHARED_LIBS=ON \
-DQT_BUILD_EXAMPLES=%{?examples:ON}%{!?examples:OFF} \
-DQT_INSTALL_EXAMPLES_SOURCES=%{?examples:ON}%{!?examples:OFF} \
-DQT_BUILD_TESTS=%{?tests:ON}%{!?tests:OFF} \
-DQT_QMAKE_TARGET_MKSPEC=%{platform}
# FIXME
# -DQT_FEATURE_directfb=ON \
%cmake_build
@ -440,7 +421,7 @@ translationdir=%{_qt6_translationdir}
Name: Qt6
Description: Qt6 Configuration
Version: 6.10.1
Version: 6.6.2
EOF
# rpm macros
@ -454,7 +435,7 @@ sed -i \
%{buildroot}%{_rpmmacrodir}/macros.qt6-qtbase
# create/own dirs
mkdir -p %{buildroot}%{_qt6_plugindir}/{designer,iconengines,script,styles}
mkdir -p %{buildroot}{%{_qt6_archdatadir}/mkspecs/modules,%{_qt6_importdir},%{_qt6_libexecdir},%{_qt6_plugindir}/{designer,iconengines,script,styles},%{_qt6_translationdir}}
mkdir -p %{buildroot}%{_sysconfdir}/xdg/QtProject
# hardlink files to {_bindir}, add -qt6 postfix to not conflict
@ -498,27 +479,10 @@ install -p -m755 -D %{SOURCE6} %{buildroot}%{_sysconfdir}/X11/xinit/xinitrc.d/10
mkdir -p %{buildroot}%{_qt6_headerdir}/QtXcb
install -m 644 src/plugins/platforms/xcb/*.h %{buildroot}%{_qt6_headerdir}/QtXcb/
# Copied from OpenSUSE packages
# These files are only useful for the Qt continuous integration
rm %{buildroot}%{_qt6_libexecdir}/ensure_pro_file.cmake
rm %{buildroot}%{_qt6_libexecdir}/qt-android-runner.py
rm %{buildroot}%{_qt6_libexecdir}/qt-testrunner.py
rm %{buildroot}%{_qt6_libexecdir}/sanitizer-testrunner.py
# Not useful for desktop installs
rm -r %{buildroot}%{_qt6_libdir}/cmake/Qt6ExamplesAssetDownloaderPrivate
rm -r %{buildroot}%{_qt6_headerdir}/QtExamplesAssetDownloader
rm %{buildroot}%{_qt6_descriptionsdir}/ExamplesAssetDownloaderPrivate.json
rm %{buildroot}%{_qt6_libdir}/libQt6ExamplesAssetDownloader.*
rm %{buildroot}%{_qt6_libdir}/qt6/metatypes/qt6examplesassetdownloaderprivate_metatypes.json
# These shouldn't be probably installed
rm -r %{buildroot}%{_qt6_libdir}/cmake/Qt6/3rdparty/extra-cmake-modules/*.patch
# This is only for Apple platforms and has a python2 dep
rm -r %{buildroot}%{_qt6_mkspecsdir}/features/uikit
rm %{buildroot}/%{_qt6_libexecdir}/qt-cmake-private-install.cmake
# Use better location for some new scripts in qtbase-6.0.1
mv %{buildroot}/%{_qt6_libexecdir}/ensure_pro_file.cmake %{buildroot}/%{_qt6_libdir}/cmake/Qt6/ensure_pro_file.cmake
%check
# verify Qt6.pc
@ -533,7 +497,7 @@ export LD_LIBRARY_PATH=%{buildroot}%{_qt6_libdir}
# dbus tests error out when building if session bus is not available
dbus-launch --exit-with-session \
%make_build sub-tests -k ||:
wlheadless-run -c %{wlheadless_compositor} -- \
xvfb-run -a --server-args="-screen 0 1280x1024x32" \
dbus-launch --exit-with-session \
time \
make check -k ||:
@ -545,7 +509,6 @@ make check -k ||:
%license LICENSES/GPL*
%license LICENSES/LGPL*
%dir %{_sysconfdir}/xdg/QtProject/
%{_qt6_archdatadir}/sbom/qtbase-%{qt_version}.spdx
%{_qt6_libdir}/libQt6Concurrent.so.6*
%{_qt6_libdir}/libQt6Core.so.6*
%{_qt6_libdir}/libQt6DBus.so.6*
@ -553,14 +516,23 @@ make check -k ||:
%{_qt6_libdir}/libQt6Sql.so.6*
%{_qt6_libdir}/libQt6Test.so.6*
%{_qt6_libdir}/libQt6Xml.so.6*
%dir %{_qt6_docdir}/
%{_qt6_docdir}/global/
%{_qt6_docdir}/config/
%{_qt6_importdir}/
%{_qt6_translationdir}/
%if "%{_qt6_prefix}" != "%{_prefix}"
%dir %{_qt6_prefix}/
%endif
%dir %{_qt6_archdatadir}/
%dir %{_qt6_datadir}/
%{_qt6_datadir}/qtlogging.ini
%dir %{_qt6_libexecdir}/
%dir %{_qt6_plugindir}/
%dir %{_qt6_plugindir}/designer/
%dir %{_qt6_plugindir}/generic/
%dir %{_qt6_plugindir}/iconengines/
%dir %{_qt6_plugindir}/imageformats/
%dir %{_qt6_plugindir}/networkinformation/
%dir %{_qt6_plugindir}/platforminputcontexts/
%dir %{_qt6_plugindir}/platforms/
%dir %{_qt6_plugindir}/platformthemes/
@ -568,61 +540,61 @@ make check -k ||:
%dir %{_qt6_plugindir}/script/
%dir %{_qt6_plugindir}/sqldrivers/
%dir %{_qt6_plugindir}/styles/
%dir %{_qt6_plugindir}/tls/
%{_qt6_plugindir}/networkinformation/libqglib.so
%{_qt6_plugindir}/networkinformation/libqnetworkmanager.so
%{_qt6_plugindir}/sqldrivers/libqsqlite.so
%{_qt6_plugindir}/tls/libqcertonlybackend.so
%{_qt6_plugindir}/tls/libqopensslbackend.so
%{_bindir}/qtpaths*
%{_qt6_bindir}/qtpaths*
%files common
# mostly empty for now, consider: filesystem/dir ownership, licenses
%{_rpmmacrodir}/macros.qt6-qtbase
%files devel
%dir %{_qt6_libdir}/qt6/modules
%dir %{_qt6_libdir}/qt6/metatypes
%dir %{_qt6_libdir}/cmake/Qt6
%dir %{_qt6_libdir}/cmake/Qt6/libexec
%dir %{_qt6_libdir}/cmake/Qt6/platforms
%dir %{_qt6_libdir}/cmake/Qt6/platforms/Platform
%dir %{_qt6_libdir}/cmake/Qt6/config.tests
%dir %{_qt6_libdir}/cmake/Qt6/3rdparty
%dir %{_qt6_libdir}/cmake/Qt6/3rdparty/extra-cmake-modules
%dir %{_qt6_libdir}/cmake/Qt6/3rdparty/extra-cmake-modules/find-modules
%dir %{_qt6_libdir}/cmake/Qt6/3rdparty/extra-cmake-modules/modules
%dir %{_qt6_libdir}/cmake/Qt6/3rdparty/kwin
%dir %{_qt6_libdir}/cmake/Qt6BuildInternals
%dir %{_qt6_libdir}/cmake/Qt6BuildInternals/StandaloneTests
%dir %{_qt6_libdir}/cmake/Qt6BuildInternals/QtStandaloneTestTemplateProject
%dir %{_qt6_libdir}/cmake/Qt6Concurrent
%dir %{_qt6_libdir}/cmake/Qt6Core
%dir %{_qt6_libdir}/cmake/Qt6CoreTools
%dir %{_qt6_libdir}/cmake/Qt6DBus
%dir %{_qt6_libdir}/cmake/Qt6DBusTools
%dir %{_qt6_libdir}/cmake/Qt6DeviceDiscoverySupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6EglFSDeviceIntegrationPrivate
%dir %{_qt6_libdir}/cmake/Qt6EglFsKmsGbmSupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6EglFsKmsSupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6ExampleIconsPrivate
%dir %{_qt6_libdir}/cmake/Qt6FbSupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6Gui
%dir %{_qt6_libdir}/cmake/Qt6GuiTools
%dir %{_qt6_libdir}/cmake/Qt6HostInfo
%dir %{_qt6_libdir}/cmake/Qt6KmsSupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6Network
%dir %{_qt6_libdir}/cmake/Qt6OpenGL
%dir %{_qt6_libdir}/cmake/Qt6OpenGLWidgets
%dir %{_qt6_libdir}/cmake/Qt6PrintSupport
%dir %{_qt6_libdir}/cmake/Qt6Sql
%dir %{_qt6_libdir}/cmake/Qt6Test
%dir %{_qt6_libdir}/cmake/Qt6WaylandClient/
%dir %{_qt6_libdir}/cmake/Qt6WaylandClientPrivate
%dir %{_qt6_libdir}/cmake/Qt6WaylandGlobalPrivate/
%dir %{_qt6_libdir}/cmake/Qt6WaylandScannerTools/
%dir %{_qt6_libdir}/cmake/Qt6WlShellIntegrationPrivate/
%dir %{_qt6_libdir}/cmake/Qt6Widgets
%dir %{_qt6_libdir}/cmake/Qt6WidgetsTools
%dir %{_qt6_libdir}/cmake/Qt6Xml
%if "%{_qt6_bindir}" != "%{_bindir}"
%dir %{_qt6_bindir}
%endif
%{_bindir}/androiddeployqt
%{_bindir}/androiddeployqt6
%{_bindir}/androidtestrunner
%{_bindir}/qdbuscpp2xml*
%{_bindir}/qdbusxml2cpp*
%{_bindir}/qmake*
%{_bindir}/qtpaths*
%{_bindir}/qt-cmake
%{_bindir}/qt-cmake-create
%{_bindir}/qt-configure-module
@ -633,16 +605,17 @@ make check -k ||:
%{_qt6_bindir}/qdbuscpp2xml
%{_qt6_bindir}/qdbusxml2cpp
%{_qt6_bindir}/qmake
%{_qt6_bindir}/qtpaths*
%{_qt6_bindir}/qt-cmake
%{_qt6_bindir}/qt-cmake-create
%{_qt6_bindir}/qt-configure-module
%{_qt6_libexecdir}/qt-cmake-private
%{_qt6_libexecdir}/qt-cmake-private-install.cmake
%{_qt6_libexecdir}/qt-cmake-standalone-test
%{_qt6_libexecdir}/cmake_automoc_parser
%{_qt6_libexecdir}/qt-internal-configure-examples
%{_qt6_libexecdir}/qt-internal-configure-tests
%{_qt6_libexecdir}/sanitizer-testrunner.py
%{_qt6_libexecdir}/syncqt
%{_qt6_libexecdir}/android_emulator_launcher.sh
%{_qt6_libexecdir}/moc
%{_qt6_libexecdir}/tracegen
%{_qt6_libexecdir}/tracepointgen
@ -650,10 +623,16 @@ make check -k ||:
%{_qt6_libexecdir}/qvkgen
%{_qt6_libexecdir}/rcc
%{_qt6_libexecdir}/uic
%{_qt6_libexecdir}/qtwaylandscanner
%{_qt6_libexecdir}/qt-testrunner.py
%{_qt6_libdir}/qt6/modules/*.json
%if "%{_qt6_headerdir}" != "%{_includedir}"
%dir %{_qt6_headerdir}
%endif
%{_qt6_headerdir}/QtConcurrent/
%{_qt6_headerdir}/QtCore/
%{_qt6_headerdir}/QtDBus/
%{_qt6_headerdir}/QtInputSupport
%{_qt6_headerdir}/QtExampleIcons
%{_qt6_headerdir}/QtGui/
%{_qt6_headerdir}/QtNetwork/
%{_qt6_headerdir}/QtOpenGL/
@ -661,12 +640,13 @@ make check -k ||:
%{_qt6_headerdir}/QtPrintSupport/
%{_qt6_headerdir}/QtSql/
%{_qt6_headerdir}/QtTest/
%{_qt6_headerdir}/QtWaylandClient/
%{_qt6_headerdir}/QtWaylandGlobal/
%{_qt6_headerdir}/QtWlShellIntegration/
%{_qt6_headerdir}/QtWidgets/
%{_qt6_headerdir}/QtXcb/
%{_qt6_headerdir}/QtXml/
%{_qt6_headerdir}/QtEglFSDeviceIntegration
%{_qt6_headerdir}/QtEglFsKmsGbmSupport
%{_qt6_headerdir}/QtEglFsKmsSupport
%{_qt6_mkspecsdir}/
%{_qt6_libdir}/libQt6Concurrent.prl
%{_qt6_libdir}/libQt6Concurrent.so
%{_qt6_libdir}/libQt6Core.prl
@ -687,19 +667,16 @@ make check -k ||:
%{_qt6_libdir}/libQt6Sql.so
%{_qt6_libdir}/libQt6Test.prl
%{_qt6_libdir}/libQt6Test.so
%{_qt6_libdir}/libQt6WaylandClient.so
%{_qt6_libdir}/libQt6WlShellIntegration.so
%{_qt6_libdir}/libQt6WaylandClient.prl
%{_qt6_libdir}/libQt6WlShellIntegration.prl
%{_qt6_libdir}/libQt6Widgets.prl
%{_qt6_libdir}/libQt6Widgets.so
%{_qt6_libdir}/libQt6XcbQpa.prl
%{_qt6_libdir}/libQt6XcbQpa.so
%{_qt6_libdir}/libQt6XcbQpa.so
%{_qt6_libdir}/libQt6Xml.prl
%{_qt6_libdir}/libQt6Xml.so
%{_qt6_libdir}/cmake/Qt6/3rdparty/extra-cmake-modules/REUSE.toml
%{_qt6_libdir}/cmake/Qt6/3rdparty/kwin/REUSE.toml
%{_qt6_libdir}/cmake/Qt6/*.in
%{_qt6_libdir}/libQt6EglFSDeviceIntegration.prl
%{_qt6_libdir}/libQt6EglFSDeviceIntegration.so
%{_qt6_libdir}/libQt6EglFsKmsGbmSupport.prl
%{_qt6_libdir}/libQt6EglFsKmsGbmSupport.so
%{_qt6_libdir}/cmake/Qt6/*.h.in
%{_qt6_libdir}/cmake/Qt6/*.cmake
%{_qt6_libdir}/cmake/Qt6/*.cmake.in
@ -726,14 +703,21 @@ make check -k ||:
%{_qt6_libdir}/cmake/Qt6BuildInternals/QtStandaloneTestTemplateProject/Main.cmake
%{_qt6_libdir}/cmake/Qt6Concurrent/*.cmake
%{_qt6_libdir}/cmake/Qt6Core/*.cmake
%{_qt6_libdir}/cmake/Qt6Core/Qt6CoreResourceInit.in.cpp
%{_qt6_libdir}/cmake/Qt6Core/Qt6CoreConfigureFileTemplate.in
%{_qt6_libdir}/cmake/Qt6CoreTools/*.cmake
%{_qt6_libdir}/cmake/Qt6DBus/*.cmake
%{_qt6_libdir}/cmake/Qt6DBusTools/*.cmake
%{_qt6_libdir}/cmake/Qt6DeviceDiscoverySupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6EglFSDeviceIntegrationPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6EglFsKmsGbmSupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6EglFsKmsSupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6ExampleIconsPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6FbSupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6Gui/*.cmake
%{_qt6_libdir}/cmake/Qt6GuiTools/*.cmake
%{_qt6_libdir}/cmake/Qt6HostInfo/*.cmake
%{_qt6_libdir}/cmake/Qt6InputSupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6KmsSupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6Network/*.cmake
%{_qt6_libdir}/cmake/Qt6OpenGL/*.cmake
%{_qt6_libdir}/cmake/Qt6OpenGLWidgets/*.cmake
@ -741,142 +725,38 @@ make check -k ||:
%{_qt6_libdir}/cmake/Qt6Sql/Qt6Sql*.cmake
%{_qt6_libdir}/cmake/Qt6Sql/Qt6QSQLiteDriverPlugin*.cmake
%{_qt6_libdir}/cmake/Qt6Test/*.cmake
%{_qt6_libdir}/cmake/Qt6WaylandClient/*.cmake
%{_qt6_libdir}/cmake/Qt6WaylandClientPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6WaylandGlobalPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6WaylandScannerTools/*.cmake
%{_qt6_libdir}/cmake/Qt6WlShellIntegrationPrivate/
%{_qt6_libdir}/cmake/Qt6Widgets/*.cmake
%{_qt6_libdir}/cmake/Qt6WidgetsTools/*.cmake
%{_qt6_libdir}/cmake/Qt6Xml/*.cmake
%{_qt6_descriptionsdir}/Concurrent.json
%{_qt6_descriptionsdir}/Core.json
%{_qt6_descriptionsdir}/DBus.json
%{_qt6_descriptionsdir}/Gui.json
%{_qt6_descriptionsdir}/Network.json
%{_qt6_descriptionsdir}/OpenGL.json
%{_qt6_descriptionsdir}/OpenGLWidgets.json
%{_qt6_descriptionsdir}/PrintSupport.json
%{_qt6_descriptionsdir}/Sql.json
%{_qt6_descriptionsdir}/Test.json
%{_qt6_descriptionsdir}/WaylandClient.json
%{_qt6_descriptionsdir}/WaylandGlobalPrivate.json
%{_qt6_descriptionsdir}/WlShellIntegrationPrivate.json
%{_qt6_descriptionsdir}/Widgets.json
%{_qt6_descriptionsdir}/Xml.json
%{_qt6_metatypesdir}/qt6concurrent_metatypes.json
%{_qt6_metatypesdir}/qt6core_metatypes.json
%{_qt6_metatypesdir}/qt6dbus_metatypes.json
%{_qt6_metatypesdir}/qt6gui_metatypes.json
%{_qt6_metatypesdir}/qt6network_metatypes.json
%{_qt6_metatypesdir}/qt6opengl_metatypes.json
%{_qt6_metatypesdir}/qt6openglwidgets_metatypes.json
%{_qt6_metatypesdir}/qt6printsupport_metatypes.json
%{_qt6_metatypesdir}/qt6sql_metatypes.json
%{_qt6_metatypesdir}/qt6test_metatypes.json
%{_qt6_metatypesdir}/qt6widgets_metatypes.json
%{_qt6_metatypesdir}/qt6xml_metatypes.json
%{_qt6_libdir}/pkgconfig/*.pc
%{_qt6_mkspecsdir}/*
## private-devel globs
%exclude %{_qt6_headerdir}/*/%{qt_version}/
%files private-devel
%{_qt6_headerdir}/QtEglFSDeviceIntegration
%{_qt6_headerdir}/QtEglFsKmsGbmSupport
%{_qt6_headerdir}/QtEglFsKmsSupport
%dir %{_qt6_libdir}/cmake/Qt6CorePrivate
%dir %{_qt6_libdir}/cmake/Qt6DBusPrivate
%dir %{_qt6_libdir}/cmake/Qt6GuiPrivate
%dir %{_qt6_libdir}/cmake/Qt6NetworkPrivate
%dir %{_qt6_libdir}/cmake/Qt6OpenGLPrivate
%dir %{_qt6_libdir}/cmake/Qt6PrintSupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6SqlPrivate
%dir %{_qt6_libdir}/cmake/Qt6TestInternalsPrivate
%dir %{_qt6_libdir}/cmake/Qt6TestInternalsPrivate/3rdparty/cmake
%dir %{_qt6_libdir}/cmake/Qt6TestPrivate
%dir %{_qt6_libdir}/cmake/Qt6WidgetsPrivate
%dir %{_qt6_libdir}/cmake/Qt6XmlPrivate
%dir %{_qt6_libdir}/cmake/Qt6EglFSDeviceIntegrationPrivate
%dir %{_qt6_libdir}/cmake/Qt6EglFsKmsGbmSupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6EglFsKmsSupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6XcbQpaPrivate
%{_qt6_libdir}/cmake/Qt6CorePrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6DBusPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6GuiPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6NetworkPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6OpenGLPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6PrintSupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6SqlPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6TestInternalsPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6TestInternalsPrivate/3rdparty/cmake/*.cmake
%{_qt6_libdir}/cmake/Qt6TestPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6WidgetsPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6XmlPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6EglFSDeviceIntegrationPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6EglFsKmsGbmSupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6EglFsKmsSupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6XcbQpaPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6Xml/*.cmake
%{_qt6_libdir}/qt6/metatypes/*.json
%{_qt6_libdir}/qt6/objects-RelWithDebInfo/ExampleIconsPrivate_resources_1/.rcc/qrc_example_icons.cpp.o
%{_qt6_libdir}/pkgconfig/*.pc
%if 0%{?egl}
%{_qt6_libdir}/libQt6EglFsKmsSupport.prl
%{_qt6_libdir}/libQt6EglFsKmsSupport.so
%endif
%{_qt6_libdir}/libQt6EglFSDeviceIntegration.prl
%{_qt6_libdir}/libQt6EglFSDeviceIntegration.so
%{_qt6_libdir}/libQt6EglFsKmsGbmSupport.prl
%{_qt6_libdir}/libQt6EglFsKmsGbmSupport.so
%{_qt6_descriptionsdir}/EglFSDeviceIntegrationPrivate.json
%{_qt6_descriptionsdir}/EglFsKmsGbmSupportPrivate.json
%{_qt6_descriptionsdir}/EglFsKmsSupportPrivate.json
%{_qt6_descriptionsdir}/XcbQpaPrivate.json
%{_qt6_metatypesdir}/qt6eglfsdeviceintegrationprivate_metatypes.json
%{_qt6_metatypesdir}/qt6eglfskmsgbmsupportprivate_metatypes.json
%{_qt6_metatypesdir}/qt6eglfskmssupportprivate_metatypes.json
%{_qt6_metatypesdir}/qt6xcbqpaprivate_metatypes.json
%{_qt6_metatypesdir}/qt6waylandclient_metatypes.json
%{_qt6_metatypesdir}/qt6wlshellintegrationprivate_metatypes.json
## private-devel globs
%exclude %{_qt6_headerdir}/*/%{qt_version}/
%files private-devel
%{_qt6_headerdir}/*/%{qt_version}/
%{_qt6_descriptionsdir}/TestInternalsPrivate.json
%files static
%dir %{_qt6_libdir}/cmake/Qt6ExampleIconsPrivate
%{_qt6_libdir}/cmake/Qt6ExampleIconsPrivate/*.cmake
%{_qt6_headerdir}/QtExampleIcons
%{_qt6_libdir}/libQt6ExampleIcons.a
%{_qt6_libdir}/libQt6ExampleIcons.prl
%{_qt6_descriptionsdir}/ExampleIconsPrivate.json
%dir %{_qt6_archdatadir}/objects-*
%{_qt6_archdatadir}/objects-*/ExampleIconsPrivate_resources_1/
%{_qt6_metatypesdir}/qt6exampleiconsprivate_metatypes.json
%dir %{_qt6_libdir}/cmake/Qt6DeviceDiscoverySupportPrivate
%{_qt6_libdir}/cmake/Qt6DeviceDiscoverySupportPrivate/*.cmake
%{_qt6_headerdir}/QtDeviceDiscoverySupport
%{_qt6_libdir}/libQt6DeviceDiscoverySupport.*a
%{_qt6_libdir}/libQt6DeviceDiscoverySupport.prl
%{_qt6_descriptionsdir}/DeviceDiscoverySupportPrivate.json
%{_qt6_metatypesdir}/qt6devicediscoverysupportprivate_metatypes.json
%dir %{_qt6_libdir}/cmake/Qt6FbSupportPrivate
%{_qt6_libdir}/cmake/Qt6FbSupportPrivate/*.cmake
%{_qt6_libdir}/libQt6ExampleIcons.a
%{_qt6_libdir}/libQt6ExampleIcons.prl
%{_qt6_headerdir}/QtFbSupport
%{_qt6_libdir}/libQt6FbSupport.*a
%{_qt6_libdir}/libQt6FbSupport.prl
%{_qt6_descriptionsdir}/FbSupportPrivate.json
%{_qt6_metatypesdir}/qt6fbsupportprivate_metatypes.json
%dir %{_qt6_libdir}/cmake/Qt6InputSupportPrivate
%{_qt6_libdir}/cmake/Qt6InputSupportPrivate/*.cmake
%{_qt6_headerdir}/QtInputSupport
%{_qt6_libdir}/libQt6InputSupport.*a
%{_qt6_libdir}/libQt6InputSupport.prl
%{_qt6_descriptionsdir}/InputSupportPrivate.json
%{_qt6_metatypesdir}/qt6inputsupportprivate_metatypes.json
%dir %{_qt6_libdir}/cmake/Qt6KmsSupportPrivate
%{_qt6_libdir}/cmake/Qt6KmsSupportPrivate/*.cmake
%{_qt6_headerdir}/QtKmsSupport
%{_qt6_libdir}/libQt6KmsSupport.*a
%{_qt6_libdir}/libQt6KmsSupport.prl
%{_qt6_descriptionsdir}/KmsSupportPrivate.json
%{_qt6_metatypesdir}/qt6kmssupportprivate_metatypes.json
%if 0%{?examples}
%files examples
%{_qt6_examplesdir}/
@ -910,8 +790,6 @@ make check -k ||:
%{_qt6_libdir}/libQt6OpenGL.so.6*
%{_qt6_libdir}/libQt6OpenGLWidgets.so.6*
%{_qt6_libdir}/libQt6PrintSupport.so.6*
%{_qt6_libdir}/libQt6WaylandClient.so.6*
%{_qt6_libdir}/libQt6WlShellIntegration.so.6*
%{_qt6_libdir}/libQt6Widgets.so.6*
%{_qt6_libdir}/libQt6XcbQpa.so.6*
# Generic
@ -943,189 +821,27 @@ make check -k ||:
%{_qt6_plugindir}/egldeviceintegrations/libqeglfs-x11-integration.so
%{_qt6_plugindir}/egldeviceintegrations/libqeglfs-kms-egldevice-integration.so
%{_qt6_plugindir}/egldeviceintegrations/libqeglfs-emu-integration.so
%dir %{_qt6_plugindir}/xcbglintegrations/
%{_qt6_plugindir}/xcbglintegrations/libqxcb-egl-integration.so
%endif
# Platforms
%{_qt6_plugindir}/platforms/libqlinuxfb.so
%{_qt6_plugindir}/platforms/libqminimal.so
%{_qt6_plugindir}/platforms/libqoffscreen.so
%{_qt6_plugindir}/platforms/libqxcb.so
%{_qt6_plugindir}/platforms/libqvnc.so
%{_qt6_plugindir}/platforms/libqvkkhrdisplay.so
%{_qt6_plugindir}/platforms/libqwayland.so
%{_qt6_plugindir}/platforms/libqxcb.so
%{_qt6_plugindir}/xcbglintegrations/libqxcb-glx-integration.so
%{_qt6_plugindir}/printsupport/libcupsprintersupport.so
# Platformthemes
%{_qt6_plugindir}/platformthemes/libqxdgdesktopportal.so
%{_qt6_plugindir}/platformthemes/libqgtk3.so
# Wayland plugins and protocols
%{_qt6_plugindir}/wayland-decoration-client/
%{_qt6_plugindir}/wayland-graphics-integration-client
%{_qt6_plugindir}/wayland-shell-integration
%{_qt6_datadir}/wayland/extensions/
%{_qt6_datadir}/wayland/protocols/
%{_qt6_plugindir}/printsupport/libcupsprintersupport.so
%changelog
* Mon Dec 22 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.1-3
- Fix crash in QWaylandShmBackingStore::scroll()
* Mon Dec 08 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.1-2
- Re-add wayland fixes for mouse scrolling
* Thu Nov 20 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.1-1
- 6.10.1
* Mon Nov 10 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.0-3
- Backport wayland fixes for mouse scrolling
* Wed Oct 29 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.0-2
- Backport: Wayland - convey preference for server side decorations
* Tue Oct 07 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.0-1
- 6.10.0
* Tue Sep 30 2025 Gwyn Ciesla <gwync@protonmail.com> - 6.10.0~rc-2
- Firebird 5 rebuild
* Thu Sep 25 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.0~rc-1
- 6.10.0 RC
* Thu Aug 28 2025 Jan Grulich <jgrulich@redhat.com> - 6.9.2-1
- 6.9.2
* Tue Aug 05 2025 František Zatloukal <fzatlouk@redhat.com> - 6.9.1-4
- Rebuilt for icu 77.1
* Mon Jul 28 2025 Adam Williamson <awilliam@redhat.com> - 6.9.1-3
- Adjust for https://fedoraproject.org/wiki/Changes/dropingOfCertPemFile removals
* Fri Jul 25 2025 Fedora Release Engineering <releng@fedoraproject.org> - 6.9.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild
* Mon Jun 02 2025 Jan Grulich <jgrulich@redhat.com> - 6.9.1-1
- 6.9.1
* Mon Apr 28 2025 Jan Grulich <jgrulich@redhat.com> - 6.9.0-2
- Fix possible crash in FontConfig database
* Wed Apr 02 2025 Jan Grulich <jgrulich@redhat.com> - 6.9.0-1
- 6.9.0
* Fri Mar 21 2025 Jan Grulich <jgrulich@redhat.com> - 6.9.0-1
- 6.9.0 RC
* Thu Feb 13 2025 Jan Grulich <jgrulich@redhat.com> - 6.8.2-3
- Fix rendering of combined emojis
* Thu Feb 06 2025 Jan Grulich <jgrulich@redhat.com> - 6.8.2-2
- Backport recommended fixes for Qt 6.8.2
* Fri Jan 31 2025 Jan Grulich <jgrulich@redhat.com> - 6.8.2-1
- 6.8.2
* Thu Jan 16 2025 Jan Grulich <jgrulich@redhat.com> - 6.8.1-11
- Backport additional fixes for emoji support
* Mon Jan 13 2025 Jan Grulich <jgrulich@redhat.com> - 6.8.1-10
- Fix directory ownership for 3rdparty cmake plugins
* Thu Jan 09 2025 Jan Grulich <jgrulich@redhat.com> - 6.8.1-9
- Fix directory ownership
Resolves: rhbz#2292582
* Wed Jan 08 2025 Jan Grulich <jgrulich@redhat.com> - 6.8.1-8
- Install CMake modules for plugins
* Tue Dec 17 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.1-7
- Fix QGnomePlatform obsolets
* Mon Dec 16 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.1-6
- Backport additional fixes for emoji support
* Tue Dec 10 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.1-5
- Obsolete QGnomePlatform and AdwaitaQt
* Sat Dec 07 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.1-4
- Move all mkspecs to -devel
* Thu Dec 05 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.1-3
- Move more stuff into -private-devel
* Tue Dec 03 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.1-2
- Do not install ExamplesAssetDownloader
* Thu Nov 28 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.1-1
- 6.8.1
* Mon Oct 21 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.0-4
- Backport - a11y atspi: Watch for enabled status change
* Wed Oct 16 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.0-3
- QtPrintSupport: make cups optional target
* Wed Oct 09 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.0-1
- Backport fix for QAbstractItemModel (kdebz#493116)
* Wed Oct 09 2024 Jan Grulich <jgrulich@redhat.com> - 6.8.0-1
- 6.8.0
* Wed Sep 04 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.2-6
- Backport - QWidget: store initialScreen as QPointer
* Fri Jul 19 2024 Fedora Release Engineering <releng@fedoraproject.org> - 6.7.2-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild
* Mon Jul 15 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.2-4
- Use qt6-filesystem
* Mon Jul 08 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.2-3
* Mon Jul 08 2024 Jan Grulich <jgrulich@redhat.com> - 6.6.2-1
- HTTP2: Delay any communication until encrypted() can be responded to
Resolves: CVE-2024-39936
* Wed Jul 03 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.2-2
- Revert: Consider versioned targets when checking the existens in
__qt_internal_walk_libs
* Mon Jul 01 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.2-1
- 6.7.2
* Tue May 21 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.1-2
- Use only major.minor version for private api tag
* Tue May 21 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.1-1
- 6.7.1
* Tue May 07 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.0-5
- QGtk3Theme: Add support for xdg-desktop-portal to get color scheme
* Wed Apr 24 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.0-4
- Use bundled double-conversion in RHEL builds
* Fri Apr 12 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.0-3
- Rebuild (gcc rhbz#2272758)
* Mon Apr 08 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.0-2
- Upstream backport: Use ifdef instead of if for __cpp_lib_span
* Tue Apr 02 2024 Jan Grulich <jgrulich@redhat.com> - 6.7.0-1
- 6.7.0
* Sat Mar 09 2024 Alessandro Astone <ales.astone@gmail.com> - 6.6.2-6
- Move /usr/bin/qtpaths-qt6 to main package
* Fri Mar 01 2024 David Abdurachmanov <davidlt@rivosinc.com> - 6.6.2-5
- Disable SSE2 on riscv64
* Fri Feb 23 2024 Neal Gompa <ngompa@fedoraproject.org> - 6.6.2-4
- Use wlheadless-run for tests instead of xvfb-run
* Mon Feb 19 2024 Jan Grulich <jgrulich@redhat.com> - 6.6.2-3
- Examples: also install source files
* Mon Feb 19 2024 Jan Grulich <jgrulich@redhat.com> - 6.6.2-2
- Examples: also install source files
* Thu Feb 15 2024 Jan Grulich <jgrulich@redhat.com> - 6.6.2-1
- 6.6.2
@ -1199,7 +915,7 @@ make check -k ||:
* Fri Apr 7 2023 Marie Loise Nolden <loise@kde.org> - 6.5.0-2
- fix xcb plugin with new dependency xcb-cursor instead of Xcursor
introduction with qt 6.5, add firebird sql plugin cleanly, clean up spec file
* Mon Apr 03 2023 Jan Grulich <jgrulich@redhat.com> - 6.5.0-1
- 6.5.0

View file

@ -0,0 +1,85 @@
diff --git a/src/gui/text/unix/qfontconfigdatabase.cpp b/src/gui/text/unix/qfontconfigdatabase.cpp
index 474644b8..f61e6e83 100644
--- a/src/gui/text/unix/qfontconfigdatabase.cpp
+++ b/src/gui/text/unix/qfontconfigdatabase.cpp
@@ -592,6 +592,7 @@ void QFontconfigDatabase::populateFontDatabase()
++f;
}
+ cacheEmojiFontFamily();
//QPA has very lazy population of the font db. We want it to be initialized when
//QApplication is constructed, so that the population procedure can do something like this to
//set the default font
@@ -735,6 +736,9 @@ QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family, QFont
if (!pattern)
return fallbackFamilies;
+ if (!m_cacheEmojiFontFamily.isEmpty())
+ fallbackFamilies << m_cacheEmojiFontFamily;
+
FcValue value;
value.type = FcTypeString;
const QByteArray cs = family.toUtf8();
@@ -1016,4 +1020,47 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef
engine->glyphFormat = format;
}
+void QFontconfigDatabase::cacheEmojiFontFamily()
+{
+ FcPattern *pattern;
+ pattern = FcPatternCreate();
+
+ FcValue value;
+ value.type = FcTypeString;
+ value.u.s = (const FcChar8 *)"emoji";
+ FcPatternAdd(pattern,FC_FAMILY,value,true);
+
+ FcLangSet *ls = FcLangSetCreate();
+ FcLangSetAdd(ls, (const FcChar8*)"und-zsye");
+ FcPatternAddLangSet(pattern, FC_LANG, ls);
+
+ FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+
+ FcResult result = FcResultMatch;
+ FcFontSet *fontSet = FcFontSort(nullptr,pattern,FcTrue,nullptr,&result);
+ FcPatternDestroy(pattern);
+
+ if (fontSet) {
+ for (int i = 0; i < fontSet->nfont; i++) {
+ FcChar8 *value = nullptr;
+ if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
+ continue;
+
+ FcLangSet *rls = nullptr;
+ if (FcPatternGetLangSet(fontSet->fonts[i], FC_LANG, 0, &rls) != FcResultMatch)
+ continue;
+
+ if (!FcLangSetContains(rls, ls))
+ continue;
+
+ m_cacheEmojiFontFamily = QString::fromUtf8((const char *)value);
+ break;
+ }
+ FcFontSetDestroy(fontSet);
+ }
+
+ FcLangSetDestroy(ls);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/text/unix/qfontconfigdatabase_p.h b/src/gui/text/unix/qfontconfigdatabase_p.h
index cf15306e..90b94087 100644
--- a/src/gui/text/unix/qfontconfigdatabase_p.h
+++ b/src/gui/text/unix/qfontconfigdatabase_p.h
@@ -37,7 +37,10 @@ public:
QFont defaultFont() const override;
private:
+ void cacheEmojiFontFamily();
void setupFontEngine(QFontEngineFT *engine, const QFontDef &fontDef) const;
+
+ QString m_cacheEmojiFontFamily;
};
QT_END_NAMESPACE

View file

@ -0,0 +1,28 @@
From 25e78cce15fdf737cc48ed5d7683ad1d01b55621 Mon Sep 17 00:00:00 2001
From: Christophe Giboudeaux <christophe@krop.fr>
Date: Sun, 20 Sep 2020 09:57:22 +0200
Subject: [PATCH] Tell the truth about private API
Mark private API with symbols only for the current patch release
This change is a port of the libqt5-qtbase patch which was
added during the Qt 5.6 cycle.
---
cmake/QtFlagHandlingHelpers.cmake | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cmake/QtFlagHandlingHelpers.cmake b/cmake/QtFlagHandlingHelpers.cmake
index d8597326cc..f9da7b2171 100644
--- a/cmake/QtFlagHandlingHelpers.cmake
+++ b/cmake/QtFlagHandlingHelpers.cmake
@@ -23,7 +23,7 @@ function(qt_internal_add_linker_version_script target)
endif()
if(TEST_ld_version_script)
- set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API {\n qt_private_api_tag*;\n")
+ set(contents "Qt_${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}_PRIVATE_API {\n qt_private_api_tag*;\n")
if(arg_PRIVATE_HEADERS)
foreach(ph ${arg_PRIVATE_HEADERS})
string(APPEND contents " @FILE:${ph}@\n")
--
2.40.0

View file

@ -1,13 +0,0 @@
diff --git a/cmake/QtFlagHandlingHelpers.cmake b/cmake/QtFlagHandlingHelpers.cmake
index 6a62b85c..1fc1f88d 100644
--- a/cmake/QtFlagHandlingHelpers.cmake
+++ b/cmake/QtFlagHandlingHelpers.cmake
@@ -71,7 +71,7 @@ function(qt_internal_add_linker_version_script target)
string(APPEND contents "\n};\nQt_${PROJECT_VERSION_MAJOR}")
if(QT_FEATURE_elf_private_full_version)
- string(APPEND contents ".${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+ string(APPEND contents ".${PROJECT_VERSION_MINOR}")
endif()
string(APPEND contents "_PRIVATE_API { qt_private_api_tag*;\n")
if(arg_PRIVATE_HEADERS)

View file

@ -1,174 +0,0 @@
From 095759818854e5a011aa8f859e566bbc6368ab76 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= <mumei6102@gmail.com>
Date: Sun, 27 Jul 2025 00:50:00 +0200
Subject: [PATCH] wayland: Compress high frequency mouse events
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add support for Qt::AA_CompressHighFrequencyEvents on Wayland.
The highest USB HID polling rate is 8 kHz (125 μs). Most mice use lower
polling rate [125 Hz - 1000 Hz]. Reject all events faster than 100 μs,
because it definitely means the application main thread is freezed by
the long operation and events are delivered one after another from the
queue. Since now we rely on the 0 ms timer to deliver the last pending
event when application main thread is no longer freezed.
Pick-to: 6.10
Task-number: QTBUG-138706
Change-Id: Ie9d539e233c5551b1756d599b65495571e195f9d
Reviewed-by: David Edmundson <davidedmundson@kde.org>
---
src/corelib/global/qnamespace.qdoc | 1 +
.../platforms/wayland/qwaylandinputdevice.cpp | 38 +++++++++++++++++++
.../platforms/wayland/qwaylandinputdevice_p.h | 12 ++++++
.../platforms/wayland/qwaylandintegration.cpp | 2 +
tests/auto/wayland/client/tst_client.cpp | 2 +
5 files changed, 55 insertions(+)
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index c845cfa7..f463d736 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -227,6 +227,7 @@
application later.
On Windows 8 and above the default value is also true, but it only applies
to touch events. Mouse and window events remain unaffected by this flag.
+ On Wayland the default value is also true, but it only applies to mouse events.
On other platforms, the default is false.
(In the future, the compression feature may be implemented across platforms.)
You can test the attribute to see whether compression is enabled.
diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
index 170e80f8..45c78765 100644
--- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
+++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
@@ -63,6 +63,34 @@ Q_LOGGING_CATEGORY(lcQpaWaylandInput, "qt.qpa.wayland.input");
// reasonable number of them. As of 2021 most touchscreen panels support 10 concurrent touchpoints.
static const int MaxTouchPoints = 10;
+QWaylandEventCompressionPrivate::QWaylandEventCompressionPrivate()
+{
+ timeElapsed.start();
+ delayTimer.setSingleShot(true);
+}
+
+bool QWaylandEventCompressionPrivate::compressEvent()
+{
+ using namespace std::chrono_literals;
+
+ if (!QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents))
+ return false;
+
+ const auto elapsed = timeElapsed.durationElapsed();
+ timeElapsed.start();
+ if (elapsed < 100us || delayTimer.isActive())
+ {
+ // The highest USB HID polling rate is 8 kHz (125 μs). Most mice use lowe polling rate [125 Hz - 1000 Hz].
+ // Reject all events faster than 100 μs, because it definitely means the application main thread is
+ // freezed by long operation and events are delivered one after another from the queue. Since now we rely
+ // on the 0 ms timer to deliver the last pending event when application main thread is no longer freezed.
+ delayTimer.start(0);
+ return true;
+ }
+
+ return false;
+}
+
QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p)
: mParent(p)
{
@@ -140,6 +168,8 @@ QWaylandInputDevice::Pointer::Pointer(QWaylandInputDevice *seat)
cursorTimerCallback();
});
#endif
+
+ mEventCompression.delayTimer.callOnTimeout(this, &QWaylandInputDevice::Pointer::flushFrameEvent);
}
QWaylandInputDevice::Pointer::~Pointer()
@@ -922,6 +952,11 @@ void QWaylandInputDevice::Pointer::pointer_axis(uint32_t time, uint32_t axis, in
void QWaylandInputDevice::Pointer::pointer_frame()
{
+ if (mEventCompression.compressEvent()) {
+ qCDebug(lcQpaWaylandInput) << "compressed pointer_frame event";
+ return;
+ }
+
flushFrameEvent();
}
@@ -1051,6 +1086,7 @@ void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event)
flushFrameEvent();
}
+ delete mFrameData.event;
mFrameData.event = event;
if (version() < WL_POINTER_FRAME_SINCE_VERSION) {
@@ -1170,6 +1206,8 @@ void QWaylandInputDevice::Pointer::flushScrollEvent()
void QWaylandInputDevice::Pointer::flushFrameEvent()
{
+ mEventCompression.delayTimer.stop();
+
if (auto *event = mFrameData.event) {
if (auto window = event->surface) {
window->handleMouse(mParent, *event);
diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
index bcaf0258..0b24999e 100644
--- a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
+++ b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
@@ -75,6 +75,16 @@ class CursorSurface;
Q_DECLARE_LOGGING_CATEGORY(lcQpaWaylandInput);
+struct QWaylandEventCompressionPrivate
+{
+ QWaylandEventCompressionPrivate();
+
+ bool compressEvent();
+
+ QElapsedTimer timeElapsed;
+ QTimer delayTimer;
+};
+
class Q_WAYLANDCLIENT_EXPORT QWaylandInputDevice
: public QObject
, public QtWayland::wl_seat
@@ -381,6 +391,8 @@ public:
bool mScrollBeginSent = false;
QPointF mScrollDeltaRemainder;
+ QWaylandEventCompressionPrivate mEventCompression;
+
void setFrameEvent(QWaylandPointerEvent *event);
void flushScrollEvent();
void flushFrameEvent();
diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp
index 669d47ee..fc869de6 100644
--- a/src/plugins/platforms/wayland/qwaylandintegration.cpp
+++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp
@@ -87,6 +87,8 @@ QWaylandIntegration::QWaylandIntegration(const QString &platformName)
: mPlatformName(platformName), mFontDb(new QGenericUnixFontDatabase())
#endif
{
+ QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
+
mDisplay.reset(new QWaylandDisplay(this));
mPlatformServices.reset(new QWaylandPlatformServices(mDisplay.data()));
diff --git a/tests/auto/wayland/client/tst_client.cpp b/tests/auto/wayland/client/tst_client.cpp
index 04400e3f..09ac4f7f 100644
--- a/tests/auto/wayland/client/tst_client.cpp
+++ b/tests/auto/wayland/client/tst_client.cpp
@@ -276,6 +276,8 @@ void tst_WaylandClient::events()
exec([&] {
pointer()->sendEnter(s, window.frameOffset() + mousePressPos);
pointer()->sendFrame(client());
+ pointer()->sendMotion(client(), window.frameOffset() + mousePressPos / 2);
+ pointer()->sendFrame(client());
pointer()->sendMotion(client(), window.frameOffset() + mousePressPos);
pointer()->sendFrame(client());
pointer()->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);

View file

@ -1,55 +0,0 @@
From 18550cd9ad04913d50abfc88a6048b7cfaf80687 Mon Sep 17 00:00:00 2001
From: Igor Khanin <igor@khanin.biz>
Date: Mon, 13 Oct 2025 14:26:39 +0300
Subject: [PATCH] wayland: Convey preference for server side decorations
As discussed in the mailing list, Qt applications generally expect top
level windows to be decorated by the windowing system - unless
explicitly requested by the developer by marking a window as frameless.
Furthermore, Qt's client side decorations for Wayland were only really
intended as a fallback.
However until now the Wayland xdg-shell integration conveyed to the
compositor (if it supports decorations negotiations) that it didn't
care whose responsibility it was to draw window decorations. This did
not matter under KWin, which resolves such cases in favor of SSDs - but
does matter under other SSD-capable compositors like cosmic-comp (which
considers SSDs to be the fallback option).
This changes the xdg-shell integration code to be explicit about
requesting SSDs.
[ChangeLog][QtWaylandClient][Important Behavior Changes] The Wayland
XDG shell integration now requests server side decorations with
compositors supporting the zxdg_decoration_manager_v1 protocol.
Change-Id: Ia025b1f6ff17248a5710f981a0cecd90c47b6cd8
Reviewed-by: David Edmundson <davidedmundson@kde.org>
---
diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
index a1a173f..8386b65 100644
--- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
+++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
@@ -201,7 +201,7 @@
delete m_decoration;
m_decoration = nullptr;
} else {
- m_decoration->unsetMode();
+ m_decoration->requestMode(QWaylandXdgToplevelDecorationV1::mode_server_side);
}
}
}
diff --git a/tests/auto/wayland/xdgdecorationv1/tst_xdgdecorationv1.cpp b/tests/auto/wayland/xdgdecorationv1/tst_xdgdecorationv1.cpp
index 5ee8569..65ac08f 100644
--- a/tests/auto/wayland/xdgdecorationv1/tst_xdgdecorationv1.cpp
+++ b/tests/auto/wayland/xdgdecorationv1/tst_xdgdecorationv1.cpp
@@ -149,7 +149,7 @@
QVERIFY(window.frameMargins().isNull());
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QCOMPOSITOR_TRY_VERIFY(toplevelDecoration()->m_unsetModeRequested);
+ QCOMPOSITOR_TRY_VERIFY(toplevelDecoration()->m_requestedMode == XdgToplevelDecorationV1::mode_server_side);
QVERIFY(window.frameMargins().isNull()); // We're still waiting for a configure
exec([&] {
toplevelDecoration()->sendConfigure(XdgToplevelDecorationV1::mode_client_side);

View file

@ -1,235 +0,0 @@
From 9dd0d936d6691904a4bb212dcf48999a5228b84f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= <mumei6102@gmail.com>
Date: Thu, 7 Aug 2025 15:42:55 +0200
Subject: [PATCH] wayland: Enable event compression and fix scroll end event
We have to deliver the scroll end event in order with other scroll
events, so move scroll end event logic into flushScrollEvent().
Track the target scroll window on scroll begin and check whether we
have a target window to prevent a crash.
Also we can't clear the scroll delta when scroll end event arrives,
because the event compression relies on this value.
Use scoped pointer for frame event to simplify code and make sure it's
deleted in destructor.
Amends 095759818854e5a011aa8f859e566bbc6368ab76
Updates 789681872fb62450fc78d1a06472a40d970a8d57
Change-Id: Ifb149c8fde1286b60439be0dab16b1df65279ea8
Reviewed-by: David Edmundson <davidedmundson@kde.org>
---
.../platforms/wayland/qwaylandinputdevice.cpp | 98 ++++++++++---------
.../platforms/wayland/qwaylandinputdevice_p.h | 6 +-
.../platforms/wayland/qwaylandintegration.cpp | 2 +
3 files changed, 61 insertions(+), 45 deletions(-)
diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
index 7fcda34c57ca..6ce43714a35f 100644
--- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
+++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
@@ -935,10 +935,7 @@ void QWaylandInputDevice::Pointer::pointer_axis(uint32_t time, uint32_t axis, in
mParent->mTime = time;
- if (version() < WL_POINTER_FRAME_SINCE_VERSION) {
- qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version";
- flushFrameEvent();
- }
+ maybePointerFrame();
}
void QWaylandInputDevice::Pointer::pointer_frame()
@@ -978,11 +975,9 @@ void QWaylandInputDevice::Pointer::pointer_axis_stop(uint32_t time, uint32_t axi
switch (axis) {
case axis_vertical_scroll:
qCDebug(lcQpaWaylandInput) << "Received vertical wl_pointer.axis_stop";
- mFrameData.delta.setY(0); //TODO: what's the point of doing this?
break;
case axis_horizontal_scroll:
qCDebug(lcQpaWaylandInput) << "Received horizontal wl_pointer.axis_stop";
- mFrameData.delta.setX(0);
break;
default:
qCWarning(lcQpaWaylandInput) << "wl_pointer.axis_stop: Unknown axis: " << axis
@@ -990,25 +985,7 @@ void QWaylandInputDevice::Pointer::pointer_axis_stop(uint32_t time, uint32_t axi
return;
}
- // May receive axis_stop for events we haven't sent a ScrollBegin for because
- // most axis_sources do not mandate an axis_stop event to be sent.
- if (!mScrollBeginSent) {
- // TODO: For now, we just ignore these events, but we could perhaps take this as an
- // indication that this compositor will in fact send axis_stop events for these sources
- // and send a ScrollBegin the next time an axis_source event with this type is encountered.
- return;
- }
-
- QWaylandWindow *target = QWaylandWindow::mouseGrab();
- if (!target)
- target = focusWindow();
- Qt::KeyboardModifiers mods = mParent->modifiers();
- const bool inverted = mFrameData.verticalAxisInverted || mFrameData.horizontalAxisInverted;
- WheelEvent wheelEvent(focusWindow(), Qt::ScrollEnd, mParent->mTime, mSurfacePos, mGlobalPos,
- QPoint(), QPoint(), Qt::MouseEventNotSynthesized, mods, inverted);
- target->handleMouse(mParent, wheelEvent);
- mScrollBeginSent = false;
- mScrollDeltaRemainder = QPointF();
+ mScrollEnd = true;
}
void QWaylandInputDevice::Pointer::pointer_axis_discrete(uint32_t axis, int32_t value)
@@ -1069,6 +1046,14 @@ void QWaylandInputDevice::Pointer::pointer_axis_relative_direction(uint32_t axis
}
}
+inline void QWaylandInputDevice::Pointer::maybePointerFrame()
+{
+ if (version() < WL_POINTER_FRAME_SINCE_VERSION) {
+ qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version";
+ pointer_frame();
+ }
+}
+
void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event)
{
qCDebug(lcQpaWaylandInput) << "Setting frame event " << event->type;
@@ -1077,13 +1062,9 @@ void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event)
flushFrameEvent();
}
- delete mFrameData.event;
- mFrameData.event = event;
+ mFrameData.event.reset(event);
- if (version() < WL_POINTER_FRAME_SINCE_VERSION) {
- qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version";
- flushFrameEvent();
- }
+ maybePointerFrame();
}
void QWaylandInputDevice::Pointer::FrameData::resetScrollData()
@@ -1163,11 +1144,24 @@ void QWaylandInputDevice::Pointer::flushScrollEvent()
{
QPoint angleDelta = mFrameData.angleDelta();
+ // The wayland protocol has separate horizontal and vertical axes, Qt has just the one inverted flag
+ // Pragmatically it should't come up
+ const bool inverted = mFrameData.verticalAxisInverted || mFrameData.horizontalAxisInverted;
+
// Angle delta is required for Qt wheel events, so don't try to send events if it's zero
if (!angleDelta.isNull()) {
- QWaylandWindow *target = QWaylandWindow::mouseGrab();
- if (!target)
- target = focusWindow();
+ QWaylandWindow *target = mScrollTarget;
+ if (!mScrollBeginSent) {
+ if (!target)
+ target = QWaylandWindow::mouseGrab();
+ if (!target)
+ target = focusWindow();
+ }
+ if (!target) {
+ qCDebug(lcQpaWaylandInput) << "Flushing scroll event aborted - no scroll target";
+ mFrameData.resetScrollData();
+ return;
+ }
if (isDefinitelyTerminated(mFrameData.axisSource) && !mScrollBeginSent) {
qCDebug(lcQpaWaylandInput) << "Flushing scroll event sending ScrollBegin";
@@ -1177,21 +1171,38 @@ void QWaylandInputDevice::Pointer::flushScrollEvent()
mParent->modifiers(), false));
mScrollBeginSent = true;
mScrollDeltaRemainder = QPointF();
+ mScrollTarget = target;
}
Qt::ScrollPhase phase = mScrollBeginSent ? Qt::ScrollUpdate : Qt::NoScrollPhase;
QPoint pixelDelta = mFrameData.pixelDeltaAndError(&mScrollDeltaRemainder);
- Qt::MouseEventSource source = mFrameData.wheelEventSource();
-
-
- // The wayland protocol has separate horizontal and vertical axes, Qt has just the one inverted flag
- // Pragmatically it should't come up
- const bool inverted = mFrameData.verticalAxisInverted || mFrameData.horizontalAxisInverted;
qCDebug(lcQpaWaylandInput) << "Flushing scroll event" << phase << pixelDelta << angleDelta;
target->handleMouse(mParent, WheelEvent(focusWindow(), phase, mParent->mTime, mSurfacePos, mGlobalPos,
- pixelDelta, angleDelta, source, mParent->modifiers(), inverted));
+ pixelDelta, angleDelta, mFrameData.wheelEventSource(), mParent->modifiers(), inverted));
+ }
+
+ if (mScrollEnd) {
+ if (mScrollBeginSent) {
+ if (auto target = mScrollTarget.get()) {
+ qCDebug(lcQpaWaylandInput) << "Flushing scroll end event";
+ target->handleMouse(mParent, WheelEvent(focusWindow(), Qt::ScrollEnd, mParent->mTime, mSurfacePos, mGlobalPos,
+ QPoint(), QPoint(), mFrameData.wheelEventSource(), mParent->modifiers(), inverted));
+ }
+ mScrollBeginSent = false;
+ mScrollDeltaRemainder = QPointF();
+ } else {
+ // May receive axis_stop for events we haven't sent a ScrollBegin for because
+ // most axis_sources do not mandate an axis_stop event to be sent.
+
+ // TODO: For now, we just ignore these events, but we could perhaps take this as an
+ // indication that this compositor will in fact send axis_stop events for these sources
+ // and send a ScrollBegin the next time an axis_source event with this type is encountered.
+ }
+ mScrollEnd = false;
+ mScrollTarget.clear();
}
+
mFrameData.resetScrollData();
}
@@ -1199,7 +1210,7 @@ void QWaylandInputDevice::Pointer::flushFrameEvent()
{
mEventCompression.delayTimer.stop();
- if (auto *event = mFrameData.event) {
+ if (auto *event = mFrameData.event.get()) {
if (auto window = event->surface) {
window->handleMouse(mParent, *event);
} else if (mFrameData.event->type == QEvent::MouseButtonRelease) {
@@ -1212,8 +1223,7 @@ void QWaylandInputDevice::Pointer::flushFrameEvent()
event->modifiers); // , Qt::MouseEventSource source =
// Qt::MouseEventNotSynthesized);
}
- delete mFrameData.event;
- mFrameData.event = nullptr;
+ mFrameData.event.reset();
}
//TODO: do modifiers get passed correctly here?
diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
index 533a10991e5e..aa2ccddbcdb8 100644
--- a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
+++ b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
@@ -370,7 +370,7 @@ private Q_SLOTS:
Qt::MouseButton mLastButton = Qt::NoButton;
struct FrameData {
- QWaylandPointerEvent *event = nullptr;
+ QScopedPointer<QWaylandPointerEvent> event;
QPointF delta;
QPoint delta120;
@@ -387,10 +387,14 @@ private Q_SLOTS:
} mFrameData;
bool mScrollBeginSent = false;
+ bool mScrollEnd = false;
QPointF mScrollDeltaRemainder;
+ QPointer<QWaylandWindow> mScrollTarget;
QWaylandEventCompressionPrivate mEventCompression;
+ void maybePointerFrame();
+
void setFrameEvent(QWaylandPointerEvent *event);
void flushScrollEvent();
void flushFrameEvent();

View file

@ -1,39 +0,0 @@
From c93008e4d06abb0072e0e5e57d84a4ae182ecfc0 Mon Sep 17 00:00:00 2001
From: Błażej Szczygieł <mumei6102@gmail.com>
Date: Tue, 21 Oct 2025 19:49:17 +0200
Subject: [PATCH] wayland: Fix crash in QWaylandShmBackingStore::scroll()
Fixes a crash when monitor is unplugged while scrolling.
recreateBackBufferIfNeeded() calls getBuffer() which may set
mFrontBuffer to nullptr.
Amends: 6f25f703fd37a900c139e14a33a4639502bfeae7
Task-number: QTBUG-139231
Change-Id: Ia5bedce2a3f6580c722f73446de81a26d40ea2f4
Reviewed-by: David Edmundson <davidedmundson@kde.org>
---
diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
index b853db2..fa70b53 100644
--- a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
+++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
@@ -229,7 +229,7 @@
// Inspired by QCALayerBackingStore.
bool QWaylandShmBackingStore::scroll(const QRegion &region, int dx, int dy)
{
- if (Q_UNLIKELY(!mBackBuffer || !mFrontBuffer))
+ if (Q_UNLIKELY(!mBackBuffer))
return false;
const qreal devicePixelRatio = waylandWindow()->scale();
@@ -241,6 +241,8 @@
return false;
recreateBackBufferIfNeeded();
+ if (!mFrontBuffer)
+ return false;
const QPoint scrollDelta(dx, dy);
const QMargins margins = windowDecorationMargins();

View file

@ -1,242 +0,0 @@
From 6f25f703fd37a900c139e14a33a4639502bfeae7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= <mumei6102@gmail.com>
Date: Wed, 13 Aug 2025 00:48:08 +0200
Subject: [PATCH] wayland: Optimize scroll operation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Don't copy the dirty region in "recreateBackBufferIfNeeded()" in
"beginPaint()". Mark this region as non-dirty in the back buffer
and paint. Finalize the back buffer (copy remaining dirty region)
before flushing. This allows to optimize scrolling, we no longer
have to do a redundant dirty area copy.
This matches the "QCALayerBackingStore" logic.
Task-number: QTBUG-139231
Change-Id: I6c19491fa8f093de9c9ce7624d8f9b65b0b722c5
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: David Edmundson <davidedmundson@kde.org>
---
.../wayland/qwaylandshmbackingstore.cpp | 111 ++++++++++++------
.../wayland/qwaylandshmbackingstore_p.h | 3 +-
2 files changed, 74 insertions(+), 40 deletions(-)
diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
index d8fc7b18ca34..591e5064ebd6 100644
--- a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
+++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
@@ -159,6 +159,8 @@ QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window, QWaylandDispla
// recreateBackBufferIfNeeded always resets mBackBuffer
if (mRequestedSize.isValid() && waylandWindow())
recreateBackBufferIfNeeded();
+ else
+ mBackBuffer = nullptr;
qDeleteAll(copy);
wl_event_queue_destroy(oldEventQueue);
});
@@ -183,11 +185,15 @@ QPaintDevice *QWaylandShmBackingStore::paintDevice()
void QWaylandShmBackingStore::updateDirtyStates(const QRegion &region)
{
- // Update dirty state of buffers based on what was painted. The back buffer will
- // not be dirty since we already painted on it, while other buffers will become dirty.
+ // Update dirty state of buffers based on what was painted. The back buffer will be
+ // less dirty, since we painted to it, while other buffers will become more dirty.
+ // This allows us to minimize copies between front and back buffers on swap in the
+ // cases where the painted region overlaps with the previous frame (front buffer).
for (QWaylandShmBuffer *b : std::as_const(mBuffers)) {
if (b != mBackBuffer)
b->dirtyRegion() += region;
+ else
+ b->dirtyRegion() -= region;
}
}
@@ -198,7 +204,7 @@ void QWaylandShmBackingStore::beginPaint(const QRegion &region)
const QMargins margins = windowDecorationMargins();
const QRegion regionTranslated = region.translated(margins.left(), margins.top());
- const bool bufferWasRecreated = recreateBackBufferIfNeeded(regionTranslated);
+ const bool bufferWasRecreated = recreateBackBufferIfNeeded();
updateDirtyStates(regionTranslated);
// Although undocumented, QBackingStore::beginPaint expects the painted region
@@ -223,7 +229,7 @@ void QWaylandShmBackingStore::endPaint()
// Inspired by QCALayerBackingStore.
bool QWaylandShmBackingStore::scroll(const QRegion &region, int dx, int dy)
{
- if (!mBackBuffer)
+ if (Q_UNLIKELY(!mBackBuffer || !mFrontBuffer))
return false;
const qreal devicePixelRatio = waylandWindow()->scale();
@@ -236,19 +242,35 @@ bool QWaylandShmBackingStore::scroll(const QRegion &region, int dx, int dy)
recreateBackBufferIfNeeded();
- QImage *backBufferImage = mBackBuffer->image();
-
const QPoint scrollDelta(dx, dy);
const QMargins margins = windowDecorationMargins();
const QRegion adjustedRegion = region.translated(margins.left(), margins.top());
- const QRect boundingRect = adjustedRegion.boundingRect();
- const QPoint devicePixelDelta = scrollDelta * devicePixelRatio;
+ const QRegion inPlaceRegion = adjustedRegion - mBackBuffer->dirtyRegion();
+ const QRegion frontBufferRegion = adjustedRegion - inPlaceRegion;
+
+ if (!inPlaceRegion.isEmpty()) {
+ const QRect inPlaceBoundingRect = inPlaceRegion.boundingRect();
+ const QPoint devicePixelDelta = scrollDelta * devicePixelRatio;
+
+ qt_scrollRectInImage(*mBackBuffer->image(),
+ QRect(inPlaceBoundingRect.topLeft() * devicePixelRatio,
+ inPlaceBoundingRect.size() * devicePixelRatio),
+ devicePixelDelta);
+ }
- qt_scrollRectInImage(*backBufferImage,
- QRect(boundingRect.topLeft() * devicePixelRatio,
- boundingRect.size() * devicePixelRatio),
- devicePixelDelta);
+ if (!frontBufferRegion.isEmpty()) {
+ QPainter painter(mBackBuffer->image());
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.scale(qreal(1) / devicePixelRatio, qreal(1) / devicePixelRatio);
+ for (const QRect &rect : frontBufferRegion) {
+ QRect sourceRect(rect.topLeft() * devicePixelRatio,
+ rect.size() * devicePixelRatio);
+ QRect destinationRect((rect.topLeft() + scrollDelta) * devicePixelRatio,
+ rect.size() * devicePixelRatio);
+ painter.drawImage(destinationRect, *mFrontBuffer->image(), sourceRect);
+ }
+ }
// We do not mark the source region as dirty, even though it technically has "moved".
// This matches the behavior of other backingstore implementations using qt_scrollRectInImage.
@@ -289,6 +311,8 @@ void QWaylandShmBackingStore::flush(QWindow *window, const QRegion &region, cons
if (windowDecoration() && windowDecoration()->isDirty())
updateDecorations();
+ finalizeBackBuffer();
+
mFrontBuffer = mBackBuffer;
QMargins margins = windowDecorationMargins();
@@ -313,6 +337,8 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size, bool &b
mBuffers.removeAt(i);
if (mBackBuffer == buffer)
mBackBuffer = nullptr;
+ if (mFrontBuffer == buffer)
+ mFrontBuffer = nullptr;
delete buffer;
}
}
@@ -341,7 +367,7 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size, bool &b
return nullptr;
}
-bool QWaylandShmBackingStore::recreateBackBufferIfNeeded(const QRegion &nonDirtyRegion)
+bool QWaylandShmBackingStore::recreateBackBufferIfNeeded()
{
wl_display_dispatch_queue_pending(mDisplay->wl_display(), mEventQueue);
@@ -375,30 +401,6 @@ bool QWaylandShmBackingStore::recreateBackBufferIfNeeded(const QRegion &nonDirty
qsizetype oldSizeInBytes = mBackBuffer ? mBackBuffer->image()->sizeInBytes() : 0;
qsizetype newSizeInBytes = buffer->image()->sizeInBytes();
- // mBackBuffer may have been deleted here but if so it means its size was different so we wouldn't copy it anyway
- if (mBackBuffer != buffer && oldSizeInBytes == newSizeInBytes) {
- const QRegion clipRegion = buffer->dirtyRegion() - nonDirtyRegion;
- const auto clipRects = clipRegion.rects();
- if (!clipRects.empty()) {
- Q_ASSERT(mBackBuffer);
- const QImage *sourceImage = mBackBuffer->image();
- QImage *targetImage = buffer->image();
-
- QPainter painter(targetImage);
- painter.setCompositionMode(QPainter::CompositionMode_Source);
- const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio();
- for (const QRect &clipRect : clipRects) { // Iterate clip rects, because complicated clip region causes higher CPU usage
- if (clipRects.size() > 1)
- painter.save();
- painter.setClipRect(clipRect);
- painter.scale(qreal(1) / targetDevicePixelRatio, qreal(1) / targetDevicePixelRatio);
- painter.drawImage(QRectF(QPointF(), targetImage->size()), *sourceImage, sourceImage->rect());
- if (clipRects.size() > 1)
- painter.restore();
- }
- }
- }
-
mBackBuffer = buffer;
for (QWaylandShmBuffer *buffer : std::as_const(mBuffers)) {
@@ -412,11 +414,40 @@ bool QWaylandShmBackingStore::recreateBackBufferIfNeeded(const QRegion &nonDirty
if (windowDecoration() && window()->isVisible() && oldSizeInBytes != newSizeInBytes)
windowDecoration()->update();
- buffer->dirtyRegion() = QRegion();
-
return bufferWasRecreated;
}
+void QWaylandShmBackingStore::finalizeBackBuffer()
+{
+ Q_ASSERT(mBackBuffer);
+
+ const QRegion clipRegion = mBackBuffer->dirtyRegion();
+ if (clipRegion.isEmpty())
+ return;
+
+ if (Q_UNLIKELY(!mFrontBuffer || mFrontBuffer == mBackBuffer))
+ return;
+
+ const QImage *sourceImage = mFrontBuffer->image();
+ QImage *targetImage = mBackBuffer->image();
+
+ QPainter painter(targetImage);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio();
+ const auto clipRects = clipRegion.rects();
+ for (const QRect &clipRect : clipRects) { // Iterate clip rects, because complicated clip region causes higher CPU usage
+ if (clipRects.size() > 1)
+ painter.save();
+ painter.setClipRect(clipRect);
+ painter.scale(qreal(1) / targetDevicePixelRatio, qreal(1) / targetDevicePixelRatio);
+ painter.drawImage(QRectF(QPointF(), targetImage->size()), *sourceImage, sourceImage->rect());
+ if (clipRects.size() > 1)
+ painter.restore();
+ }
+
+ mBackBuffer->dirtyRegion() = QRegion();
+}
+
QImage *QWaylandShmBackingStore::entireSurface() const
{
return mBackBuffer->image();
@@ -496,6 +527,8 @@ QImage QWaylandShmBackingStore::toImage() const
// instead of flush() for widgets that have renderToTexture children
// (QOpenGLWidget, QQuickWidget).
+ const_cast<QWaylandShmBackingStore *>(this)->finalizeBackBuffer();
+
return *contentSurface();
}
#endif // opengl
diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h b/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h
index efd80159e859..cfcafb283265 100644
--- a/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h
+++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h
@@ -73,7 +73,8 @@ class Q_WAYLANDCLIENT_EXPORT QWaylandShmBackingStore : public QPlatformBackingSt
QMargins windowDecorationMargins() const;
QImage *entireSurface() const;
QImage *contentSurface() const;
- bool recreateBackBufferIfNeeded(const QRegion &nonDirtyRegion = QRegion());
+ bool recreateBackBufferIfNeeded();
+ void finalizeBackBuffer();
QWaylandWindow *waylandWindow() const;
void iterateBuffer();

View file

@ -1 +1 @@
SHA512 (qtbase-everywhere-src-6.10.1.tar.xz) = fd5dcdc59ec3b39e48563513ae438eb4540a28e72c46961295de2ccb08609289d477ef7e91aac0b8983f2d5b05b901b4f5be10eaca4ac4c6aa8cd598f37a228e
SHA512 (qtbase-everywhere-src-6.6.2.tar.xz) = ea343bcf269779a4e078ed8baddfbe6c5ec4a34275c7d72b3f3928da60feece2ddc9ce4a380c6536a4e1654b483cee8918f8ad3038904725d2dd1c653ae83ece