diff options
Diffstat (limited to 'src')
115 files changed, 1025 insertions, 396 deletions
diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index 51223aef1f..e55ef47683 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -45,12 +45,12 @@ #ifdef __linux__ # define HAVE_WAIT4 1 # if defined(__BIONIC__) || (defined(__GLIBC__) && (__GLIBC__ << 8) + __GLIBC_MINOR__ >= 0x207 && \ - (!defined(__UCLIBC__) || ((__UCLIBC_MAJOR__ << 16) + (__UCLIBC_MINOR__ << 8) + __UCLIBC_SUBLEVEL__ > 0x921))) + (!defined(__UCLIBC__) || ((__UCLIBC_MAJOR__ << 16) + (__UCLIBC_MINOR__ << 8) + __UCLIBC_SUBLEVEL__ > 0x90201))) # include <sys/eventfd.h> # define HAVE_EVENTFD 1 # endif # if defined(__BIONIC__) || (defined(__GLIBC__) && (__GLIBC__ << 8) + __GLIBC_MINOR__ >= 0x209 && \ - (!defined(__UCLIBC__) || ((__UCLIBC_MAJOR__ << 16) + (__UCLIBC_MINOR__ << 8) + __UCLIBC_SUBLEVEL__ > 0x921))) + (!defined(__UCLIBC__) || ((__UCLIBC_MAJOR__ << 16) + (__UCLIBC_MINOR__ << 8) + __UCLIBC_SUBLEVEL__ > 0x90201))) # define HAVE_PIPE2 1 # endif #endif @@ -721,7 +721,7 @@ err_free: } #endif // FORKFD_NO_FORKFD -#if defined(_POSIX_SPAWN) && !defined(FORKFD_NO_SPAWNFD) +#if _POSIX_SPAWN > 0 && !defined(FORKFD_NO_SPAWNFD) int spawnfd(int flags, pid_t *ppid, const char *path, const posix_spawn_file_actions_t *file_actions, posix_spawnattr_t *attrp, char *const argv[], char *const envp[]) { diff --git a/src/3rdparty/forkfd/forkfd.h b/src/3rdparty/forkfd/forkfd.h index dcb36f9f33..38858c00fe 100644 --- a/src/3rdparty/forkfd/forkfd.h +++ b/src/3rdparty/forkfd/forkfd.h @@ -29,7 +29,7 @@ #include <stdint.h> #include <unistd.h> // to get the POSIX flags -#ifdef _POSIX_SPAWN +#if _POSIX_SPAWN > 0 # include <spawn.h> #endif @@ -51,7 +51,7 @@ int forkfd(int flags, pid_t *ppid); int forkfd_wait(int ffd, forkfd_info *info, struct rusage *rusage); int forkfd_close(int ffd); -#ifdef _POSIX_SPAWN +#if _POSIX_SPAWN > 0 /* only for spawnfd: */ # define FFD_SPAWN_SEARCH_PATH O_RDWR diff --git a/src/corelib/arch/qatomic_ia64.h b/src/corelib/arch/qatomic_ia64.h index c880e85209..2ba6d127d9 100644 --- a/src/corelib/arch/qatomic_ia64.h +++ b/src/corelib/arch/qatomic_ia64.h @@ -1035,16 +1035,16 @@ bool QBasicAtomicOps<size>::deref(T &_q_value) Q_DECL_NOTHROW } template<int size> template <typename T> inline -bool QBasicAtomicOps<size>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<size>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { - return testAndSetAcquire(_q_value, expectedValue, newValue); + return testAndSetAcquire(_q_value, expectedValue, newValue, currentValue); } template<int size> template <typename T> inline -bool QBasicAtomicOps<size>::testAndSetOrdered(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<size>::testAndSetOrdered(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { orderedMemoryFence(_q_value); - return testAndSetAcquire(_q_value, expectedValue, newValue); + return testAndSetAcquire(_q_value, expectedValue, newValue, currentValue); } template<int size> template <typename T> inline diff --git a/src/corelib/doc/qtcore.qdocconf b/src/corelib/doc/qtcore.qdocconf index 502689e4c2..3d64708def 100644 --- a/src/corelib/doc/qtcore.qdocconf +++ b/src/corelib/doc/qtcore.qdocconf @@ -25,8 +25,7 @@ qhp.QtCore.subprojects.classes.sortPages = true tagfile = ../../../doc/qtcore/qtcore.tags -depends += activeqt qtdbus qtgui qtwidgets qtnetwork qtdoc qtmacextras qtquick qtlinguist qtdesigner qtconcurrent qtxml qmake qtwinextras -# depends += qtqml # Qt namespace collides with QtQml::Qt, see QTBUG-38630 +depends += activeqt qtdbus qtgui qtwidgets qtnetwork qtdoc qtmacextras qtquick qtlinguist qtdesigner qtconcurrent qtxml qmake qtwinextras qtqml headerdirs += .. diff --git a/src/corelib/doc/src/statemachine.qdoc b/src/corelib/doc/src/statemachine.qdoc index e44a603959..d50851d816 100644 --- a/src/corelib/doc/src/statemachine.qdoc +++ b/src/corelib/doc/src/statemachine.qdoc @@ -71,6 +71,8 @@ which are currently active. All the states in a valid configuration of the state machine will have a common ancestor. + \sa {The Declarative State Machine Framework} + \section1 Classes in the State Machine Framework These classes are provided by qt for creating event-driven state machines. diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 3dc791397c..443eae5a11 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -1714,6 +1714,17 @@ \value Key_Zoom \value Key_Exit \value Key_Cancel + \value Key_MicVolumeUp + \value Key_Find + \value Key_Open + \value Key_MicVolumeDown + \value Key_New + \value Key_Settings + \value Key_Redo + \value Key_Exit + \value Key_Info + \value Key_Undo + \value Key_Guide \sa QKeyEvent::key() */ diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 84a6a1d9cb..c80c78bd3b 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -83,6 +83,7 @@ void debugBinaryString(const char *data, qint64 maxlen) static void checkWarnMessage(const QIODevice *device, const char *function, const char *what) { +#ifndef QT_NO_WARNING_OUTPUT QDebug d = qWarning(); d.noquote(); d.nospace(); @@ -98,6 +99,11 @@ static void checkWarnMessage(const QIODevice *device, const char *function, cons Q_UNUSED(device) #endif // !QT_NO_QOBJECT d << ": " << what; +#else + Q_UNUSED(device); + Q_UNUSED(function); + Q_UNUSED(what); +#endif // QT_NO_WARNING_OUTPUT } #define CHECK_MAXLEN(function, returnType) \ diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index b298b08939..019059917a 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -56,7 +56,13 @@ # include <cstdio> #elif defined(Q_OS_BSD4) && !defined(Q_OS_IOS) # include <sys/user.h> +# if defined(__GLIBC__) && defined(__FreeBSD_kernel__) +# include <sys/cdefs.h> +# include <sys/param.h> +# include <sys/sysctl.h> +# else # include <libutil.h> +# endif #endif QT_BEGIN_NAMESPACE @@ -241,9 +247,27 @@ QString QLockFilePrivate::processNameByPid(qint64 pid) buf[len] = 0; return QFileInfo(QFile::decodeName(buf)).fileName(); #elif defined(Q_OS_BSD4) && !defined(Q_OS_IOS) +# if defined(__GLIBC__) && defined(__FreeBSD_kernel__) + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; + size_t len = 0; + if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) + return QString(); + kinfo_proc *proc = static_cast<kinfo_proc *>(malloc(len)); +# else kinfo_proc *proc = kinfo_getproc(pid); +# endif if (!proc) return QString(); +# if defined(__GLIBC__) && defined(__FreeBSD_kernel__) + if (sysctl(mib, 4, proc, &len, NULL, 0) < 0) { + free(proc); + return QString(); + } + if (proc->ki_pid != pid) { + free(proc); + return QString(); + } +# endif QString name = QFile::decodeName(proc->ki_comm); free(proc); return name; diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp index 0a13f94f05..ed1c14ad8a 100644 --- a/src/corelib/io/qstandardpaths_win.cpp +++ b/src/corelib/io/qstandardpaths_win.cpp @@ -200,7 +200,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type) case AppDataLocation: case AppLocalDataLocation: case GenericDataLocation: - if (SHGetSpecialFolderPath(0, path, clsidForAppDataLocation(type), FALSE)) { + if (SHGetSpecialFolderPath(0, path, CSIDL_COMMON_APPDATA, FALSE)) { QString result = convertCharArray(path); if (type != GenericDataLocation && type != GenericConfigLocation) { #ifndef QT_BOOTSTRAPPED diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index ca3be9b7e0..ccf832e2e8 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -2858,7 +2858,7 @@ QTextStream &endl(QTextStream &stream) /*! \relates QTextStream - Calls \l{QTextStream::flush()}{flush()} on \a stream and returns \a stream. + Calls QTextStream::flush() on \a stream and returns \a stream. \sa endl(), reset(), {QTextStream manipulators} */ diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index 2cc5741250..a49fcdaf9f 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -187,7 +187,7 @@ void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode, pipeBroken = true; break; default: - emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead")); + emit winError(errorCode, QLatin1String("QWindowsPipeReader::notified")); pipeBroken = true; break; } diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp index 57053f129a..fd14523d45 100644 --- a/src/corelib/io/qwindowspipewriter.cpp +++ b/src/corelib/io/qwindowspipewriter.cpp @@ -90,11 +90,38 @@ qint64 QWindowsPipeWriter::write(const char *ptr, qint64 maxlen) return maxlen; } +class QPipeWriterOverlapped +{ +public: + QPipeWriterOverlapped() + { + overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + } + + ~QPipeWriterOverlapped() + { + CloseHandle(overlapped.hEvent); + } + + void prepare() + { + const HANDLE hEvent = overlapped.hEvent; + ZeroMemory(&overlapped, sizeof overlapped); + overlapped.hEvent = hEvent; + } + + OVERLAPPED *operator&() + { + return &overlapped; + } + +private: + OVERLAPPED overlapped; +}; + void QWindowsPipeWriter::run() { - OVERLAPPED overl; - memset(&overl, 0, sizeof overl); - overl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + QPipeWriterOverlapped overl; forever { lock.lock(); while(data.isEmpty() && (!quitNow)) { @@ -115,26 +142,24 @@ void QWindowsPipeWriter::run() const char *ptrData = copy.data(); qint64 maxlen = copy.size(); qint64 totalWritten = 0; - overl.Offset = 0; - overl.OffsetHigh = 0; + overl.prepare(); while ((!quitNow) && totalWritten < maxlen) { DWORD written = 0; if (!WriteFile(writePipe, ptrData + totalWritten, maxlen - totalWritten, &written, &overl)) { - - if (GetLastError() == 0xE8/*NT_STATUS_INVALID_USER_BUFFER*/) { + const DWORD writeError = GetLastError(); + if (writeError == 0xE8/*NT_STATUS_INVALID_USER_BUFFER*/) { // give the os a rest msleep(100); continue; } #ifndef Q_OS_WINCE - if (GetLastError() == ERROR_IO_PENDING) { - if (!GetOverlappedResult(writePipe, &overl, &written, TRUE)) { - CloseHandle(overl.hEvent); - return; - } - } else { - CloseHandle(overl.hEvent); + if (writeError != ERROR_IO_PENDING) { + qErrnoWarning(writeError, "QWindowsPipeWriter: async WriteFile failed."); + return; + } + if (!GetOverlappedResult(writePipe, &overl, &written, TRUE)) { + qErrnoWarning(GetLastError(), "QWindowsPipeWriter: GetOverlappedResult failed."); return; } #else @@ -154,7 +179,6 @@ void QWindowsPipeWriter::run() emit bytesWritten(totalWritten); emit canWrite(); } - CloseHandle(overl.hEvent); } #endif //QT_NO_THREAD diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 8f4774a1e0..2719019d30 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -455,8 +455,8 @@ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint qt_application_thread_id = QThread::currentThreadId(); # endif - // note: this call to QThread::currentThread() may end up setting theMainThread! - if (QThread::currentThread() != theMainThread) + QThread *cur = QThread::currentThread(); // note: this may end up setting theMainThread! + if (cur != theMainThread) qWarning("WARNING: QApplication was not created in the main() thread."); #endif } @@ -526,11 +526,11 @@ void QCoreApplicationPrivate::eventDispatcherReady() { } -QThread *QCoreApplicationPrivate::theMainThread = 0; +QBasicAtomicPointer<QThread> QCoreApplicationPrivate::theMainThread = Q_BASIC_ATOMIC_INITIALIZER(0); QThread *QCoreApplicationPrivate::mainThread() { - Q_ASSERT(theMainThread != 0); - return theMainThread; + Q_ASSERT(theMainThread.load() != 0); + return theMainThread.load(); } bool QCoreApplicationPrivate::threadRequiresCoreApplication() @@ -2759,7 +2759,7 @@ bool QCoreApplication::hasPendingEvents() QAbstractEventDispatcher *QCoreApplication::eventDispatcher() { if (QCoreApplicationPrivate::theMainThread) - return QCoreApplicationPrivate::theMainThread->eventDispatcher(); + return QCoreApplicationPrivate::theMainThread.load()->eventDispatcher(); return 0; } diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index 21f59d8197..9a9e8dd09a 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -105,7 +105,7 @@ public: } void maybeQuit(); - static QThread *theMainThread; + static QBasicAtomicPointer<QThread> theMainThread; static QThread *mainThread(); static bool threadRequiresCoreApplication(); diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index e8ff8a7936..ecaa78cbbc 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -390,6 +390,8 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA QSockNot *sn = dict ? dict->value(wp) : 0; if (sn) { + d->doWsaAsyncSelect(sn->fd, 0); + d->active_fd[sn->fd].selected = false; if (type < 3) { QEvent event(QEvent::SockAct); QCoreApplication::sendEvent(sn->obj, &event); @@ -632,19 +634,12 @@ void QEventDispatcherWin32Private::sendTimerEvent(int timerId) } } -void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket) +void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket, long event) { Q_ASSERT(internalHwnd); - int sn_event = 0; - if (sn_read.contains(socket)) - sn_event |= FD_READ | FD_CLOSE | FD_ACCEPT; - if (sn_write.contains(socket)) - sn_event |= FD_WRITE | FD_CONNECT; - if (sn_except.contains(socket)) - sn_event |= FD_OOB; - // BoundsChecker may emit a warning for WSAAsyncSelect when sn_event == 0 + // BoundsChecker may emit a warning for WSAAsyncSelect when event == 0 // This is a BoundsChecker bug and not a Qt bug - WSAAsyncSelect(socket, internalHwnd, sn_event ? int(WM_QT_SOCKETNOTIFIER) : 0, sn_event); + WSAAsyncSelect(socket, internalHwnd, event ? int(WM_QT_SOCKETNOTIFIER) : 0, event); } void QEventDispatcherWin32::createInternalHwnd() @@ -657,13 +652,6 @@ void QEventDispatcherWin32::createInternalHwnd() installMessageHook(); - // register all socket notifiers - QList<int> sockets = (d->sn_read.keys().toSet() - + d->sn_write.keys().toSet() - + d->sn_except.keys().toSet()).toList(); - for (int i = 0; i < sockets.count(); ++i) - d->doWsaAsyncSelect(sockets.at(i)); - // start all normal timers for (int i = 0; i < d->timerVec.count(); ++i) d->registerTimer(d->timerVec.at(i)); @@ -748,28 +736,40 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) msg = d->queuedSocketEvents.takeFirst(); } else { haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE); - if (haveMessage && (flags & QEventLoop::ExcludeUserInputEvents) - && ((msg.message >= WM_KEYFIRST - && msg.message <= WM_KEYLAST) - || (msg.message >= WM_MOUSEFIRST - && msg.message <= WM_MOUSELAST) - || msg.message == WM_MOUSEWHEEL - || msg.message == WM_MOUSEHWHEEL - || msg.message == WM_TOUCH + if (haveMessage) { + if ((flags & QEventLoop::ExcludeUserInputEvents) + && ((msg.message >= WM_KEYFIRST + && msg.message <= WM_KEYLAST) + || (msg.message >= WM_MOUSEFIRST + && msg.message <= WM_MOUSELAST) + || msg.message == WM_MOUSEWHEEL + || msg.message == WM_MOUSEHWHEEL + || msg.message == WM_TOUCH #ifndef QT_NO_GESTURES - || msg.message == WM_GESTURE - || msg.message == WM_GESTURENOTIFY + || msg.message == WM_GESTURE + || msg.message == WM_GESTURENOTIFY #endif - || msg.message == WM_CLOSE)) { - // queue user input events for later processing - haveMessage = false; - d->queuedUserInputEvents.append(msg); - } - if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers) - && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) { - // queue socket events for later processing - haveMessage = false; - d->queuedSocketEvents.append(msg); + || msg.message == WM_CLOSE)) { + // queue user input events for later processing + d->queuedUserInputEvents.append(msg); + continue; + } + if ((flags & QEventLoop::ExcludeSocketNotifiers) + && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) { + // queue socket events for later processing + d->queuedSocketEvents.append(msg); + continue; + } + } else if (!(flags & QEventLoop::ExcludeSocketNotifiers)) { + // register all socket notifiers + for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end(); + it != end; ++it) { + QSockFd &sd = it.value(); + if (!sd.selected) { + d->doWsaAsyncSelect(it.key(), sd.event); + sd.selected = true; + } + } } } if (!haveMessage) { @@ -895,8 +895,25 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier) sn->fd = sockfd; dict->insert(sn->fd, sn); - if (d->internalHwnd) - d->doWsaAsyncSelect(sockfd); + long event = 0; + if (d->sn_read.contains(sockfd)) + event |= FD_READ | FD_CLOSE | FD_ACCEPT; + if (d->sn_write.contains(sockfd)) + event |= FD_WRITE | FD_CONNECT; + if (d->sn_except.contains(sockfd)) + event |= FD_OOB; + + QSFDict::iterator it = d->active_fd.find(sockfd); + if (it != d->active_fd.end()) { + QSockFd &sd = it.value(); + if (sd.selected) { + d->doWsaAsyncSelect(sockfd, 0); + sd.selected = false; + } + sd.event |= event; + } else { + d->active_fd.insert(sockfd, QSockFd(event)); + } } void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier) @@ -915,6 +932,19 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier) #endif Q_D(QEventDispatcherWin32); + QSFDict::iterator it = d->active_fd.find(sockfd); + if (it != d->active_fd.end()) { + QSockFd &sd = it.value(); + if (sd.selected) + d->doWsaAsyncSelect(sockfd, 0); + const long event[3] = { FD_READ | FD_CLOSE | FD_ACCEPT, FD_WRITE | FD_CONNECT, FD_OOB }; + sd.event ^= event[type]; + if (sd.event == 0) + d->active_fd.erase(it); + else + sd.selected = false; + } + QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except }; QSNDict *dict = sn_vec[type]; QSockNot *sn = dict->value(sockfd); @@ -923,9 +953,6 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier) dict->remove(sockfd); delete sn; - - if (d->internalHwnd) - d->doWsaAsyncSelect(sockfd); } void QEventDispatcherWin32::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) @@ -1163,6 +1190,7 @@ void QEventDispatcherWin32::closingDown() unregisterSocketNotifier((*(d->sn_write.begin()))->obj); while (!d->sn_except.isEmpty()) unregisterSocketNotifier((*(d->sn_except.begin()))->obj); + Q_ASSERT(d->active_fd.isEmpty()); // clean up any timers for (int i = 0; i < d->timerVec.count(); ++i) diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index e59e29f1ff..8578110ee4 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -115,6 +115,14 @@ struct QSockNot { }; typedef QHash<int, QSockNot *> QSNDict; +struct QSockFd { + long event; + bool selected; + + explicit inline QSockFd(long ev = 0) : event(ev), selected(false) { } +}; +typedef QHash<int, QSockFd> QSFDict; + struct WinTimerInfo { // internal timer info QObject *dispatcher; int timerId; @@ -169,7 +177,8 @@ public: QSNDict sn_read; QSNDict sn_write; QSNDict sn_except; - void doWsaAsyncSelect(int socket); + QSFDict active_fd; + void doWsaAsyncSelect(int socket, long event); QList<QWinEventNotifier *> winEventNotifierList; void activateEventNotifier(QWinEventNotifier * wen); diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 7ae9fef622..f1ad74efb4 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -1547,12 +1547,13 @@ bool QMetaObject::invokeMethod(QObject *obj, /*! \fn QMetaObject::Connection &QMetaObject::Connection::operator=(Connection &&other) - Move-assigns \a other to this object. + Move-assigns \a other to this object, and returns a reference. */ /*! \fn QMetaObject::Connection::Connection(Connection &&o) - Move-constructs a Connection instance, making it point to the same object that \a o was pointing to. + Move-constructs a Connection instance, making it point to the same object + that \a o was pointing to. */ /*! diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index d324b6f150..4bd8b4b662 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1485,7 +1485,7 @@ void QObject::moveToThread(QThread *targetThread) } else if (d->threadData != currentData) { qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n" "Cannot move to target thread (%p)\n", - currentData->thread, d->threadData->thread, targetData ? targetData->thread : Q_NULLPTR); + currentData->thread.load(), d->threadData->thread.load(), targetData ? targetData->thread.load() : Q_NULLPTR); #ifdef Q_OS_MAC qWarning("You might be loading two sets of Qt binaries into the same process. " diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp index d789af2fd9..3a5eff0c19 100644 --- a/src/corelib/kernel/qsocketnotifier.cpp +++ b/src/corelib/kernel/qsocketnotifier.cpp @@ -98,42 +98,6 @@ public: QTcpSocket and QUdpSocket provide notification through signals, so there is normally no need to use a QSocketNotifier on them. - \section1 Notes for Windows Users - - The socket passed to QSocketNotifier will become non-blocking, even if - it was created as a blocking socket. - The activated() signal is sometimes triggered by high general activity - on the host, even if there is nothing to read. A subsequent read from - the socket can then fail, the error indicating that there is no data - available (e.g., \c{WSAEWOULDBLOCK}). This is an operating system - limitation, and not a bug in QSocketNotifier. - - To ensure that the socket notifier handles read notifications correctly, - follow these steps when you receive a notification: - - \list 1 - \li Disable the notifier. - \li Read data from the socket. - \li Re-enable the notifier if you are interested in more data (such as after - having written a new command to a remote server). - \endlist - - To ensure that the socket notifier handles write notifications correctly, - follow these steps when you receive a notification: - - \list 1 - \li Disable the notifier. - \li Write as much data as you can (before \c EWOULDBLOCK is returned). - \li Re-enable notifier if you have more data to write. - \endlist - - \b{Further information:} - On Windows, Qt always disables the notifier after getting a notification, - and only re-enables it if more data is expected. For example, if data is - read from the socket and it can be used to read more, or if reading or - writing is not possible because the socket would block, in which case - it is necessary to wait before attempting to read or write again. - \sa QFile, QProcess, QTcpSocket, QUdpSocket */ diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp index 133933f9af..c1e17b9fc4 100644 --- a/src/corelib/mimetypes/qmimedatabase.cpp +++ b/src/corelib/mimetypes/qmimedatabase.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. diff --git a/src/corelib/mimetypes/qmimedatabase.h b/src/corelib/mimetypes/qmimedatabase.h index 912d9b8443..fd19636e27 100644 --- a/src/corelib/mimetypes/qmimedatabase.h +++ b/src/corelib/mimetypes/qmimedatabase.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. diff --git a/src/corelib/mimetypes/qmimedatabase_p.h b/src/corelib/mimetypes/qmimedatabase_p.h index 1308907b9b..1ac7264a9e 100644 --- a/src/corelib/mimetypes/qmimedatabase_p.h +++ b/src/corelib/mimetypes/qmimedatabase_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. diff --git a/src/corelib/mimetypes/qmimemagicrule.cpp b/src/corelib/mimetypes/qmimemagicrule.cpp index c8508ac0d2..6a3a429179 100644 --- a/src/corelib/mimetypes/qmimemagicrule.cpp +++ b/src/corelib/mimetypes/qmimemagicrule.cpp @@ -38,6 +38,7 @@ #ifndef QT_NO_MIMETYPE +#include "qmimetypeparser_p.h" #include <QtCore/QList> #include <QtCore/QDebug> #include <qendian.h> @@ -231,26 +232,53 @@ static inline QByteArray makePattern(const QByteArray &value) return pattern; } -QMimeMagicRule::QMimeMagicRule(QMimeMagicRule::Type theType, +// Evaluate a magic match rule like +// <match value="must be converted with BinHex" type="string" offset="11"/> +// <match value="0x9501" type="big16" offset="0:64"/> + +QMimeMagicRule::QMimeMagicRule(const QString &typeStr, const QByteArray &theValue, - int theStartPos, - int theEndPos, - const QByteArray &theMask) : + const QString &offsets, + const QByteArray &theMask, + QString *errorString) : d(new QMimeMagicRulePrivate) { - Q_ASSERT(!theValue.isEmpty()); - - d->type = theType; d->value = theValue; - d->startPos = theStartPos; - d->endPos = theEndPos; d->mask = theMask; d->matchFunction = 0; + d->type = QMimeMagicRule::type(typeStr.toLatin1()); + if (d->type == Invalid) { + *errorString = QStringLiteral("Type %s is not supported").arg(typeStr); + } + + // Parse for offset as "1" or "1:10" + const int colonIndex = offsets.indexOf(QLatin1Char(':')); + const QString startPosStr = colonIndex == -1 ? offsets : offsets.mid(0, colonIndex); + const QString endPosStr = colonIndex == -1 ? offsets : offsets.mid(colonIndex + 1); + if (!QMimeTypeParserBase::parseNumber(startPosStr, &d->startPos, errorString) || + !QMimeTypeParserBase::parseNumber(endPosStr, &d->endPos, errorString)) { + d->type = Invalid; + return; + } + + if (d->value.isEmpty()) { + d->type = Invalid; + if (errorString) + *errorString = QLatin1String("Invalid empty magic rule value"); + return; + } + if (d->type >= Host16 && d->type <= Byte) { bool ok; d->number = d->value.toUInt(&ok, 0); // autodetect - Q_ASSERT(ok); + if (!ok) { + d->type = Invalid; + if (errorString) + *errorString = QString::fromLatin1("Invalid magic rule value \"%1\"").arg( + QString::fromLatin1(d->value)); + return; + } d->numberMask = !d->mask.isEmpty() ? d->mask.toUInt(&ok, 0) : 0; // autodetect } @@ -259,9 +287,23 @@ QMimeMagicRule::QMimeMagicRule(QMimeMagicRule::Type theType, d->pattern = makePattern(d->value); d->pattern.squeeze(); if (!d->mask.isEmpty()) { - Q_ASSERT(d->mask.size() >= 4 && d->mask.startsWith("0x")); - d->mask = QByteArray::fromHex(QByteArray::fromRawData(d->mask.constData() + 2, d->mask.size() - 2)); - Q_ASSERT(d->mask.size() == d->pattern.size()); + if (d->mask.size() < 4 || !d->mask.startsWith("0x")) { + d->type = Invalid; + if (errorString) + *errorString = QString::fromLatin1("Invalid magic rule mask \"%1\"").arg( + QString::fromLatin1(d->mask)); + return; + } + const QByteArray &tempMask = QByteArray::fromHex(QByteArray::fromRawData( + d->mask.constData() + 2, d->mask.size() - 2)); + if (tempMask.size() != d->pattern.size()) { + d->type = Invalid; + if (errorString) + *errorString = QString::fromLatin1("Invalid magic rule mask size \"%1\"").arg( + QString::fromLatin1(d->mask)); + return; + } + d->mask = tempMask; } else { d->mask.fill(char(-1), d->pattern.size()); } diff --git a/src/corelib/mimetypes/qmimemagicrule_p.h b/src/corelib/mimetypes/qmimemagicrule_p.h index 03ac1d1de9..6b64bfcc10 100644 --- a/src/corelib/mimetypes/qmimemagicrule_p.h +++ b/src/corelib/mimetypes/qmimemagicrule_p.h @@ -61,7 +61,8 @@ class QMimeMagicRule public: enum Type { Invalid = 0, String, Host16, Host32, Big16, Big32, Little16, Little32, Byte }; - QMimeMagicRule(Type type, const QByteArray &value, int startPos, int endPos, const QByteArray &mask = QByteArray()); + QMimeMagicRule(const QString &typeStr, const QByteArray &value, const QString &offsets, + const QByteArray &mask, QString *errorString); QMimeMagicRule(const QMimeMagicRule &other); ~QMimeMagicRule(); diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp index fa40b743d3..a8a1331053 100644 --- a/src/corelib/mimetypes/qmimeprovider.cpp +++ b/src/corelib/mimetypes/qmimeprovider.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. diff --git a/src/corelib/mimetypes/qmimeprovider_p.h b/src/corelib/mimetypes/qmimeprovider_p.h index eaf95942f7..c0517d69a4 100644 --- a/src/corelib/mimetypes/qmimeprovider_p.h +++ b/src/corelib/mimetypes/qmimeprovider_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp index 3206ff66e3..e3b01bbb89 100644 --- a/src/corelib/mimetypes/qmimetype.cpp +++ b/src/corelib/mimetypes/qmimetype.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. diff --git a/src/corelib/mimetypes/qmimetype.h b/src/corelib/mimetypes/qmimetype.h index 054a5841c4..6a00541ebc 100644 --- a/src/corelib/mimetypes/qmimetype.h +++ b/src/corelib/mimetypes/qmimetype.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. diff --git a/src/corelib/mimetypes/qmimetypeparser.cpp b/src/corelib/mimetypes/qmimetypeparser.cpp index 9610162c4f..8a8b97655a 100644 --- a/src/corelib/mimetypes/qmimetypeparser.cpp +++ b/src/corelib/mimetypes/qmimetypeparser.cpp @@ -153,8 +153,8 @@ QMimeTypeParserBase::ParseState QMimeTypeParserBase::nextState(ParseState curren return ParseError; } -// Parse int number from an (attribute) string) -static bool parseNumber(const QString &n, int *target, QString *errorMessage) +// Parse int number from an (attribute) string +bool QMimeTypeParserBase::parseNumber(const QString &n, int *target, QString *errorMessage) { bool ok; *target = n.toInt(&ok); @@ -165,37 +165,14 @@ static bool parseNumber(const QString &n, int *target, QString *errorMessage) return true; } -// Evaluate a magic match rule like -// <match value="must be converted with BinHex" type="string" offset="11"/> -// <match value="0x9501" type="big16" offset="0:64"/> #ifndef QT_NO_XMLSTREAMREADER -static bool createMagicMatchRule(const QXmlStreamAttributes &atts, - QString *errorMessage, QMimeMagicRule *&rule) +static QMimeMagicRule *createMagicMatchRule(const QXmlStreamAttributes &atts, QString *errorMessage) { const QString type = atts.value(QLatin1String(matchTypeAttributeC)).toString(); - QMimeMagicRule::Type magicType = QMimeMagicRule::type(type.toLatin1()); - if (magicType == QMimeMagicRule::Invalid) { - qWarning("%s: match type %s is not supported.", Q_FUNC_INFO, type.toUtf8().constData()); - return true; - } const QString value = atts.value(QLatin1String(matchValueAttributeC)).toString(); - if (value.isEmpty()) { - *errorMessage = QString::fromLatin1("Empty match value detected."); - return false; - } - // Parse for offset as "1" or "1:10" - int startPos, endPos; - const QString offsetS = atts.value(QLatin1String(matchOffsetAttributeC)).toString(); - const int colonIndex = offsetS.indexOf(QLatin1Char(':')); - const QString startPosS = colonIndex == -1 ? offsetS : offsetS.mid(0, colonIndex); - const QString endPosS = colonIndex == -1 ? offsetS : offsetS.mid(colonIndex + 1); - if (!parseNumber(startPosS, &startPos, errorMessage) || !parseNumber(endPosS, &endPos, errorMessage)) - return false; + const QString offsets = atts.value(QLatin1String(matchOffsetAttributeC)).toString(); const QString mask = atts.value(QLatin1String(matchMaskAttributeC)).toString(); - - rule = new QMimeMagicRule(magicType, value.toUtf8(), startPos, endPos, mask.toLatin1()); - - return true; + return new QMimeMagicRule(type, value.toUtf8(), offsets, mask.toLatin1(), errorMessage); } #endif @@ -283,9 +260,10 @@ bool QMimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString } break; case ParseMagicMatchRule: { - QMimeMagicRule *rule = 0; - if (!createMagicMatchRule(atts, errorMessage, rule)) - return false; + QString magicErrorMessage; + QMimeMagicRule *rule = createMagicMatchRule(atts, &magicErrorMessage); + if (!rule->isValid()) + qWarning("QMimeDatabase: Error parsing %s\n%s", qPrintable(fileName), qPrintable(magicErrorMessage)); QList<QMimeMagicRule> *ruleList; if (currentRules.isEmpty()) ruleList = &rules; diff --git a/src/corelib/mimetypes/qmimetypeparser_p.h b/src/corelib/mimetypes/qmimetypeparser_p.h index 2be4380cee..3a2e6b8a14 100644 --- a/src/corelib/mimetypes/qmimetypeparser_p.h +++ b/src/corelib/mimetypes/qmimetypeparser_p.h @@ -66,6 +66,8 @@ public: bool parse(QIODevice *dev, const QString &fileName, QString *errorMessage); + static bool parseNumber(const QString &n, int *target, QString *errorMessage); + protected: virtual bool process(const QMimeType &t, QString *errorMessage) = 0; virtual bool process(const QMimeGlobPattern &t, QString *errorMessage) = 0; diff --git a/src/corelib/plugin/qelfparser_p.cpp b/src/corelib/plugin/qelfparser_p.cpp index d93be439e0..3798231383 100644 --- a/src/corelib/plugin/qelfparser_p.cpp +++ b/src/corelib/plugin/qelfparser_p.cpp @@ -148,7 +148,7 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library #endif ElfSectionHeader strtab; - qulonglong soff = e_shoff + e_shentsize * (e_shtrndx); + qulonglong soff = e_shoff + qelfword_t(e_shentsize) * qelfword_t(e_shtrndx); if ((soff + e_shentsize) > fdlen || soff % 4 || soff == 0) { if (lib) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 3269ee3ae8..742a572bef 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -571,19 +571,26 @@ FreeList *freelist() return &list; } #else +static QBasicAtomicPointer<FreeList> freeListPtr; + FreeList *freelist() { - static QAtomicPointer<FreeList> list; - FreeList *local = list.loadAcquire(); + FreeList *local = freeListPtr.loadAcquire(); if (!local) { local = new FreeList; - if (!list.testAndSetRelease(0, local)) { + if (!freeListPtr.testAndSetRelease(0, local)) { delete local; - local = list.loadAcquire(); + local = freeListPtr.loadAcquire(); } } return local; } + +static void qFreeListDeleter() +{ + delete freeListPtr.load(); +} +Q_DESTRUCTOR_FUNCTION(qFreeListDeleter) #endif } diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index ffefe0b1d1..a0d354acdc 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -276,7 +276,7 @@ public: QStack<QEventLoop *> eventLoops; QPostEventList postEventList; - QThread *thread; + QAtomicPointer<QThread> thread; Qt::HANDLE threadId; QAtomicPointer<QAbstractEventDispatcher> eventDispatcher; QVector<void *> tls; diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 4b50936958..c340915d35 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -222,7 +222,7 @@ QThreadData *QThreadData::current(bool createIfNecessary) data->isAdopted = true; data->threadId = (Qt::HANDLE)pthread_self(); if (!QCoreApplicationPrivate::theMainThread) - QCoreApplicationPrivate::theMainThread = data->thread; + QCoreApplicationPrivate::theMainThread = data->thread.load(); } return data; } diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 72f04ff7af..1a4b41fee4 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -121,7 +121,7 @@ QThreadData *QThreadData::current(bool createIfNecessary) threadData->threadId = reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId())); if (!QCoreApplicationPrivate::theMainThread) { - QCoreApplicationPrivate::theMainThread = threadData->thread; + QCoreApplicationPrivate::theMainThread = threadData->thread.load(); // TODO: is there a way to reflect the branch's behavior using // WinRT API? } else { diff --git a/src/corelib/thread/qthreadstorage.cpp b/src/corelib/thread/qthreadstorage.cpp index 05ab01cc54..37892233f3 100644 --- a/src/corelib/thread/qthreadstorage.cpp +++ b/src/corelib/thread/qthreadstorage.cpp @@ -121,7 +121,7 @@ void **QThreadStorageData::get() const DEBUG_MSG("QThreadStorageData: Returning storage %d, data %p, for thread %p", id, *v, - data->thread); + data->thread.load()); return *v ? v : 0; } @@ -143,7 +143,7 @@ void **QThreadStorageData::set(void *p) DEBUG_MSG("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", id, value, - data->thread); + data->thread.load()); QMutexLocker locker(&destructorsMutex); DestructorMap *destr = destructors(); @@ -159,7 +159,7 @@ void **QThreadStorageData::set(void *p) // store new data value = p; - DEBUG_MSG("QThreadStorageData: Set storage %d for thread %p to %p", id, data->thread, p); + DEBUG_MSG("QThreadStorageData: Set storage %d for thread %p to %p", id, data->thread.load(), p); return &value; } diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 0d7225eea0..4854ceb5ca 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -3123,6 +3123,7 @@ QTimeZone QDateTime::timeZone() const case Qt::UTC: return QTimeZone::utc(); case Qt::OffsetFromUTC: + return QTimeZone(d->m_offsetFromUtc); case Qt::TimeZone: Q_ASSERT(d->m_timeZone.isValid()); return d->m_timeZone; diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 643378a7bd..7829317d1f 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -1244,13 +1244,13 @@ inline bool QByteArray::operator==(const QString &s) const inline bool QByteArray::operator!=(const QString &s) const { return QString::compare_helper(s.constData(), s.size(), constData(), size()) != 0; } inline bool QByteArray::operator<(const QString &s) const -{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) < 0; } -inline bool QByteArray::operator>(const QString &s) const { return QString::compare_helper(s.constData(), s.size(), constData(), size()) > 0; } +inline bool QByteArray::operator>(const QString &s) const +{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) < 0; } inline bool QByteArray::operator<=(const QString &s) const -{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) <= 0; } -inline bool QByteArray::operator>=(const QString &s) const { return QString::compare_helper(s.constData(), s.size(), constData(), size()) >= 0; } +inline bool QByteArray::operator>=(const QString &s) const +{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) <= 0; } #endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) #ifndef QT_NO_CAST_TO_ASCII diff --git a/src/corelib/tools/qstringalgorithms_p.h b/src/corelib/tools/qstringalgorithms_p.h index 65901b0286..a12874f567 100644 --- a/src/corelib/tools/qstringalgorithms_p.h +++ b/src/corelib/tools/qstringalgorithms_p.h @@ -101,8 +101,6 @@ template <typename StringType> struct QStringAlgorithms if (begin == str.cbegin() && end == str.cend()) return str; - if (begin == end) - return StringType(); if (!isConst && str.isDetached()) return trimmed_helper_inplace(str, begin, end); return StringType(begin, end - begin); diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index 618352d363..0ef587f333 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -1171,7 +1171,7 @@ QImageIOHandler::Transformations QImageReader::transformation() const Determines that images returned by read() should have transformation metadata automatically applied if \a enabled is \c true. - \sa autoTransform(), read() + \sa autoTransform(), transformation(), read() */ void QImageReader::setAutoTransform(bool enabled) { diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 0f4256b740..f460431c2b 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -182,7 +182,8 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q } else { // read ascii data uchar *p; int n; - for (y=0; y<h; y++) { + char buf; + for (y = 0; (y < h) && (device->peek(&buf, 1) == 1); y++) { p = outImage->scanLine(y); n = pbm_bpl; if (nbits == 1) { diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp index dbf2b3c21f..c25f3c2665 100644 --- a/src/gui/kernel/qcursor.cpp +++ b/src/gui/kernel/qcursor.cpp @@ -393,7 +393,7 @@ QCursor::QCursor(const QPixmap &pixmap, int hotX, int hotY) bmm.fill(Qt::color1); } - d = QCursorData::setBitmap(bm, bmm, hotX, hotY); + d = QCursorData::setBitmap(bm, bmm, hotX, hotY, pixmap.devicePixelRatio()); d->pixmap = pixmap; } @@ -436,7 +436,7 @@ QCursor::QCursor(const QPixmap &pixmap, int hotX, int hotY) QCursor::QCursor(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY) : d(0) { - d = QCursorData::setBitmap(bitmap, mask, hotX, hotY); + d = QCursorData::setBitmap(bitmap, mask, hotX, hotY, 1.0); } /*! @@ -656,7 +656,7 @@ void QCursorData::initialize() QCursorData::initialized = true; } -QCursorData *QCursorData::setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY) +QCursorData *QCursorData::setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY, qreal devicePixelRatio) { if (!QCursorData::initialized) QCursorData::initialize(); @@ -670,8 +670,8 @@ QCursorData *QCursorData::setBitmap(const QBitmap &bitmap, const QBitmap &mask, d->bm = new QBitmap(bitmap); d->bmm = new QBitmap(mask); d->cshape = Qt::BitmapCursor; - d->hx = hotX >= 0 ? hotX : bitmap.width() / 2; - d->hy = hotY >= 0 ? hotY : bitmap.height() / 2; + d->hx = hotX >= 0 ? hotX : bitmap.width() / 2 / devicePixelRatio; + d->hy = hotY >= 0 ? hotY : bitmap.height() / 2 / devicePixelRatio; return d; } diff --git a/src/gui/kernel/qcursor_p.h b/src/gui/kernel/qcursor_p.h index 0aaa62b891..188ea387b3 100644 --- a/src/gui/kernel/qcursor_p.h +++ b/src/gui/kernel/qcursor_p.h @@ -70,7 +70,8 @@ public: short hx, hy; static bool initialized; void update(); - static QCursorData *setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY); + static QCursorData *setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY, + qreal devicePixelRatio); }; extern QCursorData *qt_cursorTable[Qt::LastCursor + 1]; // qcursor.cpp diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 710aa714b7..b309f67866 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1131,7 +1131,7 @@ void QGuiApplicationPrivate::createPlatformIntegration() QHighDpiScaling::initHighDpiScaling(); // Load the platform integration - QString platformPluginPath = QLatin1String(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH")); + QString platformPluginPath = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH")); QByteArray platformName; @@ -1161,7 +1161,7 @@ void QGuiApplicationPrivate::createPlatformIntegration() arg.remove(0, 1); if (arg == "-platformpluginpath") { if (++i < argc) - platformPluginPath = QLatin1String(argv[i]); + platformPluginPath = QString::fromLocal8Bit(argv[i]); } else if (arg == "-platform") { if (++i < argc) platformName = argv[i]; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 89bd119564..d4edc0fca1 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1271,8 +1271,11 @@ void QWindow::setMinimumSize(const QSize &size) */ void QWindow::setX(int arg) { + Q_D(QWindow); if (x() != arg) setGeometry(QRect(arg, y(), width(), height())); + else + d->positionAutomatic = false; } /*! @@ -1281,8 +1284,11 @@ void QWindow::setX(int arg) */ void QWindow::setY(int arg) { + Q_D(QWindow); if (y() != arg) setGeometry(QRect(x(), arg, width(), height())); + else + d->positionAutomatic = false; } /*! diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index faa1ff8068..09e6e2deb8 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -232,6 +232,7 @@ bool QWindowSystemInterface::tryHandleShortcutOverrideEvent(QWindow *w, QKeyEven { #ifndef QT_NO_SHORTCUT Q_ASSERT(ev->type() == QKeyEvent::ShortcutOverride); + QGuiApplicationPrivate::modifier_buttons = ev->modifiers(); QObject *focus = w->focusObject(); if (!focus) diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp index eb7c7f4b7a..9d363dc895 100644 --- a/src/gui/math3d/qmatrix4x4.cpp +++ b/src/gui/math3d/qmatrix4x4.cpp @@ -148,8 +148,6 @@ QMatrix4x4::QMatrix4x4(const float *values) top-most 4 rows of \a matrix. If \a matrix has less than 4 columns or rows, the remaining elements are filled with elements from the identity matrix. - - \sa QMatrix4x4(const QGenericMatrix &) */ /*! diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp index 0e162713ce..e0ef7c52a5 100644 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -43,6 +43,7 @@ #include <qwindow.h> #include <qlibrary.h> #include <qimage.h> +#include <QtCore/qbytearray.h> QT_BEGIN_NAMESPACE @@ -1275,9 +1276,19 @@ static inline QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool includ #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN // Without GL_UNSIGNED_INT_8_8_8_8_REV, GL_BGRA only makes sense on little endian. - const bool supports_bgra = context->isOpenGLES() - ? context->hasExtension(QByteArrayLiteral("GL_EXT_read_format_bgra")) - : context->hasExtension(QByteArrayLiteral("GL_EXT_bgra")); + const bool has_bgra_ext = context->isOpenGLES() + ? context->hasExtension(QByteArrayLiteral("GL_EXT_read_format_bgra")) + : context->hasExtension(QByteArrayLiteral("GL_EXT_bgra")); + + const char *renderer = reinterpret_cast<const char *>(funcs->glGetString(GL_RENDERER)); + const char *ver = reinterpret_cast<const char *>(funcs->glGetString(GL_VERSION)); + + // Blacklist PowerVR Rogue G6200 as it has problems with its BGRA support. + const bool blackListed = (qstrcmp(renderer, "PowerVR Rogue G6200") == 0 + && ::strstr(ver, "1.3") != 0); + + const bool supports_bgra = has_bgra_ext && !blackListed; + if (supports_bgra) { QImage img(size, include_alpha ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32); funcs->glReadPixels(0, 0, w, h, GL_BGRA, GL_UNSIGNED_BYTE, img.bits()); diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp index 61d57ca3f8..8c3fd2ce4f 100644 --- a/src/gui/painting/qcosmeticstroker.cpp +++ b/src/gui/painting/qcosmeticstroker.cpp @@ -720,10 +720,11 @@ static inline void capAdjust(int caps, int &x1, int &x2, int &y, int yinc) template<DrawPixel drawPixel, class Dasher> static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps) { + bool didDraw = qAbs(rx2 - rx1) + qAbs(ry2 - ry1) >= 1.0; + if (stroker->clipLine(rx1, ry1, rx2, ry2)) return true; - bool didDraw = false; const int half = stroker->legacyRounding ? 31 : 0; int x1 = toF26Dot6(rx1) + half; int y1 = toF26Dot6(ry1) + half; diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp index ca411ebe08..a8c1d8297c 100644 --- a/src/gui/painting/qpdfwriter.cpp +++ b/src/gui/painting/qpdfwriter.cpp @@ -151,7 +151,8 @@ QPdfWriter::QPdfWriter(const QString &filename) Constructs a PDF writer that will write the pdf to \a device. */ QPdfWriter::QPdfWriter(QIODevice *device) - : QObject(*new QPdfWriterPrivate) + : QObject(*new QPdfWriterPrivate), + QPagedPaintDevice(new QPdfPagedPaintDevicePrivate(d_func())) { Q_D(QPdfWriter); diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index c2d986ef3d..e6f1918da8 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -888,8 +888,13 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply) // if HTTP mandates we should close // or the reply is not finished yet, e.g. it was aborted // we have to close that connection - if (reply->d_func()->isConnectionCloseEnabled() || !reply->isFinished()) - channels[i].close(); + if (reply->d_func()->isConnectionCloseEnabled() || !reply->isFinished()) { + if (reply->isAborted()) { + channels[i].abort(); + } else { + channels[i].close(); + } + } QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); return; diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 8980ed7a41..293909c914 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -205,6 +205,26 @@ void QHttpNetworkConnectionChannel::close() } +void QHttpNetworkConnectionChannel::abort() +{ + if (!socket) + state = QHttpNetworkConnectionChannel::IdleState; + else if (socket->state() == QAbstractSocket::UnconnectedState) + state = QHttpNetworkConnectionChannel::IdleState; + else + state = QHttpNetworkConnectionChannel::ClosingState; + + // pendingEncrypt must only be true in between connected and encrypted states + pendingEncrypt = false; + + if (socket) { + // socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while + // there is no socket yet. + socket->abort(); + } +} + + bool QHttpNetworkConnectionChannel::sendRequest() { Q_ASSERT(!protocolHandler.isNull()); @@ -1080,6 +1100,8 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors) connection->d_func()->pauseConnection(); if (pendingEncrypt && !reply) connection->d_func()->dequeueRequest(socket); + if (reply) // a reply was actually dequeued. + reply->d_func()->connectionChannel = this; // set correct channel like in sendRequest() and queueRequest(); if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) { if (reply) emit reply->sslErrors(errors); diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 37ad6c9b0a..87329b7397 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -157,6 +157,7 @@ public: void init(); void close(); + void abort(); bool sendRequest(); diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index dd108ad5c7..a0f05523e3 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -264,6 +264,17 @@ char* QHttpNetworkReply::userProvidedDownloadBuffer() return d->userProvidedDownloadBuffer; } +void QHttpNetworkReply::abort() +{ + Q_D(QHttpNetworkReply); + d->state = QHttpNetworkReplyPrivate::Aborted; +} + +bool QHttpNetworkReply::isAborted() const +{ + return d_func()->state == QHttpNetworkReplyPrivate::Aborted; +} + bool QHttpNetworkReply::isFinished() const { return d_func()->state == QHttpNetworkReplyPrivate::AllDoneState; diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 6e81663500..e8ed73fdac 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -121,6 +121,9 @@ public: void setUserProvidedDownloadBuffer(char*); char* userProvidedDownloadBuffer(); + void abort(); + + bool isAborted() const; bool isFinished() const; bool isPipeliningUsed() const; @@ -214,7 +217,8 @@ public: SPDYSYNSent, SPDYUploading, SPDYHalfClosed, - SPDYClosed + SPDYClosed, + Aborted } state; QHttpNetworkRequest request; diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 3fc4fa9dee..c07064fd94 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -396,6 +396,7 @@ void QHttpThreadDelegate::abortRequest() qDebug() << "QHttpThreadDelegate::abortRequest() thread=" << QThread::currentThreadId() << "sync=" << synchronous; #endif if (httpReply) { + httpReply->abort(); delete httpReply; httpReply = 0; } diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index e6fb1a09a0..7147823309 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -278,7 +278,8 @@ static void ensureInitialized() \snippet code/src_network_access_qnetworkaccessmanager.cpp 4 - Network requests can be reenabled again by calling + Network requests can be re-enabled again, and this property will resume to + reflect the actual device state by calling \snippet code/src_network_access_qnetworkaccessmanager.cpp 5 @@ -467,16 +468,12 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent) #ifndef QT_NO_BEARERMANAGEMENT Q_D(QNetworkAccessManager); - if (!d->networkSessionRequired) { - // if a session is required, we track online state through - // the QNetworkSession's signals - connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)), - SLOT(_q_onlineStateChanged(bool))); - } - // we would need all active configurations to check for - // d->networkConfigurationManager.isOnline(), which is asynchronous - // and potentially expensive. We can just check the configuration here - d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active); + // if a session is required, we track online state through + // the QNetworkSession's signals if a request is already made. + // we need to track current accessibility state by default + // + connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)), + SLOT(_q_onlineStateChanged(bool))); #endif } @@ -946,7 +943,8 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible) { Q_D(QNetworkAccessManager); - d->defaultAccessControl = false; + + d->defaultAccessControl = accessible == NotAccessible ? false : true; if (d->networkAccessible != accessible) { NetworkAccessibility previous = networkAccessible(); @@ -965,6 +963,10 @@ void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkA QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const { Q_D(const QNetworkAccessManager); + + if (d->networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined)) + return UnknownAccessibility; + if (d->networkSessionRequired) { QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession()); if (networkSession) { @@ -1622,32 +1624,56 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession if (online) { if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) { online = false; - networkAccessible = QNetworkAccessManager::NotAccessible; - emit q->networkAccessibleChanged(networkAccessible); + if (networkAccessible != QNetworkAccessManager::NotAccessible) { + networkAccessible = QNetworkAccessManager::NotAccessible; + emit q->networkAccessibleChanged(networkAccessible); + } } } else { if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) { online = true; if (defaultAccessControl) - networkAccessible = QNetworkAccessManager::Accessible; - emit q->networkAccessibleChanged(networkAccessible); + if (networkAccessible != QNetworkAccessManager::Accessible) { + networkAccessible = QNetworkAccessManager::Accessible; + emit q->networkAccessibleChanged(networkAccessible); + } } } } void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline) { - // if the user set a config, we only care whether this one is active. + Q_Q(QNetworkAccessManager); + // if the user set a config, we only care whether this one is active. // Otherwise, this QNAM is online if there is an online config. if (customNetworkConfiguration) { online = (networkConfiguration.state() & QNetworkConfiguration::Active); } else { - if (isOnline && online != isOnline) { - networkSessionStrongRef.clear(); - networkSessionWeakRef.clear(); + if (online != isOnline) { + if (isOnline) { + networkSessionStrongRef.clear(); + networkSessionWeakRef.clear(); + } + online = isOnline; + } + } + if (online) { + if (defaultAccessControl) { + if (networkAccessible != QNetworkAccessManager::Accessible) { + networkAccessible = QNetworkAccessManager::Accessible; + emit q->networkAccessibleChanged(networkAccessible); + } + } + } else if (networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined)) { + if (networkAccessible != QNetworkAccessManager::UnknownAccessibility) { + networkAccessible = QNetworkAccessManager::UnknownAccessibility; + emit q->networkAccessibleChanged(networkAccessible); + } + } else { + if (networkAccessible != QNetworkAccessManager::NotAccessible) { + networkAccessible = QNetworkAccessManager::NotAccessible; + emit q->networkAccessibleChanged(networkAccessible); } - - online = isOnline; } } diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index c715da00c1..54ae114581 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -78,7 +78,6 @@ public: customNetworkConfiguration(false), networkSessionRequired(networkConfigurationManager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired), - networkAccessible(QNetworkAccessManager::Accessible), activeReplyCount(0), online(false), initializeSession(true), @@ -86,7 +85,18 @@ public: cookieJarCreated(false), defaultAccessControl(true), authenticationManager(QSharedPointer<QNetworkAccessAuthenticationManager>::create()) - { } + { +#ifndef QT_NO_BEARERMANAGEMENT + // we would need all active configurations to check for + // d->networkConfigurationManager.isOnline(), which is asynchronous + // and potentially expensive. We can just check the configuration here + online = (networkConfiguration.state().testFlag(QNetworkConfiguration::Active)); + if (online) + networkAccessible = QNetworkAccessManager::Accessible; + else + networkAccessible = QNetworkAccessManager::NotAccessible; +#endif + } ~QNetworkAccessManagerPrivate(); void _q_replyFinished(); diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 8c0c098147..63fca2bda2 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1238,7 +1238,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData if (statusCode == 304) { #if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) - qDebug() << "Received a 304 from" << url(); + qDebug() << "Received a 304 from" << request.url(); #endif QAbstractNetworkCache *nc = managerPrivate->networkCache; if (nc) { @@ -1562,7 +1562,7 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe } #if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) - QByteArray n = rawHeader(header); + QByteArray n = q->rawHeader(header); QByteArray o; if (it != cacheHeaders.rawHeaders.constEnd()) o = (*it).second; @@ -1782,6 +1782,11 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation() QMetaObject::invokeMethod(q, "_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection); return; #endif + } else { +#ifndef QT_NO_BEARERMANAGEMENT + QObject::connect(session.data(), SIGNAL(stateChanged(QNetworkSession::State)), + q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), Qt::QueuedConnection); +#endif } if (synchronous) { @@ -1950,6 +1955,16 @@ void QNetworkReplyHttpImplPrivate::_q_networkSessionConnected() } } +void QNetworkReplyHttpImplPrivate::_q_networkSessionStateChanged(QNetworkSession::State sessionState) +{ + if (sessionState == QNetworkSession::Disconnected + && (state != Idle || state != Reconnecting)) { + error(QNetworkReplyImpl::NetworkSessionFailedError, + QCoreApplication::translate("QNetworkReply", "Network session error.")); + finished(); + } +} + void QNetworkReplyHttpImplPrivate::_q_networkSessionFailed() { // Abort waiting and working replies. diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index fff88f8f2d..44d51d82a4 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -96,6 +96,7 @@ public: #ifndef QT_NO_BEARERMANAGEMENT Q_PRIVATE_SLOT(d_func(), void _q_networkSessionConnected()) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionFailed()) + Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State)) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionUsagePoliciesChanged(QNetworkSession::UsagePolicies)) #endif Q_PRIVATE_SLOT(d_func(), void _q_finished()) @@ -171,6 +172,7 @@ public: #ifndef QT_NO_BEARERMANAGEMENT void _q_networkSessionConnected(); void _q_networkSessionFailed(); + void _q_networkSessionStateChanged(QNetworkSession::State); void _q_networkSessionUsagePoliciesChanged(QNetworkSession::UsagePolicies); #endif void _q_finished(); diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index a73e0ea75e..c73e6162d1 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -125,6 +125,11 @@ void QNetworkReplyImplPrivate::_q_startOperation() finished(); #endif return; + } else { +#ifndef QT_NO_BEARERMANAGEMENT + QObject::connect(session.data(), SIGNAL(stateChanged(QNetworkSession::State)), + q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), Qt::QueuedConnection); +#endif } #ifndef QT_NO_BEARERMANAGEMENT @@ -309,6 +314,16 @@ void QNetworkReplyImplPrivate::_q_networkSessionConnected() } } +void QNetworkReplyImplPrivate::_q_networkSessionStateChanged(QNetworkSession::State sessionState) +{ + if (sessionState == QNetworkSession::Disconnected + && (state != Idle || state != Reconnecting)) { + error(QNetworkReplyImpl::NetworkSessionFailedError, + QCoreApplication::translate("QNetworkReply", "Network session error.")); + finished(); + } +} + void QNetworkReplyImplPrivate::_q_networkSessionFailed() { // Abort waiting and working replies. diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index 3e720ef597..209bf40b72 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -89,6 +89,7 @@ public: #ifndef QT_NO_BEARERMANAGEMENT Q_PRIVATE_SLOT(d_func(), void _q_networkSessionConnected()) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionFailed()) + Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State)) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionUsagePoliciesChanged(QNetworkSession::UsagePolicies)) #endif @@ -122,6 +123,7 @@ public: #ifndef QT_NO_BEARERMANAGEMENT void _q_networkSessionConnected(); void _q_networkSessionFailed(); + void _q_networkSessionStateChanged(QNetworkSession::State); void _q_networkSessionUsagePoliciesChanged(QNetworkSession::UsagePolicies); #endif diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index abb47e9e29..d626d0bcfc 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -85,6 +85,7 @@ static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& \li Digest-MD5 \endlist + \target qauthenticator-options \section1 Options In addition to the username and password required for authentication, a @@ -104,8 +105,8 @@ static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& \section2 Basic \table - \header \li Option \li Direction \li Description - \row \li \tt{realm} \li Incoming \li Contains the realm of the authentication, the same as realm() + \header \li Option \li Direction \li Type \li Description + \row \li \tt{realm} \li Incoming \li QString \li Contains the realm of the authentication, the same as realm() \endtable The Basic authentication mechanism supports no outgoing options. @@ -119,8 +120,8 @@ static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& \section2 Digest-MD5 \table - \header \li Option \li Direction \li Description - \row \li \tt{realm} \li Incoming \li Contains the realm of the authentication, the same as realm() + \header \li Option \li Direction \li Type \li Description + \row \li \tt{realm} \li Incoming \li QString \li Contains the realm of the authentication, the same as realm() \endtable The Digest-MD5 authentication mechanism supports no outgoing options. @@ -130,7 +131,7 @@ static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& /*! - Constructs an empty authentication object + Constructs an empty authentication object. */ QAuthenticator::QAuthenticator() : d(0) @@ -138,7 +139,7 @@ QAuthenticator::QAuthenticator() } /*! - Destructs the object + Destructs the object. */ QAuthenticator::~QAuthenticator() { @@ -207,7 +208,7 @@ bool QAuthenticator::operator==(const QAuthenticator &other) const */ /*! - returns the user used for authentication. + Returns the user used for authentication. */ QString QAuthenticator::user() const { @@ -227,7 +228,7 @@ void QAuthenticator::setUser(const QString &user) } /*! - returns the password used for authentication. + Returns the password used for authentication. */ QString QAuthenticator::password() const { @@ -260,7 +261,7 @@ void QAuthenticator::detach() } /*! - returns the realm requiring authentication. + Returns the realm requiring authentication. */ QString QAuthenticator::realm() const { @@ -279,10 +280,11 @@ void QAuthenticator::setRealm(const QString &realm) /*! \since 4.7 Returns the value related to option \a opt if it was set by the server. - See \l{QAuthenticator#Options} for more information on incoming options. + See the \l{QAuthenticator#qauthenticator-options}{Options section} for + more information on incoming options. If option \a opt isn't found, an invalid QVariant will be returned. - \sa options(), QAuthenticator#Options + \sa options(), {QAuthenticator#qauthenticator-options}{QAuthenticator options} */ QVariant QAuthenticator::option(const QString &opt) const { @@ -292,10 +294,10 @@ QVariant QAuthenticator::option(const QString &opt) const /*! \since 4.7 Returns all incoming options set in this QAuthenticator object by parsing - the server reply. See \l{QAuthenticator#Options} for more information - on incoming options. + the server reply. See the \l{QAuthenticator#qauthenticator-options}{Options section} + for more information on incoming options. - \sa option(), QAuthenticator#Options + \sa option(), {QAuthenticator#qauthenticator-options}{QAuthenticator options} */ QVariantHash QAuthenticator::options() const { @@ -306,9 +308,9 @@ QVariantHash QAuthenticator::options() const \since 4.7 Sets the outgoing option \a opt to value \a value. - See \l{QAuthenticator#Options} for more information on outgoing options. + See the \l{QAuthenticator#qauthenticator-options}{Options section} for more information on outgoing options. - \sa options(), option(), QAuthenticator#Options + \sa options(), option(), {QAuthenticator#qauthenticator-options}{QAuthenticator options} */ void QAuthenticator::setOption(const QString &opt, const QVariant &value) { @@ -318,7 +320,10 @@ void QAuthenticator::setOption(const QString &opt, const QVariant &value) /*! - Returns \c true if the authenticator is null. + Returns \c true if the object has not been initialized. Returns + \c false if non-const member functions have been called, or + the content was constructed or copied from another initialized + QAuthenticator object. */ bool QAuthenticator::isNull() const { diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 02147d2054..e344a9d17e 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -745,15 +745,9 @@ bool QAbstractSocketPrivate::canReadNotification() return true; } - if (socketEngine) { - // turn the socket engine off if we've either: - // - got pending datagrams - // - reached the buffer size limit - if (isBuffered) - socketEngine->setReadNotificationEnabled(readBufferMaxSize == 0 || readBufferMaxSize > q->bytesAvailable()); - else if (socketType != QAbstractSocket::TcpSocket) - socketEngine->setReadNotificationEnabled(!socketEngine->hasPendingDatagrams()); - } + // turn the socket engine off if we've reached the buffer size limit + if (socketEngine && isBuffered) + socketEngine->setReadNotificationEnabled(readBufferMaxSize == 0 || readBufferMaxSize > q->bytesAvailable()); // reset the read socket notifier state if we reentered inside the // readyRead() connected slot. diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index ef10b1e68d..634074d91f 100644 --- a/src/network/socket/qlocalserver_unix.cpp +++ b/src/network/socket/qlocalserver_unix.cpp @@ -85,7 +85,8 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) } serverName = requestedServerName; - QString tempPath; + QByteArray encodedTempPath; + const QByteArray encodedFullServerName = QFile::encodeName(fullServerName); QScopedPointer<QTemporaryDir> tempDir; // Check any of the flags @@ -96,8 +97,7 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) setError(QLatin1String("QLocalServer::listen")); return false; } - tempPath = tempDir->path(); - tempPath += QLatin1String("/s"); + encodedTempPath = QFile::encodeName(tempDir->path() + QLatin1String("/s")); } // create the unix socket @@ -111,23 +111,23 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) // Construct the unix address struct ::sockaddr_un addr; addr.sun_family = PF_UNIX; - if (sizeof(addr.sun_path) < (uint)fullServerName.toLatin1().size() + 1) { + if (sizeof(addr.sun_path) < (uint)encodedFullServerName.size() + 1) { setError(QLatin1String("QLocalServer::listen")); closeServer(); return false; } if (socketOptions & QLocalServer::WorldAccessOption) { - if (sizeof(addr.sun_path) < (uint)tempPath.toLatin1().size() + 1) { + if (sizeof(addr.sun_path) < (uint)encodedTempPath.size() + 1) { setError(QLatin1String("QLocalServer::listen")); closeServer(); return false; } - ::memcpy(addr.sun_path, tempPath.toLatin1().data(), - tempPath.toLatin1().size() + 1); + ::memcpy(addr.sun_path, encodedTempPath.constData(), + encodedTempPath.size() + 1); } else { - ::memcpy(addr.sun_path, fullServerName.toLatin1().data(), - fullServerName.toLatin1().size() + 1); + ::memcpy(addr.sun_path, encodedFullServerName.constData(), + encodedFullServerName.size() + 1); } // bind @@ -165,13 +165,13 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) if (socketOptions & QLocalServer::OtherAccessOption) mode |= S_IRWXO; - if (::chmod(tempPath.toLatin1(), mode) == -1) { + if (::chmod(encodedTempPath.constData(), mode) == -1) { setError(QLatin1String("QLocalServer::listen")); closeServer(); return false; } - if (::rename(tempPath.toLatin1(), fullServerName.toLatin1()) == -1) { + if (::rename(encodedTempPath.constData(), encodedFullServerName.constData()) == -1) { setError(QLatin1String("QLocalServer::listen")); closeServer(); return false; diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp index 77c5028fb3..bb0f11f038 100644 --- a/src/network/socket/qlocalsocket_unix.cpp +++ b/src/network/socket/qlocalsocket_unix.cpp @@ -268,15 +268,16 @@ void QLocalSocketPrivate::_q_connectToSocket() connectingPathName += QLatin1Char('/') + connectingName; } + const QByteArray encodedConnectingPathName = QFile::encodeName(connectingPathName); struct sockaddr_un name; name.sun_family = PF_UNIX; - if (sizeof(name.sun_path) < (uint)connectingPathName.toLatin1().size() + 1) { + if (sizeof(name.sun_path) < (uint)encodedConnectingPathName.size() + 1) { QString function = QLatin1String("QLocalSocket::connectToServer"); errorOccurred(QLocalSocket::ServerNotFoundError, function); return; } - ::memcpy(name.sun_path, connectingPathName.toLatin1().data(), - connectingPathName.toLatin1().size() + 1); + ::memcpy(name.sun_path, encodedConnectingPathName.constData(), + encodedConnectingPathName.size() + 1); if (-1 == qt_safe_connect(connectingSocket, (struct sockaddr *)&name, sizeof(name))) { QString function = QLatin1String("QLocalSocket::connectToServer"); switch (errno) diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 0e14c175c5..c40eef769e 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -370,7 +370,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt int n, level; convertToLevelAndOption(opt, socketProtocol, level, n); -#if defined(SO_REUSEPORT) +#if defined(SO_REUSEPORT) && !defined(Q_OS_LINUX) if (opt == QNativeSocketEngine::AddressReusable) { // on OS X, SO_REUSEADDR isn't sufficient to allow multiple binds to the // same port (which is useful for multicast UDP). SO_REUSEPORT is, but diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 2e905ad610..9aed0caa25 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -1070,8 +1070,11 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const buf.buf = &c; buf.len = sizeof(c); DWORD flags = MSG_PEEK; - if (::WSARecvFrom(socketDescriptor, &buf, 1, 0, &flags, 0,0,0,0) == SOCKET_ERROR) - return 0; + if (::WSARecvFrom(socketDescriptor, &buf, 1, 0, &flags, 0,0,0,0) == SOCKET_ERROR) { + int err = WSAGetLastError(); + if (err != WSAECONNRESET && err != WSAENETRESET) + return 0; + } } return nbytes; } @@ -1099,14 +1102,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const int err = WSAGetLastError(); if (ret == SOCKET_ERROR && err != WSAEMSGSIZE) { WS_ERROR_DEBUG(err); - if (err == WSAECONNRESET || err == WSAENETRESET) { - // Discard error message to prevent QAbstractSocket from - // getting this message repeatedly after reenabling the - // notifiers. - flags = 0; - ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, - &storage.a, &storageSize, 0, 0); - } + result = (err == WSAECONNRESET || err == WSAENETRESET); } else { // If there's no error, or if our buffer was too small, there must be // a pending datagram. @@ -1159,12 +1155,21 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const if (recvResult != SOCKET_ERROR) { ret = qint64(bytesRead); break; - } else if (recvResult == SOCKET_ERROR && err == WSAEMSGSIZE) { - bufferCount += 5; - delete[] buf; - } else if (recvResult == SOCKET_ERROR) { - WS_ERROR_DEBUG(err); - ret = -1; + } else { + switch (err) { + case WSAEMSGSIZE: + bufferCount += 5; + delete[] buf; + continue; + case WSAECONNRESET: + case WSAENETRESET: + ret = 0; + break; + default: + WS_ERROR_DEBUG(err); + ret = -1; + break; + } break; } } diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp index 025e3e5017..44de7f8526 100644 --- a/src/network/socket/qnativesocketengine_winrt.cpp +++ b/src/network/socket/qnativesocketengine_winrt.cpp @@ -285,23 +285,11 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port) return false; } d->socketState = QAbstractSocket::ConnectingState; - hr = QWinRTFunctions::await(d->connectOp); - RETURN_FALSE_IF_FAILED("Connection could not be established"); - bool connectionErrors = false; - d->handleConnectionErrors(d->connectOp.Get(), &connectionErrors); - if (connectionErrors) - return false; - d->connectOp.Reset(); - - d->socketState = QAbstractSocket::ConnectedState; - emit connectionReady(); + hr = d->connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>( + d, &QNativeSocketEnginePrivate::handleConnectToHost).Get()); + Q_ASSERT_SUCCEEDED(hr); - // Delay the reader so that the SSL socket can upgrade - if (d->sslSocket) - connect(d->sslSocket, SIGNAL(encrypted()), SLOT(establishRead())); - else - establishRead(); - return true; + return d->socketState == QAbstractSocket::ConnectedState; } bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port) @@ -330,8 +318,7 @@ bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port) return false; } - EventRegistrationToken token; - d->tcpListener->add_ConnectionReceived(Callback<ClientConnectedHandler>(d, &QNativeSocketEnginePrivate::handleClientConnection).Get(), &token); + d->tcpListener->add_ConnectionReceived(Callback<ClientConnectedHandler>(d, &QNativeSocketEnginePrivate::handleClientConnection).Get(), &d->connectionToken); hr = d->tcpListener->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op); if (FAILED(hr)) { qErrnoWarning(hr, "Unable to bind socket."); // ### Set error message @@ -688,6 +675,14 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut) { Q_UNUSED(msecs); Q_UNUSED(timedOut); + Q_D(QNativeSocketEngine); + if (d->socketState == QAbstractSocket::ConnectingState) { + HRESULT hr = QWinRTFunctions::await(d->connectOp, QWinRTFunctions::ProcessMainThreadEvents); + if (SUCCEEDED(hr)) { + d->handleConnectionEstablished(d->connectOp.Get()); + return true; + } + } return false; } @@ -728,7 +723,6 @@ void QNativeSocketEngine::setWriteNotificationEnabled(bool enable) if (bytesToWrite()) return; // will be emitted as a result of bytes written writeNotification(); - d->notifyOnWrite = false; } } @@ -785,9 +779,8 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc qWarning("Failed to create stream socket"); return false; } - EventRegistrationToken token; socketDescriptor = qintptr(socket.Detach()); - udpSocket()->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &token); + udpSocket()->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &connectionToken); break; } default: @@ -815,11 +808,19 @@ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() , closingDown(false) , socketDescriptor(-1) , sslSocket(Q_NULLPTR) + , connectionToken( { -1 } ) { } QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate() { + if (socketDescriptor == -1 || connectionToken.value == -1) + return; + + if (socketType == QAbstractSocket::UdpSocket) + udpSocket()->remove_MessageReceived(connectionToken); + else if (socketType == QAbstractSocket::TcpSocket) + tcpListener->remove_ConnectionReceived(connectionToken); } void QNativeSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const @@ -1119,10 +1120,19 @@ HRESULT QNativeSocketEnginePrivate::handleClientConnection(IStreamSocketListener return S_OK; } -void QNativeSocketEnginePrivate::handleConnectionErrors(IAsyncAction *connectAction, bool *errorsOccured) +HRESULT QNativeSocketEnginePrivate::handleConnectToHost(IAsyncAction *action, AsyncStatus) +{ + handleConnectionEstablished(action); + return S_OK; +} + +void QNativeSocketEnginePrivate::handleConnectionEstablished(IAsyncAction *action) { - bool error = true; - HRESULT hr = connectAction->GetResults(); + Q_Q(QNativeSocketEngine); + if (wasDeleted || !connectOp) // Protect against a late callback + return; + + HRESULT hr = action->GetResults(); switch (hr) { case 0x8007274c: // A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); @@ -1140,13 +1150,32 @@ void QNativeSocketEnginePrivate::handleConnectionErrors(IAsyncAction *connectAct if (FAILED(hr)) { setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString); socketState = QAbstractSocket::UnconnectedState; - } else { - error = false; } break; } - if (errorsOccured) - *errorsOccured = error; + + // The callback might be triggered several times if we do not cancel/reset it here + if (connectOp) { + ComPtr<IAsyncInfo> info; + connectOp.As(&info); + if (info) { + info->Cancel(); + info->Close(); + } + connectOp.Reset(); + } + + socketState = QAbstractSocket::ConnectedState; + emit q->connectionReady(); + + if (socketType != QAbstractSocket::TcpSocket) + return; + + // Delay the reader so that the SSL socket can upgrade + if (sslSocket) + QObject::connect(qobject_cast<QSslSocket *>(sslSocket), &QSslSocket::encrypted, q, &QNativeSocketEngine::establishRead); + else + q->establishRead(); } HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *asyncInfo, AsyncStatus status) @@ -1166,7 +1195,7 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async hr = buffer->get_Length(&bufferLength); Q_ASSERT_SUCCEEDED(hr); if (!bufferLength) { - if (q->isReadNotificationEnabled()) + if (notifyOnRead) emit q->readReady(); return S_OK; } @@ -1190,7 +1219,7 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async readBytes.seek(readPos); readMutex.unlock(); - if (q->isReadNotificationEnabled()) + if (notifyOnRead) emit q->readReady(); ComPtr<IInputStream> stream; diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h index 4286ff6373..912b7db973 100644 --- a/src/network/socket/qnativesocketengine_winrt_p.h +++ b/src/network/socket/qnativesocketengine_winrt_p.h @@ -207,13 +207,15 @@ private: QList<ABI::Windows::Networking::Sockets::IStreamSocket *> currentConnections; QEventLoop eventLoop; QAbstractSocket *sslSocket; + EventRegistrationToken connectionToken; HRESULT handleBindCompleted(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus); HRESULT handleNewDatagram(ABI::Windows::Networking::Sockets::IDatagramSocket *socket, ABI::Windows::Networking::Sockets::IDatagramSocketMessageReceivedEventArgs *args); HRESULT handleClientConnection(ABI::Windows::Networking::Sockets::IStreamSocketListener *tcpListener, ABI::Windows::Networking::Sockets::IStreamSocketListenerConnectionReceivedEventArgs *args); - void handleConnectionErrors(ABI::Windows::Foundation::IAsyncAction *connectAction, bool *errorsOccured); + HRESULT handleConnectToHost(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus); + void handleConnectionEstablished(ABI::Windows::Foundation::IAsyncAction *action); HRESULT handleReadyRead(ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer *, UINT32> *asyncInfo, ABI::Windows::Foundation::AsyncStatus); }; diff --git a/src/network/ssl/qsslellipticcurve.cpp b/src/network/ssl/qsslellipticcurve.cpp index a16f726429..b4396d567b 100644 --- a/src/network/ssl/qsslellipticcurve.cpp +++ b/src/network/ssl/qsslellipticcurve.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE elliptic-curve cipher algorithms. Elliptic curves can be constructed from a "short name" (SN) (fromShortName()), - and by a call to QSslSocket::supportedEllipticCurves(). + and by a call to QSslConfiguration::supportedEllipticCurves(). QSslEllipticCurve instances can be compared for equality and can be used as keys in QHash and QSet. They cannot be used as key in a QMap. @@ -65,7 +65,7 @@ QT_BEGIN_NAMESPACE Constructs an invalid elliptic curve. - \sa isValid(), QSslSocket::supportedEllipticCurves() + \sa isValid(), QSslConfiguration::supportedEllipticCurves() */ /*! @@ -136,7 +136,6 @@ QT_BEGIN_NAMESPACE \relates QSslEllipticCurve Returns true if the curve \a lhs represents the same curve of \a rhs; - false otherwise. */ /*! diff --git a/src/network/ssl/qsslpresharedkeyauthenticator.cpp b/src/network/ssl/qsslpresharedkeyauthenticator.cpp index 4a3b1aa807..ab78aea1cd 100644 --- a/src/network/ssl/qsslpresharedkeyauthenticator.cpp +++ b/src/network/ssl/qsslpresharedkeyauthenticator.cpp @@ -257,7 +257,6 @@ int QSslPreSharedKeyAuthenticator::maximumPreSharedKeyLength() const identity hint, identity, pre shared key, maximum length for the identity and maximum length for the pre shared key. - \sa operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs) */ bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs) { @@ -277,7 +276,6 @@ bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKey Returns true if the authenticator object \a lhs is different than \a rhs; false otherwise. - \sa operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs) */ QT_END_NAMESPACE diff --git a/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp b/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp index a64e107e71..1dd2b462ed 100644 --- a/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp +++ b/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp @@ -59,6 +59,11 @@ QDBusPlatformMenuItem::QDBusPlatformMenuItem(quintptr tag) menuItemsByID.insert(m_dbusID, this); } +QDBusPlatformMenuItem::~QDBusPlatformMenuItem() +{ + menuItemsByID.remove(m_dbusID); +} + void QDBusPlatformMenuItem::setTag(quintptr tag) { m_tag = tag; @@ -155,6 +160,7 @@ QDBusPlatformMenu::QDBusPlatformMenu(quintptr tag) QDBusPlatformMenu::~QDBusPlatformMenu() { menusByID.remove(m_dbusID); + m_topLevelMenus.removeOne(this); } void QDBusPlatformMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) diff --git a/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h b/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h index 16bb4f195c..fdad7990e9 100644 --- a/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h +++ b/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h @@ -57,6 +57,7 @@ class QDBusPlatformMenuItem : public QPlatformMenuItem public: QDBusPlatformMenuItem(quintptr tag = 0LL); + ~QDBusPlatformMenuItem(); quintptr tag()const Q_DECL_OVERRIDE { return m_tag; } void setTag(quintptr tag) Q_DECL_OVERRIDE; diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 905f7695bb..2de7fb3b40 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -39,6 +39,10 @@ #include <QtPlatformHeaders/QEGLNativeContext> #include <QDebug> +#ifdef Q_OS_ANDROID +#include <QtCore/private/qjnihelpers_p.h> +#endif + QT_BEGIN_NAMESPACE /*! @@ -305,6 +309,14 @@ void QEGLPlatformContext::updateFormatFromGL() QByteArray version = QByteArray(reinterpret_cast<const char *>(s)); int major, minor; if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) { +#ifdef Q_OS_ANDROID + // Some Android 4.2.2 devices report OpenGL ES 3.0 without the functions being available. + static int apiLevel = QtAndroidPrivate::androidSdkVersion(); + if (apiLevel <= 17 && major >= 3) { + major = 2; + minor = 0; + } +#endif m_format.setMajorVersion(major); m_format.setMinorVersion(minor); } diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp index cd38498217..a369747a64 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp @@ -243,8 +243,13 @@ void QKdeThemePrivate::refresh() toolButtonStyle = Qt::ToolButtonTextBesideIcon; toolBarIconSize = 0; styleNames.clear(); + if (kdeVersion >= 5) + styleNames << QStringLiteral("breeze"); styleNames << QStringLiteral("Oxygen") << QStringLiteral("fusion") << QStringLiteral("windows"); - iconFallbackThemeName = iconThemeName = QStringLiteral("oxygen"); + if (kdeVersion >= 5) + iconFallbackThemeName = iconThemeName = QStringLiteral("breeze"); + else + iconFallbackThemeName = iconThemeName = QStringLiteral("oxygen"); QHash<QString, QSettings*> kdeSettings; diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm index 2098f0dc8c..8e38181c29 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.mm +++ b/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -303,7 +303,7 @@ NSCursor *QCocoaCursor::createCursorFromPixmap(const QPixmap pixmap, const QPoin NSImage *nsimage; if (pixmap.devicePixelRatio() > 1.0) { QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio(); - QPixmap scaledPixmap = pixmap.scaled(layoutSize); + QPixmap scaledPixmap = pixmap.scaled(layoutSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(scaledPixmap)); CGImageRef cgImage = qt_mac_toCGImage(pixmap.toImage()); NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 6bec6b191d..229f515995 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -87,9 +87,17 @@ void QCocoaScreen::updateGeometry() NSRect frameRect = [nsScreen frame]; - if (m_screenIndex == 0) { + // Since Mavericks, there is a setting, System Preferences->Mission Control-> + // Displays have separate Spaces. + BOOL spansDisplays = NO; +#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9) + spansDisplays = [NSScreen screensHaveSeparateSpaces]; +#endif + if (spansDisplays || m_screenIndex == 0) { m_geometry = QRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height); - // This is the primary screen, the one that contains the menubar. Its origin should be + // Displays have separate Spaces setting is on or this is the primary screen, + // the one that contains the menubar. Its origin should be // (0, 0), and it's the only one whose available geometry differs from its full geometry. NSRect visibleRect = [nsScreen visibleFrame]; m_availableGeometry = QRect(visibleRect.origin.x, diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 57739f3a58..aa7a09805a 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -463,6 +463,13 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, NSView *view = cocoaWindow ? cocoaWindow->contentView() : nil; NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil; + QScreen *screen = 0; + if (parentWindow) + screen = parentWindow->screen(); + if (!screen && !QGuiApplication::screens().isEmpty()) + screen = QGuiApplication::screens().at(0); + Q_ASSERT(screen); + // Ideally, we would call -popUpMenuPositioningItem:atLocation:inView:. // However, this showed not to work with modal windows where the menu items // would appear disabled. So, we resort to a more artisanal solution. Note @@ -479,6 +486,21 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, [popupCell setTransparent:YES]; [popupCell setMenu:m_nativeMenu]; [popupCell selectItem:nsItem]; + + int availableHeight = screen->availableSize().height(); + const QPoint &globalPos = parentWindow->mapToGlobal(pos); + int menuHeight = m_nativeMenu.size.height; + if (globalPos.y() + menuHeight > availableHeight) { + // Maybe we need to fix the vertical popup position but we don't know the + // exact popup height at the moment (and Cocoa is just guessing) nor its + // position. So, instead of translating by the popup's full height, we need + // to estimate where the menu will show up and translate by the remaining height. + float idx = ([m_nativeMenu indexOfItem:nsItem] + 1.0f) / m_nativeMenu.numberOfItems; + float heightBelowPos = (1.0 - idx) * menuHeight; + if (globalPos.y() + heightBelowPos > availableHeight) + pos.setY(pos.y() - globalPos.y() + availableHeight - heightBelowPos); + } + NSRect cellFrame = NSMakeRect(pos.x(), pos.y(), m_nativeMenu.minimumWidth, 10); [popupCell performClickWithFrame:cellFrame inView:view]; } else { @@ -487,22 +509,21 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, if (view) { // convert coordinates from view to the view's window nsPos = [view convertPoint:nsPos toView:nil]; - } else if (!QGuiApplication::screens().isEmpty()) { - QScreen *screen = QGuiApplication::screens().at(0); + } else { nsPos.y = screen->availableVirtualSize().height() - nsPos.y; } if (view) { // Finally, we need to synthesize an event. NSEvent *menuEvent = [NSEvent mouseEventWithType:NSRightMouseDown - location:nsPos - modifierFlags:0 - timestamp:0 - windowNumber:view ? view.window.windowNumber : 0 - context:nil - eventNumber:0 - clickCount:1 - pressure:1.0]; + location:nsPos + modifierFlags:0 + timestamp:0 + windowNumber:view ? view.window.windowNumber : 0 + context:nil + eventNumber:0 + clickCount:1 + pressure:1.0]; [NSMenu popUpContextMenu:m_nativeMenu withEvent:menuEvent forView:view]; } else { [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:0]; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 8a8e03d283..6f1e355790 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -799,13 +799,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) return styleMask; if ((type & Qt::Popup) == Qt::Popup) { if (!windowIsPopupType(type)) { - styleMask = NSUtilityWindowMask; + styleMask = NSUtilityWindowMask | NSResizableWindowMask; if (!(flags & Qt::CustomizeWindowHint)) { - styleMask |= NSResizableWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSTitledWindowMask; + styleMask |= NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask; } else { - if (flags & Qt::WindowMaximizeButtonHint) - styleMask |= NSResizableWindowMask; if (flags & Qt::WindowTitleHint) styleMask |= NSTitledWindowMask; if (flags & Qt::WindowCloseButtonHint) @@ -1352,6 +1349,9 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) [m_contentView setHidden: YES]; } + m_nsWindow.ignoresMouseEvents = + (window()->flags() & Qt::WindowTransparentForInput) == Qt::WindowTransparentForInput; + const qreal opacity = qt_window_private(window())->opacity; if (!qFuzzyCompare(opacity, qreal(1.0))) setOpacity(opacity); diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 7da0c4d402..a4f4c0855b 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -710,8 +710,12 @@ QT_WARNING_POP // Popups implicitly grap mouse events; forward to the active popup if there is one if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) { - if (QNSView *popupView = popup->qtView()) - targetView = popupView; + // Tooltips must be transparent for mouse events + // The bug reference is QTBUG-46379 + if (!popup->m_windowFlags.testFlag(Qt::ToolTip)) { + if (QNSView *popupView = popup->qtView()) + targetView = popupView; + } } [targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; diff --git a/src/plugins/platforms/ios/qiosmenu.h b/src/plugins/platforms/ios/qiosmenu.h index 4fa0416df7..ec23b55507 100644 --- a/src/plugins/platforms/ios/qiosmenu.h +++ b/src/plugins/platforms/ios/qiosmenu.h @@ -62,7 +62,7 @@ public: void setRole(MenuRole role) Q_DECL_OVERRIDE; void setCheckable(bool) Q_DECL_OVERRIDE {} void setChecked(bool) Q_DECL_OVERRIDE {} - void setShortcut(const QKeySequence&) Q_DECL_OVERRIDE {} + void setShortcut(const QKeySequence&) Q_DECL_OVERRIDE; void setEnabled(bool enabled) Q_DECL_OVERRIDE; void setIconSize(int) Q_DECL_OVERRIDE {} @@ -73,6 +73,7 @@ public: bool m_enabled; bool m_separator; QIOSMenu *m_menu; + QKeySequence m_shortcut; private: QString removeMnemonics(const QString &original); @@ -134,6 +135,7 @@ private: void toggleShowUsingUIMenuController(bool show); void toggleShowUsingUIPickerView(bool show); QIOSMenuItemList visibleMenuItems() const; + QIOSMenuItemList filterFirstResponderActions(const QIOSMenuItemList &menuItems); void repositionMenu(); }; diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm index 045d39e328..7aea3729fd 100644 --- a/src/plugins/platforms/ios/qiosmenu.mm +++ b/src/plugins/platforms/ios/qiosmenu.mm @@ -277,6 +277,11 @@ void QIOSMenuItem::setRole(QPlatformMenuItem::MenuRole role) m_role = role; } +void QIOSMenuItem::setShortcut(const QKeySequence &sequence) +{ + m_shortcut = sequence; +} + void QIOSMenuItem::setEnabled(bool enabled) { m_enabled = enabled; @@ -364,7 +369,7 @@ void QIOSMenu::syncMenuItem(QPlatformMenuItem *) switch (m_effectiveMenuType) { case EditMenu: - [m_menuController setVisibleMenuItems:visibleMenuItems()]; + [m_menuController setVisibleMenuItems:filterFirstResponderActions(visibleMenuItems())]; break; default: [m_pickerView setVisibleMenuItems:visibleMenuItems() selectItem:m_targetItem]; @@ -469,7 +474,7 @@ void QIOSMenu::toggleShowUsingUIMenuController(bool show) { if (show) { Q_ASSERT(!m_menuController); - m_menuController = [[QUIMenuController alloc] initWithVisibleMenuItems:visibleMenuItems()]; + m_menuController = [[QUIMenuController alloc] initWithVisibleMenuItems:filterFirstResponderActions(visibleMenuItems())]; repositionMenu(); connect(qGuiApp->inputMethod(), &QInputMethod::keyboardRectangleChanged, this, &QIOSMenu::repositionMenu); } else { @@ -542,6 +547,36 @@ QIOSMenuItemList QIOSMenu::visibleMenuItems() const return visibleMenuItems; } +QIOSMenuItemList QIOSMenu::filterFirstResponderActions(const QIOSMenuItemList &menuItems) +{ + // UIResponderStandardEditActions found in first responder will be prepended to the edit + // menu automatically (or e.g made available as buttons on the virtual keyboard). So we + // filter them out to avoid duplicates, and let first responder handle the actions instead. + // In case of QIOSTextResponder, edit actions will be converted to key events that ends up + // triggering the shortcuts of the filtered menu items. + QIOSMenuItemList filteredMenuItems; + UIResponder *responder = [UIResponder currentFirstResponder]; + + for (int i = 0; i < menuItems.count(); ++i) { + QIOSMenuItem *menuItem = menuItems.at(i); + QKeySequence shortcut = menuItem->m_shortcut; + if ((shortcut == QKeySequence::Cut && [responder canPerformAction:@selector(cut:) withSender:nil]) + || (shortcut == QKeySequence::Copy && [responder canPerformAction:@selector(copy:) withSender:nil]) + || (shortcut == QKeySequence::Paste && [responder canPerformAction:@selector(paste:) withSender:nil]) + || (shortcut == QKeySequence::Delete && [responder canPerformAction:@selector(delete:) withSender:nil]) + || (shortcut == QKeySequence::SelectAll && [responder canPerformAction:@selector(selectAll:) withSender:nil]) + || (shortcut == QKeySequence::Undo && [responder canPerformAction:@selector(undo:) withSender:nil]) + || (shortcut == QKeySequence::Redo && [responder canPerformAction:@selector(redo:) withSender:nil]) + || (shortcut == QKeySequence::Bold && [responder canPerformAction:@selector(toggleBoldface:) withSender:nil]) + || (shortcut == QKeySequence::Italic && [responder canPerformAction:@selector(toggleItalics:) withSender:nil]) + || (shortcut == QKeySequence::Underline && [responder canPerformAction:@selector(toggleUnderline:) withSender:nil])) { + continue; + } + filteredMenuItems.append(menuItem); + } + return filteredMenuItems; +} + void QIOSMenu::repositionMenu() { switch (m_effectiveMenuType) { diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index e4917593db..b95be7a883 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -231,6 +231,9 @@ if (UIView *accessoryView = static_cast<UIView *>(platformData.value(kImePlatformDataInputAccessoryView).value<void *>())) self.inputAccessoryView = [[[WrapperView alloc] initWithView:accessoryView] autorelease]; + self.undoManager.groupsByEvent = NO; + [self rebuildUndoStack]; + return self; } @@ -346,44 +349,183 @@ - (void)sendKeyPressRelease:(Qt::Key)key modifiers:(Qt::KeyboardModifiers)modifiers { - QKeyEvent press(QEvent::KeyPress, key, modifiers); - QKeyEvent release(QEvent::KeyRelease, key, modifiers); - [self sendEventToFocusObject:press]; - [self sendEventToFocusObject:release]; + QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyPress, key, modifiers); + QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyRelease, key, modifiers); +} + +#ifndef QT_NO_SHORTCUT + +- (void)sendShortcut:(QKeySequence::StandardKey)standardKey +{ + const int keys = QKeySequence(standardKey)[0]; + Qt::Key key = Qt::Key(keys & 0x0000FFFF); + Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(keys & 0xFFFF0000); + [self sendKeyPressRelease:key modifiers:modifiers]; } - (void)cut:(id)sender { Q_UNUSED(sender); - [self sendKeyPressRelease:Qt::Key_X modifiers:Qt::ControlModifier]; + [self sendShortcut:QKeySequence::Cut]; } - (void)copy:(id)sender { Q_UNUSED(sender); - [self sendKeyPressRelease:Qt::Key_C modifiers:Qt::ControlModifier]; + [self sendShortcut:QKeySequence::Copy]; } - (void)paste:(id)sender { Q_UNUSED(sender); - [self sendKeyPressRelease:Qt::Key_V modifiers:Qt::ControlModifier]; + [self sendShortcut:QKeySequence::Paste]; } - (void)selectAll:(id)sender { Q_UNUSED(sender); - [self sendKeyPressRelease:Qt::Key_A modifiers:Qt::ControlModifier]; + [self sendShortcut:QKeySequence::SelectAll]; } - (void)delete:(id)sender { Q_UNUSED(sender); - [self sendKeyPressRelease:Qt::Key_Delete modifiers:Qt::ControlModifier]; + [self sendShortcut:QKeySequence::Delete]; +} + +- (void)toggleBoldface:(id)sender +{ + Q_UNUSED(sender); + [self sendShortcut:QKeySequence::Bold]; +} + +- (void)toggleItalics:(id)sender +{ + Q_UNUSED(sender); + [self sendShortcut:QKeySequence::Italic]; +} + +- (void)toggleUnderline:(id)sender +{ + Q_UNUSED(sender); + [self sendShortcut:QKeySequence::Underline]; +} + +// ------------------------------------------------------------------------- + +- (void)undo +{ + [self sendShortcut:QKeySequence::Undo]; + [self rebuildUndoStack]; +} + +- (void)redo +{ + [self sendShortcut:QKeySequence::Redo]; + [self rebuildUndoStack]; +} + +- (void)registerRedo +{ + NSUndoManager *undoMgr = self.undoManager; + [undoMgr beginUndoGrouping]; + [undoMgr registerUndoWithTarget:self selector:@selector(redo) object:nil]; + [undoMgr endUndoGrouping]; +} + +- (void)rebuildUndoStack +{ + dispatch_async(dispatch_get_main_queue (), ^{ + // Register dummy undo/redo operations to enable Cmd-Z and Cmd-Shift-Z + // Ensure we do this outside any undo/redo callback since NSUndoManager + // will treat registerUndoWithTarget as registering a redo when called + // from within a undo callback. + NSUndoManager *undoMgr = self.undoManager; + [undoMgr removeAllActions]; + [undoMgr beginUndoGrouping]; + [undoMgr registerUndoWithTarget:self selector:@selector(undo) object:nil]; + [undoMgr endUndoGrouping]; + + // Schedule an operation that we immediately pop off to be able to schedule a redo + [undoMgr beginUndoGrouping]; + [undoMgr registerUndoWithTarget:self selector:@selector(registerRedo) object:nil]; + [undoMgr endUndoGrouping]; + [undoMgr undo]; + + // Note that, perhaps because of a bug in UIKit, the buttons on the shortcuts bar ends up + // disabled if a undo/redo callback doesn't lead to a [UITextInputDelegate textDidChange]. + // And we only call that method if Qt made changes to the text. The effect is that the buttons + // become disabled when there is nothing more to undo (Qt didn't change anything upon receiving + // an undo request). This seems to be OK behavior, so we let it stay like that unless it shows + // to cause problems. + }); } // ------------------------------------------------------------------------- +- (void)keyCommandTriggered:(UIKeyCommand *)keyCommand +{ + Qt::Key key = Qt::Key_unknown; + Qt::KeyboardModifiers modifiers = Qt::NoModifier; + + if (keyCommand.input == UIKeyInputLeftArrow) + key = Qt::Key_Left; + else if (keyCommand.input == UIKeyInputRightArrow) + key = Qt::Key_Right; + else if (keyCommand.input == UIKeyInputUpArrow) + key = Qt::Key_Up; + else if (keyCommand.input == UIKeyInputDownArrow) + key = Qt::Key_Down; + else + Q_UNREACHABLE(); + + if (keyCommand.modifierFlags & UIKeyModifierAlternate) + modifiers |= Qt::AltModifier; + if (keyCommand.modifierFlags & UIKeyModifierShift) + modifiers |= Qt::ShiftModifier; + if (keyCommand.modifierFlags & UIKeyModifierCommand) + modifiers |= Qt::ControlModifier; + + [self sendKeyPressRelease:key modifiers:modifiers]; +} + +- (void)addKeyCommandsToArray:(NSMutableArray *)array key:(NSString *)key +{ + SEL s = @selector(keyCommandTriggered:); + [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:0 action:s]]; + [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierShift action:s]]; + [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierAlternate action:s]]; + [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierAlternate|UIKeyModifierShift action:s]]; + [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand action:s]]; + [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand|UIKeyModifierShift action:s]]; +} + +- (NSArray *)keyCommands +{ + // Since keyCommands is called for every key + // press/release, we cache the result + static dispatch_once_t once; + static NSMutableArray *array; + + dispatch_once(&once, ^{ + // We let Qt move the cursor around when the arrow keys are being used. This + // is normally implemented through UITextInput, but since IM in Qt have poor + // support for moving the cursor vertically, and even less support for selecting + // text across multiple paragraphs, we do this through key events. + array = [NSMutableArray new]; + [self addKeyCommandsToArray:array key:UIKeyInputUpArrow]; + [self addKeyCommandsToArray:array key:UIKeyInputDownArrow]; + [self addKeyCommandsToArray:array key:UIKeyInputLeftArrow]; + [self addKeyCommandsToArray:array key:UIKeyInputRightArrow]; + }); + + return array; +} + +#endif // QT_NO_SHORTCUT + +// ------------------------------------------------------------------------- + - (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties { // As documented, we should not report textWillChange/textDidChange unless the text @@ -540,7 +682,17 @@ - (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset { int p = static_cast<QUITextPosition *>(position).index; - return [QUITextPosition positionWithIndex:(direction == UITextLayoutDirectionRight ? p + offset : p - offset)]; + + switch (direction) { + case UITextLayoutDirectionLeft: + return [QUITextPosition positionWithIndex:p - offset]; + case UITextLayoutDirectionRight: + return [QUITextPosition positionWithIndex:p + offset]; + default: + // Qt doesn't support getting the position above or below the current position, so + // for those cases we just return the current position, making it a no-op. + return position; + } } - (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction @@ -608,6 +760,15 @@ return toCGRect(startRect.united(endRect)); } +- (NSArray *)selectionRectsForRange:(UITextRange *)range +{ + Q_UNUSED(range); + // This method is supposed to return a rectangle for each line with selection. Since we don't + // expose an API in Qt/IM for getting this information, and since we never seems to be getting + // a call from UIKit for this, we return an empty array until a need arise. + return [[NSArray new] autorelease]; +} + - (CGRect)caretRectForPosition:(UITextPosition *)position { Q_UNUSED(position); @@ -734,10 +895,10 @@ - (void)deleteBackward { - // Since we're posting im events directly to the focus object, we should do the - // same for key events. Otherwise they might end up in a different place or out - // of sync with im events. + // UITextInput selects the text to be deleted before calling this method. To avoid + // drawing the selection, we flush after posting the key press/release. [self sendKeyPressRelease:Qt::Key_Backspace modifiers:Qt::NoModifier]; + QWindowSystemInterface::flushWindowSystemEvents(); } @end diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm index edeabf66dc..bc40069670 100644 --- a/src/plugins/platforms/ios/qiostheme.mm +++ b/src/plugins/platforms/ios/qiostheme.mm @@ -107,6 +107,8 @@ QVariant QIOSTheme::themeHint(ThemeHint hint) const switch (hint) { case QPlatformTheme::StyleNames: return QStringList(QStringLiteral("fusion")); + case KeyboardScheme: + return QVariant(int(MacKeyboardScheme)); default: return QPlatformTheme::themeHint(hint); } diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index 67b33ce235..94d894bba7 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -185,7 +185,14 @@ - (void)setFrame:(CGRect)newFrame { - [super setFrame:CGRectMake(0, 0, CGRectGetWidth(newFrame), CGRectGetHeight(self.window.bounds))]; + Q_UNUSED(newFrame); + Q_ASSERT(!self.window || self.window.rootViewController.view == self); + + // When presenting view controllers our view may be temporarily reparented into a UITransitionView + // instead of the UIWindow, and the UITransitionView may have a transform set, so we need to do a + // mapping even if we still expect to always be the root view-controller. + CGRect transformedWindowBounds = [self.superview convertRect:self.window.bounds fromView:self.window]; + [super setFrame:transformedWindowBounds]; } - (void)setBounds:(CGRect)newBounds diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index e4ec3f3cf8..02073f5098 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -152,7 +152,7 @@ bool QWindowsLibEGL::init() eglGetCurrentSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLint )), eglGetCurrentSurface); eglGetCurrentDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(void)), eglGetCurrentDisplay); eglSwapBuffers = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface)), eglSwapBuffers); - eglGetProcAddress = RESOLVE((__eglMustCastToProperFunctionPointerType (EGLAPIENTRY * )(const char *)), eglGetProcAddress); + eglGetProcAddress = RESOLVE((QFunctionPointer (EGLAPIENTRY * )(const char *)), eglGetProcAddress); if (!eglGetError || !eglGetDisplay || !eglInitialize || !eglGetProcAddress) return false; diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h index d8302c97a7..555d633a78 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.h +++ b/src/plugins/platforms/windows/qwindowseglcontext.h @@ -71,7 +71,7 @@ struct QWindowsLibEGL EGLSurface (EGLAPIENTRY * eglGetCurrentSurface)(EGLint readdraw); EGLDisplay (EGLAPIENTRY * eglGetCurrentDisplay)(void); EGLBoolean (EGLAPIENTRY * eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); - __eglMustCastToProperFunctionPointerType (EGLAPIENTRY * eglGetProcAddress)(const char *procname); + QFunctionPointer (EGLAPIENTRY *eglGetProcAddress)(const char *procname); EGLDisplay (EGLAPIENTRY * eglGetPlatformDisplayEXT)(EGLenum platform, void *native_display, const EGLint *attrib_list); diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp index 0dd2facd4d..0bfa0239aa 100644 --- a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp +++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp @@ -67,18 +67,20 @@ QWindowsGuiEventDispatcher::QWindowsGuiEventDispatcher(QObject *parent) : bool QWindowsGuiEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) { + const QEventLoop::ProcessEventsFlags oldFlags = m_flags; m_flags = flags; if (QWindowsContext::verbose > 2 && lcQpaEvents().isDebugEnabled()) qCDebug(lcQpaEvents) << '>' << __FUNCTION__ << objectName() << flags; const bool rc = QEventDispatcherWin32::processEvents(flags); if (QWindowsContext::verbose > 2 && lcQpaEvents().isDebugEnabled()) qCDebug(lcQpaEvents) << '<' << __FUNCTION__ << "returns" << rc; + m_flags = oldFlags; return rc; } void QWindowsGuiEventDispatcher::sendPostedEvents() { - QCoreApplication::sendPostedEvents(); + QEventDispatcherWin32::sendPostedEvents(); QWindowSystemInterface::sendWindowSystemEvents(m_flags); } diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index 52e83395d1..befd06f1a2 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -276,7 +276,7 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedGlesRenderers() { const GpuDescription gpu = GpuDescription::detect(); const QWindowsOpenGLTester::Renderers result = detectSupportedRenderers(gpu, true); - qDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result; + qCDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result; return result; } @@ -284,7 +284,7 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedRenderers() { const GpuDescription gpu = GpuDescription::detect(); const QWindowsOpenGLTester::Renderers result = detectSupportedRenderers(gpu, false); - qDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result; + qCDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result; return result; } diff --git a/src/printsupport/dialogs/qprintdialog_unix.cpp b/src/printsupport/dialogs/qprintdialog_unix.cpp index a15fd51c98..9633032a0f 100644 --- a/src/printsupport/dialogs/qprintdialog_unix.cpp +++ b/src/printsupport/dialogs/qprintdialog_unix.cpp @@ -806,7 +806,7 @@ void QUnixPrintWidgetPrivate::applyPrinterProperties() home += QLatin1Char('/'); if (!cur.isEmpty() && cur.at(cur.length()-1) != QLatin1Char('/')) cur += QLatin1Char('/'); - if (cur.left(home.length()) != home) + if (!cur.startsWith(home)) cur = home; if (QGuiApplication::platformName() == QLatin1String("xcb")) { if (printer->docName().isEmpty()) { diff --git a/src/printsupport/kernel/qpaintengine_alpha.cpp b/src/printsupport/kernel/qpaintengine_alpha.cpp index 0ae9464b69..79026e5762 100644 --- a/src/printsupport/kernel/qpaintengine_alpha.cpp +++ b/src/printsupport/kernel/qpaintengine_alpha.cpp @@ -146,8 +146,16 @@ void QAlphaPaintEngine::updateState(const QPaintEngineState &state) d->m_hasalpha = d->m_alphaOpacity || d->m_alphaBrush || d->m_alphaPen; - if (d->m_picengine) + if (d->m_picengine) { + const QPainter *p = painter(); + d->m_picpainter->setPen(p->pen()); + d->m_picpainter->setBrush(p->brush()); + d->m_picpainter->setBrushOrigin(p->brushOrigin()); + d->m_picpainter->setFont(p->font()); + d->m_picpainter->setOpacity(p->opacity()); + d->m_picpainter->setTransform(p->combinedTransform()); d->m_picengine->updateState(state); + } } void QAlphaPaintEngine::drawPath(const QPainterPath &path) diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp index b377401ed9..a4209d833a 100644 --- a/src/printsupport/kernel/qprintengine_win.cpp +++ b/src/printsupport/kernel/qprintengine_win.cpp @@ -93,9 +93,10 @@ static QByteArray msgBeginFailed(const char *function, const DOCINFO &d) { QString result; QTextStream str(&result); - str << "QWin32PrintEngine::begin: " << function << " failed, document \"" - << QString::fromWCharArray(d.lpszDocName) << '"'; - if (d.lpszOutput[0]) + str << "QWin32PrintEngine::begin: " << function << " failed"; + if (d.lpszDocName && d.lpszDocName[0]) + str << ", document \"" << QString::fromWCharArray(d.lpszDocName) << '"'; + if (d.lpszOutput && d.lpszOutput[0]) str << ", file \"" << QString::fromWCharArray(d.lpszOutput) << '"'; return result.toLocal8Bit(); } diff --git a/src/tools/qdoc/doc/examples/examples.qdoc b/src/tools/qdoc/doc/examples/examples.qdoc index ce67dea20e..28810e30da 100644 --- a/src/tools/qdoc/doc/examples/examples.qdoc +++ b/src/tools/qdoc/doc/examples/examples.qdoc @@ -89,9 +89,9 @@ \title UI Components \brief Basic set of UI components - This is a listing of a list of UI components implemented by QML types. - These files are available for general import and they are based off the - \e {Qt Quick Code Samples}. + This is a listing of a list of UI components implemented by QML types. These + files are available for general import and they are based on the + \l{Qt Quick Examples and Tutorials}{Qt Quick Code Samples}. This module is part of the \l{componentset}{UIComponents} example. */ diff --git a/src/widgets/accessible/accessible.pri b/src/widgets/accessible/accessible.pri index bcdfbd639c..ac8205b1e3 100644 --- a/src/widgets/accessible/accessible.pri +++ b/src/widgets/accessible/accessible.pri @@ -4,12 +4,12 @@ contains(QT_CONFIG, accessibility) { HEADERS += \ accessible/qaccessiblewidget.h \ accessible/qaccessiblewidgetfactory_p.h \ - accessible/complexwidgets.h \ - accessible/itemviews.h \ - accessible/qaccessiblemenu.h \ - accessible/qaccessiblewidgets.h \ - accessible/rangecontrols.h \ - accessible/simplewidgets.h + accessible/complexwidgets_p.h \ + accessible/itemviews_p.h \ + accessible/qaccessiblemenu_p.h \ + accessible/qaccessiblewidgets_p.h \ + accessible/rangecontrols_p.h \ + accessible/simplewidgets_p.h SOURCES += \ accessible/qaccessiblewidget.cpp \ diff --git a/src/widgets/accessible/complexwidgets.cpp b/src/widgets/accessible/complexwidgets.cpp index 649a7f4363..ba87fead3c 100644 --- a/src/widgets/accessible/complexwidgets.cpp +++ b/src/widgets/accessible/complexwidgets.cpp @@ -31,7 +31,7 @@ ** ****************************************************************************/ -#include "complexwidgets.h" +#include "complexwidgets_p.h" #include <qaccessible.h> #include <qapplication.h> diff --git a/src/widgets/accessible/complexwidgets.h b/src/widgets/accessible/complexwidgets_p.h index bd063e7517..8edf996818 100644 --- a/src/widgets/accessible/complexwidgets.h +++ b/src/widgets/accessible/complexwidgets_p.h @@ -34,6 +34,17 @@ #ifndef COMPLEXWIDGETS_H #define COMPLEXWIDGETS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/qpointer.h> #include <QtWidgets/qaccessiblewidget.h> #include <QtWidgets/qabstractitemview.h> diff --git a/src/widgets/accessible/itemviews.cpp b/src/widgets/accessible/itemviews.cpp index 23a459c7e6..1b724c9a17 100644 --- a/src/widgets/accessible/itemviews.cpp +++ b/src/widgets/accessible/itemviews.cpp @@ -31,7 +31,7 @@ ** ****************************************************************************/ -#include "itemviews.h" +#include "itemviews_p.h" #include <qheaderview.h> #include <qtableview.h> diff --git a/src/widgets/accessible/itemviews.h b/src/widgets/accessible/itemviews_p.h index 33757f168a..6a18a1231b 100644 --- a/src/widgets/accessible/itemviews.h +++ b/src/widgets/accessible/itemviews_p.h @@ -34,6 +34,17 @@ #ifndef ACCESSIBLE_ITEMVIEWS_H #define ACCESSIBLE_ITEMVIEWS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "QtCore/qpointer.h" #include <QtGui/qaccessible.h> #include <QtWidgets/qaccessiblewidget.h> diff --git a/src/widgets/accessible/qaccessiblemenu.cpp b/src/widgets/accessible/qaccessiblemenu.cpp index 72eb82b2b7..a0a7852851 100644 --- a/src/widgets/accessible/qaccessiblemenu.cpp +++ b/src/widgets/accessible/qaccessiblemenu.cpp @@ -31,7 +31,7 @@ ** ****************************************************************************/ -#include "qaccessiblemenu.h" +#include "qaccessiblemenu_p.h" #include <qmenu.h> #include <qmenubar.h> diff --git a/src/widgets/accessible/qaccessiblemenu.h b/src/widgets/accessible/qaccessiblemenu_p.h index 9c7671072d..b42c852ff1 100644 --- a/src/widgets/accessible/qaccessiblemenu.h +++ b/src/widgets/accessible/qaccessiblemenu_p.h @@ -34,6 +34,17 @@ #ifndef QACCESSIBLEMENU_H #define QACCESSIBLEMENU_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtWidgets/qaccessiblewidget.h> #include <QtCore/qpointer.h> diff --git a/src/widgets/accessible/qaccessiblewidgetfactory.cpp b/src/widgets/accessible/qaccessiblewidgetfactory.cpp index e8b325b93f..4fa7c89482 100644 --- a/src/widgets/accessible/qaccessiblewidgetfactory.cpp +++ b/src/widgets/accessible/qaccessiblewidgetfactory.cpp @@ -31,12 +31,12 @@ ** ****************************************************************************/ -#include "qaccessiblewidgets.h" -#include "qaccessiblemenu.h" -#include "simplewidgets.h" -#include "rangecontrols.h" -#include "complexwidgets.h" -#include "itemviews.h" +#include "qaccessiblewidgets_p.h" +#include "qaccessiblemenu_p.h" +#include "simplewidgets_p.h" +#include "rangecontrols_p.h" +#include "complexwidgets_p.h" +#include "itemviews_p.h" #include <qpushbutton.h> #include <qtoolbutton.h> diff --git a/src/widgets/accessible/qaccessiblewidgets.cpp b/src/widgets/accessible/qaccessiblewidgets.cpp index c598a5b4cb..adf908b821 100644 --- a/src/widgets/accessible/qaccessiblewidgets.cpp +++ b/src/widgets/accessible/qaccessiblewidgets.cpp @@ -31,7 +31,7 @@ ** ****************************************************************************/ -#include "qaccessiblewidgets.h" +#include "qaccessiblewidgets_p.h" #include "qabstracttextdocumentlayout.h" #include "qapplication.h" #include "qclipboard.h" diff --git a/src/widgets/accessible/qaccessiblewidgets.h b/src/widgets/accessible/qaccessiblewidgets_p.h index 53f8c2c603..4bdc229578 100644 --- a/src/widgets/accessible/qaccessiblewidgets.h +++ b/src/widgets/accessible/qaccessiblewidgets_p.h @@ -34,6 +34,17 @@ #ifndef QACCESSIBLEWIDGETS_H #define QACCESSIBLEWIDGETS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtWidgets/qaccessiblewidget.h> #ifndef QT_NO_ACCESSIBILITY diff --git a/src/widgets/accessible/rangecontrols.cpp b/src/widgets/accessible/rangecontrols.cpp index 002d4a9ef4..0607a35269 100644 --- a/src/widgets/accessible/rangecontrols.cpp +++ b/src/widgets/accessible/rangecontrols.cpp @@ -31,7 +31,7 @@ ** ****************************************************************************/ -#include "rangecontrols.h" +#include "rangecontrols_p.h" #include <qslider.h> #include <qdial.h> @@ -47,7 +47,7 @@ #include <qmath.h> #include <private/qmath_p.h> -#include "simplewidgets.h" // let spinbox use line edit's interface +#include "simplewidgets_p.h" // let spinbox use line edit's interface QT_BEGIN_NAMESPACE diff --git a/src/widgets/accessible/rangecontrols.h b/src/widgets/accessible/rangecontrols_p.h index 11d4435e9d..32c6d6985f 100644 --- a/src/widgets/accessible/rangecontrols.h +++ b/src/widgets/accessible/rangecontrols_p.h @@ -34,6 +34,17 @@ #ifndef RANGECONTROLS_H #define RANGECONTROLS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtWidgets/qaccessiblewidget.h> QT_BEGIN_NAMESPACE diff --git a/src/widgets/accessible/simplewidgets.cpp b/src/widgets/accessible/simplewidgets.cpp index b08c21939a..065c618cf7 100644 --- a/src/widgets/accessible/simplewidgets.cpp +++ b/src/widgets/accessible/simplewidgets.cpp @@ -31,7 +31,7 @@ ** ****************************************************************************/ -#include "simplewidgets.h" +#include "simplewidgets_p.h" #include <qabstractbutton.h> #include <qcheckbox.h> diff --git a/src/widgets/accessible/simplewidgets.h b/src/widgets/accessible/simplewidgets_p.h index 0dfd9f79c8..c2e904273f 100644 --- a/src/widgets/accessible/simplewidgets.h +++ b/src/widgets/accessible/simplewidgets_p.h @@ -34,6 +34,17 @@ #ifndef SIMPLEWIDGETS_H #define SIMPLEWIDGETS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/qcoreapplication.h> #include <QtWidgets/qaccessiblewidget.h> diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index ee2b1e6dae..443213d0de 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -2833,6 +2833,13 @@ void QFileDialogPrivate::createWidgets() if (qFileDialogUi) return; Q_Q(QFileDialog); + + // This function is sometimes called late (e.g as a fallback from setVisible). In that case we + // need to ensure that the following UI code (setupUI in particular) doesn't reset any explicitly + // set window state or geometry. + QSize preSize = q->testAttribute(Qt::WA_Resized) ? q->size() : QSize(); + Qt::WindowStates preState = q->windowState(); + model = new QFileSystemModel(q); model->setFilter(options->filter()); model->setObjectName(QLatin1String("qt_filesystem_model")); @@ -2878,6 +2885,9 @@ void QFileDialogPrivate::createWidgets() completer = new QFSCompleter(model, q); qFileDialogUi->fileNameEdit->setCompleter(completer); #endif // QT_NO_FSCOMPLETER + + qFileDialogUi->fileNameEdit->setInputMethodHints(Qt::ImhNoPredictiveText); + QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)), q, SLOT(_q_autoCompleteFileName(QString))); QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)), @@ -2991,7 +3001,8 @@ void QFileDialogPrivate::createWidgets() lineEdit()->selectAll(); _q_updateOkButton(); retranslateStrings(); - q->resize(q->sizeHint()); + q->resize(preSize.isValid() ? preSize : q->sizeHint()); + q->setWindowState(preState); } void QFileDialogPrivate::_q_showHeader(QAction *action) diff --git a/src/widgets/doc/images/filedialogurls.png b/src/widgets/doc/images/filedialogurls.png Binary files differindex 7d22ef33ae..4e26bbfb6d 100644 --- a/src/widgets/doc/images/filedialogurls.png +++ b/src/widgets/doc/images/filedialogurls.png diff --git a/src/widgets/doc/qtwidgets.qdocconf b/src/widgets/doc/qtwidgets.qdocconf index ab20a8666c..f307e9d3e4 100644 --- a/src/widgets/doc/qtwidgets.qdocconf +++ b/src/widgets/doc/qtwidgets.qdocconf @@ -26,7 +26,7 @@ qhp.QtWidgets.subprojects.classes.sortPages = true tagfile = ../../../doc/qtwidgets/qtwidgets.tags -depends += qtcore qtgui qtdoc qtsql qtdesigner qtquick qmake +depends += qtcore qtgui qtdoc qtsql qtdesigner qtquick qmake qtsvg headerdirs += .. diff --git a/src/widgets/doc/snippets/filedialogurls.cpp b/src/widgets/doc/snippets/filedialogurls.cpp index 9e2862b56f..ea771c2050 100644 --- a/src/widgets/doc/snippets/filedialogurls.cpp +++ b/src/widgets/doc/snippets/filedialogurls.cpp @@ -46,8 +46,8 @@ int main(int argv, char **args) //![0] QList<QUrl> urls; - urls << QUrl::fromLocalFile("/home/gvatteka/dev/qt-45") - << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MusicLocation)); + urls << QUrl::fromLocalFile("/Users/foo/Code/qt5") + << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::MusicLocation).first()); QFileDialog dialog; dialog.setSidebarUrls(urls); diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp index 8cb7c2b560..9a35308cad 100644 --- a/src/widgets/kernel/qgesturemanager.cpp +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -405,6 +405,8 @@ void QGestureManager::cancelGesturesForChildren(QGesture *original) Q_ASSERT(original); QWidget *originatingWidget = m_gestureTargets.value(original); Q_ASSERT(originatingWidget); + if (!originatingWidget) + return; // iterate over all active gestures and all maybe gestures // for each find the owner @@ -565,7 +567,8 @@ void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures, foreach (QGesture *gesture, gestures) { QWidget *receiver = m_gestureTargets.value(gesture, 0); Q_ASSERT(receiver); - gestureByTypes[gesture->gestureType()].insert(receiver, gesture); + if (receiver) + gestureByTypes[gesture->gestureType()].insert(receiver, gesture); } // for each gesture type diff --git a/src/widgets/kernel/qgesturemanager_p.h b/src/widgets/kernel/qgesturemanager_p.h index 8ba253d17e..4e349ac731 100644 --- a/src/widgets/kernel/qgesturemanager_p.h +++ b/src/widgets/kernel/qgesturemanager_p.h @@ -117,7 +117,7 @@ private: QHash<QGesture *, QGestureRecognizer *> m_gestureToRecognizer; QHash<QGesture *, QObject *> m_gestureOwners; - QHash<QGesture *, QWidget *> m_gestureTargets; + QHash<QGesture *, QPointer<QWidget> > m_gestureTargets; int m_lastCustomGestureId; diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 66c86a7bce..a006246454 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -5829,7 +5829,10 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint * pixmapOffset -= effectRect.topLeft(); - QPixmap pixmap(effectRect.size()); + const qreal dpr = context->painter->device()->devicePixelRatio(); + QPixmap pixmap(effectRect.size() * dpr); + pixmap.setDevicePixelRatio(dpr); + pixmap.fill(Qt::transparent); m_widget->render(&pixmap, pixmapOffset, QRegion(), QWidget::DrawChildren); return pixmap; |