diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-05-08 15:29:43 +0000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2015-05-08 17:34:00 +0000 |
commit | 9b2ee419b4218126e00096ef5034e846ff3b9db1 (patch) | |
tree | cd11989ad66ead8e506e83dea6359e3be972034e /src | |
parent | 4fe68ffbe5c93244562f2b56292d4ecf5ce39f56 (diff) | |
parent | 1fce111809f216383e60f56b57a9f68ccd2b766f (diff) |
Merge "Merge remote-tracking branch 'origin/5.4' into merge5.5" into refs/staging/5.5
Diffstat (limited to 'src')
22 files changed, 208 insertions, 257 deletions
diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index 178de363d2..12ae8a65d8 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -1092,7 +1092,9 @@ public class ExtractStyle { { try { InsetDrawable d = (InsetDrawable)drawable; - Object mInsetStateObject = getAccessibleField(InsetDrawable.class, "mInsetState").get(d); + // mInsetState changed to mState in Android 5.1 (22) + Object mInsetStateObject = getAccessibleField(InsetDrawable.class, (Build.VERSION.SDK_INT > 21) ? "mState" + : "mInsetState").get(d); Rect _padding = new Rect(); boolean hasPadding = d.getPadding(_padding); return getDrawable(getAccessibleField(mInsetStateObject.getClass(), "mDrawable").get(mInsetStateObject), filename, hasPadding ? _padding : null); diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java index 95af3c87ad..23e08f537a 100644 --- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java +++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java @@ -187,7 +187,7 @@ public class QtActivity extends Activity QT_ANDROID_THEMES = new String[] {"Theme_Light"}; QT_ANDROID_DEFAULT_THEME = "Theme_Light"; } - else if ((Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= 13) || Build.VERSION.SDK_INT == 21){ + else if ((Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= 13) || Build.VERSION.SDK_INT >= 21){ QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"}; QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light"; } else { diff --git a/src/corelib/Qt5CoreConfigExtras.cmake.in b/src/corelib/Qt5CoreConfigExtras.cmake.in index 7213a844f5..48d5f21447 100644 --- a/src/corelib/Qt5CoreConfigExtras.cmake.in +++ b/src/corelib/Qt5CoreConfigExtras.cmake.in @@ -71,7 +71,7 @@ set(_qt5_corelib_extra_includes) # macro to add it. set(Qt5_POSITION_INDEPENDENT_CODE True) set_property(TARGET Qt5::Core PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE \"ON\") -set(Qt5Core_EXECUTABLE_COMPILE_FLAGS \"-fPIE\") +set(Qt5Core_EXECUTABLE_COMPILE_FLAGS \"-fPIC\") !!IF !isEmpty(QT_NAMESPACE) list(APPEND Qt5Core_DEFINITIONS -DQT_NAMESPACE=$$QT_NAMESPACE) diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 27a3bf7c3d..99f21c1ae5 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1062,9 +1062,9 @@ Q_CORE_EXPORT int qrand(); #define QT_MODULE(x) -#if !defined(QT_BOOTSTRAPPED) && defined(QT_REDUCE_RELOCATIONS) && defined(__ELF__) && !defined(__PIC__) && !defined(__PIE__) +#if !defined(QT_BOOTSTRAPPED) && defined(QT_REDUCE_RELOCATIONS) && defined(__ELF__) && !defined(__PIC__) # error "You must build your code with position independent code if Qt was built with -reduce-relocations. "\ - "Compile your code with -fPIC or -fPIE." + "Compile your code with -fPIC." #endif namespace QtPrivate { diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index b817a24c74..d1804f2cb6 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -185,11 +185,11 @@ bool QLockFilePrivate::isApparentlyStale() const { qint64 pid; QString hostname, appname; - if (!getLockInfo(&pid, &hostname, &appname)) - return false; - if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { - if (::kill(pid, 0) == -1 && errno == ESRCH) - return true; // PID doesn't exist anymore + if (getLockInfo(&pid, &hostname, &appname)) { + if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { + if (::kill(pid, 0) == -1 && errno == ESRCH) + return true; // PID doesn't exist anymore + } } const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); return staleLockTime > 0 && age > staleLockTime; diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp index 9fe86e1ad8..27a63e126a 100644 --- a/src/corelib/io/qlockfile_win.cpp +++ b/src/corelib/io/qlockfile_win.cpp @@ -126,21 +126,21 @@ bool QLockFilePrivate::isApparentlyStale() const { qint64 pid; QString hostname, appname; - if (!getLockInfo(&pid, &hostname, &appname)) - return false; // On WinRT there seems to be no way of obtaining information about other // processes due to sandboxing #ifndef Q_OS_WINRT - if (hostname == QString::fromLocal8Bit(localHostName())) { - HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); - if (!procHandle) - return true; - // We got a handle but check if process is still alive - DWORD dwR = ::WaitForSingleObject(procHandle, 0); - ::CloseHandle(procHandle); - if (dwR == WAIT_TIMEOUT) - return true; + if (getLockInfo(&pid, &hostname, &appname)) { + if (hostname == QString::fromLocal8Bit(localHostName())) { + HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); + if (!procHandle) + return true; + // We got a handle but check if process is still alive + DWORD dwR = ::WaitForSingleObject(procHandle, 0); + ::CloseHandle(procHandle); + if (dwR == WAIT_TIMEOUT) + return true; + } } #endif // !Q_OS_WINRT const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp index c17b42ef81..af1bb56fe9 100644 --- a/src/corelib/io/qnoncontiguousbytedevice.cpp +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -216,6 +216,11 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size() return byteArray->size(); } +qint64 QNonContiguousByteDeviceByteArrayImpl::pos() +{ + return currentPosition; +} + QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb) : QNonContiguousByteDevice(), currentPosition(0) { @@ -253,6 +258,11 @@ bool QNonContiguousByteDeviceRingBufferImpl::atEnd() return currentPosition >= size(); } +qint64 QNonContiguousByteDeviceRingBufferImpl::pos() +{ + return currentPosition; +} + bool QNonContiguousByteDeviceRingBufferImpl::reset() { currentPosition = 0; @@ -381,6 +391,14 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::size() return device->size() - initialPosition; } +qint64 QNonContiguousByteDeviceIoDeviceImpl::pos() +{ + if (device->isSequential()) + return -1; + + return device->pos(); +} + QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0) { byteDevice = bd; diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h index 8b5bf3080a..38089dedd7 100644 --- a/src/corelib/io/qnoncontiguousbytedevice_p.h +++ b/src/corelib/io/qnoncontiguousbytedevice_p.h @@ -61,6 +61,7 @@ public: virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0; virtual bool advanceReadPointer(qint64 amount) = 0; virtual bool atEnd() = 0; + virtual qint64 pos() { return -1; } virtual bool reset() = 0; virtual qint64 size() = 0; @@ -103,6 +104,7 @@ public: bool atEnd() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE; + qint64 pos() Q_DECL_OVERRIDE; protected: QByteArray* byteArray; qint64 currentPosition; @@ -118,6 +120,7 @@ public: bool atEnd() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE; + qint64 pos() Q_DECL_OVERRIDE; protected: QSharedPointer<QRingBuffer> ringBuffer; qint64 currentPosition; @@ -135,6 +138,7 @@ public: bool atEnd() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE; + qint64 pos() Q_DECL_OVERRIDE; protected: QIODevice* device; QByteArray* currentReadBuffer; diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index ab2025ee5c..14aad0e193 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -36,7 +36,6 @@ #include <qdebug.h> #include <qelapsedtimer.h> #include <qeventloop.h> -#include <qtimer.h> QT_BEGIN_NAMESPACE @@ -45,13 +44,11 @@ QWindowsPipeReader::QWindowsPipeReader(QObject *parent) handle(INVALID_HANDLE_VALUE), readBufferMaxSize(0), actualReadBufferSize(0), + stopped(true), readSequenceStarted(false), - emitReadyReadTimer(new QTimer(this)), pipeBroken(false), readyReadEmitted(false) { - emitReadyReadTimer->setSingleShot(true); - connect(emitReadyReadTimer, SIGNAL(timeout()), SIGNAL(readyRead())); dataReadNotifier = new QWinOverlappedIoNotifier(this); connect(dataReadNotifier, &QWinOverlappedIoNotifier::notified, this, &QWindowsPipeReader::notified); } @@ -73,12 +70,7 @@ static bool qt_cancelIo(HANDLE handle, OVERLAPPED *overlapped) QWindowsPipeReader::~QWindowsPipeReader() { - if (readSequenceStarted) { - if (qt_cancelIo(handle, &overlapped)) - dataReadNotifier->waitForNotified(-1, &overlapped); - else - qErrnoWarning("QWindowsPipeReader: qt_cancelIo on handle %x failed.", handle); - } + stop(); } /*! @@ -89,9 +81,9 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd) readBuffer.clear(); actualReadBufferSize = 0; handle = hPipeReadEnd; - ZeroMemory(&overlapped, sizeof(overlapped)); pipeBroken = false; readyReadEmitted = false; + stopped = false; if (hPipeReadEnd != INVALID_HANDLE_VALUE) { dataReadNotifier->setHandle(hPipeReadEnd); dataReadNotifier->setEnabled(true); @@ -100,13 +92,24 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd) /*! Stops the asynchronous read sequence. - This function assumes that the file already has been closed. - It does not cancel any I/O operation. + If the read sequence is running then the I/O operation is canceled. */ void QWindowsPipeReader::stop() { - dataReadNotifier->setEnabled(false); + stopped = true; + if (readSequenceStarted) { + if (qt_cancelIo(handle, &overlapped)) { + dataReadNotifier->waitForNotified(-1, &overlapped); + } else { + const DWORD dwError = GetLastError(); + if (dwError != ERROR_NOT_FOUND) { + qErrnoWarning(dwError, "QWindowsPipeReader: qt_cancelIo on handle %x failed.", + handle); + } + } + } readSequenceStarted = false; + dataReadNotifier->setEnabled(false); handle = INVALID_HANDLE_VALUE; } @@ -119,7 +122,7 @@ qint64 QWindowsPipeReader::bytesAvailable() const } /*! - Stops the asynchronous read sequence. + Copies at most \c{maxlen} bytes from the internal read buffer to \c{data}. */ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) { @@ -147,9 +150,7 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) } if (!pipeBroken) { - if (!actualReadBufferSize) - emitReadyReadTimer->stop(); - if (!readSequenceStarted) + if (!readSequenceStarted && !stopped) startAsyncRead(); if (readSoFar == 0) return -2; // signal EWOULDBLOCK @@ -172,13 +173,41 @@ void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode, { if (&overlapped != notifiedOverlapped) return; - if (!completeAsyncRead(numberOfBytesRead, errorCode)) { + + switch (errorCode) { + case ERROR_SUCCESS: + break; + case ERROR_MORE_DATA: + // This is not an error. We're connected to a message mode + // pipe and the message didn't fit into the pipe's system + // buffer. We will read the remaining data in the next call. + break; + case ERROR_BROKEN_PIPE: + case ERROR_PIPE_NOT_CONNECTED: pipeBroken = true; + break; + default: + emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead")); + pipeBroken = true; + break; + } + + readSequenceStarted = false; + + // After the reader was stopped, the only reason why this function can be called is the + // completion of a cancellation. No signals should be emitted, and no new read sequence should + // be started in this case. + if (stopped) + return; + + if (pipeBroken) { emit pipeClosed(); return; } + + actualReadBufferSize += numberOfBytesRead; + readBuffer.truncate(actualReadBufferSize); startAsyncRead(); - emitReadyReadTimer->stop(); readyReadEmitted = true; emit readyRead(); } @@ -206,6 +235,7 @@ void QWindowsPipeReader::startAsyncRead() char *ptr = readBuffer.reserve(bytesToRead); readSequenceStarted = true; + ZeroMemory(&overlapped, sizeof(overlapped)); if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) { // We get notified by the QWinOverlappedIoNotifier - even in the synchronous case. return; @@ -241,38 +271,6 @@ void QWindowsPipeReader::startAsyncRead() /*! \internal - Sets the correct size of the read buffer after a read operation. - Returns \c false, if an error occurred or the connection dropped. - */ -bool QWindowsPipeReader::completeAsyncRead(DWORD bytesRead, DWORD errorCode) -{ - readSequenceStarted = false; - - switch (errorCode) { - case ERROR_SUCCESS: - break; - case ERROR_MORE_DATA: - // This is not an error. We're connected to a message mode - // pipe and the message didn't fit into the pipe's system - // buffer. We will read the remaining data in the next call. - break; - case ERROR_BROKEN_PIPE: - case ERROR_PIPE_NOT_CONNECTED: - return false; - default: - emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead")); - return false; - } - - actualReadBufferSize += bytesRead; - readBuffer.truncate(actualReadBufferSize); - if (!emitReadyReadTimer->isActive()) - emitReadyReadTimer->start(); - return true; -} - -/*! - \internal Returns the number of available bytes in the pipe. Sets QWindowsPipeReader::pipeBroken to true if the connection is broken. */ diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h index 7904f116cb..2c32eeb9ce 100644 --- a/src/corelib/io/qwindowspipereader_p.h +++ b/src/corelib/io/qwindowspipereader_p.h @@ -47,7 +47,6 @@ #include <qbytearray.h> #include <qobject.h> -#include <qtimer.h> #include <private/qringbuffer_p.h> #include <qt_windows.h> @@ -89,7 +88,6 @@ private Q_SLOTS: void notified(quint32 numberOfBytesRead, quint32 errorCode, OVERLAPPED *notifiedOverlapped); private: - bool completeAsyncRead(DWORD bytesRead, DWORD errorCode); DWORD checkPipeState(); private: @@ -99,8 +97,8 @@ private: qint64 readBufferMaxSize; QRingBuffer readBuffer; int actualReadBufferSize; + bool stopped; bool readSequenceStarted; - QTimer *emitReadyReadTimer; bool pipeBroken; bool readyReadEmitted; }; diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 839f90f17c..2014b7440c 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -714,7 +714,7 @@ public: }; QJpegHandlerPrivate(QJpegHandler *qq) - : quality(75), exifOrientation(1), iod_src(0), + : quality(75), iod_src(0), rgb888ToRgb32ConverterPtr(qt_convert_rgb888_to_rgb32), state(Ready), optimize(false), progressive(false), q(qq) {} @@ -730,10 +730,8 @@ public: bool readJpegHeader(QIODevice*); bool read(QImage *image); - void applyExifOrientation(QImage *image); int quality; - int exifOrientation; QVariant size; QImage::Format format; QSize scaledSize; @@ -756,97 +754,6 @@ public: QJpegHandler *q; }; -static bool readExifHeader(QDataStream &stream) -{ - char prefix[6]; - if (stream.readRawData(prefix, sizeof(prefix)) != sizeof(prefix)) - return false; - if (prefix[0] != 'E' || prefix[1] != 'x' || prefix[2] != 'i' || prefix[3] != 'f' || prefix[4] != 0 || prefix[5] != 0) - return false; - return true; -} - -/* - * Returns -1 on error - * Returns 0 if no Exif orientation was found - * Returns 1 orientation is horizontal (normal) - * Returns 2 mirror horizontal - * Returns 3 rotate 180 - * Returns 4 mirror vertical - * Returns 5 mirror horizontal and rotate 270 CCW - * Returns 6 rotate 90 CW - * Returns 7 mirror horizontal and rotate 90 CW - * Returns 8 rotate 270 CW - */ -static int getExifOrientation(QByteArray &exifData) -{ - QDataStream stream(&exifData, QIODevice::ReadOnly); - - if (!readExifHeader(stream)) - return -1; - - quint16 val; - quint32 offset; - - // read byte order marker - stream >> val; - if (val == 0x4949) // 'II' == Intel - stream.setByteOrder(QDataStream::LittleEndian); - else if (val == 0x4d4d) // 'MM' == Motorola - stream.setByteOrder(QDataStream::BigEndian); - else - return -1; // unknown byte order - - // read size - stream >> val; - if (val != 0x2a) - return -1; - - stream >> offset; - // we have already used 8 bytes of TIFF header - offset -= 8; - - // read IFD - while (!stream.atEnd()) { - quint16 numEntries; - - // skip offset bytes to get the next IFD - if (stream.skipRawData(offset) != (qint32)offset) - return -1; - - stream >> numEntries; - - for (;numEntries > 0; --numEntries) { - quint16 tag; - quint16 type; - quint32 components; - quint16 value; - quint16 dummy; - - stream >> tag >> type >> components >> value >> dummy; - if (tag == 0x0112) { // Tag Exif.Image.Orientation - if (components !=1) - return -1; - if (type != 3) // we are expecting it to be an unsigned short - return -1; - if (value < 1 || value > 8) // check for valid range - return -1; - - // It is possible to include the orientation multiple times. - // Right now the first value is returned. - return value; - } - } - - // read offset to next IFD - stream >> offset; - if (offset == 0) // this is the last IFD - break; - } - - // No Exif orientation was found - return 0; -} /*! \internal */ @@ -866,7 +773,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) if (!setjmp(err.setjmp_buffer)) { jpeg_save_markers(&info, JPEG_COM, 0xFFFF); - jpeg_save_markers(&info, JPEG_APP0+1, 0xFFFF); // Exif uses APP1 marker (void) jpeg_read_header(&info, TRUE); @@ -878,8 +784,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) format = QImage::Format_Invalid; read_jpeg_format(format, &info); - QByteArray exifData; - for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) { if (marker->marker == JPEG_COM) { QString key, value; @@ -897,18 +801,9 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) description += key + QLatin1String(": ") + value.simplified(); readTexts.append(key); readTexts.append(value); - } else if (marker->marker == JPEG_APP0+1) { - exifData.append((const char*)marker->data, marker->data_length); } } - if (exifData.size()) { - // Exif data present - int orientation = getExifOrientation(exifData); - if (orientation > 0) - exifOrientation = orientation; - } - state = ReadHeader; return true; } @@ -922,48 +817,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) return true; } -void QJpegHandlerPrivate::applyExifOrientation(QImage *image) -{ - // This is not an optimized implementation, but easiest to maintain - QTransform transform; - - switch (exifOrientation) { - case 1: // normal - break; - case 2: // mirror horizontal - *image = image->mirrored(true, false); - break; - case 3: // rotate 180 - transform.rotate(180); - *image = image->transformed(transform); - break; - case 4: // mirror vertical - *image = image->mirrored(false, true); - break; - case 5: // mirror horizontal and rotate 270 CCW - *image = image->mirrored(true, false); - transform.rotate(270); - *image = image->transformed(transform); - break; - case 6: // rotate 90 CW - transform.rotate(90); - *image = image->transformed(transform); - break; - case 7: // mirror horizontal and rotate 90 CW - *image = image->mirrored(true, false); - transform.rotate(90); - *image = image->transformed(transform); - break; - case 8: // rotate 270 CW - transform.rotate(-90); - *image = image->transformed(transform); - break; - default: - qWarning("This should never happen"); - } - exifOrientation = 1; -} - bool QJpegHandlerPrivate::read(QImage *image) { if(state == Ready) @@ -975,7 +828,6 @@ bool QJpegHandlerPrivate::read(QImage *image) if (success) { for (int i = 0; i < readTexts.size()-1; i+=2) image->setText(readTexts.at(i), readTexts.at(i+1)); - applyExifOrientation(image); state = Ready; return true; diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 75888c0062..ef40d8cb2a 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -106,15 +106,19 @@ void QHttpNetworkConnectionChannel::init() socket->setProxy(QNetworkProxy::NoProxy); #endif + // We want all signals (except the interactive ones) be connected as QueuedConnection + // because else we're falling into cases where we recurse back into the socket code + // and mess up the state. Always going to the event loop (and expecting that when reading/writing) + // is safer. QObject::connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_bytesWritten(qint64)), - Qt::DirectConnection); + Qt::QueuedConnection); QObject::connect(socket, SIGNAL(connected()), this, SLOT(_q_connected()), - Qt::DirectConnection); + Qt::QueuedConnection); QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(_q_readyRead()), - Qt::DirectConnection); + Qt::QueuedConnection); // The disconnected() and error() signals may already come // while calling connectToHost(). @@ -143,7 +147,7 @@ void QHttpNetworkConnectionChannel::init() // won't be a sslSocket if encrypt is false QObject::connect(sslSocket, SIGNAL(encrypted()), this, SLOT(_q_encrypted()), - Qt::DirectConnection); + Qt::QueuedConnection); QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(_q_sslErrors(QList<QSslError>)), Qt::DirectConnection); @@ -152,7 +156,7 @@ void QHttpNetworkConnectionChannel::init() Qt::DirectConnection); QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), this, SLOT(_q_encryptedBytesWritten(qint64)), - Qt::DirectConnection); + Qt::QueuedConnection); if (ignoreAllSslErrors) sslSocket->ignoreSslErrors(); @@ -189,8 +193,11 @@ void QHttpNetworkConnectionChannel::close() // pendingEncrypt must only be true in between connected and encrypted states pendingEncrypt = false; - if (socket) + if (socket) { + // socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while + // there is no socket yet. socket->close(); + } } @@ -356,6 +363,14 @@ bool QHttpNetworkConnectionChannel::ensureConnection() } return false; } + + // This code path for ConnectedState + if (pendingEncrypt) { + // Let's only be really connected when we have received the encrypted() signal. Else the state machine seems to mess up + // and corrupt the things sent to the server. + return false; + } + return true; } @@ -662,6 +677,12 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes) { Q_UNUSED(bytes); + if (ssl) { + // In the SSL case we want to send data from encryptedBytesWritten signal since that one + // is the one going down to the actual network, not only into some SSL buffer. + return; + } + // bytes have been written to the socket. write even more of them :) if (isSocketWriting()) sendRequest(); @@ -737,7 +758,7 @@ void QHttpNetworkConnectionChannel::_q_connected() // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again! //channels[i].reconnectAttempts = 2; - if (pendingEncrypt) { + if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState #ifndef QT_NO_SSL if (connection->sslContext().isNull()) { // this socket is making the 1st handshake for this connection, diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 6872fcb691..16d6c3b40f 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -83,6 +83,8 @@ typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair; class QHttpNetworkConnectionChannel : public QObject { Q_OBJECT public: + // TODO: Refactor this to add an EncryptingState (and remove pendingEncrypt). + // Also add an Unconnected state so IdleState does not have double meaning. enum ChannelState { IdleState = 0, // ready to send request ConnectingState = 1, // connecting to host diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp index eac261bc80..55187755bf 100644 --- a/src/network/access/qhttpprotocolhandler.cpp +++ b/src/network/access/qhttpprotocolhandler.cpp @@ -368,6 +368,13 @@ bool QHttpProtocolHandler::sendRequest() // nothing to read currently, break the loop break; } else { + if (m_channel->written != uploadByteDevice->pos()) { + // Sanity check. This was useful in tracking down an upload corruption. + qWarning() << "QHttpProtocolHandler: Internal error in sendRequest. Expected to write at position" << m_channel->written << "but read device is at" << uploadByteDevice->pos(); + Q_ASSERT(m_channel->written == uploadByteDevice->pos()); + m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::ProtocolFailure); + return false; + } qint64 currentWriteSize = m_socket->write(readPointer, currentReadSize); if (currentWriteSize == -1 || currentWriteSize != currentReadSize) { // socket broke down diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index ff919b11c5..9573d500ea 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -189,6 +189,7 @@ protected: QByteArray m_dataArray; bool m_atEnd; qint64 m_size; + qint64 m_pos; // to match calls of haveDataSlot with the expected position public: QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s) : QNonContiguousByteDevice(), @@ -196,7 +197,8 @@ public: m_amount(0), m_data(0), m_atEnd(aE), - m_size(s) + m_size(s), + m_pos(0) { } @@ -204,6 +206,11 @@ public: { } + qint64 pos() Q_DECL_OVERRIDE + { + return m_pos; + } + const char* readPointer(qint64 maximumLength, qint64 &len) Q_DECL_OVERRIDE { if (m_amount > 0) { @@ -231,11 +238,10 @@ public: m_amount -= a; m_data += a; + m_pos += a; - // To main thread to inform about our state - emit processedData(a); - - // FIXME possible optimization, already ask user thread for some data + // To main thread to inform about our state. The m_pos will be sent as a sanity check. + emit processedData(m_pos, a); return true; } @@ -252,10 +258,21 @@ public: { m_amount = 0; m_data = 0; + m_dataArray.clear(); + + if (wantDataPending) { + // had requested the user thread to send some data (only 1 in-flight at any moment) + wantDataPending = false; + } // Communicate as BlockingQueuedConnection bool b = false; emit resetData(&b); + if (b) { + // the reset succeeded, we're at pos 0 again + m_pos = 0; + // the HTTP code will anyway abort the request if !b. + } return b; } @@ -266,8 +283,13 @@ public: public slots: // From user thread: - void haveDataSlot(QByteArray dataArray, bool dataAtEnd, qint64 dataSize) + void haveDataSlot(qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize) { + if (pos != m_pos) { + // Sometimes when re-sending a request in the qhttpnetwork* layer there is a pending haveData from the + // user thread on the way to us. We need to ignore it since it is the data for the wrong(later) chunk. + return; + } wantDataPending = false; m_dataArray = dataArray; @@ -287,7 +309,7 @@ signals: // to main thread: void wantData(qint64); - void processedData(qint64); + void processedData(qint64 pos, qint64 amount); void resetData(bool *b); }; diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index c92c360420..c445677792 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -424,6 +424,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate() , synchronous(false) , state(Idle) , statusCode(0) + , uploadByteDevicePosition(false) , uploadDeviceChoking(false) , outgoingData(0) , bytesUploaded(-1) @@ -867,9 +868,9 @@ void QNetworkReplyHttpImplPrivate::postRequest() q, SLOT(uploadByteDeviceReadyReadSlot()), Qt::QueuedConnection); - // From main thread to user thread: - QObject::connect(q, SIGNAL(haveUploadData(QByteArray,bool,qint64)), - forwardUploadDevice, SLOT(haveDataSlot(QByteArray,bool,qint64)), Qt::QueuedConnection); + // From user thread to http thread: + QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,bool,qint64)), + forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,bool,qint64)), Qt::QueuedConnection); QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()), forwardUploadDevice, SIGNAL(readyRead()), Qt::QueuedConnection); @@ -877,8 +878,8 @@ void QNetworkReplyHttpImplPrivate::postRequest() // From http thread to user thread: QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)), q, SLOT(wantUploadDataSlot(qint64))); - QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)), - q, SLOT(sentUploadDataSlot(qint64))); + QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64, qint64)), + q, SLOT(sentUploadDataSlot(qint64,qint64))); QObject::connect(forwardUploadDevice, SIGNAL(resetData(bool*)), q, SLOT(resetUploadDataSlot(bool*)), Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued! @@ -1278,12 +1279,22 @@ void QNetworkReplyHttpImplPrivate::replyPreSharedKeyAuthenticationRequiredSlot(Q void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r) { *r = uploadByteDevice->reset(); + if (*r) { + // reset our own position which is used for the inter-thread communication + uploadByteDevicePosition = 0; + } } // Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread -void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 amount) +void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 pos, qint64 amount) { + if (uploadByteDevicePosition + amount != pos) { + // Sanity check, should not happen. + error(QNetworkReply::UnknownNetworkError, QString()); + return; + } uploadByteDevice->advanceReadPointer(amount); + uploadByteDevicePosition += amount; } // Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread @@ -1308,7 +1319,7 @@ void QNetworkReplyHttpImplPrivate::wantUploadDataSlot(qint64 maxSize) QByteArray dataArray(data, currentUploadDataLength); // Communicate back to HTTP thread - emit q->haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size()); + emit q->haveUploadData(uploadByteDevicePosition, dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size()); } void QNetworkReplyHttpImplPrivate::uploadByteDeviceReadyReadSlot() diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index afe807ea59..b009092196 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -121,7 +121,7 @@ public: Q_PRIVATE_SLOT(d_func(), void resetUploadDataSlot(bool *r)) Q_PRIVATE_SLOT(d_func(), void wantUploadDataSlot(qint64)) - Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64)) + Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64,qint64)) Q_PRIVATE_SLOT(d_func(), void uploadByteDeviceReadyReadSlot()) Q_PRIVATE_SLOT(d_func(), void emitReplyUploadProgress(qint64, qint64)) Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose()) @@ -145,7 +145,7 @@ signals: void startHttpRequestSynchronously(); - void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize); + void haveUploadData(const qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize); }; class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate @@ -196,6 +196,7 @@ public: // upload QNonContiguousByteDevice* createUploadByteDevice(); QSharedPointer<QNonContiguousByteDevice> uploadByteDevice; + qint64 uploadByteDevicePosition; bool uploadDeviceChoking; // if we couldn't readPointer() any data at the moment QIODevice *outgoingData; QSharedPointer<QRingBuffer> outgoingDataBuffer; @@ -285,7 +286,7 @@ public: // From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread: void resetUploadDataSlot(bool *r); void wantUploadDataSlot(qint64); - void sentUploadDataSlot(qint64); + void sentUploadDataSlot(qint64, qint64); // From user's QNonContiguousByteDevice void uploadByteDeviceReadyReadSlot(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 8ee21b121b..e817287a46 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -688,8 +688,10 @@ void QCocoaWindow::setVisible(bool visible) && [m_nsWindow isKindOfClass:[NSPanel class]]) { [(NSPanel *)m_nsWindow setWorksWhenModal:YES]; if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) { - monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDown handler:^(NSEvent *) { - QWindowSystemInterface::handleMouseEvent(window(), QPointF(-1, -1), QPointF(window()->framePosition() - QPointF(1, 1)), Qt::LeftButton); + monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDownMask|NSMouseMovedMask handler:^(NSEvent *e) { + QPointF localPoint = qt_mac_flipPoint([NSEvent mouseLocation]); + QWindowSystemInterface::handleMouseEvent(window(), window()->mapFromGlobal(localPoint.toPoint()), localPoint, + cocoaButton2QtButton([e buttonNumber])); }]; } } diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h index b792228312..016c50436b 100644 --- a/src/widgets/itemviews/qabstractitemview_p.h +++ b/src/widgets/itemviews/qabstractitemview_p.h @@ -168,8 +168,20 @@ public: QModelIndex index; int col = -1; int row = -1; + const QMimeData *mime = event->mimeData(); + + // Drag enter event shall always be accepted, if mime type and action match. + // Whether the data can actually be dropped will be checked in drag move. + if (event->type() == QEvent::DragEnter) { + const QStringList modelTypes = model->mimeTypes(); + for (int i = 0; i < modelTypes.count(); ++i) + if (mime->hasFormat(modelTypes.at(i)) + && (event->dropAction() & model->supportedDropActions())) + return true; + } + if (dropOn(event, &row, &col, &index)) { - return model->canDropMimeData(event->mimeData(), + return model->canDropMimeData(mime, dragDropMode == QAbstractItemView::InternalMove ? Qt::MoveAction : event->dropAction(), row, col, index); } diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index dd7474b930..d61277f990 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -4273,15 +4273,16 @@ void QApplicationPrivate::cleanupMultitouch_sys() { } -QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos) +QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, const QTouchEvent::TouchPoint &touchPoint) { + const QPointF screenPos = touchPoint.screenPos(); int closestTouchPointId = -1; QObject *closestTarget = 0; qreal closestDistance = qreal(0.); QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it = activeTouchPoints.constBegin(), ite = activeTouchPoints.constEnd(); while (it != ite) { - if (it.key().device == device) { + if (it.key().device == device && it.key().touchPointId != touchPoint.id()) { const QTouchEvent::TouchPoint &touchPoint = it->touchPoint; qreal dx = screenPos.x() - touchPoint.screenPos().x(); qreal dy = screenPos.y() - touchPoint.screenPos().y(); @@ -4337,7 +4338,7 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, } if (device->type() == QTouchDevice::TouchScreen) { - QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint.screenPos()); + QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint); QWidget *widget = static_cast<QWidget *>(target.data()); if (closestWidget && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) { diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 46359d7940..ba8d7ff63c 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -280,7 +280,7 @@ public: void initializeMultitouch_sys(); void cleanupMultitouch(); void cleanupMultitouch_sys(); - QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos); + QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QTouchEvent::TouchPoint &touchPoint); void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint); void removeTouchPoint(int touchPointId); static bool translateRawTouchEvent(QWidget *widget, diff --git a/src/widgets/widgets/qtoolbutton.cpp b/src/widgets/widgets/qtoolbutton.cpp index 5a56c592a6..8473b261fc 100644 --- a/src/widgets/widgets/qtoolbutton.cpp +++ b/src/widgets/widgets/qtoolbutton.cpp @@ -897,7 +897,7 @@ void QToolButton::setDefaultAction(QAction *action) return; if (!actions().contains(action)) addAction(action); - setText(action->iconText()); + setText(action->text()); setIcon(action->icon()); #ifndef QT_NO_TOOLTIP setToolTip(action->toolTip()); |