From b07f71a53f0dad132169e6d007b7305857400e99 Mon Sep 17 00:00:00 2001 From: Jarkko Koivikko Date: Tue, 31 Jan 2017 22:25:09 +0200 Subject: [PATCH 01/30] Widgets: Update micro focus in QLineEdit and friends QLineEdit, QAbstractSpinBox and QComboBox did not notify micro focus changes to the input context. In particular, the updates were missed during pre-edit stage. This change adds the missing bindings to QWidget::updateMicroFocus(). Change-Id: I9a7fff962f46dbabd8fb02836c206bace115793b Reviewed-by: Richard Moe Gustavsen --- src/widgets/widgets/qabstractspinbox.cpp | 4 + src/widgets/widgets/qcombobox.cpp | 2 + src/widgets/widgets/qlineedit.h | 1 + src/widgets/widgets/qlineedit_p.cpp | 3 + .../qabstractspinbox/qabstractspinbox.pro | 2 +- .../qabstractspinbox/tst_qabstractspinbox.cpp | 88 +++++++++++++++++++ .../widgets/qcombobox/tst_qcombobox.cpp | 75 ++++++++++++++++ .../widgets/qlineedit/tst_qlineedit.cpp | 53 +++++++++++ tests/auto/widgets/widgets/widgets.pro | 1 + 9 files changed, 228 insertions(+), 1 deletion(-) diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp index 6bcdc372ef8..7ee53587e65 100644 --- a/src/widgets/widgets/qabstractspinbox.cpp +++ b/src/widgets/widgets/qabstractspinbox.cpp @@ -694,6 +694,10 @@ void QAbstractSpinBox::setLineEdit(QLineEdit *lineEdit) this, SLOT(_q_editorTextChanged(QString))); connect(d->edit, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(_q_editorCursorPositionChanged(int,int))); + connect(d->edit, SIGNAL(cursorPositionChanged(int,int)), + this, SLOT(updateMicroFocus())); + connect(d->edit->d_func()->control, SIGNAL(updateMicroFocus()), + this, SLOT(updateMicroFocus())); } d->updateEditFieldGeometry(); d->edit->setContextMenuPolicy(Qt::NoContextMenu); diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index 4519265fb84..f4e08dc670f 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -65,6 +65,7 @@ #include #include #include +#include #include #if 0 /* Used to be included in Qt4 for Q_WS_MAC */ && !defined(QT_NO_EFFECTS) && QT_CONFIG(style_mac) #include @@ -1790,6 +1791,7 @@ void QComboBox::setLineEdit(QLineEdit *edit) connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(currentTextChanged(QString))); connect(d->lineEdit, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(updateMicroFocus())); connect(d->lineEdit, SIGNAL(selectionChanged()), this, SLOT(updateMicroFocus())); + connect(d->lineEdit->d_func()->control, SIGNAL(updateMicroFocus()), this, SLOT(updateMicroFocus())); d->lineEdit->setFrame(false); d->lineEdit->setContextMenuPolicy(Qt::NoContextMenu); d->updateFocusPolicy(); diff --git a/src/widgets/widgets/qlineedit.h b/src/widgets/widgets/qlineedit.h index 1bdcfaf8486..96dd64164fb 100644 --- a/src/widgets/widgets/qlineedit.h +++ b/src/widgets/widgets/qlineedit.h @@ -239,6 +239,7 @@ public: private: friend class QAbstractSpinBox; friend class QAccessibleLineEdit; + friend class QComboBox; #ifdef QT_KEYPAD_NAVIGATION friend class QDateTimeEdit; #endif diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp index 9947d632799..13f18f66d2d 100644 --- a/src/widgets/widgets/qlineedit_p.cpp +++ b/src/widgets/widgets/qlineedit_p.cpp @@ -196,6 +196,9 @@ void QLineEditPrivate::init(const QString& txt) QObject::connect(control, SIGNAL(textChanged(QString)), q, SLOT(updateMicroFocus())); + QObject::connect(control, SIGNAL(updateMicroFocus()), + q, SLOT(updateMicroFocus())); + // for now, going completely overboard with updates. QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(update())); diff --git a/tests/auto/widgets/widgets/qabstractspinbox/qabstractspinbox.pro b/tests/auto/widgets/widgets/qabstractspinbox/qabstractspinbox.pro index f9b601228e9..be758a8bdd5 100644 --- a/tests/auto/widgets/widgets/qabstractspinbox/qabstractspinbox.pro +++ b/tests/auto/widgets/widgets/qabstractspinbox/qabstractspinbox.pro @@ -4,7 +4,7 @@ CONFIG += testcase TARGET = tst_qabstractspinbox -QT += widgets testlib +QT += widgets gui-private core-private testlib SOURCES += tst_qabstractspinbox.cpp diff --git a/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp b/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp index 36f5df46496..3fb4863b0ed 100644 --- a/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp +++ b/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp @@ -35,6 +35,20 @@ #include #include +#include "../../../shared/platforminputcontext.h" +#include + +static inline void centerOnScreen(QWidget *w, const QSize &size) +{ + const QPoint offset = QPoint(size.width() / 2, size.height() / 2); + w->move(QGuiApplication::primaryScreen()->availableGeometry().center() - offset); +} + +static inline void centerOnScreen(QWidget *w) +{ + centerOnScreen(w, w->geometry().size()); +} + class tst_QAbstractSpinBox : public QObject { Q_OBJECT @@ -44,11 +58,19 @@ public: virtual ~tst_QAbstractSpinBox(); private slots: + void initTestCase(); + void cleanupTestCase(); + void getSetCheck(); // task-specific tests below me: void task183108_clear(); void task228728_cssselector(); + + void inputMethodUpdate(); + +private: + PlatformInputContext m_platformInputContext; }; tst_QAbstractSpinBox::tst_QAbstractSpinBox() @@ -67,6 +89,18 @@ public: void setLineEdit(QLineEdit *le) { QAbstractSpinBox::setLineEdit(le); } }; +void tst_QAbstractSpinBox::initTestCase() +{ + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = &m_platformInputContext; +} + +void tst_QAbstractSpinBox::cleanupTestCase() +{ + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = 0; +} + // Testing get/set functions void tst_QAbstractSpinBox::getSetCheck() { @@ -141,6 +175,60 @@ void tst_QAbstractSpinBox::task228728_cssselector() QSpinBox box; } +void tst_QAbstractSpinBox::inputMethodUpdate() +{ + QSpinBox box; + + QSpinBox *testWidget = &box; + testWidget->setRange(0, 1); + + centerOnScreen(testWidget); + testWidget->clear(); + testWidget->show(); + QVERIFY(QTest::qWaitForWindowExposed(testWidget)); + + testWidget->activateWindow(); + testWidget->setFocus(); + QTRY_VERIFY(testWidget->hasFocus()); + QTRY_COMPARE(qApp->focusObject(), testWidget); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + QInputMethodEvent event("1", attributes); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 1, QVariant()); + QInputMethodEvent event("1", attributes); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("1"); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); + QCOMPARE(testWidget->value(), 1); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); +} + QTEST_MAIN(tst_QAbstractSpinBox) #include "tst_qabstractspinbox.moc" diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp index 3afdc0a12af..b8820558880 100644 --- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp +++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp @@ -64,6 +64,9 @@ #include #include +#include "../../../shared/platforminputcontext.h" +#include + static inline void setFrameless(QWidget *w) { Qt::WindowFlags flags = w->windowFlags(); @@ -80,6 +83,8 @@ public: tst_QComboBox() {} private slots: + void initTestCase(); + void cleanupTestCase(); void getSetCheck(); void ensureReturnIsIgnored(); void setEditable(); @@ -162,6 +167,10 @@ private slots: void task_QTBUG_39088_inputMethodHints(); void task_QTBUG_49831_scrollerNotActivated(); void task_QTBUG_56693_itemFontFromModel(); + void inputMethodUpdate(); + +private: + PlatformInputContext m_platformInputContext; }; class MyAbstractItemDelegate : public QAbstractItemDelegate @@ -207,6 +216,18 @@ protected: QRegion visualRegionForSelection(const QItemSelection &) const { return QRegion(); } }; +void tst_QComboBox::initTestCase() +{ + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = &m_platformInputContext; +} + +void tst_QComboBox::cleanupTestCase() +{ + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = 0; +} + // Testing get/set functions void tst_QComboBox::getSetCheck() { @@ -3324,5 +3345,59 @@ void tst_QComboBox::task_QTBUG_56693_itemFontFromModel() box.hidePopup(); } +void tst_QComboBox::inputMethodUpdate() +{ + TestWidget topLevel; + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QComboBox *testWidget = topLevel.comboBox(); + // make sure we have no lineedit + QVERIFY(!testWidget->lineEdit()); + // test setEditable(true) + testWidget->setEditable(true); + QVERIFY(testWidget->lineEdit()); + + testWidget->activateWindow(); + testWidget->setFocus(); + QTRY_VERIFY(testWidget->hasFocus()); + QTRY_COMPARE(qApp->focusObject(), testWidget); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + QInputMethodEvent event("preedit text", attributes); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 1, QVariant()); + QInputMethodEvent event("preedit text", attributes); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("preedit text"); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); + QCOMPARE(testWidget->lineEdit()->text(), QString("preedit text")); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); +} + QTEST_MAIN(tst_QComboBox) #include "tst_qcombobox.moc" diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index a4614d0a9d0..4c0ffdc77cc 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -294,6 +294,8 @@ private slots: void inputMethodQueryImHints_data(); void inputMethodQueryImHints(); + void inputMethodUpdate(); + void undoRedoAndEchoModes_data(); void undoRedoAndEchoModes(); @@ -4184,6 +4186,57 @@ void tst_QLineEdit::inputMethodQueryImHints() QCOMPARE(static_cast(value.toInt()), hints); } +void tst_QLineEdit::inputMethodUpdate() +{ + QLineEdit *testWidget = ensureTestWidget(); + + centerOnScreen(testWidget); + testWidget->show(); + QVERIFY(QTest::qWaitForWindowExposed(testWidget)); + + testWidget->setText(""); + testWidget->activateWindow(); + testWidget->setFocus(); + QTRY_VERIFY(testWidget->hasFocus()); + QTRY_COMPARE(qApp->focusObject(), testWidget); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + QInputMethodEvent event("preedit text", attributes); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 1, QVariant()); + QInputMethodEvent event("preedit text", attributes); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("preedit text"); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); + QCOMPARE(testWidget->text(), QString("preedit text")); + + m_platformInputContext.m_updateCallCount = 0; + { + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(testWidget, &event); + } + QVERIFY(m_platformInputContext.m_updateCallCount >= 1); +} + void tst_QLineEdit::undoRedoAndEchoModes_data() { QTest::addColumn("echoMode"); diff --git a/tests/auto/widgets/widgets/widgets.pro b/tests/auto/widgets/widgets/widgets.pro index a8e8f6d865b..c098108edc6 100644 --- a/tests/auto/widgets/widgets/widgets.pro +++ b/tests/auto/widgets/widgets/widgets.pro @@ -49,6 +49,7 @@ SUBDIRS=\ # The following tests depend on private API: !qtConfig(private_tests): SUBDIRS -= \ + qabstractspinbox \ qcombobox \ qmainwindow \ qtextedit \ From cfe1a295fc479e8d83914920dbe8b117a9eca91b Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 13 Feb 2017 10:12:07 +0100 Subject: [PATCH 02/30] qeglfskmsegldevicescreen.cpp: add errno.h include Compilation failed with clang 3.9.1: qeglfskmsegldevicescreen.cpp:104:27: error: use of undeclared identifier 'errno' qErrnoWarning(errno, "drmModeSetCrtc failed"); Change-Id: I7cf08494359092b9cdac10bb013ac56c3ddf5597 Reviewed-by: Laszlo Agocs --- .../eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp | 1 + 1 file changed, 1 insertion(+) 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 7e5477e4bfc..a27c89faab4 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp @@ -41,6 +41,7 @@ #include "qeglfskmsegldevice.h" #include #include +#include QT_BEGIN_NAMESPACE From 9965e92e4f3d99e0cd4a6f74b21552b1d89fae97 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 18 Feb 2017 12:31:19 +0100 Subject: [PATCH 03/30] Make better use of new QStringList::join(QLatin1String) overload It was added in Qt 5.8. Change-Id: I7194fbfaef9219110604f3b03a893a658c996c06 Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Thiago Macieira --- src/gui/kernel/qguiapplication.cpp | 2 +- src/plugins/platforms/windows/qwindowsclipboard.cpp | 4 ++-- src/plugins/platforms/windows/qwindowsdialoghelpers.cpp | 2 +- src/tools/moc/main.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 7c596d5ae5d..c057fccadec 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1124,7 +1124,7 @@ static void init_platform(const QString &pluginArgument, const QString &platform = QStringLiteral("This application failed to start because it could not find or load the Qt platform plugin \"%1\"\nin \"%2\".\n\n").arg(name, QDir::toNativeSeparators(platformPluginPath)); if (!keys.isEmpty()) { fatalMessage += QStringLiteral("Available platform plugins are: %1.\n\n").arg( - keys.join(QStringLiteral(", "))); + keys.join(QLatin1String(", "))); } fatalMessage += QStringLiteral("Reinstalling the application may fix this problem."); #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index 11cd1756e66..01191a7dc15 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -81,7 +81,7 @@ static QDebug operator<<(QDebug d, const QMimeData *mimeData) d << "QMimeData("; if (mimeData) { const QStringList formats = mimeData->formats(); - d << "formats=" << formats.join(QStringLiteral(", ")); + d << "formats=" << formats.join(QLatin1String(", ")); if (mimeData->hasText()) d << ", text=" << mimeData->text(); if (mimeData->hasHtml()) @@ -321,7 +321,7 @@ void QWindowsClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) const HRESULT src = OleSetClipboard(m_data); if (src != S_OK) { QString mimeDataFormats = mimeData ? - mimeData->formats().join(QStringLiteral(", ")) : QString(QStringLiteral("NULL")); + mimeData->formats().join(QLatin1String(", ")) : QString(QStringLiteral("NULL")); qErrnoWarning("OleSetClipboard: Failed to set mime data (%s) on clipboard: %s", qPrintable(mimeDataFormats), QWindowsContext::comErrorString(src).constData()); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 63f78cfa637..f4527bcc600 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -1189,7 +1189,7 @@ void QWindowsNativeFileDialogBase::selectNameFilter(const QString &filter) if (index < 0) { qWarning("%s: Invalid parameter '%s' not found in '%s'.", __FUNCTION__, qPrintable(filter), - qPrintable(m_nameFilters.join(QStringLiteral(", ")))); + qPrintable(m_nameFilters.join(QLatin1String(", ")))); return; } m_fileDialog->SetFileTypeIndex(index + 1); // one-based. diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp index 6128d5490b0..b30de662587 100644 --- a/src/tools/moc/main.cpp +++ b/src/tools/moc/main.cpp @@ -305,7 +305,7 @@ int runMoc(int argc, char **argv) const QStringList files = parser.positionalArguments(); if (files.count() > 1) { - error(qPrintable(QStringLiteral("Too many input files specified: '") + files.join(QStringLiteral("' '")) + QLatin1Char('\''))); + error(qPrintable(QLatin1String("Too many input files specified: '") + files.join(QLatin1String("' '")) + QLatin1Char('\''))); parser.showHelp(1); } else if (!files.isEmpty()) { filename = files.first(); From 5f80a7956e1b884c7ce7f5102185a052c84d2056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 17 Feb 2017 15:22:47 +0100 Subject: [PATCH 04/30] windowflags: Improve compound states handling Change-Id: Iab5df40b69cf9c0e11f0e495a6b27af9c05fbd94 Reviewed-by: Olivier Goffart (Woboq GmbH) --- tests/manual/windowflags/controllerwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/manual/windowflags/controllerwindow.cpp b/tests/manual/windowflags/controllerwindow.cpp index 3654bfbad09..9a12c8b2c9d 100644 --- a/tests/manual/windowflags/controllerwindow.cpp +++ b/tests/manual/windowflags/controllerwindow.cpp @@ -191,12 +191,12 @@ static bool isTopLevel(const QObject *o) return false; } -static Qt::WindowState windowState(const QObject *o) +static Qt::WindowStates windowState(const QObject *o) { if (o->isWidgetType()) { Qt::WindowStates states = static_cast(o)->windowState(); states &= ~Qt::WindowActive; - return static_cast(int(states)); + return states; } #if QT_VERSION >= 0x050000 if (o->isWindowType()) From 7057b19b89e164f1698b72a338e532b935e199e9 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Tue, 14 Feb 2017 13:31:37 +0100 Subject: [PATCH 05/30] Only define "accessibility" feature once The "accessibility" feature was defined globally for qtbase, but also in src/gui. The definitions could end up with different values. Change-Id: I1a932c3c04a5fc26b9f67eb4f5ff02e524f380e7 Reviewed-by: Lars Knoll --- configure.json | 11 ----------- src/gui/configure.json | 7 +++++++ src/testlib/qtestaccessible.h | 6 +++--- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/configure.json b/configure.json index 276bb095e5a..987fabc2ea2 100644 --- a/configure.json +++ b/configure.json @@ -56,7 +56,6 @@ "android-sdk": "string", "android-toolchain-version": "string", - "accessibility": "boolean", "android-style-assets": "boolean", "appstore-compliant": "boolean", "avx": "boolean", @@ -915,10 +914,6 @@ "condition": "config.qnx && tests.stack_protector", "output": [ "publicQtConfig" ] }, - "accessibility": { - "label": "Accessibility", - "output": [ "publicFeature", "feature" ] - }, "system-zlib": { "label": "Using system zlib", "condition": "libs.zlib", @@ -1080,11 +1075,6 @@ or compile needed modules into the library." "message": "Qt is using double for qreal on this system. This is binary-incompatible against Qt 5.1. Configure with '-qreal float' to create a build that is binary-compatible with 5.1." }, - { - "type": "warning", - "condition": "!features.accessibility", - "message": "Accessibility disabled. This configuration of Qt is unsupported." - }, { "type": "error", "condition": "!features.stl", @@ -1191,7 +1181,6 @@ Configure with '-qreal float' to create a build that is binary-compatible with 5 }, { "section": "Support enabled for", "entries": [ - "accessibility", "pkg-config", "qml-debug", "libudev", diff --git a/src/gui/configure.json b/src/gui/configure.json index 08e50db9069..52ccb600245 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -7,6 +7,7 @@ "commandline": { "options": { + "accessibility": "boolean", "angle": "boolean", "direct2d": "boolean", "directfb": "boolean", @@ -1042,6 +1043,11 @@ Specify -opengl desktop to use regular OpenGL." "message": "The OpenGL functionality tests failed! You might need to modify the include and library search paths by editing QMAKE_INCDIR_OPENGL[_ES2], QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your platform." + }, + { + "type": "warning", + "condition": "!features.accessibility", + "message": "Accessibility disabled. This configuration of Qt is unsupported." } ], @@ -1049,6 +1055,7 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla { "section": "Qt Gui", "entries": [ + "accessibility", "freetype", "system-freetype", "harfbuzz", diff --git a/src/testlib/qtestaccessible.h b/src/testlib/qtestaccessible.h index c4c79b7deb1..464f87fb5c9 100644 --- a/src/testlib/qtestaccessible.h +++ b/src/testlib/qtestaccessible.h @@ -47,8 +47,6 @@ #include -#ifndef QT_NO_ACCESSIBILITY - #define QVERIFY_EVENT(event) \ QVERIFY(QTestAccessibility::verifyEvent(event)) @@ -59,6 +57,8 @@ #include #include +#if QT_CONFIG(accessibility) + QT_BEGIN_NAMESPACE @@ -294,5 +294,5 @@ private: QT_END_NAMESPACE -#endif // QT_NO_ACCESSIBILITY +#endif // QT_CONFIG(accessibility) #endif // QTESTACCESSIBLE_H From f3a4b4258f2d207b5a8e73d62822a3afe1bf8a72 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 14 Feb 2017 12:44:13 +0100 Subject: [PATCH 06/30] QWidget: update the font when the screen is changed The screen may change the dpi so the font dpi is also changed. We must tell QWidget that the font has changed by sending the FontChanged event to all sub widgets so they can update their geometry. Task-number: QTBUG-48242 Change-Id: Ibcdcc0c96429b8cd16311928298294f47a23e816 Reviewed-by: Friedemann Kleint Reviewed-by: Shawn Rutledge Reviewed-by: Marc Mutz --- src/widgets/kernel/qwidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index dc55c2d5d96..2cb259468d1 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -9191,6 +9191,7 @@ bool QWidget::event(QEvent *event) const QWindow *win = te->window; d->setWinId((win && win->handle()) ? win->handle()->winId() : 0); } + d->updateFont(d->data.fnt); #ifndef QT_NO_OPENGL d->renderToTextureReallyDirty = 1; #endif From 8d1fc3ca4d3a27b1ed5d1b8de4023aad9b629f61 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 11 May 2016 11:53:02 +0200 Subject: [PATCH 07/30] QtGui: port the last remaining Q_FOREACH loops and add QT_NO_FOREACH Port the last two remaining Q_FOREACH users in QtGui to C++11 range-for and mark the library as Q_FOREACH -free, using QT_NO_FOREACH. Change-Id: Ie6c5eea0af4227af6ef3dc0b4da2cf62e09d8b52 Reviewed-by: Friedemann Kleint --- src/gui/gui.pro | 2 +- src/gui/image/qpnghandler.cpp | 2 +- src/gui/painting/qcoregraphics.mm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 5f8cbe2cbe3..511cfd1d22a 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -3,7 +3,7 @@ QT = core-private qtConfig(opengl.*): MODULE_CONFIG = opengl -DEFINES += QT_NO_USING_NAMESPACE +DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH QMAKE_DOCS = $$PWD/doc/qtgui.qdocconf diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index d55a26b2a46..1d19c165fcd 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -745,7 +745,7 @@ static void set_text(const QImage &image, png_structp png_ptr, png_infop info_pt #ifdef PNG_iTXt_SUPPORTED bool needsItxt = false; - foreach(const QChar c, it.value()) { + for (const QChar c : it.value()) { uchar ch = c.cell(); if (c.row() || (ch < 0x20 && ch != '\n') || (ch > 0x7e && ch < 0xa0)) { needsItxt = true; diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm index a64a184e255..768d3e71480 100644 --- a/src/gui/painting/qcoregraphics.mm +++ b/src/gui/painting/qcoregraphics.mm @@ -133,7 +133,7 @@ NSImage *qt_mac_create_nsimage(const QIcon &icon, int defaultSize) QList availableSizes = icon.availableSizes(); if (availableSizes.isEmpty() && defaultSize > 0) availableSizes << QSize(defaultSize, defaultSize); - foreach (QSize size, availableSizes) { + for (QSize size : qAsConst(availableSizes)) { QPixmap pm = icon.pixmap(size); if (pm.isNull()) continue; From 3e5d5852ddc45201e721ec513fbc37745c98a78a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 17 Feb 2017 15:33:46 +0100 Subject: [PATCH 08/30] windowflags: Update preview info when window state changes Change-Id: I072939cdff0bd58779d9c163cb23e8176f3bc84a Reviewed-by: Timur Pocheptsov --- tests/manual/windowflags/previewwindow.cpp | 42 +++++++++++++--------- tests/manual/windowflags/previewwindow.h | 6 ++-- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/tests/manual/windowflags/previewwindow.cpp b/tests/manual/windowflags/previewwindow.cpp index 54084fd1bc8..65a287f7889 100644 --- a/tests/manual/windowflags/previewwindow.cpp +++ b/tests/manual/windowflags/previewwindow.cpp @@ -202,16 +202,21 @@ PreviewWindow::PreviewWindow(QWidget *parent) setWindowTitle(tr("Preview Qt %1").arg(QLatin1String(QT_VERSION_STR))); } -void PreviewWindow::resizeEvent(QResizeEvent *e) +bool PreviewWindow::event(QEvent *event) { - QWidget::resizeEvent(e); - updateInfo(); -} + const bool ret = QWidget::event(event); -void PreviewWindow::moveEvent(QMoveEvent *e) -{ - QWidget::moveEvent(e); - updateInfo(); + switch (event->type()) { + case QEvent::Move: + case QEvent::Resize: + case QEvent::WindowStateChange: + updateInfo(); + break; + default: + break; + } + + return ret; } void PreviewWindow::setWindowFlags(Qt::WindowFlags flags) @@ -234,16 +239,21 @@ PreviewDialog::PreviewDialog(QWidget *parent) setWindowTitle(tr("Preview Qt %1").arg(QLatin1String(QT_VERSION_STR))); } -void PreviewDialog::resizeEvent(QResizeEvent *e) +bool PreviewDialog::event(QEvent *event) { - QDialog::resizeEvent(e); - updateInfo(); -} + const bool ret = QDialog::event(event); -void PreviewDialog::moveEvent(QMoveEvent *e) -{ - QDialog::moveEvent(e); - updateInfo(); + switch (event->type()) { + case QEvent::Move: + case QEvent::Resize: + case QEvent::WindowStateChange: + updateInfo(); + break; + default: + break; + } + + return ret; } void PreviewDialog::setWindowFlags(Qt::WindowFlags flags) diff --git a/tests/manual/windowflags/previewwindow.h b/tests/manual/windowflags/previewwindow.h index acd79735ad9..9730e7a3f93 100644 --- a/tests/manual/windowflags/previewwindow.h +++ b/tests/manual/windowflags/previewwindow.h @@ -48,8 +48,7 @@ public slots: void updateInfo(); protected: - void resizeEvent(QResizeEvent *); - void moveEvent(QMoveEvent *); + bool event(QEvent *) override; private: QPlainTextEdit *textEdit; @@ -68,8 +67,7 @@ public slots: void updateInfo(); protected: - void resizeEvent(QResizeEvent *); - void moveEvent(QMoveEvent *); + bool event(QEvent *) override; private: QPlainTextEdit *textEdit; From 2fbe54472e10e42ceebed54cfb42b9b2384b7203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 20 Feb 2017 12:09:28 +0100 Subject: [PATCH 09/30] macOS: Retain foreign windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regression after 89842b97d74d1, where the retain was part of setView. We release m_view in the destructor, regardless of how the view was acquired, and the non-foreign window retains by being the one creating the view. Task-number: QTBUG-59001 Change-Id: I6d9621a63ea6ec2cee008986b0ab72ff61110ad7 Reviewed-by: René J.V. Bertin Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoawindow.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 918f376446b..60cababba4f 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -472,6 +472,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) if (tlw->type() == Qt::ForeignWindow) { m_view = (NSView *)WId(tlw->property("_q_foreignWinId").value()); + [m_view retain]; } else { m_view = [[QNSView alloc] initWithCocoaWindow:this]; // Enable high-dpi OpenGL for retina displays. Enabling has the side From 22a88dce03f12c70aa9987570cc408829cb2574e Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 21 Feb 2017 08:43:12 +0100 Subject: [PATCH 10/30] QErrorMessage: handle all message types The perils of adding a default: case to a switch over an enum type: the compiler no longer warns when the enum is extended. Provide strings for QtCriticalMsg and QtInfoMsg, too. [ChangeLog][QtWidgets][QErrorMessage] No longer displays critical (QtCriticalMsg) and informational (QtInfoMsg) messages as if they were debug (QtDebugMsg) ones. Change-Id: Id6776081be736ad92423ec016988dcd92a963cc7 Reviewed-by: Friedemann Kleint Reviewed-by: Mitch Curtis Reviewed-by: David Faure Reviewed-by: Edward Welbourne --- src/widgets/dialogs/qerrormessage.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/widgets/dialogs/qerrormessage.cpp b/src/widgets/dialogs/qerrormessage.cpp index 5fcbe3fe9d3..bcfc00d9829 100644 --- a/src/widgets/dialogs/qerrormessage.cpp +++ b/src/widgets/dialogs/qerrormessage.cpp @@ -163,14 +163,20 @@ static void jump(QtMsgType t, const QMessageLogContext & /*context*/, const QStr switch (t) { case QtDebugMsg: - default: rich = QErrorMessage::tr("Debug Message:"); break; case QtWarningMsg: rich = QErrorMessage::tr("Warning:"); break; + case QtCriticalMsg: + rich = QErrorMessage::tr("Critical Error:"); + break; case QtFatalMsg: rich = QErrorMessage::tr("Fatal Error:"); + break; + case QtInfoMsg: + rich = QErrorMessage::tr("Information:"); + break; } rich = QString::fromLatin1("

%1

").arg(rich); rich += Qt::convertFromPlainText(m, Qt::WhiteSpaceNormal); From 3b38392844dd9e145a4783445fd3c96e84bb94d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 7 Feb 2017 14:09:04 +0100 Subject: [PATCH 11/30] testlib: Add qWaitFor to wait for predicate Reduces duplication of logic and allows other primitives to be built on top. Change-Id: Ia100014cfb0c09ac2f47c3a156d0c76f0fddafa8 Reviewed-by: Simon Hausmann --- .../snippets/code/src_qtestlib_qtestcase.cpp | 8 +++ src/testlib/qtestcase.h | 3 +- src/testlib/qtestcase.qdoc | 15 ++++ src/testlib/qtestsystem.h | 71 +++++++++++-------- 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp b/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp index 01ee8102f40..990b7a38d7b 100644 --- a/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp +++ b/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp @@ -306,5 +306,13 @@ QTest::keyClick(myWindow, Qt::Key_Escape); QTest::keyClick(myWindow, Qt::Key_Escape, Qt::ShiftModifier, 200); //! [29] +//! [30] +MyObject obj; +obj.startup(); +QTest::qWaitFor([&]() { + return obj.isReady(); +}, 3000); +//! [30] + } diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index a7e825396a7..4beb9ea52dc 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -150,7 +150,8 @@ do {\ #define QTRY_IMPL(expr, timeout)\ const int qt_test_step = 50; \ const int qt_test_timeoutValue = timeout; \ - QTRY_LOOP_IMPL((expr), qt_test_timeoutValue, qt_test_step); \ + bool timedOut = !QTest::qWaitFor([&]() { return (expr); }, qt_test_timeoutValue); \ + Q_UNUSED(timedOut); \ QTRY_TIMEOUT_DEBUG_IMPL((expr), qt_test_timeoutValue, qt_test_step)\ // Will try to wait for the expression to become true while allowing event processing diff --git a/src/testlib/qtestcase.qdoc b/src/testlib/qtestcase.qdoc index 8f3d140adda..f7d816b8f97 100644 --- a/src/testlib/qtestcase.qdoc +++ b/src/testlib/qtestcase.qdoc @@ -1062,6 +1062,21 @@ \sa QTest::qSleep(), QSignalSpy::wait() */ +/*! \fn void QTest::qWaitFor(Predicate predicate, int timeout) + + Waits for \a timeout milliseconds or until the \a predicate returns true. + + Returns \c true if the \a preciate returned true within \a timeout milliseconds, otherwise returns \c false. + + Example: + \snippet code/src_qtestlib_qtestcase.cpp 30 + + The code above will wait for the object to become ready, for a + maximum of three seconds. + + \since 5.9 +*/ + /*! \fn bool QTest::qWaitForWindowExposed(QWindow *window, int timeout) \since 5.0 diff --git a/src/testlib/qtestsystem.h b/src/testlib/qtestsystem.h index 4c611aab6b8..7e0dae19136 100644 --- a/src/testlib/qtestsystem.h +++ b/src/testlib/qtestsystem.h @@ -54,41 +54,60 @@ QT_BEGIN_NAMESPACE namespace QTest { + template + static Q_REQUIRED_RESULT bool qWaitFor(Predicate predicate, int timeout = 5000) + { + // We should not spint the event loop in case the predicate is already true, + // otherwise we might send new events that invalidate the predicate. + if (predicate()) + return true; + + // qWait() is expected to spin the event loop, even when called with a small + // timeout like 1ms, so we we can't use a simple while-loop here based on + // the deadline timer not having timed out. Use do-while instead. + + int remaining = timeout; + QDeadlineTimer deadline(remaining, Qt::PreciseTimer); + + do { + QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); + + remaining = deadline.remainingTime(); + if (remaining > 0) { + QTest::qSleep(qMin(10, remaining)); + remaining = deadline.remainingTime(); + } + + if (predicate()) + return true; + + remaining = deadline.remainingTime(); + } while (remaining > 0); + + return predicate(); // Last chance + } + Q_DECL_UNUSED inline static void qWait(int ms) { Q_ASSERT(QCoreApplication::instance()); - - QDeadlineTimer timer(ms, Qt::PreciseTimer); - int remaining = ms; - do { - QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); - QCoreApplication::sendPostedEvents(Q_NULLPTR, QEvent::DeferredDelete); - remaining = timer.remainingTime(); - if (remaining <= 0) - break; - QTest::qSleep(qMin(10, remaining)); - remaining = timer.remainingTime(); - } while (remaining > 0); + auto unconditionalWait = []() { return false; }; + bool timedOut = !qWaitFor(unconditionalWait, ms); + Q_UNUSED(timedOut); } #ifdef QT_GUI_LIB inline static bool qWaitForWindowActive(QWindow *window, int timeout = 5000) { - QDeadlineTimer timer(timeout, Qt::PreciseTimer); - int remaining = timeout; - while (!window->isActive() && remaining > 0) { - QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); - QCoreApplication::sendPostedEvents(Q_NULLPTR, QEvent::DeferredDelete); - QTest::qSleep(10); - remaining = timer.remainingTime(); - } + bool becameActive = qWaitFor([&]() { return window->isActive(); }, timeout); + // Try ensuring the platform window receives the real position. // (i.e. that window->pos() reflects reality) // isActive() ( == FocusIn in case of X) does not guarantee this. It seems some WMs randomly // send the final ConfigureNotify (the one with the non-bogus 0,0 position) after the FocusIn. // If we just let things go, every mapTo/FromGlobal call the tests perform directly after // qWaitForWindowShown() will generate bogus results. - if (window->isActive()) { + if (becameActive) { int waitNo = 0; // 0, 0 might be a valid position after all, so do not wait for ever while (window->position().isNull()) { if (waitNo++ > timeout / 10) @@ -101,15 +120,7 @@ namespace QTest inline static bool qWaitForWindowExposed(QWindow *window, int timeout = 5000) { - QDeadlineTimer timer(timeout, Qt::PreciseTimer); - int remaining = timeout; - while (!window->isExposed() && remaining > 0) { - QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); - QCoreApplication::sendPostedEvents(Q_NULLPTR, QEvent::DeferredDelete); - QTest::qSleep(10); - remaining = timer.remainingTime(); - } - return window->isExposed(); + return qWaitFor([&]() { return window->isExposed(); }, timeout); } #endif From e0a9a0e2179a5f44b98eff9fec607a01dedf07b0 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 20 Feb 2017 10:07:29 +0100 Subject: [PATCH 12/30] QArrayDataOps: do not use QTypeInfo::isStatic anymore These days, QTypeInfoQuery and isRelocatable should be used. Change-Id: Ieac2d7fcef6b1d5466b14bbd1066901d6e751a55 Reviewed-by: Thiago Macieira --- src/corelib/tools/qarraydataops.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 47a19dd75d0..847f6806de5 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -412,7 +412,7 @@ struct QArrayOpsSelector template struct QArrayOpsSelector::isComplex && !QTypeInfo::isStatic + !QTypeInfoQuery::isComplex && QTypeInfoQuery::isRelocatable >::type> { typedef QPodArrayOps Type; @@ -421,7 +421,7 @@ struct QArrayOpsSelector struct QArrayOpsSelector::isComplex && !QTypeInfo::isStatic + QTypeInfoQuery::isComplex && QTypeInfoQuery::isRelocatable >::type> { typedef QMovableArrayOps Type; From 7de8745eaae6777819824cffd40a842fa0dd377b Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 26 Dec 2014 21:14:53 +0100 Subject: [PATCH 13/30] QSizePolicy: add C++14-style constexpr where possible This is straight-forward, since, unlike with transposed(), we can assume that every compiler that supports C++14 constexpr also supports C++11 uniform initialization. For Clang and GCC, this is clear. For MSVC, we might need to reconsider this, as, according to qcompilerdetection.h, 2015 still does not support uniform initialization (but not C++14 constexpr, either), and we don't know what 2017 will support. Change-Id: Idac7aa929d275645478a926896dca0dff166e114 Reviewed-by: Giuseppe D'Angelo Reviewed-by: Thiago Macieira --- src/widgets/kernel/qsizepolicy.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/widgets/kernel/qsizepolicy.h b/src/widgets/kernel/qsizepolicy.h index 3ab672a8e87..eceb08259eb 100644 --- a/src/widgets/kernel/qsizepolicy.h +++ b/src/widgets/kernel/qsizepolicy.h @@ -129,8 +129,8 @@ public: QT_SIZEPOLICY_CONSTEXPR Policy verticalPolicy() const { return static_cast(bits.verPolicy); } ControlType controlType() const; - void setHorizontalPolicy(Policy d) { bits.horPolicy = d; } - void setVerticalPolicy(Policy d) { bits.verPolicy = d; } + Q_DECL_RELAXED_CONSTEXPR void setHorizontalPolicy(Policy d) { bits.horPolicy = d; } + Q_DECL_RELAXED_CONSTEXPR void setVerticalPolicy(Policy d) { bits.verPolicy = d; } void setControlType(ControlType type); QT_SIZEPOLICY_CONSTEXPR Qt::Orientations expandingDirections() const { @@ -138,9 +138,9 @@ public: | ( (horizontalPolicy() & ExpandFlag) ? Qt::Horizontal : Qt::Orientations() ) ; } - void setHeightForWidth(bool b) { bits.hfw = b; } + Q_DECL_RELAXED_CONSTEXPR void setHeightForWidth(bool b) { bits.hfw = b; } QT_SIZEPOLICY_CONSTEXPR bool hasHeightForWidth() const { return bits.hfw; } - void setWidthForHeight(bool b) { bits.wfh = b; } + Q_DECL_RELAXED_CONSTEXPR void setWidthForHeight(bool b) { bits.wfh = b; } QT_SIZEPOLICY_CONSTEXPR bool hasWidthForHeight() const { return bits.wfh; } QT_SIZEPOLICY_CONSTEXPR bool operator==(const QSizePolicy& s) const { return data == s.data; } @@ -152,13 +152,13 @@ public: QT_SIZEPOLICY_CONSTEXPR int horizontalStretch() const { return static_cast(bits.horStretch); } QT_SIZEPOLICY_CONSTEXPR int verticalStretch() const { return static_cast(bits.verStretch); } - void setHorizontalStretch(int stretchFactor) { bits.horStretch = static_cast(qBound(0, stretchFactor, 255)); } - void setVerticalStretch(int stretchFactor) { bits.verStretch = static_cast(qBound(0, stretchFactor, 255)); } + Q_DECL_RELAXED_CONSTEXPR void setHorizontalStretch(int stretchFactor) { bits.horStretch = static_cast(qBound(0, stretchFactor, 255)); } + Q_DECL_RELAXED_CONSTEXPR void setVerticalStretch(int stretchFactor) { bits.verStretch = static_cast(qBound(0, stretchFactor, 255)); } QT_SIZEPOLICY_CONSTEXPR bool retainSizeWhenHidden() const { return bits.retainSizeWhenHidden; } - void setRetainSizeWhenHidden(bool retainSize) { bits.retainSizeWhenHidden = retainSize; } + Q_DECL_RELAXED_CONSTEXPR void setRetainSizeWhenHidden(bool retainSize) { bits.retainSizeWhenHidden = retainSize; } - void transpose() { *this = transposed(); } + Q_DECL_RELAXED_CONSTEXPR void transpose() { *this = transposed(); } #ifndef Q_QDOC QT_SIZEPOLICY_CONSTEXPR_AND_UNIFORM_INIT #endif From 5426e689f9d7d5e5e6e1a877578f17c96d248fdd Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 15 Feb 2017 16:35:07 +0100 Subject: [PATCH 14/30] Fix a race condition between QObject::connect and qRegisterMetaType QObject::connect will extract the QArgumentType for first the signal, then the slot. The QArgumentType with a string constructor will query the metatype system to get the meta type id. But it might happen that between the extraction of the signal's argument and the slot's argument, qRegisterMetaType was called in another thread. For this reason, it's possible that one QArgumentType has a type id while the other does not. For this reason, we should fall back to compare the string if any of the argument's type is 0. Task-number: QTBUG-50901 Change-Id: I260ca662ff00a773ae519f78bb633e05fde0ea81 Reviewed-by: Timur Pocheptsov Reviewed-by: Marc Mutz Reviewed-by: Jesus Fernandez Reviewed-by: Thiago Macieira --- src/corelib/kernel/qmetaobject_p.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index 1c540f64c72..e247c48703e 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -143,21 +143,17 @@ public: } bool operator==(const QArgumentType &other) const { - if (_type) + if (_type && other._type) return _type == other._type; - else if (other._type) - return false; else - return _name == other._name; + return name() == other.name(); } bool operator!=(const QArgumentType &other) const { - if (_type) + if (_type && other._type) return _type != other._type; - else if (other._type) - return true; else - return _name != other._name; + return name() != other.name(); } private: From c585802e946d97e7d177ea334a162dc7bc286b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 30 Jan 2017 14:57:29 +0100 Subject: [PATCH 15/30] QWindow: Remove "_q_foreignWinId" dynamic property The platform plugins reading this out of the QWindow was a layering violation, and propagates the notion that a window can shape shift into representing a new native handle, while none of the platform plugins support this. A foreign QWindow is created via the factory function fromWinId(), at which point we can pass the WId all the way to the platform plugin as function arguments, where the platform will create a corresponding platform-window. The platform window can then answer the question of whether or not it's representing a foreign window, which determines a few behavioral changes here and there, as well as supplying the native window handle back for QWindow::winId(); [ChangeLog][QtGui][QWindow] The "_q_foreignWinId" dynamic property is no longer set nor read. [ChangeLog][QtGui][QPA] The function createForeignWindow() has been added to QPlatormIntegration and is now responsible for creating foreign windows. The function isForeignWindow() in QPlatformWindow has been added, and platforms should implement this to return true for windows created by createForeignWindow(). Task-number: QTBUG-58383 Change-Id: If84142f95172f62b9377eb5d2a4d792cad36010b Reviewed-by: Gabriel de Dietrich --- src/gui/kernel/qplatformintegration.h | 1 + src/gui/kernel/qwindow.cpp | 24 +++++++----- src/gui/kernel/qwindow_p.h | 2 +- .../android/qandroidplatformforeignwindow.cpp | 5 +-- .../android/qandroidplatformforeignwindow.h | 3 +- .../android/qandroidplatformintegration.cpp | 11 ++++-- .../android/qandroidplatformintegration.h | 1 + .../platforms/cocoa/qcocoaintegration.h | 1 + .../platforms/cocoa/qcocoaintegration.mm | 5 +++ src/plugins/platforms/cocoa/qcocoawindow.h | 4 +- src/plugins/platforms/cocoa/qcocoawindow.mm | 11 ++++-- .../platforms/windows/qwindowsintegration.cpp | 37 ++++++++++--------- .../platforms/windows/qwindowsintegration.h | 1 + .../platforms/windows/qwindowswindow.h | 1 + src/plugins/platforms/xcb/qxcbintegration.cpp | 21 +++++++++++ src/plugins/platforms/xcb/qxcbintegration.h | 1 + src/plugins/platforms/xcb/qxcbwindow.cpp | 12 ++---- .../widgets/qmaccocoaviewcontainer_mac.mm | 29 +++++++-------- 18 files changed, 106 insertions(+), 64 deletions(-) diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index 466b3348bdd..0449e0b4c84 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -108,6 +108,7 @@ public: virtual QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; virtual QPlatformWindow *createPlatformWindow(QWindow *window) const = 0; + virtual QPlatformWindow *createForeignWindow(QWindow *, WId) const { return 0; } virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const = 0; #ifndef QT_NO_OPENGL virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 9d41a72072a..8e989589494 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -424,7 +424,7 @@ void QWindowPrivate::setTopLevelScreen(QScreen *newScreen, bool recreate) } } -void QWindowPrivate::create(bool recursive) +void QWindowPrivate::create(bool recursive, WId nativeHandle) { Q_Q(QWindow); if (platformWindow) @@ -433,8 +433,10 @@ void QWindowPrivate::create(bool recursive) if (q->parent()) q->parent()->create(); - platformWindow = QGuiApplicationPrivate::platformIntegration()->createPlatformWindow(q); - Q_ASSERT(platformWindow || q->type() == Qt::ForeignWindow); + QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration(); + platformWindow = nativeHandle ? platformIntegration->createForeignWindow(q, nativeHandle) + : platformIntegration->createPlatformWindow(q); + Q_ASSERT(platformWindow); if (!platformWindow) { qWarning() << "Failed to create platform window for" << q << "with flags" << q->flags(); @@ -629,9 +631,6 @@ WId QWindow::winId() const { Q_D(const QWindow); - if (type() == Qt::ForeignWindow) - return WId(property("_q_foreignWinId").value()); - if(!d->platformWindow) const_cast(this)->create(); @@ -865,7 +864,12 @@ void QWindow::setFlags(Qt::WindowFlags flags) Qt::WindowFlags QWindow::flags() const { Q_D(const QWindow); - return d->windowFlags; + Qt::WindowFlags flags = d->windowFlags; + + if (d->platformWindow && d->platformWindow->isForeignWindow()) + flags |= Qt::ForeignWindow; + + return flags; } /*! @@ -2584,13 +2588,13 @@ QWindow *QWindow::fromWinId(WId id) } QWindow *window = new QWindow; - window->setFlags(Qt::ForeignWindow); - window->setProperty("_q_foreignWinId", QVariant::fromValue(id)); - window->create(); + qt_window_private(window)->create(false, id); + if (!window->handle()) { delete window; return nullptr; } + return window; } diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 272401453ab..59016e45519 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -136,7 +136,7 @@ public: void updateSiblingPosition(SiblingPosition); bool windowRecreationRequired(QScreen *newScreen) const; - void create(bool recursive); + void create(bool recursive, WId nativeHandle = 0); void destroy(); void setTopLevelScreen(QScreen *newScreen, bool recreate); void connectToScreen(QScreen *topLevelScreen); diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp index 8c1f0ea8d27..1c920c0af9d 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp @@ -45,12 +45,11 @@ QT_BEGIN_NAMESPACE -QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window) +QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle) : QAndroidPlatformWindow(window), m_surfaceId(-1) { - const WId wId = window->property("_q_foreignWinId").value(); - m_view = reinterpret_cast(wId); + m_view = reinterpret_cast(nativeHandle); if (m_view.isValid()) QtAndroid::setViewVisibility(m_view.object(), false); } diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h index d42c36dceec..af1eee5499a 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE class QAndroidPlatformForeignWindow : public QAndroidPlatformWindow { public: - explicit QAndroidPlatformForeignWindow(QWindow *window); + explicit QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle); ~QAndroidPlatformForeignWindow(); void lower() override; void raise() override; @@ -57,6 +57,7 @@ public: void setVisible(bool visible) override; void applicationStateChanged(Qt::ApplicationState state) override; void setParent(const QPlatformWindow *window) override; + bool isForeignWindow() const override { return true; } private: int m_surfaceId; diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 173431208fe..73aa9d0e8ab 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -284,10 +284,13 @@ QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *wind { if (!QtAndroid::activity()) return nullptr; - if (window->type() == Qt::ForeignWindow) - return new QAndroidPlatformForeignWindow(window); - else - return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay); + + return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay); +} + +QPlatformWindow *QAndroidPlatformIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const +{ + return new QAndroidPlatformForeignWindow(window, nativeHandle); } QAbstractEventDispatcher *QAndroidPlatformIntegration::createEventDispatcher() const diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h index 23378012508..be10c3d1618 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/qandroidplatformintegration.h @@ -78,6 +78,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const override; QPlatformWindow *createPlatformWindow(QWindow *window) const override; + QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override; QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; QAbstractEventDispatcher *createEventDispatcher() const override; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index a3c375881d3..ecdd20c4dc0 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -126,6 +126,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; + QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const Q_DECL_OVERRIDE; #ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; #endif diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 291d39ea9d7..91f408e5c2d 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -524,6 +524,11 @@ QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWindow *window) const return new QCocoaWindow(window); } +QPlatformWindow *QCocoaIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const +{ + return new QCocoaWindow(window, nativeHandle); +} + #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index f60597fe428..8e2c4414652 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -156,7 +156,7 @@ class QCocoaWindow : public QObject, public QPlatformWindow { Q_OBJECT public: - QCocoaWindow(QWindow *tlw); + QCocoaWindow(QWindow *tlw, WId nativeHandle = 0); ~QCocoaWindow(); void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; @@ -186,6 +186,8 @@ public: QMargins frameMargins() const Q_DECL_OVERRIDE; QSurfaceFormat format() const Q_DECL_OVERRIDE; + bool isForeignWindow() const Q_DECL_OVERRIDE; + void requestActivateWindow() Q_DECL_OVERRIDE; WId winId() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 60cababba4f..2dd151e3249 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -433,7 +433,7 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterNotificationCallbacks) const int QCocoaWindow::NoAlertRequest = -1; -QCocoaWindow::QCocoaWindow(QWindow *tlw) +QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle) : QPlatformWindow(tlw) , m_view(nil) , m_nsWindow(0) @@ -470,8 +470,8 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) QMacAutoReleasePool pool; - if (tlw->type() == Qt::ForeignWindow) { - m_view = (NSView *)WId(tlw->property("_q_foreignWinId").value()); + if (nativeHandle) { + m_view = reinterpret_cast(nativeHandle); [m_view retain]; } else { m_view = [[QNSView alloc] initWithCocoaWindow:this]; @@ -563,6 +563,11 @@ void QCocoaWindow::setGeometry(const QRect &rectIn) setCocoaGeometry(rect); } +bool QCocoaWindow::isForeignWindow() const +{ + return ![m_view isKindOfClass:[QNSView class]]; +} + QRect QCocoaWindow::geometry() const { // QWindows that are embedded in a NSView hiearchy may be considered diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 5a3020387ad..316f93e3acb 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -304,24 +304,6 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons return result; } - if (window->type() == Qt::ForeignWindow) { - const HWND hwnd = reinterpret_cast(window->winId()); - if (!IsWindow(hwnd)) { - qWarning("Windows QPA: Invalid foreign window ID %p.", hwnd); - return nullptr; - } - QWindowsForeignWindow *result = new QWindowsForeignWindow(window, hwnd); - const QRect obtainedGeometry = result->geometry(); - QScreen *screen = Q_NULLPTR; - if (const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry)) - screen = pScreen->screen(); - if (screen && screen != window->screen()) - window->setScreen(screen); - qCDebug(lcQpaWindows) << "Foreign window:" << window << showbase << hex - << result->winId() << noshowbase << dec << obtainedGeometry << screen; - return result; - } - QWindowsWindowData requested; requested.flags = window->flags(); requested.geometry = QHighDpi::toNativePixels(window->geometry(), window); @@ -365,6 +347,25 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons return result; } +QPlatformWindow *QWindowsIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const +{ + const HWND hwnd = reinterpret_cast(nativeHandle); + if (!IsWindow(hwnd)) { + qWarning("Windows QPA: Invalid foreign window ID %p.", hwnd); + return nullptr; + } + QWindowsForeignWindow *result = new QWindowsForeignWindow(window, hwnd); + const QRect obtainedGeometry = result->geometry(); + QScreen *screen = Q_NULLPTR; + if (const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry)) + screen = pScreen->screen(); + if (screen && screen != window->screen()) + window->setScreen(screen); + qCDebug(lcQpaWindows) << "Foreign window:" << window << showbase << hex + << result->winId() << noshowbase << dec << obtainedGeometry << screen; + return result; +} + // Overridden to return a QWindowsDirect2DWindow in Direct2D plugin. QWindowsWindow *QWindowsIntegration::createPlatformWindowHelper(QWindow *window, const QWindowsWindowData &data) const { diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 7647b0f4a62..607203829f0 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -73,6 +73,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const override; QPlatformWindow *createPlatformWindow(QWindow *window) const override; + QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override; #ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; QOpenGLContext::OpenGLModuleType openGLModuleType() override; diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 10cfc18dff5..e541b110a66 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -171,6 +171,7 @@ public: void raise() override { raise_sys(); } void lower() override { lower_sys(); } void setWindowTitle(const QString &title) override { setWindowTitle_sys(title); } + bool isForeignWindow() const override { return true; } protected: HWND handle() const override { return m_hwnd; } diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 47c85fce188..40858b39e08 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -214,6 +214,27 @@ QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const return xcbWindow; } +class QXcbForeignWindow : public QXcbWindow +{ +public: + QXcbForeignWindow(QWindow *window, WId nativeHandle) + : QXcbWindow(window) { m_window = nativeHandle; } + ~QXcbForeignWindow() {} + bool isForeignWindow() const override { return true; } + +protected: + // No-ops + void create() override {} + void destroy() override {} +}; + +QPlatformWindow *QXcbIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const +{ + QXcbWindow *xcbWindow = new QXcbForeignWindow(window, nativeHandle); + xcbWindow->create(); + return xcbWindow; +} + #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index f8034f436f4..baa5c9d835b 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -61,6 +61,7 @@ public: ~QXcbIntegration(); QPlatformWindow *createPlatformWindow(QWindow *window) const override; + QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override; #ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; #endif diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index fd231790751..f7c36ec3867 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -341,11 +341,6 @@ enum { void QXcbWindow::create() { - if (window()->type() == Qt::ForeignWindow) { - m_window = window()->winId(); - return; - } - destroy(); m_windowState = Qt::WindowNoState; @@ -590,9 +585,10 @@ QXcbWindow::~QXcbWindow() if (m_currentBitmapCursor != XCB_CURSOR_NONE) { xcb_free_cursor(xcb_connection(), m_currentBitmapCursor); } - if (window()->type() != Qt::ForeignWindow) - destroy(); - else { + + destroy(); + + if (isForeignWindow()) { if (connection()->mouseGrabber() == this) connection()->setMouseGrabber(Q_NULLPTR); if (connection()->mousePressWindow() == this) diff --git a/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm b/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm index 8e565ecfe08..610df2125b6 100644 --- a/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm +++ b/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm @@ -44,6 +44,7 @@ #include #include #include +#include /*! \class QMacCocoaViewContainer @@ -117,7 +118,9 @@ QMacCocoaViewContainerPrivate::~QMacCocoaViewContainerPrivate() QMacCocoaViewContainer::QMacCocoaViewContainer(NSView *view, QWidget *parent) : QWidget(*new QMacCocoaViewContainerPrivate, parent, 0) { + // Ensures that we have a QWindow, even if we're not a top level widget setAttribute(Qt::WA_NativeWindow); + setCocoaView(view); } @@ -149,23 +152,19 @@ void QMacCocoaViewContainer::setCocoaView(NSView *view) [view retain]; d->nsview = view; + // Get rid of QWindow completely, and re-create a new vanilla one, which + // we will then re-configure to be a foreign window. + destroy(); + create(); + + // Can't use QWindow::fromWinId() here due to QWidget controlling its + // QWindow, and can't use QWidget::createWindowContainer() due to the + // QMacCocoaViewContainer class being public API instead of a factory + // function. QWindow *window = windowHandle(); - - // Note that we only set the flag on the QWindow, and not the QWidget. - // These two are not in sync, so from a QWidget standpoint the widget - // is not a Window, and hence will be shown when the parent widget is - // shown, like all QWidget children. - window->setFlags(Qt::ForeignWindow); - window->setProperty("_q_foreignWinId", view ? WId(view) : QVariant()); - - // Destroying the platform window implies hiding the window, and we - // also lose the geometry information that the platform window kept, - // and fall back to the stale QWindow geometry, so we update the two - // based on the widget visibility and geometry, which is up to date. window->destroy(); - window->setVisible(isVisible()); - window->setGeometry(geometry()); - window->create(); + qt_window_private(window)->create(false, WId(view)); + Q_ASSERT(window->handle()); [oldView release]; } From adca47cbc10f2458ea54cee841c06dc169763fe6 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 21 Feb 2017 13:25:43 +0100 Subject: [PATCH 16/30] QTzTimeZonePrivate: introduce PosixZone class ... as a replacement for QPair, and move some repsonsibilities into it. This avoids the repeated use of the magic number INT_MIN to indicate absence of an offset and does away with the confusing .first and .second, replacing them instead with proper names, .name and .offset. Change-Id: I0f6906467b8efa16bed2bf5677f2bbbd534da1ae Reviewed-by: Thiago Macieira --- src/corelib/tools/qtimezoneprivate_tz.cpp | 69 ++++++++++++++--------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index 38dff889194..9cbe3392256 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -452,13 +452,31 @@ static inline bool asciiIsLetter(char ch) return ch >= 'a' && ch <= 'z'; } +namespace { + +struct PosixZone +{ + enum { + InvalidOffset = INT_MIN, + }; + + QString name; + int offset; + + static PosixZone invalid() { return {QString(), InvalidOffset}; } + static PosixZone parse(const char *&pos, const char *end); + + bool hasValidOffset() const Q_DECL_NOTHROW { return offset != InvalidOffset; } +}; + +} // unnamed namespace + // Returns the zone name, the offset (in seconds) and advances \a begin to // where the parsing ended. Returns a zone of INT_MIN in case an offset // couldn't be read. -static QPair parsePosixZoneNameAndOffset(const char *&pos, const char *end) +PosixZone PosixZone::parse(const char *&pos, const char *end) { static const char offsetChars[] = "0123456789:"; - QPair result = qMakePair(QString(), INT_MIN); const char *nameBegin = pos; const char *nameEnd; @@ -480,7 +498,7 @@ static QPair parsePosixZoneNameAndOffset(const char *&pos, const c pos = nameEnd; } if (nameEnd - nameBegin < 3) - return result; // name must be at least 3 characters long + return invalid(); // name must be at least 3 characters long // zone offset, form [+-]hh:mm:ss const char *zoneBegin = pos; @@ -493,11 +511,10 @@ static QPair parsePosixZoneNameAndOffset(const char *&pos, const c ++zoneEnd; } - result.first = QString::fromUtf8(nameBegin, nameEnd - nameBegin); - if (zoneEnd > zoneBegin) - result.second = parsePosixOffset(zoneBegin, zoneEnd); + QString name = QString::fromUtf8(nameBegin, nameEnd - nameBegin); + const int offset = zoneEnd > zoneBegin ? parsePosixOffset(zoneBegin, zoneEnd) : InvalidOffset; pos = zoneEnd; - return result; + return {std::move(name), offset}; } static QVector calculatePosixTransitions(const QByteArray &posixRule, @@ -517,19 +534,19 @@ static QVector calculatePosixTransitions(const QByteArra // See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html QList parts = posixRule.split(','); - QPair stdZone, dstZone; + PosixZone stdZone, dstZone; { const QByteArray &zoneinfo = parts.at(0); const char *begin = zoneinfo.constBegin(); - stdZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd()); - if (stdZone.second == INT_MIN) { - stdZone.second = 0; // reset to UTC if we failed to parse + stdZone = PosixZone::parse(begin, zoneinfo.constEnd()); + if (!stdZone.hasValidOffset()) { + stdZone.offset = 0; // reset to UTC if we failed to parse } else if (begin < zoneinfo.constEnd()) { - dstZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd()); - if (dstZone.second == INT_MIN) { + dstZone = PosixZone::parse(begin, zoneinfo.constEnd()); + if (!dstZone.hasValidOffset()) { // if the dst offset isn't provided, it is 1 hour ahead of the standard offset - dstZone.second = stdZone.second + (60 * 60); + dstZone.offset = stdZone.offset + (60 * 60); } } } @@ -538,10 +555,10 @@ static QVector calculatePosixTransitions(const QByteArra if (parts.count() == 1) { QTimeZonePrivate::Data data; data.atMSecsSinceEpoch = lastTranMSecs; - data.offsetFromUtc = stdZone.second; - data.standardTimeOffset = stdZone.second; + data.offsetFromUtc = stdZone.offset; + data.standardTimeOffset = stdZone.offset; data.daylightTimeOffset = 0; - data.abbreviation = stdZone.first; + data.abbreviation = stdZone.name; result << data; return result; } @@ -568,18 +585,18 @@ static QVector calculatePosixTransitions(const QByteArra for (int year = startYear; year <= endYear; ++year) { QTimeZonePrivate::Data dstData; QDateTime dst(calculatePosixDate(dstDateRule, year), dstTime, Qt::UTC); - dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.second * 1000); - dstData.offsetFromUtc = dstZone.second; - dstData.standardTimeOffset = stdZone.second; - dstData.daylightTimeOffset = dstZone.second - stdZone.second; - dstData.abbreviation = dstZone.first; + dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.offset * 1000); + dstData.offsetFromUtc = dstZone.offset; + dstData.standardTimeOffset = stdZone.offset; + dstData.daylightTimeOffset = dstZone.offset - stdZone.offset; + dstData.abbreviation = dstZone.name; QTimeZonePrivate::Data stdData; QDateTime std(calculatePosixDate(stdDateRule, year), stdTime, Qt::UTC); - stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.second * 1000); - stdData.offsetFromUtc = stdZone.second; - stdData.standardTimeOffset = stdZone.second; + stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.offset * 1000); + stdData.offsetFromUtc = stdZone.offset; + stdData.standardTimeOffset = stdZone.offset; stdData.daylightTimeOffset = 0; - stdData.abbreviation = stdZone.first; + stdData.abbreviation = stdZone.name; // Part of the high year will overflow if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) { if (dstData.atMSecsSinceEpoch > 0) { From 53c0568924ef2f3f5b7d556dc8b5e3c9ce868bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 14 Feb 2017 16:32:42 +0100 Subject: [PATCH 17/30] macOS: Make sure NSResizableWindowMask is set when toggling fullscreen Instead of setting the mask in toggleFullScreen(), which is only hit when going to fullscreen via our own API, we do it in the window notification callbacks, which also includes going to full screen via the native macOS title bar buttons. This allows making customized windows without Qt::WindowMaximizeButtonHint full screen with the full geometry of the screen. Change-Id: I63c3e4582ea7c4fe8c0008265793c5f656b830b2 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoawindow.h | 2 + src/plugins/platforms/cocoa/qcocoawindow.mm | 42 ++++++++++++++------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 8e2c4414652..567eb7438b4 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -208,7 +208,9 @@ public: Q_NOTIFICATION_HANDLER(NSWindowDidResignKeyNotification) void windowDidResignKey(); Q_NOTIFICATION_HANDLER(NSWindowDidMiniaturizeNotification) void windowDidMiniaturize(); Q_NOTIFICATION_HANDLER(NSWindowDidDeminiaturizeNotification) void windowDidDeminiaturize(); + Q_NOTIFICATION_HANDLER(NSWindowWillEnterFullScreenNotification) void windowWillEnterFullScreen(); Q_NOTIFICATION_HANDLER(NSWindowDidEnterFullScreenNotification) void windowDidEnterFullScreen(); + Q_NOTIFICATION_HANDLER(NSWindowWillExitFullScreenNotification) void windowWillExitFullScreen(); Q_NOTIFICATION_HANDLER(NSWindowDidExitFullScreenNotification) void windowDidExitFullScreen(); Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen(); Q_NOTIFICATION_HANDLER(NSWindowDidOrderOnScreenAndFinishAnimatingNotification) void windowDidOrderOnScreen(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 2dd151e3249..75c13d6bbcd 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -947,6 +947,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) if (m_drawContentBorderGradient) styleMask |= NSTexturedBackgroundWindowMask; + // Don't wipe fullscreen state + if (m_nsWindow.styleMask & NSFullScreenWindowMask) + styleMask |= NSFullScreenWindowMask; + return styleMask; } @@ -1369,19 +1373,40 @@ void QCocoaWindow::windowDidDeminiaturize() reportCurrentWindowState(); } +void QCocoaWindow::windowWillEnterFullScreen() +{ + // The NSWindow needs to be resizable, otherwise we'll end up with + // the normal window geometry, centered in the middle of the screen + // on a black background. The styleMask will be reset below. + m_nsWindow.styleMask |= NSResizableWindowMask; +} + void QCocoaWindow::windowDidEnterFullScreen() { Q_ASSERT_X(m_nsWindow.qt_fullScreen, "QCocoaWindow", "FullScreen category processes window notifications first"); + // Reset to original styleMask + setWindowFlags(m_windowFlags); + reportCurrentWindowState(); } +void QCocoaWindow::windowWillExitFullScreen() +{ + // The NSWindow needs to be resizable, otherwise we'll end up with + // a weird zoom animation. The styleMask will be reset below. + m_nsWindow.styleMask |= NSResizableWindowMask; +} + void QCocoaWindow::windowDidExitFullScreen() { Q_ASSERT_X(!m_nsWindow.qt_fullScreen, "QCocoaWindow", "FullScreen category processes window notifications first"); + // Reset to original styleMask + setWindowFlags(m_windowFlags); + Qt::WindowState requestedState = window()->windowState(); // Deliver update of QWindow state @@ -1875,24 +1900,13 @@ void QCocoaWindow::toggleMaximized() void QCocoaWindow::toggleFullScreen() { - // The NSWindow needs to be resizable, otherwise we'll end up with - // the normal window geometry, centered in the middle of the screen - // on a black background. - const bool wasResizable = m_nsWindow.styleMask & NSResizableWindowMask; - m_nsWindow.styleMask |= NSResizableWindowMask; - - // It also needs to have the correct collection behavior for the - // toggleFullScreen call to have an effect. - const bool wasFullScreenEnabled = m_nsWindow.collectionBehavior & NSWindowCollectionBehaviorFullScreenPrimary; + // The window needs to have the correct collection behavior for the + // toggleFullScreen call to have an effect. The collection behavior + // will be reset in windowDidEnterFullScreen/windowDidLeaveFullScreen. m_nsWindow.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary; const id sender = m_nsWindow; [m_nsWindow toggleFullScreen:sender]; - - if (!wasResizable) - m_nsWindow.styleMask &= ~NSResizableWindowMask; - if (!wasFullScreenEnabled) - m_nsWindow.collectionBehavior &= ~NSWindowCollectionBehaviorFullScreenPrimary; } bool QCocoaWindow::isTransitioningToFullScreen() const From 4df229ce50d72e814c34b73c14a30c4d3d4724b1 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 20 Feb 2017 14:04:35 +0100 Subject: [PATCH 18/30] QArrayDataOps: don't use value-initialization ... but default-initialization instead. This bug may have rendered the diverse Qt::Uninitialized ctors we have in Qt containers ineffective. Change-Id: I5a369fa8527f19b6f8cc1a9f36512f6a0058839a Reviewed-by: Thiago Macieira --- src/corelib/tools/qarraydataops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 847f6806de5..ae83e6986e7 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -145,7 +145,7 @@ struct QGenericArrayOps T *const begin = this->begin(); do { - new (begin + this->size) T(); + new (begin + this->size) T; } while (uint(++this->size) != newSize); } From 19085350fb3b9de89a4c3e5a6c1c7bbb2a43c324 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 20 Feb 2017 10:07:29 +0100 Subject: [PATCH 19/30] Do not use QTypeInfo::isStatic anymore ... except in QList. When dafa3618 introduced isRelocatable and QTypeInfoQuery, the intention was to decouple the memory layout of QList from the reallocation optimizations in QVector. This never happened, as QVector (and QVarLengthArray) continue to use isStatic to this day. Fix by porting both QVector and QVLA to QTypeInfoQuery and isRelocatable. Change-Id: I6951f2cf21f0cbb24e2dbd38f80f1bd82007d394 Reviewed-by: Thiago Macieira --- src/corelib/tools/qlist.h | 1 + src/corelib/tools/qvarlengtharray.h | 4 ++-- src/corelib/tools/qvector.h | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index c0a92aaa101..f861c1e71cb 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -126,6 +126,7 @@ class QList public: struct MemoryLayout : std::conditional< + // must stay isStatic until ### Qt 6 for BC reasons (don't use !isRelocatable)! QTypeInfo::isStatic || QTypeInfo::isLarge, QListData::IndirectLayout, typename std::conditional< diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index bb5ae78d2b3..25f5176c226 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -352,7 +352,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray::realloc(int asize, int a a = Prealloc; } s = 0; - if (QTypeInfo::isStatic) { + if (!QTypeInfoQuery::isRelocatable) { QT_TRY { // copy all the old elements while (s < copySize) { @@ -445,7 +445,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray::iterator QVarLengthA if (n != 0) { resize(s + n); const T copy(t); - if (QTypeInfo::isStatic) { + if (!QTypeInfoQuery::isRelocatable) { T *b = ptr + offset; T *j = ptr + s; T *i = j - n; diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 5225b68d40f..c69d27bbf98 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -553,7 +553,7 @@ void QVector::reallocData(const int asize, const int aalloc, QArrayData::Allo T *srcEnd = asize > d->size ? d->end() : d->begin() + asize; T *dst = x->begin(); - if (QTypeInfo::isStatic || (isShared && QTypeInfo::isComplex)) { + if (!QTypeInfoQuery::isRelocatable || (isShared && QTypeInfo::isComplex)) { // we can not move the data, we need to copy construct it while (srcBegin != srcEnd) { new (dst++) T(*srcBegin++); @@ -598,7 +598,7 @@ void QVector::reallocData(const int asize, const int aalloc, QArrayData::Allo } if (d != x) { if (!d->ref.deref()) { - if (QTypeInfo::isStatic || !aalloc || (isShared && QTypeInfo::isComplex)) { + if (!QTypeInfoQuery::isRelocatable || !aalloc || (isShared && QTypeInfo::isComplex)) { // data was copy constructed, we need to call destructors // or if !alloc we did nothing to the old 'd'. freeData(d); @@ -697,7 +697,7 @@ typename QVector::iterator QVector::insert(iterator before, size_type n, c const T copy(t); if (!isDetached() || d->size + n > int(d->alloc)) reallocData(d->size, d->size + n, QArrayData::Grow); - if (QTypeInfo::isStatic) { + if (!QTypeInfoQuery::isRelocatable) { T *b = d->end(); T *i = d->end() + n; while (i != b) @@ -746,7 +746,7 @@ typename QVector::iterator QVector::erase(iterator abegin, iterator aend) detach(); abegin = d->begin() + itemsUntouched; aend = abegin + itemsToErase; - if (QTypeInfo::isStatic) { + if (!QTypeInfoQuery::isRelocatable) { iterator moveBegin = abegin + itemsToErase; iterator moveEnd = d->end(); while (moveBegin != moveEnd) { From 7c647edae928d27343b64b5e0f0805920b754110 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 20 Feb 2017 13:50:35 +0100 Subject: [PATCH 20/30] QTypeInfo: don't treat enums and (extended) integral types as complex We fully specialize QTypeInfo for most C++ built-in types, but enums and extended integral types (like GCC's int128_t) were not covered. Now that we depend on , we can stop pessimizing enums and extended integral types in QVector and QVLA by defaulting QTypeInfo::isComplex to true for such types. Fix a test that checked that enums were complex types. This should have been a XFAIL test. Enums are not complex types. Change-Id: Ibb0fb38cc83e980a428b5573d1db5666593418ae Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/global/qtypeinfo.h | 2 +- tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h index 53f6b3fff6a..cbba253a759 100644 --- a/src/corelib/global/qtypeinfo.h +++ b/src/corelib/global/qtypeinfo.h @@ -60,7 +60,7 @@ public: enum { isPointer = false, isIntegral = std::is_integral::value, - isComplex = true, + isComplex = !isIntegral && !std::is_enum::value, isStatic = true, isRelocatable = std::is_enum::value, isLarge = (sizeof(T)>sizeof(void*)), diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 7d9f56ef38e..e3c810984cb 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -731,7 +731,7 @@ QT_FOR_EACH_STATIC_CORE_POINTER(ADD_METATYPE_TEST_ROW) QTest::newRow("QPair") << ::qMetaTypeId >() << false << true << false << false; QTest::newRow("QPair") << ::qMetaTypeId >() << true << true << false << false; QTest::newRow("QPair") << ::qMetaTypeId >() << true << false << false << false; - QTest::newRow("FlagsDataEnum") << ::qMetaTypeId() << true << true << false << true; + QTest::newRow("FlagsDataEnum") << ::qMetaTypeId() << true << false << false << true; // invalid ids. QTest::newRow("-1") << -1 << false << false << false << false; From beaf33983eeb67ed3279f4835cf94c15a5e80969 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 31 Jan 2017 15:09:27 +0100 Subject: [PATCH 21/30] Fix wrong access to qMemRotateFunctions Since this table was restructured in 7c401397a4 and changed to being indexed bitwidth and not format, NEON-enabled builds have been writing to an undefined place after the table. Discovered by compiler warnings on CI. Change-Id: I109cd19a8dd703bdafdf13afd3f96ebeaa0e6de5 Reviewed-by: Erik Verbruggen --- src/gui/painting/qdrawhelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 654be5690ba..9233bff68c2 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -6549,8 +6549,8 @@ static void qInitDrawhelperFunctions() destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon; destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon; - qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon; - qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon; + qMemRotateFunctions[QPixelLayout::BPP16][0] = qt_memrotate90_16_neon; + qMemRotateFunctions[QPixelLayout::BPP16][2] = qt_memrotate270_16_neon; #endif #endif // defined(__ARM_NEON__) From 494ee2aa8d063f3159f3980832808872097286d6 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 10 Feb 2017 11:43:57 +0100 Subject: [PATCH 22/30] QThreadPool: supersede cancel() with tryTake() The cancel() function added in 5b11e43e for Qt 5.5 suffers from a number of problems: First, if runnable->autoDelete() is true, then the function suffers from the ABA problem (see documentation written for trytake()). Second, if runnable->autoDelete() is false, due to cancel() throwing away crucial information instead of returning it, the caller cannot know whether the runnable was canceled (and thus has to be deleted), wasn't found or is currently executing (and thus mustn't be deleted), or has finished executing (and can be used to extract the result). Deprecate this dangerous API and replace it with the much more useful Private::stealRunnable(), promoted to public API and renamed to tryTake() for consistency with the rest of Qt. Described the various caveats in the function's documentation. [ChangeLog][QtCore][QThreadPool] The cancel() function suffers from several subtle issues and has been replaced with a new tryTake() function. Change-Id: I93125935614087efa24b3e3969dd6718aeabaa4f Reviewed-by: Edward Welbourne --- src/corelib/thread/qthreadpool.cpp | 50 ++++++---- src/corelib/thread/qthreadpool.h | 5 + src/corelib/thread/qthreadpool_p.h | 1 - .../thread/qthreadpool/tst_qthreadpool.cpp | 92 +++++++++++++++++++ 4 files changed, 130 insertions(+), 18 deletions(-) diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp index 2ecf8f729a1..e45aaec1034 100644 --- a/src/corelib/thread/qthreadpool.cpp +++ b/src/corelib/thread/qthreadpool.cpp @@ -316,22 +316,39 @@ void QThreadPoolPrivate::clear() } /*! - \internal - Searches for \a runnable in the queue, removes it from the queue and - returns \c true if it was found in the queue + \since 5.9 + + Attempts to remove the specified \a runnable from the queue if it is not yet started. + If the runnable had not been started, returns \c true, and ownership of \a runnable + is transferred to the caller (even when \c{runnable->autoDelete() == true}). + Otherwise returns \c false. + + \note If \c{runnable->autoDelete() == true}, this function may remove the wrong + runnable. This is known as the \l{https://en.wikipedia.org/wiki/ABA_problem}{ABA problem}: + the original \a runnable may already have executed and has since been deleted. + The memory is re-used for another runnable, which then gets removed instead of + the intended one. For this reason, we recommend calling this function only for + runnables that are not auto-deleting. + + \sa start(), QRunnable::autoDelete() */ -bool QThreadPoolPrivate::stealRunnable(QRunnable *runnable) +bool QThreadPool::tryTake(QRunnable *runnable) { + Q_D(QThreadPool); + if (runnable == 0) return false; { - QMutexLocker locker(&mutex); - QVector >::iterator it = queue.begin(); - QVector >::iterator end = queue.end(); + QMutexLocker locker(&d->mutex); + + auto it = d->queue.begin(); + auto end = d->queue.end(); while (it != end) { if (it->first == runnable) { - queue.erase(it); + d->queue.erase(it); + if (runnable->autoDelete()) + --runnable->ref; // undo ++ref in start() return true; } ++it; @@ -349,10 +366,10 @@ bool QThreadPoolPrivate::stealRunnable(QRunnable *runnable) */ void QThreadPoolPrivate::stealAndRunRunnable(QRunnable *runnable) { - if (!stealRunnable(runnable)) + Q_Q(QThreadPool); + if (!q->tryTake(runnable)) return; - const bool autoDelete = runnable->autoDelete(); - bool del = autoDelete && !--runnable->ref; + const bool del = runnable->autoDelete() && !runnable->ref; // tryTake already deref'ed runnable->run(); @@ -642,24 +659,23 @@ void QThreadPool::clear() d->clear(); } +#if QT_DEPRECATED_SINCE(5, 9) /*! \since 5.5 + \obsolete use tryTake() instead, but note the different deletion rules. Removes the specified \a runnable from the queue if it is not yet started. The runnables for which \l{QRunnable::autoDelete()}{runnable->autoDelete()} returns \c true are deleted. - \sa start() + \sa start(), tryTake() */ void QThreadPool::cancel(QRunnable *runnable) { - Q_D(QThreadPool); - if (!d->stealRunnable(runnable)) - return; - if (runnable->autoDelete() && !--runnable->ref) { + if (tryTake(runnable) && runnable->autoDelete() && !runnable->ref) // tryTake already deref'ed delete runnable; - } } +#endif QT_END_NAMESPACE diff --git a/src/corelib/thread/qthreadpool.h b/src/corelib/thread/qthreadpool.h index 0ad63c5ac35..74a8c28fc83 100644 --- a/src/corelib/thread/qthreadpool.h +++ b/src/corelib/thread/qthreadpool.h @@ -83,7 +83,12 @@ public: bool waitForDone(int msecs = -1); void clear(); + +#if QT_DEPRECATED_SINCE(5, 9) + QT_DEPRECATED_X("use tryTake(), but note the different deletion rules") void cancel(QRunnable *runnable); +#endif + bool tryTake(QRunnable *runnable) Q_REQUIRED_RESULT; }; QT_END_NAMESPACE diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h index ea8127efef0..4a9f9e5cfa4 100644 --- a/src/corelib/thread/qthreadpool_p.h +++ b/src/corelib/thread/qthreadpool_p.h @@ -82,7 +82,6 @@ public: void reset(); bool waitForDone(int msecs); void clear(); - bool stealRunnable(QRunnable *runnable); void stealAndRunRunnable(QRunnable *runnable); mutable QMutex mutex; diff --git a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp index 5b7242fddb6..fdc4ecb5c8b 100644 --- a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp +++ b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp @@ -89,6 +89,7 @@ private slots: void waitForDone(); void clear(); void cancel(); + void tryTake(); void waitForDoneTimeout(); void destroyingWaitsForTasksToFinish(); void stressTest(); @@ -1042,6 +1043,97 @@ void tst_QThreadPool::cancel() delete runnables[runs-1]; } +void tst_QThreadPool::tryTake() +{ + QSemaphore sem(0); + QSemaphore startedThreads(0); + + class SemaphoreReleaser + { + QSemaphore &sem; + int n; + Q_DISABLE_COPY(SemaphoreReleaser) + public: + explicit SemaphoreReleaser(QSemaphore &sem, int n) + : sem(sem), n(n) {} + + ~SemaphoreReleaser() + { + sem.release(n); + } + }; + + class BlockingRunnable : public QRunnable + { + public: + QSemaphore &sem; + QSemaphore &startedThreads; + QAtomicInt &dtorCounter; + QAtomicInt &runCounter; + int dummy; + + explicit BlockingRunnable(QSemaphore &s, QSemaphore &started, QAtomicInt &c, QAtomicInt &r) + : sem(s), startedThreads(started), dtorCounter(c), runCounter(r) {} + + ~BlockingRunnable() + { + dtorCounter.fetchAndAddRelaxed(1); + } + + void run() override + { + startedThreads.release(); + runCounter.fetchAndAddRelaxed(1); + sem.acquire(); + count.ref(); + } + }; + + enum { + MaxThreadCount = 3, + OverProvisioning = 2, + Runs = MaxThreadCount * OverProvisioning + }; + + QThreadPool threadPool; + threadPool.setMaxThreadCount(MaxThreadCount); + BlockingRunnable *runnables[Runs]; + + // ensure that the QThreadPool doesn't deadlock if any of the checks fail + // and cause an early return: + const SemaphoreReleaser semReleaser(sem, Runs); + + count.store(0); + QAtomicInt dtorCounter = 0; + QAtomicInt runCounter = 0; + for (int i = 0; i < Runs; i++) { + runnables[i] = new BlockingRunnable(sem, startedThreads, dtorCounter, runCounter); + runnables[i]->setAutoDelete(i != 0 && i != Runs - 1); // one which will run and one which will not + QVERIFY(!threadPool.tryTake(runnables[i])); // verify NOOP for jobs not in the queue + threadPool.start(runnables[i]); + } + // wait for all worker threads to have started up: + QVERIFY(startedThreads.tryAcquire(MaxThreadCount, 60*1000 /* 1min */)); + + for (int i = 0; i < MaxThreadCount; ++i) { + // check taking runnables doesn't work once they were started: + QVERIFY(!threadPool.tryTake(runnables[i])); + } + for (int i = MaxThreadCount; i < Runs ; ++i) { + QVERIFY(threadPool.tryTake(runnables[i])); + delete runnables[i]; + } + + runnables[0]->dummy = 0; // valgrind will catch this if tryTake() is crazy enough to delete currently running jobs + QCOMPARE(dtorCounter.load(), int(Runs - MaxThreadCount)); + sem.release(MaxThreadCount); + threadPool.waitForDone(); + QCOMPARE(runCounter.load(), int(MaxThreadCount)); + QCOMPARE(count.load(), int(MaxThreadCount)); + QCOMPARE(dtorCounter.load(), int(Runs - 1)); + delete runnables[0]; // if the pool deletes them then we'll get double-free crash +} + void tst_QThreadPool::destroyingWaitsForTasksToFinish() { QTime total, pass; From 9fbe3a926223813094003fcb99abf5f2bc0da727 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 22 Feb 2017 11:24:15 +0100 Subject: [PATCH 23/30] QErrorMessage: replace a QPair with a struct Instead of the incomprehensible "names" .first and .second, the code can now use .content and .type. Change-Id: I7fe320ded33a07fb8ff77ac96c17fc5ee1079da3 Reviewed-by: Friedemann Kleint --- src/widgets/dialogs/qerrormessage.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/widgets/dialogs/qerrormessage.cpp b/src/widgets/dialogs/qerrormessage.cpp index bcfc00d9829..8200135abe2 100644 --- a/src/widgets/dialogs/qerrormessage.cpp +++ b/src/widgets/dialogs/qerrormessage.cpp @@ -62,6 +62,13 @@ QT_BEGIN_NAMESPACE +namespace { +struct Message { + QString content; + QString type; +}; +} + class QErrorMessagePrivate : public QDialogPrivate { Q_DECLARE_PUBLIC(QErrorMessage) @@ -70,7 +77,7 @@ public: QCheckBox * again; QTextEdit * errors; QLabel * icon; - std::queue > pending; + std::queue pending; QSet doNotShow; QSet doNotShowType; QString currentMessage; @@ -303,9 +310,8 @@ bool QErrorMessagePrivate::isMessageToBeShown(const QString &message, const QStr bool QErrorMessagePrivate::nextPending() { while (!pending.empty()) { - QPair &pendingMessage = pending.front(); - QString message = qMove(pendingMessage.first); - QString type = qMove(pendingMessage.second); + QString message = std::move(pending.front().content); + QString type = std::move(pending.front().type); pending.pop(); if (isMessageToBeShown(message, type)) { #ifndef QT_NO_TEXTHTMLPARSER @@ -355,7 +361,7 @@ void QErrorMessage::showMessage(const QString &message, const QString &type) Q_D(QErrorMessage); if (!d->isMessageToBeShown(message, type)) return; - d->pending.push(qMakePair(message, type)); + d->pending.push({message, type}); if (!isVisible() && d->nextPending()) show(); } From 3ac8b8c6961bb5b2ae82bbaee154282c54bd0b90 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 20 Feb 2017 09:36:34 +0100 Subject: [PATCH 24/30] QTypeInfo: record whether it was specialized This is one of the pillars of my static container checking toolbox, one of the main checks being that every type put into a Qt container has been marked up with Q_DECLARE_TYPEINFO. Obviously, we cannot upstream such a checker and inflict it upon the world, but we can put some foundations in. This is the most central one. Change-Id: I9185facb2f37ba9fcc12c9aae5675eed454d755c Reviewed-by: Giuseppe D'Angelo Reviewed-by: Thiago Macieira --- src/corelib/global/qtypeinfo.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h index cbba253a759..7031021e166 100644 --- a/src/corelib/global/qtypeinfo.h +++ b/src/corelib/global/qtypeinfo.h @@ -58,6 +58,7 @@ class QTypeInfo { public: enum { + isSpecialized = std::is_enum::value, // don't require every enum to be marked manually isPointer = false, isIntegral = std::is_integral::value, isComplex = !isIntegral && !std::is_enum::value, @@ -74,6 +75,7 @@ class QTypeInfo { public: enum { + isSpecialized = true, isPointer = false, isIntegral = false, isComplex = false, @@ -90,6 +92,7 @@ class QTypeInfo { public: enum { + isSpecialized = true, isPointer = true, isIntegral = false, isComplex = false, @@ -152,6 +155,7 @@ class QTypeInfoMerger { public: enum { + isSpecialized = true, isComplex = QTypeInfoQuery::isComplex || QTypeInfoQuery::isComplex || QTypeInfoQuery::isComplex || QTypeInfoQuery::isComplex, isStatic = QTypeInfoQuery::isStatic || QTypeInfoQuery::isStatic @@ -173,6 +177,7 @@ class QTypeInfo< CONTAINER > \ { \ public: \ enum { \ + isSpecialized = true, \ isPointer = false, \ isIntegral = false, \ isComplex = true, \ @@ -201,6 +206,7 @@ class QTypeInfo< CONTAINER > \ { \ public: \ enum { \ + isSpecialized = true, \ isPointer = false, \ isIntegral = false, \ isComplex = true, \ @@ -241,6 +247,7 @@ class QTypeInfo \ { \ public: \ enum { \ + isSpecialized = true, \ isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0), \ isStatic = (((FLAGS) & (Q_MOVABLE_TYPE | Q_PRIMITIVE_TYPE)) == 0), \ isRelocatable = !isStatic || ((FLAGS) & Q_RELOCATABLE_TYPE), \ From b952bd3605315465b1ceb90e0924707f781a9f9e Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 20 Dec 2014 22:13:58 +0100 Subject: [PATCH 25/30] QSizePolicy: make (Policy,Policy) ctor constexpr Unfortunately, that ctor also takes a ControlType argument (defaulted), and calls the non-constexpr, non-inline function setControlType(). In order to make at least the two-arg version constexpr, I added a use of the ternary operator to check for type == DefaultType, making all calls of the ctor that use type == DefaultType constexpr. For init'ing an aggregate type without ctor in the ctor-init-list, I needed to require uniform initialization, too. C++11-style constexpr cannot call void functions, so I needed to extract the transformation part of setControlType() into a new function that returns the result instead of storing it directly. Saves a surprising 2K in QtWidgets text size on GCC 4.9, AMD64 Linux stripped release builds. Change-Id: Ib4adf5fd6e54d5345dbfe1c298554278faf13c58 Reviewed-by: Giuseppe D'Angelo --- src/widgets/kernel/qsizepolicy.cpp | 11 +++++++---- src/widgets/kernel/qsizepolicy.h | 9 +++++++++ .../widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/widgets/kernel/qsizepolicy.cpp b/src/widgets/kernel/qsizepolicy.cpp index a03523d2afd..b08a9abb1e8 100644 --- a/src/widgets/kernel/qsizepolicy.cpp +++ b/src/widgets/kernel/qsizepolicy.cpp @@ -254,6 +254,11 @@ QSizePolicy::ControlType QSizePolicy::controlType() const \sa QStyle::layoutSpacing() */ void QSizePolicy::setControlType(ControlType type) +{ + bits.ctype = toControlTypeFieldValue(type); +} + +quint32 QSizePolicy::toControlTypeFieldValue(ControlType type) Q_DECL_NOTHROW { /* The control type is a flag type, with values 0x1, 0x2, 0x4, 0x8, 0x10, @@ -271,10 +276,8 @@ void QSizePolicy::setControlType(ControlType type) int i = 0; while (true) { - if (type & (0x1 << i)) { - bits.ctype = i; - return; - } + if (type & (0x1 << i)) + return i; ++i; } } diff --git a/src/widgets/kernel/qsizepolicy.h b/src/widgets/kernel/qsizepolicy.h index eceb08259eb..83ce5853ab4 100644 --- a/src/widgets/kernel/qsizepolicy.h +++ b/src/widgets/kernel/qsizepolicy.h @@ -119,12 +119,19 @@ public: QT_SIZEPOLICY_CONSTEXPR QSizePolicy() : data(0) { } +#ifdef Q_COMPILER_UNIFORM_INIT + QT_SIZEPOLICY_CONSTEXPR QSizePolicy(Policy horizontal, Policy vertical, ControlType type = DefaultType) + : bits{0, 0, quint32(horizontal), quint32(vertical), + type == DefaultType ? 0 : toControlTypeFieldValue(type), 0, 0, 0} + {} +#else QSizePolicy(Policy horizontal, Policy vertical, ControlType type = DefaultType) : data(0) { bits.horPolicy = horizontal; bits.verPolicy = vertical; setControlType(type); } +#endif // uniform-init QT_SIZEPOLICY_CONSTEXPR Policy horizontalPolicy() const { return static_cast(bits.horPolicy); } QT_SIZEPOLICY_CONSTEXPR Policy verticalPolicy() const { return static_cast(bits.verPolicy); } ControlType controlType() const; @@ -176,6 +183,8 @@ private: struct Bits; QT_SIZEPOLICY_CONSTEXPR explicit QSizePolicy(Bits b) Q_DECL_NOTHROW : bits(b) { } + static quint32 toControlTypeFieldValue(ControlType type) Q_DECL_NOTHROW; + struct Bits { quint32 horStretch : 8; quint32 verStretch : 8; diff --git a/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp b/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp index 98b765a6c6d..4ae1f02ce28 100644 --- a/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp +++ b/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp @@ -113,6 +113,8 @@ void tst_QSizePolicy::constExpr() // check that certain ctors are constexpr (compile-only): { Q_CONSTEXPR QSizePolicy sp; Q_UNUSED(sp); } { Q_CONSTEXPR QSizePolicy sp = QSizePolicy(); Q_UNUSED(sp); } + { Q_CONSTEXPR QSizePolicy sp = QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); Q_UNUSED(sp); } + { Q_CONSTEXPR QSizePolicy sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding, QSizePolicy::DefaultType); Q_UNUSED(sp); } #else QSKIP("QSizePolicy cannot be constexpr with this version of the compiler."); #endif From 2cda991ab19cbe115dfa965acc3686f067960773 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 26 Jan 2017 17:39:06 +0100 Subject: [PATCH 26/30] QStaticByteArrayMatcher: fix MSVC warning MSVC 2013 complained: src/corelib/tools/qbytearraymatcher.h(143) : warning C4351: new behavior: elements of array 'QStaticByteArrayMatcher<6>::m_pattern' will be default initialized Fix the same way as 9a07ab9234ccb4ed0d6aa3a64b4b2c888635dae5: by suppressing the warning. Change-Id: Ic41f7eabe7e39709d76e6062f5891cdcfaa6e1ed Reviewed-by: Friedemann Kleint --- src/corelib/tools/qbytearraymatcher.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/corelib/tools/qbytearraymatcher.h b/src/corelib/tools/qbytearraymatcher.h index 51e08ba4bfc..476bc3c0490 100644 --- a/src/corelib/tools/qbytearraymatcher.h +++ b/src/corelib/tools/qbytearraymatcher.h @@ -132,6 +132,9 @@ private: } }; +QT_WARNING_PUSH +QT_WARNING_DISABLE_MSVC(4351) // MSVC 2013: "new behavior: elements of array ... will be default initialized" + // remove once we drop MSVC 2013 support template class QStaticByteArrayMatcher : QStaticByteArrayMatcherBase { @@ -153,6 +156,8 @@ public: QByteArray pattern() const { return QByteArray(m_pattern, int(N - 1)); } }; +QT_WARNING_POP + template Q_DECL_RELAXED_CONSTEXPR QStaticByteArrayMatcher qMakeStaticByteArrayMatcher(const char (&pattern)[N]) Q_DECL_NOTHROW { return QStaticByteArrayMatcher(pattern); } From 4cd002402fe12f5e50d8267d0e9c39e525b99c2d Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 21 Feb 2017 13:30:14 +0100 Subject: [PATCH 27/30] Simplify QTzTimeZonePrivate implementation - Don't init m_icu with 0. It's a QSharedDataPointer, which inits to nullptr anyway. - The copy ctor didn't do anything out of the ordinary, so = default it. It's also only used in the implementation of clone(), so make it private. Removes three #if QT_CONFIG blocks. We can't use ctor delegation here, because systemTimeZoneId() is a virtual function. Change-Id: I2cd06c3349686b6f21c897acb5c12185a36d5b9f Reviewed-by: Thiago Macieira --- src/corelib/tools/qtimezoneprivate_p.h | 2 +- src/corelib/tools/qtimezoneprivate_tz.cpp | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/corelib/tools/qtimezoneprivate_p.h b/src/corelib/tools/qtimezoneprivate_p.h index 682edd39963..158c547f6ab 100644 --- a/src/corelib/tools/qtimezoneprivate_p.h +++ b/src/corelib/tools/qtimezoneprivate_p.h @@ -287,12 +287,12 @@ Q_DECL_CONSTEXPR inline bool operator!=(const QTzTransitionRule &lhs, const QTzT class Q_AUTOTEST_EXPORT QTzTimeZonePrivate Q_DECL_FINAL : public QTimeZonePrivate { + QTzTimeZonePrivate(const QTzTimeZonePrivate &) = default; public: // Create default time zone QTzTimeZonePrivate(); // Create named time zone QTzTimeZonePrivate(const QByteArray &ianaId); - QTzTimeZonePrivate(const QTzTimeZonePrivate &other); ~QTzTimeZonePrivate(); QTimeZonePrivate *clone() Q_DECL_OVERRIDE; diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index 9cbe3392256..7cd5d6d5067 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -615,32 +615,16 @@ static QVector calculatePosixTransitions(const QByteArra // Create the system default time zone QTzTimeZonePrivate::QTzTimeZonePrivate() -#if QT_CONFIG(icu) - : m_icu(0) -#endif { init(systemTimeZoneId()); } // Create a named time zone QTzTimeZonePrivate::QTzTimeZonePrivate(const QByteArray &ianaId) -#if QT_CONFIG(icu) - : m_icu(0) -#endif { init(ianaId); } -QTzTimeZonePrivate::QTzTimeZonePrivate(const QTzTimeZonePrivate &other) - : QTimeZonePrivate(other), m_tranTimes(other.m_tranTimes), - m_tranRules(other.m_tranRules), m_abbreviations(other.m_abbreviations), -#if QT_CONFIG(icu) - m_icu(other.m_icu), -#endif - m_posixRule(other.m_posixRule) -{ -} - QTzTimeZonePrivate::~QTzTimeZonePrivate() { } From 4d92712a2c92c019c37238f808ae7a1900f45b97 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 22 Feb 2017 20:26:48 +0100 Subject: [PATCH 28/30] QTimeZonePrivate: make clone() const, use covariant return types There's nothing wrong with cloning a const QTimeZonePrivate, so make clone() const. Also, if you're cloning a QTzTimeZonePrivate, you already know that you get a QTzTimeZonePrivate back. C++ supports covariant return types for this reason, so use them. Change-Id: I60e19e89b1b7bad080c552f1baca314ab0a6295e Reviewed-by: Thiago Macieira --- src/corelib/tools/qtimezoneprivate.cpp | 4 ++-- src/corelib/tools/qtimezoneprivate_android.cpp | 2 +- src/corelib/tools/qtimezoneprivate_icu.cpp | 2 +- src/corelib/tools/qtimezoneprivate_mac.mm | 2 +- src/corelib/tools/qtimezoneprivate_p.h | 14 +++++++------- src/corelib/tools/qtimezoneprivate_tz.cpp | 2 +- src/corelib/tools/qtimezoneprivate_win.cpp | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/corelib/tools/qtimezoneprivate.cpp b/src/corelib/tools/qtimezoneprivate.cpp index ea8f6d1438e..7b780ecf7d3 100644 --- a/src/corelib/tools/qtimezoneprivate.cpp +++ b/src/corelib/tools/qtimezoneprivate.cpp @@ -136,7 +136,7 @@ QTimeZonePrivate::~QTimeZonePrivate() { } -QTimeZonePrivate *QTimeZonePrivate::clone() +QTimeZonePrivate *QTimeZonePrivate::clone() const { return new QTimeZonePrivate(*this); } @@ -784,7 +784,7 @@ QUtcTimeZonePrivate::~QUtcTimeZonePrivate() { } -QTimeZonePrivate *QUtcTimeZonePrivate::clone() +QUtcTimeZonePrivate *QUtcTimeZonePrivate::clone() const { return new QUtcTimeZonePrivate(*this); } diff --git a/src/corelib/tools/qtimezoneprivate_android.cpp b/src/corelib/tools/qtimezoneprivate_android.cpp index e079fa0d63f..c3f8c3e0d95 100644 --- a/src/corelib/tools/qtimezoneprivate_android.cpp +++ b/src/corelib/tools/qtimezoneprivate_android.cpp @@ -88,7 +88,7 @@ void QAndroidTimeZonePrivate::init(const QByteArray &ianaId) m_id = ianaId; } -QTimeZonePrivate *QAndroidTimeZonePrivate::clone() +QAndroidTimeZonePrivate *QAndroidTimeZonePrivate::clone() const { return new QAndroidTimeZonePrivate(*this); } diff --git a/src/corelib/tools/qtimezoneprivate_icu.cpp b/src/corelib/tools/qtimezoneprivate_icu.cpp index c088fe7694b..887486f567b 100644 --- a/src/corelib/tools/qtimezoneprivate_icu.cpp +++ b/src/corelib/tools/qtimezoneprivate_icu.cpp @@ -305,7 +305,7 @@ QIcuTimeZonePrivate::~QIcuTimeZonePrivate() ucal_close(m_ucal); } -QTimeZonePrivate *QIcuTimeZonePrivate::clone() +QIcuTimeZonePrivate *QIcuTimeZonePrivate::clone() const { return new QIcuTimeZonePrivate(*this); } diff --git a/src/corelib/tools/qtimezoneprivate_mac.mm b/src/corelib/tools/qtimezoneprivate_mac.mm index 0c2dbe6feff..4e9a432fbfa 100644 --- a/src/corelib/tools/qtimezoneprivate_mac.mm +++ b/src/corelib/tools/qtimezoneprivate_mac.mm @@ -82,7 +82,7 @@ QMacTimeZonePrivate::~QMacTimeZonePrivate() [m_nstz release]; } -QTimeZonePrivate *QMacTimeZonePrivate::clone() +QMacTimeZonePrivate *QMacTimeZonePrivate::clone() const { return new QMacTimeZonePrivate(*this); } diff --git a/src/corelib/tools/qtimezoneprivate_p.h b/src/corelib/tools/qtimezoneprivate_p.h index 158c547f6ab..9985d0672cb 100644 --- a/src/corelib/tools/qtimezoneprivate_p.h +++ b/src/corelib/tools/qtimezoneprivate_p.h @@ -92,7 +92,7 @@ public: QTimeZonePrivate(const QTimeZonePrivate &other); virtual ~QTimeZonePrivate(); - virtual QTimeZonePrivate *clone(); + virtual QTimeZonePrivate *clone() const; bool operator==(const QTimeZonePrivate &other) const; bool operator!=(const QTimeZonePrivate &other) const; @@ -187,7 +187,7 @@ public: QUtcTimeZonePrivate(const QUtcTimeZonePrivate &other); virtual ~QUtcTimeZonePrivate(); - QTimeZonePrivate *clone() Q_DECL_OVERRIDE; + QUtcTimeZonePrivate *clone() const override; Data data(qint64 forMSecsSinceEpoch) const Q_DECL_OVERRIDE; @@ -234,7 +234,7 @@ public: QIcuTimeZonePrivate(const QIcuTimeZonePrivate &other); ~QIcuTimeZonePrivate(); - QTimeZonePrivate *clone() Q_DECL_OVERRIDE; + QIcuTimeZonePrivate *clone() const override; QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType, const QLocale &locale) const Q_DECL_OVERRIDE; @@ -295,7 +295,7 @@ public: QTzTimeZonePrivate(const QByteArray &ianaId); ~QTzTimeZonePrivate(); - QTimeZonePrivate *clone() Q_DECL_OVERRIDE; + QTzTimeZonePrivate *clone() const override; QLocale::Country country() const Q_DECL_OVERRIDE; QString comment() const Q_DECL_OVERRIDE; @@ -351,7 +351,7 @@ public: QMacTimeZonePrivate(const QMacTimeZonePrivate &other); ~QMacTimeZonePrivate(); - QTimeZonePrivate *clone() Q_DECL_OVERRIDE; + QMacTimeZonePrivate *clone() const override; QString comment() const Q_DECL_OVERRIDE; @@ -404,7 +404,7 @@ public: QWinTimeZonePrivate(const QWinTimeZonePrivate &other); ~QWinTimeZonePrivate(); - QTimeZonePrivate *clone() Q_DECL_OVERRIDE; + QWinTimeZonePrivate *clone() const override; QString comment() const Q_DECL_OVERRIDE; @@ -454,7 +454,7 @@ public: QAndroidTimeZonePrivate(const QAndroidTimeZonePrivate &other); ~QAndroidTimeZonePrivate(); - QTimeZonePrivate *clone() Q_DECL_OVERRIDE; + QAndroidTimeZonePrivate *clone() const override; QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType, const QLocale &locale) const Q_DECL_OVERRIDE; diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index 7cd5d6d5067..1714c9802f9 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -629,7 +629,7 @@ QTzTimeZonePrivate::~QTzTimeZonePrivate() { } -QTimeZonePrivate *QTzTimeZonePrivate::clone() +QTzTimeZonePrivate *QTzTimeZonePrivate::clone() const { return new QTzTimeZonePrivate(*this); } diff --git a/src/corelib/tools/qtimezoneprivate_win.cpp b/src/corelib/tools/qtimezoneprivate_win.cpp index 4febeda5375..16dfaefb745 100644 --- a/src/corelib/tools/qtimezoneprivate_win.cpp +++ b/src/corelib/tools/qtimezoneprivate_win.cpp @@ -415,7 +415,7 @@ QWinTimeZonePrivate::~QWinTimeZonePrivate() { } -QTimeZonePrivate *QWinTimeZonePrivate::clone() +QWinTimeZonePrivate *QWinTimeZonePrivate::clone() const { return new QWinTimeZonePrivate(*this); } From 21298aad45ebf770122d9f843b379a077239ecc1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 2 Feb 2017 16:24:48 +0100 Subject: [PATCH 29/30] Enable FTS5, will be used by Assistant instead of clucene Change-Id: Ifd1d7128c6080650b5ad43f87410c7058d8c5a74 Reviewed-by: Karsten Heimrich --- src/3rdparty/sqlite.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty/sqlite.pri b/src/3rdparty/sqlite.pri index 8f504540648..79179daaf42 100644 --- a/src/3rdparty/sqlite.pri +++ b/src/3rdparty/sqlite.pri @@ -1,5 +1,5 @@ CONFIG(release, debug|release):DEFINES *= NDEBUG -DEFINES += SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_RTREE +DEFINES += SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_FTS5 SQLITE_ENABLE_RTREE !contains(CONFIG, largefile):DEFINES += SQLITE_DISABLE_LFS qtConfig(posix_fallocate): DEFINES += HAVE_POSIX_FALLOCATE=1 winrt: DEFINES += SQLITE_OS_WINRT From 35fa30e65d26b9e4840cfa793ed8369b3475c1fd Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 23 Feb 2017 10:32:31 +0100 Subject: [PATCH 30/30] Revert "testlib: Add qWaitFor to wait for predicate" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3b38392844dd9e145a4783445fd3c96e84bb94d1. The change caused test compile failures with MSVC2015 in qqmlsettings; a variable was not captured in the lambda expression. This appears to be a compiler bug of MSVC. Task-number: QTBUG-59096 Change-Id: I3bf5288eb005b2e1661819bb33bc54fb944d0150 Reviewed-by: Liang Qi Reviewed-by: Jan Arve Sæther Reviewed-by: Simon Hausmann --- .../snippets/code/src_qtestlib_qtestcase.cpp | 8 --- src/testlib/qtestcase.h | 3 +- src/testlib/qtestcase.qdoc | 15 ---- src/testlib/qtestsystem.h | 71 ++++++++----------- 4 files changed, 31 insertions(+), 66 deletions(-) diff --git a/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp b/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp index 990b7a38d7b..01ee8102f40 100644 --- a/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp +++ b/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp @@ -306,13 +306,5 @@ QTest::keyClick(myWindow, Qt::Key_Escape); QTest::keyClick(myWindow, Qt::Key_Escape, Qt::ShiftModifier, 200); //! [29] -//! [30] -MyObject obj; -obj.startup(); -QTest::qWaitFor([&]() { - return obj.isReady(); -}, 3000); -//! [30] - } diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index 4beb9ea52dc..a7e825396a7 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -150,8 +150,7 @@ do {\ #define QTRY_IMPL(expr, timeout)\ const int qt_test_step = 50; \ const int qt_test_timeoutValue = timeout; \ - bool timedOut = !QTest::qWaitFor([&]() { return (expr); }, qt_test_timeoutValue); \ - Q_UNUSED(timedOut); \ + QTRY_LOOP_IMPL((expr), qt_test_timeoutValue, qt_test_step); \ QTRY_TIMEOUT_DEBUG_IMPL((expr), qt_test_timeoutValue, qt_test_step)\ // Will try to wait for the expression to become true while allowing event processing diff --git a/src/testlib/qtestcase.qdoc b/src/testlib/qtestcase.qdoc index f7d816b8f97..8f3d140adda 100644 --- a/src/testlib/qtestcase.qdoc +++ b/src/testlib/qtestcase.qdoc @@ -1062,21 +1062,6 @@ \sa QTest::qSleep(), QSignalSpy::wait() */ -/*! \fn void QTest::qWaitFor(Predicate predicate, int timeout) - - Waits for \a timeout milliseconds or until the \a predicate returns true. - - Returns \c true if the \a preciate returned true within \a timeout milliseconds, otherwise returns \c false. - - Example: - \snippet code/src_qtestlib_qtestcase.cpp 30 - - The code above will wait for the object to become ready, for a - maximum of three seconds. - - \since 5.9 -*/ - /*! \fn bool QTest::qWaitForWindowExposed(QWindow *window, int timeout) \since 5.0 diff --git a/src/testlib/qtestsystem.h b/src/testlib/qtestsystem.h index 7e0dae19136..4c611aab6b8 100644 --- a/src/testlib/qtestsystem.h +++ b/src/testlib/qtestsystem.h @@ -54,60 +54,41 @@ QT_BEGIN_NAMESPACE namespace QTest { - template - static Q_REQUIRED_RESULT bool qWaitFor(Predicate predicate, int timeout = 5000) - { - // We should not spint the event loop in case the predicate is already true, - // otherwise we might send new events that invalidate the predicate. - if (predicate()) - return true; - - // qWait() is expected to spin the event loop, even when called with a small - // timeout like 1ms, so we we can't use a simple while-loop here based on - // the deadline timer not having timed out. Use do-while instead. - - int remaining = timeout; - QDeadlineTimer deadline(remaining, Qt::PreciseTimer); - - do { - QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); - QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); - - remaining = deadline.remainingTime(); - if (remaining > 0) { - QTest::qSleep(qMin(10, remaining)); - remaining = deadline.remainingTime(); - } - - if (predicate()) - return true; - - remaining = deadline.remainingTime(); - } while (remaining > 0); - - return predicate(); // Last chance - } - Q_DECL_UNUSED inline static void qWait(int ms) { Q_ASSERT(QCoreApplication::instance()); - auto unconditionalWait = []() { return false; }; - bool timedOut = !qWaitFor(unconditionalWait, ms); - Q_UNUSED(timedOut); + + QDeadlineTimer timer(ms, Qt::PreciseTimer); + int remaining = ms; + do { + QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); + QCoreApplication::sendPostedEvents(Q_NULLPTR, QEvent::DeferredDelete); + remaining = timer.remainingTime(); + if (remaining <= 0) + break; + QTest::qSleep(qMin(10, remaining)); + remaining = timer.remainingTime(); + } while (remaining > 0); } #ifdef QT_GUI_LIB inline static bool qWaitForWindowActive(QWindow *window, int timeout = 5000) { - bool becameActive = qWaitFor([&]() { return window->isActive(); }, timeout); - + QDeadlineTimer timer(timeout, Qt::PreciseTimer); + int remaining = timeout; + while (!window->isActive() && remaining > 0) { + QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); + QCoreApplication::sendPostedEvents(Q_NULLPTR, QEvent::DeferredDelete); + QTest::qSleep(10); + remaining = timer.remainingTime(); + } // Try ensuring the platform window receives the real position. // (i.e. that window->pos() reflects reality) // isActive() ( == FocusIn in case of X) does not guarantee this. It seems some WMs randomly // send the final ConfigureNotify (the one with the non-bogus 0,0 position) after the FocusIn. // If we just let things go, every mapTo/FromGlobal call the tests perform directly after // qWaitForWindowShown() will generate bogus results. - if (becameActive) { + if (window->isActive()) { int waitNo = 0; // 0, 0 might be a valid position after all, so do not wait for ever while (window->position().isNull()) { if (waitNo++ > timeout / 10) @@ -120,7 +101,15 @@ namespace QTest inline static bool qWaitForWindowExposed(QWindow *window, int timeout = 5000) { - return qWaitFor([&]() { return window->isExposed(); }, timeout); + QDeadlineTimer timer(timeout, Qt::PreciseTimer); + int remaining = timeout; + while (!window->isExposed() && remaining > 0) { + QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); + QCoreApplication::sendPostedEvents(Q_NULLPTR, QEvent::DeferredDelete); + QTest::qSleep(10); + remaining = timer.remainingTime(); + } + return window->isExposed(); } #endif