From bdb485519d957bb551d5eeae8a866df45a59c647 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Wed, 9 Dec 2009 14:35:32 +0100 Subject: Use realpath() only on systems we know it works on. We use realpath(X,0) extension that is defined by the latest POSIX standard and not many systems support it at the moment. For now we limit it to Linux and Symbian. Mac supports it starting with 10.6, and we'll implement it properly for Mac in 4.7. We know that neither *BSD systems nor Solaris do not support it. Reviewed-by: Markus Goetz --- src/corelib/io/qfsfileengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 37b0ea1..e4c4e3f 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -144,7 +144,7 @@ QString QFSFileEnginePrivate::canonicalized(const QString &path) return path; #endif // Mac OS X 10.5.x doesn't support the realpath(X,0) extenstion we use here. -#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) || defined(Q_OS_SYMBIAN) +#if defined(Q_OS_LINIX) || defined(Q_OS_SYMBIAN) char *ret = realpath(path.toLocal8Bit().constData(), (char*)0); if (ret) { QString canonicalPath = QDir::cleanPath(QString::fromLocal8Bit(ret)); -- cgit v0.12 From c73d4f8b55dbb79b7a2df38d167a7c5ffd4520ce Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 10 Dec 2009 10:04:36 +0100 Subject: Fix compilation: private headers must be #included with "" The reason is that the private headers don't exist in any of the -I lines, so they need to be found by the preprocessor relative to the source file, which means "". Task-number: QTBUG-6665 Reviewed-by: Trust Me --- src/dbus/qdbusargument_p.h | 2 +- src/dbus/qdbusconnection_p.h | 2 +- src/dbus/qdbusconnectioninterface.cpp | 2 +- src/dbus/qdbuserror.cpp | 2 +- src/dbus/qdbusintegrator_p.h | 2 +- src/dbus/qdbusinterface.cpp | 2 +- src/dbus/qdbusinterface_p.h | 4 ++-- src/dbus/qdbusinternalfilters.cpp | 2 +- src/dbus/qdbusmessage.cpp | 2 +- src/dbus/qdbusmetatype.cpp | 2 +- src/dbus/qdbusutil.cpp | 2 +- src/dbus/qdbusxmlparser_p.h | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h index 47c5e62..17302b4 100644 --- a/src/dbus/qdbusargument_p.h +++ b/src/dbus/qdbusargument_p.h @@ -54,7 +54,7 @@ // #include -#include +#include "qdbus_symbols_p.h" QT_BEGIN_NAMESPACE diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index b65e101..d6f7598 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -67,7 +67,7 @@ #include #include -#include +#include "qdbus_symbols_p.h" #include diff --git a/src/dbus/qdbusconnectioninterface.cpp b/src/dbus/qdbusconnectioninterface.cpp index 0f9a67f..ec61859 100644 --- a/src/dbus/qdbusconnectioninterface.cpp +++ b/src/dbus/qdbusconnectioninterface.cpp @@ -49,7 +49,7 @@ #include #include -#include // for the DBUS_* constants +#include "qdbus_symbols_p.h" // for the DBUS_* constants QT_BEGIN_NAMESPACE diff --git a/src/dbus/qdbuserror.cpp b/src/dbus/qdbuserror.cpp index 5c2fa2b..a48b878 100644 --- a/src/dbus/qdbuserror.cpp +++ b/src/dbus/qdbuserror.cpp @@ -44,7 +44,7 @@ #include #include -#include +#include "qdbus_symbols_p.h" #include "qdbusmessage.h" #include "qdbusmessage_p.h" diff --git a/src/dbus/qdbusintegrator_p.h b/src/dbus/qdbusintegrator_p.h index 5b18aca..85c6cb2 100644 --- a/src/dbus/qdbusintegrator_p.h +++ b/src/dbus/qdbusintegrator_p.h @@ -54,7 +54,7 @@ #ifndef QDBUSINTEGRATOR_P_H #define QDBUSINTEGRATOR_P_H -#include +#include "qdbus_symbols_p.h" #include "qcoreevent.h" #include "qeventloop.h" diff --git a/src/dbus/qdbusinterface.cpp b/src/dbus/qdbusinterface.cpp index d0a693f..c05e6a9 100644 --- a/src/dbus/qdbusinterface.cpp +++ b/src/dbus/qdbusinterface.cpp @@ -41,7 +41,7 @@ #include "qdbusinterface.h" -#include +#include "qdbus_symbols_p.h" #include #include diff --git a/src/dbus/qdbusinterface_p.h b/src/dbus/qdbusinterface_p.h index 3d11af1..a601608 100644 --- a/src/dbus/qdbusinterface_p.h +++ b/src/dbus/qdbusinterface_p.h @@ -54,8 +54,8 @@ #ifndef QDBUSINTERFACEPRIVATE_H #define QDBUSINTERFACEPRIVATE_H -#include -#include +#include "qdbusabstractinterface_p.h" +#include "qdbusmetaobject_p.h" #include QT_BEGIN_NAMESPACE diff --git a/src/dbus/qdbusinternalfilters.cpp b/src/dbus/qdbusinternalfilters.cpp index acd04d3..37110c5 100644 --- a/src/dbus/qdbusinternalfilters.cpp +++ b/src/dbus/qdbusinternalfilters.cpp @@ -41,7 +41,7 @@ #include "qdbusconnection_p.h" -#include +#include "qdbus_symbols_p.h" #include #include #include diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp index 4f1950b..a37ba1f 100644 --- a/src/dbus/qdbusmessage.cpp +++ b/src/dbus/qdbusmessage.cpp @@ -44,7 +44,7 @@ #include #include -#include +#include "qdbus_symbols_p.h" #include "qdbusargument_p.h" #include "qdbuserror.h" diff --git a/src/dbus/qdbusmetatype.cpp b/src/dbus/qdbusmetatype.cpp index 237aea3..afa3bbf 100644 --- a/src/dbus/qdbusmetatype.cpp +++ b/src/dbus/qdbusmetatype.cpp @@ -42,7 +42,7 @@ #include "qdbusmetatype.h" #include -#include +#include "qdbus_symbols_p.h" #include #include diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp index bf5a739..01b1dbd 100644 --- a/src/dbus/qdbusutil.cpp +++ b/src/dbus/qdbusutil.cpp @@ -41,7 +41,7 @@ #include "qdbusutil_p.h" -#include +#include "qdbus_symbols_p.h" #include diff --git a/src/dbus/qdbusxmlparser_p.h b/src/dbus/qdbusxmlparser_p.h index 3dbae1b..1a0523b 100644 --- a/src/dbus/qdbusxmlparser_p.h +++ b/src/dbus/qdbusxmlparser_p.h @@ -56,7 +56,7 @@ #include #include #include -#include +#include "qdbusintrospection_p.h" QT_BEGIN_NAMESPACE -- cgit v0.12 From f85306467b84cbc300d13aa52e0f5db4b1a2b1e6 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 10 Dec 2009 10:10:43 +0100 Subject: Fix compilation if QT_NO_DATESTRING is defined. If we have no string parsing in QDateTime, then we use sscanf, so we must include Task-number: QTBUG-6668 Reviewed-by: Markus Goetz --- src/network/access/qnetworkrequest.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index c91c608..923f2e3 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -49,6 +49,9 @@ #include "QtCore/qdatetime.h" #include +#ifndef QT_NO_DATESTRING +# include +#endif QT_BEGIN_NAMESPACE -- cgit v0.12 From 16e4047a627d85182d9d9622a839fa51a9650aca Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Thu, 10 Dec 2009 11:15:28 +0100 Subject: Fixes a qfileinfo autotest. Canonical file paths can begin with slash only on unix platforms. Reviewed-by: Prasanth --- tests/auto/qfileinfo/tst_qfileinfo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/qfileinfo/tst_qfileinfo.cpp b/tests/auto/qfileinfo/tst_qfileinfo.cpp index cd58fd6..1445f5b 100644 --- a/tests/auto/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/qfileinfo/tst_qfileinfo.cpp @@ -513,9 +513,11 @@ void tst_QFileInfo::canonicalFilePath() QFileInfo info("/tmp/../../../../../../../../../../../../../../../../../"); info.canonicalFilePath(); +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) // This used to crash on Mac QFileInfo dontCrash(QLatin1String("/")); QCOMPARE(dontCrash.canonicalFilePath(), QLatin1String("/")); +#endif #ifndef Q_OS_WIN // test symlinks -- cgit v0.12 From 4d3839eb99d720393e1386d63fa04c83367bb076 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 10 Dec 2009 11:29:22 +0100 Subject: Ensure that QProcessEnvironment::operator== doesn't crash Also add an extensive autotest suite for QProcessEnvironment Task-number: QTBUG-6701 Reviewed-by: Markus Goetz --- src/corelib/io/qprocess.cpp | 3 +- tests/auto/auto.pro | 1 + .../qprocessenvironment/qprocessenvironment.pro | 5 + .../tst_qprocessenvironment.cpp | 265 +++++++++++++++++++++ 4 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qprocessenvironment/qprocessenvironment.pro create mode 100644 tests/auto/qprocessenvironment/tst_qprocessenvironment.cpp diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 37161bc..c78af3c 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -275,7 +275,7 @@ QProcessEnvironment &QProcessEnvironment::operator=(const QProcessEnvironment &o */ bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const { - return d->hash == other.d->hash; + return d == other.d || (d && other.d && d->hash == other.d->hash); } /*! @@ -334,6 +334,7 @@ bool QProcessEnvironment::contains(const QString &name) const */ void QProcessEnvironment::insert(const QString &name, const QString &value) { + // d detaches from null d->hash.insert(prepareName(name), prepareValue(value)); } diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 92d29ae..5041812 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -256,6 +256,7 @@ SUBDIRS += \ qprinter \ qprinterinfo \ qprocess \ + qprocessenvironment \ qprogressbar \ qprogressdialog \ qpropertyanimation \ diff --git a/tests/auto/qprocessenvironment/qprocessenvironment.pro b/tests/auto/qprocessenvironment/qprocessenvironment.pro new file mode 100644 index 0000000..398facc --- /dev/null +++ b/tests/auto/qprocessenvironment/qprocessenvironment.pro @@ -0,0 +1,5 @@ +load(qttest_p4) + +QT = core + +SOURCES += tst_qprocessenvironment.cpp diff --git a/tests/auto/qprocessenvironment/tst_qprocessenvironment.cpp b/tests/auto/qprocessenvironment/tst_qprocessenvironment.cpp new file mode 100644 index 0000000..1cde33c --- /dev/null +++ b/tests/auto/qprocessenvironment/tst_qprocessenvironment.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +// Note: +// in cross-platform tests, ALWAYS use UPPERCASE variable names +// That's because on Windows, the variables are uppercased + +class tst_QProcessEnvironment: public QObject +{ + Q_OBJECT +private slots: + void operator_eq(); + void clearAndIsEmpty(); + void insert(); + void emptyNull(); + void toStringList(); + + void caseSensitivity(); + void systemEnvironment(); + void putenv(); +}; + +void tst_QProcessEnvironment::operator_eq() +{ + QProcessEnvironment e1; + QVERIFY(e1 == e1); + e1.clear(); + QVERIFY(e1 == e1); + + e1 = QProcessEnvironment(); + QProcessEnvironment e2; + QVERIFY(e1 == e2); + + e1.clear(); + QVERIFY(e1 != e2); + + e2.clear(); + + QVERIFY(e1 == e2); +} + +void tst_QProcessEnvironment::clearAndIsEmpty() +{ + QProcessEnvironment e; + e.insert("FOO", "bar"); + QVERIFY(!e.isEmpty()); + e.clear(); + QVERIFY(e.isEmpty()); +} + +void tst_QProcessEnvironment::insert() +{ + QProcessEnvironment e; + e.insert("FOO", "bar"); + QVERIFY(!e.isEmpty()); + QVERIFY(e.contains("FOO")); + QCOMPARE(e.value("FOO"), QString("bar")); + + e.remove("FOO"); + QVERIFY(!e.contains("FOO")); + QVERIFY(e.value("FOO").isNull()); + + e.clear(); + QVERIFY(!e.contains("FOO")); +} + +void tst_QProcessEnvironment::emptyNull() +{ + QProcessEnvironment e; + + e.insert("FOO", ""); + QVERIFY(e.contains("FOO")); + QVERIFY(e.value("FOO").isEmpty()); + QVERIFY(!e.value("FOO").isNull()); + + e.insert("FOO", QString()); + QVERIFY(e.contains("FOO")); + QVERIFY(e.value("FOO").isEmpty()); + // don't test if it's NULL, since we shall not make a guarantee + + e.remove("FOO"); + QVERIFY(!e.contains("FOO")); +} + +void tst_QProcessEnvironment::toStringList() +{ + QProcessEnvironment e; + QVERIFY(e.isEmpty()); + QVERIFY(e.toStringList().isEmpty()); + + e.insert("FOO", "bar"); + QStringList result = e.toStringList(); + QVERIFY(!result.isEmpty()); + QCOMPARE(result.length(), 1); + QCOMPARE(result.at(0), QString("FOO=bar")); + + e.clear(); + e.insert("BAZ", ""); + result = e.toStringList(); + QCOMPARE(result.at(0), QString("BAZ=")); + + e.insert("FOO", "bar"); + e.insert("A", "bc"); + e.insert("HELLO", "World"); + result = e.toStringList(); + QCOMPARE(result.length(), 4); + + // order is not specified, so use contains() + QVERIFY(result.contains("FOO=bar")); + QVERIFY(result.contains("BAZ=")); + QVERIFY(result.contains("A=bc")); + QVERIFY(result.contains("HELLO=World")); +} + +void tst_QProcessEnvironment::caseSensitivity() +{ + QProcessEnvironment e; + e.insert("foo", "bar"); + +#ifdef Q_OS_WIN + // on Windows, it's uppercased + QVERIFY(e.contains("foo")); + QVERIFY(e.contains("FOO")); + QVERIFY(e.contains("FoO")); + + QCOMPARE(e.value("foo"), QString("bar")); + QCOMPARE(e.value("FOO"), QString("bar")); + QCOMPARE(e.value("FoO"), QString("bar")); + + QStringList list = e.toStringList(); + QCOMPARE(list.at(0), QString("FOO=bar")); +#else + // otherwise, it's case sensitive + QVERIFY(e.contains("foo")); + QVERIFY(!e.contains("FOO")); + + e.insert("FOO", "baz"); + QVERIFY(e.contains("FOO")); + QCOMPARE(e.value("FOO"), QString("baz")); + QCOMPARE(e.value("foo"), QString("bar")); + + QStringList list = e.toStringList(); + QVERIFY(list.contains("foo=bar")); + QVERIFY(list.contains("FOO=baz")); +#endif +} + +void tst_QProcessEnvironment::systemEnvironment() +{ + static const char envname[] = "THIS_ENVIRONMENT_VARIABLE_HOPEFULLY_DOESNT_EXIST"; + QByteArray path = qgetenv("PATH"); + QByteArray nonexistant = qgetenv(envname); + QProcessEnvironment system = QProcessEnvironment::systemEnvironment(); + + QVERIFY(nonexistant.isNull()); + +#ifdef Q_WS_WINCE + // Windows CE has no environment + QVERIFY(path.isEmpty()); + QVERIFY(!system.contains("PATH")); + QVERIFY(system.isEmpty()); +#else + // all other system have environments + if (path.isEmpty()) + QFAIL("Could not find the PATH environment variable -- please correct the test environment"); + + QVERIFY(system.contains("PATH")); + QCOMPARE(system.value("PATH"), QString::fromLocal8Bit(path)); + + QVERIFY(!system.contains(envname)); + +# ifdef Q_OS_WIN + // check case-insensitive too + QVERIFY(system.contains("path")); + QCOMPARE(system.value("path"), QString::fromLocal8Bit(path)); + + QVERIFY(!system.contains(QString(envname).toLower())); +# endif +#endif +} + +void tst_QProcessEnvironment::putenv() +{ +#ifdef Q_WS_WINCE + QSKIP("Windows CE has no environment", SkipAll); +#else + static const char envname[] = "WE_RE_SETTING_THIS_ENVIRONMENT_VARIABLE"; + static bool testRan = false; + + if (testRan) + QFAIL("You cannot run this test more than once, since we modify the environment"); + testRan = true; + + QByteArray valBefore = qgetenv(envname); + if (!valBefore.isNull()) + QFAIL("The environment variable we set in the environment is already set! -- please correct the test environment"); + QProcessEnvironment eBefore = QProcessEnvironment::systemEnvironment(); + + qputenv(envname, "Hello, World"); + QByteArray valAfter = qgetenv(envname); + if (valAfter != "Hello, World") + QSKIP("Could not test: qputenv did not do its job", SkipAll); + + QProcessEnvironment eAfter = QProcessEnvironment::systemEnvironment(); + + QVERIFY(!eBefore.contains(envname)); + QVERIFY(eAfter.contains(envname)); + QCOMPARE(eAfter.value(envname), QString("Hello, World")); + +# ifdef Q_OS_WIN + // check case-insensitive too + QString lower = envname; + lower = lower.toLower(); + QVERIFY(!eBefore.contains(lower)); + QVERIFY(eAfter.contains(lower)); + QCOMPARE(eAfter.value(lower), QString("Hello, World")); +# endif +#endif +} + +QTEST_MAIN(tst_QProcessEnvironment) + +#include "tst_qprocessenvironment.moc" -- cgit v0.12 From 6c161d6cca6c08843b479c00fffb9c7217aec505 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Thu, 10 Dec 2009 16:39:46 +1000 Subject: Install private headers when configuring Qt with -developer-build. Many Qt autotests require both private symbols and private headers. Private symbols are turned on using -developer-build. However, prior to this commit there was no way to install private headers into the Qt install directory. This is particularly relevant for packaging systems which use `make install' to determine what should be packaged. For example, Qt for Maemo debian packages are effectively unusable for Qt autotests without this commit. Reviewed-by: Michael Goddard --- bin/syncqt | 6 ++++++ src/qt_install.pri | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/bin/syncqt b/bin/syncqt index a14a82d..629e124 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -666,6 +666,7 @@ foreach (@modules_to_sync) { #information used after the syncing my $pri_install_classes = ""; my $pri_install_files = ""; + my $pri_install_pfiles = ""; my $libcapitals = $lib; $libcapitals =~ y/a-z/A-Z/; @@ -834,6 +835,10 @@ foreach (@modules_to_sync) { $pri_install_files.= "$pri_install_iheader ";; } } + else { + my $pri_install_iheader = fixPaths($iheader, $current_dir); + $pri_install_pfiles.= "$pri_install_iheader ";; + } } print "header created for $iheader ($header_copies)\n" if($header_copies > 0); } @@ -878,6 +883,7 @@ foreach (@modules_to_sync) { my $headers_pri_contents = ""; $headers_pri_contents .= "SYNCQT.HEADER_FILES = $pri_install_files\n"; $headers_pri_contents .= "SYNCQT.HEADER_CLASSES = $pri_install_classes\n"; + $headers_pri_contents .= "SYNCQT.PRIVATE_HEADER_FILES = $pri_install_pfiles\n"; my $headers_pri_file = "$out_basedir/include/$lib/headers.pri"; if(-e "$headers_pri_file") { open HEADERS_PRI_FILE, "<$headers_pri_file"; diff --git a/src/qt_install.pri b/src/qt_install.pri index ebeac8d..5b29942 100644 --- a/src/qt_install.pri +++ b/src/qt_install.pri @@ -30,6 +30,12 @@ qt_install_headers { targ_headers.files = $$INSTALL_HEADERS targ_headers.path = $$[QT_INSTALL_HEADERS]/$$TARGET INSTALLS += targ_headers + + contains(QT_CONFIG,private_tests) { + private_headers.files = $$SYNCQT.PRIVATE_HEADER_FILES + private_headers.path = $$[QT_INSTALL_HEADERS]/$$TARGET/private + INSTALLS += private_headers + } } embedded:equals(TARGET, QtGui) { -- cgit v0.12 From 669cb438384f1ceafd4b2ee783b9a52d7110ccf7 Mon Sep 17 00:00:00 2001 From: Anders Ahlen Date: Fri, 11 Dec 2009 12:00:47 +0100 Subject: Document QTextEncoder::fromUnicode as QT3 support member Make deprecated QTextEncoder::fromUnicode ( const QString & uc, int & lenInOut ) documented as QT3 support member Task-number: QTBUG-6614 Merge-request: 399 Reviewed-by: Thiago Macieira --- src/corelib/codecs/qtextcodec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/codecs/qtextcodec.h b/src/corelib/codecs/qtextcodec.h index f831700..6170272 100644 --- a/src/corelib/codecs/qtextcodec.h +++ b/src/corelib/codecs/qtextcodec.h @@ -161,7 +161,7 @@ public: QByteArray fromUnicode(const QString& str); QByteArray fromUnicode(const QChar *uc, int len); #ifdef QT3_SUPPORT - QByteArray fromUnicode(const QString& uc, int& lenInOut); + QT3_SUPPORT QByteArray fromUnicode(const QString& uc, int& lenInOut); #endif bool hasFailure() const; private: -- cgit v0.12 From bafc505ea03ff423c02e0380ba6f255e160483a1 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 11 Dec 2009 11:35:57 +0100 Subject: Fix tst_QTouchEvent::touchUpdateAndEndNeverPropagate() QGrahpicsItem behaves similarly to QWidget; if the TouchUpdate or TouchEnd event is ignored, then the event sent to the view and scene will also be ignored. Reviewed-by: Trust me --- tests/auto/qtouchevent/tst_qtouchevent.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qtouchevent/tst_qtouchevent.cpp b/tests/auto/qtouchevent/tst_qtouchevent.cpp index f95a5c6..98af4fb 100644 --- a/tests/auto/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/qtouchevent/tst_qtouchevent.cpp @@ -496,7 +496,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); QVERIFY(res); // the scene accepts the event, since it found an item to send the event to - QVERIFY(touchUpdateEvent.isAccepted()); + QVERIFY(!touchUpdateEvent.isAccepted()); QVERIFY(child.seenTouchUpdate); QVERIFY(!root.seenTouchUpdate); @@ -510,7 +510,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() res = QApplication::sendEvent(view.viewport(), &touchEndEvent); QVERIFY(res); // the scene accepts the event, since it found an item to send the event to - QVERIFY(touchEndEvent.isAccepted()); + QVERIFY(!touchEndEvent.isAccepted()); QVERIFY(child.seenTouchEnd); QVERIFY(!root.seenTouchEnd); } -- cgit v0.12 From 05ba6bad6c0927d22ccf026446dfdb9d85b3f03e Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 11 Dec 2009 11:38:19 +0100 Subject: Fix crashes when deleting QWidgets and QGraphicsItems in touch event handlers. Use QWeakPointer to bail out early if a widget is deleted while we are delivering/propagating a TouchBegin event. In QGraphicsScene, we need to make sure that we clear the scene's active touch points for items that are removed from the scene. This allows us to detect when an item is removed during TouchBegin event delivery/propagation. Unlike QWidget, propagation continues since we use a hit-test instead of the item's hierarchy for propagation. Task-number: QTBUG-6654 Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsscene.cpp | 24 ++- src/gui/kernel/qapplication.cpp | 10 +- tests/auto/qtouchevent/tst_qtouchevent.cpp | 246 ++++++++++++++++++++++++++++- 3 files changed, 274 insertions(+), 6 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 27ebb79..2a53456 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -613,6 +613,19 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) if (item == lastActivePanel) lastActivePanel = 0; + // Cancel active touches + { + QMap::iterator it = itemForTouchPointId.begin(); + while (it != itemForTouchPointId.end()) { + if (it.value() == item) { + sceneCurrentTouchPoints.remove(it.key()); + it = itemForTouchPointId.erase(it); + } else { + ++it; + } + } + } + // Disable selectionChanged() for individual items ++selectionChanging; int oldSelectedItemsSize = selectedItems.size(); @@ -5679,17 +5692,22 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve touchEvent->setAccepted(acceptTouchEvents); res = acceptTouchEvents && sendEvent(item, touchEvent); eventAccepted = touchEvent->isAccepted(); - item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted); + if (itemForTouchPointId.value(touchEvent->touchPoints().first().id()) == 0) { + // item was deleted + item = 0; + } else { + item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted); + } touchEvent->spont = false; if (res && eventAccepted) { // the first item to accept the TouchBegin gets an implicit grab. for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i); - itemForTouchPointId[touchPoint.id()] = item; + itemForTouchPointId[touchPoint.id()] = item; // can be zero } break; } - if (item->isPanel()) + if (item && item->isPanel()) break; } diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 9f4cd0c..8c63968 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -4092,9 +4092,15 @@ bool QApplication::notify(QObject *receiver, QEvent *e) bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); touchEvent->setWidget(widget); touchEvent->setAccepted(acceptTouchEvents); + QWeakPointer p = widget; res = acceptTouchEvents && d->notify_helper(widget, touchEvent); eventAccepted = touchEvent->isAccepted(); - widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); + if (p.isNull()) { + // widget was deleted + widget = 0; + } else { + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); + } touchEvent->spont = false; if (res && eventAccepted) { // the first widget to accept the TouchBegin gets an implicit grab. @@ -4103,7 +4109,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) d->widgetForTouchPointId[touchPoint.id()] = widget; } break; - } else if (widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { + } else if (p.isNull() || widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { break; } QPoint offset = widget->pos(); diff --git a/tests/auto/qtouchevent/tst_qtouchevent.cpp b/tests/auto/qtouchevent/tst_qtouchevent.cpp index 98af4fb..da8721c 100644 --- a/tests/auto/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/qtouchevent/tst_qtouchevent.cpp @@ -48,6 +48,7 @@ public: QList touchBeginPoints, touchUpdatePoints, touchEndPoints; bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; + bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd; tst_QTouchEventWidget() : QWidget() @@ -62,6 +63,7 @@ public: touchEndPoints.clear(); seenTouchBegin = seenTouchUpdate = seenTouchEnd = false; acceptTouchBegin = acceptTouchUpdate = acceptTouchEnd = true; + deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; } bool event(QEvent *event) @@ -74,6 +76,8 @@ public: seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd; touchBeginPoints = static_cast(event)->touchPoints(); event->setAccepted(acceptTouchBegin); + if (deleteInTouchBegin) + delete this; break; case QEvent::TouchUpdate: if (!seenTouchBegin) qWarning("TouchUpdate: have not seen TouchBegin"); @@ -81,6 +85,8 @@ public: seenTouchUpdate = seenTouchBegin && !seenTouchEnd; touchUpdatePoints = static_cast(event)->touchPoints(); event->setAccepted(acceptTouchUpdate); + if (deleteInTouchUpdate) + delete this; break; case QEvent::TouchEnd: if (!seenTouchBegin) qWarning("TouchEnd: have not seen TouchBegin"); @@ -88,6 +94,8 @@ public: seenTouchEnd = seenTouchBegin && !seenTouchEnd; touchEndPoints = static_cast(event)->touchPoints(); event->setAccepted(acceptTouchEnd); + if (deleteInTouchEnd) + delete this; break; default: return QWidget::event(event); @@ -102,13 +110,21 @@ public: QList touchBeginPoints, touchUpdatePoints, touchEndPoints; bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; + bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd; + tst_QTouchEventGraphicsItem **weakpointer; tst_QTouchEventGraphicsItem() - : QGraphicsItem() + : QGraphicsItem(), weakpointer(0) { reset(); } + ~tst_QTouchEventGraphicsItem() + { + if (weakpointer) + *weakpointer = 0; + } + void reset() { touchBeginPoints.clear(); @@ -116,6 +132,7 @@ public: touchEndPoints.clear(); seenTouchBegin = seenTouchUpdate = seenTouchEnd = false; acceptTouchBegin = acceptTouchUpdate = acceptTouchEnd = true; + deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; } QRectF boundingRect() const { return QRectF(0, 0, 10, 10); } @@ -131,6 +148,8 @@ public: seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd; touchBeginPoints = static_cast(event)->touchPoints(); event->setAccepted(acceptTouchBegin); + if (deleteInTouchBegin) + delete this; break; case QEvent::TouchUpdate: if (!seenTouchBegin) qWarning("TouchUpdate: have not seen TouchBegin"); @@ -138,6 +157,8 @@ public: seenTouchUpdate = seenTouchBegin && !seenTouchEnd; touchUpdatePoints = static_cast(event)->touchPoints(); event->setAccepted(acceptTouchUpdate); + if (deleteInTouchUpdate) + delete this; break; case QEvent::TouchEnd: if (!seenTouchBegin) qWarning("TouchEnd: have not seen TouchBegin"); @@ -145,6 +166,8 @@ public: seenTouchEnd = seenTouchBegin && !seenTouchEnd; touchEndPoints = static_cast(event)->touchPoints(); event->setAccepted(acceptTouchEnd); + if (deleteInTouchEnd) + delete this; break; default: return QGraphicsItem::sceneEvent(event); @@ -168,6 +191,8 @@ private slots: void basicRawEventTranslation(); void multiPointRawEventTranslationOnTouchScreen(); void multiPointRawEventTranslationOnTouchPad(); + void deleteInEventHandler(); + void deleteInRawEventTranslation(); }; void tst_QTouchEvent::touchDisabledByDefault() @@ -1059,6 +1084,225 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() } } +void tst_QTouchEvent::deleteInEventHandler() +{ + // QWidget + { + QWidget window; + tst_QTouchEventWidget *child1, *child2, *child3; + child1 = new tst_QTouchEventWidget; + child2 = new tst_QTouchEventWidget; + child3 = new tst_QTouchEventWidget; + child1->setParent(&window); + child2->setParent(&window); + child3->setParent(&window); + child1->setAttribute(Qt::WA_AcceptTouchEvents); + child2->setAttribute(Qt::WA_AcceptTouchEvents); + child3->setAttribute(Qt::WA_AcceptTouchEvents); + child1->deleteInTouchBegin = true; + child2->deleteInTouchUpdate = true; + child3->deleteInTouchEnd = true; + + QList touchPoints; + touchPoints.append(QTouchEvent::TouchPoint(0)); + QTouchEvent touchBeginEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointStationary, + touchPoints); + QTouchEvent touchEndEvent(QEvent::TouchEnd, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointReleased, + touchPoints); + QWeakPointer p; + bool res; + + touchBeginEvent.ignore(); + p = child1; + res = QApplication::sendEvent(child1, &touchBeginEvent); + // event is handled, but widget should be deleted + QVERIFY(res && touchBeginEvent.isAccepted() && p.isNull()); + + touchBeginEvent.ignore(); + p = child2; + res = QApplication::sendEvent(child2, &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && !p.isNull()); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(child2, &touchUpdateEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && p.isNull()); + + touchBeginEvent.ignore(); + p = child3; + res = QApplication::sendEvent(child3, &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && !p.isNull()); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(child3, &touchUpdateEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && !p.isNull()); + touchEndEvent.ignore(); + res = QApplication::sendEvent(child3, &touchEndEvent); + QVERIFY(res && touchEndEvent.isAccepted() && p.isNull()); + } + + // QGraphicsView + { + QGraphicsScene scene; + QGraphicsView view(&scene); + tst_QTouchEventGraphicsItem *root, *child1, *child2, *child3; + root = new tst_QTouchEventGraphicsItem; + child1 = new tst_QTouchEventGraphicsItem; + child2 = new tst_QTouchEventGraphicsItem; + child3 = new tst_QTouchEventGraphicsItem; + child1->setParentItem(root); + child2->setParentItem(root); + child3->setParentItem(root); + child1->setZValue(1.); + child2->setZValue(0.); + child3->setZValue(-1.); + child1->setAcceptTouchEvents(true); + child2->setAcceptTouchEvents(true); + child3->setAcceptTouchEvents(true); + child1->deleteInTouchBegin = true; + child2->deleteInTouchUpdate = true; + child3->deleteInTouchEnd = true; + + scene.addItem(root); + view.resize(200, 200); + view.fitInView(scene.sceneRect()); + + QTouchEvent::TouchPoint touchPoint(0); + touchPoint.setState(Qt::TouchPointPressed); + touchPoint.setPos(view.mapFromScene(child1->mapToScene(child1->boundingRect().center()))); + touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); + touchPoint.setScenePos(view.mapToScene(touchPoint.pos().toPoint())); + QList touchPoints; + touchPoints.append(touchPoint); + QTouchEvent touchBeginEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + touchPoints[0].setState(Qt::TouchPointMoved); + QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointMoved, + touchPoints); + touchPoints[0].setState(Qt::TouchPointReleased); + QTouchEvent touchEndEvent(QEvent::TouchEnd, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointReleased, + touchPoints); + bool res; + + child1->weakpointer = &child1; + touchBeginEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && !child1); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && !child1); + touchEndEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchEndEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && !child1); + + child2->weakpointer = &child2; + touchBeginEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && child2); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); + QVERIFY(res && !touchUpdateEvent.isAccepted() && !child2); + touchEndEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchEndEvent); + QVERIFY(res && !touchUpdateEvent.isAccepted() && !child2); + + child3->weakpointer = &child3; + res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && child3); + res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); + QVERIFY(res && !touchUpdateEvent.isAccepted() && child3); + res = QApplication::sendEvent(view.viewport(), &touchEndEvent); + QVERIFY(res && !touchEndEvent.isAccepted() && !child3); + + delete root; + } +} + +void tst_QTouchEvent::deleteInRawEventTranslation() +{ + tst_QTouchEventWidget touchWidget; + touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); + touchWidget.setGeometry(100, 100, 300, 300); + + tst_QTouchEventWidget *leftWidget = new tst_QTouchEventWidget; + leftWidget->setParent(&touchWidget); + leftWidget->setAttribute(Qt::WA_AcceptTouchEvents); + leftWidget->setGeometry(0, 100, 100, 100); + leftWidget->deleteInTouchBegin = true; + leftWidget->show(); + + tst_QTouchEventWidget *centerWidget = new tst_QTouchEventWidget; + centerWidget->setParent(&touchWidget); + centerWidget->setAttribute(Qt::WA_AcceptTouchEvents); + centerWidget->setGeometry(100, 100, 100, 100); + centerWidget->deleteInTouchUpdate = true; + centerWidget->show(); + + tst_QTouchEventWidget *rightWidget = new tst_QTouchEventWidget; + rightWidget->setParent(&touchWidget); + rightWidget->setAttribute(Qt::WA_AcceptTouchEvents); + rightWidget->setGeometry(200, 100, 100, 100); + rightWidget->deleteInTouchEnd = true; + rightWidget->show(); + + QPointF leftPos = leftWidget->rect().center(); + QPointF centerPos = centerWidget->rect().center(); + QPointF rightPos = rightWidget->rect().center(); + QPointF leftScreenPos = leftWidget->mapToGlobal(leftPos.toPoint()); + QPointF centerScreenPos = centerWidget->mapToGlobal(centerPos.toPoint()); + QPointF rightScreenPos = rightWidget->mapToGlobal(rightPos.toPoint()); + QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + + QWeakPointer pl = leftWidget, pc = centerWidget, pr = rightWidget; + + QList rawTouchPoints; + rawTouchPoints.append(QTouchEvent::TouchPoint(0)); + rawTouchPoints.append(QTouchEvent::TouchPoint(1)); + rawTouchPoints.append(QTouchEvent::TouchPoint(2)); + rawTouchPoints[0].setState(Qt::TouchPointPressed); + rawTouchPoints[0].setScreenPos(leftScreenPos); + rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry)); + rawTouchPoints[1].setState(Qt::TouchPointPressed); + rawTouchPoints[1].setScreenPos(centerScreenPos); + rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry)); + rawTouchPoints[2].setState(Qt::TouchPointPressed); + rawTouchPoints[2].setScreenPos(rightScreenPos); + rawTouchPoints[2].setNormalizedPos(normalized(rawTouchPoints[2].pos(), screenGeometry)); + + // generate begin events on all widgets, the left widget should die + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); + QVERIFY(pl.isNull() && !pc.isNull() && !pr.isNull()); + + // generate update events on all widget, the center widget should die + rawTouchPoints[0].setState(Qt::TouchPointMoved); + rawTouchPoints[1].setState(Qt::TouchPointMoved); + rawTouchPoints[2].setState(Qt::TouchPointMoved); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); + + // generate end events on all widget, the right widget should die + rawTouchPoints[0].setState(Qt::TouchPointReleased); + rawTouchPoints[1].setState(Qt::TouchPointReleased); + rawTouchPoints[2].setState(Qt::TouchPointReleased); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); +} + QTEST_MAIN(tst_QTouchEvent) #include "tst_qtouchevent.moc" -- cgit v0.12 From 9aa60dfdf5b4837b9ceb15d8fcbc96f37dce7b5a Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 11 Dec 2009 15:19:30 +0100 Subject: Check if the timeout expired during the time update in qt_safe_select It can happen that select(2) returns -1 with EINTR, but the time remaining was too small for us to update the time. Our own processing (plus the syscall to clock_gettime(2)) leads us past the timeout, so we get a negative timeval. Task-number: QTBUG-6755 Reviewed-by: Bradley T. Hughes --- src/corelib/kernel/qcore_unix.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp index 5885591..d0dc7be 100644 --- a/src/corelib/kernel/qcore_unix.cpp +++ b/src/corelib/kernel/qcore_unix.cpp @@ -129,7 +129,7 @@ static inline bool time_update(struct timeval *tv, const struct timeval &start, // clock source is monotonic, so we can recalculate how much timeout is left struct timeval now = qt_gettime(); *tv = timeout + start - now; - return true; + return tv->tv_sec >= 0; } int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, @@ -154,7 +154,8 @@ int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, // recalculate the timeout if (!time_update(&timeout, start, *orig_timeout)) { - // clock reset, fake timeout error + // timeout during update + // or clock reset, fake timeout error return 0; } } -- cgit v0.12