diff --git a/qt5/.md5sum b/qt5/.md5sum index 5e4010c09..deec53fae 100644 --- a/qt5/.md5sum +++ b/qt5/.md5sum @@ -1 +1,9 @@ 47763c168f58b1196271b231f03c8bae qt-everywhere-opensource-src-5.6.0.tar.xz +5e96b5cfa248b8b071919adb27abc715 qt5-alsa1.11.patch +28cddedf6c15751d08c1382bf1074fa7 qtbug-44964.patch +7f152c40947027acba56023e9d693260 qtbug-45812.patch +b09aa4f5763f013b06153fbdbc844404 qtbug-51648.patch +ef981ff6892337cdab424ebb113b3c39 qtbug-51649.patch +f59a1ea0f10a055ba930a53832933482 qtbug-51676.patch +462f079cd46f869def6858903a718bf5 qtbug-53071.patch +da4fd787ea877516397a027412e975e1 qtbug-53071b.patch diff --git a/qt5/Pkgfile b/qt5/Pkgfile index e26603edf..63f554cae 100644 --- a/qt5/Pkgfile +++ b/qt5/Pkgfile @@ -6,12 +6,35 @@ name=qt5 version=5.6.0 -release=1 -source=(http://download.qt.io/official_releases/qt/${version%.*}/$version/single/qt-everywhere-opensource-src-$version.tar.xz) +release=2 +source=(http://download.qt.io/official_releases/qt/${version%.*}/$version/single/qt-everywhere-opensource-src-$version.tar.xz + qt5-alsa1.11.patch + qtbug-51648.patch + qtbug-51649.patch + qtbug-51676.patch + qtbug-45812.patch + qtbug-44964.patch + qtbug-53071.patch + qtbug-53071b.patch) build() { cd qt-everywhere-opensource-src-$version + # Backport fixes for QtDBus deadlocks + patch -p1 -d qtbase -i $SRC/qtbug-51648.patch + patch -p1 -d qtbase -i $SRC/qtbug-51649.patch + patch -p1 -d qtbase -i $SRC/qtbug-51676.patch + + # Fix drag and drop from some applications + patch -p1 -d qtbase -i $SRC/qtbug-45812.patch + + # Fix parsing of tzfile(5) POSIX rule zone names with bracket quotes + patch -p1 -d qtbase -i $SRC/qtbug-53071.patch + patch -p1 -d qtbase -i $SRC/qtbug-53071b.patch + + # Don't compress tablet motion events + patch -p1 -d qtbase -i $SRC/qtbug-44964.patch + # Respect system CXX [ "$CXX" ] || CXX=g++ sed -i "/^QMAKE_CXX\s/s|=.*|= $CXX|" qtbase/mkspecs/common/g++-base.conf diff --git a/qt5/qt5-alsa1.11.patch b/qt5/qt5-alsa1.11.patch new file mode 100644 index 000000000..e713282d2 --- /dev/null +++ b/qt5/qt5-alsa1.11.patch @@ -0,0 +1,11 @@ +--- qtbase-opensource-src-5.6.0-rc/config.tests/unix/alsa/alsatest.cpp.0 2016-02-29 08:15:48.203031809 +0000 ++++ qtbase-opensource-src-5.6.0-rc/config.tests/unix/alsa/alsatest.cpp 2016-02-29 08:16:39.712811962 +0000 +@@ -32,7 +32,7 @@ + ****************************************************************************/ + + #include +-#if(!(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 10)) ++#if(!(SND_LIB_MAJOR == 1 && (SND_LIB_MINOR > 0 || SND_LIB_SUBMINOR >= 10))) + #error "Alsa version found too old, require >= 1.0.10" + #endif + diff --git a/qt5/qtbug-44964.patch b/qt5/qtbug-44964.patch new file mode 100644 index 000000000..1890adbeb --- /dev/null +++ b/qt5/qtbug-44964.patch @@ -0,0 +1,100 @@ +From 60cd1c67759642018ef93cc45a90714729100d9d Mon Sep 17 00:00:00 2001 +From: Shawn Rutledge +Date: Thu, 28 Apr 2016 11:30:30 +0200 +Subject: [PATCH] xcb: don't compress tablet motion events + +7edd10e6c added this compression feature, but it's not a good idea for +drawing-tablet applications, because smooth drawing depends on receiving +every movement of the stylus. + +Also show the device ID in qt.qpa.input.devices category logging. + +[ChangeLog][X11] The new X event compression feature that was added in +5.6.0 no longer applies to motion events from drawing tablets. + +Task-number: QTBUG-44964 +Change-Id: Icd2ca8ca77d8f80c2f39160c74208db10e382501 +Reviewed-by: Gatis Paeglis +--- + src/plugins/platforms/xcb/qxcbconnection.cpp | 7 ++++++- + src/plugins/platforms/xcb/qxcbconnection.h | 1 + + src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 21 ++++++++++++++------- + 3 files changed, 21 insertions(+), 8 deletions(-) + +diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp +index edfaf2b..669ef3a 100644 +--- a/src/plugins/platforms/xcb/qxcbconnection.cpp ++++ b/src/plugins/platforms/xcb/qxcbconnection.cpp +@@ -1626,8 +1626,13 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, + if (!m_xi2Enabled) + return false; + +- // compress XI_Motion ++ // compress XI_Motion, but not from tablet devices + if (isXIType(event, m_xiOpCode, XI_Motion)) { ++#ifndef QT_NO_TABLETEVENT ++ xXIDeviceEvent *xdev = reinterpret_cast(event); ++ if (const_cast(this)->tabletDataForDevice(xdev->sourceid)) ++ return false; ++#endif // QT_NO_TABLETEVENT + for (int j = nextIndex; j < eventqueue->size(); ++j) { + xcb_generic_event_t *next = eventqueue->at(j); + if (!isValid(next)) +diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h +index 7ba9588..501da1c 100644 +--- a/src/plugins/platforms/xcb/qxcbconnection.h ++++ b/src/plugins/platforms/xcb/qxcbconnection.h +@@ -578,6 +578,7 @@ private slots: + bool xi2HandleTabletEvent(void *event, TabletData *tabletData, QXcbWindowEventListener *eventListener); + void xi2ReportTabletEvent(TabletData &tabletData, void *event); + QVector m_tabletData; ++ TabletData *tabletDataForDevice(int id); + #endif // !QT_NO_TABLETEVENT + struct ScrollingDevice { + ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { } +diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +index 9911afb..025dde3 100644 +--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp ++++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +@@ -113,7 +113,7 @@ void QXcbConnection::xi2SetupDevices() + // Only non-master pointing devices are relevant here. + if (devices[i].use != XISlavePointer) + continue; +- qCDebug(lcQpaXInputDevices) << "input device "<< devices[i].name; ++ qCDebug(lcQpaXInputDevices) << "input device " << devices[i].name << "ID" << devices[i].deviceid; + #ifndef QT_NO_TABLETEVENT + TabletData tabletData; + #endif +@@ -507,12 +507,9 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) + } + + #ifndef QT_NO_TABLETEVENT +- for (int i = 0; i < m_tabletData.count(); ++i) { +- if (m_tabletData.at(i).deviceId == sourceDeviceId) { +- if (xi2HandleTabletEvent(xiEvent, &m_tabletData[i], eventListener)) +- return; +- } +- } ++ QXcbConnection::TabletData *tablet = tabletDataForDevice(sourceDeviceId); ++ if (tablet && xi2HandleTabletEvent(xiEvent, tablet, eventListener)) ++ return; + #endif // QT_NO_TABLETEVENT + + #ifdef XCB_USE_XINPUT21 +@@ -1198,6 +1195,16 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event) + xTilt, yTilt, tangentialPressure, + rotation, 0, tabletData.serialId); + } ++ ++QXcbConnection::TabletData *QXcbConnection::tabletDataForDevice(int id) ++{ ++ for (int i = 0; i < m_tabletData.count(); ++i) { ++ if (m_tabletData.at(i).deviceId == id) ++ return &m_tabletData[i]; ++ } ++ return Q_NULLPTR; ++} ++ + #endif // QT_NO_TABLETEVENT + + #endif // XCB_USE_XINPUT2 diff --git a/qt5/qtbug-45812.patch b/qt5/qtbug-45812.patch new file mode 100644 index 000000000..15243871d --- /dev/null +++ b/qt5/qtbug-45812.patch @@ -0,0 +1,98 @@ +From 269fdbdd2bedda5f5eacb751224d3a3fc3eed5bc Mon Sep 17 00:00:00 2001 +From: Urs Fleisch +Date: Fri, 26 Feb 2016 17:46:09 +0100 +Subject: [PATCH] xcb: Fix drag and drop to applications like Emacs and + Chromium. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Drops without matching time stamp do not work. I have fixed the issue by +reanimating the findXdndAwareParent() function (adapted to XCB) and +using it to find a matching transaction if all else fails. + +Task-number: QTBUG-45812 +Change-Id: Ibca15bbab02ccf2f25280418e9edf36972ebf9a0 +Reviewed-by: Błażej Szczygieł +Reviewed-by: Dmitry Shachnev +Reviewed-by: Shawn Rutledge +--- + src/plugins/platforms/xcb/qxcbdrag.cpp | 55 +++++++++++++++++++++++++++------- + 1 file changed, 44 insertions(+), 11 deletions(-) + +diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp +index f5cc873..f1428d0 100644 +--- a/src/plugins/platforms/xcb/qxcbdrag.cpp ++++ b/src/plugins/platforms/xcb/qxcbdrag.cpp +@@ -1072,6 +1072,40 @@ void QXcbDrag::cancel() + send_leave(); + } + ++// find an ancestor with XdndAware on it ++static xcb_window_t findXdndAwareParent(QXcbConnection *c, xcb_window_t window) ++{ ++ xcb_window_t target = 0; ++ forever { ++ // check if window has XdndAware ++ xcb_get_property_cookie_t gpCookie = Q_XCB_CALL( ++ xcb_get_property(c->xcb_connection(), false, window, ++ c->atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0)); ++ xcb_get_property_reply_t *gpReply = xcb_get_property_reply( ++ c->xcb_connection(), gpCookie, 0); ++ bool aware = gpReply && gpReply->type != XCB_NONE; ++ free(gpReply); ++ if (aware) { ++ target = window; ++ break; ++ } ++ ++ // try window's parent ++ xcb_query_tree_cookie_t qtCookie = Q_XCB_CALL( ++ xcb_query_tree_unchecked(c->xcb_connection(), window)); ++ xcb_query_tree_reply_t *qtReply = xcb_query_tree_reply( ++ c->xcb_connection(), qtCookie, NULL); ++ if (!qtReply) ++ break; ++ xcb_window_t root = qtReply->root; ++ xcb_window_t parent = qtReply->parent; ++ free(qtReply); ++ if (window == root) ++ break; ++ window = parent; ++ } ++ return target; ++} + + void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event) + { +@@ -1099,17 +1133,16 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event + // xcb_convert_selection() that we sent the XdndDrop event to. + at = findTransactionByWindow(event->requestor); + } +-// if (at == -1 && event->time == XCB_CURRENT_TIME) { +-// // previous Qt versions always requested the data on a child of the target window +-// // using CurrentTime... but it could be asking for either drop data or the current drag's data +-// Window target = findXdndAwareParent(event->requestor); +-// if (target) { +-// if (current_target && current_target == target) +-// at = -2; +-// else +-// at = findXdndDropTransactionByWindow(target); +-// } +-// } ++ ++ if (at == -1 && event->time == XCB_CURRENT_TIME) { ++ xcb_window_t target = findXdndAwareParent(connection(), event->requestor); ++ if (target) { ++ if (current_target == target) ++ at = -2; ++ else ++ at = findTransactionByWindow(target); ++ } ++ } + } + + QDrag *transactionDrag = 0; +-- +2.7.1 + diff --git a/qt5/qtbug-51648.patch b/qt5/qtbug-51648.patch new file mode 100644 index 000000000..279839b04 --- /dev/null +++ b/qt5/qtbug-51648.patch @@ -0,0 +1,88 @@ +From b024fbe83863fc57364a52c717d5b43d654bdb5d Mon Sep 17 00:00:00 2001 +From: Weng Xuetian +Date: Sat, 5 Mar 2016 12:23:21 -0800 +Subject: [PATCH] QtDBus: clean up signal hooks and object tree in + closeConnection + +If a QObject is added or passed as receiver to QDBusConnection::connect() +and it is managed by Q_GLOBAL_STATIC or similar mechanism, it is +possible that when that its destructor is called after the dbus daemon +thread ends. In that case, QObject::destroyed connected via +Qt::BlockingQueuedConnection to QDBusConnectionPrivate will cause dead +lock since the thread is no longer processing events. + +Task-number: QTBUG-51648 +Change-Id: I1a1810a6d6d0234af0269d5f3fc1f54101bf1547 +--- + src/dbus/qdbusconnection_p.h | 1 + + src/dbus/qdbusintegrator.cpp | 28 +++++++++++++++++++++++++++- + 2 files changed, 28 insertions(+), 1 deletion(-) + +diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h +index c77daf7..565eb83 100644 +--- a/src/dbus/qdbusconnection_p.h ++++ b/src/dbus/qdbusconnection_p.h +@@ -254,6 +254,7 @@ private: + const QVector &metaTypes, int slotIdx); + + SignalHookHash::Iterator removeSignalHookNoLock(SignalHookHash::Iterator it); ++ void disconnectObjectTree(ObjectTreeNode &node); + + bool isServiceRegisteredByThread(const QString &serviceName); + +diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp +index cd44861..a3cd47b 100644 +--- a/src/dbus/qdbusintegrator.cpp ++++ b/src/dbus/qdbusintegrator.cpp +@@ -1030,7 +1030,6 @@ QDBusConnectionPrivate::~QDBusConnectionPrivate() + qPrintable(name)); + + closeConnection(); +- rootNode.children.clear(); // free resources + qDeleteAll(cachedMetaObjects); + + if (mode == ClientMode || mode == PeerMode) { +@@ -1052,6 +1051,20 @@ QDBusConnectionPrivate::~QDBusConnectionPrivate() + } + } + ++void QDBusConnectionPrivate::disconnectObjectTree(QDBusConnectionPrivate::ObjectTreeNode &haystack) ++{ ++ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin(); ++ ++ while (it != haystack.children.end()) { ++ disconnectObjectTree(*it); ++ it++; ++ } ++ ++ if (haystack.obj) { ++ haystack.obj->disconnect(this); ++ } ++} ++ + void QDBusConnectionPrivate::closeConnection() + { + QDBusWriteLocker locker(CloseConnectionAction, this); +@@ -1075,6 +1088,19 @@ void QDBusConnectionPrivate::closeConnection() + } + + qDeleteAll(pendingCalls); ++ ++ // clean up all signal hook and object tree, to avoid QObject::destroyed ++ // being activated to dbus daemon thread which already quits. ++ // dbus connection is already closed, so there is nothing we could do be clean ++ // up everything here. ++ SignalHookHash::iterator sit = signalHooks.begin(); ++ while (sit != signalHooks.end()) { ++ sit.value().obj->disconnect(this); ++ sit++; ++ } ++ ++ disconnectObjectTree(rootNode); ++ rootNode.children.clear(); // free resources + } + + void QDBusConnectionPrivate::checkThread() +-- +2.7.1 + diff --git a/qt5/qtbug-51649.patch b/qt5/qtbug-51649.patch new file mode 100644 index 000000000..3b7cf9ec6 --- /dev/null +++ b/qt5/qtbug-51649.patch @@ -0,0 +1,159 @@ +From acde2e69df5dedc624674107596f276125e22864 Mon Sep 17 00:00:00 2001 +From: Weng Xuetian +Date: Thu, 3 Mar 2016 21:56:53 -0800 +Subject: [PATCH] QtDBus: finish all pending call with error if disconnected + +libdbus will send a local signal if connection gets disconnected. When +this happens, end all pending calls with QDBusError::Disconnected. + +Task-number: QTBUG-51649 +Change-Id: I5c7d2a468bb5da746d0c0e53e458c1e376f186a9 +--- + src/dbus/dbus_minimal_p.h | 2 ++ + src/dbus/qdbusintegrator.cpp | 26 +++++++++++++++++----- + src/dbus/qdbusutil_p.h | 6 +++++ + .../dbus/qdbusconnection/tst_qdbusconnection.cpp | 22 ++++++++++++++++++ + .../dbus/qdbusconnection/tst_qdbusconnection.h | 1 + + 5 files changed, 51 insertions(+), 6 deletions(-) + +diff --git a/src/dbus/dbus_minimal_p.h b/src/dbus/dbus_minimal_p.h +index f0a2954..8f25b24 100644 +--- a/src/dbus/dbus_minimal_p.h ++++ b/src/dbus/dbus_minimal_p.h +@@ -99,9 +99,11 @@ typedef dbus_uint32_t dbus_bool_t; + /* dbus-shared.h */ + #define DBUS_SERVICE_DBUS "org.freedesktop.DBus" + #define DBUS_PATH_DBUS "/org/freedesktop/DBus" ++#define DBUS_PATH_LOCAL "/org/freedesktop/DBus/Local" + #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" + #define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable" + #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" ++#define DBUS_INTERFACE_LOCAL "org.freedesktop.DBus.Local" + + #define DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1 /**< Allow another service to become the primary owner if requested */ + #define DBUS_NAME_FLAG_REPLACE_EXISTING 0x2 /**< Request to replace the current primary owner */ +diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp +index cd44861..320419f 100644 +--- a/src/dbus/qdbusintegrator.cpp ++++ b/src/dbus/qdbusintegrator.cpp +@@ -519,6 +519,14 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg) + switch (amsg.type()) { + case QDBusMessage::SignalMessage: + handleSignal(amsg); ++ // Check local disconnected signal from libdbus ++ if (amsg.interface() == QDBusUtil::dbusInterfaceLocal() ++ && amsg.path() == QDBusUtil::dbusPathLocal() ++ && amsg.member() == QDBusUtil::disconnected() ++ && !QDBusMessagePrivate::isLocal(amsg)) { ++ while (!pendingCalls.isEmpty()) ++ processFinishedCall(pendingCalls.first()); ++ } + // if there are any other filters in this DBusConnection, + // let them see the signal too + return false; +@@ -1767,10 +1775,16 @@ void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call) + + QDBusMessage &msg = call->replyMessage; + if (call->pending) { +- // decode the message +- DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending); +- msg = QDBusMessagePrivate::fromDBusMessage(reply, connection->capabilities); +- q_dbus_message_unref(reply); ++ // when processFinishedCall is called and pending call is not completed, ++ // it means we received disconnected signal from libdbus ++ if (q_dbus_pending_call_get_completed(call->pending)) { ++ // decode the message ++ DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending); ++ msg = QDBusMessagePrivate::fromDBusMessage(reply, connection->capabilities); ++ q_dbus_message_unref(reply); ++ } else { ++ msg = QDBusMessage::createError(QDBusError::Disconnected, QDBusUtil::disconnectedErrorMessage()); ++ } + } + qDBusDebug() << connection << "got message reply:" << msg; + +@@ -2070,8 +2084,8 @@ void QDBusConnectionPrivate::sendInternal(QDBusPendingCallPrivate *pcall, void * + pcall->pending = pending; + q_dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0); + +- // DBus won't notify us when a peer disconnects so we need to track these ourselves +- if (mode == QDBusConnectionPrivate::PeerMode) ++ // DBus won't notify us when a peer disconnects or server terminates so we need to track these ourselves ++ if (mode == QDBusConnectionPrivate::PeerMode || mode == QDBusConnectionPrivate::ClientMode) + pendingCalls.append(pcall); + + return; +diff --git a/src/dbus/qdbusutil_p.h b/src/dbus/qdbusutil_p.h +index 8f5ae92..ca70ff9 100644 +--- a/src/dbus/qdbusutil_p.h ++++ b/src/dbus/qdbusutil_p.h +@@ -155,6 +155,8 @@ namespace QDBusUtil + { return QStringLiteral(DBUS_SERVICE_DBUS); } + inline QString dbusPath() + { return QStringLiteral(DBUS_PATH_DBUS); } ++ inline QString dbusPathLocal() ++ { return QStringLiteral(DBUS_PATH_LOCAL); } + inline QString dbusInterface() + { + // it's the same string, but just be sure +@@ -165,8 +167,12 @@ namespace QDBusUtil + { return QStringLiteral(DBUS_INTERFACE_PROPERTIES); } + inline QString dbusInterfaceIntrospectable() + { return QStringLiteral(DBUS_INTERFACE_INTROSPECTABLE); } ++ inline QString dbusInterfaceLocal() ++ { return QStringLiteral(DBUS_INTERFACE_LOCAL); } + inline QString nameOwnerChanged() + { return QStringLiteral("NameOwnerChanged"); } ++ inline QString disconnected() ++ { return QStringLiteral("Disconnected"); } + inline QString disconnectedErrorMessage() + { return QStringLiteral("Not connected to D-Bus server"); } + } +diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp +index e91f87d..6c7e6b1 100644 +--- a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp ++++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp +@@ -1218,6 +1218,28 @@ void tst_QDBusConnection::callVirtualObjectLocal() + QCOMPARE(obj.replyArguments, subPathReply.arguments()); + } + ++void tst_QDBusConnection::pendingCallWhenDisconnected() ++{ ++ QDBusServer *server = new QDBusServer; ++ QDBusConnection con = QDBusConnection::connectToPeer(server->address(), "disconnect"); ++ QTestEventLoop::instance().enterLoop(2); ++ QVERIFY(!QTestEventLoop::instance().timeout()); ++ QVERIFY(con.isConnected()); ++ ++ delete server; ++ ++ // Make sure we call the method before we know it is disconnected. ++ QVERIFY(con.isConnected()); ++ QDBusMessage message = QDBusMessage::createMethodCall("", "/", QString(), "method"); ++ QDBusPendingCall reply = con.asyncCall(message); ++ ++ QTestEventLoop::instance().enterLoop(2); ++ QVERIFY(!con.isConnected()); ++ QVERIFY(reply.isFinished()); ++ QVERIFY(reply.isError()); ++ QVERIFY(reply.error().type() == QDBusError::Disconnected); ++} ++ + QString MyObject::path; + QString MyObjectWithoutInterface::path; + QString MyObjectWithoutInterface::interface; +diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h +index a53ba32..720e484 100644 +--- a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h ++++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h +@@ -121,6 +121,7 @@ private slots: + void registerVirtualObject(); + void callVirtualObject(); + void callVirtualObjectLocal(); ++ void pendingCallWhenDisconnected(); + + public: + QString serviceName() const { return "org.qtproject.Qt.Autotests.QDBusConnection"; } +-- +2.7.1 + diff --git a/qt5/qtbug-51676.patch b/qt5/qtbug-51676.patch new file mode 100644 index 000000000..8672a2136 --- /dev/null +++ b/qt5/qtbug-51676.patch @@ -0,0 +1,126 @@ +From 11c5e716b08b6b3c5a7c9fce96b0cde8624ec869 Mon Sep 17 00:00:00 2001 +From: Thiago Macieira +Date: Tue, 15 Mar 2016 11:00:20 -0700 +Subject: [PATCH] Fix QtDBus deadlock inside kded/kiod + +Whenever a message spy was installed, we failed to actually process +looped-back messages by queueing them for processing by the spy. That +had as a consequence that the caller got an error reply. Worse, since +the message had been queued, QtDBus would attempt to deliver it later. +Since that message had isLocal==true, bad things happened inside the +manager thread. + +The correct solution is not to queue the message for the filter. If the +message is local, then simply deliver directly, as we're still in the +user's thread. This used to be the behavior in Qt 5.5. + +Task-number: QTBUG-51676 +Change-Id: I1dc112894cde7121e8ce302ae51b438ade1ff612 +--- + src/dbus/qdbusintegrator.cpp | 42 ++++++++++++++++++++++++++++++++---------- + src/dbus/qdbusintegrator_p.h | 1 + + 2 files changed, 33 insertions(+), 10 deletions(-) + +diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp +index cd44861..478a2c4 100644 +--- a/src/dbus/qdbusintegrator.cpp ++++ b/src/dbus/qdbusintegrator.cpp +@@ -481,6 +481,11 @@ QDBusSpyCallEvent::~QDBusSpyCallEvent() + + void QDBusSpyCallEvent::placeMetaCall(QObject *) + { ++ invokeSpyHooks(msg, hooks, hookCount); ++} ++ ++inline void QDBusSpyCallEvent::invokeSpyHooks(const QDBusMessage &msg, const Hook *hooks, int hookCount) ++{ + // call the spy hook list + for (int i = 0; i < hookCount; ++i) + hooks[i](msg); +@@ -509,7 +514,12 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg) + { + if (!ref.load()) + return false; +- if (!dispatchEnabled && !QDBusMessagePrivate::isLocal(amsg)) { ++ ++ // local message are always delivered, regardless of filtering ++ // or whether the dispatcher is enabled ++ bool isLocal = QDBusMessagePrivate::isLocal(amsg); ++ ++ if (!dispatchEnabled && !isLocal) { + // queue messages only, we'll handle them later + qDBusDebug() << this << "delivery is suspended"; + pendingMessages << amsg; +@@ -523,13 +533,23 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg) + // let them see the signal too + return false; + case QDBusMessage::MethodCallMessage: +- // run it through the spy filters (if any) before the regular processing ++ // run it through the spy filters (if any) before the regular processing: ++ // a) if it's a local message, we're in the caller's thread, so invoke the filter directly ++ // b) if it's an external message, post to the main thread + if (Q_UNLIKELY(qDBusSpyHookList.exists()) && qApp) { + const QDBusSpyHookList &list = *qDBusSpyHookList; +- qDBusDebug() << this << "invoking message spies"; +- QCoreApplication::postEvent(qApp, new QDBusSpyCallEvent(this, QDBusConnection(this), +- amsg, list.constData(), list.size())); +- return true; ++ if (isLocal) { ++ Q_ASSERT(QThread::currentThread() != thread()); ++ qDBusDebug() << this << "invoking message spies directly"; ++ QDBusSpyCallEvent::invokeSpyHooks(amsg, list.constData(), list.size()); ++ } else { ++ qDBusDebug() << this << "invoking message spies via event"; ++ QCoreApplication::postEvent(qApp, new QDBusSpyCallEvent(this, QDBusConnection(this), ++ amsg, list.constData(), list.size())); ++ ++ // we'll be called back, so return ++ return true; ++ } + } + + handleObjectCall(amsg); +@@ -1451,9 +1471,9 @@ void QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg) + // that means the dispatchLock mutex is locked + // must not call out to user code in that case + // +- // however, if the message is internal, handleMessage was called +- // directly and no lock is in place. We can therefore call out to +- // user code, if necessary ++ // however, if the message is internal, handleMessage was called directly ++ // (user's thread) and no lock is in place. We can therefore call out to ++ // user code, if necessary. + ObjectTreeNode result; + int usedLength; + QThread *objThread = 0; +@@ -1492,12 +1512,14 @@ void QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg) + usedLength, msg)); + return; + } else if (objThread != QThread::currentThread()) { +- // synchronize with other thread ++ // looped-back message, targeting another thread: ++ // synchronize with it + postEventToThread(HandleObjectCallPostEventAction, result.obj, + new QDBusActivateObjectEvent(QDBusConnection(this), this, result, + usedLength, msg, &sem)); + semWait = true; + } else { ++ // looped-back message, targeting current thread + semWait = false; + } + } // release the lock +diff --git a/src/dbus/qdbusintegrator_p.h b/src/dbus/qdbusintegrator_p.h +index 2bbebdf..c0d9c22 100644 +--- a/src/dbus/qdbusintegrator_p.h ++++ b/src/dbus/qdbusintegrator_p.h +@@ -145,6 +145,7 @@ public: + {} + ~QDBusSpyCallEvent(); + void placeMetaCall(QObject *) Q_DECL_OVERRIDE; ++ static inline void invokeSpyHooks(const QDBusMessage &msg, const Hook *hooks, int hookCount); + + QDBusConnection conn; // keeps the refcount in QDBusConnectionPrivate up + QDBusMessage msg; +-- +2.7.1 + diff --git a/qt5/qtbug-53071.patch b/qt5/qtbug-53071.patch new file mode 100644 index 000000000..a348cda20 --- /dev/null +++ b/qt5/qtbug-53071.patch @@ -0,0 +1,272 @@ +From e9041c7fc1052167f1ec2df0ea9623059e55d00f Mon Sep 17 00:00:00 2001 +From: Thiago Macieira +Date: Thu, 28 Apr 2016 22:09:01 -0700 +Subject: [PATCH] Fix parsing of tzfile(5) POSIX rule zone names with bracket + quotes + +POSIX.1-2001 allows quoting a zone name so that it can contain other +characters besides letters, by enclosing it in angle brackets ('<' and +'>'). This hadn't been used until recently (tzdata2016b), when the +Asia/Barnaul rule started using a zone name "+07" (the name variable +contained the value "<+07>-7"). + +Thanks to Paul Eggert for reporting and investigating the root cause. + +Task-number: QTBUG-53071 +Change-Id: Id5480807d25e49e78b79ffff1449bc410776cb66 +Reviewed-by: Edward Welbourne +Reviewed-by: Lars Knoll +--- + src/corelib/tools/qtimezoneprivate_tz.cpp | 176 ++++++++++++++------- + .../auto/corelib/tools/qtimezone/tst_qtimezone.cpp | 10 ++ + 2 files changed, 130 insertions(+), 56 deletions(-) + +diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp +index 85ed345..cb9581a 100644 +--- a/src/corelib/tools/qtimezoneprivate_tz.cpp ++++ b/src/corelib/tools/qtimezoneprivate_tz.cpp +@@ -41,6 +41,8 @@ + + #include + ++#include "qlocale_tools_p.h" ++ + #include + + QT_BEGIN_NAMESPACE +@@ -384,25 +386,100 @@ static QTime parsePosixTime(const QByteArray &timeRule) + return QTime(2, 0, 0); + } + +-static int parsePosixOffset(const QByteArray &timeRule) ++static int parsePosixOffset(const char *begin, const char *end) + { + // Format "[+|-]hh[:mm[:ss]]" +- QList parts = timeRule.split(':'); +- int count = parts.count(); +- if (count == 3) { +- int hour = parts.at(0).toInt(); +- int sign = hour >= 0 ? -1 : 1; +- return sign * ((qAbs(hour) * 60 * 60) + (parts.at(1).toInt() * 60) + parts.at(2).toInt()); +- } else if (count == 2) { +- int hour = parts.at(0).toInt(); +- int sign = hour >= 0 ? -1 : 1; +- return sign * ((qAbs(hour) * 60 * 60) + (parts.at(1).toInt() * 60)); +- } else if (count == 1) { +- int hour = parts.at(0).toInt(); +- int sign = hour >= 0 ? -1 : 1; +- return sign * (qAbs(hour) * 60 * 60); +- } +- return 0; ++ int hour, min = 0, sec = 0; ++ ++ // note that the sign is inverted because POSIX counts in hours West of GMT ++ bool negate = true; ++ if (*begin == '+') { ++ ++begin; ++ } else if (*begin == '-') { ++ negate = false; ++ ++begin; ++ } ++ ++ bool ok = false; ++ hour = qstrtoll(begin, &begin, 10, &ok); ++ if (!ok) ++ return INT_MIN; ++ if (begin < end && *begin == ':') { ++ // minutes ++ ++begin; ++ min = qstrtoll(begin, &begin, 10, &ok); ++ if (!ok || min < 0) ++ return INT_MIN; ++ ++ if (begin < end && *begin == ':') { ++ // seconds ++ ++begin; ++ sec = qstrtoll(begin, &begin, 10, &ok); ++ if (!ok || sec < 0) ++ return INT_MIN; ++ } ++ } ++ ++ // we must have consumed everything ++ if (begin != end) ++ return INT_MIN; ++ ++ int value = (hour * 60 + min) * 60 + sec; ++ return negate ? -value : value; ++} ++ ++static inline bool asciiIsLetter(char ch) ++{ ++ ch |= 0x20; // lowercases if it is a letter, otherwise just corrupts ch ++ return ch >= 'a' && ch <= 'z'; ++} ++ ++// 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) ++{ ++ static const char offsetChars[] = "0123456789:"; ++ QPair result = qMakePair(QString(), INT_MIN); ++ ++ const char *nameBegin = pos; ++ const char *nameEnd; ++ Q_ASSERT(pos < end); ++ ++ if (*pos == '<') { ++ nameBegin = pos + 1; // skip the '<' ++ nameEnd = nameBegin; ++ while (nameEnd < end && *nameEnd != '>') { ++ // POSIX says only alphanumeric, but we allow anything ++ ++nameEnd; ++ } ++ pos = nameEnd + 1; // skip the '>' ++ } else { ++ nameBegin = pos; ++ nameEnd = nameBegin; ++ while (nameEnd < end && asciiIsLetter(*nameEnd)) ++ ++nameEnd; ++ pos = nameEnd; ++ } ++ if (nameEnd - nameBegin < 3) ++ return result; // name must be at least 3 characters long ++ ++ // zone offset, form [+-]hh:mm:ss ++ const char *zoneBegin = pos; ++ const char *zoneEnd = pos; ++ if (zoneEnd < end && (zoneEnd[0] == '+' || zoneEnd[0] == '-')) ++ ++zoneEnd; ++ while (zoneEnd < end) { ++ if (strchr(offsetChars, char(*zoneEnd)) == NULL) ++ break; ++ ++zoneEnd; ++ } ++ ++ result.first = QString::fromUtf8(nameBegin, nameEnd - nameBegin); ++ if (zoneEnd > zoneBegin) ++ result.second = parsePosixOffset(zoneBegin, zoneEnd); ++ pos = zoneEnd; ++ return result; + } + + static QVector calculatePosixTransitions(const QByteArray &posixRule, +@@ -419,51 +496,38 @@ static QVector calculatePosixTransitions(const QByteArra + + // POSIX Format is like "TZ=CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00" + // i.e. "std offset dst [offset],start[/time],end[/time]" +- // See http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html ++ // See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html + QList parts = posixRule.split(','); + +- QString name = QString::fromUtf8(parts.at(0)); +- QString stdName; +- QString stdOffsetString; +- QString dstName; +- QString dstOffsetString; +- bool parsedStdName = false; +- bool parsedStdOffset = false; +- for (int i = 0; i < name.size(); ++i) { +- if (name.at(i).isLetter()) { +- if (parsedStdName) { +- parsedStdOffset = true; +- dstName.append(name.at(i)); +- } else { +- stdName.append(name.at(i)); ++ QPair 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 ++ } else if (begin < zoneinfo.constEnd()) { ++ dstZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd()); ++ if (dstZone.second == INT_MIN) { ++ // if the dst offset isn't provided, it is 1 hour ahead of the standard offset ++ dstZone.second = stdZone.second + (60 * 60); + } +- } else { +- parsedStdName = true; +- if (parsedStdOffset) +- dstOffsetString.append(name.at(i)); +- else +- stdOffsetString.append(name.at(i)); + } + } + +- int utcOffset = parsePosixOffset(stdOffsetString.toUtf8()); +- + // If only the name part then no transitions + if (parts.count() == 1) { + QTimeZonePrivate::Data data; + data.atMSecsSinceEpoch = lastTranMSecs; +- data.offsetFromUtc = utcOffset; +- data.standardTimeOffset = utcOffset; ++ data.offsetFromUtc = stdZone.second; ++ data.standardTimeOffset = stdZone.second; + data.daylightTimeOffset = 0; +- data.abbreviation = stdName; ++ data.abbreviation = stdZone.first; + result << data; + return result; + } + +- // If not populated the total dst offset is 1 hour +- int dstOffset = utcOffset + (60 * 60); +- if (!dstOffsetString.isEmpty()) +- dstOffset = parsePosixOffset(dstOffsetString.toUtf8()); + + // Get the std to dst transtion details + QList dstParts = parts.at(1).split('/'); +@@ -486,18 +550,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() - (utcOffset * 1000); +- dstData.offsetFromUtc = dstOffset; +- dstData.standardTimeOffset = utcOffset; +- dstData.daylightTimeOffset = dstOffset - utcOffset; +- dstData.abbreviation = dstName; ++ 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; + QTimeZonePrivate::Data stdData; + QDateTime std(calculatePosixDate(stdDateRule, year), stdTime, Qt::UTC); +- stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstOffset * 1000); +- stdData.offsetFromUtc = utcOffset; +- stdData.standardTimeOffset = utcOffset; ++ stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.second * 1000); ++ stdData.offsetFromUtc = stdZone.second; ++ stdData.standardTimeOffset = stdZone.second; + stdData.daylightTimeOffset = 0; +- stdData.abbreviation = stdName; ++ stdData.abbreviation = stdZone.first; + // Part of the high year will overflow + if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) { + if (dstData.atMSecsSinceEpoch > 0) { +diff --git a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp +index ea83510..ce72e7c 100644 +--- a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp ++++ b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp +@@ -847,6 +847,16 @@ void tst_QTimeZone::tzTest() + QTzTimeZonePrivate::Data datatz2 = tztz2.data(std); + QTzTimeZonePrivate::Data datautc2 = tzutc2.data(std); + QCOMPARE(datatz2.offsetFromUtc, datautc2.offsetFromUtc); ++ ++ // Test a timezone with a name that isn't all letters ++ QTzTimeZonePrivate tzBarnaul("Asia/Barnaul"); ++ if (tzBarnaul.isValid()) { ++ QCOMPARE(tzBarnaul.data(std).abbreviation, QString("+07")); ++ ++ // first full day of the new rule (tzdata2016b) ++ QDateTime dt(QDate(2016, 3, 28), QTime(0, 0, 0), Qt::UTC); ++ QCOMPARE(tzBarnaul.data(dt.toMSecsSinceEpoch()).abbreviation, QString("+07")); ++ } + #endif // Q_OS_UNIX + } + diff --git a/qt5/qtbug-53071b.patch b/qt5/qtbug-53071b.patch new file mode 100644 index 000000000..c4f954280 --- /dev/null +++ b/qt5/qtbug-53071b.patch @@ -0,0 +1,122 @@ +From cd25866f6533923c208f52d58516f3725f69cefb Mon Sep 17 00:00:00 2001 +From: Thiago Macieira +Date: Wed, 18 May 2016 13:38:55 -0700 +Subject: [PATCH] Use the code we already have for parsing the transition time + too + +It's there and it's more efficient anyway. + +Change-Id: Ie9fd7afe060b4e4a8052fffd144fc40647430268 +Reviewed-by: Edward Welbourne +Reviewed-by: Brett Stottlemyer +Reviewed-by: Lars Knoll +--- + src/corelib/tools/qtimezoneprivate_tz.cpp | 68 ++++++++++++++++++------------- + 1 file changed, 40 insertions(+), 28 deletions(-) + +diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp +index cb9581a..bfa967e 100644 +--- a/src/corelib/tools/qtimezoneprivate_tz.cpp ++++ b/src/corelib/tools/qtimezoneprivate_tz.cpp +@@ -372,37 +372,21 @@ static QDate calculatePosixDate(const QByteArray &dateRule, int year) + } + } + +-static QTime parsePosixTime(const QByteArray &timeRule) ++// returns the time in seconds, INT_MIN if we failed to parse ++static int parsePosixTime(const char *begin, const char *end) + { +- // Format "HH:mm:ss", put check parts count just in case +- QList parts = timeRule.split(':'); +- int count = parts.count(); +- if (count == 3) +- return QTime(parts.at(0).toInt(), parts.at(1).toInt(), parts.at(2).toInt()); +- else if (count == 2) +- return QTime(parts.at(0).toInt(), parts.at(1).toInt(), 0); +- else if (count == 1) +- return QTime(parts.at(0).toInt(), 0, 0); +- return QTime(2, 0, 0); +-} +- +-static int parsePosixOffset(const char *begin, const char *end) +-{ +- // Format "[+|-]hh[:mm[:ss]]" ++ // Format "hh[:mm[:ss]]" + int hour, min = 0, sec = 0; + +- // note that the sign is inverted because POSIX counts in hours West of GMT +- bool negate = true; +- if (*begin == '+') { +- ++begin; +- } else if (*begin == '-') { +- negate = false; +- ++begin; +- } ++ // Note that the calls to qstrtoll do *not* check the end pointer, which ++ // means they proceed until they find a non-digit. We check that we're ++ // still in range at the end, but we may have read from past end. It's the ++ // caller's responsibility to ensure that begin is part of a ++ // null-terminated string. + + bool ok = false; + hour = qstrtoll(begin, &begin, 10, &ok); +- if (!ok) ++ if (!ok || hour < 0) + return INT_MIN; + if (begin < end && *begin == ':') { + // minutes +@@ -424,7 +408,35 @@ static int parsePosixOffset(const char *begin, const char *end) + if (begin != end) + return INT_MIN; + +- int value = (hour * 60 + min) * 60 + sec; ++ return (hour * 60 + min) * 60 + sec; ++} ++ ++static QTime parsePosixTransitionTime(const QByteArray &timeRule) ++{ ++ // Format "hh[:mm[:ss]]" ++ int value = parsePosixTime(timeRule.constBegin(), timeRule.constEnd()); ++ if (value == INT_MIN) { ++ // if we failed to parse, return 02:00 ++ return QTime(2, 0, 0); ++ } ++ return QTime::fromMSecsSinceStartOfDay(value * 1000); ++} ++ ++static int parsePosixOffset(const char *begin, const char *end) ++{ ++ // Format "[+|-]hh[:mm[:ss]]" ++ // note that the sign is inverted because POSIX counts in hours West of GMT ++ bool negate = true; ++ if (*begin == '+') { ++ ++begin; ++ } else if (*begin == '-') { ++ negate = false; ++ ++begin; ++ } ++ ++ int value = parsePosixTime(begin, end); ++ if (value == INT_MIN) ++ return value; + return negate ? -value : value; + } + +@@ -534,7 +546,7 @@ static QVector calculatePosixTransitions(const QByteArra + QByteArray dstDateRule = dstParts.at(0); + QTime dstTime; + if (dstParts.count() > 1) +- dstTime = parsePosixTime(dstParts.at(1)); ++ dstTime = parsePosixTransitionTime(dstParts.at(1)); + else + dstTime = QTime(2, 0, 0); + +@@ -543,7 +555,7 @@ static QVector calculatePosixTransitions(const QByteArra + QByteArray stdDateRule = stdParts.at(0); + QTime stdTime; + if (stdParts.count() > 1) +- stdTime = parsePosixTime(stdParts.at(1)); ++ stdTime = parsePosixTransitionTime(stdParts.at(1)); + else + stdTime = QTime(2, 0, 0); +