From e524724f9dc6f64f6f94b842682c751dcd07225f Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Mon, 15 Oct 2018 09:51:12 +0200 Subject: [PATCH 01/22] tst_qfilesystemmodel: Do not use nested calls of auto test functions Calling rowCount inside another auto test function yields unexpected results, if rowCount fails. Without a check for QTest::currentTestFailed the failure will not stop the calling function and other functions like rowsInserted and rowsRemoved might happily continue even though their requirements are not met. That caused a crash on winrt under certain circumstances. In addition to that TRY_WAIT now does not only wait for the given amount of time, but also gives feedback about its result. Before this change TRY_WAIT was basically useless, as it gave no indication about its success/failure. Fixes: QTBUG-71121 Change-Id: Ibd3f233a0b913db799814be97c4274d510643c74 Reviewed-by: Friedemann Kleint --- .../qfilesystemmodel/tst_qfilesystemmodel.cpp | 79 +++++++++++++------ 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp index d8a680881a7..9ee5292fcb1 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -51,10 +51,15 @@ // Will try to wait for the condition while allowing event processing // for a maximum of 5 seconds. -#define TRY_WAIT(expr) \ +#define TRY_WAIT(expr, timedOut) \ do { \ + *timedOut = true; \ const int step = 50; \ - for (int __i = 0; __i < 5000 && !(expr); __i+=step) { \ + for (int __i = 0; __i < 5000; __i += step) { \ + if (expr) { \ + *timedOut = false; \ + break; \ + } \ QTest::qWait(step); \ } \ } while(0) @@ -123,6 +128,8 @@ private slots: protected: bool createFiles(const QString &test_path, const QStringList &initial_files, int existingFileCount = 0, const QStringList &intial_dirs = QStringList()); + QModelIndex prepareTestModelRoot(const QString &test_path, QSignalSpy **spy2 = nullptr, + QSignalSpy **spy3 = nullptr); private: QFileSystemModel *model; @@ -306,7 +313,11 @@ void tst_QFileSystemModel::iconProvider() bool tst_QFileSystemModel::createFiles(const QString &test_path, const QStringList &initial_files, int existingFileCount, const QStringList &initial_dirs) { //qDebug() << (model->rowCount(model->index(test_path))) << existingFileCount << initial_files; - TRY_WAIT((model->rowCount(model->index(test_path)) == existingFileCount)); + bool timedOut = false; + TRY_WAIT((model->rowCount(model->index(test_path)) == existingFileCount), &timedOut); + if (timedOut) + return false; + for (int i = 0; i < initial_dirs.count(); ++i) { QDir dir(test_path); if (!dir.exists()) { @@ -363,23 +374,45 @@ bool tst_QFileSystemModel::createFiles(const QString &test_path, const QStringLi return true; } -void tst_QFileSystemModel::rowCount() +QModelIndex tst_QFileSystemModel::prepareTestModelRoot(const QString &test_path, QSignalSpy **spy2, + QSignalSpy **spy3) { - QString tmp = flatDirTestPath; - QVERIFY(createFiles(tmp, QStringList())); + if (model->rowCount(model->index(test_path)) != 0) + return QModelIndex(); - QSignalSpy spy2(model, SIGNAL(rowsInserted(QModelIndex,int,int))); - QSignalSpy spy3(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); + if (spy2) + *spy2 = new QSignalSpy(model, &QFileSystemModel::rowsInserted); + if (spy3) + *spy3 = new QSignalSpy(model, &QFileSystemModel::rowsAboutToBeInserted); - QStringList files = QStringList() << "b" << "d" << "f" << "h" << "j" << ".a" << ".c" << ".e" << ".g"; + QStringList files = { "b", "d", "f", "h", "j", ".a", ".c", ".e", ".g" }; QString l = "b,d,f,h,j,.a,.c,.e,.g"; - QVERIFY(createFiles(tmp, files)); + if (!createFiles(test_path, files)) + return QModelIndex(); - QModelIndex root = model->setRootPath(tmp); - QTRY_COMPARE(model->rowCount(root), 5); - QVERIFY(spy2.count() > 0); - QVERIFY(spy3.count() > 0); + QModelIndex root = model->setRootPath(test_path); + if (!root.isValid()) + return QModelIndex(); + + bool timedOut = false; + TRY_WAIT(model->rowCount(root) == 5, &timedOut); + if (timedOut) + return QModelIndex(); + + return root; +} + +void tst_QFileSystemModel::rowCount() +{ + const QString tmp = flatDirTestPath; + QSignalSpy *spy2 = nullptr; + QSignalSpy *spy3 = nullptr; + QModelIndex root = prepareTestModelRoot(flatDirTestPath, &spy2, &spy3); + QVERIFY(root.isValid()); + + QVERIFY(spy2 && spy2->count() > 0); + QVERIFY(spy3 && spy3->count() > 0); } void tst_QFileSystemModel::rowsInserted_data() @@ -401,9 +434,9 @@ static inline QString lastEntry(const QModelIndex &root) void tst_QFileSystemModel::rowsInserted() { - QString tmp = flatDirTestPath; - rowCount(); - QModelIndex root = model->index(model->rootPath()); + const QString tmp = flatDirTestPath; + QModelIndex root = prepareTestModelRoot(tmp); + QVERIFY(root.isValid()); QFETCH(int, ascending); QFETCH(int, count); @@ -454,9 +487,9 @@ void tst_QFileSystemModel::rowsRemoved_data() void tst_QFileSystemModel::rowsRemoved() { - QString tmp = flatDirTestPath; - rowCount(); - QModelIndex root = model->index(model->rootPath()); + const QString tmp = flatDirTestPath; + QModelIndex root = prepareTestModelRoot(tmp); + QVERIFY(root.isValid()); QFETCH(int, count); QFETCH(int, ascending); @@ -509,9 +542,9 @@ void tst_QFileSystemModel::dataChanged() { QSKIP("This can't be tested right now since we don't watch files, only directories."); - QString tmp = flatDirTestPath; - rowCount(); - QModelIndex root = model->index(model->rootPath()); + const QString tmp = flatDirTestPath; + QModelIndex root = prepareTestModelRoot(tmp); + QVERIFY(root.isValid()); QFETCH(int, count); QFETCH(int, assending); From 013cf4aeb3e705165614715fcda59c22f58cc5b0 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Fri, 19 Oct 2018 07:37:23 +0200 Subject: [PATCH 02/22] angle: Add additional information to qt_attribution.json Task-number: QTBUG-71112 Change-Id: If1b81589f295657597a9dfa3671128a927cbe488 Reviewed-by: Andre de la Rocha Reviewed-by: Edward Welbourne --- src/3rdparty/angle/qt_attribution.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/3rdparty/angle/qt_attribution.json b/src/3rdparty/angle/qt_attribution.json index e35e1f0eb98..b10343d9456 100644 --- a/src/3rdparty/angle/qt_attribution.json +++ b/src/3rdparty/angle/qt_attribution.json @@ -5,6 +5,10 @@ "QDocModule": "qtgui", "QtUsage": "Used on Windows to implement OpenGL ES on top of DirectX. Configure with -no-opengl, or -opengl desktop to exclude.", + "Description": "The ANGLE library translates OpenGL ES API calls to hardware-supported APIs.", + "Homepage": "http://angleproject.org/", + "Version": "chromium/3280", + "License": "BSD 3-clause \"New\" or \"Revised\" License", "LicenseId": "BSD-3-Clause", "LicenseFile": "LICENSE", From 88fe7c8cad0bb8e9aee1373c7a7a24d1e4be24ca Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 24 Oct 2018 14:22:43 +0200 Subject: [PATCH 03/22] Windows QPA: Fix 2-finger scroll not working with some touchpads It seems some touchpads only send legacy WM_MOUSEWHEEL/WM_MOUSEHWHEEL messages for 2-finger scrolling, instead of WM_POINTERWHEEL/ WM_POINTERHWHEEL, even after EnableMouseInPointer(TRUE), in spite of sending the expected pointer messages for normal pointer movement/taps. This change adds a workaround to handle legacy wheel messages even when in pointer mode. Task-number: QTBUG-71257 Change-Id: Ib360051147c4521751a5b91d90fa7657496777fa Reviewed-by: Oliver Wolff Reviewed-by: Friedemann Kleint --- .../windows/qwindowspointerhandler.cpp | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 21dc0cd577b..2b6c696979f 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -484,6 +484,9 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h case WM_POINTERHWHEEL: case WM_POINTERWHEEL: { + if (!isValidWheelReceiver(window)) + return true; + int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam); // Qt horizontal wheel rotation orientation is opposite to the one in WM_POINTERHWHEEL @@ -493,8 +496,7 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h const QPoint angleDelta = (msg.message == WM_POINTERHWHEEL || (keyModifiers & Qt::AltModifier)) ? QPoint(delta, 0) : QPoint(0, delta); - if (isValidWheelReceiver(window)) - QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); + QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); return true; } case WM_POINTERLEAVE: @@ -508,7 +510,6 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, MSG msg, PVOID vTouchInfo, quint32 count) { Q_UNUSED(hwnd); - Q_UNUSED(et); if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. @@ -707,21 +708,46 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin // Process old-style mouse messages here. bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) { - Q_UNUSED(et); - // Generate enqueued events. flushTouchEvents(m_touchDevice); flushTabletEvents(); *result = 0; - if (msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE) + if (et != QtWindows::MouseWheelEvent && msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE) return false; - const QPoint localPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); - const QPoint globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, localPos); + const QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); + QPoint localPos; + QPoint globalPos; + if ((et == QtWindows::MouseWheelEvent) || (et & QtWindows::NonClientEventFlag)) { + globalPos = eventPos; + localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos); + } else { + localPos = eventPos; + globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, eventPos); + } + const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); QWindowsWindow *platformWindow = static_cast(window->handle()); + if (et == QtWindows::MouseWheelEvent) { + + if (!isValidWheelReceiver(window)) + return true; + + int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam); + + // Qt horizontal wheel rotation orientation is opposite to the one in WM_MOUSEHWHEEL + if (msg.message == WM_MOUSEHWHEEL) + delta = -delta; + + const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ? + QPoint(delta, 0) : QPoint(0, delta); + + QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); + return true; + } + if (msg.message == WM_MOUSELEAVE) { if (window == m_currentWindow) { QWindowSystemInterface::handleLeaveEvent(window); @@ -762,7 +788,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW m_windowUnderPointer = currentWindowUnderPointer; } - const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const Qt::MouseButtons mouseButtons = queryMouseButtons(); if (!discardEvent) From 8e1c8076282f87a8d19f73feb1bb5baf068de1e1 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 24 Oct 2018 11:11:21 +0200 Subject: [PATCH 04/22] xcb: fix unresponsive mouse clicks after VT switch This patch amends d67214302f269242ae3d8d2b962fd91ec42c979e. The issue was caused by mistakenly interchanging m_hasXRender <-> m_hasXRandr. Also renamed selectXRandrEvents() -> xrandrSelectEvents() to be more consistent with xi2Select*() API. And moved the xrandrSelectEvents() to QXcbConnection ctor for the same reason. Fixes: QTBUG-71305 Change-Id: I26f9bac3ae1f997f53134eb97f3569fb6d3c13fe Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbconnection.cpp | 3 +++ src/plugins/platforms/xcb/qxcbconnection.h | 2 +- src/plugins/platforms/xcb/qxcbconnection_basic.cpp | 4 ++-- src/plugins/platforms/xcb/qxcbconnection_screens.cpp | 6 ++---- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 9e857ea2ff2..45f096a13aa 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -105,6 +105,9 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra m_xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower(); + if (hasXRandr()) + xrandrSelectEvents(); + initializeScreens(); #if QT_CONFIG(xcb_xinput) diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 49e79ec3fd5..5d53b97d376 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -250,7 +250,7 @@ protected: bool event(QEvent *e) override; private: - void selectXRandrEvents(); + void xrandrSelectEvents(); QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const; QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const; QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow) const; diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp index 7bed3c8937c..b8335d12408 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp @@ -308,7 +308,7 @@ void QXcbBasicConnection::initializeXRandr() return; } - m_hasXRender = true; + m_hasXRandr = true; m_xrenderVersion.first = xrenderQuery->major_version; m_xrenderVersion.second = xrenderQuery->minor_version; #endif @@ -358,7 +358,7 @@ void QXcbBasicConnection::initializeXRender() return; } - m_hasXRandr = true; + m_hasXRender = true; m_xrandrFirstEvent = reply->first_event; } diff --git a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp index 4c380bf39fb..fe9e0be86d6 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp @@ -46,7 +46,7 @@ #include -void QXcbConnection::selectXRandrEvents() +void QXcbConnection::xrandrSelectEvents() { xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(setup()); for (; rootIter.rem; xcb_screen_next(&rootIter)) { @@ -270,8 +270,6 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen) void QXcbConnection::initializeScreens() { - selectXRandrEvents(); - xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup()); int xcbScreenNumber = 0; // screen number in the xcb sense QXcbScreen *primaryScreen = nullptr; @@ -284,7 +282,7 @@ void QXcbConnection::initializeScreens() QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber); m_virtualDesktops.append(virtualDesktop); QList siblings; - if (hasXRender()) { + if (hasXRandr()) { // RRGetScreenResourcesCurrent is fast but it may return nothing if the // configuration is not initialized wrt to the hardware. We should call // RRGetScreenResources in this case. From 95ba049f8787258ccb28eeda72d1fac71f90e6f6 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 23 Oct 2018 11:18:22 +0200 Subject: [PATCH 05/22] Remove QSKIP and bring the test back to business MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit on macOS, where it was skipped but where it now seems to be stable/work. Task-number: QTBUG-39983 Change-Id: I100a57f23b43074ebacc012be247d92acc6ae336 Reviewed-by: Mårten Nordheim Reviewed-by: Edward Welbourne --- tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp index fed05698fd9..da5327594c7 100644 --- a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp +++ b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp @@ -209,9 +209,6 @@ void tst_QIODevice::read_QByteArray() //-------------------------------------------------------------------- void tst_QIODevice::unget() { -#if defined(Q_OS_MAC) - QSKIP("The unget network test is unstable on Mac. See QTBUG-39983."); -#endif QBuffer buffer; buffer.open(QBuffer::ReadWrite); buffer.write("ZXCV"); From 321f11db53422fe797c881cafa36ee44406d803c Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 23 Oct 2018 11:37:07 +0200 Subject: [PATCH 06/22] tst_QLocalSocket::processConnections: remove QSKIP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit on macOS, the test seems to be stable nowadays. Task-number: QTBUG-39986 Change-Id: I18430c3feb27a5bee5474e1eb95f7d89b25f00a9 Reviewed-by: Edward Welbourne Reviewed-by: Mårten Nordheim --- tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp index 779d55a77af..45ab2755101 100644 --- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp @@ -962,9 +962,6 @@ void tst_QLocalSocket::processConnection() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else -#ifdef Q_OS_MAC - QSKIP("The processConnection test is unstable on Mac. See QTBUG-39986."); -#endif #ifdef Q_OS_WIN const QString exeSuffix = QStringLiteral(".exe"); From b10ee45546e152e08b2494bd45eb22426e9d2dc9 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 23 Oct 2018 15:42:24 +0200 Subject: [PATCH 07/22] tst_qeventdispatcher: remove macOS from the BLACKLIST MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the test is stable in Qt 5.12. Task-number: QTBUG-60993 Change-Id: I0c366567121688d9518e90b5e8f9ec1b4006b7b9 Reviewed-by: Mårten Nordheim Reviewed-by: Edward Welbourne --- tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST b/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST index fb7e025b7ca..b1590a5ccf3 100644 --- a/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST +++ b/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST @@ -1,7 +1,5 @@ [sendPostedEvents] windows -osx [registerTimer] windows -osx winrt From 269172037db11d6e62bcef2d5c7491af9244f203 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Thu, 18 Oct 2018 10:20:42 +1000 Subject: [PATCH 08/22] wasm: use maintainTimers instead of processEvents for touch callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If39cdeedef60a47c0ba1afbab6adf1668bf5d0d6 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmeventtranslator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index 23251fd610b..a3fdcd1025e 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -546,7 +546,7 @@ int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEven else QWindowSystemInterface::handleTouchCancelEvent(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, keyModifier); - QCoreApplication::processEvents(); + QWasmEventDispatcher::maintainTimers(); return 1; } From 95476bfcf64aa9cb43775ebfe3410ce9565de4d5 Mon Sep 17 00:00:00 2001 From: Ivan Komissarov Date: Mon, 22 Oct 2018 19:08:57 +0200 Subject: [PATCH 09/22] qendian: Fix float conversions Since Qt 5.10, qTo/FromBig/LittleEndian stopped working. It may be confusing, but big endian floats do exist, so not to break old code, we should support them. Change-Id: I21cdbc7f48ec030ce3d82f1cd1aad212f0fe5dd0 Reviewed-by: Thiago Macieira --- src/corelib/global/qendian.h | 26 ++++++++++++ .../corelib/global/qtendian/tst_qtendian.cpp | 40 +++++++++++++++++-- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/corelib/global/qendian.h b/src/corelib/global/qendian.h index 1cc8a823d9c..0e67a1ab8ef 100644 --- a/src/corelib/global/qendian.h +++ b/src/corelib/global/qendian.h @@ -41,6 +41,7 @@ #ifndef QENDIAN_H #define QENDIAN_H +#include #include // include stdlib.h and hope that it defines __GLIBC__ for glibc-based systems @@ -151,6 +152,31 @@ template <> inline Q_DECL_CONSTEXPR qint8 qbswap(qint8 source) return source; } +// floating specializations +template +Float qbswapFloatHelper(Float source) +{ + // memcpy call in qFromUnaligned is recognized by optimizer as a correct way of type prunning + auto temp = qFromUnaligned::Unsigned>(&source); + temp = qbswap(temp); + return qFromUnaligned(&temp); +} + +template <> inline qfloat16 qbswap(qfloat16 source) +{ + return qbswapFloatHelper(source); +} + +template <> inline float qbswap(float source) +{ + return qbswapFloatHelper(source); +} + +template <> inline double qbswap(double source) +{ + return qbswapFloatHelper(source); +} + /* * qbswap(const T src, const void *dest); * Changes the byte order of \a src from big endian to little endian or vice versa diff --git a/tests/auto/corelib/global/qtendian/tst_qtendian.cpp b/tests/auto/corelib/global/qtendian/tst_qtendian.cpp index 7043969c2fb..2345bb39c10 100644 --- a/tests/auto/corelib/global/qtendian/tst_qtendian.cpp +++ b/tests/auto/corelib/global/qtendian/tst_qtendian.cpp @@ -64,6 +64,9 @@ struct TestData quint16 data16; quint8 data8; + float dataFloat; + double dataDouble; + quint8 reserved; }; @@ -72,6 +75,7 @@ template <> quint8 getData(const TestData &d) { return d.data8; } template <> quint16 getData(const TestData &d) { return d.data16; } template <> quint32 getData(const TestData &d) { return d.data32; } template <> quint64 getData(const TestData &d) { return d.data64; } +template <> float getData(const TestData &d) { return d.dataFloat; } union RawTestData { @@ -79,9 +83,39 @@ union RawTestData TestData data; }; -static const TestData inNativeEndian = { Q_UINT64_C(0x0123456789abcdef), 0x00c0ffee, 0xcafe, 0xcf, '\0' }; -static const RawTestData inBigEndian = { "\x01\x23\x45\x67\x89\xab\xcd\xef" "\x00\xc0\xff\xee" "\xca\xfe" "\xcf" }; -static const RawTestData inLittleEndian = { "\xef\xcd\xab\x89\x67\x45\x23\x01" "\xee\xff\xc0\x00" "\xfe\xca" "\xcf" }; +template +Float int2Float(typename QIntegerForSizeof::Unsigned i) +{ + Float result = 0; + memcpy(reinterpret_cast(&result), reinterpret_cast(&i), sizeof (Float)); + return result; +} + +static const TestData inNativeEndian = { + Q_UINT64_C(0x0123456789abcdef), + 0x00c0ffee, + 0xcafe, + 0xcf, + int2Float(0x00c0ffeeU), + int2Float(Q_UINT64_C(0x0123456789abcdef)), + '\0' +}; +static const RawTestData inBigEndian = { + "\x01\x23\x45\x67\x89\xab\xcd\xef" + "\x00\xc0\xff\xee" + "\xca\xfe" + "\xcf" + "\x00\xc0\xff\xee" + "\x01\x23\x45\x67\x89\xab\xcd\xef" +}; +static const RawTestData inLittleEndian = { + "\xef\xcd\xab\x89\x67\x45\x23\x01" + "\xee\xff\xc0\x00" + "\xfe\xca" + "\xcf" + "\xee\xff\xc0\x00" + "\xef\xcd\xab\x89\x67\x45\x23\x01" +}; #define EXPAND_ENDIAN_TEST(endian) \ do { \ From d02fed67814a3cb8f28a4f0ec61e075858fce238 Mon Sep 17 00:00:00 2001 From: Rafael Roquetto Date: Mon, 1 Oct 2018 09:16:28 +1000 Subject: [PATCH 10/22] macOS: restore hidden popup windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to to explicitly unhide popup windows that were previously explicitly hidden by applicationWillHide, so that their visibility will be effectively restored when the application is unhidden (otherwise the windows are gone forever even though their internal visibility is set to true). Change-Id: I4dbd209b07f769cc815851b40c41db0739ca2dc9 Task-number: QTBUG-71014 Reviewed-by: Timur Pocheptsov Reviewed-by: Edward Welbourne Reviewed-by: Tor Arne Vestbø --- .../cocoa/qcocoaapplicationdelegate.mm | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 221a8b0866a..44ab16d300e 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -86,6 +86,7 @@ #include #include "qt_mac_p.h" #include +#include QT_USE_NAMESPACE @@ -93,6 +94,7 @@ QT_USE_NAMESPACE bool startedQuit; NSObject *reflectionDelegate; bool inLaunch; + QWindowList hiddenWindows; } + (instancetype)sharedDelegate @@ -322,12 +324,28 @@ QT_USE_NAMESPACE // fact that the application itself is hidden, which will cause a problem when // the application is made visible again. const QWindowList topLevelWindows = QGuiApplication::topLevelWindows(); - for (QWindow *topLevelWindow : qAsConst(topLevelWindows)) { - if ((topLevelWindow->type() & Qt::Popup) == Qt::Popup && topLevelWindow->isVisible()) + for (QWindow *topLevelWindow : topLevelWindows) { + if ((topLevelWindow->type() & Qt::Popup) == Qt::Popup && topLevelWindow->isVisible()) { topLevelWindow->hide(); + + if ((topLevelWindow->type() & Qt::Tool) == Qt::Tool) + hiddenWindows << topLevelWindow; + } } } +- (void)applicationDidUnhide:(NSNotification *)notification +{ + if (reflectionDelegate + && [reflectionDelegate respondsToSelector:@selector(applicationDidUnhide:)]) + [reflectionDelegate applicationDidUnhide:notification]; + + for (QWindow *window : qAsConst(hiddenWindows)) + window->show(); + + hiddenWindows.clear(); +} + - (void)applicationDidBecomeActive:(NSNotification *)notification { if (reflectionDelegate From 58d2180dfac2e279b7fae89d467b16d82d80eb7e Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 28 Oct 2018 11:33:29 +0100 Subject: [PATCH 11/22] Add since 5.11 markers to two QFile enums Change-Id: Iaa015046cdcece10c28437da40fcd6cdc9d55eb3 Reviewed-by: Thiago Macieira --- src/corelib/io/qiodevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 5dd5f8031ec..86e21f0a663 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -333,7 +333,7 @@ QIODevicePrivate::~QIODevicePrivate() allowed. This flag currently only affects QFile. Other classes might use this flag in the future, but until then using this flag with any classes other than QFile may - result in undefined behavior. + result in undefined behavior. (since Qt 5.11) \value ExistingOnly Fail if the file to be opened does not exist. This flag must be specified alongside ReadOnly, WriteOnly, or ReadWrite. Note that using this flag with ReadOnly alone @@ -341,7 +341,7 @@ QIODevicePrivate::~QIODevicePrivate() not exist. This flag currently only affects QFile. Other classes might use this flag in the future, but until then using this flag with any classes other than QFile may - result in undefined behavior. + result in undefined behavior. (since Qt 5.11) Certain flags, such as \c Unbuffered and \c Truncate, are meaningless when used with some subclasses. Some of these From fc1ab49cd75608f257fb9aa577fed490c5a8e551 Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Wed, 24 Oct 2018 10:28:23 +0300 Subject: [PATCH 12/22] Fix leak in QContiguousCache::setCapacity Fixes: QTBUG-52125 Change-Id: Id0073e73279d049cf3f89ef6ea3a5ca1027efb0d Reviewed-by: Thiago Macieira --- src/corelib/tools/qcontiguouscache.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index faa7263d6b1..fdb9c6d19a7 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -217,6 +217,7 @@ void QContiguousCache::setCapacity(int asize) detach(); union { QContiguousCacheData *d; QContiguousCacheTypedData *p; } x; x.d = allocateData(asize); + x.d->ref.store(1); x.d->alloc = asize; x.d->count = qMin(d->count, asize); x.d->offset = d->offset + d->count - x.d->count; From eb056ee233c80376a837beba8f712a0f1068dae3 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Thu, 25 Oct 2018 18:18:57 +0200 Subject: [PATCH 13/22] Fix painter opacity being ignored when rendering to PDF The opacity set on a QPainter was being ignored for drawImage()/drawPixmap() calls when rendering to a PDF file through QPdfWriter/QPrinter. This change fixes it for PDF files v1.4 (default version) or v1.6. For PDF/A-1b files, opacity will remain ignored to ensure compliance with the specification. Task-number: QTBUG-70752 Change-Id: I4280e898698e0367dfb4c6ac2cd14ca2bf98850e Reviewed-by: Oliver Wolff Reviewed-by: Lars Knoll Reviewed-by: Friedemann Kleint --- src/gui/painting/qpdf.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index b410e9b9008..e69726b6173 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -953,7 +953,18 @@ void QPdfEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, con if (object < 0) return; - *d->currentPage << "q\n/GSa gs\n"; + *d->currentPage << "q\n"; + + if ((d->pdfVersion != QPdfEngine::Version_A1b) && (d->opacity != 1.0)) { + int stateObject = d->addConstantAlphaObject(qRound(255 * d->opacity), qRound(255 * d->opacity)); + if (stateObject) + *d->currentPage << "/GState" << stateObject << "gs\n"; + else + *d->currentPage << "/GSa gs\n"; + } else { + *d->currentPage << "/GSa gs\n"; + } + *d->currentPage << QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(), rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix)); @@ -981,7 +992,18 @@ void QPdfEngine::drawImage(const QRectF &rectangle, const QImage &image, const Q if (object < 0) return; - *d->currentPage << "q\n/GSa gs\n"; + *d->currentPage << "q\n"; + + if ((d->pdfVersion != QPdfEngine::Version_A1b) && (d->opacity != 1.0)) { + int stateObject = d->addConstantAlphaObject(qRound(255 * d->opacity), qRound(255 * d->opacity)); + if (stateObject) + *d->currentPage << "/GState" << stateObject << "gs\n"; + else + *d->currentPage << "/GSa gs\n"; + } else { + *d->currentPage << "/GSa gs\n"; + } + *d->currentPage << QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(), rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix)); From aa0e3d02d5a6a646594b04c753ebc1655e44a141 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 25 Oct 2018 13:21:44 +0200 Subject: [PATCH 14/22] winrt: Use SwitchToThread instead of Sleep(0) UWP also supports SwitchToThread. The usage of Sleep(0) was a leftover that was forgotten when porting to desktop Window's approach of handling threads. Change-Id: I5e3d6fb3eefe07407b910cc6a6b45781d320e151 Reviewed-by: Friedemann Kleint Reviewed-by: Simon Hausmann Reviewed-by: Thiago Macieira --- src/corelib/thread/qthread_win.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index e04d27d7b64..e56fe2c6aea 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -465,11 +465,7 @@ int QThread::idealThreadCount() Q_DECL_NOTHROW void QThread::yieldCurrentThread() { -#if !defined(Q_OS_WINRT) SwitchToThread(); -#else - ::Sleep(0); -#endif } #endif // QT_CONFIG(thread) From 7e7514482fb2086fda100439a34b5b4ef627d329 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 25 Oct 2018 15:28:40 +0200 Subject: [PATCH 15/22] winrt: Skip a test row of tst_QRegularExpression::threadSafety PCRE2 does not support JIT on winrt. This test row takes a long time (30 seconds here) without JIT and thus might cause test timeouts in COIN when run on winrt. Change-Id: I79d9f6be16dbe16594ae2bf51f353acd06b3d2fe Reviewed-by: Simon Hausmann --- .../tools/qregularexpression/tst_qregularexpression.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp index f520e9742a4..18098f16bfd 100644 --- a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp +++ b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp @@ -2108,12 +2108,16 @@ void tst_QRegularExpression::threadSafety_data() QTest::addRow("pattern%d", ++i) << "ab.*cd" << subject; } + // pcre2 does not support JIT for winrt. As this test row takes a long time without JIT we skip + // it for winrt as it might time out in COIN. +#ifndef Q_OS_WINRT { QString subject = "ab"; subject.append(QString(512*1024, QLatin1Char('x'))); subject.append("c"); QTest::addRow("pattern%d", ++i) << "ab.*cd" << subject; } +#endif // Q_OS_WINRT { QString subject = "ab"; From 7f54ea714ed62f3b4fb88dedbee9357bf6a26d26 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 23 Oct 2018 11:15:00 +0200 Subject: [PATCH 16/22] QtCore/Windows: Add pointer messages to the debug operator for MSG Task-number: QTBUG-71257 Change-Id: I53a4cee7b84b4075342cc016bb3382f473c27788 Reviewed-by: Andre de la Rocha --- src/corelib/kernel/qcoreapplication_win.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index 0109e2c6588..0c57ad34b9d 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -417,6 +417,23 @@ static const char *findWMstr(uint msg) { 0x0232, "WM_EXITSIZEMOVE" }, { 0x0233, "WM_DROPFILES" }, { 0x0234, "WM_MDIREFRESHMENU" }, + { 0x0241, "WM_NCPOINTERUPDATE"}, + { 0x0242, "WM_NCPOINTERDOWN"}, + { 0x0243, "WM_NCPOINTERUP"}, + { 0x0245, "WM_POINTERUPDATE"}, + { 0x0246, "WM_POINTERDOWN"}, + { 0x0247, "WM_POINTERUP"}, + { 0x0249, "WM_POINTERENTER"}, + { 0x024A, "WM_POINTERLEAVE"}, + { 0x0248, "WM_POINTERACTIVATE"}, + { 0x024C, "WM_POINTERCAPTURECHANGED"}, + { 0x024D, "WM_TOUCHHITTESTING"}, + { 0x024E, "WM_POINTERWHEEL"}, + { 0x024F, "WM_POINTERHWHEEL"}, + { 0x0250, "DM_POINTERHITTEST"}, + { 0x0251, "WM_POINTERROUTEDTO"}, + { 0x0252, "WM_POINTERROUTEDAWAY"}, + { 0x0253, "WM_POINTERROUTEDRELEASED"}, { 0x0281, "WM_IME_SETCONTEXT" }, { 0x0282, "WM_IME_NOTIFY" }, { 0x0283, "WM_IME_CONTROL" }, From 497f43c90f7160c1b198d829eab21c8c010fc7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Wed, 24 Oct 2018 12:46:04 +0200 Subject: [PATCH 17/22] tst_QCborValue: Disable support for spaceship operator Spaceship operator was disabled for QCborValue, but not the test. Change-Id: Icb91da689f62ef6de9f4fa926346505c5e50e9eb Reviewed-by: Thiago Macieira --- tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp index 38b26e7de4c..4b753eab6b6 100644 --- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp +++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp @@ -330,7 +330,7 @@ void tst_QCborValue::copyCompare() QCOMPARE(v, other); QVERIFY(!(v != other)); QVERIFY(!(v < other)); -#if QT_HAS_INCLUDE() +#if 0 && QT_HAS_INCLUDE() QVERIFY(v <= other); QVERIFY(v >= other); QVERIFY(!(v > other)); From 4c37b64411f60d2667963db8e7d42459cad663e6 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Thu, 18 Oct 2018 10:02:48 +0200 Subject: [PATCH 18/22] Add terminating character when sending byte arrays in FileChooser portal Terminating character is needed for gtk portal backend, which is not able to contruct a string without it and thus not able to pre-select a file or a directory in file dialog. Change-Id: I5b40fb1ce584936fc92e93f38dc8559890852d99 Reviewed-by: Thiago Macieira --- .../xdgdesktopportal/qxdgdesktopportalfiledialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp index cda267d24bc..5e94d1558ed 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp @@ -181,10 +181,10 @@ void QXdgDesktopPortalFileDialog::openPortal() if (d->saveFile) { if (!d->directory.isEmpty()) - options.insert(QLatin1String("current_folder"), d->directory.toLatin1()); + options.insert(QLatin1String("current_folder"), d->directory.toLatin1().append('\0')); if (!d->selectedFiles.isEmpty()) - options.insert(QLatin1String("current_file"), d->selectedFiles.first().toLatin1()); + options.insert(QLatin1String("current_file"), d->selectedFiles.first().toLatin1().append('\0')); } // Insert filters From a952fd7d5b03ce1968ec58871fbb8b3600895900 Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Wed, 26 Sep 2018 10:29:14 +0300 Subject: [PATCH 19/22] QObject: Fix isSignalConnected() when signals have been disconnected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bitmap cache for the first 64 signals being connected was only set when the connection is added. It was never unset when the connection was removed. Internal use of the connectedSignals bitmap is not hurt by it occasionally saying a signal is connected even though it is not, since the purpose of those checks is avoiding expensive operations that are not necessary if nothing is connected to the signal. However, the public API using this cache meant that it also never spotted signals being disconnected. This was not documented. Fix the behavior by only using the cache if it is up to date. If it is not, use a slower path that gives the correct answer. To avoid making disconnections and QObject destructions slower, the cache is only updated to unset disconnected signals when new signal connections are added. No extra work is done in the common case where signals are only removed in the end of the QObject's lifetime. Fixes: QTBUG-32340 Change-Id: Ieb6e498060157153cec60d9c8f1c33056993fda1 Reviewed-by: Ville Voutilainen Reviewed-by: Thiago Macieira Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Jędrzej Nowacki --- src/corelib/kernel/qobject.cpp | 34 ++++++++---- .../corelib/kernel/qobject/tst_qobject.cpp | 53 +++++++++++++++++++ 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 07208b7f407..deab51cfd08 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -421,6 +421,7 @@ void QObjectPrivate::cleanConnectionLists() { if (connectionLists->dirty && !connectionLists->inUse) { // remove broken connections + bool allConnected = false; for (int signal = -1; signal < connectionLists->count(); ++signal) { QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal]; @@ -432,11 +433,13 @@ void QObjectPrivate::cleanConnectionLists() QObjectPrivate::Connection **prev = &connectionList.first; QObjectPrivate::Connection *c = *prev; + bool connected = false; // whether the signal is still connected somewhere while (c) { if (c->receiver) { last = c; prev = &c->nextConnectionList; c = *prev; + connected = true; } else { QObjectPrivate::Connection *next = c->nextConnectionList; *prev = next; @@ -448,6 +451,14 @@ void QObjectPrivate::cleanConnectionLists() // Correct the connection list's last pointer. // As conectionList.last could equal last, this could be a noop connectionList.last = last; + + if (!allConnected && !connected && signal >= 0 + && size_t(signal) < sizeof(connectedSignals) * 8) { + // This signal is no longer connected + connectedSignals[signal >> 5] &= ~(1 << (signal & 0x1f)); + } else if (signal == -1) { + allConnected = connected; + } } connectionLists->dirty = false; } @@ -2501,19 +2512,20 @@ bool QObject::isSignalConnected(const QMetaMethod &signal) const signalIndex += QMetaObjectPrivate::signalOffset(signal.mobj); - if (signalIndex < sizeof(d->connectedSignals) * 8) + QMutexLocker locker(signalSlotLock(this)); + if (!d->connectionLists) + return false; + + if (signalIndex < sizeof(d->connectedSignals) * 8 && !d->connectionLists->dirty) return d->isSignalConnected(signalIndex); - QMutexLocker locker(signalSlotLock(this)); - if (d->connectionLists) { - if (signalIndex < uint(d->connectionLists->count())) { - const QObjectPrivate::Connection *c = - d->connectionLists->at(signalIndex).first; - while (c) { - if (c->receiver) - return true; - c = c->nextConnectionList; - } + if (signalIndex < uint(d->connectionLists->count())) { + const QObjectPrivate::Connection *c = + d->connectionLists->at(signalIndex).first; + while (c) { + if (c->receiver) + return true; + c = c->nextConnectionList; } } return false; diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 68c6ece5833..effc82261ba 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -103,6 +103,7 @@ private slots: void deleteQObjectWhenDeletingEvent(); void overloads(); void isSignalConnected(); + void isSignalConnectedAfterDisconnection(); void qMetaObjectConnect(); void qMetaObjectDisconnectOne(); void sameName(); @@ -3835,6 +3836,58 @@ void tst_QObject::isSignalConnected() QVERIFY(!o.isSignalConnected(QMetaMethod())); } +void tst_QObject::isSignalConnectedAfterDisconnection() +{ + ManySignals o; + const QMetaObject *meta = o.metaObject(); + + const QMetaMethod sig00 = meta->method(meta->indexOfSignal("sig00()")); + QVERIFY(!o.isSignalConnected(sig00)); + QObject::connect(&o, &ManySignals::sig00, qt_noop); + QVERIFY(o.isSignalConnected(sig00)); + QVERIFY(QObject::disconnect(&o, &ManySignals::sig00, 0, 0)); + QVERIFY(!o.isSignalConnected(sig00)); + + const QMetaMethod sig69 = meta->method(meta->indexOfSignal("sig69()")); + QVERIFY(!o.isSignalConnected(sig69)); + QObject::connect(&o, &ManySignals::sig69, qt_noop); + QVERIFY(o.isSignalConnected(sig69)); + QVERIFY(QObject::disconnect(&o, &ManySignals::sig69, 0, 0)); + QVERIFY(!o.isSignalConnected(sig69)); + + { + ManySignals o2; + QObject::connect(&o, &ManySignals::sig00, &o2, &ManySignals::sig00); + QVERIFY(o.isSignalConnected(sig00)); + // o2 is destructed + } + QVERIFY(!o.isSignalConnected(sig00)); + + const QMetaMethod sig01 = meta->method(meta->indexOfSignal("sig01()")); + QObject::connect(&o, &ManySignals::sig00, qt_noop); + QObject::connect(&o, &ManySignals::sig01, qt_noop); + QObject::connect(&o, &ManySignals::sig69, qt_noop); + QVERIFY(o.isSignalConnected(sig00)); + QVERIFY(o.isSignalConnected(sig01)); + QVERIFY(o.isSignalConnected(sig69)); + QVERIFY(QObject::disconnect(&o, &ManySignals::sig69, 0, 0)); + QVERIFY(o.isSignalConnected(sig00)); + QVERIFY(o.isSignalConnected(sig01)); + QVERIFY(!o.isSignalConnected(sig69)); + QVERIFY(QObject::disconnect(&o, &ManySignals::sig00, 0, 0)); + QVERIFY(!o.isSignalConnected(sig00)); + QVERIFY(o.isSignalConnected(sig01)); + QVERIFY(!o.isSignalConnected(sig69)); + QObject::connect(&o, &ManySignals::sig69, qt_noop); + QVERIFY(!o.isSignalConnected(sig00)); + QVERIFY(o.isSignalConnected(sig01)); + QVERIFY(o.isSignalConnected(sig69)); + QVERIFY(QObject::disconnect(&o, &ManySignals::sig01, 0, 0)); + QVERIFY(!o.isSignalConnected(sig00)); + QVERIFY(!o.isSignalConnected(sig01)); + QVERIFY(o.isSignalConnected(sig69)); +} + void tst_QObject::qMetaObjectConnect() { SenderObject *s = new SenderObject; From deee147acaf1009eca439b0e959025971aab0c90 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 29 Oct 2018 10:55:36 +0100 Subject: [PATCH 20/22] Fix doc Change-Id: I75386b948763bbe784fc36abe7e69696bc04219d Reviewed-by: Leena Miettinen --- src/gui/painting/qrgba64.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qrgba64.qdoc b/src/gui/painting/qrgba64.qdoc index 26c78a5dcd5..3ee8a355e63 100644 --- a/src/gui/painting/qrgba64.qdoc +++ b/src/gui/painting/qrgba64.qdoc @@ -35,7 +35,7 @@ QRgba64 is a 64-bit data-structure containing four 16-bit color channels: Red, green, blue and alpha. - QRgba64 can be used a replacement for QRgb when higher precision is needed. In particular a + QRgba64 can be used as a replacement for QRgb when higher precision is needed. In particular a premultiplied QRgba64 can operate on unpremultiplied QRgb without loss of precision except for alpha 0. From f25c68646226fe19e98887ad43a7e12e0d87734b Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 26 Oct 2018 15:56:39 +0200 Subject: [PATCH 21/22] xcb: remove leftover function It was forgotten in 4050ee6ac7da0e5e7414c699c3cd4e26193c653d Change-Id: Icace56161b8ae372dba105f82da0d1c1b69542c1 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbwindow.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 6667f45343e..d2ca9fe0b98 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -207,7 +207,6 @@ protected: void setTransparentForMouseEvents(bool transparent); void updateDoesNotAcceptFocus(bool doesNotAcceptFocus); - QRect windowToWmGeometry(QRect r) const; void sendXEmbedMessage(xcb_window_t window, quint32 message, quint32 detail = 0, quint32 data1 = 0, quint32 data2 = 0); void handleXEmbedMessage(const xcb_client_message_event_t *event); From f5c0a19077989b5ac14071ecd095e29f62d05602 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 17 Oct 2018 17:28:55 +0200 Subject: [PATCH 22/22] xcb: move clipboard code out of QXcbConnection::processXcbEvents ... to QXcbConnection::handleXcbEvent(), which is where it belongs. This patch amends bc6f5b3ff61f4b1dea14084349702f2895feda66 (Sep, 2013). And some other design cleanups. Change-Id: Iefa0793c58de16a59d2294f38311e1e8dfa3035b Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbclipboard.cpp | 196 ++++++++----------- src/plugins/platforms/xcb/qxcbclipboard.h | 41 +++- src/plugins/platforms/xcb/qxcbconnection.cpp | 13 +- src/plugins/platforms/xcb/qxcbconnection.h | 1 + 4 files changed, 121 insertions(+), 130 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index 3fd14a659e3..9c7559d514d 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -153,114 +153,71 @@ private: QByteArray format_atoms; }; -namespace { -class INCRTransaction; -typedef QMap TransactionMap; -static TransactionMap *transactions = 0; - -//#define INCR_DEBUG - -class INCRTransaction : public QObject +QXcbClipboardTransaction::QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb_window_t w, + xcb_atom_t p, QByteArray d, xcb_atom_t t, int f) + : m_clipboard(clipboard), m_window(w), m_property(p), m_data(d), m_target(t), m_format(f) { - Q_OBJECT -public: - INCRTransaction(QXcbConnection *c, xcb_window_t w, xcb_atom_t p, - QByteArray d, uint i, xcb_atom_t t, int f, int to) : - conn(c), win(w), property(p), data(d), increment(i), - target(t), format(f), timeout(to), offset(0) - { - const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; - xcb_change_window_attributes(conn->xcb_connection(), win, + const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; + xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window, + XCB_CW_EVENT_MASK, values); + + m_abortTimerId = startTimer(m_clipboard->clipboardTimeout()); +} + +QXcbClipboardTransaction::~QXcbClipboardTransaction() +{ + if (m_abortTimerId) + killTimer(m_abortTimerId); + m_abortTimerId = 0; + m_clipboard->removeTransaction(m_window); +} + +bool QXcbClipboardTransaction::updateIncrementalProperty(const xcb_property_notify_event_t *event) +{ + if (event->atom != m_property || event->state != XCB_PROPERTY_DELETE) + return false; + + // restart the timer + if (m_abortTimerId) + killTimer(m_abortTimerId); + m_abortTimerId = startTimer(m_clipboard->clipboardTimeout()); + + uint bytes_left = uint(m_data.size()) - m_offset; + if (bytes_left > 0) { + int increment = m_clipboard->increment(); + uint bytes_to_send = qMin(uint(increment), bytes_left); + + qCDebug(lcQpaClipboard, "sending %d bytes, %d remaining, transaction: %p)", + bytes_to_send, bytes_left - bytes_to_send, this); + + uint32_t dataSize = bytes_to_send / (m_format / 8); + xcb_change_property(m_clipboard->xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + m_property, m_target, m_format, dataSize, m_data.constData() + m_offset); + m_offset += bytes_to_send; + } else { + qCDebug(lcQpaClipboard, "transaction %p completed", this); + + xcb_change_property(m_clipboard->xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + m_property, m_target, m_format, 0, nullptr); + + const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT }; + xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window, XCB_CW_EVENT_MASK, values); - if (!transactions) { -#ifdef INCR_DEBUG - qDebug("INCRTransaction: creating the TransactionMap"); -#endif - transactions = new TransactionMap; - conn->clipboard()->setProcessIncr(true); - } - transactions->insert(win, this); - abort_timer = startTimer(timeout); + delete this; // self destroy } + return true; +} - ~INCRTransaction() - { - if (abort_timer) - killTimer(abort_timer); - abort_timer = 0; - transactions->remove(win); - if (transactions->isEmpty()) { -#ifdef INCR_DEBUG - qDebug("INCRTransaction: no more INCR transactions left in the TransactionMap"); -#endif - delete transactions; - transactions = 0; - conn->clipboard()->setProcessIncr(false); - } + +void QXcbClipboardTransaction::timerEvent(QTimerEvent *ev) +{ + if (ev->timerId() == m_abortTimerId) { + // this can happen when the X client we are sending data + // to decides to exit (normally or abnormally) + qCDebug(lcQpaClipboard, "timed out while sending data to %p", this); + delete this; // self destroy } - - void updateIncrProperty(xcb_property_notify_event_t *event, bool &accepted) - { - xcb_connection_t *c = conn->xcb_connection(); - if (event->atom == property && event->state == XCB_PROPERTY_DELETE) { - accepted = true; - // restart the timer - if (abort_timer) - killTimer(abort_timer); - abort_timer = startTimer(timeout); - - unsigned int bytes_left = data.size() - offset; - if (bytes_left > 0) { - unsigned int bytes_to_send = qMin(increment, bytes_left); -#ifdef INCR_DEBUG - qDebug("INCRTransaction: sending %d bytes, %d remaining (INCR transaction %p)", - bytes_to_send, bytes_left - bytes_to_send, this); -#endif - int dataSize = bytes_to_send / (format / 8); - xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property, - target, format, dataSize, data.constData() + offset); - offset += bytes_to_send; - } else { -#ifdef INCR_DEBUG - qDebug("INCRTransaction: INCR transaction %p completed", this); -#endif - xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property, - target, format, 0, (const void *)0); - const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT }; - xcb_change_window_attributes(conn->xcb_connection(), win, - XCB_CW_EVENT_MASK, values); - // self destroy - delete this; - } - } - } - -protected: - void timerEvent(QTimerEvent *ev) override - { - if (ev->timerId() == abort_timer) { - // this can happen when the X client we are sending data - // to decides to exit (normally or abnormally) -#ifdef INCR_DEBUG - qDebug("INCRTransaction: Timed out while sending data to %p", this); -#endif - delete this; - } - } - -private: - QXcbConnection *conn; - xcb_window_t win; - xcb_atom_t property; - QByteArray data; - uint increment; - xcb_atom_t target; - int format; - int timeout; - uint offset; - int abort_timer; -}; -} // unnamed namespace +} const int QXcbClipboard::clipboard_timeout = 5000; @@ -282,6 +239,9 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c) xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask); xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask); } + + // change property protocol request is 24 bytes + m_increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; } QXcbClipboard::~QXcbClipboard() @@ -313,16 +273,17 @@ QXcbClipboard::~QXcbClipboard() delete m_clientClipboard[QClipboard::Selection]; } -void QXcbClipboard::incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted) +bool QXcbClipboard::handlePropertyNotify(const xcb_generic_event_t *event) { - uint response_type = ge->response_type & ~0x80; - if (response_type == XCB_PROPERTY_NOTIFY) { - xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge; - TransactionMap::Iterator it = transactions->find(event->window); - if (it != transactions->end()) { - (*it)->updateIncrProperty(event, accepted); - } - } + if (m_transactions.isEmpty() || event->response_type != XCB_PROPERTY_NOTIFY) + return false; + + auto propertyNotify = reinterpret_cast(event); + TransactionMap::Iterator it = m_transactions.find(propertyNotify->window); + if (it == m_transactions.constEnd()) + return false; + + return (*it)->updateIncrementalProperty(propertyNotify); } xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const @@ -522,19 +483,18 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win // This 'bool' can be removed once there is a proper fix for QTBUG-32853 if (m_clipboard_closing) allow_incr = false; - // X_ChangeProperty protocol request is 24 bytes - const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; - if (data.size() > increment && allow_incr) { + + if (data.size() > m_increment && allow_incr) { long bytes = data.size(); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes); - new INCRTransaction(connection(), window, property, data, increment, - atomFormat, dataFormat, clipboard_timeout); + auto transaction = new QXcbClipboardTransaction(this, window, property, data, atomFormat, dataFormat); + m_transactions.insert(window, transaction); return property; } // make sure we can perform the XChangeProperty in a single request - if (data.size() > increment) + if (data.size() > m_increment) return XCB_NONE; // ### perhaps use several XChangeProperty calls w/ PropModeAppend? int dataSize = data.size() / (dataFormat / 8); // use a single request to transfer data diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h index abab42a6134..26d3b3b395a 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.h +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -45,14 +45,41 @@ #include #include +#include + QT_BEGIN_NAMESPACE #ifndef QT_NO_CLIPBOARD class QXcbConnection; class QXcbScreen; +class QXcbClipboard; class QXcbClipboardMime; +class QXcbClipboardTransaction : public QObject +{ + Q_OBJECT +public: + QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb_window_t w, xcb_atom_t p, + QByteArray d, xcb_atom_t t, int f); + ~QXcbClipboardTransaction(); + + bool updateIncrementalProperty(const xcb_property_notify_event_t *event); + +protected: + void timerEvent(QTimerEvent *ev) override; + +private: + QXcbClipboard *m_clipboard; + xcb_window_t m_window; + xcb_atom_t m_property; + QByteArray m_data; + xcb_atom_t m_target; + uint8_t m_format; + uint m_offset = 0; + int m_abortTimerId = 0; +}; + class QXcbClipboard : public QXcbObject, public QPlatformClipboard { public: @@ -81,13 +108,16 @@ public: QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom); - void setProcessIncr(bool process) { m_incr_active = process; } - bool processIncr() { return m_incr_active; } - void incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted); + bool handlePropertyNotify(const xcb_generic_event_t *event); xcb_window_t getSelectionOwner(xcb_atom_t atom) const; QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0); + int increment() const { return m_increment; } + int clipboardTimeout() const { return clipboard_timeout; } + + void removeTransaction(xcb_window_t window) { m_transactions.remove(window); } + private: xcb_generic_event_t *waitForClipboardEvent(xcb_window_t window, int type, bool checkManager = false); @@ -107,9 +137,12 @@ private: static const int clipboard_timeout; - bool m_incr_active = false; + int m_increment = 0; bool m_clipboard_closing = false; xcb_timestamp_t m_incr_receive_time = 0; + + using TransactionMap = QMap; + TransactionMap m_transactions; }; #endif // QT_NO_CLIPBOARD diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 45f096a13aa..37ee980924f 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -84,6 +84,7 @@ Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") Q_LOGGING_CATEGORY(lcQpaEventReader, "qt.qpa.events.reader") Q_LOGGING_CATEGORY(lcQpaPeeker, "qt.qpa.peeker") Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard") +Q_LOGGING_CATEGORY(lcQpaClipboard, "qt.qpa.clipboard") Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd") // this event type was added in libxcb 1.10, @@ -651,6 +652,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) break; case XCB_PROPERTY_NOTIFY: { +#ifndef QT_NO_CLIPBOARD + if (m_clipboard->handlePropertyNotify(event)) + break; +#endif auto propertyNotify = reinterpret_cast(event); if (propertyNotify->atom == atom(QXcbAtom::_NET_WORKAREA)) { QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window); @@ -1010,14 +1015,6 @@ void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags) if (compressEvent(event)) continue; -#ifndef QT_NO_CLIPBOARD - bool accepted = false; - if (clipboard()->processIncr()) - clipboard()->incrTransactionPeeker(event, accepted); - if (accepted) - continue; -#endif - auto isWaitingFor = [=](PeekFunc peekFunc) { // These callbacks return true if the event is what they were // waiting for, remove them from the list in that case. diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 5d53b97d376..47036ca257e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -68,6 +68,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen) Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents) Q_DECLARE_LOGGING_CATEGORY(lcQpaPeeker) Q_DECLARE_LOGGING_CATEGORY(lcQpaKeyboard) +Q_DECLARE_LOGGING_CATEGORY(lcQpaClipboard) Q_DECLARE_LOGGING_CATEGORY(lcQpaXDnd) Q_DECLARE_LOGGING_CATEGORY(lcQpaEventReader)