diff options
author | João Abecasis <joao.abecasis@nokia.com> | 2011-02-16 19:01:17 +0100 |
---|---|---|
committer | João Abecasis <joao.abecasis@nokia.com> | 2011-02-16 19:01:17 +0100 |
commit | 9db05f0b7bf68392dc925d4047aa74dac88b348a (patch) | |
tree | 3690ea636187c9af9459ff3bfd4cab3e2af97c57 | |
parent | 0df215e5afc780c1fddd9e410f7ef0814ac1307c (diff) | |
parent | 5a1676af979ab75c8939e53e0223ccbea7708de4 (diff) | |
download | qt4-tools-9db05f0b7bf68392dc925d4047aa74dac88b348a.tar.gz |
Merge branch earth-team/master into earth-staging
Conflicts:
doc/src/development/qmake-manual.qdoc
56 files changed, 1428 insertions, 439 deletions
diff --git a/demos/browser/networkaccessmanager.cpp b/demos/browser/networkaccessmanager.cpp index 9e717bb684..c63c0eb6da 100644 --- a/demos/browser/networkaccessmanager.cpp +++ b/demos/browser/networkaccessmanager.cpp @@ -64,7 +64,7 @@ NetworkAccessManager::NetworkAccessManager(QObject *parent) : QNetworkAccessManager(parent), requestFinishedCount(0), requestFinishedFromCacheCount(0), requestFinishedPipelinedCount(0), - requestFinishedSecureCount(0) + requestFinishedSecureCount(0), requestFinishedDownloadBufferCount(0) { connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); @@ -106,14 +106,19 @@ void NetworkAccessManager::requestFinished(QNetworkReply *reply) if (reply->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool() == true) requestFinishedSecureCount++; + if (reply->attribute(QNetworkRequest::DownloadBufferAttribute).isValid() == true) + requestFinishedDownloadBufferCount++; + if (requestFinishedCount % 10) return; double pctCached = (double(requestFinishedFromCacheCount) * 100.0/ double(requestFinishedCount)); double pctPipelined = (double(requestFinishedPipelinedCount) * 100.0/ double(requestFinishedCount)); double pctSecure = (double(requestFinishedSecureCount) * 100.0/ double(requestFinishedCount)); + double pctDownloadBuffer = (double(requestFinishedDownloadBufferCount) * 100.0/ double(requestFinishedCount)); + #ifdef QT_DEBUG - qDebug("STATS [%lli requests total] [%3.2f%% from cache] [%3.2f%% pipelined] [%3.2f%% SSL/TLS]", requestFinishedCount, pctCached, pctPipelined, pctSecure); + qDebug("STATS [%lli requests total] [%3.2f%% from cache] [%3.2f%% pipelined] [%3.2f%% SSL/TLS] [%3.2f%% Zerocopy]", requestFinishedCount, pctCached, pctPipelined, pctSecure, pctDownloadBuffer); #endif } diff --git a/demos/browser/networkaccessmanager.h b/demos/browser/networkaccessmanager.h index 76fc1980b7..d6e6ede819 100644 --- a/demos/browser/networkaccessmanager.h +++ b/demos/browser/networkaccessmanager.h @@ -60,6 +60,7 @@ private: qint64 requestFinishedFromCacheCount; qint64 requestFinishedPipelinedCount; qint64 requestFinishedSecureCount; + qint64 requestFinishedDownloadBufferCount; public slots: void loadSettings(); diff --git a/doc/src/development/qmake-manual.qdoc b/doc/src/development/qmake-manual.qdoc index c3a044f21a..373254c55c 100644 --- a/doc/src/development/qmake-manual.qdoc +++ b/doc/src/development/qmake-manual.qdoc @@ -1901,8 +1901,17 @@ \target PWD \section1 PWD - This variable contains the full path leading to the directory where - the \l {qmake}{ \c qmake} project file (project.pro) is located. + The \c PWD variable specifies the full path leading to the directory + containing the current file being parsed. This can be useful + to refer to files within the source tree when writing project files to + support shadow builds. + + See also \l{#_PRO_FILE_PWD_}{_PRO_FILE_PWD_}. + + \note IN_PWD is an alias for PWD. + + \note Function calls have no effect on the value of PWD. PWD will refer to + the path of the calling file. \target OUT_PWD \section1 OUT_PWD @@ -3399,6 +3408,19 @@ \tableofcontents{2} + \section1 packagesExist(packages) + + Uses the PKGCONFIG mechanism to determine whether or not the given packages + exist at the time of project parsing. + + This can be useful to optionally enable or disable features. For example: + + \snippet doc/src/snippets/code/doc_src_qmake-manual.qdoc 157 + + And then, in the code: + + \snippet doc/src/snippets/code/doc_src_qmake-manual.qdoc 158 + \section1 basename(variablename) Returns the basename of the file specified. For example: diff --git a/doc/src/snippets/code/doc_src_qmake-manual.qdoc b/doc/src/snippets/code/doc_src_qmake-manual.qdoc index f6ac4f866e..a35a3d90c5 100644 --- a/doc/src/snippets/code/doc_src_qmake-manual.qdoc +++ b/doc/src/snippets/code/doc_src_qmake-manual.qdoc @@ -1029,3 +1029,15 @@ DEPLOYMENT += dep_note //! [156] DEPLOYMENT.display_name = My Qt App //! [156] + +//! [157] +packagesExist(sqlite3 QtNetwork QtDeclarative) { + DEFINES += USE_FANCY_UI +} +//! [157] + +//! [158] +#ifdef USE_FANCY_UI + // Use the fancy UI, as we have extra packages available +#endif +//! [158] diff --git a/mkspecs/common/armcc.conf b/mkspecs/common/armcc.conf index 2c765bcdff..4f178d745e 100644 --- a/mkspecs/common/armcc.conf +++ b/mkspecs/common/armcc.conf @@ -37,5 +37,6 @@ QMAKE_LFLAGS_PLUGIN += $$QMAKE_LFLAGS_SHLIB QMAKE_LFLAGS_THREAD += QMAKE_AR = armar --create +QMAKE_LIB = armar --create QMAKE_RANLIB = diff --git a/mkspecs/common/symbian/symbian-makefile.conf b/mkspecs/common/symbian/symbian-makefile.conf index 899f8c2790..cffc859b93 100644 --- a/mkspecs/common/symbian/symbian-makefile.conf +++ b/mkspecs/common/symbian/symbian-makefile.conf @@ -2,7 +2,11 @@ # qmake configuration for makefile based symbian # -MAKEFILE_GENERATOR = SYMBIAN_UNIX +contains(QMAKE_HOST.os,Windows) { + MAKEFILE_GENERATOR = SYMBIAN_MINGW +} else { + MAKEFILE_GENERATOR = SYMBIAN_UNIX +} include(symbian.conf) @@ -24,10 +28,18 @@ CONFIG *= no_plugin_name_prefix QMAKE_PREFIX_STATICLIB = QMAKE_SYMBIAN_SHLIB = 1 +QMAKE_LINK_OBJECT_SCRIPT = objects + is_using_gnupoc { - DEFINES *= __PRODUCT_INCLUDE__=\"<$${EPOCROOT}epoc32/include/variant/symbian_os.hrh>\" -} else { - DEFINES *= __PRODUCT_INCLUDE__=\"<$${EPOCROOT}epoc32/include/variant/Symbian_OS.hrh>\" + DEFINES *= __QT_PRODUCT_INCLUDE_IS_LOWERCASE__ +} +QMAKE_SYMBIAN_INCLUDES = $$[QT_INSTALL_DATA]/mkspecs/common/symbian/symbianincludes.h +symbian-armcc { + QMAKE_CFLAGS += --preinclude $$QMAKE_SYMBIAN_INCLUDES + QMAKE_CXXFLAGS += --preinclude $$QMAKE_SYMBIAN_INCLUDES +} else:symbian-gcce { + QMAKE_CFLAGS += -include $$QMAKE_SYMBIAN_INCLUDES + QMAKE_CXXFLAGS += -include $$QMAKE_SYMBIAN_INCLUDES } DEFINES *= \ __SYMBIAN32__ \ diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index 3644bc65bc..63db511f24 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -118,11 +118,11 @@ contains(QMAKE_HOST.os,Windows) { } QMAKE_IDL = midl -QMAKE_LIB = ar -ru -QMAKE_RC = windres QMAKE_ZIP = zip -r -9 QMAKE_UNZIP = unzip -o +QMAKE_WRITE_DEFAULT_RC = 1 + QMAKE_TAR = tar -cf QMAKE_GZIP = gzip -9f @@ -239,7 +239,7 @@ defineTest(matchSymbianLanguages) { language = $$replace(translation, "^(.*/)?[^/]+_(([^_]{2,3}_)?[^_]{2,3})\\.ts$", \\2) contains(SYMBIAN_SUPPORTED_LANGUAGES, $$language) { SYMBIAN_MATCHED_LANGUAGES += $$language - SYMBIAN_MATCHED_TRANSLATIONS += $$translation + SYMBIAN_MATCHED_TRANSLATIONS += $$_PRO_FILE_PWD_/$$translation } } diff --git a/mkspecs/common/symbian/symbianincludes.h b/mkspecs/common/symbian/symbianincludes.h new file mode 100644 index 0000000000..5d7f488fdb --- /dev/null +++ b/mkspecs/common/symbian/symbianincludes.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the mkspecs 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$ +** +****************************************************************************/ + +#ifndef __PRODUCT_INCLUDE__ +# ifdef __QT_PRODUCT_INCLUDE_IS_LOWERCASE__ +# define __PRODUCT_INCLUDE__ <variant/symbian_os.hrh> +# else +# define __PRODUCT_INCLUDE__ <variant/Symbian_OS.hrh> +# endif +#endif + +#ifndef __QT_SYMBIAN_RESOURCE__ +# if defined(__ARMCC__) || defined(__CC_ARM) +# ifdef __QT_RVCT_HEADER_IS_2_2__ +# include <rvct2_2.h> +# else +# include <rvct.h> +# endif +# endif +#endif diff --git a/mkspecs/features/link_pkgconfig.prf b/mkspecs/features/link_pkgconfig.prf index d70e5de104..a3dbd1ffcc 100644 --- a/mkspecs/features/link_pkgconfig.prf +++ b/mkspecs/features/link_pkgconfig.prf @@ -1,7 +1,12 @@ # handle pkg-config files -isEmpty(PKG_CONFIG):PKG_CONFIG = pkg-config +isEmpty(PKG_CONFIG):PKG_CONFIG = pkg-config # keep consistent with qt_functions.prf too! + for(PKGCONFIG_LIB, $$list($$unique(PKGCONFIG))) { + # don't proceed if the .pro asks for a package we don't have! + !packagesExist($$PKGCONFIG_LIB):error("Package $$PKGCONFIG_LIB not found") + QMAKE_CXXFLAGS += $$system($$PKG_CONFIG --cflags $$PKGCONFIG_LIB) QMAKE_CFLAGS += $$system($$PKG_CONFIG --cflags $$PKGCONFIG_LIB) LIBS += $$system($$PKG_CONFIG --libs $$PKGCONFIG_LIB) } + diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 964e13b77c..1fb6298ced 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -46,7 +46,12 @@ defineTest(qtAddLibrary) { } } symbian { - isEqual(LIB_NAME, QtGui) { + isEqual(LIB_NAME, QtCore) { + #workaround for dependency from f32file.h on e32svr.h which has moved location in symbian3 + contains(SYMBIAN_VERSION, Symbian3) { + INCLUDEPATH *= $$OS_LAYER_SYSTEMINCLUDE + } + } else:isEqual(LIB_NAME, QtGui) { # Needed for #include <QtGui> because qs60mainapplication.h includes aknapp.h INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE } else:isEqual(LIB_NAME, QtWebKit) { @@ -103,3 +108,17 @@ defineTest(qtPrepareTool) { } export($$1) } + +defineTest(packagesExist) { + # this can't be done in global scope here because qt_functions is loaded + # before the .pro is parsed, so if the .pro set PKG_CONFIG, we wouldn't know it + # yet. oops. + isEmpty(PKG_CONFIG):PKG_CONFIG = pkg-config # keep consistent with link_pkgconfig.prf! too + + for(package, ARGS) { + !system($$PKG_CONFIG --exists $$package):return(false) + } + + return(true) +} + diff --git a/mkspecs/features/symbian/symbian_building.prf b/mkspecs/features/symbian/symbian_building.prf index 9288583c4c..678838c5b9 100644 --- a/mkspecs/features/symbian/symbian_building.prf +++ b/mkspecs/features/symbian/symbian_building.prf @@ -1,6 +1,11 @@ symbian-armcc { QMAKE_CFLAGS += $$QMAKE_CFLAGS.ARMCC QMAKE_CXXFLAGS += $$QMAKE_CXXFLAGS.ARMCC + # This is to prevent inclusion of the shipped RVCT headers, which are often in the + # environment variable RVCTxxINC by default. -J prevents the searching of that location, + # but needs a path, so just specify somewhere guaranteed not to contain header files. + QMAKE_CFLAGS += -J$${EPOCROOT}epoc32/ignore_this_path + QMAKE_CXXFLAGS += -J$${EPOCROOT}epoc32/ignore_this_path } else:symbian-gcce { QMAKE_CFLAGS += $$QMAKE_CFLAGS.GCCE QMAKE_CXXFLAGS += $$QMAKE_CXXFLAGS.GCCE @@ -235,13 +240,9 @@ contains(TEMPLATE, app):!contains(QMAKE_LINK, "^@:.*") { } # Symbian resource files -symbian-armcc: { - SYMBIAN_RVCT22INC=$$(RVCT22INC) - !isEmpty(SYMBIAN_RVCT22INC):symbian_resources_INCLUDES = -I$${SYMBIAN_RVCT22INC} -} -symbian_resources_INCLUDES = $$replace(symbian_resources_INCLUDES, ",", " -I") -symbian_resources_INCLUDES += $$join(INCLUDEPATH, " -I", "-I") +symbian_resources_INCLUDES = $$join(INCLUDEPATH, " -I", "-I") symbian_resources_DEFINES = $$join(DEFINES, " -D", "-D") +symbian_resources_DEFINES += -D__QT_SYMBIAN_RESOURCE__ symbian_resources_RCC_DIR = $$replace(RCC_DIR, "/$", "") symbian_resources_INCLUDES += "-I$$symbian_resources_RCC_DIR" @@ -256,6 +257,7 @@ for(symbian_resource, SYMBIAN_RESOURCES) { symbianresources.input = SYMBIAN_RESOURCES symbianresources.output = $$symbian_resources_RCC_DIR/${QMAKE_FILE_BASE}$${QT_LIBINFIX}.rsg symbianresources.commands = cpp -nostdinc -undef \ + -include $$QMAKE_SYMBIAN_INCLUDES \ $$symbian_resources_INCLUDES \ $$symbian_resources_DEFINES \ ${QMAKE_FILE_NAME} \ @@ -271,46 +273,79 @@ symbianresources.CONFIG = no_link target_predeps QMAKE_EXTRA_COMPILERS += symbianresources +# This section generates the rsg and rsc files for symbian. contains(TEMPLATE, "app"):!contains(CONFIG, "no_icon") { - # Make our own extra target in order to get dependencies for generated - # files right. This also avoids the warning about files not found. - symbianGenResource.target = $${symbian_resources_RCC_DIR}/$${baseTarget}.rsg - symbianGenResource.commands = cpp -nostdinc -undef \ - $$symbian_resources_INCLUDES \ - $$symbian_resources_DEFINES \ - $${baseTarget}.rss \ - > $${symbian_resources_RCC_DIR}/$${baseTarget}.rpp \ - && rcomp -u -m045,046,047 \ - -s$${symbian_resources_RCC_DIR}/$${baseTarget}.rpp \ - -o$${symbianDestdir}/$${baseTarget}.rsc \ - -h$${symbian_resources_RCC_DIR}/$${baseTarget}.rsg \ - -i$${baseTarget}.rss - silent:symbianGenResource.commands = @echo rcomp $${baseTarget}.rss && $$symbianGenResource.commands - symbianGenResource.depends = $${baseTarget}.rss - PRE_TARGETDEPS += $${symbian_resources_RCC_DIR}/$${baseTarget}.rsg - QMAKE_CLEAN += $${symbian_resources_RCC_DIR}/$${baseTarget}.rsg - QMAKE_CLEAN += $${symbian_resources_RCC_DIR}/$${baseTarget}.rpp - QMAKE_DISTCLEAN += $${baseTarget}.rss - QMAKE_DISTCLEAN += $${symbianDestdir}/$${baseTarget}.rsc - - symbianGenRegResource.target = $${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rsg - symbianGenRegResource.commands = cpp -nostdinc -undef \ - $$symbian_resources_INCLUDES \ - $$symbian_resources_DEFINES \ - $${baseTarget}_reg.rss \ - > $${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rpp \ - && rcomp -u -m045,046,047 \ - -s$${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rpp \ - -o$${symbianDestdir}/$${baseTarget}_reg.rsc \ - -h$${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rsg \ - -i$${baseTarget}_reg.rss - silent:symbianGenRegResource.commands = @echo rcomp $${baseTarget}_reg.rss && $$symbianGenRegResource.commands - symbianGenRegResource.depends = $${baseTarget}_reg.rss $${symbian_resources_RCC_DIR}/$${baseTarget}.rsg - PRE_TARGETDEPS += $${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rsg - QMAKE_CLEAN += $${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rsg - QMAKE_CLEAN += $${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rpp - QMAKE_DISTCLEAN += $${baseTarget}_reg.rss - QMAKE_DISTCLEAN += $${symbianDestdir}/$${baseTarget}_reg.rsc + # Look for extra languages for the resources, and then generate a target for each one. + localize_deployment:symbianGenResourceLanguages = $$SYMBIAN_MATCHED_LANGUAGES default + else:symbianGenResourceLanguages = default + for(language, symbianGenResourceLanguages) { + # Special languages get their language number appended to the filename. + contains(language, default) { + symbianGenResource_DEFINES = $$symbian_resources_DEFINES + rpp = $${symbian_resources_RCC_DIR}/$${baseTarget}.rpp + rsc = $${symbianDestdir}/$${baseTarget}.rsc + rsg = $${symbian_resources_RCC_DIR}/$${baseTarget}.rsg + } else { + languageNo = $$eval(SYMBIAN_LANG.$$language) + symbianGenResource_DEFINES = $$symbian_resources_DEFINES -DLANGUAGE_$${languageNo} + rpp = $${symbian_resources_RCC_DIR}/$${baseTarget}_$${languageNo}.rpp + rsc = $${symbianDestdir}/$${baseTarget}.r$${languageNo} + rsg = $${symbian_resources_RCC_DIR}/$${baseTarget}_$${languageNo}.rsg + } + + # Make our own extra target in order to get dependencies for generated + # files right. This also avoids the warning about files not found. + eval(symbianGenResource_$${language}.target = $$rsg) + eval(symbianGenResource_$${language}.commands = cpp -nostdinc -undef \ + -include $$QMAKE_SYMBIAN_INCLUDES \ + $$symbian_resources_INCLUDES \ + $$symbianGenResource_DEFINES \ + $${baseTarget}.rss \ + > $$rpp \ + && rcomp -u -m045,046,047 \ + -s$$rpp \ + -o$$rsc \ + -h$$rsg \ + -i$${baseTarget}.rss) + silent:eval(symbianGenResource_$${language}.commands = @echo rcomp $${baseTarget}.rss && $$eval(symbianGenResource_$${language}.commands)) + eval(symbianGenResource_$${language}.depends = $${baseTarget}.rss) + PRE_TARGETDEPS += $$rsg + QMAKE_CLEAN += $$rsg $$rpp + QMAKE_DISTCLEAN += $$rsc + + QMAKE_EXTRA_TARGETS += symbianGenResource_$${language} + + # Note that we depend on the base rsg file, even if dealing with a specific language. + # hence we don't use $$rsg on the next line. + eval(symbianGenRegResource_$${language}.depends = $${baseTarget}_reg.rss $${symbian_resources_RCC_DIR}/$${baseTarget}.rsg) + contains(language, default) { + rpp = $${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rpp + rsc = $${symbianDestdir}/$${baseTarget}_reg.rsc + rsg = $${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rsg + } else { + rpp = $${symbian_resources_RCC_DIR}/$${baseTarget}_reg_$${languageNo}.rpp + rsc = $${symbianDestdir}/$${baseTarget}_reg.r$${languageNo} + rsg = $${symbian_resources_RCC_DIR}/$${baseTarget}_reg_$${languageNo}.rsg + } + eval(symbianGenRegResource_$${language}.target = $$rsg) + eval(symbianGenRegResource_$${language}.commands = cpp -nostdinc -undef \ + -include $$QMAKE_SYMBIAN_INCLUDES \ + $$symbian_resources_INCLUDES \ + $$symbianGenResource_DEFINES \ + $${baseTarget}_reg.rss \ + > $$rpp \ + && rcomp -u -m045,046,047 \ + -s$$rpp \ + -o$$rsc \ + -h$$rsg \ + -i$${baseTarget}_reg.rss) + silent:eval(symbianGenRegResource_$${language}.commands = @echo rcomp $${baseTarget}_reg.rss && $$eval(symbianGenRegResource_$${language}.commands)) + PRE_TARGETDEPS += $$rsg + QMAKE_CLEAN += $$rsg $$rpp + QMAKE_DISTCLEAN += $$rsc + + QMAKE_EXTRA_TARGETS += symbianGenRegResource_$${language} + } # Trick to get qmake to create the RCC_DIR for us. symbianRccDirCreation.input = SOURCES @@ -318,14 +353,15 @@ contains(TEMPLATE, "app"):!contains(CONFIG, "no_icon") { symbianRccDirCreation.output = $${symbian_resources_RCC_DIR}/symbian_resource_dummy symbianRccDirCreation.CONFIG = no_link combine - QMAKE_EXTRA_TARGETS += symbianGenResource symbianGenRegResource QMAKE_EXTRA_COMPILERS += symbianRccDirCreation - QMAKE_DISTCLEAN += $${baseTarget}.loc + QMAKE_DISTCLEAN += $${baseTarget}.rss \ + $${baseTarget}_reg.rss \ + $${baseTarget}.loc } # Generated pkg files -QMAKE_DISTCLEAN += $${baseTarget}_template.pkg -QMAKE_DISTCLEAN += $${baseTarget}_installer.pkg -QMAKE_DISTCLEAN += $${baseTarget}_stub.pkg +QMAKE_DISTCLEAN += $${baseTarget}_template.pkg \ + $${baseTarget}_installer.pkg \ + $${baseTarget}_stub.pkg diff --git a/mkspecs/symbian-armcc/qmake.conf b/mkspecs/symbian-armcc/qmake.conf index be6af391fb..77a19662fc 100644 --- a/mkspecs/symbian-armcc/qmake.conf +++ b/mkspecs/symbian-armcc/qmake.conf @@ -53,10 +53,7 @@ INCLUDEPATH = $${EPOCROOT}epoc32/include \ exists($${EPOCROOT}epoc32/include/rvct2_2) { INCLUDEPATH += $${EPOCROOT}epoc32/include/rvct2_2 - QMAKE_CFLAGS += --preinclude rvct2_2.h - QMAKE_CXXFLAGS += --preinclude rvct2_2.h + DEFINES *= __QT_RVCT_HEADER_IS_2_2__ } else { INCLUDEPATH += $${EPOCROOT}epoc32/include/rvct - QMAKE_CFLAGS += --preinclude rvct.h - QMAKE_CXXFLAGS += --preinclude rvct.h } diff --git a/mkspecs/symbian-gcce/qmake.conf b/mkspecs/symbian-gcce/qmake.conf index 9eee43df15..1d1053c3eb 100644 --- a/mkspecs/symbian-gcce/qmake.conf +++ b/mkspecs/symbian-gcce/qmake.conf @@ -72,16 +72,16 @@ QMAKE_LFLAGS += --target1-abs \ QMAKE_LIBDIR += $${EPOCROOT}epoc32/release/armv5/udeb/ # g++ knows the path to the gcc-shipped-libs, ld doesn't. So cache the full path in the generate Makefile -QMAKE_GCC_SEARCH_DIRS =$$system($$QMAKE_CXX -print-search-dirs) -for(line, QMAKE_GCC_SEARCH_DIRS) { - contains(line, "libraries:") { - foundIt="1" - } else { - contains(foundIt, "1") { - QMAKE_LFLAGS += $$replace(line, "[=:]", " -L") - } - } +QMAKE_GCC_SEARCH_DIRS = $$system($$QMAKE_CXX -print-search-dirs) +QMAKE_GCC_SEARCH_DIRS = "$$join(QMAKE_GCC_SEARCH_DIRS, " ")" +QMAKE_GCC_SEARCH_DIRS = $$replace(QMAKE_GCC_SEARCH_DIRS, ".*libraries: *", "") +QMAKE_GCC_SEARCH_DIRS = $$replace(QMAKE_GCC_SEARCH_DIRS, "=", "") +contains(QMAKE_HOST.os,Windows) { + QMAKE_GCC_SEARCH_DIRS = $$split(QMAKE_GCC_SEARCH_DIRS, ;) +} else { + QMAKE_GCC_SEARCH_DIRS = $$split(QMAKE_GCC_SEARCH_DIRS, :) } +for(line, QMAKE_GCC_SEARCH_DIRS):QMAKE_LIBDIR += $$line QMAKE_LIBDIR += $${EPOCROOT}epoc32/release/armv5/lib diff --git a/mkspecs/unsupported/linux-armcc/qmake.conf b/mkspecs/unsupported/linux-armcc/qmake.conf new file mode 100644 index 0000000000..77891c3ff9 --- /dev/null +++ b/mkspecs/unsupported/linux-armcc/qmake.conf @@ -0,0 +1,32 @@ +# +# qmake configuration for linux-armcc +# + +MAKEFILE_GENERATOR = UNIX +TARGET_PLATFORM = unix +TEMPLATE = app +CONFIG += qt warn_on release incremental link_prl armcc_linker +QT += core gui +QMAKE_INCREMENTAL_STYLE = sublib + +include(../../common/linux.conf) +include(../../common/armcc.conf) +load(qt_config) + +# use armcc for linking since armlink doesn't understand the arm_linux_config_file option +QMAKE_LINK = armcc +QMAKE_LINK_SHLIB = armcc +QMAKE_LINK_C = armcc +QMAKE_LINK_C_SHLIB = armcc + +QMAKE_LFLAGS_SHLIB += --apcs=/fpic --shared +QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB + +QMAKE_LIBS += libstdc++.so librt.so + +CONFIG -= rvct_linker + +QMAKE_CFLAGS += --gnu --arm_linux --dllimport_runtime --thumb --cpu Cortex-A9 --arm_linux_config_file="$(HOME)/qt_rvct_config" --arm-linux-paths --apcs=/interwork --visibility_inlines_hidden --diag_suppress 1300,2523 +QMAKE_CXXFLAGS += $$QMAKE_CFLAGS --cpp + +QMAKE_LFLAGS += --diag_suppress 6331,6780,6439 --arm_linux_config_file="$(HOME)/qt_rvct_config" --arm-linux-paths diff --git a/mkspecs/unsupported/linux-armcc/qplatformdefs.h b/mkspecs/unsupported/linux-armcc/qplatformdefs.h new file mode 100644 index 0000000000..a1ce6a1468 --- /dev/null +++ b/mkspecs/unsupported/linux-armcc/qplatformdefs.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the qmake spec 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$ +** +****************************************************************************/ + +#ifndef QPLATFORMDEFS_H +#define QPLATFORMDEFS_H + +// Get Qt defines/settings + +#include "qglobal.h" + +// Set any POSIX/XOPEN defines at the top of this file to turn on specific APIs + +// 1) need to reset default environment if _BSD_SOURCE is defined +// 2) need to specify POSIX thread interfaces explicitly in glibc 2.0 +// 3) it seems older glibc need this to include the X/Open stuff +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include <unistd.h> + + +// We are hot - unistd.h should have turned on the specific APIs we requested + +#include <features.h> +#include <pthread.h> +#include <dirent.h> +#include <fcntl.h> +#include <grp.h> +#include <pwd.h> +#include <signal.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/ipc.h> +#include <sys/time.h> +#include <sys/shm.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <netinet/in.h> +#ifndef QT_NO_IPV6IFNAME +#include <net/if.h> +#endif + +#define QT_USE_XOPEN_LFS_EXTENSIONS +#include "../../common/posix/qplatformdefs.h" + +#undef QT_SOCKLEN_T + +#if defined(__GLIBC__) && (__GLIBC__ >= 2) +#define QT_SOCKLEN_T socklen_t +#else +#define QT_SOCKLEN_T int +#endif + +#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500) +#define QT_SNPRINTF ::snprintf +#define QT_VSNPRINTF ::vsnprintf +#endif + +#endif // QPLATFORMDEFS_H diff --git a/mkspecs/win32-g++/qmake.conf b/mkspecs/win32-g++/qmake.conf index 65ae590cfc..da657276b6 100644 --- a/mkspecs/win32-g++/qmake.conf +++ b/mkspecs/win32-g++/qmake.conf @@ -62,6 +62,8 @@ QMAKE_LFLAGS_WINDOWS = -Wl,-subsystem,windows QMAKE_LFLAGS_DLL = -shared QMAKE_LINK_OBJECT_MAX = 10 QMAKE_LINK_OBJECT_SCRIPT= object_script +QMAKE_PREFIX_STATICLIB = lib +QMAKE_EXTENSION_STATICLIB = a QMAKE_LIBS = diff --git a/qmake/generators/metamakefile.cpp b/qmake/generators/metamakefile.cpp index f0ab435fa6..ae48ddd3b0 100644 --- a/qmake/generators/metamakefile.cpp +++ b/qmake/generators/metamakefile.cpp @@ -489,6 +489,8 @@ MetaMakefileGenerator::createMakefileGenerator(QMakeProject *proj, bool noIO) mkfile = new SymbianSbsv2MakefileGenerator; } else if(gen == "SYMBIAN_UNIX") { mkfile = new SymbianMakefileTemplate<UnixMakefileGenerator>; + } else if(gen == "SYMBIAN_MINGW") { + mkfile = new SymbianMakefileTemplate<MingwMakefileGenerator>; } else { fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData()); } @@ -545,7 +547,7 @@ MetaMakefileGenerator::modesForGenerator(const QString &gen, } else if (gen == "PROJECTBUILDER" || gen == "XCODE") { *host_mode = Option::HOST_MACX_MODE; *target_mode = Option::TARG_MACX_MODE; - } else if (gen == "SYMBIAN_ABLD" || gen == "SYMBIAN_SBSV2" || gen == "SYMBIAN_UNIX") { + } else if (gen == "SYMBIAN_ABLD" || gen == "SYMBIAN_SBSV2" || gen == "SYMBIAN_UNIX" || gen == "SYMBIAN_MINGW") { #if defined(Q_OS_MAC) *host_mode = Option::HOST_MACX_MODE; #elif defined(Q_OS_UNIX) diff --git a/qmake/generators/symbian/symbiancommon.cpp b/qmake/generators/symbian/symbiancommon.cpp index 46b8cf5273..32b465b4bf 100644 --- a/qmake/generators/symbian/symbiancommon.cpp +++ b/qmake/generators/symbian/symbiancommon.cpp @@ -394,8 +394,7 @@ void SymbianCommonGenerator::generatePkgFile(const QString &iconFile, t << manufacturerStr << endl; } - // ### FIXME: remove epocBuild check once makefile based mkspecs support localized resource generation - if (epocBuild && symbianLocalizationList.size()) { + if (symbianLocalizationList.size()) { // Add localized resources to DEPLOYMENT if default resource deployment is done addLocalizedResourcesToDeployment("default_resource_deployment.files", symbianLocalizationList); addLocalizedResourcesToDeployment("default_reg_deployment.files", symbianLocalizationList); diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index 29d85f7142..e659e62288 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -148,6 +148,8 @@ UnixMakefileGenerator::init() project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + libdirs[i]; if (project->isActiveConfig("rvct_linker")) { project->values("QMAKE_LIBDIR_FLAGS") += "--userlibpath " + escapeFilePath(libdirs[i]); + } else if (project->isActiveConfig("armcc_linker")) { + project->values("QMAKE_LIBDIR_FLAGS") += "-L--userlibpath=" + escapeFilePath(libdirs[i]); } else { project->values("QMAKE_LIBDIR_FLAGS") += "-L" + escapeFilePath(libdirs[i]); } @@ -486,7 +488,7 @@ UnixMakefileGenerator::findLibraries() } else if(opt.startsWith("-l")) { if (!project->isEmpty("QMAKE_RVCT_LINKSTYLE")) { (*it) = opt.mid(2); - } else if (project->isActiveConfig("rvct_linker")) { + } else if (project->isActiveConfig("rvct_linker") || project->isActiveConfig("armcc_linker")) { (*it) = "lib" + opt.mid(2) + ".so"; } else { stub = opt.mid(2); diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index a450f04b99..26393325c9 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -202,8 +202,31 @@ void createArObjectScriptFile(const QString &fileName, const QString &target, co } } +void createRvctObjectScriptFile(const QString &fileName, const QStringList &objList) +{ + QString filePath = Option::output_dir + QDir::separator() + fileName; + QFile file(filePath); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream t(&file); + for (QStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) { + if (QDir::isRelativePath(*it)) + t << "./" << *it << endl; + else + t << *it << endl; + } + t.flush(); + file.close(); + } +} + void MingwMakefileGenerator::writeMingwParts(QTextStream &t) { + if (!project->isEmpty("QMAKE_SYMBIAN_SHLIB")) { + t << "vpath %.dso " << project->values("QMAKE_LIBDIR").join(";") << endl; + t << "vpath %.lib " << project->values("QMAKE_LIBDIR").join(";") << endl; + t << "\n\n"; + } + writeStandardParts(t); if (!preCompHeaderOut.isEmpty()) { @@ -270,7 +293,7 @@ void MingwMakefileGenerator::init() if(configs.indexOf("qt") == -1) configs.append("qt"); - if(project->isActiveConfig("dll")) { + if(project->isActiveConfig("dll") && project->values("QMAKE_SYMBIAN_SHLIB").isEmpty()) { QString destDir = ""; if(!project->first("DESTDIR").isEmpty()) destDir = Option::fixPathToTargetOS(project->first("DESTDIR") + Option::dir_sep, false, false); @@ -279,7 +302,7 @@ void MingwMakefileGenerator::init() project->values("QMAKE_LFLAGS").append(QString("-Wl,--out-implib,") + project->first("MINGW_IMPORT_LIB")); } - if(!project->values("DEF_FILE").isEmpty()) + if(!project->values("DEF_FILE").isEmpty() && project->values("QMAKE_SYMBIAN_SHLIB").isEmpty()) project->values("QMAKE_LFLAGS").append(QString("-Wl,") + project->first("DEF_FILE")); MakefileGenerator::init(); @@ -315,12 +338,9 @@ void MingwMakefileGenerator::init() void MingwMakefileGenerator::fixTargetExt() { if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") { - project->values("TARGET_EXT").append(".a"); project->values("QMAKE_LFLAGS").append("-static"); - project->values("TARGET").first() = "lib" + project->first("TARGET"); - } else { - Win32MakefileGenerator::fixTargetExt(); } + Win32MakefileGenerator::fixTargetExt(); } void MingwMakefileGenerator::writeIncPart(QTextStream &t) @@ -348,17 +368,28 @@ void MingwMakefileGenerator::writeLibsPart(QTextStream &t) t << "LIBS = "; if(!project->values("QMAKE_LIBDIR").isEmpty()) writeLibDirPart(t); - t << var("QMAKE_LIBS").replace(QRegExp("(\\slib|^lib)")," -l") << ' ' - << var("QMAKE_LIBS_PRIVATE").replace(QRegExp("(\\slib|^lib)")," -l") << endl; + if (project->isActiveConfig("rvct_linker")) { + t << var("QMAKE_LIBS") << ' ' + << var("QMAKE_LIBS_PRIVATE") << endl; + } else { + t << var("QMAKE_LIBS").replace(QRegExp("(\\slib|^lib)")," -l") << ' ' + << var("QMAKE_LIBS_PRIVATE").replace(QRegExp("(\\slib|^lib)")," -l") << endl; + } } } void MingwMakefileGenerator::writeLibDirPart(QTextStream &t) { QStringList libDirs = project->values("QMAKE_LIBDIR"); - for (int i = 0; i < libDirs.size(); ++i) + QString libArg = QString::fromLatin1("-L"); + if (project->isActiveConfig("rvct_linker")) + libArg = QString::fromLatin1("--userlibpath "); + for (int i = 0; i < libDirs.size(); ++i) { libDirs[i].remove("\""); - t << valGlue(libDirs,"-L"+quote,quote+" -L" +quote,quote) << " "; + if (libDirs[i].endsWith("\\")) + libDirs[i].chop(1); + } + t << valGlue(libDirs, libArg+quote, quote+" "+libArg+quote, quote) << " "; } void MingwMakefileGenerator::writeObjectsPart(QTextStream &t) @@ -370,20 +401,33 @@ void MingwMakefileGenerator::writeObjectsPart(QTextStream &t) if (!var("BUILD_NAME").isEmpty()) { ar_script_file += "." + var("BUILD_NAME"); } - createArObjectScriptFile(ar_script_file, var("DEST_TARGET"), project->values("OBJECTS")); // QMAKE_LIB is used for win32, including mingw, whereas QMAKE_AR is used on Unix. - // Strip off any options since the ar commands will be read from file. - QString ar_cmd = var("QMAKE_LIB").section(" ", 0, 0);; - if (ar_cmd.isEmpty()) - ar_cmd = "ar"; - objectsLinkLine = ar_cmd + " -M < " + ar_script_file; + if (project->isActiveConfig("rvct_linker")) { + createRvctObjectScriptFile(ar_script_file, project->values("OBJECTS")); + QString ar_cmd = project->values("QMAKE_LIB").join(" "); + if (ar_cmd.isEmpty()) + ar_cmd = "armar --create"; + objectsLinkLine = ar_cmd + " " + var("DEST_TARGET") + " --via " + ar_script_file; + } else { + // Strip off any options since the ar commands will be read from file. + QString ar_cmd = var("QMAKE_LIB").section(" ", 0, 0);; + if (ar_cmd.isEmpty()) + ar_cmd = "ar"; + createArObjectScriptFile(ar_script_file, var("DEST_TARGET"), project->values("OBJECTS")); + objectsLinkLine = ar_cmd + " -M < " + ar_script_file; + } } else { QString ld_script_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET"); if (!var("BUILD_NAME").isEmpty()) { ld_script_file += "." + var("BUILD_NAME"); } - createLdObjectScriptFile(ld_script_file, project->values("OBJECTS")); - objectsLinkLine = ld_script_file; + if (project->isActiveConfig("rvct_linker")) { + createRvctObjectScriptFile(ld_script_file, project->values("OBJECTS")); + objectsLinkLine = QString::fromLatin1("--via ") + ld_script_file; + } else { + createLdObjectScriptFile(ld_script_file, project->values("OBJECTS")); + objectsLinkLine = ld_script_file; + } } Win32MakefileGenerator::writeObjectsPart(t); } diff --git a/qmake/generators/win32/mingw_make.h b/qmake/generators/win32/mingw_make.h index 007b48b2f4..5bc9c7b3b4 100644 --- a/qmake/generators/win32/mingw_make.h +++ b/qmake/generators/win32/mingw_make.h @@ -54,17 +54,17 @@ public: protected: QString escapeDependencyPath(const QString &path) const; QString getLibTarget(); + bool writeMakefile(QTextStream &); + void init(); private: bool isWindowsShell() const; void writeMingwParts(QTextStream &); void writeIncPart(QTextStream &t); void writeLibsPart(QTextStream &t); void writeLibDirPart(QTextStream &t); - bool writeMakefile(QTextStream &); void writeObjectsPart(QTextStream &t); void writeBuildRulesPart(QTextStream &t); void writeRcFilePart(QTextStream &t); - void init(); void processPrlVariable(const QString &var, const QStringList &l); QStringList &findDependencies(const QString &file); diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index e0a370ce16..603ffb5493 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -314,7 +314,8 @@ void Win32MakefileGenerator::processVars() // TARGET_VERSION_EXT will be used to add a version number onto the target name if (project->values("TARGET_VERSION_EXT").isEmpty() - && !project->values("VER_MAJ").isEmpty()) + && !project->values("VER_MAJ").isEmpty() + && project->values("QMAKE_SYMBIAN_SHLIB").isEmpty()) project->values("TARGET_VERSION_EXT").append(project->values("VER_MAJ").first()); if(project->isEmpty("QMAKE_COPY_FILE")) @@ -342,16 +343,43 @@ void Win32MakefileGenerator::processVars() if(!(*libDir_it).isEmpty()) (*libDir_it) = Option::fixPathToTargetOS((*libDir_it), false, false); } + + if (project->values("TEMPLATE").contains("app")) { + project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_APP"); + project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_APP"); + project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_APP"); + } else if (project->values("TEMPLATE").contains("lib") && project->isActiveConfig("dll")) { + if(!project->isActiveConfig("plugin") || !project->isActiveConfig("plugin_no_share_shlib_cflags")) { + project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_SHLIB"); + project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_SHLIB"); + } + if (project->isActiveConfig("plugin")) { + project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_PLUGIN"); + project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_PLUGIN"); + project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PLUGIN"); + } else { + project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SHLIB"); + } + } } void Win32MakefileGenerator::fixTargetExt() { - if (!project->values("QMAKE_APP_FLAG").isEmpty()) + if (project->isEmpty("QMAKE_EXTENSION_STATICLIB")) + project->values("QMAKE_EXTENSION_STATICLIB").append("lib"); + if (project->isEmpty("QMAKE_EXTENSION_SHLIB")) + project->values("QMAKE_EXTENSION_SHLIB").append("dll"); + + if (!project->values("QMAKE_APP_FLAG").isEmpty()) { project->values("TARGET_EXT").append(".exe"); - else if (project->isActiveConfig("shared")) - project->values("TARGET_EXT").append(project->first("TARGET_VERSION_EXT") + ".dll"); - else - project->values("TARGET_EXT").append(".lib"); + } else if (project->isActiveConfig("shared")) { + project->values("TARGET_EXT").append(project->first("TARGET_VERSION_EXT") + "." + + project->first("QMAKE_EXTENSION_SHLIB")); + project->values("TARGET").first() = project->first("QMAKE_PREFIX_SHLIB") + project->first("TARGET"); + } else { + project->values("TARGET_EXT").append("." + project->first("QMAKE_EXTENSION_STATICLIB")); + project->values("TARGET").first() = project->first("QMAKE_PREFIX_STATICLIB") + project->first("TARGET"); + } } void Win32MakefileGenerator::processRcFileVar() diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri index 8eae391e5c..83caa96840 100644 --- a/src/corelib/global/global.pri +++ b/src/corelib/global/global.pri @@ -23,7 +23,7 @@ INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global # Only used on platforms with CONFIG += precompile_header PRECOMPILED_HEADER = global/qt_pch.h -linux*:!static:!symbian-armcc:!symbian-gcce { +linux*:!static:!symbian-gcce:!*-armcc* { QMAKE_LFLAGS += -Wl,-e,qt_core_boilerplate prog=$$quote(if (/program interpreter: (.*)]/) { print $1; }) DEFINES += ELF_INTERPRETER=\\\"$$system(readelf -l /bin/ls | perl -n -e \'$$prog\')\\\" diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 2a41b9e386..960fe6e90f 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -448,6 +448,9 @@ namespace QT_NAMESPACE {} # if __TARGET_ARCH_ARM >= 6 # define QT_HAVE_ARMV6 # endif +/* work-around for missing compiler intrinsics */ +# define __is_empty(X) false +# define __is_pod(X) false #elif defined(__GNUC__) # define Q_CC_GNU # define Q_C_CALLBACKS @@ -1199,6 +1202,11 @@ class QDataStream; #define QT_SUPPORTS(FEATURE) (!defined(QT_NO_##FEATURE)) +#if defined(Q_OS_LINUX) && defined(Q_CC_RVCT) +# define Q_DECL_EXPORT __attribute__((visibility("default"))) +# define Q_DECL_IMPORT __attribute__((visibility("default"))) +#endif + #ifndef Q_DECL_EXPORT # if defined(Q_OS_WIN) || defined(Q_CC_NOKIAX86) || defined(Q_CC_RVCT) # define Q_DECL_EXPORT __declspec(dllexport) diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp index 9446ebb805..cf19224360 100644 --- a/src/corelib/io/qfilesystemengine.cpp +++ b/src/corelib/io/qfilesystemengine.cpp @@ -168,7 +168,7 @@ static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &ent const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator)); for (int i = 0; i < paths.count(); i++) { - entry = QFileSystemEntry(paths.at(i) % QLatin1Char('/') % filePath.mid(prefixSeparator + 1)); + entry = QFileSystemEntry(QDir::cleanPath(paths.at(i) % QLatin1Char('/') % filePath.mid(prefixSeparator + 1))); // Recurse! if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true)) return true; diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 6acd811750..030be1b382 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -174,8 +174,9 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, if (entry.isEmpty() || entry.isRoot()) return entry; -#ifdef __UCLIBC__ - return QFileSystemEntry::slowCanonicalName(entry); +#if !defined(Q_OS_MAC) && _POSIX_VERSION < 200809L + // realpath(X,0) is not supported + return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath())); #else char *ret = 0; # if defined(Q_OS_MAC) && !defined(QT_NO_CORESERVICES) @@ -533,8 +534,7 @@ bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSyst { Q_UNUSED(source); Q_UNUSED(target); - // # we can implement this using sendfile(2) - //when this function returns false, block copy is used in QFile which sets the error code. + error = QSystemError(ENOSYS, QSystemError::StandardLibraryError); //Function not implemented return false; } diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp index e78f86af32..d213b0e968 100644 --- a/src/corelib/kernel/qeventloop.cpp +++ b/src/corelib/kernel/qeventloop.cpp @@ -175,6 +175,8 @@ bool QEventLoop::processEvents(ProcessEventsFlags flags) int QEventLoop::exec(ProcessEventsFlags flags) { Q_D(QEventLoop); + //we need to protect from race condition with QThread::exit + QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex); if (d->threadData->quitNow) return -1; @@ -186,6 +188,7 @@ int QEventLoop::exec(ProcessEventsFlags flags) d->exit = false; ++d->threadData->loopLevel; d->threadData->eventLoops.push(this); + locker.unlock(); // remove posted quit events when entering a new event loop QCoreApplication *app = QCoreApplication::instance(); @@ -205,6 +208,7 @@ int QEventLoop::exec(ProcessEventsFlags flags) "reimplement QApplication::notify() and catch all exceptions there.\n"); // copied from below + locker.relock(); QEventLoop *eventLoop = d->threadData->eventLoops.pop(); Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error"); Q_UNUSED(eventLoop); // --release warning @@ -216,6 +220,7 @@ int QEventLoop::exec(ProcessEventsFlags flags) #endif // copied above + locker.relock(); QEventLoop *eventLoop = d->threadData->eventLoops.pop(); Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error"); Q_UNUSED(eventLoop); // --release warning diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index 5a7ee2f1d1..0ad73f5fe9 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -370,18 +370,18 @@ template <class T> inline T qobject_cast(QObject *object) { #if !defined(QT_NO_QOBJECT_CHECK) - reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(object)); + reinterpret_cast<T>(object)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(object)); #endif - return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast(object)); + return static_cast<T>(reinterpret_cast<T>(object)->staticMetaObject.cast(object)); } template <class T> inline T qobject_cast(const QObject *object) { #if !defined(QT_NO_QOBJECT_CHECK) - reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(const_cast<QObject *>(object))); + reinterpret_cast<T>(object)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(const_cast<QObject *>(object))); #endif - return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast(object)); + return static_cast<T>(reinterpret_cast<T>(object)->staticMetaObject.cast(object)); } diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 1be32ad531..c0b947ad19 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -155,9 +155,11 @@ void QFactoryLoader::update() continue; } QObject *instance = library->instance(); - if (!instance) + if (!instance) { + library->release(); // ignore plugins that have a valid signature but cannot be loaded. continue; + } QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instance); if (instance && factory && instance->qt_metacast(d->iid)) keys = factory->keys(); diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index dfe4aae183..5f75195b4e 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -163,6 +163,7 @@ class QMutexData ~QMutexData(); }; +#ifdef QT_NO_DEBUG inline void QMutex::unlockInline() { if (d->recursive) { @@ -189,7 +190,13 @@ inline void QMutex::lockInline() lockInternal(); } } - +#else // QT_NO_DEBUG +//in debug we do not use inline calls in order to allow debugging tools +// to hook the mutex locking functions. +inline void QMutex::unlockInline() { unlock(); } +inline bool QMutex::tryLockInline() { return tryLock(); } +inline void QMutex::lockInline() { lock(); } +#endif // QT_NO_DEBUG #else // QT_NO_THREAD diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 9a2dbec01c..36e07c0285 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -209,8 +209,6 @@ public: bool canWait; QVector<void *> tls; - QMutex mutex; - # ifdef Q_OS_SYMBIAN RThread symbian_thread_handle; # endif diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 0766447fd4..5e0d2a2ee7 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -110,6 +110,17 @@ QT_BEGIN_NAMESPACE enum { ThreadPriorityResetFlag = 0x80000000 }; +#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL)) +#define HAVE_TLS +#endif +#if defined(Q_CC_XLC) || defined (Q_CC_SUN) +#define HAVE_TLS +#endif + +#ifdef HAVE_TLS +static __thread QThreadData *currentThreadData = 0; +#endif + static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT; static pthread_key_t current_thread_data_key; @@ -157,7 +168,9 @@ Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key) // that pthread has, so pthread_setspecific is also used. static QThreadData *get_thread_data() { -#ifdef Q_OS_SYMBIAN +#ifdef HAVE_TLS + return currentThreadData; +#elif defined Q_OS_SYMBIAN return reinterpret_cast<QThreadData *>(Dll::Tls()); #else pthread_once(¤t_thread_data_once, create_current_thread_data_key); @@ -167,7 +180,9 @@ static QThreadData *get_thread_data() static void set_thread_data(QThreadData *data) { -#ifdef Q_OS_SYMBIAN +#ifdef HAVE_TLS + currentThreadData = data; +#elif defined Q_OS_SYMBIAN qt_symbian_throwIfError(Dll::SetTls(data)); #endif pthread_once(¤t_thread_data_once, create_current_thread_data_key); @@ -176,7 +191,9 @@ static void set_thread_data(QThreadData *data) static void clear_thread_data() { -#ifdef Q_OS_SYMBIAN +#ifdef HAVE_TLS + currentThreadData = 0; +#elif defined Q_OS_SYMBIAN Dll::FreeTls(); #endif pthread_setspecific(current_thread_data_key, 0); @@ -310,7 +327,10 @@ void *QThreadPrivate::start(void *arg) set_thread_data(data); data->ref(); - data->quitNow = false; + { + QMutexLocker locker(&thr->d_func()->mutex); + data->quitNow = thr->d_func()->exited; + } // ### TODO: allow the user to create a custom event dispatcher createEventDispatcher(data); diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index cb2d1a94dc..6b7932bbdc 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -298,7 +298,10 @@ unsigned int __stdcall QThreadPrivate::start(void *arg) QThread::setTerminationEnabled(false); - data->quitNow = false; + { + QMutexLocker locker(&thr->d_func()->mutex); + data->quitNow = thr->d_func()->exited; + } // ### TODO: allow the user to create a custom event dispatcher createEventDispatcher(data); diff --git a/src/corelib/tools/qscopedvaluerollback.cpp b/src/corelib/tools/qscopedvaluerollback.cpp new file mode 100644 index 0000000000..8933efc180 --- /dev/null +++ b/src/corelib/tools/qscopedvaluerollback.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module 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 "qscopedvaluerollback.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QScopedValueRollback + \brief The QScopedValueRollback resets a variable to its previous value on destruction + \since 4.8 + \ingroup misc + + The QScopedAssignment class can be used to revert state when an + exception is thrown without needing to write try-catch blocks. + + It can also be used to manage variables that are temporarily set, + such as reentrancy guards. By using this class, the variable will + be reset whether the function is exited normally, exited early by + a return statement, or exited by an exception. + + The template can only be instantiated with a type that supports assignment. + + \sa QScopedPointer +*/ + +/*! + \fn QScopedValueRollback::QScopedValueRollback(T &var) + + Stores the previous value of var internally, for revert on destruction. +*/ + +/*! + \fn QScopedValueRollback::~QScopedValueRollback() + + Assigns the previous value to the managed variable. + This is the value at construction time, or at the last call to commit() +*/ + +/*! + \fn void QScopedValueRollback::commit() + + Updates the previous value of the managed variable to its current value. +*/ + +QT_END_NAMESPACE diff --git a/src/network/access/qnetworkaccessdatabackend_p.h b/src/corelib/tools/qscopedvaluerollback.h index 18569ecfe4..e874428b3c 100644 --- a/src/network/access/qnetworkaccessdatabackend_p.h +++ b/src/corelib/tools/qscopedvaluerollback.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtNetwork module of the Qt Toolkit. +** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -39,46 +39,43 @@ ** ****************************************************************************/ -#ifndef QNETWORKACCESSDATABACKEND_P_H -#define QNETWORKACCESSDATABACKEND_P_H +#ifndef QSCOPEDVALUEROLLBACK_H +#define QSCOPEDVALUEROLLBACK_H -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the Network Access API. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include "qnetworkaccessbackend_p.h" +#include <QtCore/qglobal.h> +QT_BEGIN_HEADER QT_BEGIN_NAMESPACE +QT_MODULE(Core) -class QNetworkAccessDataBackend: public QNetworkAccessBackend +template <typename T> +class QScopedValueRollback { public: - QNetworkAccessDataBackend(); - virtual ~QNetworkAccessDataBackend(); + QScopedValueRollback(T &var) : + varRef(var) + { + oldValue = varRef; + } - virtual void open(); - virtual void closeDownstreamChannel(); - virtual void closeUpstreamChannel(); - virtual bool waitForDownstreamReadyRead(int msecs); - virtual bool waitForUpstreamBytesWritten(int msecs); + ~QScopedValueRollback() + { + varRef = oldValue; + } - virtual bool processRequestSynchronously(); -}; + void commit() + { + oldValue = varRef; + } -class QNetworkAccessDataBackendFactory: public QNetworkAccessBackendFactory -{ -public: - virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, - const QNetworkRequest &request) const; +private: + T& varRef; + T oldValue; + + Q_DISABLE_COPY(QScopedValueRollback) }; QT_END_NAMESPACE +QT_END_HEADER -#endif +#endif // QSCOPEDVALUEROLLBACK_H diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 03bb32d8e1..9d564a108b 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -29,6 +29,9 @@ HEADERS += \ tools/qrect.h \ tools/qregexp.h \ tools/qringbuffer_p.h \ + tools/qscopedpointer.h \ + tools/qscopedpointer_p.h \ + tools/qscopedvaluerollback.h \ tools/qshareddata.h \ tools/qsharedpointer.h \ tools/qsharedpointer_impl.h \ @@ -45,9 +48,7 @@ HEADERS += \ tools/qelapsedtimer.h \ tools/qunicodetables_p.h \ tools/qvarlengtharray.h \ - tools/qvector.h \ - tools/qscopedpointer.h \ - tools/qscopedpointer_p.h + tools/qvector.h SOURCES += \ diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index eb9c7edfa9..6e7b9a7478 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1547,6 +1547,8 @@ void qt_init(QApplicationPrivate * /* priv */, int) repository = 0; #endif + qt_keymapper_private()->updateInputLanguage(); + #ifdef QT_KEYPAD_NAVIGATION if (touch) { QApplicationPrivate::navigationMode = Qt::NavigationModeNone; @@ -2094,6 +2096,13 @@ int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent } break; #endif + +#ifdef Q_WS_S60 + case KEikInputLanguageChange: + qt_keymapper_private()->updateInputLanguage(); + break; +#endif + default: break; } diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index fbb4920a9a..589b12e99e 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -5227,14 +5227,15 @@ bool QETWidget::translateConfigEvent(const XEvent *event) bool trust = isVisible() && (d->topData()->parentWinId == XNone || d->topData()->parentWinId == QX11Info::appRootWindow()); + bool isCPos = false; if (event->xconfigure.send_event || trust) { // if a ConfigureNotify comes from a real sendevent request, we can // trust its values. newCPos.rx() = event->xconfigure.x + event->xconfigure.border_width; newCPos.ry() = event->xconfigure.y + event->xconfigure.border_width; + isCPos = true; } - if (isVisible()) QApplication::syncX(); @@ -5260,6 +5261,7 @@ bool QETWidget::translateConfigEvent(const XEvent *event) otherEvent.xconfigure.border_width; newCPos.ry() = otherEvent.xconfigure.y + otherEvent.xconfigure.border_width; + isCPos = true; } } #ifndef QT_NO_XSYNC @@ -5272,6 +5274,19 @@ bool QETWidget::translateConfigEvent(const XEvent *event) #endif // QT_NO_XSYNC } + if (!isCPos) { + // we didn't get an updated position of the toplevel. + // either we haven't moved or there is a bug in the window manager. + // anyway, let's query the position to be certain. + int x, y; + Window child; + XTranslateCoordinates(X11->display, internalWinId(), + QApplication::desktop()->screen(d->xinfo.screen())->internalWinId(), + 0, 0, &x, &y, &child); + newCPos.rx() = x; + newCPos.ry() = y; + } + QRect cr (geometry()); if (newCPos != cr.topLeft()) { // compare with cpos (exluding frame) QPoint oldPos = geometry().topLeft(); @@ -5314,18 +5329,6 @@ bool QETWidget::translateConfigEvent(const XEvent *event) } if (wasResize) { - static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); - if (d->extra->compress_events && !slowResize && !data->in_show && isVisible()) { - QApplication::syncX(); - XEvent otherEvent; - while (XCheckTypedWindowEvent(X11->display, internalWinId(), ConfigureNotify, &otherEvent) - && !qt_x11EventFilter(&otherEvent) && !x11Event(&otherEvent) - && otherEvent.xconfigure.event == otherEvent.xconfigure.window) { - data->crect.setWidth(otherEvent.xconfigure.width); - data->crect.setHeight(otherEvent.xconfigure.height); - } - } - if (isVisible() && data->crect.size() != oldSize) { Q_ASSERT(d->extra->topextra); QWidgetBackingStore *bs = d->extra->topextra->backingStore.data(); @@ -5334,7 +5337,7 @@ bool QETWidget::translateConfigEvent(const XEvent *event) // resize optimization in order to get invalidated regions for resized widgets. // The optimization discards all invalidateBuffer() calls since we're going to // repaint everything anyways, but that's not the case with static contents. - if (!slowResize && !hasStaticContents) + if (!hasStaticContents) d->extra->topextra->inTopLevelResize = true; QResizeEvent e(data->crect.size(), oldSize); QApplication::sendSpontaneousEvent(this, &e); diff --git a/src/gui/kernel/qkeymapper_p.h b/src/gui/kernel/qkeymapper_p.h index 7a7c6a5f5f..ec2d8492fe 100644 --- a/src/gui/kernel/qkeymapper_p.h +++ b/src/gui/kernel/qkeymapper_p.h @@ -213,6 +213,7 @@ public: int mapS60ScanCodesToQt(TUint s60key); int mapQtToS60Key(int qtKey); int mapQtToS60ScanCodes(int qtKey); + void updateInputLanguage(); #endif }; diff --git a/src/gui/kernel/qkeymapper_s60.cpp b/src/gui/kernel/qkeymapper_s60.cpp index f0b17ac3b0..bcf32a5e78 100644 --- a/src/gui/kernel/qkeymapper_s60.cpp +++ b/src/gui/kernel/qkeymapper_s60.cpp @@ -40,7 +40,11 @@ ****************************************************************************/ #include "private/qkeymapper_p.h" +#include <private/qcore_symbian_p.h> #include <e32keys.h> +#include <e32cmn.h> +#include <centralrepository.h> +#include <biditext.h> QT_BEGIN_NAMESPACE @@ -214,4 +218,32 @@ int QKeyMapperPrivate::mapQtToS60ScanCodes(int qtKey) } return res; } + +void QKeyMapperPrivate::updateInputLanguage() +{ +#ifdef Q_WS_S60 + TInt err; + CRepository *repo; + const TUid KCRUidAknFep = TUid::Uid(0x101F876D); + const TUint32 KAknFepInputTxtLang = 0x00000005; + TRAP(err, repo = CRepository::NewL(KCRUidAknFep)); + if (err != KErrNone) + return; + + TInt symbianLang; + err = repo->Get(KAknFepInputTxtLang, symbianLang); + delete repo; + if (err != KErrNone) + return; + + QString qtLang = QString::fromAscii(qt_symbianLocaleName(symbianLang)); + keyboardInputLocale = QLocale(qtLang); + keyboardInputDirection = (TBidiText::ScriptDirectionality(TLanguage(symbianLang)) == TBidiText::ERightToLeft) + ? Qt::RightToLeft : Qt::LeftToRight; +#else + keyboardInputLocale = QLocale(); + keyboardInputDirection = Qt::LeftToRight; +#endif +} + QT_END_NAMESPACE diff --git a/src/gui/widgets/qsizegrip.cpp b/src/gui/widgets/qsizegrip.cpp index f2ea1bfe89..630aecfc09 100644 --- a/src/gui/widgets/qsizegrip.cpp +++ b/src/gui/widgets/qsizegrip.cpp @@ -309,6 +309,7 @@ void QSizeGrip::mousePressEvent(QMouseEvent * e) #ifdef Q_WS_X11 // Use a native X11 sizegrip for "real" top-level windows if supported. if (tlw->isWindow() && X11->isSupportedByWM(ATOM(_NET_WM_MOVERESIZE)) + && !(tlw->windowFlags() & Qt::X11BypassWindowManagerHint) && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !qt_widget_private(tlw)->hasHeightForWidth()) { XEvent xev; xev.xclient.type = ClientMessage; @@ -420,7 +421,8 @@ void QSizeGrip::mouseMoveEvent(QMouseEvent * e) #ifdef Q_WS_X11 if (tlw->isWindow() && X11->isSupportedByWM(ATOM(_NET_WM_MOVERESIZE)) - && tlw->isTopLevel() && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !qt_widget_private(tlw)->hasHeightForWidth()) + && tlw->isTopLevel() && !(tlw->windowFlags() & Qt::X11BypassWindowManagerHint) + && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !qt_widget_private(tlw)->hasHeightForWidth()) return; #endif #ifdef Q_WS_WIN diff --git a/src/network/access/access.pri b/src/network/access/access.pri index f8dfda6ff3..7497c1aa6e 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -8,6 +8,7 @@ HEADERS += \ access/qhttpnetworkreply_p.h \ access/qhttpnetworkconnection_p.h \ access/qhttpnetworkconnectionchannel_p.h \ + access/qnetworkaccessauthenticationmanager_p.h \ access/qnetworkaccessmanager.h \ access/qnetworkaccessmanager_p.h \ access/qnetworkaccesscache_p.h \ @@ -42,6 +43,7 @@ SOURCES += \ access/qhttpnetworkreply.cpp \ access/qhttpnetworkconnection.cpp \ access/qhttpnetworkconnectionchannel.cpp \ + access/qnetworkaccessauthenticationmanager.cpp \ access/qnetworkaccessmanager.cpp \ access/qnetworkaccesscache.cpp \ access/qnetworkaccessbackend.cpp \ diff --git a/src/network/access/qnetworkaccessauthenticationmanager.cpp b/src/network/access/qnetworkaccessauthenticationmanager.cpp new file mode 100644 index 0000000000..d2bf00accf --- /dev/null +++ b/src/network/access/qnetworkaccessauthenticationmanager.cpp @@ -0,0 +1,297 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtNetwork module 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 "qnetworkaccessmanager.h" +#include "qnetworkaccessmanager_p.h" +#include "qnetworkaccessauthenticationmanager_p.h" + +#include "QtCore/qbuffer.h" +#include "QtCore/qurl.h" +#include "QtCore/qvector.h" +#include "QtCore/QMutexLocker" +#include "QtNetwork/qauthenticator.h" + +QT_BEGIN_NAMESPACE + + + + +class QNetworkAuthenticationCache: private QVector<QNetworkAuthenticationCredential>, + public QNetworkAccessCache::CacheableObject +{ +public: + QNetworkAuthenticationCache() + { + setExpires(false); + setShareable(true); + reserve(1); + } + + QNetworkAuthenticationCredential *findClosestMatch(const QString &domain) + { + iterator it = qLowerBound(begin(), end(), domain); + if (it == end() && !isEmpty()) + --it; + if (it == end() || !domain.startsWith(it->domain)) + return 0; + return &*it; + } + + void insert(const QString &domain, const QString &user, const QString &password) + { + QNetworkAuthenticationCredential *closestMatch = findClosestMatch(domain); + if (closestMatch && closestMatch->domain == domain) { + // we're overriding the current credentials + closestMatch->user = user; + closestMatch->password = password; + } else { + QNetworkAuthenticationCredential newCredential; + newCredential.domain = domain; + newCredential.user = user; + newCredential.password = password; + + if (closestMatch) + QVector<QNetworkAuthenticationCredential>::insert(++closestMatch, newCredential); + else + QVector<QNetworkAuthenticationCredential>::insert(end(), newCredential); + } + } + + virtual void dispose() { delete this; } +}; + +#ifndef QT_NO_NETWORKPROXY +static QByteArray proxyAuthenticationKey(const QNetworkProxy &proxy, const QString &realm) +{ + QUrl key; + + switch (proxy.type()) { + case QNetworkProxy::Socks5Proxy: + key.setScheme(QLatin1String("proxy-socks5")); + break; + + case QNetworkProxy::HttpProxy: + case QNetworkProxy::HttpCachingProxy: + key.setScheme(QLatin1String("proxy-http")); + break; + + case QNetworkProxy::FtpCachingProxy: + key.setScheme(QLatin1String("proxy-ftp")); + break; + + case QNetworkProxy::DefaultProxy: + case QNetworkProxy::NoProxy: + // shouldn't happen + return QByteArray(); + + // no default: + // let there be errors if a new proxy type is added in the future + } + + if (key.scheme().isEmpty()) + // proxy type not handled + return QByteArray(); + + key.setUserName(proxy.user()); + key.setHost(proxy.hostName()); + key.setPort(proxy.port()); + key.setFragment(realm); + return "auth:" + key.toEncoded(); +} +#endif + +static inline QByteArray authenticationKey(const QUrl &url, const QString &realm) +{ + QUrl copy = url; + copy.setFragment(realm); + return "auth:" + copy.toEncoded(QUrl::RemovePassword | QUrl::RemovePath | QUrl::RemoveQuery); +} + + +#ifndef QT_NO_NETWORKPROXY +void QNetworkAccessAuthenticationManager::cacheProxyCredentials(const QNetworkProxy &p, + const QAuthenticator *authenticator) +{ + Q_ASSERT(authenticator); + Q_ASSERT(p.type() != QNetworkProxy::DefaultProxy); + Q_ASSERT(p.type() != QNetworkProxy::NoProxy); + + QMutexLocker mutexLocker(&mutex); + + QString realm = authenticator->realm(); + QNetworkProxy proxy = p; + proxy.setUser(authenticator->user()); + // Set two credentials: one with the username and one without + do { + // Set two credentials actually: one with and one without the realm + do { + QByteArray cacheKey = proxyAuthenticationKey(proxy, realm); + if (cacheKey.isEmpty()) + return; // should not happen + + QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache; + auth->insert(QString(), authenticator->user(), authenticator->password()); + authenticationCache.addEntry(cacheKey, auth); // replace the existing one, if there's any + + if (realm.isEmpty()) { + break; + } else { + realm.clear(); + } + } while (true); + + if (proxy.user().isEmpty()) + break; + else + proxy.setUser(QString()); + } while (true); +} + +QNetworkAuthenticationCredential +QNetworkAccessAuthenticationManager::fetchCachedProxyCredentials(const QNetworkProxy &p, + const QAuthenticator *authenticator) +{ + QNetworkProxy proxy = p; + if (proxy.type() == QNetworkProxy::DefaultProxy) { + proxy = QNetworkProxy::applicationProxy(); + } + if (!proxy.password().isEmpty()) + return QNetworkAuthenticationCredential(); // no need to set credentials if it already has them + + QString realm; + if (authenticator) + realm = authenticator->realm(); + + QMutexLocker mutexLocker(&mutex); + QByteArray cacheKey = proxyAuthenticationKey(proxy, realm); + if (cacheKey.isEmpty()) + return QNetworkAuthenticationCredential(); + if (!authenticationCache.hasEntry(cacheKey)) + return QNetworkAuthenticationCredential(); + + QNetworkAuthenticationCache *auth = + static_cast<QNetworkAuthenticationCache *>(authenticationCache.requestEntryNow(cacheKey)); + QNetworkAuthenticationCredential cred = *auth->findClosestMatch(QString()); + authenticationCache.releaseEntry(cacheKey); + + // proxy cache credentials always have exactly one item + Q_ASSERT_X(!cred.isNull(), "QNetworkAccessManager", + "Internal inconsistency: found a cache key for a proxy, but it's empty"); + return cred; +} + +#endif + +void QNetworkAccessAuthenticationManager::cacheCredentials(const QUrl &url, + const QAuthenticator *authenticator) +{ + Q_ASSERT(authenticator); + QString domain = QString::fromLatin1("/"); // FIXME: make QAuthenticator return the domain + QString realm = authenticator->realm(); + + QMutexLocker mutexLocker(&mutex); + + // Set two credentials actually: one with and one without the username in the URL + QUrl copy = url; + copy.setUserName(authenticator->user()); + do { + QByteArray cacheKey = authenticationKey(copy, realm); + if (authenticationCache.hasEntry(cacheKey)) { + QNetworkAuthenticationCache *auth = + static_cast<QNetworkAuthenticationCache *>(authenticationCache.requestEntryNow(cacheKey)); + auth->insert(domain, authenticator->user(), authenticator->password()); + authenticationCache.releaseEntry(cacheKey); + } else { + QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache; + auth->insert(domain, authenticator->user(), authenticator->password()); + authenticationCache.addEntry(cacheKey, auth); + } + + if (copy.userName().isEmpty()) { + break; + } else { + copy.setUserName(QString()); + } + } while (true); +} + +/*! + Fetch the credential data from the credential cache. + + If auth is 0 (as it is when called from createRequest()), this will try to + look up with an empty realm. That fails in most cases for HTTP (because the + realm is seldom empty for HTTP challenges). In any case, QHttpNetworkConnection + never sends the credentials on the first attempt: it needs to find out what + authentication methods the server supports. + + For FTP, realm is always empty. +*/ +QNetworkAuthenticationCredential +QNetworkAccessAuthenticationManager::fetchCachedCredentials(const QUrl &url, + const QAuthenticator *authentication) +{ + if (!url.password().isEmpty()) + return QNetworkAuthenticationCredential(); // no need to set credentials if it already has them + + QString realm; + if (authentication) + realm = authentication->realm(); + + QByteArray cacheKey = authenticationKey(url, realm); + + QMutexLocker mutexLocker(&mutex); + if (!authenticationCache.hasEntry(cacheKey)) + return QNetworkAuthenticationCredential(); + + QNetworkAuthenticationCache *auth = + static_cast<QNetworkAuthenticationCache *>(authenticationCache.requestEntryNow(cacheKey)); + QNetworkAuthenticationCredential cred = *auth->findClosestMatch(url.path()); + authenticationCache.releaseEntry(cacheKey); + return cred; +} + +void QNetworkAccessAuthenticationManager::clearCache() +{ + authenticationCache.clear(); +} + +QT_END_NAMESPACE + diff --git a/src/network/access/qnetworkaccessauthenticationmanager_p.h b/src/network/access/qnetworkaccessauthenticationmanager_p.h new file mode 100644 index 0000000000..d2347b1722 --- /dev/null +++ b/src/network/access/qnetworkaccessauthenticationmanager_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtNetwork module 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$ +** +****************************************************************************/ + +#ifndef QNETWORKACCESSAUTHENTICATIONMANAGER_P_H +#define QNETWORKACCESSAUTHENTICATIONMANAGER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the Network Access API. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qnetworkaccessmanager.h" +#include "qnetworkaccesscache_p.h" +#include "qnetworkaccessbackend_p.h" +#include "QtNetwork/qnetworkproxy.h" +#include "QtCore/QMutex" + +QT_BEGIN_NAMESPACE + +class QAuthenticator; +class QAbstractNetworkCache; +class QNetworkAuthenticationCredential; +class QNetworkCookieJar; + +class QNetworkAuthenticationCredential +{ +public: + QString domain; + QString user; + QString password; + bool isNull() { + return domain.isNull(); + } +}; +Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE); +inline bool operator<(const QNetworkAuthenticationCredential &t1, const QString &t2) +{ return t1.domain < t2; } + +class QNetworkAccessAuthenticationManager +{ +public: + QNetworkAccessAuthenticationManager() { }; + + void cacheCredentials(const QUrl &url, const QAuthenticator *auth); + QNetworkAuthenticationCredential fetchCachedCredentials(const QUrl &url, + const QAuthenticator *auth = 0); + +#ifndef QT_NO_NETWORKPROXY + void cacheProxyCredentials(const QNetworkProxy &proxy, const QAuthenticator *auth); + QNetworkAuthenticationCredential fetchCachedProxyCredentials(const QNetworkProxy &proxy, + const QAuthenticator *auth = 0); +#endif + + void clearCache(); + +protected: + QNetworkAccessCache authenticationCache; + QMutex mutex; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index fd1fa60d4e..53ae29e932 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -329,7 +329,7 @@ void QNetworkAccessBackend::authenticationRequired(QAuthenticator *authenticator void QNetworkAccessBackend::cacheCredentials(QAuthenticator *authenticator) { - manager->cacheCredentials(this->reply->url, authenticator); + manager->authenticationManager->cacheCredentials(this->reply->url, authenticator); } void QNetworkAccessBackend::metaDataChanged() diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index f1c444790b..22f62cb1c6 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -341,107 +341,6 @@ static void ensureInitialized() QNetworkReply::sslConfiguration(), QNetworkReply::ignoreSslErrors() */ -class QNetworkAuthenticationCredential -{ -public: - QString domain; - QString user; - QString password; -}; -Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE); -inline bool operator<(const QNetworkAuthenticationCredential &t1, const QString &t2) -{ return t1.domain < t2; } - -class QNetworkAuthenticationCache: private QVector<QNetworkAuthenticationCredential>, - public QNetworkAccessCache::CacheableObject -{ -public: - QNetworkAuthenticationCache() - { - setExpires(false); - setShareable(true); - reserve(1); - } - - QNetworkAuthenticationCredential *findClosestMatch(const QString &domain) - { - iterator it = qLowerBound(begin(), end(), domain); - if (it == end() && !isEmpty()) - --it; - if (it == end() || !domain.startsWith(it->domain)) - return 0; - return &*it; - } - - void insert(const QString &domain, const QString &user, const QString &password) - { - QNetworkAuthenticationCredential *closestMatch = findClosestMatch(domain); - if (closestMatch && closestMatch->domain == domain) { - // we're overriding the current credentials - closestMatch->user = user; - closestMatch->password = password; - } else { - QNetworkAuthenticationCredential newCredential; - newCredential.domain = domain; - newCredential.user = user; - newCredential.password = password; - - if (closestMatch) - QVector<QNetworkAuthenticationCredential>::insert(++closestMatch, newCredential); - else - QVector<QNetworkAuthenticationCredential>::insert(end(), newCredential); - } - } - - virtual void dispose() { delete this; } -}; - -#ifndef QT_NO_NETWORKPROXY -static QByteArray proxyAuthenticationKey(const QNetworkProxy &proxy, const QString &realm) -{ - QUrl key; - - switch (proxy.type()) { - case QNetworkProxy::Socks5Proxy: - key.setScheme(QLatin1String("proxy-socks5")); - break; - - case QNetworkProxy::HttpProxy: - case QNetworkProxy::HttpCachingProxy: - key.setScheme(QLatin1String("proxy-http")); - break; - - case QNetworkProxy::FtpCachingProxy: - key.setScheme(QLatin1String("proxy-ftp")); - break; - - case QNetworkProxy::DefaultProxy: - case QNetworkProxy::NoProxy: - // shouldn't happen - return QByteArray(); - - // no default: - // let there be errors if a new proxy type is added in the future - } - - if (key.scheme().isEmpty()) - // proxy type not handled - return QByteArray(); - - key.setUserName(proxy.user()); - key.setHost(proxy.hostName()); - key.setPort(proxy.port()); - key.setFragment(realm); - return "auth:" + key.toEncoded(); -} -#endif - -static inline QByteArray authenticationKey(const QUrl &url, const QString &realm) -{ - QUrl copy = url; - copy.setFragment(realm); - return "auth:" + copy.toEncoded(QUrl::RemovePassword | QUrl::RemovePath | QUrl::RemoveQuery); -} /*! Constructs a QNetworkAccessManager object that is the center of @@ -1124,10 +1023,10 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QNetworkAccessBackend // also called when last URL is empty, e.g. on first call if (backend->reply->urlForLastAuthentication.isEmpty() || url != backend->reply->urlForLastAuthentication) { - QNetworkAuthenticationCredential *cred = fetchCachedCredentials(url, authenticator); - if (cred) { - authenticator->setUser(cred->user); - authenticator->setPassword(cred->password); + QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedCredentials(url, authenticator); + if (!cred.isNull()) { + authenticator->setUser(cred.user); + authenticator->setPassword(cred.password); backend->reply->urlForLastAuthentication = url; return; } @@ -1140,7 +1039,7 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QNetworkAccessBackend backend->reply->urlForLastAuthentication = url; emit q->authenticationRequired(backend->reply->q_func(), authenticator); - cacheCredentials(url, authenticator); + authenticationManager->cacheCredentials(url, authenticator); } #ifndef QT_NO_NETWORKPROXY @@ -1157,10 +1056,10 @@ void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBac // possible solution: some tracking inside the authenticator // or a new function proxyAuthenticationSucceeded(true|false) if (proxy != backend->reply->lastProxyAuthentication) { - QNetworkAuthenticationCredential *cred = fetchCachedProxyCredentials(proxy); - if (cred) { - authenticator->setUser(cred->user); - authenticator->setPassword(cred->password); + QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy); + if (!cred.isNull()) { + authenticator->setUser(cred.user); + authenticator->setPassword(cred.password); return; } } @@ -1172,75 +1071,7 @@ void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBac backend->reply->lastProxyAuthentication = proxy; emit q->proxyAuthenticationRequired(proxy, authenticator); - cacheProxyCredentials(proxy, authenticator); -} - -void QNetworkAccessManagerPrivate::cacheProxyCredentials(const QNetworkProxy &p, - const QAuthenticator *authenticator) -{ - Q_ASSERT(authenticator); - Q_ASSERT(p.type() != QNetworkProxy::DefaultProxy); - Q_ASSERT(p.type() != QNetworkProxy::NoProxy); - - QString realm = authenticator->realm(); - QNetworkProxy proxy = p; - proxy.setUser(authenticator->user()); - // Set two credentials: one with the username and one without - do { - // Set two credentials actually: one with and one without the realm - do { - QByteArray cacheKey = proxyAuthenticationKey(proxy, realm); - if (cacheKey.isEmpty()) - return; // should not happen - - QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache; - auth->insert(QString(), authenticator->user(), authenticator->password()); - objectCache.addEntry(cacheKey, auth); // replace the existing one, if there's any - - if (realm.isEmpty()) { - break; - } else { - realm.clear(); - } - } while (true); - - if (proxy.user().isEmpty()) - break; - else - proxy.setUser(QString()); - } while (true); -} - -QNetworkAuthenticationCredential * -QNetworkAccessManagerPrivate::fetchCachedProxyCredentials(const QNetworkProxy &p, - const QAuthenticator *authenticator) -{ - QNetworkProxy proxy = p; - if (proxy.type() == QNetworkProxy::DefaultProxy) { - proxy = QNetworkProxy::applicationProxy(); - } - if (!proxy.password().isEmpty()) - return 0; // no need to set credentials if it already has them - - QString realm; - if (authenticator) - realm = authenticator->realm(); - - QByteArray cacheKey = proxyAuthenticationKey(proxy, realm); - if (cacheKey.isEmpty()) - return 0; - if (!objectCache.hasEntry(cacheKey)) - return 0; - - QNetworkAuthenticationCache *auth = - static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey)); - QNetworkAuthenticationCredential *cred = auth->findClosestMatch(QString()); - objectCache.releaseEntry(cacheKey); - - // proxy cache credentials always have exactly one item - Q_ASSERT_X(cred, "QNetworkAccessManager", - "Internal inconsistency: found a cache key for a proxy, but it's empty"); - return cred; + authenticationManager->cacheProxyCredentials(proxy, authenticator); } QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query) @@ -1264,73 +1095,10 @@ QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProx } #endif -void QNetworkAccessManagerPrivate::cacheCredentials(const QUrl &url, - const QAuthenticator *authenticator) -{ - Q_ASSERT(authenticator); - QString domain = QString::fromLatin1("/"); // FIXME: make QAuthenticator return the domain - QString realm = authenticator->realm(); - - // Set two credentials actually: one with and one without the username in the URL - QUrl copy = url; - copy.setUserName(authenticator->user()); - do { - QByteArray cacheKey = authenticationKey(copy, realm); - if (objectCache.hasEntry(cacheKey)) { - QNetworkAuthenticationCache *auth = - static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey)); - auth->insert(domain, authenticator->user(), authenticator->password()); - objectCache.releaseEntry(cacheKey); - } else { - QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache; - auth->insert(domain, authenticator->user(), authenticator->password()); - objectCache.addEntry(cacheKey, auth); - } - - if (copy.userName().isEmpty()) { - break; - } else { - copy.setUserName(QString()); - } - } while (true); -} - -/*! - Fetch the credential data from the credential cache. - - If auth is 0 (as it is when called from createRequest()), this will try to - look up with an empty realm. That fails in most cases for HTTP (because the - realm is seldom empty for HTTP challenges). In any case, QHttpNetworkConnection - never sends the credentials on the first attempt: it needs to find out what - authentication methods the server supports. - - For FTP, realm is always empty. -*/ -QNetworkAuthenticationCredential * -QNetworkAccessManagerPrivate::fetchCachedCredentials(const QUrl &url, - const QAuthenticator *authentication) -{ - if (!url.password().isEmpty()) - return 0; // no need to set credentials if it already has them - - QString realm; - if (authentication) - realm = authentication->realm(); - - QByteArray cacheKey = authenticationKey(url, realm); - if (!objectCache.hasEntry(cacheKey)) - return 0; - - QNetworkAuthenticationCache *auth = - static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey)); - QNetworkAuthenticationCredential *cred = auth->findClosestMatch(url.path()); - objectCache.releaseEntry(cacheKey); - return cred; -} - void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager) { manager->d_func()->objectCache.clear(); + manager->d_func()->authenticationManager->clearCache(); } QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate() diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index cf4d2f3386..dba1fd242a 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -59,6 +59,7 @@ #include "private/qobject_p.h" #include "QtNetwork/qnetworkproxy.h" #include "QtNetwork/qnetworksession.h" +#include "qnetworkaccessauthenticationmanager_p.h" QT_BEGIN_NAMESPACE @@ -81,7 +82,8 @@ public: online(false), initializeSession(true), #endif - cookieJarCreated(false) + cookieJarCreated(false), + authenticationManager(new QNetworkAccessAuthenticationManager) { } ~QNetworkAccessManagerPrivate(); @@ -137,6 +139,9 @@ public: bool cookieJarCreated; + // The cache with authorization data: + QNetworkAccessAuthenticationManager* authenticationManager; + // this cache can be used by individual backends to cache e.g. their TCP connections to a server // and use the connections for multiple requests. QNetworkAccessCache objectCache; diff --git a/src/network/kernel/qnetworkinterface_symbian.cpp b/src/network/kernel/qnetworkinterface_symbian.cpp index 03133d0aa6..8e5db3c7eb 100644 --- a/src/network/kernel/qnetworkinterface_symbian.cpp +++ b/src/network/kernel/qnetworkinterface_symbian.cpp @@ -43,7 +43,7 @@ #include "qnetworkinterface.h" #include "qnetworkinterface_p.h" -#include "../corelib/kernel/qcore_symbian_p.h" +#include <private/qcore_symbian_p.h> #ifndef QT_NO_NETWORKINTERFACE diff --git a/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri index ebeccc9ad5..b7a87f38d8 100644 --- a/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri +++ b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri @@ -34,6 +34,12 @@ silent:symbian_sqlite3_dso.commands = @echo unzipping $@ && $$symbian_sqlite3_dso.commands QMAKE_EXTRA_COMPILERS += symbian_sqlite3_dso + # Workaround for the fact that make doesn't understand that sqlite3.dso + # is the same as $OBJECTS_DIR/sqlite3.dso + symbian_sqlite3_dso_standalone.target = sqlite3.dso + symbian_sqlite3_dso_standalone.depends = $$symbian_sqlite3_dso.output + QMAKE_EXTRA_TARGETS += symbian_sqlite3_dso_standalone + symbian_sqlite3_ver_dso.input = symbian_sqlite3_zip_file symbian_sqlite3_ver_dso.output = sqlite3{00060003}.dso !isEmpty(OBJECTS_DIR):symbian_sqlite3_ver_dso.output = $$OBJECTS_DIR/$$symbian_sqlite3_ver_dso.output diff --git a/src/src.pro b/src/src.pro index c07d3998a5..0bf3b52da2 100644 --- a/src/src.pro +++ b/src/src.pro @@ -109,7 +109,7 @@ src_webkit_declarative.target = sub-webkitdeclarative src_phonon.depends = src_gui src_multimedia.depends = src_gui contains(QT_CONFIG, opengl):src_multimedia.depends += src_opengl - src_tools_activeqt.depends = src_tools_idc src_gui + src_activeqt.depends = src_tools_idc src_gui src_declarative.depends = src_gui src_script src_network src_plugins.depends = src_gui src_sql src_svg contains(QT_CONFIG, multimedia):src_plugins.depends += src_multimedia diff --git a/tests/auto/corelib.pro b/tests/auto/corelib.pro index 3451b5312c..6810f766c4 100644 --- a/tests/auto/corelib.pro +++ b/tests/auto/corelib.pro @@ -59,6 +59,7 @@ SUBDIRS=\ qresourceengine \ qringbuffer \ qscopedpointer \ + qscopedvaluerollback \ qsemaphore \ qsequentialanimationgroup \ qset \ diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 1d2a69f4d0..3715162f33 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -342,6 +342,8 @@ private Q_SLOTS: void synchronousRequest(); void synchronousRequestSslFailure(); + void httpAbort(); + // NOTE: This test must be last! void parentingRepliesToTheApp(); }; @@ -3850,19 +3852,13 @@ void tst_QNetworkReply::ioPostToHttpUploadProgress() disconnect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); incomingSocket->setReadBufferSize(1*1024); - QTestEventLoop::instance().enterLoop(2); + QTestEventLoop::instance().enterLoop(5); // some progress should have been made QList<QVariant> args = spy.last(); QVERIFY(!args.isEmpty()); QVERIFY(args.at(0).toLongLong() > 0); - - incomingSocket->setReadBufferSize(32*1024); - incomingSocket->read(16*1024); - QTestEventLoop::instance().enterLoop(2); - // some more progress than before - QList<QVariant> args2 = spy.last(); - QVERIFY(!args2.isEmpty()); - QVERIFY(args2.at(0).toLongLong() > args.at(0).toLongLong()); + // but not everything! + QVERIFY(args.at(0).toLongLong() != sourceFile.size()); // set the read buffer to unlimited incomingSocket->setReadBufferSize(0); @@ -3870,8 +3866,10 @@ void tst_QNetworkReply::ioPostToHttpUploadProgress() // progress should be finished QList<QVariant> args3 = spy.last(); QVERIFY(!args3.isEmpty()); - QVERIFY(args3.at(0).toLongLong() > args2.at(0).toLongLong()); + // More progress than before + QVERIFY(args3.at(0).toLongLong() > args.at(0).toLongLong()); QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong()); + // And actually finished.. QCOMPARE(args3.at(0).toLongLong(), sourceFile.size()); // after sending this, the QNAM should emit finished() @@ -4570,7 +4568,7 @@ void tst_QNetworkReply::proxyChange() manager.setProxy(dummyProxy); QNetworkReplyPtr reply3 = manager.get(req); connect(reply3, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(1); + QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(int(reply3->error()) > 0); @@ -5325,7 +5323,7 @@ void tst_QNetworkReply::qtbug13431replyThrottling() connect(&nam, SIGNAL(finished(QNetworkReply*)), &helper, SLOT(replyFinished(QNetworkReply*))); // Download a bigger file - QNetworkRequest netRequest(QUrl("http://qt-test-server/qtest/bigfile")); + QNetworkRequest netRequest(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile")); helper.m_reply = nam.get(netRequest); // Set the throttle helper.m_reply->setReadBufferSize(36000); @@ -5506,6 +5504,18 @@ void tst_QNetworkReply::synchronousRequestSslFailure() QCOMPARE(sslErrorsSpy.count(), 0); } +void tst_QNetworkReply::httpAbort() +{ + // FIXME: Implement a test that aborts a big HTTP reply + // a) after the first readyRead() + // b) immediatly after the get() + // c) after the finished() + // The goal is no crash and no irrelevant signals after the abort + + // FIXME Also implement one where we do a big upload and then abort(). + // It must not crash either. +} + // NOTE: This test must be last testcase in tst_qnetworkreply! void tst_QNetworkReply::parentingRepliesToTheApp() { diff --git a/tests/auto/qscopedvaluerollback/qscopedvaluerollback.pro b/tests/auto/qscopedvaluerollback/qscopedvaluerollback.pro new file mode 100644 index 0000000000..f06e21ba1f --- /dev/null +++ b/tests/auto/qscopedvaluerollback/qscopedvaluerollback.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qscopedvaluerollback.cpp +QT -= gui +CONFIG += parallel_test diff --git a/tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp b/tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp new file mode 100644 index 0000000000..956253fb75 --- /dev/null +++ b/tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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 <QtTest/QtTest> +#include <QtCore/QScopedValueRollback> + +/*! + \class tst_QScopedValueRollback + \internal + \since 4.8 + \brief Tests class QScopedValueRollback. + + */ +class tst_QScopedValueRollback : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void leavingScope(); + void leavingScopeAfterCommit(); + void rollbackToPreviousCommit(); + void exceptions(); + void earlyExitScope(); +private: + void earlyExitScope_helper(int exitpoint, int &member); +}; + +void tst_QScopedValueRollback::leavingScope() +{ + int i = 0; + bool b = false; + QString s("This is useful"); + + //test rollback on going out of scope + { + QScopedValueRollback<int> ri(i); + QScopedValueRollback<bool> rb(b); + QScopedValueRollback<QString> rs(s); + QCOMPARE(b, false); + QCOMPARE(i, 0); + QCOMPARE(s, QString("This is useful")); + b = true; + i = 1; + s = "Useless"; + QCOMPARE(b, true); + QCOMPARE(i, 1); + QCOMPARE(s, QString("Useless")); + } + QCOMPARE(b, false); + QCOMPARE(i, 0); + QCOMPARE(s, QString("This is useful")); +} + +void tst_QScopedValueRollback::leavingScopeAfterCommit() +{ + int i = 0; + bool b = false; + QString s("This is useful"); + + //test rollback on going out of scope + { + QScopedValueRollback<int> ri(i); + QScopedValueRollback<bool> rb(b); + QScopedValueRollback<QString> rs(s); + QCOMPARE(b, false); + QCOMPARE(i, 0); + QCOMPARE(s, QString("This is useful")); + b = true; + i = 1; + s = "Useless"; + QCOMPARE(b, true); + QCOMPARE(i, 1); + QCOMPARE(s, QString("Useless")); + ri.commit(); + rb.commit(); + rs.commit(); + } + QCOMPARE(b, true); + QCOMPARE(i, 1); + QCOMPARE(s, QString("Useless")); +} + +void tst_QScopedValueRollback::rollbackToPreviousCommit() +{ + int i=0; + { + QScopedValueRollback<int> ri(i); + i++; + ri.commit(); + i++; + } + QCOMPARE(i,1); + { + QScopedValueRollback<int> ri1(i); + i++; + ri1.commit(); + i++; + ri1.commit(); + i++; + } + QCOMPARE(i,3); +} + +void tst_QScopedValueRollback::exceptions() +{ + bool b = false; + bool caught = false; + QT_TRY + { + QScopedValueRollback<bool> rb(b); + b = true; + QT_THROW(std::bad_alloc()); //if Qt compiled without exceptions this is noop + rb.commit(); //if Qt compiled without exceptions, true is committed + } + QT_CATCH(...) + { + caught = true; + } + QCOMPARE(b, !caught); //expect false if exception was thrown, true otherwise +} + +void tst_QScopedValueRollback::earlyExitScope() +{ + int i=0; + int j=0; + while (true) { + QScopedValueRollback<int> ri(i); + i++; + j=i; + if (i>8) break; + ri.commit(); + } + QCOMPARE(i,8); + QCOMPARE(j,9); + + for (i = 0; i < 5; i++) { + j=1; + earlyExitScope_helper(i,j); + QCOMPARE(j, 1<<i); + } +} + +void tst_QScopedValueRollback::earlyExitScope_helper(int exitpoint, int& member) +{ + QScopedValueRollback<int> r(member); + member *= 2; + if (exitpoint == 0) + return; + r.commit(); + member *= 2; + if (exitpoint == 1) + return; + r.commit(); + member *= 2; + if (exitpoint == 2) + return; + r.commit(); + member *= 2; + if (exitpoint == 3) + return; + r.commit(); +} + +QTEST_MAIN(tst_QScopedValueRollback) +#include "tst_qscopedvaluerollback.moc" diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp index 19c6c166dc..c69052ee7d 100644 --- a/tests/auto/qthread/tst_qthread.cpp +++ b/tests/auto/qthread/tst_qthread.cpp @@ -113,6 +113,7 @@ private slots: void wait3_slowDestructor(); void destroyFinishRace(); void startFinishRace(); + void startAndQuitCustomEventLoop(); void stressTest(); }; @@ -1150,5 +1151,20 @@ void tst_QThread::startFinishRace() } } +void tst_QThread::startAndQuitCustomEventLoop() +{ + struct Thread : QThread { + void run() { QEventLoop().exec(); } + }; + + for (int i = 0; i < 5; i++) { + Thread t; + t.start(); + t.quit(); + t.wait(); + } +} + + QTEST_MAIN(tst_QThread) #include "tst_qthread.moc" diff --git a/tools/runonphone/main.cpp b/tools/runonphone/main.cpp index 9390fb45dc..5281544385 100644 --- a/tools/runonphone/main.cpp +++ b/tools/runonphone/main.cpp @@ -56,12 +56,13 @@ void printUsage(QTextStream& outstream, QString exeName) { outstream << exeName << " [options] [program] [program arguments]" << endl - << "-s, --sis <file> specify sis file to install" << endl + << "-s, --sis <local file> specify sis file to install" << endl << "-p, --portname <COMx> specify COM port to use by device name" << endl << "-f, --portfriendlyname <substring> specify COM port to use by friendly name" << endl << "-t, --timeout <milliseconds> terminate test if timeout occurs" << endl << "-v, --verbose show debugging output" << endl << "-q, --quiet hide progress messages" << endl + << "-u, --upload <local file> upload executable file to phone" << endl << "-d, --download <remote file> <local file> copy file from phone to PC after running test" << endl << "--nocrashlog Don't capture call stack if test crashes" << endl << "--crashlogpath <dir> Path to save crash logs (default=working dir)" << endl @@ -84,6 +85,7 @@ int main(int argc, char *argv[]) QStringList args = QCoreApplication::arguments(); QTextStream outstream(stdout); QTextStream errstream(stderr); + QString uploadLocalFile; QString downloadRemoteFile; QString downloadLocalFile; int loglevel=1; @@ -112,6 +114,18 @@ int main(int argc, char *argv[]) return 1; } } + else if (arg == "--upload" || arg == "-u") { + CHECK_PARAMETER_EXISTS + uploadLocalFile = it.next(); + if (!QFileInfo(uploadLocalFile).exists()) { + errstream << "Executable file (" << uploadLocalFile << ") doesn't exist" << endl; + return 1; + } + if (!(QFileInfo(uploadLocalFile).suffix() == "exe")) { + errstream << "File (" << uploadLocalFile << ") must be an executable" << endl; + return 1; + } + } else if (arg == "--download" || arg == "-d") { CHECK_PARAMETER_EXISTS downloadRemoteFile = it.next(); @@ -147,12 +161,18 @@ int main(int argc, char *argv[]) } } - if (exeFile.isEmpty() && sisFile.isEmpty() && + if (exeFile.isEmpty() && sisFile.isEmpty() && uploadLocalFile.isEmpty() && (downloadLocalFile.isEmpty() || downloadRemoteFile.isEmpty())) { printUsage(outstream, args[0]); return 1; } + if (!uploadLocalFile.isEmpty() && (!downloadLocalFile.isEmpty() || !downloadRemoteFile.isEmpty())) { + errstream << "Upload option can't be used together with download" << endl; + printUsage(outstream, args[0]); + return 1; + } + if (serialPortName.isEmpty()) { if (loglevel > 0) outstream << "Detecting serial ports" << endl; @@ -182,19 +202,20 @@ int main(int argc, char *argv[]) QScopedPointer<trk::Launcher> launcher; launcher.reset(new trk::Launcher(trk::Launcher::ActionPingOnly)); - QFileInfo info(exeFile); + QFileInfo exeInfo(exeFile); + QFileInfo uploadInfo(uploadLocalFile); if (!sisFile.isEmpty()) { launcher->addStartupActions(trk::Launcher::ActionCopyInstall); launcher->setCopyFileName(sisFile, "c:\\data\\testtemp.sis"); launcher->setInstallFileName("c:\\data\\testtemp.sis"); } - else if (info.exists()) { + else if (!uploadLocalFile.isEmpty() && uploadInfo.exists()) { launcher->addStartupActions(trk::Launcher::ActionCopy); - launcher->setCopyFileName(exeFile, QString("c:\\sys\\bin\\") + info.fileName()); + launcher->setCopyFileName(uploadLocalFile, QString("c:\\sys\\bin\\") + uploadInfo.fileName()); } if (!exeFile.isEmpty()) { launcher->addStartupActions(trk::Launcher::ActionRun); - launcher->setFileName(QString("c:\\sys\\bin\\") + info.fileName()); + launcher->setFileName(QString("c:\\sys\\bin\\") + exeInfo.fileName()); launcher->setCommandLineArgs(cmdLine); } if (!downloadRemoteFile.isEmpty() && !downloadLocalFile.isEmpty()) { |