From 38a16b8be0a1e408fae19611e68f2caa12440d68 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Tue, 3 Apr 2018 19:37:29 -0700 Subject: [PATCH 01/12] QMacStyle doesn't depend on Carbon anymore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We also remove the old documentation file that is now mostly outdated. Change-Id: I32c9c6b0984be5e41653a92b0b9287a89f73ee38 Reviewed-by: Morten Johan Sørvig --- src/plugins/styles/mac/mac.pro | 2 +- src/plugins/styles/mac/qmacstyle.qdoc | 207 --------------------- src/plugins/styles/mac/qmacstyle_mac_p_p.h | 3 - 3 files changed, 1 insertion(+), 211 deletions(-) delete mode 100644 src/plugins/styles/mac/qmacstyle.qdoc diff --git a/src/plugins/styles/mac/mac.pro b/src/plugins/styles/mac/mac.pro index f3c7c1c067..9044354c07 100644 --- a/src/plugins/styles/mac/mac.pro +++ b/src/plugins/styles/mac/mac.pro @@ -10,7 +10,7 @@ HEADERS += \ qmacstyle_mac_p.h \ qmacstyle_mac_p_p.h -LIBS_PRIVATE += -framework AppKit -framework ApplicationServices -framework Carbon +LIBS_PRIVATE += -framework AppKit DISTFILES += macstyle.json diff --git a/src/plugins/styles/mac/qmacstyle.qdoc b/src/plugins/styles/mac/qmacstyle.qdoc deleted file mode 100644 index 30b3d7775f..0000000000 --- a/src/plugins/styles/mac/qmacstyle.qdoc +++ /dev/null @@ -1,207 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -/*! - \class QMacStyle - \brief The QMacStyle class provides a \macos style using the Apple Appearance Manager. - - \ingroup appearance - \inmodule QtWidgets - \internal - - This class is implemented as a wrapper to the HITheme - APIs, allowing applications to be styled according to the current - theme in use on \macos. This is done by having primitives - in QStyle implemented in terms of what \macos would normally theme. - - \warning This style is only available on \macos because it relies on the - HITheme APIs. - - There are additional issues that should be taken - into consideration to make an application compatible with the - \l{Apple Human Interface Guidelines}{Apple Human Interface Guidelines}. Some of these issues are outlined - below. - - \list - - \li Layout - The restrictions on window layout are such that some - aspects of layout that are style-dependent cannot be achieved - using QLayout. Changes are being considered (and feedback would be - appreciated) to make layouts QStyle-able. Some of the restrictions - involve horizontal and vertical widget alignment and widget size - (covered below). - - \li Widget size - \macos allows widgets to have specific fixed sizes. Qt - does not fully implement this behavior so as to maintain cross-platform - compatibility. As a result some widgets sizes may be inappropriate (and - subsequently not rendered correctly by the HITheme APIs).The - QWidget::sizeHint() will return the appropriate size for many - managed widgets (widgets enumerated in \l QStyle::ContentsType). - - \li Effects - QMacStyle uses HITheme for performing most of the drawing, but - also uses emulation in a few cases where HITheme does not provide the - required functionality (for example, tab bars on Panther, the toolbar - separator, etc). We tried to make the emulation as close to the original as - possible. Please report any issues you see in effects or non-standard - widgets. - - \endlist - - There are other issues that need to be considered in the feel of - your application (including the general color scheme to match the - Aqua colors). The Guidelines mentioned above will remain current - with new advances and design suggestions for \macos. - - Note that the functions provided by QMacStyle are - reimplementations of QStyle functions; see QStyle for their - documentation. - - \image qmacstyle.png - \sa QWindowsVistaStyle, QWindowsStyle, QFusionStyle -*/ - - -/*! - \enum QStyleHelper::WidgetSizePolicy - - \value SizeSmall - \value SizeLarge - \value SizeMini - \value SizeDefault -*/ - -/*! \fn QMacStyle::QMacStyle() - Constructs a QMacStyle object. -*/ - -/*! \fn QMacStyle::~QMacStyle() - Destructs a QMacStyle object. -*/ - -/*! \fn void QMacStyle::polish(QPalette &pal) - \reimp -*/ - -/*! \fn void QMacStyle::polish(QApplication *) - \reimp -*/ - -/*! \fn void QMacStyle::unpolish(QApplication *) - \reimp -*/ - -/*! \fn void QMacStyle::polish(QWidget* w) - \reimp -*/ - -/*! \fn void QMacStyle::unpolish(QWidget* w) - \reimp -*/ - -/*! \fn int QMacStyle::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const - \reimp -*/ - -/*! \fn QPalette QMacStyle::standardPalette() const - \reimp -*/ - -/*! \fn int QMacStyle::styleHint(QStyle::StyleHint sh, const QStyleOption *opt, const QWidget *w, QStyleHintReturn *hret) const - \reimp -*/ - -/*! \fn QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const - \reimp -*/ - -/*! \fn QPixmap QMacStyle::standardPixmap(QStyle::StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget) const - \reimp -*/ - -/*! \fn void QStyleHelper::setWidgetSizePolicy(const QWidget *widget, QStyleHelper::WidgetSizePolicy policy) - - \obsolete - - Call QWidget::setAttribute() with Qt::WA_MacMiniSize, Qt::WA_MacSmallSize, - or Qt::WA_MacNormalSize instead. -*/ - -/*! \fn QStyleHelper::WidgetSizePolicy QStyleHelper::widgetSizePolicy(const QWidget *widget, const QStyleOption *opt) - \obsolete - - Call QWidget::testAttribute() with Qt::WA_MacMiniSize, Qt::WA_MacSmallSize, - or Qt::WA_MacNormalSize instead. -*/ - -/*! \fn void QMacStyle::drawPrimitive(QStyle::PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w) const - - \reimp -*/ - -/*! \fn void QMacStyle::drawControl(QStyle::ControlElement ce, const QStyleOption *opt, QPainter *p, const QWidget *w) const - - \reimp -*/ - -/*! \fn QRect QMacStyle::subElementRect(QStyle::SubElement sr, const QStyleOption *opt, const QWidget *widget) const - - \reimp -*/ - -/*! \fn void QMacStyle::drawComplexControl(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *widget) const - \reimp -*/ - -/*! \fn QStyle::SubControl QMacStyle::hitTestComplexControl(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt, const QWidget *widget) const - \reimp -*/ - -/*! \fn QRect QMacStyle::subControlRect(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QStyle::SubControl sc, const QWidget *widget) const - \reimp -*/ - -/*! \fn QSize QMacStyle::sizeFromContents(QStyle::ContentsType ct, const QStyleOption *opt, const QSize &csz, const QWidget *widget) const - \reimp -*/ - -/*! \fn void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal, bool enabled, const QString &text, QPalette::ColorRole textRole) const - \reimp -*/ - -/*! \fn bool QMacStyle::event(QEvent *e) - \reimp -*/ - -/*! \fn QIcon QMacStyle::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *opt, const QWidget *widget) const - \reimp -*/ - -/*! \fn int QMacStyle::layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget) const - \reimp -*/ - diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h index 705bb2b462..2a81274765 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h @@ -41,9 +41,6 @@ #ifndef QMACSTYLE_MAC_P_P_H #define QMACSTYLE_MAC_P_P_H -#include -#undef check - #include #include #include "qmacstyle_mac_p.h" From e8733ffc510cdf3a2e0c21afeeb11535e56d5e2b Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Fri, 6 Apr 2018 16:09:18 +0300 Subject: [PATCH 02/12] QWindowsPipeReader: fix waiting on inactive pipe To read data from a named pipe, QWindowsPipeReader uses the ReadFileEx() function which runs asynchronously. When reading is completed and the thread is in an alertable wait state, the notified() callback is called by the system, reporting a completion status of that operation. Then the callback queues a readyRead signal and starts a new sequence. The latter is skipped if the pipe is broken or the read buffer is full. Thus, if an application does not run the event loop, the next call to QWindowsPipeReader::waitForReadyRead() should emit the queued signal and report true to the caller even if no new read operation was started. Change-Id: I37102dbb1c00191d93365bfc2e94e743d9f3962a Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qwindowspipereader.cpp | 6 +++--- .../network/socket/qlocalsocket/tst_qlocalsocket.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index 3055fb392e..2312d5ca63 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -316,15 +316,15 @@ void QWindowsPipeReader::emitPendingReadyRead() */ bool QWindowsPipeReader::waitForReadyRead(int msecs) { - if (!readSequenceStarted) - return false; - if (readyReadPending) { if (!inReadyRead) emitPendingReadyRead(); return true; } + if (!readSequenceStarted) + return false; + if (!waitForNotification(msecs)) return false; diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp index 08e9e05463..53d260f19e 100644 --- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp @@ -42,6 +42,10 @@ #include // for unlink() #endif +#ifdef Q_OS_WIN +#include +#endif + Q_DECLARE_METATYPE(QLocalSocket::LocalSocketError) Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState) Q_DECLARE_METATYPE(QLocalServer::SocketOption) @@ -629,6 +633,14 @@ void tst_QLocalSocket::readBufferOverflow() QCOMPARE(client.bytesAvailable(), 0); #ifdef Q_OS_WIN + serverSocket->write(buffer, readBufferSize); + QVERIFY(serverSocket->waitForBytesWritten()); + + // ensure the read completion routine is called + SleepEx(100, true); + QVERIFY(client.waitForReadyRead()); + QCOMPARE(client.read(buffer, readBufferSize), qint64(readBufferSize)); + // Test overflow caused by an asynchronous pipe operation. client.setReadBufferSize(1); serverSocket->write(buffer, 2); From 7f782e1fc41ff7694f9bf7434d5a4db0545c0413 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Thu, 5 Apr 2018 13:02:35 +0200 Subject: [PATCH 03/12] Fix crash if QPixmap::defaultDepth() is called when no QGuiApplication This static method can be called before QGuiApplication is created. At that point there is yet no primary screen, so the implementation needs to guard against dereferencing a nullptr. Task-number: QTBUG-67309 Change-Id: I6b7b9e97b1c3c79bf2f9c6d6247c3b10f39f7a55 Reviewed-by: Friedemann Kleint --- src/gui/image/qpixmap.cpp | 8 +++++++- .../gui/kernel/qguiapplication/tst_qguiapplication.cpp | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 5b3e3985a7..1ea503a268 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1467,12 +1467,18 @@ QBitmap QPixmap::mask() const On all platforms the depth of the primary screen will be returned. + \note QGuiApplication must be created before calling this function. + \sa depth(), QColormap::depth(), {QPixmap#Pixmap Information}{Pixmap Information} */ int QPixmap::defaultDepth() { - return QGuiApplication::primaryScreen()->depth(); + QScreen *primary = QGuiApplication::primaryScreen(); + if (Q_LIKELY(primary)) + return primary->depth(); + qWarning("QPixmap: QGuiApplication must be created before calling defaultDepth()."); + return 0; } /*! diff --git a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp index b5a69d920a..fc011d726d 100644 --- a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp +++ b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp @@ -1099,6 +1099,8 @@ void tst_QGuiApplication::staticFunctions() QGuiApplication::setQuitOnLastWindowClosed(true); QGuiApplication::quitOnLastWindowClosed(); QGuiApplication::applicationState(); + + QPixmap::defaultDepth(); } void tst_QGuiApplication::settableStyleHints_data() From ca58764da1cc57c8546607c0a83d085a8c5a298e Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Fri, 16 Mar 2018 15:10:10 +0100 Subject: [PATCH 04/12] PDF engine: handle abnormally long string cases The output routine used a fixed size scratch buffer, with no attempt to handle overrun. Add a simple fallback code path for such (extremely rare) cases. Task-number: QTBUG-66788 Change-Id: I52531b829baeaa48a8fb5a637a020ee9f89d270a Reviewed-by: Friedemann Kleint --- src/gui/painting/qpdf.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index e421055ef3..e58f9cee4c 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -2045,7 +2045,6 @@ void QPdfEnginePrivate::printString(const QString &string) } -// For strings up to 10000 bytes only ! void QPdfEnginePrivate::xprintf(const char* fmt, ...) { if (!stream) @@ -2057,12 +2056,18 @@ void QPdfEnginePrivate::xprintf(const char* fmt, ...) va_list args; va_start(args, fmt); int bufsize = qvsnprintf(buf, msize, fmt, args); - - Q_ASSERT(bufsizewriteRawData(buf, bufsize); + if (Q_LIKELY(bufsize < msize)) { + stream->writeRawData(buf, bufsize); + } else { + // Fallback for abnormal cases + QScopedArrayPointer tmpbuf(new char[bufsize + 1]); + va_start(args, fmt); + bufsize = qvsnprintf(tmpbuf.data(), bufsize + 1, fmt, args); + va_end(args); + stream->writeRawData(tmpbuf.data(), bufsize); + } streampos += bufsize; } From 66cc08961f8a6a0b499a22ae205e639eb821e0b7 Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Tue, 3 Apr 2018 16:54:23 +0300 Subject: [PATCH 05/12] tst_QWidget: Avoid unconditional qWait()s Task-number: QTBUG-63992 Change-Id: I1696ccbdf0523ece694f2dac52c015443c8b19fb Reviewed-by: Gatis Paeglis --- .../widgets/kernel/qwidget/tst_qwidget.cpp | 104 ++++-------------- 1 file changed, 19 insertions(+), 85 deletions(-) diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 5a9c5dd175..823a52ce70 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -620,7 +620,7 @@ void tst_QWidget::initTestCase() void tst_QWidget::cleanup() { - QVERIFY(QApplication::topLevelWidgets().isEmpty()); + QTRY_VERIFY(QApplication::topLevelWidgets().isEmpty()); } void tst_QWidget::fontPropagation() @@ -1619,13 +1619,11 @@ void tst_QWidget::focusChainOnHide() qApp->setActiveWindow(parent->window()); child->activateWindow(); child->setFocus(); - qApp->processEvents(); - QTRY_COMPARE(child->hasFocus(), true); + QTRY_VERIFY(child->hasFocus()); child->hide(); - qApp->processEvents(); - QTRY_COMPARE(parent->hasFocus(), true); + QTRY_VERIFY(parent->hasFocus()); QCOMPARE(parent.data(), qApp->focusWidget()); } @@ -2632,25 +2630,21 @@ void tst_QWidget::normalGeometry() QCOMPARE(parent.normalGeometry(), geom); parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); - QTest::qWait(10); QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized); QTRY_VERIFY(parent.geometry() != geom); QTRY_COMPARE(parent.normalGeometry(), geom); parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); - QTest::qWait(10); QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized)); QTRY_COMPARE(parent.geometry(), geom); QTRY_COMPARE(parent.normalGeometry(), geom); parent.showMaximized(); - QTest::qWait(10); QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized); QTRY_VERIFY(parent.geometry() != geom); QCOMPARE(parent.normalGeometry(), geom); parent.showNormal(); - QTest::qWait(10); QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized)); QTRY_COMPARE(parent.geometry(), geom); QCOMPARE(parent.normalGeometry(), geom); @@ -2723,8 +2717,7 @@ void tst_QWidget::setGeometry() tlw.setGeometry(tr); child.setGeometry(cr); tlw.showNormal(); - QTest::qWait(50); - QCOMPARE(tlw.geometry().size(), tr.size()); + QTRY_COMPARE(tlw.geometry().size(), tr.size()); QCOMPARE(child.geometry(), cr); tlw.setParent(0, Qt::Window|Qt::FramelessWindowHint); @@ -2847,7 +2840,6 @@ void tst_QWidget::lostUpdatesOnHide() void tst_QWidget::raise() { - QTest::qWait(10); QScopedPointer parentPtr(new QWidget); parentPtr->resize(200, 200); parentPtr->setObjectName(QLatin1String("raise")); @@ -2872,7 +2864,6 @@ void tst_QWidget::raise() parentPtr->show(); QVERIFY(QTest::qWaitForWindowExposed(parentPtr.data())); - QTest::qWait(10); #ifdef Q_OS_OSX if (child1->internalWinId()) { @@ -2919,15 +2910,13 @@ void tst_QWidget::raise() QWidget *parent = parentPtr.take(); parent->setParent(&topLevel); topLevel.show(); - QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); - QTest::qWait(50); UpdateWidget *onTop = new UpdateWidget(&topLevel); onTop->reset(); onTop->resize(topLevel.size()); onTop->setAutoFillBackground(true); onTop->show(); - QTest::qWait(50); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); QTRY_VERIFY(onTop->numPaintEvents > 0); onTop->reset(); @@ -3436,7 +3425,6 @@ void tst_QWidget::widgetAt() w2->setWindowTitle(w2->objectName()); w1->showNormal(); QVERIFY(QTest::qWaitForWindowExposed(w1.data())); - qApp->processEvents(); const QPoint testPos = referencePos + QPoint(100, 100); QWidget *wr; QTRY_VERIFY((wr = QApplication::widgetAt((testPos)))); @@ -3444,29 +3432,22 @@ void tst_QWidget::widgetAt() w2->showNormal(); QVERIFY(QTest::qWaitForWindowExposed(w2.data())); - qApp->processEvents(); - qApp->processEvents(); - qApp->processEvents(); QTRY_VERIFY((wr = QApplication::widgetAt(testPos))); QCOMPARE(wr->objectName(), QString("w2")); w2->lower(); - qApp->processEvents(); QTRY_VERIFY((wr = QApplication::widgetAt(testPos)) && wr->objectName() == QString("w1")); w2->raise(); - qApp->processEvents(); QTRY_VERIFY((wr = QApplication::widgetAt(testPos)) && wr->objectName() == QString("w2")); QWidget *w3 = new QWidget(w2.data()); w3->setGeometry(10,10,50,50); w3->setObjectName("w3"); w3->showNormal(); - qApp->processEvents(); QTRY_VERIFY((wr = QApplication::widgetAt(testPos)) && wr->objectName() == QString("w3")); w3->setAttribute(Qt::WA_TransparentForMouseEvents); - qApp->processEvents(); QTRY_VERIFY((wr = QApplication::widgetAt(testPos)) && wr->objectName() == QString("w2")); if (!QGuiApplicationPrivate::platformIntegration() @@ -3478,8 +3459,6 @@ void tst_QWidget::widgetAt() QPoint point = w2->mapFromGlobal(testPos); rgn -= QRect(point, QSize(1,1)); w2->setMask(rgn); - qApp->processEvents(); - QTest::qWait(10); QTRY_VERIFY((wr = QApplication::widgetAt(testPos))); QTRY_COMPARE(wr->objectName(), w1->objectName()); @@ -3493,8 +3472,6 @@ void tst_QWidget::widgetAt() p.drawPoint(w2->mapFromGlobal(testPos)); p.end(); w2->setMask(bitmap); - qApp->processEvents(); - QTest::qWait(10); QTRY_COMPARE(QApplication::widgetAt(testPos), w1.data()); QTRY_VERIFY(QApplication::widgetAt(testPos + QPoint(1, 1)) == w2.data()); } @@ -3514,7 +3491,6 @@ void tst_QWidget::task110173() QTest::keyClick( &w, Qt::Key_Tab ); w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); - QTest::qWait(200); } class Widget : public QWidget @@ -3731,8 +3707,7 @@ void tst_QWidget::optimizedResizeMove() staticWidget.resize(150, 150); parent.show(); QVERIFY(QTest::qWaitForWindowExposed(&parent)); - QTest::qWait(20); - QTRY_COMPARE(staticWidget.gotPaintEvent, true); + QTRY_VERIFY(staticWidget.gotPaintEvent); staticWidget.gotPaintEvent = false; staticWidget.move(staticWidget.pos() + QPoint(10, 10)); @@ -3751,8 +3726,7 @@ void tst_QWidget::optimizedResizeMove() staticWidget.gotPaintEvent = false; staticWidget.resize(staticWidget.size() + QSize(10, 10)); - QTest::qWait(20); - QCOMPARE(staticWidget.gotPaintEvent, true); + QTRY_VERIFY(staticWidget.gotPaintEvent); QCOMPARE(staticWidget.partial, true); staticWidget.gotPaintEvent = false; @@ -3762,8 +3736,7 @@ void tst_QWidget::optimizedResizeMove() staticWidget.gotPaintEvent = false; staticWidget.resize(staticWidget.size() + QSize(10, -10)); - QTest::qWait(20); - QCOMPARE(staticWidget.gotPaintEvent, true); + QTRY_VERIFY(staticWidget.gotPaintEvent); QCOMPARE(staticWidget.partial, true); staticWidget.gotPaintEvent = false; @@ -3775,8 +3748,7 @@ void tst_QWidget::optimizedResizeMove() staticWidget.gotPaintEvent = false; staticWidget.move(staticWidget.pos() + QPoint(10, 10)); staticWidget.resize(staticWidget.size() + QSize(10, 10)); - QTest::qWait(20); - QCOMPARE(staticWidget.gotPaintEvent, true); + QTRY_VERIFY(staticWidget.gotPaintEvent); QCOMPARE(staticWidget.partial, true); staticWidget.gotPaintEvent = false; @@ -3789,8 +3761,7 @@ void tst_QWidget::optimizedResizeMove() staticWidget.gotPaintEvent = false; staticWidget.move(staticWidget.pos() + QPoint(-10, -10)); staticWidget.resize(staticWidget.size() + QSize(-10, -10)); - QTest::qWait(20); - QCOMPARE(staticWidget.gotPaintEvent, true); + QTRY_VERIFY(staticWidget.gotPaintEvent); QCOMPARE(staticWidget.partial, false); staticWidget.setAttribute(Qt::WA_StaticContents, true); @@ -3810,8 +3781,7 @@ void tst_QWidget::optimizedResize_topLevel() topLevel.gotPaintEvent = false; topLevel.show(); QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); - QTest::qWait(10); - QTRY_COMPARE(topLevel.gotPaintEvent, true); + QTRY_VERIFY(topLevel.gotPaintEvent); topLevel.gotPaintEvent = false; topLevel.partial = false; @@ -3830,15 +3800,14 @@ void tst_QWidget::optimizedResize_topLevel() MoveWindow(winHandleOf(&topLevel), frame.x(), frame.y(), frame.width() + 10, frame.height() + 10, true); -#endif - QTest::qWait(100); +#endif // Expected update region: New rect - old rect. QRegion expectedUpdateRegion(topLevel.rect()); expectedUpdateRegion -= QRect(QPoint(), topLevel.size() - QSize(10, 10)); - QTRY_COMPARE(topLevel.gotPaintEvent, true); + QTRY_VERIFY(topLevel.gotPaintEvent); if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("offscreen")) QSKIP("QTBUG-26424"); QCOMPARE(topLevel.partial, true); @@ -3886,12 +3855,10 @@ void tst_QWidget::setMinimumSize() QCOMPARE(w.size(), defaultSize + QSize(200, 200)); QVERIFY(!w.testAttribute(Qt::WA_Resized)); - // Setting a minimum size larger than the desktop does not work on WinCE, - // so skip this part of the test. QSize nonDefaultSize = defaultSize + QSize(5,5); w.setMinimumSize(nonDefaultSize); w.showNormal(); - QTest::qWait(50); + QVERIFY(QTest::qWaitForWindowActive(&w)); QVERIFY2(w.height() >= nonDefaultSize.height(), msgComparisonFailed(w.height(), ">=", nonDefaultSize.height())); QVERIFY2(w.width() >= nonDefaultSize.width(), @@ -3943,7 +3910,7 @@ void tst_QWidget::setFixedSize() w.setFixedSize(defaultSize + QSize(150, 150)); w.showNormal(); - QTest::qWait(50); + QVERIFY(QTest::qWaitForWindowActive(&w)); if (m_platform == QStringLiteral("xcb")) QSKIP("QTBUG-26424"); QCOMPARE(w.size(), defaultSize + QSize(150,150)); @@ -4306,7 +4273,6 @@ void tst_QWidget::update() QSKIP("QTBUG-52974"); #endif - QTest::qWait(10); // Wait for the initStuff to do it's stuff. Q_CHECK_PAINTEVENTS UpdateWidget w; @@ -4315,8 +4281,6 @@ void tst_QWidget::update() w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); - QApplication::processEvents(); - QApplication::processEvents(); QTRY_COMPARE(w.numPaintEvents, 1); QCOMPARE(w.visibleRegion(), QRegion(w.rect())); @@ -5228,7 +5192,6 @@ void tst_QWidget::moveChild() #endif parent.showNormal(); QVERIFY(QTest::qWaitForWindowExposed(&parent)); - QTest::qWait(30); QTRY_COMPARE(parent.r, QRegion(parent.rect()) - child.geometry()); QTRY_COMPARE(child.r, QRegion(child.rect())); @@ -5244,10 +5207,9 @@ void tst_QWidget::moveChild() QPoint pos = child.pos() + offset; child.move(pos); - QTest::qWait(100); QTRY_COMPARE(pos, child.pos()); - QCOMPARE(parent.r, QRegion(oldGeometry) - child.geometry()); + QTRY_COMPARE(parent.r, QRegion(oldGeometry) - child.geometry()); #if !defined(Q_OS_OSX) // should be scrolled in backingstore QCOMPARE(child.r, QRegion()); @@ -5277,7 +5239,6 @@ void tst_QWidget::showAndMoveChild() parent.show(); qApp->setActiveWindow(&parent); QVERIFY(QTest::qWaitForWindowActive(&parent)); - QTest::qWait(10); QWidget child(&parent); child.resize(desktopDimensions.width()/2, desktopDimensions.height()/2); @@ -5315,14 +5276,12 @@ void tst_QWidget::subtractOpaqueSiblings() w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); - QTest::qWait(10); large->reset(); medium->reset(); tall->reset(); medium->update(); - QTest::qWait(10); // QWidgetPrivate::subtractOpaqueSiblings() should prevent parts of medium // to be repainted and tall from be repainted at all. @@ -7524,7 +7483,6 @@ void tst_QWidget::repaintWhenChildDeleted() w.setGeometry(QRect(startPoint, QSize(100, 100))); w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); - QTest::qWait(10); QTRY_COMPARE(w.r, QRegion(w.rect())); w.r = QRegion(); @@ -7532,12 +7490,10 @@ void tst_QWidget::repaintWhenChildDeleted() ColorWidget child(&w, Qt::Widget, Qt::blue); child.setGeometry(10, 10, 10, 10); child.show(); - QTest::qWait(10); QTRY_COMPARE(child.r, QRegion(child.rect())); w.r = QRegion(); } - QTest::qWait(10); QTRY_COMPARE(w.r, QRegion(10, 10, 10, 10)); } @@ -7558,7 +7514,6 @@ void tst_QWidget::hideOpaqueChildWhileHidden() w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); - QTest::qWait(10); QTRY_COMPARE(child2.r, QRegion(child2.rect())); child.r = QRegion(); child2.r = QRegion(); @@ -7566,13 +7521,11 @@ void tst_QWidget::hideOpaqueChildWhileHidden() child.hide(); child2.hide(); - QTest::qWait(100); - QCOMPARE(w.r, QRegion(child.geometry())); + QTRY_COMPARE(w.r, QRegion(child.geometry())); child.show(); - QTest::qWait(100); - QCOMPARE(child.r, QRegion(child.rect())); + QTRY_COMPARE(child.r, QRegion(child.rect())); QCOMPARE(child2.r, QRegion()); } @@ -7593,7 +7546,6 @@ void tst_QWidget::updateWhileMinimized() widget.reset(); widget.show(); QVERIFY(QTest::qWaitForWindowExposed(&widget)); - QApplication::processEvents(); QTRY_VERIFY(widget.numPaintEvents > 0); QTest::qWait(150); @@ -8125,7 +8077,6 @@ void tst_QWidget::doubleRepaint() int expectedRepaints = 1; widget.show(); QVERIFY(QTest::qWaitForWindowExposed(&widget)); - QTest::qWait(10); QTRY_COMPARE(widget.numPaintEvents, expectedRepaints); widget.numPaintEvents = 0; @@ -8165,7 +8116,6 @@ void tst_QWidget::resizeInPaintEvent() QCOMPARE(widget.numPaintEvents, 1); widget.numPaintEvents = 0; - QTest::qWait(10); // Make sure the resize triggers another update. QTRY_COMPARE(widget.numPaintEvents, 1); } @@ -8188,7 +8138,6 @@ void tst_QWidget::opaqueChildren() widget.show(); QVERIFY(QTest::qWaitForWindowExposed(&widget)); - QTest::qWait(100); // Child, grandChild and greatGrandChild are outside the ancestor clip. QRegion expectedOpaqueRegion(50, 50, 150, 150); @@ -8257,7 +8206,6 @@ void tst_QWidget::setMaskInResizeEvent() testWidget.show(); w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); - QTest::qWait(30); QTRY_VERIFY(w.numPaintEvents > 0); w.reset(); @@ -8311,7 +8259,6 @@ void tst_QWidget::moveInResizeEvent() testWidget.setGeometry(50, 50, 200, 200); testWidget.show(); QVERIFY(QTest::qWaitForWindowExposed(&testWidget)); - QTest::qWait(300); QRect expectedGeometry(100,100, 100, 100); QTRY_COMPARE(testWidget.geometry(), expectedGeometry); @@ -8326,7 +8273,6 @@ void tst_QWidget::immediateRepaintAfterInvalidateBuffer() centerOnScreen(widget.data()); widget->show(); QVERIFY(QTest::qWaitForWindowExposed(widget.data())); - QTest::qWait(200); widget->numPaintEvents = 0; @@ -8489,7 +8435,7 @@ void tst_QWidget::moveRect() child.setUpdatesEnabled(false); child.setAttribute(Qt::WA_OpaquePaintEvent); widget.show(); - QTest::qWait(200); + QVERIFY(QTest::qWaitForWindowExposed(&widget)); child.move(10, 10); // Don't crash. } @@ -8590,7 +8536,6 @@ void tst_QWidget::reparentStaticWidget() window2.move(window1.geometry().topRight() + QPoint(100, 0)); window2.show(); QVERIFY(QTest::qWaitForWindowExposed(&window2)); - QTest::qWait(20); // Reparent into another top-level. child->setParent(&window2); @@ -8702,7 +8647,6 @@ void tst_QWidget::translucentWidget() label.move(labelPos); label.show(); QVERIFY(QTest::qWaitForWindowExposed(&label)); - QTest::qWait(200); QPixmap widgetSnapshot; @@ -8800,7 +8744,6 @@ void tst_QWidget::setClearAndResizeMask() const QRegion childMask(0, 0, 50, 50); child.setMask(childMask); QTRY_COMPARE(child.mask(), childMask); - QTest::qWait(50); // and ensure that the child widget doesn't get any update. #ifdef Q_OS_OSX // Mac always issues a full update when calling setMask, and we cannot force it to not do so. @@ -8821,7 +8764,6 @@ void tst_QWidget::setClearAndResizeMask() // Clear child widget mask child.clearMask(); QTRY_COMPARE(child.mask(), QRegion()); - QTest::qWait(10); // and ensure that that the child widget gets an update for the area outside the old mask. QTRY_COMPARE(child.numPaintEvents, 1); outsideOldMask = child.rect(); @@ -8839,7 +8781,6 @@ void tst_QWidget::setClearAndResizeMask() // Mask child widget with a mask that is bigger than the rect child.setMask(QRegion(0, 0, 1000, 1000)); - QTest::qWait(100); #ifdef Q_OS_OSX // Mac always issues a full update when calling setMask, and we cannot force it to not do so. if (child.internalWinId()) @@ -9093,7 +9034,6 @@ void tst_QWidget::syntheticEnterLeave() window.raise(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QTest::qWait(300); #define RESET_EVENT_COUNTS \ window.numEnterEvents = 0; \ @@ -9302,7 +9242,6 @@ void tst_QWidget::updateOnDestroyedSignal() widget.show(); QVERIFY(QTest::qWaitForWindowExposed(&widget)); - QTest::qWait(200); // Please do not crash. MyEvilObject evil(child); @@ -9315,7 +9254,6 @@ void tst_QWidget::toplevelLineEditFocus() w.setMinimumWidth(m_testWidgetSize.width()); w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); - QTest::qWait(20); QTRY_COMPARE(QApplication::activeWindow(), (QWidget*)&w); QTRY_COMPARE(QApplication::focusWidget(), (QWidget*)&w); @@ -9766,14 +9704,10 @@ void tst_QWidget::nativeChildFocus() p1->setFocus(); p1->setAttribute(Qt::WA_NativeWindow); p2->setAttribute(Qt::WA_NativeWindow); - QApplication::processEvents(); QVERIFY(QTest::qWaitForWindowExposed(&w)); - QTest::qWait(10); QCOMPARE(QApplication::activeWindow(), &w); QCOMPARE(QApplication::focusWidget(), static_cast(p1)); - - QTest::qWait(1000); } static bool lenientCompare(const QPixmap &actual, const QPixmap &expected) From 26355be54d7e7aa1c8e6a7adcb6bb9de68700dd9 Mon Sep 17 00:00:00 2001 From: Akihito Izawa Date: Thu, 12 Apr 2018 15:52:18 +0900 Subject: [PATCH 06/12] QStyleHints: emit correct signal when calling setMouseQuickSelectionThreshold Change-Id: Ieb76ecc406c25ca11a108775ebd46a8e597401b5 Reviewed-by: Andy Shaw Reviewed-by: J-P Nurmi --- src/gui/kernel/qstylehints.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp index b2d968c046..48060a2c37 100644 --- a/src/gui/kernel/qstylehints.cpp +++ b/src/gui/kernel/qstylehints.cpp @@ -551,7 +551,7 @@ void QStyleHints::setMouseQuickSelectionThreshold(int threshold) if (d->m_mouseQuickSelectionThreshold == threshold) return; d->m_mouseQuickSelectionThreshold = threshold; - emit mouseDoubleClickIntervalChanged(threshold); + emit mouseQuickSelectionThresholdChanged(threshold); } /*! From a8906e35103c9c30597bf3b0034371498669f9da Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 12 Apr 2018 13:59:51 +0200 Subject: [PATCH 07/12] winrt: QWinRTEGLContext: add isValid functionality QPlatformOpenGLContext::isValid always returns true but it is possible that creation of the context fails in QWinRTEGLContext. This case should be reflected in isValid because other places (like QOpenGLContext::isValid()) rely on it and not having proper information about the validity of the context might lead to crashes. Task-number: QTBUG-67568 Change-Id: If989ca47cdf7b27c44961beee5d97a4647184b0a Reviewed-by: Maurice Kalinowski --- src/plugins/platforms/winrt/qwinrteglcontext.cpp | 6 ++++++ src/plugins/platforms/winrt/qwinrteglcontext.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index 8a250c516a..eeb79be2e6 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -354,6 +354,12 @@ QFunctionPointer QWinRTEGLContext::getProcAddress(const char *procName) return eglGetProcAddress(procName); } +bool QWinRTEGLContext::isValid() const +{ + Q_D(const QWinRTEGLContext); + return d->eglContext != EGL_NO_CONTEXT; +} + EGLDisplay QWinRTEGLContext::display() { return g->eglDisplay; diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h index 5c75aa90d0..325dc82c40 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.h +++ b/src/plugins/platforms/winrt/qwinrteglcontext.h @@ -60,6 +60,7 @@ public: QSurfaceFormat format() const override; QFunctionPointer getProcAddress(const char *procName) override; + bool isValid() const override; static EGLDisplay display(); private: From 07f1c9665827bf9bc7dc70154fdee168c8118aaa Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 Jan 2018 16:43:48 +0100 Subject: [PATCH 08/12] Improve performance of QResource::load() Avoid creating a QDateTime in the resource that will almost never get used. Constructing the date time is expensive as we convert the time stamp to local time. Task-number: QTBUG-65713 Change-Id: I3638e108a8fbd237cd93e98aa2adc0ca2127822c Reviewed-by: Simon Hausmann Reviewed-by: Tuukka Turunen --- src/corelib/io/qresource.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index 35a0de4fb7..7502fb57a3 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -116,7 +116,7 @@ public: inline bool isContainer(int node) const { return flags(node) & Directory; } inline bool isCompressed(int node) const { return flags(node) & Compressed; } const uchar *data(int node, qint64 *size) const; - QDateTime lastModified(int node) const; + quint64 lastModified(int node) const; QStringList children(int node) const; virtual QString mappingRoot() const { return QString(); } bool mappingRootSubdir(const QString &path, QString *match=0) const; @@ -245,7 +245,7 @@ public: mutable qint64 size; mutable const uchar *data; mutable QStringList children; - mutable QDateTime lastModified; + mutable quint64 lastModified; QResource *q_ptr; Q_DECLARE_PUBLIC(QResource) @@ -259,7 +259,7 @@ QResourcePrivate::clear() data = 0; size = 0; children.clear(); - lastModified = QDateTime(); + lastModified = 0; container = 0; for(int i = 0; i < related.size(); ++i) { QResourceRoot *root = related.at(i); @@ -301,7 +301,7 @@ QResourcePrivate::load(const QString &file) data = 0; size = 0; compressed = 0; - lastModified = QDateTime(); + lastModified = 0; res->ref.ref(); related.append(res); } @@ -539,7 +539,7 @@ QDateTime QResource::lastModified() const { Q_D(const QResource); d->ensureInitialized(); - return d->lastModified; + return d->lastModified ? QDateTime::fromMSecsSinceEpoch(d->lastModified) : QDateTime(); } /*! @@ -797,18 +797,14 @@ const uchar *QResourceRoot::data(int node, qint64 *size) const return 0; } -QDateTime QResourceRoot::lastModified(int node) const +quint64 QResourceRoot::lastModified(int node) const { if (node == -1 || version < 0x02) - return QDateTime(); + return 0; const int offset = findOffset(node) + 14; - const quint64 timeStamp = qFromBigEndian(tree + offset); - if (timeStamp == 0) - return QDateTime(); - - return QDateTime::fromMSecsSinceEpoch(timeStamp); + return qFromBigEndian(tree + offset); } QStringList QResourceRoot::children(int node) const From 0dd3e02aacf7db51a1ab75170f9ceb759f334fec Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Wed, 4 Apr 2018 09:50:22 +0300 Subject: [PATCH 09/12] tests/auto/widgets/util: Avoid unconditional qWait()s Task-number: QTBUG-63992 Change-Id: I795e564b051bbabd1fc2d2fca8171da6072f99eb Reviewed-by: Friedemann Kleint Reviewed-by: Gatis Paeglis --- .../util/qcompleter/tst_qcompleter.cpp | 5 ++--- .../widgets/util/qscroller/tst_qscroller.cpp | 21 +++++++------------ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp index 6fbb0fe5fa..0511c278d5 100644 --- a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp +++ b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp @@ -1099,8 +1099,8 @@ void tst_QCompleter::multipleWidgets() comboBox->show(); window.activateWindow(); QApplication::setActiveWindow(&window); - QTest::qWait(50); - QTRY_COMPARE(QApplication::focusWidget(), comboBox); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QCOMPARE(QApplication::focusWidget(), comboBox); comboBox->lineEdit()->setText("it"); QCOMPARE(comboBox->currentText(), QString("it")); // should not complete with setText QTest::keyPress(comboBox, 'e'); @@ -1112,7 +1112,6 @@ void tst_QCompleter::multipleWidgets() lineEdit->setCompleter(&completer); lineEdit->show(); lineEdit->setFocus(); - QTest::qWait(50); QTRY_COMPARE(QApplication::focusWidget(), lineEdit); lineEdit->setText("it"); QCOMPARE(lineEdit->text(), QString("it")); // should not completer with setText diff --git a/tests/auto/widgets/util/qscroller/tst_qscroller.cpp b/tests/auto/widgets/util/qscroller/tst_qscroller.cpp index 67bae43c9d..43063881b2 100644 --- a/tests/auto/widgets/util/qscroller/tst_qscroller.cpp +++ b/tests/auto/widgets/util/qscroller/tst_qscroller.cpp @@ -394,8 +394,7 @@ void tst_QScroller::scroll() // wait until finished, check that no further first scroll is sent sw->receivedFirst = false; sw->receivedScroll = false; - while (s1->state() == QScroller::Scrolling) - QTest::qWait(100); + QTRY_VERIFY(s1->state() != QScroller::Scrolling); QCOMPARE( sw->receivedFirst, false ); QCOMPARE( sw->receivedScroll, true ); @@ -409,8 +408,7 @@ void tst_QScroller::scroll() sw->scrollArea = QRectF(0, 0, 0, 1000); kineticScrollNoTest(sw, QPointF(0, 500), QPoint(0, 0), QPoint(100, 0), QPoint(200, 0)); - while (s1->state() != QScroller::Inactive) - QTest::qWait(20); + QTRY_COMPARE(s1->state(), QScroller::Inactive); QCOMPARE(sw->currentPos.x(), 0.0); QCOMPARE(sw->currentPos.y(), 500.0); @@ -443,8 +441,7 @@ void tst_QScroller::overshoot() s1->setScrollerProperties(sp1); kineticScrollNoTest(sw, QPointF(500, 500), QPoint(0, 0), QPoint(400, 0), QPoint(490, 0)); - while (s1->state() != QScroller::Inactive) - QTest::qWait(20); + QTRY_COMPARE(s1->state(), QScroller::Inactive); //qDebug() << "Overshoot fuzzy: "<currentPos; QVERIFY(qFuzzyCompare( sw->currentPos.x(), 0 )); @@ -459,8 +456,7 @@ void tst_QScroller::overshoot() s1->setScrollerProperties(sp1); kineticScrollNoTest(sw, QPointF(0, 500), QPoint(0, 0), QPoint(400, 0), QPoint(490, 0)); - while (s1->state() != QScroller::Inactive) - QTest::qWait(20); + QTRY_COMPARE(s1->state(), QScroller::Inactive); //qDebug() << "Overshoot fuzzy: "<currentPos; QVERIFY(qFuzzyCompare( sw->currentPos.x(), 0 )); @@ -475,8 +471,7 @@ void tst_QScroller::overshoot() s1->setScrollerProperties(sp1); kineticScrollNoTest(sw, QPointF(0, 500), QPoint(0, 0), QPoint(400, 0), QPoint(490, 0)); - while (s1->state() != QScroller::Inactive) - QTest::qWait(20); + QTRY_COMPARE(s1->state(), QScroller::Inactive); //qDebug() << "Overshoot fuzzy: "<currentPos; @@ -492,8 +487,7 @@ void tst_QScroller::overshoot() s1->setScrollerProperties(sp1); kineticScrollNoTest(sw, QPointF(500, 500), QPoint(0, 0), QPoint(400, 0), QPoint(490, 0)); - while (s1->state() != QScroller::Inactive) - QTest::qWait(20); + QTRY_COMPARE(s1->state(), QScroller::Inactive); QVERIFY(qFuzzyCompare( sw->currentPos.x(), 0 )); QVERIFY(qFuzzyCompare( sw->currentPos.y(), 500 )); @@ -509,8 +503,7 @@ void tst_QScroller::overshoot() s1->setScrollerProperties(sp1); kineticScrollNoTest(sw, QPointF(500, 500), QPoint(0, 0), QPoint(400, 0), QPoint(490, 0)); - while (s1->state() != QScroller::Inactive) - QTest::qWait(20); + QTRY_COMPARE(s1->state(), QScroller::Inactive); QVERIFY(qFuzzyCompare( sw->currentPos.x(), 0 )); QVERIFY(qFuzzyCompare( sw->currentPos.y(), 500 )); From cba414a26b58b867d0c46ac214606e29e4bbdd94 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 15 Mar 2018 18:07:48 +0100 Subject: [PATCH 10/12] xcb: cleanup the code for detecting when to create/destroy SHM segment - removed the check for "m_segmentSize > 0" as according to the code it will never be <= 0. - wrap the entire logic in connection()->hasShm() { .. } as that is when the logic becomes relevant. This makes the code more readable. Change-Id: I572420df8e29cc46593f8a13c250f8c05c6a9108 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbbackingstore.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 659d1c53cb..8cfcc49f9a 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -219,12 +219,14 @@ void QXcbBackingStoreImage::create(const QSize &size, const xcb_format_t *fmt, Q if (!segmentSize) return; - if (hasShm() && m_segmentSize > 0 && (m_segmentSize < segmentSize || m_segmentSize / 2 >= segmentSize)) - destroyShmSegment(m_segmentSize); - if (!hasShm() && connection()->hasShm()) - { - qCDebug(lcQpaXcb) << "creating shared memory" << segmentSize << "for" << size << "depth" << fmt->depth << "bits" << fmt->bits_per_pixel; - createShmSegment(segmentSize); + if (connection()->hasShm()) { + if (m_shm_info.shmaddr && (m_segmentSize < segmentSize || m_segmentSize / 2 >= segmentSize)) + destroyShmSegment(m_segmentSize); + if (!m_shm_info.shmaddr) { + qCDebug(lcQpaXcb) << "creating shared memory" << segmentSize << "for" + << size << "depth" << fmt->depth << "bits" << fmt->bits_per_pixel; + createShmSegment(segmentSize); + } } m_xcb_image->data = m_shm_info.shmaddr ? m_shm_info.shmaddr : (uint8_t *)malloc(segmentSize); From 7286d9d8dd1f8543007218a91d5c6767a7a7b152 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 23 Mar 2018 14:24:23 +0100 Subject: [PATCH 11/12] xcb: fix bitmap cursor loading performance regression ... introduced by 422838685c31d9b57133a8711bfd5db92095d96d. Instead of completely droping caching for bitmap cursors we can do the same what is done in libXcursor - have a fixed size cache, with oldest entries eventually being replaced with new bitmaps. This fixes the original issue, where the hash was growing indefinitely until running out of file descriptors and won't have the performance penalty as in 422838685c31d9b57133a8711bfd5db92095d96d. Task-number: QTBUG-66897 Change-Id: I14f80b46f97fd0e2c920e17a31ffbc0441cd9d22 Reviewed-by: Uli Schlachter Reviewed-by: Robin Burchell Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbcursor.cpp | 42 +++++++++++++----------- src/plugins/platforms/xcb/qxcbcursor.h | 16 ++++++++- src/plugins/platforms/xcb/qxcbwindow.cpp | 22 ------------- src/plugins/platforms/xcb/qxcbwindow.h | 3 -- 4 files changed, 38 insertions(+), 45 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index 34b7d0d236..70138abede 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -301,6 +301,9 @@ QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c) QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen) : QXcbObject(conn), m_screen(screen), m_gtkCursorThemeInitialized(false) { + // see NUM_BITMAPS in libXcursor/src/xcursorint.h + m_bitmapCache.setMaxCost(8); + if (cursorCount++) return; @@ -351,37 +354,38 @@ QXcbCursor::~QXcbCursor() } #ifndef QT_NO_CURSOR -void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget) +void QXcbCursor::changeCursor(QCursor *cursor, QWindow *window) { - QXcbWindow *w = 0; - if (widget && widget->handle()) - w = static_cast(widget->handle()); - else - // No X11 cursor control when there is no widget under the cursor + if (!window || !window->handle()) return; xcb_cursor_t c = XCB_CURSOR_NONE; - bool isBitmapCursor = false; - if (cursor) { + const QXcbCursorCacheKey key(*cursor); const Qt::CursorShape shape = cursor->shape(); - isBitmapCursor = shape == Qt::BitmapCursor; - if (!isBitmapCursor) { - const QXcbCursorCacheKey key(*cursor); - CursorHash::iterator it = m_cursorHash.find(key); - if (it == m_cursorHash.end()) { - it = m_cursorHash.insert(key, createFontCursor(shape)); + if (shape == Qt::BitmapCursor) { + auto *bitmap = m_bitmapCache.object(key); + if (bitmap) { + c = bitmap->cursor; + } else { + c = createBitmapCursor(cursor); + m_bitmapCache.insert(key, new CachedCursor(xcb_connection(), c)); } - c = it.value(); } else { - // Do not cache bitmap cursors, as otherwise they have unclear - // lifetime (we effectively leak xcb_cursor_t). - c = createBitmapCursor(cursor); + auto it = m_cursorHash.find(key); + if (it == m_cursorHash.end()) { + c = createFontCursor(shape); + m_cursorHash.insert(key, c); + } else { + c = it.value(); + } } } - w->setCursor(c, isBitmapCursor); + auto *w = static_cast(window->handle()); + xcb_change_window_attributes(xcb_connection(), w->xcb_window(), XCB_CW_CURSOR, &c); + xcb_flush(xcb_connection()); } static int cursorIdForShape(int cshape) diff --git a/src/plugins/platforms/xcb/qxcbcursor.h b/src/plugins/platforms/xcb/qxcbcursor.h index e3f88518fe..5bc806381c 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.h +++ b/src/plugins/platforms/xcb/qxcbcursor.h @@ -43,6 +43,8 @@ #include #include "qxcbscreen.h" +#include + QT_BEGIN_NAMESPACE #ifndef QT_NO_CURSOR @@ -76,7 +78,7 @@ public: QXcbCursor(QXcbConnection *conn, QXcbScreen *screen); ~QXcbCursor(); #ifndef QT_NO_CURSOR - void changeCursor(QCursor *cursor, QWindow *widget) override; + void changeCursor(QCursor *cursor, QWindow *window) override; #endif QPoint pos() const override; void setPos(const QPoint &pos) override; @@ -89,9 +91,20 @@ public: #endif private: + #ifndef QT_NO_CURSOR typedef QHash CursorHash; + struct CachedCursor + { + explicit CachedCursor(xcb_connection_t *conn, xcb_cursor_t c) + : cursor(c), connection(conn) {} + ~CachedCursor() { xcb_free_cursor(connection, cursor); } + xcb_cursor_t cursor; + xcb_connection_t *connection; + }; + typedef QCache BitmapCursorCache; + xcb_cursor_t createFontCursor(int cshape); xcb_cursor_t createBitmapCursor(QCursor *cursor); xcb_cursor_t createNonStandardCursor(int cshape); @@ -100,6 +113,7 @@ private: QXcbScreen *m_screen; #ifndef QT_NO_CURSOR CursorHash m_cursorHash; + BitmapCursorCache m_bitmapCache; #endif #if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) static void cursorThemePropertyChanged(QXcbVirtualDesktop *screen, diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index fed096f311..f87da28ee0 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -562,10 +562,6 @@ void QXcbWindow::create() QXcbWindow::~QXcbWindow() { - if (m_currentBitmapCursor != XCB_CURSOR_NONE) { - xcb_free_cursor(xcb_connection(), m_currentBitmapCursor); - } - destroy(); } @@ -2591,24 +2587,6 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab) return result; } -void QXcbWindow::setCursor(xcb_cursor_t cursor, bool isBitmapCursor) -{ - xcb_connection_t *conn = xcb_connection(); - - xcb_change_window_attributes(conn, m_window, XCB_CW_CURSOR, &cursor); - xcb_flush(conn); - - if (m_currentBitmapCursor != XCB_CURSOR_NONE) { - xcb_free_cursor(conn, m_currentBitmapCursor); - } - - if (isBitmapCursor) { - m_currentBitmapCursor = cursor; - } else { - m_currentBitmapCursor = XCB_CURSOR_NONE; - } -} - void QXcbWindow::windowEvent(QEvent *event) { switch (event->type()) { diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 957c4e9cbd..cb8af9e666 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -103,8 +103,6 @@ public: bool setKeyboardGrabEnabled(bool grab) override; bool setMouseGrabEnabled(bool grab) override; - void setCursor(xcb_cursor_t cursor, bool isBitmapCursor); - QSurfaceFormat format() const override; void windowEvent(QEvent *event) override; @@ -285,7 +283,6 @@ protected: SyncState m_syncState = NoSyncNeeded; QXcbSyncWindowRequest *m_pendingSyncRequest = nullptr; - xcb_cursor_t m_currentBitmapCursor = XCB_CURSOR_NONE; }; class QXcbForeignWindow : public QXcbWindow From d5ac11891d8237ca2f02390ffd0ff103578b520e Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 10 Apr 2018 11:50:31 +0200 Subject: [PATCH 12/12] xcb: prevent crash with pixmap cursors on XRender-less X servers We were using xcb_render_* APIs without checking if the server even supports this extension. Attempting to use an extension which is not present will always result in a crash. This patch adds the required guards and refactors how we detect presence of XRender extension. Also instead of falling back to some odd-looking bitmapped version just leave the current cursor unchanged. That is how we did it in Qt4 AFAICT. Task-number: QTBUG-66935 Change-Id: I4f27f1d65a77563ec34f3e0e94492c9236d7f9a6 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbconnection.cpp | 11 ++++++++--- src/plugins/platforms/xcb/qxcbconnection.h | 10 +++++++++- src/plugins/platforms/xcb/qxcbcursor.cpp | 15 +++++++++++---- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 2431f99ab8..444e3a7669 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -2136,17 +2136,22 @@ void QXcbConnection::initializeXRender() { #if QT_CONFIG(xcb_render) const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_render_id); - if (!reply || !reply->present) + if (!reply || !reply->present) { + qCDebug(lcQpaXcb, "XRender extension not present on the X server"); return; + } auto xrender_query = Q_XCB_REPLY(xcb_render_query_version, m_connection, XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MINOR_VERSION); - if (!xrender_query || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) { - qWarning("QXcbConnection: Failed to initialize XRender"); + if (!xrender_query) { + qCWarning(lcQpaXcb, "xcb_render_query_version failed"); return; } + has_render_extension = true; + m_xrenderVersion.first = xrender_query->major_version; + m_xrenderVersion.second = xrender_query->minor_version; #endif } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index ced5208c81..d9321d94d0 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -478,7 +478,13 @@ public: bool hasXRandr() const { return has_randr_extension; } bool hasInputShape() const { return has_input_shape; } bool hasXKB() const { return has_xkb; } - bool hasXRender() const { return has_render_extension; } + bool hasXRender(int major = -1, int minor = -1) const + { + if (has_render_extension && major != -1 && minor != -1) + return m_xrenderVersion >= qMakePair(major, minor); + + return has_render_extension; + } bool hasXInput2() const { return m_xi2Enabled; } bool hasShm() const { return has_shm; } bool hasShmFd() const { return has_shm_fd; } @@ -707,6 +713,8 @@ private: bool has_shm = false; bool has_shm_fd = false; + QPair m_xrenderVersion; + Qt::MouseButtons m_buttonState = 0; Qt::MouseButton m_button = Qt::NoButton; diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index 70138abede..8d151b760b 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -601,12 +601,19 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor) { - xcb_connection_t *conn = xcb_connection(); QPoint spot = cursor->hotSpot(); xcb_cursor_t c = XCB_NONE; - if (cursor->pixmap().depth() > 1) - c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot); - if (!c) { + if (cursor->pixmap().depth() > 1) { +#if QT_CONFIG(xcb_render) + if (connection()->hasXRender(0, 5)) + c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot); + else + qCWarning(lcQpaXcb, "xrender >= 0.5 required to create pixmap cursors"); +#else + qCWarning(lcQpaXcb, "This build of Qt does not support pixmap cursors"); +#endif + } else { + xcb_connection_t *conn = xcb_connection(); xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap()->toImage()); xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask()->toImage()); c = xcb_generate_id(conn);