summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/io/qdirentryinfo_p.h2
-rw-r--r--src/corelib/kernel/qmetatype.h3
-rw-r--r--src/corelib/kernel/qproperty.h38
-rw-r--r--src/corelib/kernel/qvariant.cpp5
-rw-r--r--src/corelib/serialization/qxmlstream.cpp12
-rw-r--r--src/corelib/serialization/qxmlstream_p.h2
-rw-r--r--src/corelib/text/qbytearray.cpp9
-rw-r--r--src/corelib/text/qstringalgorithms_p.h7
-rw-r--r--src/corelib/text/qstringlist.cpp2
-rw-r--r--src/gui/itemmodels/qfileinfogatherer.cpp2
-rw-r--r--src/gui/math3d/qquaternion.cpp8
-rw-r--r--src/gui/math3d/qquaternion.h10
-rw-r--r--src/gui/painting/qdatabuffer_p.h10
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h4
-rw-r--r--src/gui/text/qtextformat.cpp11
-rw-r--r--src/platformsupport/devicediscovery/qdevicediscovery_p.h1
-rw-r--r--src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp3
-rw-r--r--src/platformsupport/kmsconvenience/qkmsdevice.cpp501
-rw-r--r--src/platformsupport/kmsconvenience/qkmsdevice_p.h25
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscontext.cpp6
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration.cpp4
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration_p.h1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp45
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp42
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h5
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp58
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp35
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h7
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp5
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp21
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h6
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style.cpp10
-rw-r--r--src/testlib/qtestlog.cpp8
-rw-r--r--src/tools/moc/moc.cpp7
-rw-r--r--src/tools/moc/moc.h3
40 files changed, 789 insertions, 144 deletions
diff --git a/src/corelib/io/qdirentryinfo_p.h b/src/corelib/io/qdirentryinfo_p.h
index 7ed5391ff04..8864255c425 100644
--- a/src/corelib/io/qdirentryinfo_p.h
+++ b/src/corelib/io/qdirentryinfo_p.h
@@ -148,7 +148,7 @@ private:
QFileSystemEntry entry;
QFileSystemMetaData metaData;
- std::optional<QFileInfo> fileInfoOpt;
+ std::optional<QFileInfo> fileInfoOpt = std::nullopt;
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 0ec95c3bb99..d31566b4e95 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -2103,6 +2103,9 @@ public:
while (begin != end && is_space(*(end - 1)))
end--;
+ if (begin == end)
+ return len;
+
// Convert 'char const *' into 'const char *'. Start at index 1,
// not 0, because 'const char *' is already OK.
const char *cst = begin + 1;
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h
index f4e7942e947..a3c4e109adf 100644
--- a/src/corelib/kernel/qproperty.h
+++ b/src/corelib/kernel/qproperty.h
@@ -299,7 +299,7 @@ public:
auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
This->m_handler();
})
- , m_handler(handler)
+ , m_handler(std::move(handler))
{
}
@@ -310,7 +310,7 @@ public:
auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
This->m_handler();
})
- , m_handler(handler)
+ , m_handler(std::move(handler))
{
setSource(property);
}
@@ -329,7 +329,7 @@ public:
auto This = static_cast<QPropertyNotifier *>(self);
This->m_handler();
})
- , m_handler(handler)
+ , m_handler(std::move(handler))
{
}
@@ -341,7 +341,7 @@ public:
auto This = static_cast<QPropertyNotifier *>(self);
This->m_handler();
})
- , m_handler(handler)
+ , m_handler(std::move(handler))
{
setSource(property);
}
@@ -516,7 +516,7 @@ public:
QPropertyChangeHandler<Functor> onValueChanged(Functor f)
{
static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
- return QPropertyChangeHandler<Functor>(*this, f);
+ return QPropertyChangeHandler<Functor>(*this, std::move(f));
}
template<typename Functor>
@@ -524,14 +524,14 @@ public:
{
static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
f();
- return onValueChanged(f);
+ return onValueChanged(std::move(f));
}
template<typename Functor>
QPropertyNotifier addNotifier(Functor f)
{
static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
- return QPropertyNotifier(*this, f);
+ return QPropertyNotifier(*this, std::move(f));
}
const QtPrivate::QPropertyBindingData &bindingData() const { return d; }
@@ -785,7 +785,7 @@ public:
template<typename Functor>
QPropertyChangeHandler<Functor> onValueChanged(Functor f) const
{
- QPropertyChangeHandler<Functor> handler(f);
+ QPropertyChangeHandler<Functor> handler(std::move(f));
observe(&handler);
return handler;
}
@@ -794,13 +794,13 @@ public:
QPropertyChangeHandler<Functor> subscribe(Functor f) const
{
f();
- return onValueChanged(f);
+ return onValueChanged(std::move(f));
}
template<typename Functor>
QPropertyNotifier addNotifier(Functor f)
{
- QPropertyNotifier handler(f);
+ QPropertyNotifier handler(std::move(f));
observe(&handler);
return handler;
}
@@ -1046,19 +1046,19 @@ public:
template<typename Functor>
QPropertyChangeHandler<Functor> onValueChanged(Functor f)
{
- return QBindable<T>(aliasedProperty(), iface).onValueChanged(f);
+ return QBindable<T>(aliasedProperty(), iface).onValueChanged(std::move(f));
}
template<typename Functor>
QPropertyChangeHandler<Functor> subscribe(Functor f)
{
- return QBindable<T>(aliasedProperty(), iface).subscribe(f);
+ return QBindable<T>(aliasedProperty(), iface).subscribe(std::move(f));
}
template<typename Functor>
QPropertyNotifier addNotifier(Functor f)
{
- return QBindable<T>(aliasedProperty(), iface).addNotifier(f);
+ return QBindable<T>(aliasedProperty(), iface).addNotifier(std::move(f));
}
bool isValid() const
@@ -1238,7 +1238,7 @@ public:
QPropertyChangeHandler<Functor> onValueChanged(Functor f)
{
static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
- return QPropertyChangeHandler<Functor>(*this, f);
+ return QPropertyChangeHandler<Functor>(*this, std::move(f));
}
template<typename Functor>
@@ -1246,14 +1246,14 @@ public:
{
static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
f();
- return onValueChanged(f);
+ return onValueChanged(std::move(f));
}
template<typename Functor>
QPropertyNotifier addNotifier(Functor f)
{
static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
- return QPropertyNotifier(*this, f);
+ return QPropertyNotifier(*this, std::move(f));
}
const QtPrivate::QPropertyBindingData &bindingData() const
@@ -1386,7 +1386,7 @@ public:
QPropertyChangeHandler<Functor> onValueChanged(Functor f)
{
static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
- return QPropertyChangeHandler<Functor>(*this, f);
+ return QPropertyChangeHandler<Functor>(*this, std::move(f));
}
template<typename Functor>
@@ -1394,14 +1394,14 @@ public:
{
static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
f();
- return onValueChanged(f);
+ return onValueChanged(std::move(f));
}
template<typename Functor>
QPropertyNotifier addNotifier(Functor f)
{
static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
- return QPropertyNotifier(*this, f);
+ return QPropertyNotifier(*this, std::move(f));
}
QtPrivate::QPropertyBindingData &bindingData() const
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 3a2dcb4a12d..e91797a3ffe 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -321,11 +321,6 @@ static QVariant::Private clonePrivate(const QVariant::Private &other)
\compares equality
- Because C++ forbids unions from including types that have
- non-default constructors or destructors, most interesting Qt
- classes cannot be used in unions. Without QVariant, this would be
- a problem for QObject::property() and for database work, etc.
-
A QVariant object holds a single value of a single typeId() at a
time. (Some types are multi-valued, for example a string list.)
You can find out what type, T, the variant holds, convert it to a
diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp
index ad9e1089bfe..b4751d1324f 100644
--- a/src/corelib/serialization/qxmlstream.cpp
+++ b/src/corelib/serialization/qxmlstream.cpp
@@ -1081,10 +1081,12 @@ void QXmlStreamReaderPrivate::parseEntity(const QString &value)
inline void QXmlStreamReaderPrivate::reallocateStack()
{
stack_size <<= 1;
- sym_stack = reinterpret_cast<Value*> (realloc(sym_stack, stack_size * sizeof(Value)));
- Q_CHECK_PTR(sym_stack);
- state_stack = reinterpret_cast<int*> (realloc(state_stack, stack_size * sizeof(int)));
- Q_CHECK_PTR(state_stack);
+ void *p = realloc(sym_stack, stack_size * sizeof(Value));
+ Q_CHECK_PTR(p);
+ sym_stack = static_cast<Value*>(p);
+ p = realloc(state_stack, stack_size * sizeof(int));
+ Q_CHECK_PTR(p);
+ state_stack = static_cast<int*>(p);
}
@@ -2036,7 +2038,7 @@ void QXmlStreamReaderPrivate::startDocument()
// unspecified (i.e. System) encoding.
QString buf = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
if (!decoder.hasError())
- readBuffer = buf;
+ readBuffer = std::move(buf);
}
}
}
diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h
index 4bba6bcc765..bd8770200db 100644
--- a/src/corelib/serialization/qxmlstream_p.h
+++ b/src/corelib/serialization/qxmlstream_p.h
@@ -140,8 +140,8 @@ public:
if (tos + extraCapacity + 1 > cap) {
cap = qMax(tos + extraCapacity + 1, cap << 1 );
void *ptr = realloc(static_cast<void *>(data), cap * sizeof(T));
+ Q_CHECK_PTR(ptr);
data = reinterpret_cast<T *>(ptr);
- Q_CHECK_PTR(data);
}
}
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index d518a2f28f2..3e27f0260d3 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -1889,6 +1889,15 @@ QByteArray::QByteArray(qsizetype size, Qt::Initialization)
}
/*!
+ \fn QByteArray::QByteArray(QByteArrayView v)
+ \since 6.8
+
+ Constructs a byte array initialized with the byte array view's data.
+
+ The QByteArray will be null if and only if \a v is null.
+*/
+
+/*!
Sets the size of the byte array to \a size bytes.
If \a size is greater than the current size, the byte array is
diff --git a/src/corelib/text/qstringalgorithms_p.h b/src/corelib/text/qstringalgorithms_p.h
index a017ec58d49..c873858c59b 100644
--- a/src/corelib/text/qstringalgorithms_p.h
+++ b/src/corelib/text/qstringalgorithms_p.h
@@ -149,7 +149,10 @@ template <typename StringType> struct QStringAlgorithms
return src.size() + adjust;
}
- static inline void replace_detaching(StringType &src, qsizetype bsize,
+ // Instead of detaching, i.e. copying the whole data array then performing the
+ // replacement, create a new buffer, copy `src` and `after` to it and swap it
+ // with `src`.
+ static inline void replace_into_copy(StringType &src, qsizetype bsize,
ViewType after, QSpan<const qsizetype> indices,
qsizetype newlen)
{
@@ -237,7 +240,7 @@ template <typename StringType> struct QStringAlgorithms
// Instead of detaching (which would copy the whole data array) then
// performing the replacement, allocate a new string and copy the data
// over from `src` and `after` as needed.
- replace_detaching(src, bsize, after, indices, newlen);
+ replace_into_copy(src, bsize, after, indices, newlen);
return;
}
diff --git a/src/corelib/text/qstringlist.cpp b/src/corelib/text/qstringlist.cpp
index bb9cf2f0c9f..e6f85849f27 100644
--- a/src/corelib/text/qstringlist.cpp
+++ b/src/corelib/text/qstringlist.cpp
@@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
\reentrant
- QStringList inherits from QList<QString>. Like QList, QStringList is
+ QStringList is actually just a QList<QString>. Like QList, QStringList is
\l{implicitly shared}. It provides fast index-based access as well as fast
insertions and removals. Passing string lists as value parameters is both
fast and safe.
diff --git a/src/gui/itemmodels/qfileinfogatherer.cpp b/src/gui/itemmodels/qfileinfogatherer.cpp
index a0192c99828..df43f53050a 100644
--- a/src/gui/itemmodels/qfileinfogatherer.cpp
+++ b/src/gui/itemmodels/qfileinfogatherer.cpp
@@ -149,6 +149,8 @@ void QFileInfoGatherer::fetchExtendedInformation(const QString &path, const QStr
while ((loc = this->path.lastIndexOf(path, loc - 1)) != -1) {
if (this->files.at(loc) == files)
return;
+ if (loc == 0)
+ break;
}
#if QT_CONFIG(thread)
diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp
index edbe507e93d..72a01554750 100644
--- a/src/gui/math3d/qquaternion.cpp
+++ b/src/gui/math3d/qquaternion.cpp
@@ -427,13 +427,13 @@ QQuaternion QQuaternion::fromAxisAndAngle
*/
/*!
- \fn QQuaternion QQuaternion::fromEulerAngles(const QVector3D &eulerAngles)
+ \fn QQuaternion QQuaternion::fromEulerAngles(const QVector3D &angles)
\since 5.5
\overload
- Creates a quaternion that corresponds to a rotation of \a eulerAngles:
- eulerAngles.z() degrees around the z axis, eulerAngles.x() degrees around the x axis,
- and eulerAngles.y() degrees around the y axis (in that order).
+ Creates a quaternion that corresponds to a rotation of \a angles:
+ angles.z() degrees around the z axis, angles.x() degrees around the x axis,
+ and angles.y() degrees around the y axis (in that order).
\sa toEulerAngles()
*/
diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h
index 7fb153063c5..0ea844ae41f 100644
--- a/src/gui/math3d/qquaternion.h
+++ b/src/gui/math3d/qquaternion.h
@@ -109,7 +109,7 @@ QT_WARNING_POP
#ifndef QT_NO_VECTOR3D
inline QVector3D toEulerAngles() const;
- static inline QQuaternion fromEulerAngles(const QVector3D &eulerAngles);
+ static inline QQuaternion fromEulerAngles(const QVector3D &angles);
#endif
QT7_ONLY(Q_GUI_EXPORT) void getEulerAngles(float *pitch, float *yaw, float *roll) const;
QT7_ONLY(Q_GUI_EXPORT) static QQuaternion fromEulerAngles(float pitch, float yaw, float roll);
@@ -311,23 +311,23 @@ inline QVector3D operator*(const QQuaternion &quaternion, const QVector3D &vec)
return quaternion.rotatedVector(vec);
}
-inline void QQuaternion::getAxisAndAngle(QVector3D *axis, float *angle) const
+void QQuaternion::getAxisAndAngle(QVector3D *axis, float *angle) const
{
float aX, aY, aZ;
getAxisAndAngle(&aX, &aY, &aZ, angle);
*axis = QVector3D(aX, aY, aZ);
}
-inline QVector3D QQuaternion::toEulerAngles() const
+QVector3D QQuaternion::toEulerAngles() const
{
float pitch, yaw, roll;
getEulerAngles(&pitch, &yaw, &roll);
return QVector3D(pitch, yaw, roll);
}
-inline QQuaternion QQuaternion::fromEulerAngles(const QVector3D &eulerAngles)
+QQuaternion QQuaternion::fromEulerAngles(const QVector3D &angles)
{
- return QQuaternion::fromEulerAngles(eulerAngles.x(), eulerAngles.y(), eulerAngles.z());
+ return QQuaternion::fromEulerAngles(angles.x(), angles.y(), angles.z());
}
#endif // QT_NO_VECTOR3D
diff --git a/src/gui/painting/qdatabuffer_p.h b/src/gui/painting/qdatabuffer_p.h
index c7474dc57a3..4872853514b 100644
--- a/src/gui/painting/qdatabuffer_p.h
+++ b/src/gui/painting/qdatabuffer_p.h
@@ -87,8 +87,9 @@ public:
capacity = 1;
while (capacity < size)
capacity *= 2;
- buffer = (Type*) QtPrivate::fittedRealloc(static_cast<void*>(buffer), 0, &capacity, sizeof(Type));
- Q_CHECK_PTR(buffer);
+ auto ptr = QtPrivate::fittedRealloc(static_cast<void*>(buffer), 0, &capacity, sizeof(Type));
+ Q_CHECK_PTR(ptr);
+ buffer = static_cast<Type*>(ptr);
}
}
@@ -96,8 +97,9 @@ public:
Q_ASSERT(capacity >= size);
if (size) {
capacity = size;
- buffer = (Type*) QtPrivate::fittedRealloc(static_cast<void*>(buffer), 0, &capacity, sizeof(Type));
- Q_CHECK_PTR(buffer);
+ const auto ptr = QtPrivate::fittedRealloc(static_cast<void*>(buffer), 0, &capacity, sizeof(Type));
+ Q_CHECK_PTR(ptr);
+ buffer = static_cast<Type*>(ptr);
siz = std::min(siz, size);
} else {
QtPrivate::sizedFree(buffer, capacity, sizeof(Type));
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index d436afc5c77..1a60afbdd8e 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -361,7 +361,7 @@ inline void QClipData::appendSpan(int x, int length, int y, int coverage)
if (count == allocated) {
allocated *= 2;
- m_spans = (QT_FT_Span *)realloc(m_spans, allocated*sizeof(QT_FT_Span));
+ m_spans = static_cast<QT_FT_Span*>(q_check_ptr(realloc(m_spans, allocated * sizeof(QT_FT_Span))));
}
m_spans[count].x = x;
m_spans[count].len = length;
@@ -378,7 +378,7 @@ inline void QClipData::appendSpans(const QT_FT_Span *s, int num)
do {
allocated *= 2;
} while (count + num > allocated);
- m_spans = (QT_FT_Span *)realloc(m_spans, allocated*sizeof(QT_FT_Span));
+ m_spans = static_cast<QT_FT_Span*>(q_check_ptr(realloc(m_spans, allocated * sizeof(QT_FT_Span))));
}
memcpy(m_spans+count, s, num*sizeof(QT_FT_Span));
count += num;
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 06ae00123f0..379fb70a81a 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -2245,6 +2245,17 @@ void QTextCharFormat::setFont(const QFont &font, FontPropertiesInheritanceBehavi
/*!
Returns the font for this character format.
+
+ This function takes into account the format's font attributes (such as fontWeight()
+ and fontPointSize()) and resolves them on top of the default font, defined as follows.
+ If the format is part of a document, that is the document's default font.
+ Otherwise the properties are resolved on top of a default constructed QFont.
+
+ For example, if this format's font size hasn't been changed from the default font,
+ fontPointSize() returns 0, while \c {font().pointSize()} returns the actual
+ size used for drawing.
+
+ \sa QTextDocument::defaultFont()
*/
QFont QTextCharFormat::font() const
{
diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_p.h b/src/platformsupport/devicediscovery/qdevicediscovery_p.h
index 59ce3cd8896..61b0c705898 100644
--- a/src/platformsupport/devicediscovery/qdevicediscovery_p.h
+++ b/src/platformsupport/devicediscovery/qdevicediscovery_p.h
@@ -58,6 +58,7 @@ public:
signals:
void deviceDetected(const QString &deviceNode);
void deviceRemoved(const QString &deviceNode);
+ void deviceChanged(const QString &deviceNode);
protected:
QDeviceDiscovery(QDeviceTypes types, QObject *parent) : QObject(parent), m_types(types) { }
diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp b/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp
index edb3fc58a22..e4d69101f75 100644
--- a/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp
+++ b/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp
@@ -175,6 +175,9 @@ void QDeviceDiscoveryUDev::handleUDevNotification()
if (qstrcmp(action, "remove") == 0)
emit deviceRemoved(devNode);
+ if (qstrcmp(action, "change") == 0)
+ emit deviceChanged(devNode);
+
cleanup:
udev_device_unref(dev);
}
diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
index cdd2ac2d572..7b2637bfffe 100644
--- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp
+++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
@@ -151,17 +151,45 @@ static inline void assignPlane(QKmsOutput *output, QKmsPlane *plane)
output->eglfs_plane = plane;
}
-QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
- drmModeConnectorPtr connector,
- ScreenInfo *vinfo)
+static bool orderedScreenLessThan(const QKmsDevice::OrderedScreen &a,
+ const QKmsDevice::OrderedScreen &b)
+{
+ return a.vinfo.virtualIndex < b.vinfo.virtualIndex;
+}
+
+QKmsDevice::OrderedScreen::OrderedScreen() : screen(nullptr) { }
+
+QKmsDevice::OrderedScreen::OrderedScreen(QPlatformScreen *screen,
+ const QKmsDevice::ScreenInfo &vinfo)
+ : screen(screen), vinfo(vinfo)
+{
+}
+
+QDebug operator<<(QDebug dbg, const QPlatformScreen *screen)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "QPlatformScreen=" << (const void *)screen << " ("
+ << (screen ? screen->name() : QString()) << ")";
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, const QKmsDevice::OrderedScreen &s)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "OrderedScreen(" << s.screen << ") : " << s.vinfo.virtualIndex << " / "
+ << s.vinfo.virtualPos << " / primary: " << s.vinfo.isPrimary << ")";
+ return dbg;
+}
+
+bool QKmsDevice::createScreenInfoForConnector(drmModeResPtr resources,
+ drmModeConnectorPtr connector, ScreenInfo &vinfo)
{
- Q_ASSERT(vinfo);
const QByteArray connectorName = nameForConnector(connector);
const int crtc = crtcForConnector(resources, connector);
if (crtc < 0) {
qWarning() << "No usable crtc/encoder pair for connector" << connectorName;
- return nullptr;
+ return false;
}
OutputConfiguration configuration;
@@ -195,45 +223,54 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
configuration = OutputConfigPreferred;
}
- *vinfo = ScreenInfo();
- vinfo->virtualIndex = userConnectorConfig.value(QStringLiteral("virtualIndex"), INT_MAX).toInt();
+ vinfo.virtualIndex = userConnectorConfig.value(QStringLiteral("virtualIndex"), INT_MAX).toInt();
if (userConnectorConfig.contains(QStringLiteral("virtualPos"))) {
const QByteArray vpos = userConnectorConfig.value(QStringLiteral("virtualPos")).toByteArray();
const QByteArrayList vposComp = vpos.split(',');
- if (vposComp.size() == 2)
- vinfo->virtualPos = QPoint(vposComp[0].trimmed().toInt(), vposComp[1].trimmed().toInt());
+ if (vposComp.count() == 2) {
+ vinfo.virtualPos = QPoint(vposComp[0].trimmed().toInt(), vposComp[1].trimmed().toInt());
+ qCDebug(qLcKmsDebug) << "Parsing virtualPos to: " << vinfo.virtualPos;
+ } else {
+ vinfo.virtualPos = QPoint(-1, -1);
+ qCDebug(qLcKmsDebug) << "Could not parse virtualPos,"
+ << "will be calculated based on virtualIndex";
+ }
+ } else {
+ vinfo.virtualPos = QPoint(-1, -1);
}
+
if (userConnectorConfig.value(QStringLiteral("primary")).toBool())
- vinfo->isPrimary = true;
+ vinfo.isPrimary = true;
const uint32_t crtc_id = resources->crtcs[crtc];
if (configuration == OutputConfigOff) {
qCDebug(qLcKmsDebug) << "Turning off output" << connectorName;
drmModeSetCrtc(m_dri_fd, crtc_id, 0, 0, 0, 0, 0, nullptr);
- return nullptr;
+ return false;
}
// Skip disconnected output
if (configuration == OutputConfigPreferred && connector->connection == DRM_MODE_DISCONNECTED) {
qCDebug(qLcKmsDebug) << "Skipping disconnected output" << connectorName;
- return nullptr;
+ return false;
}
if (configuration == OutputConfigSkip) {
qCDebug(qLcKmsDebug) << "Skipping output" << connectorName;
- return nullptr;
+ return false;
}
// Get the current mode on the current crtc
drmModeModeInfo crtc_mode;
memset(&crtc_mode, 0, sizeof crtc_mode);
if (drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->encoder_id)) {
+
drmModeCrtcPtr crtc = drmModeGetCrtc(m_dri_fd, encoder->crtc_id);
drmModeFreeEncoder(encoder);
if (!crtc)
- return nullptr;
+ return false;
if (crtc->mode_valid)
crtc_mode = crtc->mode;
@@ -303,7 +340,7 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
if (selected_mode < 0) {
qWarning() << "No modes available for output" << connectorName;
- return nullptr;
+ return false;
} else {
int width = modes[selected_mode].hdisplay;
int height = modes[selected_mode].vdisplay;
@@ -504,9 +541,8 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
m_crtc_allocator |= (1 << output.crtc_index);
- vinfo->output = output;
-
- return createScreen(output);
+ vinfo.output = output;
+ return true;
}
drmModePropertyPtr QKmsDevice::connectorProperty(drmModeConnectorPtr connector, const QByteArray &name)
@@ -566,29 +602,233 @@ QKmsDevice::~QKmsDevice()
#endif
}
-struct OrderedScreen
+void QKmsDevice::checkConnectedScreens()
{
- OrderedScreen() : screen(nullptr) { }
- OrderedScreen(QPlatformScreen *screen, const QKmsDevice::ScreenInfo &vinfo)
- : screen(screen), vinfo(vinfo) { }
- QPlatformScreen *screen;
- QKmsDevice::ScreenInfo vinfo;
-};
+ if (m_screenConfig->headless())
+ return;
-QDebug operator<<(QDebug dbg, const OrderedScreen &s)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace() << "OrderedScreen(QPlatformScreen=" << s.screen << " (" << s.screen->name() << ") : "
- << s.vinfo.virtualIndex
- << " / " << s.vinfo.virtualPos
- << " / primary: " << s.vinfo.isPrimary
- << ")";
- return dbg;
+ drmModeResPtr resources = drmModeGetResources(m_dri_fd);
+ if (!resources) {
+ qErrnoWarning(errno, "drmModeGetResources failed");
+ return;
+ }
+
+ QList<uint32_t> newConnects;
+ QList<uint32_t> newDisconnects;
+ const QMap<QString, QVariantMap> userConfig = m_screenConfig->outputSettings();
+
+ for (int i = 0; i < resources->count_connectors; i++) {
+ drmModeConnectorPtr connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
+ if (!connector) {
+ qErrnoWarning(errno, "drmModeGetConnector failed");
+ continue;
+ }
+
+ const uint32_t id = connector->connector_id;
+
+ const QByteArray connectorName = nameForConnector(connector);
+ const QVariantMap userCConfig = userConfig.value(QString::fromUtf8(connectorName));
+ const QByteArray mode = userCConfig.value(QStringLiteral("mode")).toByteArray().toLower();
+ if (mode == "off" || mode == "skip")
+ continue;
+
+ if (connector->connection == DRM_MODE_CONNECTED) {
+ if (!m_registeredScreens.contains(id))
+ newConnects.append(id);
+ else
+ qCDebug(qLcKmsDebug) << "Connected screen already registered: connector id=" << id;
+ }
+
+ if (connector->connection == DRM_MODE_DISCONNECTED) {
+ if (m_registeredScreens.contains(id))
+ newDisconnects.append(id);
+ else
+ qCDebug(qLcKmsDebug) << "Disconnected screen not registered: connector id=" << id;
+ }
+
+ drmModeFreeConnector(connector);
+ }
+
+ if (newConnects.isEmpty() && newDisconnects.isEmpty()) {
+ qCDebug(qLcKmsDebug) << "EGLFS/KMS: KMS-device-change but no new connects or disconnects "
+ << "to process - exiting";
+ return;
+ } else {
+ qCDebug(qLcKmsDebug) << "EGLFS/KMS: KMS-device-change, new connects:" << newConnects
+ << ", and disconnected: " << newDisconnects;
+ }
+
+ const int remainingScreenCount = m_registeredScreens.count() - newDisconnects.count();
+ if (remainingScreenCount == 0 && m_headlessScreen == nullptr) {
+ qCDebug(qLcKmsDebug) << "EGLFS/KMS: creating headless screen before"
+ << "unregistering screens to avoid having no screens";
+ m_headlessScreen = createHeadlessScreen();
+ registerScreen(m_headlessScreen, true, QPoint(),
+ QList<QPlatformScreen *>() << m_headlessScreen);
+ }
+
+ for (uint32_t connectorId : newDisconnects) {
+ OrderedScreen orderedScreen = m_registeredScreens.take(connectorId);
+ QPlatformScreen *screen = orderedScreen.screen;
+
+ // Clear active crtc of the plane associated with the screen output
+ // and, if applicable, disassociate it from the eglfs plane.
+ uint32_t crtcId = (orderedScreen.vinfo.output.eglfs_plane != nullptr) // if we have an assigned plan
+ ? orderedScreen.vinfo.output.eglfs_plane->activeCrtcId // we use the active crtc_id to disable everything
+ : orderedScreen.vinfo.output.crtc_id; // if not, we use the default crtc_id
+
+ if (orderedScreen.vinfo.output.eglfs_plane != nullptr)
+ orderedScreen.vinfo.output.eglfs_plane->activeCrtcId = 0;
+
+ // Clear crtc allocator bit for screen
+ const int crtcIdx = orderedScreen.vinfo.output.crtc_index;
+ m_crtc_allocator &= ~(1 << crtcIdx);
+
+ const int ret = drmModeSetCrtc(m_dri_fd, crtcId, 0, 0, 0, nullptr, 0, nullptr);
+
+ if (ret != 0) {
+ qCWarning(qLcKmsDebug) << "Could not disable CRTC" << crtcId
+ << "on connector" << connectorId << "removal:" << ret;
+ } else {
+ qCDebug(qLcKmsDebug) << "Disabled CRTC" << crtcId
+ << "for connector " << connectorId << "disconnected";
+ }
+
+ // As we've already turned the crtc off, we don't want to restore the saved_crtc
+ if (orderedScreen.vinfo.output.saved_crtc) {
+ drmModeFreeCrtc(orderedScreen.vinfo.output.saved_crtc);
+ orderedScreen.vinfo.output.saved_crtc = nullptr;
+ updateScreenOutput(orderedScreen.screen, orderedScreen.vinfo.output);
+ }
+
+ unregisterScreen(screen);
+ }
+
+ for (uint32_t connectorId : newConnects) {
+ drmModeConnectorPtr connector = drmModeGetConnector(m_dri_fd, connectorId);
+ if (!connector) {
+ qErrnoWarning(errno, "drmModeGetConnector failed");
+ continue;
+ }
+
+ ScreenInfo vinfo;
+ bool succ = createScreenInfoForConnector(resources, connector, vinfo);
+ drmModeFreeConnector(connector);
+ if (!succ)
+ continue;
+
+ QPlatformScreen *screen = createScreen(vinfo.output);
+ if (!screen)
+ continue;
+
+ OrderedScreen orderedScreen(screen, vinfo);
+ m_registeredScreens[connectorId] = orderedScreen;
+ }
+
+ drmModeFreeResources(resources);
+
+ registerScreens(newConnects);
}
-static bool orderedScreenLessThan(const OrderedScreen &a, const OrderedScreen &b)
+void QKmsDevice::updateScreens()
{
- return a.vinfo.virtualIndex < b.vinfo.virtualIndex;
+ if (m_screenConfig->headless())
+ return;
+
+ drmModeResPtr resources = drmModeGetResources(m_dri_fd);
+ if (!resources) {
+ qErrnoWarning(errno, "drmModeGetResources failed");
+ return;
+ }
+
+ QList<uint32_t> newConnects;
+ QList<OrderedScreen> newDisconnects;
+
+ for (int i = 0; i < resources->count_connectors; i++) {
+ drmModeConnectorPtr connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
+ if (!connector)
+ continue;
+
+ if (m_registeredScreens.contains(connector->connector_id)) {
+ OrderedScreen &os = m_registeredScreens[connector->connector_id];
+
+ // As we're currently *re*creating the information of an used connector,
+ // we have to "fake" it being not in use at two places:
+ // (note: the only thing we'll restore is, in case of failure, the eglfs_plane
+ // probably not necessary but good practice)
+
+ // 1) crtc_allocator for the crtc
+ const int crtcIdx = os.vinfo.output.crtc_index;
+ m_crtc_allocator &= ~(1 << crtcIdx);
+
+ // 2) the plane itself
+ if (os.vinfo.output.eglfs_plane)
+ os.vinfo.output.eglfs_plane->activeCrtcId = 0;
+
+ // We also save the saved crtc to restore it in case of success
+ // (otherwise QKmsOutput::restoreMode would restore to a second-latest crtc,
+ // rather then the original one)
+ drmModeCrtcPtr saved_saved_crtc = nullptr;
+ if (os.vinfo.output.saved_crtc)
+ saved_saved_crtc = os.vinfo.output.saved_crtc;
+
+ ScreenInfo vinfo;
+ bool succ = createScreenInfoForConnector(resources, connector, vinfo);
+ if (!succ) {
+ // Here we either failed the recreate, or the config turns the screen off.
+ // In either case, we'll treat it as a disconnect
+
+ // Either this connector is disconnected, broken or turned off
+ // In all those cases we don't need or want to restore the previous mode
+ if (os.vinfo.output.saved_crtc) {
+ drmModeFreeCrtc(os.vinfo.output.saved_crtc);
+ os.vinfo.output.saved_crtc = nullptr;
+ updateScreenOutput(os.screen, os.vinfo.output);
+ }
+
+ // move from one container to another - we don't want registerScreens
+ // to deal with this, but need to call registerScreens before the disconnects
+ newDisconnects.append(m_registeredScreens.take(connector->connector_id));
+ drmModeFreeConnector(connector);
+ continue;
+ }
+ drmModeFreeConnector(connector);
+
+ drmModeFreeCrtc(vinfo.output.saved_crtc);
+ vinfo.output.saved_crtc = saved_saved_crtc; // This is vital as config changes should
+ // never override the original saved_crtc
+ os.vinfo = vinfo;
+ updateScreenOutput(os.screen, os.vinfo.output);
+
+ } else {
+ ScreenInfo vinfo;
+ bool succ = createScreenInfoForConnector(resources, connector, vinfo);
+ if (!succ) // If we fail here we do nothing, as there is nothing to restore or cleanup
+ continue;
+
+ QPlatformScreen *screen = createScreen(vinfo.output);
+ OrderedScreen orderedScreen(screen, vinfo);
+ m_registeredScreens[connector->connector_id] = orderedScreen;
+ newConnects.append(connector->connector_id);
+ }
+ }
+
+ // In case we end up with zero screen, we do the fallback first
+ if (m_registeredScreens.count() == 0 && m_headlessScreen == nullptr) {
+ // Create headless screen before unregistering screens to avoid having no screens
+ m_headlessScreen = createHeadlessScreen();
+ registerScreen(m_headlessScreen, true, QPoint(),
+ QList<QPlatformScreen *>() << m_headlessScreen);
+ }
+
+ // Register new and updates existing screens
+ registerScreens(newConnects);
+
+ // Last we unregister the disconncted ones
+ for (const OrderedScreen &os : newDisconnects)
+ unregisterScreen(os.screen);
+
+ drmModeFreeResources(resources);
}
void QKmsDevice::createScreens()
@@ -599,7 +839,8 @@ void QKmsDevice::createScreens()
QPlatformScreen *screen = createHeadlessScreen();
if (screen) {
qCDebug(qLcKmsDebug, "Headless mode enabled");
- registerScreen(screen, true, QPoint(0, 0), QList<QPlatformScreen *>());
+ registerScreen(screen, true, QPoint(0, 0),
+ QList<QPlatformScreen *>() << screen);
return;
} else {
qWarning("QKmsDevice: Requested headless mode without support in the backend. Request is ignored.");
@@ -630,8 +871,7 @@ void QKmsDevice::createScreens()
discoverPlanes();
- QList<OrderedScreen> screens;
-
+ QList<uint32_t> newConnects;
int wantedConnectorIndex = -1;
bool ok;
int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_CONNECTOR_INDEX", &ok);
@@ -647,19 +887,47 @@ void QKmsDevice::createScreens()
continue;
drmModeConnectorPtr connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
- if (!connector)
+ if (!connector) {
+ qErrnoWarning(errno, "drmModeGetConnector failed");
continue;
+ }
ScreenInfo vinfo;
- QPlatformScreen *screen = createScreenForConnector(resources, connector, &vinfo);
- if (screen)
- screens.append(OrderedScreen(screen, vinfo));
-
+ bool succ = createScreenInfoForConnector(resources, connector, vinfo);
+ uint32_t connectorId = connector->connector_id;
drmModeFreeConnector(connector);
+ if (!succ)
+ continue;
+
+ QPlatformScreen *screen = createScreen(vinfo.output);
+ if (!screen)
+ continue;
+
+ OrderedScreen orderedScreen(screen, vinfo);
+ m_registeredScreens[connectorId] = orderedScreen;
+ newConnects.append(connectorId);
}
drmModeFreeResources(resources);
+ if (!qEnvironmentVariable("QT_QPA_EGLFS_HOTPLUG_ENABLED").isEmpty()
+ && newConnects.empty() && m_headlessScreen == nullptr) {
+ qCDebug(qLcKmsDebug) << "'QT_QPA_EGLFS_HOTPLUG_ENABLED' was set and no screen was connected/found during start-up."
+ << "In order for Qt to operate properly a qt_headless screen will be created."
+ << "It will be automatically removed as soon as the first screen is connected";
+ // Create headless screen before unregistering screens to avoid having no screens
+ m_headlessScreen = createHeadlessScreen();
+ registerScreen(m_headlessScreen, true, QPoint(),
+ QList<QPlatformScreen *>() << m_headlessScreen);
+ }
+
+ registerScreens(newConnects);
+}
+
+void QKmsDevice::registerScreens(QList<uint32_t> newConnects)
+{
+ QList<OrderedScreen> screens = m_registeredScreens.values();
+
// Use stable sort to preserve the original (DRM connector) order
// for outputs with unspecified indices.
std::stable_sort(screens.begin(), screens.end(), orderedScreenLessThan);
@@ -692,44 +960,129 @@ void QKmsDevice::createScreens()
// Figure out the virtual desktop and register the screens to QPA/QGuiApplication.
QPoint pos(0, 0);
- QList<QPlatformScreen *> siblings;
+ QList<OrderedScreen> siblings;
QList<QPoint> virtualPositions;
int primarySiblingIdx = -1;
+ QRegion deskRegion;
for (const OrderedScreen &orderedScreen : screens) {
QPlatformScreen *s = orderedScreen.screen;
QPoint virtualPos(0, 0);
// set up a horizontal or vertical virtual desktop
- if (orderedScreen.vinfo.virtualPos.isNull()) {
- virtualPos = pos;
- if (m_screenConfig->virtualDesktopLayout() == QKmsScreenConfig::VirtualDesktopLayoutVertical)
- pos.ry() += s->geometry().height();
- else
- pos.rx() += s->geometry().width();
+ if (orderedScreen.vinfo.virtualPos.x() == -1 || orderedScreen.vinfo.virtualPos.y() == -1) {
+ if (orderedScreen.vinfo.output.clone_source.isEmpty()) {
+ virtualPos = pos;
+ if (m_screenConfig->virtualDesktopLayout() == QKmsScreenConfig::VirtualDesktopLayoutVertical)
+ pos.ry() += s->geometry().height();
+ else
+ pos.rx() += s->geometry().width();
+ } else {
+ for (int i = 0; i < screens.count(); i++) {
+ const OrderedScreen &os = screens[i];
+ if (os.vinfo.output.name == orderedScreen.vinfo.output.clone_source) {
+ if (i >= virtualPositions.count()) {
+ qCWarning(qLcKmsDebug)
+ << "WARNING: When using clone on kms config,"
+ << "you have to either order your screens (virtualIndex),"
+ << "so clones come after their source,"
+ << "or specify 'virtualPos' for each clone."
+ << "Otherwise desktop-geomerty might not work properly!";
+ virtualPos = pos;
+ } else {
+ virtualPos = virtualPositions[i];
+ }
+ break;
+ }
+ }
+ }
} else {
virtualPos = orderedScreen.vinfo.virtualPos;
}
- qCDebug(qLcKmsDebug) << "Adding QPlatformScreen" << s << "(" << s->name() << ")"
- << "to QPA with geometry" << s->geometry()
- << "and isPrimary=" << orderedScreen.vinfo.isPrimary;
+
// The order in qguiapp's screens list will match the order set by
// virtualIndex. This is not only handy but also required since for instance
// evdevtouch relies on it when performing touch device - screen mapping.
if (!m_screenConfig->separateScreens()) {
- qCDebug(qLcKmsDebug) << " virtual position is" << virtualPos;
- siblings.append(s);
+ siblings.append(orderedScreen);
virtualPositions.append(virtualPos);
if (orderedScreen.vinfo.isPrimary)
primarySiblingIdx = siblings.size() - 1;
} else {
- registerScreen(s, orderedScreen.vinfo.isPrimary, virtualPos, QList<QPlatformScreen *>() << s);
+ const bool isNewScreen = newConnects.contains(orderedScreen.vinfo.output.connector_id);
+ if (isNewScreen) {
+ qCDebug(qLcKmsDebug) << "Adding QPlatformScreen" << s << "(" << s->name() << ")"
+ << "to QPA with geometry" << s->geometry()
+ << ", virtual position" << virtualPos
+ << "and isPrimary=" << orderedScreen.vinfo.isPrimary;
+ registerScreen(s, orderedScreen.vinfo.isPrimary, virtualPos,
+ QList<QPlatformScreen *>() << s);
+ deskRegion += s->geometry();
+ } else {
+ qCDebug(qLcKmsDebug) << "Updating QPlatformScreen" << s << "(" << s->name() << ")"
+ << "to QPA with geometry" << s->geometry()
+ << ", virtual position" << virtualPos
+ << "and isPrimary=" << orderedScreen.vinfo.isPrimary;
+ updateScreen(s, virtualPos, QList<QPlatformScreen *>() << s);
+ deskRegion += s->geometry();
+ }
}
}
if (!m_screenConfig->separateScreens()) {
+ QList<QPlatformScreen *> platformScreenSiblings;
+ for (int i = 0; i < siblings.count(); ++i) {
+ platformScreenSiblings.append(siblings[i].screen);
+ }
+
// enable the virtual desktop
- for (int i = 0; i < siblings.size(); ++i)
- registerScreen(siblings[i], i == primarySiblingIdx, virtualPositions[i], siblings);
+ for (int i = 0; i < siblings.count(); ++i) {
+ QPlatformScreen *screen = platformScreenSiblings[i];
+ const OrderedScreen &orderedScreen = siblings[i];
+ const bool isNewScreen = newConnects.contains(orderedScreen.vinfo.output.connector_id);
+ if (isNewScreen) {
+ qCDebug(qLcKmsDebug) << "Adding QPlatformScreen" << screen
+ << "(" << screen->name() << ")"
+ << "to QPA with geometry" << screen->geometry()
+ << ", virtual position" << virtualPositions[i]
+ << "and isPrimary=" << orderedScreen.vinfo.isPrimary;
+ registerScreen(screen, i == primarySiblingIdx, virtualPositions[i],
+ platformScreenSiblings);
+ deskRegion += screen->geometry();
+ } else {
+ qCDebug(qLcKmsDebug) << "Updating QPlatformScreen" << screen
+ << "(" << screen->name() << ")"
+ << "to QPA with geometry" << screen->geometry()
+ << ", virtual position" << virtualPositions[i]
+ << "and isPrimary=" << orderedScreen.vinfo.isPrimary;
+ updateScreen(screen, virtualPositions[i], platformScreenSiblings);
+ deskRegion += screen->geometry();
+ }
+ }
+ }
+
+ // Remove headless screen if other screens have become available
+ if (!m_registeredScreens.empty() && m_headlessScreen) {
+ unregisterScreen(m_headlessScreen);
+ m_headlessScreen = nullptr;
+ }
+
+ // Due to layout changes it's possible that we have to reset/bound
+ // the cursor into the available space (otherwise the cursor might vanish)
+ QPoint currCPos = QCursor::pos();
+ if (!deskRegion.contains(currCPos)) {
+
+ // We try boudingRect first
+ QRect deskRect = deskRegion.boundingRect();
+ currCPos.setX(qMin(currCPos.x(), deskRect.width()) - 1);
+ currCPos.setY(qMin(currCPos.y(), deskRect.height()) - 1);
+
+ // If boudingRect isn't good enough, we go to 0
+ if (!deskRegion.contains(currCPos))
+ currCPos = QPoint(0,0);
+
+ qCDebug(qLcKmsDebug) << "Due to desktop layout change, overriding cursor pos."
+ << "Is: " << QCursor::pos() << ", will be: " << currCPos;
+ QCursor::setPos(currCPos);
}
}
@@ -749,6 +1102,25 @@ void QKmsDevice::registerScreenCloning(QPlatformScreen *screen,
Q_UNUSED(screensCloningThisScreen);
}
+void QKmsDevice::unregisterScreen(QPlatformScreen *screen)
+{
+ Q_UNUSED(screen);
+}
+
+void QKmsDevice::updateScreen(QPlatformScreen *screen, const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings)
+{
+ Q_UNUSED(screen);
+ Q_UNUSED(virtualPos);
+ Q_UNUSED(virtualSiblings);
+}
+
+void QKmsDevice::updateScreenOutput(QPlatformScreen *screen, const QKmsOutput &output)
+{
+ Q_UNUSED(screen);
+ Q_UNUSED(output);
+}
+
// drm_property_type_is is not available in old headers
static inline bool propTypeIs(drmModePropertyPtr prop, uint32_t type)
{
@@ -1002,6 +1374,12 @@ QKmsScreenConfig::QKmsScreenConfig()
{
}
+void QKmsScreenConfig::refreshConfig()
+{
+ m_outputSettings.clear();
+ loadConfig();
+}
+
void QKmsScreenConfig::loadConfig()
{
QByteArray json = qgetenv("QT_QPA_EGLFS_KMS_CONFIG");
@@ -1039,6 +1417,11 @@ void QKmsScreenConfig::loadConfig()
m_headless = false;
}
+ const QString headlessSizeStr = object.value(QLatin1String("headlessSize")).toString();
+ if (sscanf(headlessSizeStr.toUtf8().constData(), "%dx%d", &headlessSize.rwidth(),
+ &headlessSize.rheight()) == 2)
+ m_headlessSize = headlessSize;
+
m_hwCursor = object.value("hwcursor"_L1).toBool(m_hwCursor);
m_pbuffers = object.value("pbuffers"_L1).toBool(m_pbuffers);
m_devicePath = object.value("device"_L1).toString();
diff --git a/src/platformsupport/kmsconvenience/qkmsdevice_p.h b/src/platformsupport/kmsconvenience/qkmsdevice_p.h
index 050d836cb18..3e6ec108175 100644
--- a/src/platformsupport/kmsconvenience/qkmsdevice_p.h
+++ b/src/platformsupport/kmsconvenience/qkmsdevice_p.h
@@ -88,11 +88,12 @@ public:
QMap<QString, QVariantMap> outputSettings() const { return m_outputSettings; }
virtual void loadConfig();
+ void refreshConfig();
protected:
QString m_devicePath;
bool m_headless;
- QSize m_headlessSize;
+ QSize m_headlessSize{ 1024, 768 };
bool m_hwCursor;
bool m_separateScreens;
bool m_pbuffers;
@@ -196,6 +197,14 @@ public:
QKmsOutput output;
};
+ struct OrderedScreen
+ {
+ OrderedScreen();
+ OrderedScreen(QPlatformScreen *screen, const ScreenInfo &vinfo);
+ QPlatformScreen *screen = nullptr;
+ ScreenInfo vinfo;
+ };
+
QKmsDevice(QKmsScreenConfig *screenConfig, const QString &path = QString());
virtual ~QKmsDevice();
@@ -210,6 +219,8 @@ public:
bool threadLocalAtomicCommit(void *user_data);
void threadLocalAtomicReset();
#endif
+ void checkConnectedScreens();
+ void updateScreens();
void createScreens();
int fd() const;
@@ -218,6 +229,7 @@ public:
QKmsScreenConfig *screenConfig() const;
protected:
+ void registerScreens(QList<uint32_t> newConnects = QList<uint32_t>());
virtual QPlatformScreen *createScreen(const QKmsOutput &output) = 0;
virtual QPlatformScreen *createHeadlessScreen();
virtual void registerScreenCloning(QPlatformScreen *screen,
@@ -227,12 +239,15 @@ protected:
bool isPrimary,
const QPoint &virtualPos,
const QList<QPlatformScreen *> &virtualSiblings) = 0;
+ virtual void unregisterScreen(QPlatformScreen *screen);
+ virtual void updateScreen(QPlatformScreen *screen, const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings);
+ virtual void updateScreenOutput(QPlatformScreen *screen, const QKmsOutput &output);
void setFd(int fd);
int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector);
- QPlatformScreen *createScreenForConnector(drmModeResPtr resources,
- drmModeConnectorPtr connector,
- ScreenInfo *vinfo);
+ bool createScreenInfoForConnector(drmModeResPtr resources, drmModeConnectorPtr connector,
+ ScreenInfo &vinfo);
drmModePropertyPtr connectorProperty(drmModeConnectorPtr connector, const QByteArray &name);
drmModePropertyBlobPtr connectorPropertyBlob(drmModeConnectorPtr connector, const QByteArray &name);
typedef std::function<void(drmModePropertyPtr, quint64)> PropCallback;
@@ -257,6 +272,8 @@ protected:
quint32 m_crtc_allocator;
QList<QKmsPlane> m_planes;
+ QMap<uint32_t, OrderedScreen> m_registeredScreens;
+ QPlatformScreen *m_headlessScreen = nullptr;
private:
Q_DISABLE_COPY(QKmsDevice)
diff --git a/src/plugins/platforms/eglfs/api/qeglfscontext.cpp b/src/plugins/platforms/eglfs/api/qeglfscontext.cpp
index 9c10c1a998c..0b9db8039f1 100644
--- a/src/plugins/platforms/eglfs/api/qeglfscontext.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfscontext.cpp
@@ -79,8 +79,10 @@ void QEglFSContext::swapBuffers(QPlatformSurface *surface)
// draw the cursor
if (surface->surface()->surfaceClass() == QSurface::Window) {
QPlatformWindow *window = static_cast<QPlatformWindow *>(surface);
- if (QEglFSCursor *cursor = qobject_cast<QEglFSCursor *>(window->screen()->cursor()))
- cursor->paintOnScreen();
+ if (QPlatformScreen *screen = window->screen()) {
+ if (QEglFSCursor *cursor = qobject_cast<QEglFSCursor *>(screen->cursor()))
+ cursor->paintOnScreen();
+ }
}
qt_egl_device_integration()->waitForVSync(surface);
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
index 4abe948117e..2f278a474e0 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
@@ -154,6 +154,7 @@ QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *wi
if (!window->handle())
window->create();
static_cast<QEglFSWindow *>(window->handle())->setBackingStore(bs);
+ m_bs = bs;
return bs;
#else
Q_UNUSED(window);
@@ -175,6 +176,9 @@ QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
if (window->type() != Qt::ToolTip && window->screen() == QGuiApplication::primaryScreen())
w->requestActivateWindow();
+ if (window->isTopLevel())
+ w->setBackingStore(static_cast<QOpenGLCompositorBackingStore *>(m_bs));
+
return w;
}
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
index 2359b7f29f1..3865b7130b7 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
@@ -112,6 +112,7 @@ private:
QScopedPointer<QFbVtHandler> m_vtHandler;
QPointer<QWindow> m_pointerWindow;
bool m_disableInputHandlers;
+ mutable QPlatformBackingStore *m_bs = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h
index a0f78bb3103..cca9097e2f0 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h
@@ -62,6 +62,8 @@ public:
void reevaluateVisibilityForScreens() { setPos(pos()); }
+ QEglFSKmsGbmScreen *screen() const { return m_screen; }
+
private:
void initCursorAtlas();
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
index a7592ed55e4..9f19e649f85 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
@@ -113,13 +113,27 @@ QPlatformScreen *QEglFSKmsGbmDevice::createScreen(const QKmsOutput &output)
{
QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(this, output, false);
- createGlobalCursor(screen);
+
+ // On some platforms (e.g. rpi4), you'll get a kernel warning/error
+ // if the cursor is created 'at the same time' as the screen is created.
+ // (drmModeMoveCursor is the specific call that causes the issue)
+ // When this issue is triggered, the screen's connector is unusable until reboot
+ //
+ // Below is a work-around (without negative implications for other platforms).
+ //
+ // interval of 0 and QMetaObject::invokeMethod (w/o Qt::QueuedConnection)
+ // do no help / will still trigger issue
+ QTimer::singleShot(1, [screen, this](){
+ createGlobalCursor(screen);
+ });
return screen;
}
QPlatformScreen *QEglFSKmsGbmDevice::createHeadlessScreen()
{
+ destroyGlobalCursor();
+
return new QEglFSKmsGbmScreen(this, QKmsOutput(), true);
}
@@ -127,9 +141,6 @@ void QEglFSKmsGbmDevice::registerScreenCloning(QPlatformScreen *screen,
QPlatformScreen *screenThisScreenClones,
const QList<QPlatformScreen *> &screensCloningThisScreen)
{
- if (!screenThisScreenClones && screensCloningThisScreen.isEmpty())
- return;
-
QEglFSKmsGbmScreen *gbmScreen = static_cast<QEglFSKmsGbmScreen *>(screen);
gbmScreen->initCloning(screenThisScreenClones, screensCloningThisScreen);
}
@@ -144,6 +155,32 @@ void QEglFSKmsGbmDevice::registerScreen(QPlatformScreen *screen,
m_globalCursor->reevaluateVisibilityForScreens();
}
+void QEglFSKmsGbmDevice::unregisterScreen(QPlatformScreen *screen)
+{
+ // The global cursor holds a pointer to a QEglFSKmsGbmScreen.
+ // If that screen is being unregistered,
+ // this will recreate the global cursor with the first sibling screen.
+ if (m_globalCursor && screen == m_globalCursor->screen()) {
+ qCDebug(qLcEglfsKmsDebug) << "Destroying global GBM mouse cursor due to unregistering"
+ << "it's screen - will probably be recreated right away";
+ delete m_globalCursor;
+ m_globalCursor = nullptr;
+
+ QList<QPlatformScreen *> siblings = screen->virtualSiblings();
+ siblings.removeOne(screen);
+ if (siblings.count() > 0) {
+ QEglFSKmsGbmScreen *kmsScreen = static_cast<QEglFSKmsGbmScreen *>(siblings.first());
+ m_globalCursor = new QEglFSKmsGbmCursor(kmsScreen);
+ qCDebug(qLcEglfsKmsDebug) << "Creating new global GBM mouse cursor on sibling screen";
+ } else {
+ qCWarning(qLcEglfsKmsDebug) << "Couldn't find a sibling to recreate"
+ << "the GBM mouse cursor - it might vanish";
+ }
+ }
+
+ QEglFSKmsDevice::unregisterScreen(screen);
+}
+
bool QEglFSKmsGbmDevice::usesEventReader() const
{
static const bool eventReaderThreadDisabled = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_NO_EVENT_READER_THREAD");
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h
index e00992ed291..0ffed0ec4ef 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h
@@ -51,6 +51,7 @@ public:
bool isPrimary,
const QPoint &virtualPos,
const QList<QPlatformScreen *> &virtualSiblings) override;
+ void unregisterScreen(QPlatformScreen *screen) override;
bool usesEventReader() const;
QEglFSKmsEventReader *eventReader() { return &m_eventReader; }
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
index 05ffb3b212e..eb61de3c534 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
@@ -11,6 +11,7 @@
#include "private/qeglfscursor_p.h"
#include <QtCore/QLoggingCategory>
+#include <QtCore/QFileSystemWatcher>
#include <QtGui/QScreen>
#include <QtDeviceDiscoverySupport/private/qdevicediscovery_p.h>
@@ -23,6 +24,10 @@ QEglFSKmsGbmIntegration::QEglFSKmsGbmIntegration()
qCDebug(qLcEglfsKmsDebug, "New DRM/KMS via GBM integration created");
}
+QEglFSKmsGbmIntegration::~QEglFSKmsGbmIntegration()
+{
+}
+
#ifndef EGL_EXT_platform_base
typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
#endif
@@ -94,14 +99,16 @@ void QEglFSKmsGbmIntegration::presentBuffer(QPlatformSurface *surface)
QKmsDevice *QEglFSKmsGbmIntegration::createDevice()
{
+
+ m_deviceDiscovery = std::unique_ptr<QDeviceDiscovery>(QDeviceDiscovery::create(QDeviceDiscovery::Device_VideoMask));
+ m_kmsConfigWatcher = std::unique_ptr<QFileSystemWatcher>(new QFileSystemWatcher());
+
QString path = screenConfig()->devicePath();
if (!path.isEmpty()) {
qCDebug(qLcEglfsKmsDebug) << "GBM: Using DRM device" << path << "specified in config file";
} else {
- QDeviceDiscovery *d = QDeviceDiscovery::create(QDeviceDiscovery::Device_VideoMask);
- const QStringList devices = d->scanConnectedDevices();
+ const QStringList devices = m_deviceDiscovery->scanConnectedDevices();
qCDebug(qLcEglfsKmsDebug) << "Found the following video devices:" << devices;
- d->deleteLater();
if (Q_UNLIKELY(devices.isEmpty()))
qFatal("Could not find DRM device!");
@@ -110,6 +117,35 @@ QKmsDevice *QEglFSKmsGbmIntegration::createDevice()
qCDebug(qLcEglfsKmsDebug) << "Using" << path;
}
+ bool hotreload = !qEnvironmentVariable("QT_QPA_EGLFS_HOTPLUG_ENABLED").isEmpty();
+ if (hotreload) {
+ qCWarning(qLcEglfsKmsDebug) << "EGLFS/KMS: Hot-Reload on KMS-events enabled, be aware that"
+ << "this requires actions in UI code for proper functionallity"
+ << "(e.g. close/open windows on screen's disconnect/connect)";
+ QObject::connect(m_deviceDiscovery.get(), &QDeviceDiscovery::deviceChanged,
+ m_deviceDiscovery.get(), [this](const QString &deviceNode) {
+ qCDebug(qLcEglfsKmsDebug) << "KMS device changed:" << deviceNode;
+ m_device->checkConnectedScreens();
+ });
+ }
+
+ QString json = qEnvironmentVariable("QT_QPA_EGLFS_KMS_CONFIG");
+ if (json.isEmpty())
+ json = qEnvironmentVariable("QT_QPA_KMS_CONFIG");
+
+ if (!json.isEmpty()) {
+ m_kmsConfigWatcher->addPath(json);
+ QObject::connect(m_kmsConfigWatcher.get(), &QFileSystemWatcher::fileChanged,
+ m_kmsConfigWatcher.get(), [this, json]() {
+ qCDebug(qLcEglfsKmsDebug) << "KMS config-file has changed! path:"
+ << json;
+ m_screenConfig->refreshConfig();
+ m_device->updateScreens();
+ m_kmsConfigWatcher->addPath(json); // as per QFileSystemWatcher doc we have to re-add
+ // the path in case it's a new file
+ });
+ }
+
return new QEglFSKmsGbmDevice(screenConfig(), path);
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h
index fb118438d25..7c2c2a474d7 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h
@@ -24,11 +24,14 @@
QT_BEGIN_NAMESPACE
class QEglFSKmsDevice;
+class QDeviceDiscovery;
+class QFileSystemWatcher;
class Q_EGLFS_EXPORT QEglFSKmsGbmIntegration : public QEglFSKmsIntegration
{
public:
QEglFSKmsGbmIntegration();
+ ~QEglFSKmsGbmIntegration() override;
EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) override;
EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format) override;
@@ -42,6 +45,8 @@ protected:
QKmsDevice *createDevice() override;
private:
+ std::unique_ptr<QDeviceDiscovery> m_deviceDiscovery;
+ std::unique_ptr<QFileSystemWatcher> m_kmsConfigWatcher;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index 00fecb87f1f..332030f03f2 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -20,7 +20,7 @@
QT_BEGIN_NAMESPACE
-QMutex QEglFSKmsGbmScreen::m_nonThreadedFlipMutex;
+QMutex QEglFSKmsGbmScreen::s_nonThreadedFlipMutex;
static inline uint32_t drmFormatToGbmFormat(uint32_t drmFormat)
{
@@ -92,9 +92,26 @@ QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsDevice *device, const QKmsOutput
QEglFSKmsGbmScreen::~QEglFSKmsGbmScreen()
{
const int remainingScreenCount = qGuiApp->screens().count();
- qCDebug(qLcEglfsKmsDebug, "Screen dtor. Remaining screens: %d", remainingScreenCount);
+ qCDebug(qLcEglfsKmsDebug, "Screen dtor. %p Remaining screens: %d", this, remainingScreenCount);
if (!remainingScreenCount && !device()->screenConfig()->separateScreens())
static_cast<QEglFSKmsGbmDevice *>(device())->destroyGlobalCursor();
+
+ if (m_cloneSource) {
+ // Remove this screen from the screen that has it as a clone destination
+ QList<CloneDestination> &dests = m_cloneSource->m_cloneDests;
+ auto newEnd = std::remove_if(dests.begin(), dests.end(),
+ [this](CloneDestination &dest) {
+ return dest.screen == this;
+ });
+ dests.erase(newEnd, dests.end());
+ }
+
+ // Other screens can no longer have this screen as a clone source
+ for (CloneDestination &dest : m_cloneDests) {
+ dest.screen->m_cloneSource = nullptr;
+ // Mode must be set again before flipping
+ dest.screen->m_output.mode_set = false;
+ }
}
QPlatformCursor *QEglFSKmsGbmScreen::cursor() const
@@ -206,9 +223,12 @@ void QEglFSKmsGbmScreen::initCloning(QPlatformScreen *screenThisScreenClones,
if (clonesAnother) {
m_cloneSource = static_cast<QEglFSKmsGbmScreen *>(screenThisScreenClones);
qCDebug(qLcEglfsKmsDebug, "Screen %s clones %s", qPrintable(name()), qPrintable(m_cloneSource->name()));
+ } else {
+ m_cloneSource = nullptr;
}
// clone sources need to know their additional destinations
+ m_cloneDests.clear();
for (QPlatformScreen *s : screensCloningThisScreen) {
CloneDestination d;
d.screen = static_cast<QEglFSKmsGbmScreen *>(s);
@@ -271,8 +291,11 @@ void QEglFSKmsGbmScreen::nonThreadedPageFlipHandler(int fd,
// note that with cloning involved this callback is called also for screens that clone another one
Q_UNUSED(fd);
QEglFSKmsGbmScreen *screen = static_cast<QEglFSKmsGbmScreen *>(user_data);
- screen->flipFinished();
- screen->pageFlipped(sequence, tv_sec, tv_usec);
+ // The screen might have been deleted when DRM calls this handler
+ if (QEglFSKmsScreen::isScreenKnown(screen)) {
+ screen->flipFinished();
+ screen->pageFlipped(sequence, tv_sec, tv_usec);
+ }
}
void QEglFSKmsGbmScreen::waitForFlipWithEventReader(QEglFSKmsGbmScreen *screen)
@@ -280,7 +303,21 @@ void QEglFSKmsGbmScreen::waitForFlipWithEventReader(QEglFSKmsGbmScreen *screen)
m_flipMutex.lock();
QEglFSKmsGbmDevice *dev = static_cast<QEglFSKmsGbmDevice *>(device());
dev->eventReader()->startWaitFlip(screen, &m_flipMutex, &m_flipCond);
- m_flipCond.wait(&m_flipMutex);
+
+ // We should only wait forever on this screen, clones should have a timeout
+ // (e.g. I clone might have been created just before the flip,
+ // we might wait for it but it might not know about waking us up)
+ bool succ = false;
+ if (screen == this)
+ succ = m_flipCond.wait(&m_flipMutex);
+ else
+ succ = m_flipCond.wait(&m_flipMutex, 300);
+
+ if (!succ)
+ qCWarning(qLcEglfsKmsDebug) << "timeout on waitForFlipWithEventReader, screen to wait for:"
+ << screen << ", screen waiting (shouldn't be the same screen):"
+ << this;
+
m_flipMutex.unlock();
screen->flipFinished();
}
@@ -306,7 +343,7 @@ void QEglFSKmsGbmScreen::waitForFlip()
waitForFlipWithEventReader(d.screen);
}
} else {
- QMutexLocker lock(&m_nonThreadedFlipMutex);
+ QMutexLocker lock(&s_nonThreadedFlipMutex);
while (m_gbm_bo_next) {
drmEventContext drmEvent;
memset(&drmEvent, 0, sizeof(drmEvent));
@@ -359,15 +396,10 @@ static void addAtomicFlip(drmModeAtomicReq *request, const QKmsOutput &output, u
void QEglFSKmsGbmScreen::flip()
{
- // For headless screen just return silently. It is not necessarily an error
+ // For headless or cloned screen just return silently. It is not necessarily an error
// to end up here, so show no warnings.
- if (m_headless)
- return;
-
- if (m_cloneSource) {
- qWarning("Screen %s clones another screen. swapBuffers() not allowed.", qPrintable(name()));
+ if (m_headless || m_cloneSource)
return;
- }
if (!m_gbm_surface) {
qWarning("Cannot sync before platform init!");
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h
index aca34fcae21..65625a3c1cd 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h
@@ -67,7 +67,7 @@ protected:
QMutex m_flipMutex;
QWaitCondition m_flipCond;
- static QMutex m_nonThreadedFlipMutex;
+ static QMutex s_nonThreadedFlipMutex;
QScopedPointer<QEglFSKmsGbmCursor> m_cursor;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
index ece19f46a49..ff4921c2b15 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
@@ -213,9 +213,13 @@ QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const
QEglFSKmsEglDeviceWindow *eglWindow = new QEglFSKmsEglDeviceWindow(window, this);
m_funcs->initialize(eglWindow->screen()->display());
- if (Q_UNLIKELY(!(m_funcs->has_egl_output_base && m_funcs->has_egl_output_drm && m_funcs->has_egl_stream &&
- m_funcs->has_egl_stream_producer_eglsurface && m_funcs->has_egl_stream_consumer_egloutput)))
+ if (Q_UNLIKELY(!(m_funcs->has_egl_output_base && m_funcs->has_egl_output_drm
+ && m_funcs->has_egl_stream && m_funcs->has_egl_stream_producer_eglsurface
+ && m_funcs->has_egl_stream_consumer_egloutput))) {
+ qCDebug(qLcEglfsKmsDebug, "EGL_EXTENSIONS %s",
+ eglQueryString(eglWindow->screen()->display(), EGL_EXTENSIONS));
qFatal("Required extensions missing!");
+ }
return eglWindow;
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
index 5af45e63a2f..5775ac3607a 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
@@ -71,7 +71,7 @@ QEglFSKmsEglDeviceScreen::~QEglFSKmsEglDeviceScreen()
}
const int remainingScreenCount = qGuiApp->screens().size();
- qCDebug(qLcEglfsKmsDebug, "Screen dtor. Remaining screens: %d", remainingScreenCount);
+ qCDebug(qLcEglfsKmsDebug, "Screen dtor. %p Remaining screens: %d", this, remainingScreenCount);
if (!remainingScreenCount && !device()->screenConfig()->separateScreens())
static_cast<QEglFSKmsEglDevice *>(device())->destroyGlobalCursor();
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
index 037b26f023e..59ca53355d6 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
@@ -25,4 +25,39 @@ void QEglFSKmsDevice::registerScreen(QPlatformScreen *screen,
QWindowSystemInterface::handleScreenAdded(s, isPrimary);
}
+void QEglFSKmsDevice::unregisterScreen(QPlatformScreen *screen)
+{
+ QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen);
+ for (QPlatformScreen *sibling : s->virtualSiblings())
+ static_cast<QEglFSKmsScreen *>(sibling)->removeSibling(s);
+
+ QWindowSystemInterface::handleScreenRemoved(screen);
+}
+
+void QEglFSKmsDevice::updateScreen(QPlatformScreen *screen, const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings)
+{
+ QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen);
+ QRect before = s->geometry();
+ s->setVirtualPosition(virtualPos);
+ s->setVirtualSiblings(virtualSiblings);
+ QRect after = s->geometry();
+
+ if (before != after)
+ QWindowSystemInterface::handleScreenGeometryChange(s->screen(), after,
+ s->availableGeometry());
+}
+
+void QEglFSKmsDevice::updateScreenOutput(QPlatformScreen *screen, const QKmsOutput &output)
+{
+ QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen);
+ QRect before = s->geometry();
+ s->updateOutput(output);
+ QRect after = s->geometry();
+
+ if (before != after)
+ QWindowSystemInterface::handleScreenGeometryChange(s->screen(), after,
+ s->availableGeometry());
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h
index 6e11953a699..49b82d8baad 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h
@@ -30,6 +30,13 @@ public:
bool isPrimary,
const QPoint &virtualPos,
const QList<QPlatformScreen *> &virtualSiblings) override;
+
+ void unregisterScreen(QPlatformScreen *screen) override;
+
+ void updateScreen(QPlatformScreen *screen, const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings) override;
+
+ void updateScreenOutput(QPlatformScreen *screen, const QKmsOutput &output) override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
index c0c96554962..fa735388bc0 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
@@ -20,7 +20,10 @@ static void pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec,
t->eventHost()->handlePageFlipCompleted(user_data);
QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(user_data);
- screen->pageFlipped(sequence, tv_sec, tv_usec);
+ if (QEglFSKmsScreen::isScreenKnown(screen))
+ screen->pageFlipped(sequence, tv_sec, tv_usec);
+ else
+ qWarning("Deleted screen got it's pageFlipHandler called; Dead pointer: %p", user_data);
}
class RegisterWaitFlipEvent : public QEvent
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
index cc7381fb701..a40287bdfed 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
@@ -16,6 +16,8 @@
QT_BEGIN_NAMESPACE
+QSet<QEglFSKmsScreen *> QEglFSKmsScreen::s_screens;
+
class QEglFSKmsInterruptHandler : public QObject
{
public:
@@ -59,10 +61,14 @@ QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsDevice *device, const QKmsOutput &outp
} else {
qCDebug(qLcEglfsKmsDebug) << "No EDID data for output" << name();
}
+
+ s_screens.insert(this);
}
QEglFSKmsScreen::~QEglFSKmsScreen()
{
+ s_screens.remove(this);
+
m_output.cleanup(m_device);
delete m_interruptHandler;
}
@@ -166,6 +172,11 @@ void QEglFSKmsScreen::waitForFlip()
{
}
+void QEglFSKmsScreen::updateOutput(QKmsOutput output)
+{
+ m_output = output;
+}
+
void QEglFSKmsScreen::restoreMode()
{
m_output.restoreMode(m_device);
@@ -180,6 +191,11 @@ qreal QEglFSKmsScreen::refreshRate() const
return refresh > 0 ? refresh : 60;
}
+void QEglFSKmsScreen::removeSibling(QPlatformScreen *screen)
+{
+ m_siblings.removeAll(screen);
+}
+
QList<QPlatformScreen::Mode> QEglFSKmsScreen::modes() const
{
QList<QPlatformScreen::Mode> list;
@@ -227,4 +243,9 @@ void QEglFSKmsScreen::pageFlipped(unsigned int sequence, unsigned int tv_sec, un
Q_UNUSED(tv_usec);
}
+bool QEglFSKmsScreen::isScreenKnown(QEglFSKmsScreen *s)
+{
+ return s_screens.contains(s);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h
index 6fb1f9a1348..2dc49152a97 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h
@@ -58,6 +58,7 @@ public:
QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; }
void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; }
+ void removeSibling(QPlatformScreen *screen);
QList<QPlatformScreen::Mode> modes() const override;
@@ -68,6 +69,7 @@ public:
virtual void waitForFlip();
+ void updateOutput(QKmsOutput output);
QKmsOutput &output() { return m_output; }
void restoreMode();
@@ -80,6 +82,8 @@ public:
void setCursorOutOfRange(bool b) { m_cursorOutOfRange = b; }
virtual void pageFlipped(unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec);
+ static bool isScreenKnown(QEglFSKmsScreen *s);
+
protected:
QEglFSKmsDevice *m_device;
@@ -95,6 +99,8 @@ protected:
QEglFSKmsInterruptHandler *m_interruptHandler;
bool m_headless;
+
+ static QSet<QEglFSKmsScreen *> s_screens;
};
QT_END_NAMESPACE
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp
index 7179109505b..3f40dea5eb9 100644
--- a/src/plugins/styles/modernwindows/qwindows11style.cpp
+++ b/src/plugins/styles/modernwindows/qwindows11style.cpp
@@ -1662,7 +1662,7 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
}
case CE_ItemViewItem: {
if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
- if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget)) {
+ if (qobject_cast<const QAbstractItemView *>(widget)) {
QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget);
@@ -1764,10 +1764,10 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
- if (!view || !view->isPersistentEditorOpen(vopt->index)) {
- painter->setPen(highlightCurrent && highContrastTheme ? vopt->palette.base().color() : option->palette.text().color());
- d->viewItemDrawText(painter, vopt, textRect);
- }
+ painter->setPen(highlightCurrent && highContrastTheme ? vopt->palette.base().color()
+ : vopt->palette.text().color());
+ d->viewItemDrawText(painter, vopt, textRect);
+
// paint a vertical marker for QListView
if (vopt->state & State_Selected) {
if (const QListView *lv = qobject_cast<const QListView *>(widget);
diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp
index 8a94aa0e19f..f41242f357d 100644
--- a/src/testlib/qtestlog.cpp
+++ b/src/testlib/qtestlog.cpp
@@ -193,6 +193,7 @@ namespace QTest {
if (const auto *regex = get_if<QRegularExpression>(&pattern))
return regex->match(message).hasMatch();
#endif
+ Q_ASSERT(pattern.metaType() == QMetaType::fromType<QString>());
return stringsMatch(pattern.toString(), message);
}
@@ -265,6 +266,9 @@ namespace QTest {
if (!message.contains(*regex))
continue;
#endif
+ } else {
+ // The no-arg clearFailOnWarnings()'s null pattern matches all messages.
+ Q_ASSERT(pattern.isNull());
}
const size_t maxMsgLen = 1024;
@@ -402,6 +406,10 @@ void QTestLog::printUnhandledIgnoreMessages()
} else if (const auto *regex = get_if<QRegularExpression>(&list->pattern)) {
message = "Did not receive any message matching: \"%1\""_L1.arg(regex->pattern());
#endif
+ } else {
+ Q_UNREACHABLE();
+ message = "Missing message of unrecognized pattern type: \"%1\""_L1.arg(
+ list->pattern.metaType().name());
}
for (auto &logger : QTest::loggers->allLoggers())
logger->addMessage(QAbstractTestLogger::Info, message);
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 14280712154..64fd334d467 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -259,6 +259,7 @@ bool Moc::parseEnum(EnumDef *def, ClassDef *containingClass)
return false; // anonymous enum
isTypdefEnum = true;
}
+ def->lineNumber = symbol().lineNum;
if (test(COLON)) { // C++11 strongly typed enum
// enum Foo : unsigned long { ... };
def->type = normalizeType(parseType().name);
@@ -464,6 +465,8 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
}
next(LPAREN, "Not a signal or slot declaration");
def->name = tempType.name;
+ def->lineNumber = symbol().lineNum;
+
scopedFunctionName = tempType.isScoped;
if (!test(RPAREN)) {
@@ -1366,6 +1369,7 @@ void Moc::createPropertyDef(PropertyDef &propDef, int propertyIndex, Moc::Proper
{
propDef.location = index;
propDef.relativeIndex = propertyIndex;
+ propDef.lineNumber = symbol().lineNum;
Type t = parseType();
QByteArray type = t.name;
@@ -2156,6 +2160,7 @@ QJsonObject FunctionDef::toJson(int index) const
if (revision > 0)
fdef["revision"_L1] = revision;
+ fdef["lineNumber"_L1] = lineNumber;
if (wasCloned)
fdef["isCloned"_L1] = true;
@@ -2220,6 +2225,7 @@ QJsonObject PropertyDef::toJson() const
prop["final"_L1] = final;
prop["required"_L1] = required;
prop["index"_L1] = relativeIndex;
+ prop["lineNumber"_L1] = lineNumber;
if (revision > 0)
prop["revision"_L1] = revision;
@@ -2231,6 +2237,7 @@ QJsonObject EnumDef::toJson(const ClassDef &cdef) const
QJsonObject def;
uint flags = this->flags | cdef.enumDeclarations.value(name);
def["name"_L1] = QString::fromUtf8(name);
+ def["lineNumber"_L1] = lineNumber;
if (!enumName.isEmpty())
def["alias"_L1] = QString::fromUtf8(enumName);
if (!type.isEmpty())
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index f08edb3f0d2..fcf000c655f 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -58,6 +58,7 @@ struct EnumDef
QFlags<QtMocConstants::EnumFlags> flags = {};
QJsonObject toJson(const ClassDef &cdef) const;
QByteArray qualifiedType(const ClassDef *cdef) const;
+ int lineNumber = 0;
};
Q_DECLARE_TYPEINFO(EnumDef, Q_RELOCATABLE_TYPE);
@@ -84,6 +85,7 @@ struct FunctionDef
enum Access { Private, Protected, Public };
Access access = Private;
int revision = 0;
+ int lineNumber = 0;
bool isConst = false;
bool isVirtual = false;
@@ -130,6 +132,7 @@ struct PropertyDef
bool final = false;
bool required = false;
int relativeIndex = -1; // property index in current metaobject
+ int lineNumber = 0;
qsizetype location = -1; // token index, used for error reporting