summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-06-06 08:34:03 +0200
committerLiang Qi <liang.qi@qt.io>2016-06-06 09:04:55 +0200
commit57057f76add416d0faf2e09a90c126baafb6198e (patch)
tree07d54f8e5daeb3ed1161723542e94c324d745166 /src
parentdc0ae02ebc8e221f952829230c0301a718a6f10b (diff)
parentfd70978693bd92761e9989bc1c76bf83c1e8c987 (diff)
Merge remote-tracking branch 'origin/5.6' into 5.7
Conflicts: .qmake.conf config.tests/unix/nis/nis.cpp mkspecs/unsupported/freebsd-g++/qplatformdefs.h src/corelib/tools/qdatetime.cpp src/corelib/tools/qsimd.cpp src/corelib/tools/qsimd_p.h src/network/access/access.pri src/network/access/qnetworkreplynsurlconnectionimpl.mm src/network/access/qnetworkreplynsurlconnectionimpl_p.h src/plugins/platforms/cocoa/qnsview.mm src/plugins/printsupport/windows/qwindowsprintdevice.cpp tests/auto/corelib/kernel/qobject/tst_qobject.cpp tests/auto/network/access/qnetworkreply/BLACKLIST tests/auto/widgets/widgets/qopenglwidget/BLACKLIST Change-Id: I4b32055bbf922392ef0264fd403405416fffee57
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/forkfd/forkfd.c46
-rw-r--r--src/corelib/global/global.pri23
-rw-r--r--src/corelib/global/qcompilerdetection.h7
-rw-r--r--src/corelib/global/qendian.h24
-rw-r--r--src/corelib/global/qendian.qdoc23
-rw-r--r--src/corelib/global/qsystemdetection.h4
-rw-r--r--src/corelib/io/io.pri1
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp4
-rw-r--r--src/corelib/io/qfilesystemwatcher_kqueue.cpp2
-rw-r--r--src/corelib/io/qlockfile_unix.cpp43
-rw-r--r--src/corelib/io/qlockfile_win.cpp6
-rw-r--r--src/corelib/io/qprocess.cpp10
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp2
-rw-r--r--src/corelib/io/qwindowspipewriter.cpp2
-rw-r--r--src/corelib/json/qjson_p.h2
-rw-r--r--src/corelib/json/qjsonvalue.cpp24
-rw-r--r--src/corelib/kernel/qcore_unix.cpp10
-rw-r--r--src/corelib/kernel/qcore_unix_p.h10
-rw-r--r--src/corelib/kernel/qobject.cpp2
-rw-r--r--src/corelib/kernel/qobject.h6
-rw-r--r--src/corelib/mimetypes/qmimemagicrule.cpp3
-rw-r--r--src/corelib/tools/qbitarray.cpp26
-rw-r--r--src/corelib/tools/qcryptographichash.cpp20
-rw-r--r--src/corelib/tools/qdatetime.cpp2
-rw-r--r--src/corelib/tools/qhash.cpp9
-rw-r--r--src/corelib/tools/qmessageauthenticationcode.cpp20
-rw-r--r--src/corelib/tools/qsimd.cpp22
-rw-r--r--src/corelib/tools/qstring.cpp2
-rw-r--r--src/corelib/tools/qtimezoneprivate_tz.cpp214
-rw-r--r--src/gui/doc/snippets/code/src_gui_kernel_qclipboard.cpp2
-rw-r--r--src/gui/image/qbmphandler.cpp16
-rw-r--r--src/gui/image/qimage.cpp6
-rw-r--r--src/gui/kernel/qclipboard.cpp8
-rw-r--r--src/gui/painting/qpainter.cpp9
-rw-r--r--src/gui/text/qfontdatabase.cpp3
-rw-r--r--src/gui/text/qfontengine.cpp3
-rw-r--r--src/gui/text/qtextengine.cpp8
-rw-r--r--src/gui/text/qtextformat.cpp7
-rw-r--r--src/gui/text/qtextformat.h4
-rw-r--r--src/network/access/access.pri10
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp2
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp10
-rw-r--r--src/network/access/qnetworkreplynsurlconnectionimpl.mm458
-rw-r--r--src/network/access/qnetworkreplynsurlconnectionimpl_p.h87
-rw-r--r--src/network/kernel/qdnslookup_unix.cpp7
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp6
-rw-r--r--src/network/socket/qnativesocketengine_winrt.cpp30
-rw-r--r--src/network/socket/qnativesocketengine_winrt_p.h3
-rw-r--r--src/network/socket/qsocks5socketengine.cpp4
-rw-r--r--src/network/ssl/qsslsocket.cpp3
-rw-r--r--src/platformheaders/doc/src/qtplatformheaders.qdoc13
-rw-r--r--src/platformsupport/devicediscovery/devicediscovery.pri22
-rw-r--r--src/platformsupport/eglconvenience/qeglconvenience.cpp4
-rw-r--r--src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp15
-rw-r--r--src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h3
-rw-r--r--src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp13
-rw-r--r--src/platformsupport/platformsupport.pro6
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm8
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm18
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp2
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.h5
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm40
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm1
-rw-r--r--src/plugins/platforms/minimal/minimal.pro1
-rw-r--r--src/plugins/platforms/platforms.pro4
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.cpp67
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp11
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp7
-rw-r--r--src/plugins/platforms/winrt/qwinrtdrag.cpp893
-rw-r--r--src/plugins/platforms/winrt/qwinrtdrag.h113
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.cpp14
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.h4
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp18
-rw-r--r--src/plugins/platforms/winrt/winrt.pro11
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp2
-rw-r--r--src/plugins/plugins.pro2
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintdevice.cpp156
-rw-r--r--src/testlib/doc/qttestlib.qdocconf2
-rw-r--r--src/testlib/doc/src/qttestlib-manual.qdoc5
-rw-r--r--src/testlib/qtestblacklist.cpp70
-rw-r--r--src/testlib/qtestcase.cpp2
-rw-r--r--src/widgets/dialogs/qdialog.cpp6
-rw-r--r--src/widgets/itemviews/qabstractitemview.cpp3
-rw-r--r--src/widgets/kernel/qdesktopwidget.cpp99
-rw-r--r--src/widgets/kernel/qdesktopwidget_p.h16
-rw-r--r--src/widgets/kernel/qopenglwidget.cpp4
-rw-r--r--src/widgets/kernel/qwidgetbackingstore.cpp22
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp8
-rw-r--r--src/widgets/widgets/qwidgetlinecontrol.cpp18
-rw-r--r--src/widgets/widgets/qwidgetlinecontrol_p.h5
92 files changed, 1930 insertions, 1046 deletions
diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c
index ad05ab1a01..7b711e197b 100644
--- a/src/3rdparty/forkfd/forkfd.c
+++ b/src/3rdparty/forkfd/forkfd.c
@@ -30,6 +30,9 @@
#include "forkfd.h"
#include <sys/types.h>
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+# include <sys/param.h>
+#endif
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
@@ -65,7 +68,9 @@
# undef HAVE_WAITID
#endif
-#if defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version >= 1000032
+#if (defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version >= 1000032) || \
+ (defined(__OpenBSD__) && OpenBSD >= 201505) || \
+ (defined(__NetBSD__) && __NetBSD_Version__ >= 600000000)
# define HAVE_PIPE2 1
#endif
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) || \
@@ -410,6 +415,26 @@ chain_handler:
old_sigaction.sa_handler(signum);
}
+static void ignore_sigpipe()
+{
+#ifdef O_NOSIGPIPE
+ static ffd_atomic_int done = FFD_ATOMIC_INIT(0);
+ if (ffd_atomic_load(&done, FFD_ATOMIC_RELAXED))
+ return;
+#endif
+
+ struct sigaction action;
+ memset(&action, 0, sizeof action);
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ action.sa_flags = 0;
+ sigaction(SIGPIPE, &action, NULL);
+
+#ifdef O_NOSIGPIPE
+ ffd_atomic_store(&done, 1, FFD_ATOMIC_RELAXED);
+#endif
+}
+
static void forkfd_initialize()
{
#if defined(HAVE_BROKEN_WAITID)
@@ -446,6 +471,11 @@ static void forkfd_initialize()
*/
sigaction(SIGCHLD, &action, &old_sigaction);
+#ifndef O_NOSIGPIPE
+ /* disable SIGPIPE too */
+ ignore_sigpipe();
+#endif
+
#ifndef __GNUC__
atexit(cleanup);
#endif
@@ -486,13 +516,23 @@ static void cleanup()
static int create_pipe(int filedes[], int flags)
{
- int ret;
+ int ret = -1;
#ifdef HAVE_PIPE2
/* use pipe2(2) whenever possible, since it can thread-safely create a
* cloexec pair of pipes. Without it, we have a race condition setting
* FD_CLOEXEC
*/
- ret = pipe2(filedes, O_CLOEXEC);
+
+# ifdef O_NOSIGPIPE
+ /* try first with O_NOSIGPIPE */
+ ret = pipe2(filedes, O_CLOEXEC | O_NOSIGPIPE);
+ if (ret == -1) {
+ /* O_NOSIGPIPE not supported, ignore SIGPIPE */
+ ignore_sigpipe();
+ }
+# endif
+ if (ret == -1)
+ ret = pipe2(filedes, O_CLOEXEC);
if (ret == -1)
return ret;
diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri
index dd846955f6..6a8948822c 100644
--- a/src/corelib/global/global.pri
+++ b/src/corelib/global/global.pri
@@ -28,8 +28,9 @@ SOURCES += \
global/qmalloc.cpp \
global/qnumeric.cpp \
global/qlogging.cpp \
- global/qhooks.cpp \
- global/qversiontagging.cpp
+ global/qhooks.cpp
+
+VERSIONTAGGING_SOURCES = global/qversiontagging.cpp
# qlibraryinfo.cpp includes qconfig.cpp
INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global
@@ -63,3 +64,21 @@ journald {
syslog {
DEFINES += QT_USE_SYSLOG
}
+
+gcc:ltcg {
+ versiontagging_compiler.commands = $$QMAKE_CXX -c $(CXXFLAGS) $(INCPATH)
+
+ # Disable LTO, as the symbols disappear somehow under GCC
+ versiontagging_compiler.commands += -fno-lto
+
+ versiontagging_compiler.commands += -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN}
+ versiontagging_compiler.dependency_type = TYPE_C
+ versiontagging_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
+ versiontagging_compiler.input = VERSIONTAGGING_SOURCES
+ versiontagging_compiler.variable_out = OBJECTS
+ versiontagging_compiler.name = compiling[versiontagging] ${QMAKE_FILE_IN}
+ silent: versiontagging_compiler.commands = @echo compiling[versiontagging] ${QMAKE_FILE_IN} && $$versiontagging_compiler.commands
+ QMAKE_EXTRA_COMPILERS += versiontagging_compiler
+} else {
+ SOURCES += $$VERSIONTAGGING_SOURCES
+}
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index 85613283f9..669ab136ac 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -756,7 +756,9 @@
# define Q_COMPILER_TEMPLATE_ALIAS
# endif
# if __has_feature(cxx_thread_local)
-# define Q_COMPILER_THREAD_LOCAL
+# if !defined(__FreeBSD__) /* FreeBSD clang fails on __cxa_thread_atexit */
+# define Q_COMPILER_THREAD_LOCAL
+# endif
# endif
# if __has_feature(cxx_user_literals)
# define Q_COMPILER_UDL
@@ -1114,7 +1116,8 @@
# define Q_DECL_NOTHROW Q_DECL_NOEXCEPT
#endif
-#if defined(Q_COMPILER_ALIGNOF) && !defined(Q_ALIGNOF)
+#if defined(Q_COMPILER_ALIGNOF)
+# undef Q_ALIGNOF
# define Q_ALIGNOF(x) alignof(x)
#endif
diff --git a/src/corelib/global/qendian.h b/src/corelib/global/qendian.h
index c5ff82c10a..34bb015a2f 100644
--- a/src/corelib/global/qendian.h
+++ b/src/corelib/global/qendian.h
@@ -49,6 +49,11 @@
QT_BEGIN_NAMESPACE
+#ifdef __has_builtin
+# define QT_HAS_BUILTIN(x) __has_builtin(x)
+#else
+# define QT_HAS_BUILTIN(x) 0
+#endif
/*
* ENDIAN FUNCTIONS
@@ -71,18 +76,29 @@ template <typename T> inline void qbswap(const T src, uchar *dest)
// Used to implement a type-safe and alignment-safe copy operation
// If you want to avoid the memcpy, you must write specializations for these functions
-template <typename T> inline void qToUnaligned(const T src, uchar *dest)
+template <typename T> Q_ALWAYS_INLINE void qToUnaligned(const T src, uchar *dest)
{
// Using sizeof(T) inside memcpy function produces internal compiler error with
// MSVC2008/ARM in tst_endian -> use extra indirection to resolve size of T.
const size_t size = sizeof(T);
- memcpy(dest, &src, size);
+#if QT_HAS_BUILTIN(__builtin_memcpy)
+ __builtin_memcpy
+#else
+ memcpy
+#endif
+ (dest, &src, size);
}
-template <typename T> inline T qFromUnaligned(const uchar *src)
+
+template <typename T> Q_ALWAYS_INLINE T qFromUnaligned(const uchar *src)
{
T dest;
const size_t size = sizeof(T);
- memcpy(&dest, src, size);
+#if QT_HAS_BUILTIN(__builtin_memcpy)
+ __builtin_memcpy
+#else
+ memcpy
+#endif
+ (&dest, src, size);
return dest;
}
diff --git a/src/corelib/global/qendian.qdoc b/src/corelib/global/qendian.qdoc
index 63d924211f..3b22dcec87 100644
--- a/src/corelib/global/qendian.qdoc
+++ b/src/corelib/global/qendian.qdoc
@@ -34,6 +34,29 @@
*/
/*!
+ \internal
+ \fn T qFromUnaligned(const uchar *ptr)
+ \since 5.5
+
+ Loads a \c{T} from address \a ptr, which may be misaligned.
+
+ Use of this function avoids the undefined behavior that the C++ standard
+ otherwise attributes to unaligned loads.
+*/
+
+/*!
+ \internal
+ \fn void qToUnaligned(T t, uchar *ptr)
+ \since 4.5
+
+ Stores \a t to address \a ptr, which may be misaligned.
+
+ Use of this function avoids the undefined behavior that the C++ standard
+ otherwise attributes to unaligned stores.
+*/
+
+
+/*!
\fn T qFromBigEndian(const uchar *src)
\since 4.3
\relates <QtEndian>
diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h
index 97f750a3a6..1e95d1a2ec 100644
--- a/src/corelib/global/qsystemdetection.h
+++ b/src/corelib/global/qsystemdetection.h
@@ -67,6 +67,7 @@
NETBSD - NetBSD
OPENBSD - OpenBSD
BSDI - BSD/OS
+ INTERIX - Interix
IRIX - SGI Irix
OSF - HP Tru64 UNIX
SCO - SCO OpenServer 5
@@ -172,6 +173,9 @@
#elif defined(__bsdi__)
# define Q_OS_BSDI
# define Q_OS_BSD4
+#elif defined(__INTERIX)
+# define Q_OS_INTERIX
+# define Q_OS_BSD4
#elif defined(__sgi)
# define Q_OS_IRIX
#elif defined(__osf__)
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index 06674e9a3f..1cb2909c2a 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -149,7 +149,6 @@ win32 {
SOURCES += io/qsettings_mac.cpp
OBJECTIVE_SOURCES += io/qurl_mac.mm
}
- freebsd: LIBS_PRIVATE += -lutil # qlockfile_unix.cpp requires this
mac {
SOURCES += io/qstorageinfo_mac.cpp
OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index 8b11830fbe..acea610625 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -58,7 +58,7 @@
# include "qfilesystemwatcher_win_p.h"
#elif defined(USE_INOTIFY)
# include "qfilesystemwatcher_inotify_p.h"
-#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_IOS)
+#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_IOS)
# include "qfilesystemwatcher_kqueue_p.h"
#elif defined(Q_OS_OSX)
# include "qfilesystemwatcher_fsevents_p.h"
@@ -74,7 +74,7 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject
// there is a chance that inotify may fail on Linux pre-2.6.13 (August
// 2005), so we can't just new inotify directly.
return QInotifyFileSystemWatcherEngine::create(parent);
-#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_IOS)
+#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_IOS)
return QKqueueFileSystemWatcherEngine::create(parent);
#elif defined(Q_OS_OSX)
return QFseventsFileSystemWatcherEngine::create(parent);
diff --git a/src/corelib/io/qfilesystemwatcher_kqueue.cpp b/src/corelib/io/qfilesystemwatcher_kqueue.cpp
index 264973d556..4f6c83ebcf 100644
--- a/src/corelib/io/qfilesystemwatcher_kqueue.cpp
+++ b/src/corelib/io/qfilesystemwatcher_kqueue.cpp
@@ -172,7 +172,6 @@ QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths
QStringList *files,
QStringList *directories)
{
- bool isEmpty;
QStringList p = paths;
if (pathToID.isEmpty())
return p;
@@ -193,7 +192,6 @@ QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths
else
files->removeAll(path);
}
- isEmpty = pathToID.isEmpty();
return p;
}
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index 03dc5fc660..e1bd769e77 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -71,14 +71,12 @@
#elif defined(Q_OS_HAIKU)
# include <kernel/OS.h>
#elif defined(Q_OS_BSD4) && !defined(Q_OS_IOS)
+# if !defined(Q_OS_NETBSD)
# include <sys/user.h>
-# if defined(__GLIBC__) && defined(__FreeBSD_kernel__)
+# endif
# include <sys/cdefs.h>
# include <sys/param.h>
# include <sys/sysctl.h>
-# else
-# include <libutil.h>
-# endif
#endif
QT_BEGIN_NAMESPACE
@@ -286,30 +284,33 @@ QString QLockFilePrivate::processNameByPid(qint64 pid)
return QString();
return QFile::decodeName(info.name);
#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));
+# if defined(Q_OS_NETBSD)
+ struct kinfo_proc2 kp;
+ int mib[6] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, (int)pid, sizeof(struct kinfo_proc2), 1 };
+# elif defined(Q_OS_OPENBSD)
+ struct kinfo_proc kp;
+ int mib[6] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid, sizeof(struct kinfo_proc), 1 };
# else
- kinfo_proc *proc = kinfo_getproc(pid);
+ struct kinfo_proc kp;
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid };
# endif
- if (!proc)
+ size_t len = sizeof(kp);
+ u_int mib_len = sizeof(mib)/sizeof(u_int);
+
+ if (sysctl(mib, mib_len, &kp, &len, NULL, 0) < 0)
return QString();
-# if defined(__GLIBC__) && defined(__FreeBSD_kernel__)
- if (sysctl(mib, 4, proc, &len, NULL, 0) < 0) {
- free(proc);
+
+# if defined(Q_OS_OPENBSD) || defined(Q_OS_NETBSD)
+ if (kp.p_pid != pid)
return QString();
- }
- if (proc->ki_pid != pid) {
- free(proc);
+ QString name = QFile::decodeName(kp.p_comm);
+# else
+ if (kp.ki_pid != pid)
return QString();
- }
+ QString name = QFile::decodeName(kp.ki_comm);
# endif
- QString name = QFile::decodeName(proc->ki_comm);
- free(proc);
return name;
+
#else
Q_UNUSED(pid);
return QString();
diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp
index 9062df37da..4afab3d135 100644
--- a/src/corelib/io/qlockfile_win.cpp
+++ b/src/corelib/io/qlockfile_win.cpp
@@ -143,9 +143,11 @@ bool QLockFilePrivate::isApparentlyStale() const
if (!procHandle)
return true;
// We got a handle but check if process is still alive
- DWORD dwR = ::WaitForSingleObject(procHandle, 0);
+ DWORD exitCode = 0;
+ if (!::GetExitCodeProcess(procHandle, &exitCode))
+ exitCode = 0;
::CloseHandle(procHandle);
- if (dwR == WAIT_TIMEOUT)
+ if (exitCode != STILL_ACTIVE)
return true;
const QString processName = processNameByPid(pid);
if (!processName.isEmpty() && processName != appname)
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index a9d3e0bfe8..914d4421d0 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -2097,10 +2097,7 @@ void QProcess::start(const QString &program, const QStringList &arguments, OpenM
return;
}
if (program.isEmpty()) {
- Q_D(QProcess);
- d->processError = QProcess::FailedToStart;
- setErrorString(tr("No program defined"));
- emit error(d->processError);
+ d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined"));
return;
}
@@ -2127,10 +2124,7 @@ void QProcess::start(OpenMode mode)
return;
}
if (d->program.isEmpty()) {
- Q_D(QProcess);
- d->processError = QProcess::FailedToStart;
- setErrorString(tr("No program defined"));
- emit error(d->processError);
+ d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined"));
return;
}
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 3a9f74bf59..0daf041954 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -84,7 +84,7 @@
# if !defined(ST_RDONLY)
# define ST_RDONLY MNT_RDONLY
# endif
-# if !defined(_STATFS_F_FLAGS)
+# if !defined(_STATFS_F_FLAGS) && !defined(Q_OS_NETBSD)
# define _STATFS_F_FLAGS 1
# endif
#elif defined(Q_OS_ANDROID)
diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp
index ab179641f8..b0ca0d979b 100644
--- a/src/corelib/io/qwindowspipewriter.cpp
+++ b/src/corelib/io/qwindowspipewriter.cpp
@@ -208,6 +208,8 @@ bool QWindowsPipeWriter::write(const QByteArray &ba)
void QWindowsPipeWriter::stop()
{
stopped = true;
+ bytesWrittenPending = false;
+ pendingBytesWrittenValue = 0;
if (writeSequenceStarted) {
if (!qt_cancelIo(handle, &overlapped)) {
const DWORD dwError = GetLastError();
diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h
index 5e34845fe3..f92a6821d7 100644
--- a/src/corelib/json/qjson_p.h
+++ b/src/corelib/json/qjson_p.h
@@ -410,7 +410,7 @@ public:
// pack with itself, we'll discard the high part anyway
chunk = _mm_packus_epi16(chunk, chunk);
// unaligned 64-bit store
- qUnalignedStore(l + i, _mm_cvtsi128_si64(chunk));
+ qToUnaligned(_mm_cvtsi128_si64(chunk), l + i);
i += 8;
}
# endif
diff --git a/src/corelib/json/qjsonvalue.cpp b/src/corelib/json/qjsonvalue.cpp
index b21f59ae35..718dfa43b3 100644
--- a/src/corelib/json/qjsonvalue.cpp
+++ b/src/corelib/json/qjsonvalue.cpp
@@ -275,25 +275,11 @@ QJsonValue::QJsonValue(const QJsonValue &other)
*/
QJsonValue &QJsonValue::operator =(const QJsonValue &other)
{
- if (t == String && stringData && !stringData->ref.deref())
- free(stringData);
-
- t = other.t;
- dbl = other.dbl;
-
- if (d != other.d) {
-
- if (d && !d->ref.deref())
- delete d;
- d = other.d;
- if (d)
- d->ref.ref();
-
- }
-
- if (t == String && stringData)
- stringData->ref.ref();
-
+ QJsonValue copy(other);
+ // swap(copy);
+ qSwap(dbl, copy.dbl);
+ qSwap(d, copy.d);
+ qSwap(t, copy.t);
return *this;
}
diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp
index 93af957d95..2042964427 100644
--- a/src/corelib/kernel/qcore_unix.cpp
+++ b/src/corelib/kernel/qcore_unix.cpp
@@ -41,16 +41,6 @@
#include "qcore_unix_p.h"
#include "qelapsedtimer.h"
-#ifdef Q_OS_NACL
-#elif !defined (Q_OS_VXWORKS)
-# if !defined(Q_OS_HPUX) || defined(__ia64)
-# include <sys/select.h>
-# endif
-# include <sys/time.h>
-#else
-# include <selectLib.h>
-#endif
-
#include <stdlib.h>
#ifdef Q_OS_MAC
diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h
index 319914a99d..53f2a50191 100644
--- a/src/corelib/kernel/qcore_unix_p.h
+++ b/src/corelib/kernel/qcore_unix_p.h
@@ -65,6 +65,16 @@
#include <sys/stat.h>
#include <unistd.h>
+#ifdef Q_OS_NACL
+#elif !defined (Q_OS_VXWORKS)
+# if !defined(Q_OS_HPUX) || defined(__ia64)
+# include <sys/select.h>
+# endif
+# include <sys/time.h>
+#else
+# include <selectLib.h>
+#endif
+
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 9b421d6a78..ffb50ddac3 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -4699,7 +4699,7 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s
QOrderedMutexLocker locker(signalSlotLock(sender),
signalSlotLock(receiver));
- if (type & Qt::UniqueConnection) {
+ if (type & Qt::UniqueConnection && slot) {
QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
if (connectionLists && connectionLists->count() > signal_index) {
const QObjectPrivate::Connection *c2 =
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index e99c8f35f3..c06f702b30 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -419,8 +419,7 @@ protected:
QScopedPointer<QObjectData> d_ptr;
static const QMetaObject staticQtMetaObject;
- friend inline const QMetaObject *qt_getQtMetaObject() Q_DECL_NOEXCEPT
- { return &staticQtMetaObject; }
+ friend inline const QMetaObject *qt_getQtMetaObject() Q_DECL_NOEXCEPT;
friend struct QMetaObject;
friend struct QMetaObjectPrivate;
@@ -451,6 +450,9 @@ inline QMetaObject::Connection QObject::connect(const QObject *asender, const ch
const char *amember, Qt::ConnectionType atype) const
{ return connect(asender, asignal, this, amember, atype); }
+inline const QMetaObject *qt_getQtMetaObject() Q_DECL_NOEXCEPT
+{ return &QObject::staticQtMetaObject; }
+
#ifndef QT_NO_USERDATA
class Q_CORE_EXPORT QObjectUserData {
public:
diff --git a/src/corelib/mimetypes/qmimemagicrule.cpp b/src/corelib/mimetypes/qmimemagicrule.cpp
index 0db3407b7b..8461bf7130 100644
--- a/src/corelib/mimetypes/qmimemagicrule.cpp
+++ b/src/corelib/mimetypes/qmimemagicrule.cpp
@@ -48,7 +48,6 @@
#include <QtCore/QList>
#include <QtCore/QDebug>
#include <qendian.h>
-#include <private/qsimd_p.h> // for qUnalignedLoad
QT_BEGIN_NAMESPACE
@@ -164,7 +163,7 @@ bool QMimeMagicRule::matchNumber(const QByteArray &data) const
const char *p = data.constData() + m_startPos;
const char *e = data.constData() + qMin(data.size() - int(sizeof(T)), m_endPos + 1);
for ( ; p <= e; ++p) {
- if ((qUnalignedLoad<T>(p) & mask) == (value & mask))
+ if ((qFromUnaligned<T>(reinterpret_cast<const uchar *>(p)) & mask) == (value & mask))
return true;
}
diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp
index 446e09b1c0..12e4687b3c 100644
--- a/src/corelib/tools/qbitarray.cpp
+++ b/src/corelib/tools/qbitarray.cpp
@@ -42,6 +42,7 @@
#include <qalgorithms.h>
#include <qdatastream.h>
#include <qdebug.h>
+#include <qendian.h>
#include <string.h>
QT_BEGIN_NAMESPACE
@@ -169,25 +170,6 @@ QBitArray::QBitArray(int size, bool value)
Same as size().
*/
-template <typename T> T qUnalignedLoad(const uchar *ptr)
-{
- /*
- * Testing with different compilers shows that they all optimize the memcpy
- * call away and replace with direct loads whenever possible. On x86 and PPC,
- * GCC does direct unaligned loads; on MIPS, it generates a pair of load-left
- * and load-right instructions. ICC and Clang do the same on x86. This is both
- * 32- and 64-bit.
- *
- * On ARM cores without unaligned loads, the compiler leaves a call to
- * memcpy.
- */
-
- T u;
- memcpy(&u, ptr, sizeof(u));
- return u;
-}
-
-
/*!
If \a on is true, this function returns the number of
1-bits stored in the bit array; otherwise the number
@@ -203,17 +185,17 @@ int QBitArray::count(bool on) const
const quint8 *const end = reinterpret_cast<const quint8 *>(d.end());
while (bits + 7 <= end) {
- quint64 v = qUnalignedLoad<quint64>(bits);
+ quint64 v = qFromUnaligned<quint64>(bits);
bits += 8;
numBits += int(qPopulationCount(v));
}
if (bits + 3 <= end) {
- quint32 v = qUnalignedLoad<quint32>(bits);
+ quint32 v = qFromUnaligned<quint32>(bits);
bits += 4;
numBits += int(qPopulationCount(v));
}
if (bits + 1 < end) {
- quint16 v = qUnalignedLoad<quint16>(bits);
+ quint16 v = qFromUnaligned<quint16>(bits);
bits += 2;
numBits += int(qPopulationCount(v));
}
diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp
index 3cb3606013..08f89d2f02 100644
--- a/src/corelib/tools/qcryptographichash.cpp
+++ b/src/corelib/tools/qcryptographichash.cpp
@@ -95,9 +95,29 @@ static SHA3Final * const sha3Final = Final;
available on all platforms (MSVC 2008, for example), we #define them to the
Qt equivalents.
*/
+
+#ifdef uint64_t
+#undef uint64_t
+#endif
+
#define uint64_t QT_PREPEND_NAMESPACE(quint64)
+
+#ifdef uint32_t
+#undef uint32_t
+#endif
+
#define uint32_t QT_PREPEND_NAMESPACE(quint32)
+
+#ifdef uint8_t
+#undef uint8_t
+#endif
+
#define uint8_t QT_PREPEND_NAMESPACE(quint8)
+
+#ifdef int_least16_t
+#undef int_least16_t
+#endif
+
#define int_least16_t QT_PREPEND_NAMESPACE(qint16)
// Header from rfc6234 with 1 modification:
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index e18c220884..6750925853 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -2180,7 +2180,7 @@ static int qt_timezone()
// number of seconds west of UTC.
// - It also takes DST into account, so we need to adjust it to always
// get the Standard Time offset.
- return -t.tm_gmtoff + (t.tm_isdst ? SECS_PER_HOUR : 0L);
+ return -t.tm_gmtoff + (t.tm_isdst ? (long)SECS_PER_HOUR : 0L);
#elif defined(Q_OS_INTEGRITY)
return 0;
#else
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index 2f0886edce..593a87e65d 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -58,6 +58,7 @@
#include <qbytearray.h>
#include <qdatetime.h>
#include <qbasicatomic.h>
+#include <qendian.h>
#include <private/qsimd_p.h>
#ifndef QT_BOOTSTRAPPED
@@ -112,24 +113,24 @@ static uint crc32(const Char *ptr, size_t len, uint h)
p += 8;
for ( ; p <= e; p += 8)
- h2 = _mm_crc32_u64(h2, qUnalignedLoad<qlonglong>(p - 8));
+ h2 = _mm_crc32_u64(h2, qFromUnaligned<qlonglong>(p - 8));
h = h2;
p -= 8;
len = e - p;
if (len & 4) {
- h = _mm_crc32_u32(h, qUnalignedLoad<uint>(p));
+ h = _mm_crc32_u32(h, qFromUnaligned<uint>(p));
p += 4;
}
# else
p += 4;
for ( ; p <= e; p += 4)
- h = _mm_crc32_u32(h, qUnalignedLoad<uint>(p - 4));
+ h = _mm_crc32_u32(h, qFromUnaligned<uint>(p - 4));
p -= 4;
len = e - p;
# endif
if (len & 2) {
- h = _mm_crc32_u16(h, qUnalignedLoad<ushort>(p));
+ h = _mm_crc32_u16(h, qFromUnaligned<ushort>(p));
p += 2;
}
if (sizeof(Char) == 1 && len & 1)
diff --git a/src/corelib/tools/qmessageauthenticationcode.cpp b/src/corelib/tools/qmessageauthenticationcode.cpp
index 9b91474283..9a84191452 100644
--- a/src/corelib/tools/qmessageauthenticationcode.cpp
+++ b/src/corelib/tools/qmessageauthenticationcode.cpp
@@ -46,9 +46,29 @@
available on all platforms (MSVC 2008, for example), we #define them to the
Qt equivalents.
*/
+
+#ifdef uint64_t
+#undef uint64_t
+#endif
+
#define uint64_t QT_PREPEND_NAMESPACE(quint64)
+
+#ifdef uint32_t
+#undef uint32_t
+#endif
+
#define uint32_t QT_PREPEND_NAMESPACE(quint32)
+
+#ifdef uint8_t
+#undef uint8_t
+#endif
+
#define uint8_t QT_PREPEND_NAMESPACE(quint8)
+
+#ifdef int_least16_t
+#undef int_least16_t
+#endif
+
#define int_least16_t QT_PREPEND_NAMESPACE(qint16)
// Header from rfc6234 with 1 modification:
diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp
index 3a5f0f18a1..c869c4e089 100644
--- a/src/corelib/tools/qsimd.cpp
+++ b/src/corelib/tools/qsimd.cpp
@@ -751,26 +751,4 @@ void qDumpCPUFeatures()
puts("");
}
-/*!
- \internal
- \fn T qUnalignedLoad(const void *ptr)
- \since 5.6.1
-
- Loads a \c{T} from address \a ptr, which may be misaligned.
-
- Use of this function avoid the undefined behavior that the C++ standard
- otherwise attributes to unaligned loads.
-*/
-
-/*!
- \internal
- \fn void qUnalignedStore(void *ptr, T t)
- \since 5.6.1
-
- Stores \a t to address \a ptr, which may be misaligned.
-
- Use of this function avoid the undefined behavior that the C++ standard
- otherwise attributes to unaligned stores.
-*/
-
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 9f968978dc..940fd5817b 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -584,7 +584,7 @@ static int ucstrncmp(const QChar *a, const uchar *c, int l)
// we'll read uc[offset..offset+7] (16 bytes) and c[offset..offset+7] (8 bytes)
if (uc + offset + 7 < e) {
// same, but we're using an 8-byte load
- __m128i chunk = _mm_cvtsi64_si128(qUnalignedLoad<long long>(c + offset));
+ __m128i chunk = _mm_cvtsi64_si128(qFromUnaligned<long long>(c + offset));
__m128i secondHalf = _mm_unpacklo_epi8(chunk, nullmask);
__m128i ucdata = _mm_loadu_si128((const __m128i*)(uc + offset));
diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp
index 8040365581..c2630c8593 100644
--- a/src/corelib/tools/qtimezoneprivate_tz.cpp
+++ b/src/corelib/tools/qtimezoneprivate_tz.cpp
@@ -47,6 +47,8 @@
#include <qdebug.h>
+#include "qlocale_tools_p.h"
+
#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -376,39 +378,126 @@ static QDate calculatePosixDate(const QByteArray &dateRule, int year)
}
}
-static QTime parsePosixTime(const QByteArray &timeRule)
+// returns the time in seconds, INT_MIN if we failed to parse
+static int parsePosixTime(const char *begin, const char *end)
{
- // Format "HH:mm:ss", put check parts count just in case
- QList<QByteArray> parts = timeRule.split(':');
- int count = parts.count();
- if (count == 3)
- return QTime(parts.at(0).toInt(), parts.at(1).toInt(), parts.at(2).toInt());
- else if (count == 2)
- return QTime(parts.at(0).toInt(), parts.at(1).toInt(), 0);
- else if (count == 1)
- return QTime(parts.at(0).toInt(), 0, 0);
- return QTime(2, 0, 0);
+ // Format "hh[:mm[:ss]]"
+ int hour, min = 0, sec = 0;
+
+ // Note that the calls to qstrtoll do *not* check the end pointer, which
+ // means they proceed until they find a non-digit. We check that we're
+ // still in range at the end, but we may have read from past end. It's the
+ // caller's responsibility to ensure that begin is part of a
+ // null-terminated string.
+
+ bool ok = false;
+ hour = qstrtoll(begin, &begin, 10, &ok);
+ if (!ok || hour < 0)
+ return INT_MIN;
+ if (begin < end && *begin == ':') {
+ // minutes
+ ++begin;
+ min = qstrtoll(begin, &begin, 10, &ok);
+ if (!ok || min < 0)
+ return INT_MIN;
+
+ if (begin < end && *begin == ':') {
+ // seconds
+ ++begin;
+ sec = qstrtoll(begin, &begin, 10, &ok);
+ if (!ok || sec < 0)
+ return INT_MIN;
+ }
+ }
+
+ // we must have consumed everything
+ if (begin != end)
+ return INT_MIN;
+
+ return (hour * 60 + min) * 60 + sec;
}
-static int parsePosixOffset(const QByteArray &timeRule)
+static QTime parsePosixTransitionTime(const QByteArray &timeRule)
+{
+ // Format "hh[:mm[:ss]]"
+ int value = parsePosixTime(timeRule.constBegin(), timeRule.constEnd());
+ if (value == INT_MIN) {
+ // if we failed to parse, return 02:00
+ return QTime(2, 0, 0);
+ }
+ return QTime::fromMSecsSinceStartOfDay(value * 1000);
+}
+
+static int parsePosixOffset(const char *begin, const char *end)
{
// Format "[+|-]hh[:mm[:ss]]"
- QList<QByteArray> parts = timeRule.split(':');
- int count = parts.count();
- if (count == 3) {
- int hour = parts.at(0).toInt();
- int sign = hour >= 0 ? -1 : 1;
- return sign * ((qAbs(hour) * 60 * 60) + (parts.at(1).toInt() * 60) + parts.at(2).toInt());
- } else if (count == 2) {
- int hour = parts.at(0).toInt();
- int sign = hour >= 0 ? -1 : 1;
- return sign * ((qAbs(hour) * 60 * 60) + (parts.at(1).toInt() * 60));
- } else if (count == 1) {
- int hour = parts.at(0).toInt();
- int sign = hour >= 0 ? -1 : 1;
- return sign * (qAbs(hour) * 60 * 60);
- }
- return 0;
+ // note that the sign is inverted because POSIX counts in hours West of GMT
+ bool negate = true;
+ if (*begin == '+') {
+ ++begin;
+ } else if (*begin == '-') {
+ negate = false;
+ ++begin;
+ }
+
+ int value = parsePosixTime(begin, end);
+ if (value == INT_MIN)
+ return value;
+ return negate ? -value : value;
+}
+
+static inline bool asciiIsLetter(char ch)
+{
+ ch |= 0x20; // lowercases if it is a letter, otherwise just corrupts ch
+ return ch >= 'a' && ch <= 'z';
+}
+
+// Returns the zone name, the offset (in seconds) and advances \a begin to
+// where the parsing ended. Returns a zone of INT_MIN in case an offset
+// couldn't be read.
+static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const char *end)
+{
+ static const char offsetChars[] = "0123456789:";
+ QPair<QString, int> result = qMakePair(QString(), INT_MIN);
+
+ const char *nameBegin = pos;
+ const char *nameEnd;
+ Q_ASSERT(pos < end);
+
+ if (*pos == '<') {
+ nameBegin = pos + 1; // skip the '<'
+ nameEnd = nameBegin;
+ while (nameEnd < end && *nameEnd != '>') {
+ // POSIX says only alphanumeric, but we allow anything
+ ++nameEnd;
+ }
+ pos = nameEnd + 1; // skip the '>'
+ } else {
+ nameBegin = pos;
+ nameEnd = nameBegin;
+ while (nameEnd < end && asciiIsLetter(*nameEnd))
+ ++nameEnd;
+ pos = nameEnd;
+ }
+ if (nameEnd - nameBegin < 3)
+ return result; // name must be at least 3 characters long
+
+ // zone offset, form [+-]hh:mm:ss
+ const char *zoneBegin = pos;
+ const char *zoneEnd = pos;
+ if (zoneEnd < end && (zoneEnd[0] == '+' || zoneEnd[0] == '-'))
+ ++zoneEnd;
+ while (zoneEnd < end) {
+ if (strchr(offsetChars, char(*zoneEnd)) == NULL)
+ break;
+ ++zoneEnd;
+ }
+
+ result.first = QString::fromUtf8(nameBegin, nameEnd - nameBegin);
+ if (zoneEnd > zoneBegin)
+ result.second = parsePosixOffset(zoneBegin, zoneEnd);
+ pos = zoneEnd;
+ return result;
}
static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule,
@@ -425,58 +514,45 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
// POSIX Format is like "TZ=CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00"
// i.e. "std offset dst [offset],start[/time],end[/time]"
- // See http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
+ // See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
QList<QByteArray> parts = posixRule.split(',');
- QString name = QString::fromUtf8(parts.at(0));
- QString stdName;
- QString stdOffsetString;
- QString dstName;
- QString dstOffsetString;
- bool parsedStdName = false;
- bool parsedStdOffset = false;
- for (int i = 0; i < name.size(); ++i) {
- if (name.at(i).isLetter()) {
- if (parsedStdName) {
- parsedStdOffset = true;
- dstName.append(name.at(i));
- } else {
- stdName.append(name.at(i));
+ QPair<QString, int> stdZone, dstZone;
+ {
+ const QByteArray &zoneinfo = parts.at(0);
+ const char *begin = zoneinfo.constBegin();
+
+ stdZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());
+ if (stdZone.second == INT_MIN) {
+ stdZone.second = 0; // reset to UTC if we failed to parse
+ } else if (begin < zoneinfo.constEnd()) {
+ dstZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());
+ if (dstZone.second == INT_MIN) {
+ // if the dst offset isn't provided, it is 1 hour ahead of the standard offset
+ dstZone.second = stdZone.second + (60 * 60);
}
- } else {
- parsedStdName = true;
- if (parsedStdOffset)
- dstOffsetString.append(name.at(i));
- else
- stdOffsetString.append(name.at(i));
}
}
- int utcOffset = parsePosixOffset(stdOffsetString.toUtf8());
-
// If only the name part then no transitions
if (parts.count() == 1) {
QTimeZonePrivate::Data data;
data.atMSecsSinceEpoch = lastTranMSecs;
- data.offsetFromUtc = utcOffset;
- data.standardTimeOffset = utcOffset;
+ data.offsetFromUtc = stdZone.second;
+ data.standardTimeOffset = stdZone.second;
data.daylightTimeOffset = 0;
- data.abbreviation = stdName;
+ data.abbreviation = stdZone.first;
result << data;
return result;
}
- // If not populated the total dst offset is 1 hour
- int dstOffset = utcOffset + (60 * 60);
- if (!dstOffsetString.isEmpty())
- dstOffset = parsePosixOffset(dstOffsetString.toUtf8());
// Get the std to dst transtion details
QList<QByteArray> dstParts = parts.at(1).split('/');
QByteArray dstDateRule = dstParts.at(0);
QTime dstTime;
if (dstParts.count() > 1)
- dstTime = parsePosixTime(dstParts.at(1));
+ dstTime = parsePosixTransitionTime(dstParts.at(1));
else
dstTime = QTime(2, 0, 0);
@@ -485,25 +561,25 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
QByteArray stdDateRule = stdParts.at(0);
QTime stdTime;
if (stdParts.count() > 1)
- stdTime = parsePosixTime(stdParts.at(1));
+ stdTime = parsePosixTransitionTime(stdParts.at(1));
else
stdTime = QTime(2, 0, 0);
for (int year = startYear; year <= endYear; ++year) {
QTimeZonePrivate::Data dstData;
QDateTime dst(calculatePosixDate(dstDateRule, year), dstTime, Qt::UTC);
- dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (utcOffset * 1000);
- dstData.offsetFromUtc = dstOffset;
- dstData.standardTimeOffset = utcOffset;
- dstData.daylightTimeOffset = dstOffset - utcOffset;
- dstData.abbreviation = dstName;
+ dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.second * 1000);
+ dstData.offsetFromUtc = dstZone.second;
+ dstData.standardTimeOffset = stdZone.second;
+ dstData.daylightTimeOffset = dstZone.second - stdZone.second;
+ dstData.abbreviation = dstZone.first;
QTimeZonePrivate::Data stdData;
QDateTime std(calculatePosixDate(stdDateRule, year), stdTime, Qt::UTC);
- stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstOffset * 1000);
- stdData.offsetFromUtc = utcOffset;
- stdData.standardTimeOffset = utcOffset;
+ stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.second * 1000);
+ stdData.offsetFromUtc = stdZone.second;
+ stdData.standardTimeOffset = stdZone.second;
stdData.daylightTimeOffset = 0;
- stdData.abbreviation = stdName;
+ stdData.abbreviation = stdZone.first;
// Part of the high year will overflow
if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) {
if (dstData.atMSecsSinceEpoch > 0) {
diff --git a/src/gui/doc/snippets/code/src_gui_kernel_qclipboard.cpp b/src/gui/doc/snippets/code/src_gui_kernel_qclipboard.cpp
index d5f610cf28..8581510133 100644
--- a/src/gui/doc/snippets/code/src_gui_kernel_qclipboard.cpp
+++ b/src/gui/doc/snippets/code/src_gui_kernel_qclipboard.cpp
@@ -49,7 +49,7 @@
****************************************************************************/
//! [0]
-QClipboard *clipboard = QApplication::clipboard();
+QClipboard *clipboard = QGuiApplication::clipboard();
QString originalText = clipboard->text();
...
clipboard->setText(newText);
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
index b8290861af..9545abfd21 100644
--- a/src/gui/image/qbmphandler.cpp
+++ b/src/gui/image/qbmphandler.cpp
@@ -289,6 +289,12 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
format = QImage::Format_Mono;
}
+ if (depth != 32) {
+ ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits;
+ if (ncols < 1 || ncols > 256) // sanity check - don't run out of mem if color table is broken
+ return false;
+ }
+
if (bi.biHeight < 0)
h = -h; // support images with negative height
@@ -296,19 +302,15 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
image = QImage(w, h, format);
if (image.isNull()) // could not create image
return false;
- }
-
- if (depth != 32) {
- ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits;
- if (ncols < 1 || ncols > 256) // sanity check - don't run out of mem if color table is broken
- return false;
- image.setColorCount(ncols);
+ if (ncols)
+ image.setColorCount(ncols); // Ensure valid QImage
}
image.setDotsPerMeterX(bi.biXPelsPerMeter);
image.setDotsPerMeterY(bi.biYPelsPerMeter);
if (ncols > 0) { // read color table
+ image.setColorCount(ncols);
uchar rgb[4];
int rgb_len = t == BMP_OLD ? 3 : 4;
for (int i=0; i<ncols; i++) {
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 82ad9b1738..36595025f5 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -176,6 +176,9 @@ QImageData::~QImageData()
data = 0;
}
+#if defined(_M_ARM)
+#pragma optimize("", off)
+#endif
bool QImageData::checkForAlphaPixels() const
{
@@ -290,6 +293,9 @@ bool QImageData::checkForAlphaPixels() const
return has_alpha_pixels;
}
+#if defined(_M_ARM)
+#pragma optimize("", on)
+#endif
/*!
\class QImage
diff --git a/src/gui/kernel/qclipboard.cpp b/src/gui/kernel/qclipboard.cpp
index e5e268ace3..21dbdadcf8 100644
--- a/src/gui/kernel/qclipboard.cpp
+++ b/src/gui/kernel/qclipboard.cpp
@@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
Drop}.
There is a single QClipboard object in an application, accessible
- as QApplication::clipboard().
+ as QGuiApplication::clipboard().
Example:
\snippet code/src_gui_kernel_qclipboard.cpp 0
@@ -137,7 +137,7 @@ QT_BEGIN_NAMESPACE
\endlist
- \sa QApplication
+ \sa QGuiApplication
*/
/*!
@@ -147,7 +147,7 @@ QT_BEGIN_NAMESPACE
Do not call this function.
- Call QApplication::clipboard() instead to get a pointer to the
+ Call QGuiApplication::clipboard() instead to get a pointer to the
application's global clipboard object.
There is only one clipboard in the window system, and creating
@@ -165,7 +165,7 @@ QClipboard::QClipboard(QObject *parent)
Destroys the clipboard.
- You should never delete the clipboard. QApplication will do this
+ You should never delete the clipboard. QGuiApplication will do this
when the application terminates.
*/
QClipboard::~QClipboard()
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 9cad9e0a1d..2c5e0672b1 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -2186,11 +2186,10 @@ void QPainter::setBrushOrigin(const QPointF &p)
destination pixel in such a way that the alpha component of the
source defines the translucency of the pixel.
- When the paint device is a QImage, the image format must be set to
- \l {QImage::Format}{Format_ARGB32_Premultiplied} or
- \l {QImage::Format}{Format_ARGB32} for the composition modes to have
- any effect. For performance the premultiplied version is the preferred
- format.
+ Several composition modes require an alpha channel in the source or
+ target images to have an effect. For optimal performance the
+ image format \l {QImage::Format}{Format_ARGB32_Premultiplied} is
+ preferred.
When a composition mode is set it applies to all painting
operator, pens, brushes, gradients and pixmap/image drawing.
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 9b50581bea..22df0eda30 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -2732,8 +2732,7 @@ void QFontDatabase::load(const QFontPrivate *d, int script)
}
if (req.pointSize < 0)
req.pointSize = req.pixelSize*72.0/d->dpi;
- if (req.weight == 0)
- req.weight = QFont::Normal;
+ req.weight = QFont::Normal;
if (req.stretch == 0)
req.stretch = 100;
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 74317e99c3..fe5d544dba 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -1833,8 +1833,7 @@ QFontEngine *QFontEngineMulti::loadEngine(int at)
request.family = fallbackFamilyAt(at - 1);
if (QFontEngine *engine = QFontDatabase::findFont(request, m_script)) {
- if (request.weight > QFont::Normal)
- engine->fontDef.weight = request.weight;
+ engine->fontDef.weight = request.weight;
if (request.style > QFont::StyleNormal)
engine->fontDef.style = request.style;
return engine;
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 7ee02b71c9..28fb9d2769 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -1645,8 +1645,14 @@ void QTextEngine::itemize() const
if (analysis->bidiLevel % 2)
--analysis->bidiLevel;
analysis->flags = QScriptAnalysis::LineOrParagraphSeparator;
- if (option.flags() & QTextOption::ShowLineAndParagraphSeparators)
+ if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) {
+ const int offset = uc - string;
+ layoutData->string.detach();
+ string = reinterpret_cast<const ushort *>(layoutData->string.unicode());
+ uc = string + offset;
+ e = uc + length;
*const_cast<ushort*>(uc) = 0x21B5; // visual line separator
+ }
break;
case QChar::Tabulation:
analysis->flags = QScriptAnalysis::Tab;
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 402bd75a76..2109b15a85 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -364,9 +364,10 @@ void QTextFormatPrivate::recalcFont() const
f.setPixelSize(props.at(i).value.toInt());
break;
case QTextFormat::FontWeight: {
- int weight = props.at(i).value.toInt();
- if (weight == 0) weight = QFont::Normal;
- f.setWeight(weight);
+ const QVariant weightValue = props.at(i).value;
+ int weight = weightValue.toInt();
+ if (weight >= 0 && weightValue.isValid())
+ f.setWeight(weight);
break; }
case QTextFormat::FontItalic:
f.setItalic(props.at(i).value.toBool());
diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h
index bc627521ff..805affd87c 100644
--- a/src/gui/text/qtextformat.h
+++ b/src/gui/text/qtextformat.h
@@ -431,9 +431,9 @@ public:
{ return doubleProperty(FontPointSize); }
inline void setFontWeight(int weight)
- { if (weight == QFont::Normal) weight = 0; setProperty(FontWeight, weight); }
+ { setProperty(FontWeight, weight); }
inline int fontWeight() const
- { int weight = intProperty(FontWeight); if (weight == 0) weight = QFont::Normal; return weight; }
+ { return hasProperty(FontWeight) ? intProperty(FontWeight) : QFont::Normal; }
inline void setFontItalic(bool italic)
{ setProperty(FontItalic, italic); }
inline bool fontItalic() const
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index 42c7c80f3b..38e9c25269 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -72,14 +72,4 @@ SOURCES += \
mac: LIBS_PRIVATE += -framework Security
-ios {
- HEADERS += \
- access/qnetworkreplynsurlconnectionimpl_p.h
-
- OBJECTIVE_SOURCES += \
- access/qnetworkreplynsurlconnectionimpl.mm
-
- LIBS_PRIVATE += -framework Foundation
-}
-
include($$PWD/../../3rdparty/zlib_dependency.pri)
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 56716cbe01..2f7be01078 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -331,7 +331,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
priv->phase = QAuthenticatorPrivate::Start;
QString connectHost = connection->d_func()->hostName;
- qint16 connectPort = connection->d_func()->port;
+ quint16 connectPort = connection->d_func()->port;
#ifndef QT_NO_NETWORKPROXY
// HTTPS always use transparent proxy.
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 927e103abc..587ab27a0f 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -56,10 +56,6 @@
#include "qnetworkreplydataimpl_p.h"
#include "qnetworkreplyfileimpl_p.h"
-#if defined(Q_OS_IOS) && defined(QT_NO_SSL)
-#include "qnetworkreplynsurlconnectionimpl_p.h"
-#endif
-
#include "QtCore/qbuffer.h"
#include "QtCore/qurl.h"
#include "QtCore/qvector.h"
@@ -1207,12 +1203,6 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
}
}
-// Use NSURLConnection for https on iOS when OpenSSL is disabled.
-#if defined(Q_OS_IOS) && defined(QT_NO_SSL)
- if (scheme == QLatin1String("https"))
- return new QNetworkReplyNSURLConnectionImpl(this, request, op, outgoingData);
-#endif
-
#ifndef QT_NO_HTTP
// Since Qt 5 we use the new QNetworkReplyHttpImpl
if (scheme == QLatin1String("http") || scheme == QLatin1String("preconnect-http")
diff --git a/src/network/access/qnetworkreplynsurlconnectionimpl.mm b/src/network/access/qnetworkreplynsurlconnectionimpl.mm
deleted file mode 100644
index 58a3ba1448..0000000000
--- a/src/network/access/qnetworkreplynsurlconnectionimpl.mm
+++ /dev/null
@@ -1,458 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qnetworkreplynsurlconnectionimpl_p.h"
-
-#include "QtCore/qdatetime.h"
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <Foundation/Foundation.h>
-
-QT_BEGIN_NAMESPACE
-
-// Network reply implementation using NSUrlConnection.
-//
-// Class/object structure:
-//
-// QNetworkReplyNSURLConnectionImpl
-// |- QNetworkReplyNSURLConnectionImplPrivate
-// |- (bytes read)
-// |- (QIODevice and CFStream for async POST data transfer)
-// |- NSURLConnection
-// |- QtNSURLConnectionDelegate <NSURLConnectionDataDelegate>
-// |- NSURLResponse/NSHTTPURLResponse
-// |- (response data)
-//
-// The main entry point is the QNetworkReplyNSURLConnectionImpl constructor, which
-// receives a network request from QNetworkAccessManager. The constructor
-// creates a NSURLRequest and initiates a NSURLConnection with a QtNSURLConnectionDelegate.
-// The delegate callbacks are then called asynchronously as the request completes.
-//
-
-@class QtNSURLConnectionDelegate;
-class QNetworkReplyNSURLConnectionImplPrivate: public QNetworkReplyPrivate
-{
-public:
- QNetworkReplyNSURLConnectionImplPrivate();
- virtual ~QNetworkReplyNSURLConnectionImplPrivate();
-
- Q_DECLARE_PUBLIC(QNetworkReplyNSURLConnectionImpl)
- NSURLConnection * urlConnection;
- QtNSURLConnectionDelegate *urlConnectionDelegate;
- qint64 bytesRead;
-
- // Sequental outgiong data streaming
- QIODevice *outgoingData;
- CFReadStreamRef readStream;
- CFWriteStreamRef writeStream;
- CFIndex transferBufferSize;
-
- // Forwarding functions to the public class.
- void setFinished();
- void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
- void setRawHeader(const QByteArray &headerName, const QByteArray &value);
- void setError(QNetworkReply::NetworkError errorCode, const QString &errorString);
- void setAttribute(QNetworkRequest::Attribute code, const QVariant &value);
-};
-
-@interface QtNSURLConnectionDelegate : NSObject
-{
- NSURLResponse *response;
- NSMutableData *responseData;
- QNetworkReplyNSURLConnectionImplPrivate * replyprivate;
-}
-
-- (id)initWithQNetworkReplyNSURLConnectionImplPrivate:(QNetworkReplyNSURLConnectionImplPrivate *)a_replyPrivate ;
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_3_0)
-- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
-#endif
-- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError*)error;
-- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response;
-- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data;
-- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten
- totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
-- (NSCachedURLResponse*)connection:(NSURLConnection*)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse;
-- (NSURLRequest*)connection:(NSURLConnection*)connection willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectResponse;
-- (void)connectionDidFinishLoading:(NSURLConnection*)connection;
-- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection*)connection;
-
-@end
-
-QNetworkReplyNSURLConnectionImplPrivate::QNetworkReplyNSURLConnectionImplPrivate()
- : QNetworkReplyPrivate()
- , urlConnection(0)
- , urlConnectionDelegate(0)
- , bytesRead(0)
- , readStream(0)
- , writeStream(0)
- , transferBufferSize(4096)
-{
-}
-
-QNetworkReplyNSURLConnectionImplPrivate::~QNetworkReplyNSURLConnectionImplPrivate()
-{
- [urlConnection cancel];
- [urlConnection release];
- [urlConnectionDelegate release];
- if (readStream)
- CFRelease(readStream);
- if (writeStream)
- CFRelease(writeStream);
-}
-
-void QNetworkReplyNSURLConnectionImplPrivate::setFinished()
-{
- q_func()->setFinished(true);
- QMetaObject::invokeMethod(q_func(), "finished", Qt::QueuedConnection);
-}
-
-void QNetworkReplyNSURLConnectionImplPrivate::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
-{
- q_func()->setHeader(header, value);
-}
-
-void QNetworkReplyNSURLConnectionImplPrivate::setRawHeader(const QByteArray &headerName, const QByteArray &value)
-{
- q_func()->setRawHeader(headerName, value);
-}
-
-void QNetworkReplyNSURLConnectionImplPrivate::setError(QNetworkReply::NetworkError errorCode, const QString &errorString)
-{
- q_func()->setError(errorCode, errorString);
-}
-
-void QNetworkReplyNSURLConnectionImplPrivate::setAttribute(QNetworkRequest::Attribute code, const QVariant &value)
-{
- q_func()->setAttribute(code, value);
-}
-
-void QNetworkReplyNSURLConnectionImpl::readyReadOutgoingData()
-{
- Q_D(QNetworkReplyNSURLConnectionImpl);
- int bytesRead = 0;
- do {
- char data[d->transferBufferSize];
- bytesRead = d->outgoingData->read(data, d->transferBufferSize);
- if (bytesRead <= 0)
- break;
- CFIndex bytesWritten = CFWriteStreamWrite(d->writeStream, reinterpret_cast<unsigned char *>(data), bytesRead);
- if (bytesWritten != bytesRead) {
- CFErrorRef err = CFWriteStreamCopyError(d->writeStream);
- qWarning() << "QNetworkReplyNSURLConnectionImpl: CFWriteStreamWrite error"
- << (err ? QString::number(CFErrorGetCode(err)) : QStringLiteral(""));
- }
- } while (bytesRead > 0);
-
- if (d->outgoingData->atEnd())
- CFWriteStreamClose(d->writeStream);
-}
-
-@interface QtNSURLConnectionDelegate ()
-
-@property (nonatomic, retain) NSURLResponse* response;
-@property (nonatomic, retain) NSMutableData* responseData;
-
-@end
-
-@implementation QtNSURLConnectionDelegate
-
-@synthesize response;
-@synthesize responseData;
-
-- (id)initWithQNetworkReplyNSURLConnectionImplPrivate:(QNetworkReplyNSURLConnectionImplPrivate *)a_replyPrivate
-{
- if (self = [super init])
- replyprivate = a_replyPrivate;
- return self;
-}
-
-- (void)dealloc
-{
- [response release];
- [responseData release];
- [super dealloc];
-}
-
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_3_0)
-- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
-{
- Q_UNUSED(connection)
- Q_UNUSED(challenge)
-
- if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
- SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
- SecTrustResultType resultType;
- SecTrustEvaluate(serverTrust, &resultType);
- if (resultType == kSecTrustResultUnspecified) {
- // All good
- [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
- } else if (resultType == kSecTrustResultRecoverableTrustFailure) {
- // Certificate verification error, ask user
- // ### TODO actually ask user
- // (test site: https://testssl-expire.disig.sk/index.en.html)
- qWarning() << "QNetworkReplyNSURLConnection: Certificate verification error handlig is"
- << "not implemented. Connection will time out.";
- } else {
- // other error, which the default handler will handle
- [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
- }
- }
-
- [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
-}
-#endif
-
-- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
-{
- Q_UNUSED(connection)
-
- QNetworkReply::NetworkError qtError = QNetworkReply::UnknownNetworkError;
- if ([[error domain] isEqualToString:NSURLErrorDomain]) {
- switch ([error code]) {
- case NSURLErrorTimedOut: qtError = QNetworkReply::TimeoutError; break;
- case NSURLErrorUnsupportedURL: qtError = QNetworkReply::ProtocolUnknownError; break;
- case NSURLErrorCannotFindHost: qtError = QNetworkReply::HostNotFoundError; break;
- case NSURLErrorCannotConnectToHost: qtError = QNetworkReply::ConnectionRefusedError; break;
- case NSURLErrorNetworkConnectionLost: qtError = QNetworkReply::NetworkSessionFailedError; break;
- case NSURLErrorDNSLookupFailed: qtError = QNetworkReply::HostNotFoundError; break;
- case NSURLErrorNotConnectedToInternet: qtError = QNetworkReply::NetworkSessionFailedError; break;
- case NSURLErrorUserAuthenticationRequired: qtError = QNetworkReply::AuthenticationRequiredError; break;
- default: break;
- }
- }
-
- replyprivate->setError(qtError, QString::fromNSString([error localizedDescription]));
- replyprivate->setFinished();
-}
-
-- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)aResponse
-{
- Q_UNUSED(connection)
- self.response = aResponse;
- self.responseData = [NSMutableData data];
-
- // copy headers
- if ([aResponse isKindOfClass:[NSHTTPURLResponse class]]) {
- NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)aResponse;
- NSDictionary *headers = [httpResponse allHeaderFields];
- for (NSString *key in headers) {
- NSString *value = [headers objectForKey:key];
- replyprivate->setRawHeader(QString::fromNSString(key).toUtf8(), QString::fromNSString(value).toUtf8());
- }
-
- int code = [httpResponse statusCode];
- replyprivate->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, code);
- } else {
- if ([aResponse expectedContentLength] != NSURLResponseUnknownLength)
- replyprivate->setHeader(QNetworkRequest::ContentLengthHeader, [aResponse expectedContentLength]);
- }
-
- QMetaObject::invokeMethod(replyprivate->q_func(), "metaDataChanged", Qt::QueuedConnection);
-}
-
-- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
-{
- Q_UNUSED(connection)
- [responseData appendData:data];
-
- if ([response expectedContentLength] != NSURLResponseUnknownLength) {
- QMetaObject::invokeMethod(replyprivate->q_func(), "downloadProgress", Qt::QueuedConnection,
- Q_ARG(qint64, qint64([responseData length] + replyprivate->bytesRead)),
- Q_ARG(qint64, qint64([response expectedContentLength])));
- }
-
- QMetaObject::invokeMethod(replyprivate->q_func(), "readyRead", Qt::QueuedConnection);
-}
-
-- (void)connection:(NSURLConnection*)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten
- totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
-{
- Q_UNUSED(connection)
- Q_UNUSED(bytesWritten)
- QMetaObject::invokeMethod(replyprivate->q_func(), "uploadProgress", Qt::QueuedConnection,
- Q_ARG(qint64, qint64(totalBytesWritten)),
- Q_ARG(qint64, qint64(totalBytesExpectedToWrite)));
-}
-
-- (NSCachedURLResponse*)connection:(NSURLConnection*)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse
-{
- Q_UNUSED(connection)
- return cachedResponse;
-}
-
-- (NSURLRequest*)connection:(NSURLConnection*)connection willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectResponse
-{
- Q_UNUSED(connection)
- Q_UNUSED(redirectResponse)
- return request;
-}
-
-- (void)connectionDidFinishLoading:(NSURLConnection*)connection
-{
- Q_UNUSED(connection)
- replyprivate->setFinished();
-}
-
-- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection*)connection
-{
- Q_UNUSED(connection)
- return YES;
-}
-
-@end
-
-QNetworkReplyNSURLConnectionImpl::~QNetworkReplyNSURLConnectionImpl()
-{
-}
-
-QNetworkReplyNSURLConnectionImpl::QNetworkReplyNSURLConnectionImpl(QObject *parent,
- const QNetworkRequest &request, const QNetworkAccessManager::Operation operation, QIODevice* outgoingData)
- : QNetworkReply(*new QNetworkReplyNSURLConnectionImplPrivate(), parent)
-{
- setRequest(request);
- setUrl(request.url());
- setOperation(operation);
- QNetworkReply::open(QIODevice::ReadOnly);
-
- QNetworkReplyNSURLConnectionImplPrivate *d = (QNetworkReplyNSURLConnectionImplPrivate*) d_func();
-
- QUrl url = request.url();
- if (url.host() == QLatin1String("localhost"))
- url.setHost(QString());
-
- if (url.path().isEmpty())
- url.setPath(QLatin1String("/"));
- setUrl(url);
-
- // Create a NSMutableURLRequest from QNetworkRequest
- NSMutableURLRequest *nsRequest = [NSMutableURLRequest requestWithURL:request.url().toNSURL()
- cachePolicy:NSURLRequestUseProtocolCachePolicy
- timeoutInterval:60.0];
- // copy headers
- const auto headers = request.rawHeaderList();
- for (const QByteArray &header : headers) {
- QByteArray headerValue = request.rawHeader(header);
- [nsRequest addValue:QString::fromUtf8(headerValue).toNSString()
- forHTTPHeaderField:QString::fromUtf8(header).toNSString()];
- }
-
- if (operation == QNetworkAccessManager::GetOperation)
- [nsRequest setHTTPMethod:@"GET"];
- else if (operation == QNetworkAccessManager::PostOperation)
- [nsRequest setHTTPMethod:@"POST"];
- else if (operation == QNetworkAccessManager::PutOperation)
- [nsRequest setHTTPMethod:@"PUT"];
- else if (operation == QNetworkAccessManager::DeleteOperation)
- [nsRequest setHTTPMethod:@"DELETE"];
- else
- qWarning() << "QNetworkReplyNSURLConnection: Unsupported netork operation" << operation;
-
- if (outgoingData) {
- d->outgoingData = outgoingData;
- if (outgoingData->isSequential()) {
- // set up streaming from outgoingData iodevice to request
- CFStreamCreateBoundPair(kCFAllocatorDefault, &d->readStream, &d->writeStream, d->transferBufferSize);
- CFWriteStreamOpen(d->writeStream);
- [nsRequest setHTTPBodyStream:reinterpret_cast<NSInputStream *>(d->readStream)];
- connect(outgoingData, SIGNAL(readyRead()), this, SLOT(readyReadOutgoingData()));
- readyReadOutgoingData();
- } else {
- // move all data at once
- QByteArray data = outgoingData->readAll();
- [nsRequest setHTTPBody:[NSData dataWithBytes:data.constData() length:data.length()]];
- }
- }
-
- // Create connection
- d->urlConnectionDelegate = [[QtNSURLConnectionDelegate alloc] initWithQNetworkReplyNSURLConnectionImplPrivate:d];
- d->urlConnection = [[NSURLConnection alloc] initWithRequest:nsRequest delegate:d->urlConnectionDelegate];
- if (!d->urlConnection) {
- // ### what type of error is an initWithRequest fail?
- setError(QNetworkReply::ProtocolUnknownError, QStringLiteral("QNetworkReplyNSURLConnection internal error"));
- }
-}
-
-void QNetworkReplyNSURLConnectionImpl::close()
-{
- // No-op? Network ops should continue (especially POSTs)
- QNetworkReply::close();
-}
-
-void QNetworkReplyNSURLConnectionImpl::abort()
-{
- Q_D(QNetworkReplyNSURLConnectionImpl);
- [d->urlConnection cancel];
- QNetworkReply::close();
-}
-
-qint64 QNetworkReplyNSURLConnectionImpl::bytesAvailable() const
-{
- Q_D(const QNetworkReplyNSURLConnectionImpl);
- qint64 available = QNetworkReply::bytesAvailable() +
- [[d->urlConnectionDelegate responseData] length];
- return available;
-}
-
-bool QNetworkReplyNSURLConnectionImpl::isSequential() const
-{
- return true;
-}
-
-qint64 QNetworkReplyNSURLConnectionImpl::size() const
-{
- Q_D(const QNetworkReplyNSURLConnectionImpl);
- return [[d->urlConnectionDelegate responseData] length] + d->bytesRead;
-}
-
-/*!
- \internal
-*/
-qint64 QNetworkReplyNSURLConnectionImpl::readData(char *data, qint64 maxlen)
-{
- Q_D(QNetworkReplyNSURLConnectionImpl);
- qint64 dataSize = [[d->urlConnectionDelegate responseData] length];
- qint64 canRead = qMin(maxlen, dataSize);
- const char *sourceBase = static_cast<const char *>([[d->urlConnectionDelegate responseData] bytes]);
- memcpy(data, sourceBase, canRead);
- [[d->urlConnectionDelegate responseData] replaceBytesInRange:NSMakeRange(0, canRead) withBytes:NULL length:0];
- d->bytesRead += canRead;
- return canRead;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkreplynsurlconnectionimpl_p.h b/src/network/access/qnetworkreplynsurlconnectionimpl_p.h
deleted file mode 100644
index c948e66629..0000000000
--- a/src/network/access/qnetworkreplynsurlconnectionimpl_p.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QNETWORKREPLYNSURLCONNECTIONIMPL_H
-#define QNETWORKREPLYNSURLCONNECTIONIMPL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of the Network Access API. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qnetworkreply.h"
-#include "qnetworkreply_p.h"
-#include "qnetworkaccessmanager.h"
-#include <QFile>
-#include <private/qabstractfileengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QNetworkReplyNSURLConnectionImplPrivate;
-class QNetworkReplyNSURLConnectionImpl: public QNetworkReply
-{
- Q_OBJECT
-public:
- QNetworkReplyNSURLConnectionImpl(QObject *parent, const QNetworkRequest &req, const QNetworkAccessManager::Operation op, QIODevice* outgoingData);
- virtual ~QNetworkReplyNSURLConnectionImpl();
- virtual void abort();
-
- // reimplemented from QNetworkReply
- virtual void close();
- virtual qint64 bytesAvailable() const;
- virtual bool isSequential () const;
- qint64 size() const;
-
- virtual qint64 readData(char *data, qint64 maxlen);
-public Q_SLOTS:
- void readyReadOutgoingData();
-
- Q_DECLARE_PRIVATE(QNetworkReplyNSURLConnectionImpl)
-};
-
-QT_END_NAMESPACE
-
-#endif // QNetworkReplyNSURLConnectionImpl_H
diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp
index 35981a2f2c..41038dc8da 100644
--- a/src/network/kernel/qdnslookup_unix.cpp
+++ b/src/network/kernel/qdnslookup_unix.cpp
@@ -47,7 +47,9 @@
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
-#include <arpa/nameser_compat.h>
+#if !defined(Q_OS_OPENBSD)
+# include <arpa/nameser_compat.h>
+#endif
#include <resolv.h>
#if defined(__GNU_LIBRARY__) && !defined(__UCLIBC__)
@@ -58,6 +60,9 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_LIBRARY
+#if defined(Q_OS_OPENBSD)
+typedef struct __res_state* res_state;
+#endif
typedef int (*dn_expand_proto)(const unsigned char *, const unsigned char *, const unsigned char *, char *, int);
static dn_expand_proto local_dn_expand = 0;
typedef void (*res_nclose_proto)(res_state);
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index b3e456be69..7ef9d7f26b 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -560,7 +560,9 @@ int QNativeSocketEnginePrivate::nativeAccept()
setError(QAbstractSocket::SocketResourceError, NotSocketErrorString);
break;
case EPROTONOSUPPORT:
+#if !defined(Q_OS_OPENBSD)
case EPROTO:
+#endif
case EAFNOSUPPORT:
case EINVAL:
setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString);
@@ -900,7 +902,9 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVIF
&& cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sockaddr_dl))) {
sockaddr_dl *sdl = reinterpret_cast<sockaddr_dl *>(CMSG_DATA(cmsgptr));
-
+# if defined(Q_OS_OPENBSD)
+# define LLINDEX(s) ((s)->sdl_index)
+# endif
header->ifindex = LLINDEX(sdl);
}
# endif
diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp
index 181c49f200..dd43615f98 100644
--- a/src/network/socket/qnativesocketengine_winrt.cpp
+++ b/src/network/socket/qnativesocketengine_winrt.cpp
@@ -337,7 +337,7 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
d->socketState = QAbstractSocket::ConnectingState;
hr = QEventDispatcherWinRT::runOnXamlThread([d]() {
return d->connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>(
- d, &QNativeSocketEnginePrivate::handleConnectToHost).Get());
+ d, &QNativeSocketEnginePrivate::handleConnectOpFinished).Get());
});
Q_ASSERT_SUCCEEDED(hr);
@@ -477,7 +477,10 @@ void QNativeSocketEngine::close()
hr = socket3->CancelIOAsync(&action);
Q_ASSERT_SUCCEEDED(hr);
hr = QWinRTFunctions::await(action);
- Q_ASSERT_SUCCEEDED(hr);
+ // If there is no pending IO (no read established before) the function will fail with
+ // "function was called at an unexpected time" which is fine.
+ if (hr != E_ILLEGAL_METHOD_CALL)
+ Q_ASSERT_SUCCEEDED(hr);
return S_OK;
});
Q_ASSERT_SUCCEEDED(hr);
@@ -759,7 +762,7 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
if (d->socketState == QAbstractSocket::ConnectingState) {
HRESULT hr = QWinRTFunctions::await(d->connectOp, QWinRTFunctions::ProcessMainThreadEvents);
if (SUCCEEDED(hr)) {
- d->handleConnectionEstablished(d->connectOp.Get());
+ d->handleConnectOpFinished(d->connectOp.Get(), Completed);
return true;
}
}
@@ -1214,38 +1217,32 @@ HRESULT QNativeSocketEnginePrivate::handleClientConnection(IStreamSocketListener
return S_OK;
}
-HRESULT QNativeSocketEnginePrivate::handleConnectToHost(IAsyncAction *action, AsyncStatus)
-{
- handleConnectionEstablished(action);
- return S_OK;
-}
-
-void QNativeSocketEnginePrivate::handleConnectionEstablished(IAsyncAction *action)
+HRESULT QNativeSocketEnginePrivate::handleConnectOpFinished(IAsyncAction *action, AsyncStatus)
{
Q_Q(QNativeSocketEngine);
if (wasDeleted || !connectOp) // Protect against a late callback
- return;
+ return S_OK;
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);
socketState = QAbstractSocket::UnconnectedState;
- break;
+ return S_OK;
case 0x80072751: // A socket operation was attempted to an unreachable host.
setError(QAbstractSocket::HostNotFoundError, HostUnreachableErrorString);
socketState = QAbstractSocket::UnconnectedState;
- break;
+ return S_OK;
case 0x8007274d: // No connection could be made because the target machine actively refused it.
setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
socketState = QAbstractSocket::UnconnectedState;
- break;
+ return S_OK;
default:
if (FAILED(hr)) {
setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString);
socketState = QAbstractSocket::UnconnectedState;
+ return S_OK;
}
- break;
}
// The callback might be triggered several times if we do not cancel/reset it here
@@ -1267,13 +1264,14 @@ void QNativeSocketEnginePrivate::handleConnectionEstablished(IAsyncAction *actio
emit q->connectionReady();
if (socketType != QAbstractSocket::TcpSocket)
- return;
+ return S_OK;
// 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();
+ return S_OK;
}
HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *asyncInfo, AsyncStatus status)
diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h
index 325e4965e6..5b76c2d223 100644
--- a/src/network/socket/qnativesocketengine_winrt_p.h
+++ b/src/network/socket/qnativesocketengine_winrt_p.h
@@ -220,8 +220,7 @@ private:
ABI::Windows::Networking::Sockets::IDatagramSocketMessageReceivedEventArgs *args);
HRESULT handleClientConnection(ABI::Windows::Networking::Sockets::IStreamSocketListener *tcpListener,
ABI::Windows::Networking::Sockets::IStreamSocketListenerConnectionReceivedEventArgs *args);
- HRESULT handleConnectToHost(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus);
- void handleConnectionEstablished(ABI::Windows::Foundation::IAsyncAction *action);
+ HRESULT handleConnectOpFinished(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus);
HRESULT handleReadyRead(ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer *, UINT32> *asyncInfo, ABI::Windows::Foundation::AsyncStatus);
};
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index eb9264ba20..a57a1dca2c 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -1122,7 +1122,9 @@ bool QSocks5SocketEngine::connectInternal()
}
if (d->socketState != QAbstractSocket::ConnectingState) {
- if (d->socks5State == QSocks5SocketEnginePrivate::Uninitialized) {
+ if (d->socks5State == QSocks5SocketEnginePrivate::Uninitialized
+ // We may have new auth credentials since an earlier failure:
+ || d->socks5State == QSocks5SocketEnginePrivate::AuthenticatingError) {
setState(QAbstractSocket::ConnectingState);
//limit buffer in internal socket, data is buffered in the external socket under application control
d->data->controlSocket->setReadBufferSize(65536);
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index a5ee9bf0c1..472db3aa81 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -2632,7 +2632,8 @@ QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories()
<< "/var/ssl/certs/" // AIX
<< "/usr/local/ssl/certs/" // Solaris
<< "/etc/openssl/certs/" // BlackBerry
- << "/opt/openssl/certs/"; // HP-UX
+ << "/opt/openssl/certs/" // HP-UX
+ << "/etc/ssl/"; // OpenBSD
}
/*!
diff --git a/src/platformheaders/doc/src/qtplatformheaders.qdoc b/src/platformheaders/doc/src/qtplatformheaders.qdoc
index 745edf7983..6eb7b27cce 100644
--- a/src/platformheaders/doc/src/qtplatformheaders.qdoc
+++ b/src/platformheaders/doc/src/qtplatformheaders.qdoc
@@ -80,6 +80,19 @@
\sa QXcbWindowFunctions QWindowsWindowFunctions
+ \section1 Getting Started
+
+ To include the definitions of the module's functions and classes, use the following directives:
+ \code
+ #include <QtPlatformHeaders/QWindowsWindowFunctions>
+ #include <QtPlatformHeaders/QXcbWindowFunctions>
+ \endcode
+
+ As the module is header-only, no further modifications to the .pro files are required to use it.
+
+ \note The module name (\c QtPlatformHeaders) must appear in the \c #include directive.
+ \note It is not necessary to enclose the code in \c #ifdef directives depending on platform.
+
\section1 API Reference
\list
\li \l{Qt Platform Headers C++ Classes}{C++ Classes}
diff --git a/src/platformsupport/devicediscovery/devicediscovery.pri b/src/platformsupport/devicediscovery/devicediscovery.pri
index 1ac25da901..9829ae88ba 100644
--- a/src/platformsupport/devicediscovery/devicediscovery.pri
+++ b/src/platformsupport/devicediscovery/devicediscovery.pri
@@ -1,18 +1,14 @@
HEADERS += $$PWD/qdevicediscovery_p.h
-linux {
- contains(QT_CONFIG, libudev) {
- SOURCES += $$PWD/qdevicediscovery_udev.cpp
- HEADERS += $$PWD/qdevicediscovery_udev_p.h
- INCLUDEPATH += $$QMAKE_INCDIR_LIBUDEV
- LIBS_PRIVATE += $$QMAKE_LIBS_LIBUDEV
- } else: contains(QT_CONFIG, evdev) {
- SOURCES += $$PWD/qdevicediscovery_static.cpp
- HEADERS += $$PWD/qdevicediscovery_static_p.h
- } else {
- SOURCES += $$PWD/qdevicediscovery_dummy.cpp
- HEADERS += $$PWD/qdevicediscovery_dummy_p.h
- }
+contains(QT_CONFIG, libudev) {
+ SOURCES += $$PWD/qdevicediscovery_udev.cpp
+ HEADERS += $$PWD/qdevicediscovery_udev_p.h
+ INCLUDEPATH += $$QMAKE_INCDIR_LIBUDEV
+ LIBS_PRIVATE += $$QMAKE_LIBS_LIBUDEV
+} else: contains(QT_CONFIG, evdev) {
+ SOURCES += $$PWD/qdevicediscovery_static.cpp
+ HEADERS += $$PWD/qdevicediscovery_static_p.h
} else {
SOURCES += $$PWD/qdevicediscovery_dummy.cpp
+ HEADERS += $$PWD/qdevicediscovery_dummy_p.h
}
diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp
index f8efd105bc..da41cfeabf 100644
--- a/src/platformsupport/eglconvenience/qeglconvenience.cpp
+++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp
@@ -587,6 +587,10 @@ int q_screenDepthFromFb(int framebufferDevice)
qreal q_refreshRateFromFb(int framebufferDevice)
{
+#ifndef Q_OS_LINUX
+ Q_UNUSED(framebufferDevice)
+#endif
+
static qreal rate = 0;
#ifdef Q_OS_LINUX
diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
index 36de1e0c69..c7f6dd2740 100644
--- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
+++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
@@ -60,7 +60,7 @@ Q_LOGGING_CATEGORY(qLcEvdevKeyMap, "qt.qpa.input.keymap")
#include "qevdevkeyboard_defaultmap_p.h"
QEvdevKeyboardHandler::QEvdevKeyboardHandler(const QString &device, int fd, bool disableZap, bool enableCompose, const QString &keymapFile)
- : m_device(device), m_fd(fd),
+ : m_device(device), m_fd(fd), m_notify(Q_NULLPTR),
m_modifiers(0), m_composing(0), m_dead_unicode(0xffff),
m_no_zap(disableZap), m_do_compose(enableCompose),
m_keymap(0), m_keymap_size(0), m_keycompose(0), m_keycompose_size(0)
@@ -75,9 +75,8 @@ QEvdevKeyboardHandler::QEvdevKeyboardHandler(const QString &device, int fd, bool
unloadKeymap();
// socket notifier for events on the keyboard device
- QSocketNotifier *notifier;
- notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
- connect(notifier, SIGNAL(activated(int)), this, SLOT(readKeycode()));
+ m_notify = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
+ connect(m_notify, SIGNAL(activated(int)), this, SLOT(readKeycode()));
}
QEvdevKeyboardHandler::~QEvdevKeyboardHandler()
@@ -162,6 +161,14 @@ void QEvdevKeyboardHandler::readKeycode()
} else if (result < 0) {
if (errno != EINTR && errno != EAGAIN) {
qErrnoWarning(errno, "evdevkeyboard: Could not read from input device");
+ // If the device got disconnected, stop reading, otherwise we get flooded
+ // by the above error over and over again.
+ if (errno == ENODEV) {
+ delete m_notify;
+ m_notify = Q_NULLPTR;
+ qt_safe_close(m_fd);
+ m_fd = -1;
+ }
return;
}
} else {
diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h
index 89fa879115..b94323fcbb 100644
--- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h
+++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h
@@ -57,6 +57,8 @@
QT_BEGIN_NAMESPACE
+class QSocketNotifier;
+
namespace QEvdevKeyboardMap {
const quint32 FileMagic = 0x514d4150; // 'QMAP'
@@ -186,6 +188,7 @@ private:
QString m_device;
int m_fd;
+ QSocketNotifier *m_notify;
// keymap handling
quint8 m_modifiers;
diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp
index 382b9b1514..d5ea04bee8 100644
--- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp
+++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp
@@ -111,9 +111,8 @@ QEvdevMouseHandler::QEvdevMouseHandler(const QString &device, int fd, bool abs,
m_abs = getHardwareMaximum();
// socket notifier for events on the mouse device
- QSocketNotifier *notifier;
- notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
- connect(notifier, SIGNAL(activated(int)), this, SLOT(readMouseData()));
+ m_notify = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
+ connect(m_notify, SIGNAL(activated(int)), this, SLOT(readMouseData()));
}
QEvdevMouseHandler::~QEvdevMouseHandler()
@@ -202,6 +201,14 @@ void QEvdevMouseHandler::readMouseData()
} else if (result < 0) {
if (errno != EINTR && errno != EAGAIN) {
qErrnoWarning(errno, "evdevmouse: Could not read from input device");
+ // If the device got disconnected, stop reading, otherwise we get flooded
+ // by the above error over and over again.
+ if (errno == ENODEV) {
+ delete m_notify;
+ m_notify = Q_NULLPTR;
+ qt_safe_close(m_fd);
+ m_fd = -1;
+ }
return;
}
} else {
diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro
index 81c7faa389..60be964b74 100644
--- a/src/platformsupport/platformsupport.pro
+++ b/src/platformsupport/platformsupport.pro
@@ -21,7 +21,11 @@ include(accessibility/accessibility.pri)
include(linuxaccessibility/linuxaccessibility.pri)
include(clipboard/clipboard.pri)
include(platformcompositor/platformcompositor.pri)
-contains(QT_CONFIG, dbus) {
+
+# dbus convenience, but not for darwin: the platform
+# plugins for these platforms do not use dbus and we
+# don't want to create a false dependency.
+!darwin: contains(QT_CONFIG, dbus) {
include(dbusmenu/dbusmenu.pri)
include(dbustray/dbustray.pri)
}
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index eaa0170748..91ce91004f 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -153,7 +153,7 @@ static bool isMouseEvent(NSEvent *ev)
if (NSMouseInRect(loc, windowFrame, NO) &&
!NSMouseInRect(loc, contentFrame, NO))
{
- QNSView *contentView = (QNSView *)pw->contentView();
+ QNSView *contentView = pw->m_qtView;
[contentView handleFrameStrutMouseEvent: theEvent];
}
}
@@ -1188,7 +1188,11 @@ NSView *QCocoaWindow::contentView() const
void QCocoaWindow::setContentView(NSView *contentView)
{
// Remove and release the previous content view
- [m_contentView removeFromSuperview];
+ if (m_nsWindow)
+ [m_nsWindow setContentView:nil];
+ else
+ [m_contentView removeFromSuperview];
+
[m_contentView release];
// Insert and retain the new content view
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 5972cf9504..3469166fdc 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -663,7 +663,9 @@ QT_WARNING_POP
- (BOOL)becomeFirstResponder
{
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
+ if (!m_window || !m_platformWindow)
+ return NO;
+ if (m_window->flags() & Qt::WindowTransparentForInput)
return NO;
if (!m_platformWindow->windowIsPopupType() && !m_isMenuView)
QWindowSystemInterface::handleWindowActivated([self topLevelWindow]);
@@ -672,11 +674,13 @@ QT_WARNING_POP
- (BOOL)acceptsFirstResponder
{
+ if (!m_window || !m_platformWindow)
+ return NO;
if (m_isMenuView)
return NO;
if (m_platformWindow->shouldRefuseKeyWindowAndFirstResponder())
return NO;
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
+ if (m_window->flags() & Qt::WindowTransparentForInput)
return NO;
if ((m_window->flags() & Qt::ToolTip) == Qt::ToolTip)
return NO;
@@ -686,7 +690,9 @@ QT_WARNING_POP
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
{
Q_UNUSED(theEvent)
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
+ if (!m_window || !m_platformWindow)
+ return NO;
+ if (m_window->flags() & Qt::WindowTransparentForInput)
return NO;
return YES;
}
@@ -2199,7 +2205,11 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
// keep our state, and QGuiApplication state (buttons member) in-sync,
// or future mouse events will be processed incorrectly
- m_buttons &= ~(m_sendUpAsRightButton ? Qt::RightButton : Qt::LeftButton);
+ NSUInteger pmb = [NSEvent pressedMouseButtons];
+ for (int buttonNumber = 0; buttonNumber < 32; buttonNumber++) { // see cocoaButton2QtButton() for the 32 value
+ if (!(pmb & (1 << buttonNumber)))
+ m_buttons &= ~cocoaButton2QtButton(buttonNumber);
+ }
NSPoint windowPoint = [self convertPoint: point fromView: nil];
QPoint qtWindowPoint(windowPoint.x, windowPoint.y);
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
index abff88b4bd..5b779d6732 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
@@ -132,7 +132,7 @@ void QEglFSKmsGbmCursor::updateMouseStatus()
m_state = visible ? CursorPendingVisible : CursorPendingHidden;
#ifndef QT_NO_CURSOR
- changeCursor(nullptr, m_screen->topLevelAt(pos()));
+ changeCursor(Q_NULLPTR, m_screen->topLevelAt(pos()));
#endif
}
diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h
index 82bcf48855..2b0643f26e 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.h
+++ b/src/plugins/platforms/ios/qiosinputcontext.h
@@ -42,6 +42,7 @@
#include <UIKit/UIKit.h>
+#include <QtCore/qlocale.h>
#include <QtGui/qevent.h>
#include <QtGui/qtransform.h>
#include <qpa/qplatforminputcontext.h>
@@ -52,6 +53,7 @@ const char kImePlatformDataReturnKeyType[] = "returnKeyType";
QT_BEGIN_NAMESPACE
+@class QIOSLocaleListener;
@class QIOSKeyboardListener;
@class QIOSTextInputResponder;
@protocol KeyboardState;
@@ -98,6 +100,8 @@ public:
void reset() Q_DECL_OVERRIDE;
void commit() Q_DECL_OVERRIDE;
+ QLocale locale() const Q_DECL_OVERRIDE;
+
void clearCurrentFocusObject();
void setFocusObject(QObject *object) Q_DECL_OVERRIDE;
@@ -118,6 +122,7 @@ public:
private:
UIView* scrollableRootView();
+ QIOSLocaleListener *m_localeListener;
QIOSKeyboardListener *m_keyboardHideGesture;
QIOSTextInputResponder *m_textResponder;
KeyboardState m_keyboardState;
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index d553d16698..ef93d68cf0 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -62,6 +62,39 @@ static QUIView *focusView()
// -------------------------------------------------------------------------
+@interface QIOSLocaleListener : NSObject
+@end
+
+@implementation QIOSLocaleListener
+
+- (id)init
+{
+ if (self = [super init]) {
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ [notificationCenter addObserver:self
+ selector:@selector(localeDidChange:)
+ name:NSCurrentLocaleDidChangeNotification object:nil];
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)localeDidChange:(NSNotification *)notification
+{
+ Q_UNUSED(notification);
+ QIOSInputContext::instance()->emitLocaleChanged();
+}
+
+@end
+
+// -------------------------------------------------------------------------
+
@interface QIOSKeyboardListener : UIGestureRecognizer <UIGestureRecognizerDelegate> {
@private
QIOSInputContext *m_context;
@@ -291,6 +324,7 @@ QIOSInputContext *QIOSInputContext::instance()
QIOSInputContext::QIOSInputContext()
: QPlatformInputContext()
+ , m_localeListener([QIOSLocaleListener new])
, m_keyboardHideGesture([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
, m_textResponder(0)
{
@@ -304,6 +338,7 @@ QIOSInputContext::QIOSInputContext()
QIOSInputContext::~QIOSInputContext()
{
+ [m_localeListener release];
[m_keyboardHideGesture.view removeGestureRecognizer:m_keyboardHideGesture];
[m_keyboardHideGesture release];
@@ -663,3 +698,8 @@ void QIOSInputContext::commit()
[m_textResponder unmarkText];
[m_textResponder notifyInputDelegate:Qt::ImSurroundingText];
}
+
+QLocale QIOSInputContext::locale() const
+{
+ return QLocale(QString::fromNSString([[NSLocale currentLocale] objectForKey:NSLocaleIdentifier]));
+}
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index eb12739e98..37d5557794 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -359,6 +359,7 @@
- (void)sendKeyPressRelease:(Qt::Key)key modifiers:(Qt::KeyboardModifiers)modifiers
{
+ QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject, true);
QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyPress, key, modifiers);
QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyRelease, key, modifiers);
QWindowSystemInterface::flushWindowSystemEvents();
diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro
index 0d31d6605b..bd6f2d8e6f 100644
--- a/src/plugins/platforms/minimal/minimal.pro
+++ b/src/plugins/platforms/minimal/minimal.pro
@@ -11,6 +11,7 @@ HEADERS = qminimalintegration.h \
OTHER_FILES += minimal.json
CONFIG += qpa/genericunixfontdatabase
+darwin: DEFINES += QT_NO_FONTCONFIG
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QMinimalIntegrationPlugin
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
index cb3764f5df..a5b64636af 100644
--- a/src/plugins/platforms/platforms.pro
+++ b/src/plugins/platforms/platforms.pro
@@ -2,9 +2,9 @@ TEMPLATE = subdirs
android: SUBDIRS += android
-SUBDIRS += minimal
+!android: SUBDIRS += minimal
-!win32|contains(QT_CONFIG, freetype):SUBDIRS += offscreen
+!android:if(!win32|contains(QT_CONFIG, freetype)): SUBDIRS += offscreen
contains(QT_CONFIG, xcb) {
SUBDIRS += xcb
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp
index a3f9f0b44b..0ce4e87e52 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp
@@ -205,26 +205,9 @@ QWindowsEGLStaticContext::QWindowsEGLStaticContext(EGLDisplay display)
{
}
-QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester::Renderers preferredType)
+bool QWindowsEGLStaticContext::initializeAngle(QWindowsOpenGLTester::Renderers preferredType, HDC dc,
+ EGLDisplay *display, EGLint *major, EGLint *minor)
{
- const HDC dc = QWindowsContext::instance()->displayContext();
- if (!dc){
- qWarning("%s: No Display", __FUNCTION__);
- return 0;
- }
-
- if (!libEGL.init()) {
- qWarning("%s: Failed to load and resolve libEGL functions", __FUNCTION__);
- return 0;
- }
- if (!libGLESv2.init()) {
- qWarning("%s: Failed to load and resolve libGLESv2 functions", __FUNCTION__);
- return 0;
- }
-
- EGLDisplay display = EGL_NO_DISPLAY;
- EGLint major = 0;
- EGLint minor = 0;
#ifdef EGL_ANGLE_platform_angle
if (libEGL.eglGetPlatformDisplayEXT
&& (preferredType & QWindowsOpenGLTester::AngleBackendMask)) {
@@ -242,16 +225,52 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester:
else if (preferredType & QWindowsOpenGLTester::AngleRendererD3d11Warp)
attributes = anglePlatformAttributes[2];
if (attributes) {
- display = libEGL.eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, dc, attributes);
- if (!libEGL.eglInitialize(display, &major, &minor)) {
- display = EGL_NO_DISPLAY;
- major = minor = 0;
+ *display = libEGL.eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, dc, attributes);
+ if (!libEGL.eglInitialize(*display, major, minor)) {
+ libEGL.eglTerminate(*display);
+ *display = EGL_NO_DISPLAY;
+ *major = *minor = 0;
+ return false;
}
}
}
#else // EGL_ANGLE_platform_angle
- Q_UNUSED(preferredType)
+ Q_UNUSED(preferredType);
+ Q_UNUSED(dc);
+ Q_UNUSED(display);
+ Q_UNUSED(major);
+ Q_UNUSED(minor);
#endif
+ return true;
+}
+
+QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester::Renderers preferredType)
+{
+ const HDC dc = QWindowsContext::instance()->displayContext();
+ if (!dc){
+ qWarning("%s: No Display", __FUNCTION__);
+ return 0;
+ }
+
+ if (!libEGL.init()) {
+ qWarning("%s: Failed to load and resolve libEGL functions", __FUNCTION__);
+ return 0;
+ }
+ if (!libGLESv2.init()) {
+ qWarning("%s: Failed to load and resolve libGLESv2 functions", __FUNCTION__);
+ return 0;
+ }
+
+ EGLDisplay display = EGL_NO_DISPLAY;
+ EGLint major = 0;
+ EGLint minor = 0;
+
+ if (!initializeAngle(preferredType, dc, &display, &major, &minor)
+ && (preferredType & QWindowsOpenGLTester::AngleRendererD3d11)) {
+ preferredType &= ~QWindowsOpenGLTester::AngleRendererD3d11;
+ initializeAngle(preferredType, dc, &display, &major, &minor);
+ }
+
if (display == EGL_NO_DISPLAY)
display = libEGL.eglGetDisplay(dc);
if (!display) {
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h
index c7f7cee3c2..48a19f81e5 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.h
+++ b/src/plugins/platforms/windows/qwindowseglcontext.h
@@ -131,6 +131,8 @@ public:
private:
explicit QWindowsEGLStaticContext(EGLDisplay display);
+ static bool initializeAngle(QWindowsOpenGLTester::Renderers preferredType, HDC dc,
+ EGLDisplay *display, EGLint *major, EGLint *minor);
const EGLDisplay m_display;
};
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index 806af6458b..4f3df32f16 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -1346,8 +1346,7 @@ QFontEngine *QWindowsMultiFontEngine::loadEngine(int at)
QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace,
fontEngine->fontDef.pixelSize,
data);
- if (fontEngine->fontDef.weight > QFont::Normal)
- fedw->fontDef.weight = fontEngine->fontDef.weight;
+ fedw->fontDef.weight = fontEngine->fontDef.weight;
if (fontEngine->fontDef.style > QFont::StyleNormal)
fedw->fontDef.style = fontEngine->fontDef.style;
fedw->fontDef.family = fam;
@@ -1364,8 +1363,7 @@ QFontEngine *QWindowsMultiFontEngine::loadEngine(int at)
// reason
QFontEngine *fe = new QWindowsFontEngine(fam, lf, data);
- if (fontEngine->fontDef.weight > QFont::Normal)
- fe->fontDef.weight = fontEngine->fontDef.weight;
+ fe->fontDef.weight = fontEngine->fontDef.weight;
if (fontEngine->fontDef.style > QFont::StyleNormal)
fe->fontDef.style = fontEngine->fontDef.style;
fe->fontDef.family = fam;
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 96940f3f4c..4bf424f5f6 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -138,7 +138,16 @@ public:
explicit ShGetFileInfoFunction(const wchar_t *fn, DWORD a, SHFILEINFO *i, UINT f, bool *r) :
m_fileName(fn), m_attributes(a), m_flags(f), m_info(i), m_result(r) {}
- void operator()() const { *m_result = SHGetFileInfo(m_fileName, m_attributes, m_info, sizeof(SHFILEINFO), m_flags); }
+ void operator()() const
+ {
+#ifndef Q_OS_WINCE
+ const UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+#endif
+ *m_result = SHGetFileInfo(m_fileName, m_attributes, m_info, sizeof(SHFILEINFO), m_flags);
+#ifndef Q_OS_WINCE
+ SetErrorMode(oldErrorMode);
+#endif
+ }
private:
const wchar_t *m_fileName;
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 31c9984559..76a36851ce 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1677,11 +1677,12 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
return false;
PAINTSTRUCT ps;
+ BeginPaint(hwnd, &ps);
+
// Observed painting problems with Aero style disabled (QTBUG-7865).
+ // 5.8: Consider making it dependent on !DwmIsCompositionEnabled().
if (testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered))
- InvalidateRect(hwnd, 0, false);
-
- BeginPaint(hwnd, &ps);
+ SelectClipRgn(ps.hdc, NULL);
// If the a window is obscured by another window (such as a child window)
// we still need to send isExposed=true, for compatibility.
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp
new file mode 100644
index 0000000000..2ef50aa4e2
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp
@@ -0,0 +1,893 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qwinrtdrag.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/QMimeData>
+#include <QtCore/QStringList>
+#include <QtGui/QGuiApplication>
+#include <qpa/qwindowsysteminterface.h>
+
+#include <qfunctions_winrt.h>
+#include <private/qeventdispatcher_winrt_p.h>
+
+#include <Windows.ApplicationModel.datatransfer.h>
+#include <windows.ui.xaml.h>
+#include <windows.foundation.collections.h>
+#include <windows.graphics.imaging.h>
+#include <windows.storage.streams.h>
+#include <functional>
+#include <robuffer.h>
+
+using namespace ABI::Windows::ApplicationModel::DataTransfer;
+using namespace ABI::Windows::ApplicationModel::DataTransfer::DragDrop;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Graphics::Imaging;
+using namespace ABI::Windows::Storage;
+using namespace ABI::Windows::Storage::Streams;
+using namespace ABI::Windows::UI::Xaml;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime")
+
+ComPtr<IBuffer> createIBufferFromData(const char *data, qint32 size)
+{
+ static ComPtr<IBufferFactory> bufferFactory;
+ HRESULT hr;
+ if (!bufferFactory) {
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ IID_PPV_ARGS(&bufferFactory));
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+
+ ComPtr<IBuffer> buffer;
+ const UINT32 length = size;
+ hr = bufferFactory->Create(length, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = buffer->put_Length(length);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
+ hr = buffer.As(&byteArrayAccess);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ byte *bytes;
+ hr = byteArrayAccess->Buffer(&bytes);
+ Q_ASSERT_SUCCEEDED(hr);
+ memcpy(bytes, data, length);
+ return buffer;
+}
+
+class DragThreadTransferData : public QObject
+{
+ Q_OBJECT
+public slots:
+ void handleDrag();
+public:
+ explicit DragThreadTransferData(QObject *parent = Q_NULLPTR);
+ QWindow *window;
+ QWinRTInternalMimeData *mime;
+ QPoint point;
+ Qt::DropActions actions;
+ bool dropAction;
+ ComPtr<IDragEventArgs> nativeArgs;
+ ComPtr<IDragOperationDeferral> deferral;
+};
+
+inline QString hStringToQString(const HString &hString)
+{
+ quint32 l;
+ const wchar_t *raw = hString.GetRawBuffer(&l);
+ return (QString::fromWCharArray(raw, l));
+}
+
+inline HString qStringToHString(const QString &qString)
+{
+ HString h;
+ h.Set(reinterpret_cast<const wchar_t*>(qString.utf16()), qString.size());
+ return h;
+}
+
+namespace NativeFormatStrings {
+ static ComPtr<IStandardDataFormatsStatics> dataStatics;
+ static HSTRING text; // text/plain
+ static HSTRING html; // text/html
+ static HSTRING storage; // text/uri-list
+}
+
+static inline DataPackageOperation translateFromQDragDropActions(const Qt::DropAction action)
+{
+ switch (action) {
+ case Qt::CopyAction:
+ return DataPackageOperation_Copy;
+ case Qt::MoveAction:
+ return DataPackageOperation_Move;
+ case Qt::LinkAction:
+ return DataPackageOperation_Link;
+ case Qt::IgnoreAction:
+ default:
+ return DataPackageOperation_None;
+ }
+}
+
+static inline Qt::DropActions translateToQDragDropActions(const DataPackageOperation op)
+{
+ Qt::DropActions actions = Qt::IgnoreAction;
+ // None needs to be interpreted as the sender being able to handle
+ // anything and let the receiver decide
+ if (op == DataPackageOperation_None)
+ actions = Qt::LinkAction | Qt::CopyAction | Qt::MoveAction;
+ if (op & DataPackageOperation_Link)
+ actions |= Qt::LinkAction;
+ if (op & DataPackageOperation_Copy)
+ actions |= Qt::CopyAction;
+ if (op & DataPackageOperation_Move)
+ actions |= Qt::MoveAction;
+ return actions;
+}
+
+QWinRTInternalMimeData::QWinRTInternalMimeData()
+ : QInternalMimeData()
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+ if (!NativeFormatStrings::dataStatics) {
+ HRESULT hr;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_StandardDataFormats).Get(),
+ IID_PPV_ARGS(&NativeFormatStrings::dataStatics));
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = NativeFormatStrings::dataStatics->get_Text(&NativeFormatStrings::text);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = NativeFormatStrings::dataStatics->get_Html(&NativeFormatStrings::html);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = NativeFormatStrings::dataStatics->get_StorageItems(&NativeFormatStrings::storage);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+}
+
+QWinRTInternalMimeData::~QWinRTInternalMimeData()
+{
+}
+
+bool QWinRTInternalMimeData::hasFormat_sys(const QString &mimetype) const
+{
+ qCDebug(lcQpaMime) << __FUNCTION__ << mimetype;
+
+ if (!dataView)
+ return false;
+
+ return formats_sys().contains(mimetype);
+}
+
+QStringList QWinRTInternalMimeData::formats_sys() const
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+
+ if (!dataView)
+ return QStringList();
+
+ if (!formats.isEmpty())
+ return formats;
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([this]() {
+ boolean contains;
+ HRESULT hr;
+ hr = dataView->Contains(NativeFormatStrings::text, &contains);
+ if (SUCCEEDED(hr) && contains)
+ formats.append(QLatin1String("text/plain"));
+
+ hr = dataView->Contains(NativeFormatStrings::html, &contains);
+ if (SUCCEEDED(hr) && contains)
+ formats.append(QLatin1String("text/html"));
+
+ hr = dataView->Contains(NativeFormatStrings::storage, &contains);
+ if (SUCCEEDED(hr) && contains)
+ formats.append(QLatin1String("text/uri-list"));
+
+ // We need to add any additional format as well, for legacy windows
+ // reasons, but also in case someone adds custom formats.
+ ComPtr<IVectorView<HSTRING>> availableFormats;
+ hr = dataView->get_AvailableFormats(&availableFormats);
+ RETURN_OK_IF_FAILED("Could not query available formats.");
+
+ quint32 size;
+ hr = availableFormats->get_Size(&size);
+ RETURN_OK_IF_FAILED("Could not query format vector size.");
+ for (quint32 i = 0; i < size; ++i) {
+ HString str;
+ hr = availableFormats->GetAt(i, str.GetAddressOf());
+ if (FAILED(hr))
+ continue;
+ formats.append(hStringToQString(str));
+ }
+ return S_OK;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+
+ return formats;
+}
+
+QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const
+{
+ qCDebug(lcQpaMime) << __FUNCTION__ << mimetype << preferredType;
+
+ if (!dataView || !formats.contains(mimetype))
+ return QVariant();
+
+ QVariant result;
+ HRESULT hr;
+ if (mimetype == QLatin1String("text/plain")) {
+ hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() {
+ HRESULT hr;
+ ComPtr<IAsyncOperation<HSTRING>> op;
+ HString res;
+ hr = dataView->GetTextAsync(&op);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(op, res.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(hStringToQString(res));
+ return S_OK;
+ });
+ } else if (mimetype == QLatin1String("text/uri-list")) {
+ hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() {
+ HRESULT hr;
+ ComPtr<IAsyncOperation<IVectorView<IStorageItem*>*>> op;
+ hr = dataView->GetStorageItemsAsync(&op);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVectorView<IStorageItem*>> nativeItems;
+ hr = QWinRTFunctions::await(op, nativeItems.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ QList<QVariant> items;
+ quint32 count;
+ hr = nativeItems->get_Size(&count);
+ for (quint32 i = 0; i < count; ++i) {
+ ComPtr<IStorageItem> item;
+ hr = nativeItems->GetAt(i, &item);
+ Q_ASSERT_SUCCEEDED(hr);
+ HString path;
+ hr = item->get_Path(path.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ items.append(QUrl::fromLocalFile(hStringToQString(path)));
+ }
+ result.setValue(items);
+ return S_OK;
+ });
+ } else if (mimetype == QLatin1String("text/html")) {
+ hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() {
+ HRESULT hr;
+ ComPtr<IAsyncOperation<HSTRING>> op;
+ HString res;
+ hr = dataView->GetHtmlFormatAsync(&op);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(op, res.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(hStringToQString(res));
+ return S_OK;
+ });
+ } else {
+ // Asking for custom data
+ hr = QEventDispatcherWinRT::runOnXamlThread([this, &result, mimetype]() {
+ HRESULT hr;
+ ComPtr<IAsyncOperation<IInspectable*>> op;
+ ComPtr<IInspectable> res;
+ HString type;
+ type.Set(reinterpret_cast<const wchar_t*>(mimetype.utf16()), mimetype.size());
+ hr = dataView->GetDataAsync(type.Get(), &op);
+ RETURN_OK_IF_FAILED("Could not query custom drag data.");
+ hr = QWinRTFunctions::await(op, res.GetAddressOf());
+ if (FAILED(hr) || !res) {
+ qCDebug(lcQpaMime) << "Custom drop data operation returned no results or failed.";
+ return S_OK;
+ }
+
+ // Test for properties
+ ComPtr<IPropertyValue> propertyValue;
+ hr = res.As(&propertyValue);
+ if (SUCCEEDED(hr)) {
+ // We need to check which type of custom data we are receiving
+ PropertyType type;
+ propertyValue->get_Type(&type);
+ switch (type) {
+ case PropertyType_UInt8: {
+ quint8 v;
+ hr = propertyValue->GetUInt8(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Int16: {
+ qint16 v;
+ hr = propertyValue->GetInt16(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_UInt16: {
+ quint16 v;
+ hr = propertyValue->GetUInt16(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Int32: {
+ qint32 v;
+ hr = propertyValue->GetInt32(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_UInt32: {
+ quint32 v;
+ hr = propertyValue->GetUInt32(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Int64: {
+ qint64 v;
+ hr = propertyValue->GetInt64(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_UInt64: {
+ quint64 v;
+ hr = propertyValue->GetUInt64(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Single: {
+ float v;
+ hr = propertyValue->GetSingle(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Double: {
+ double v;
+ hr = propertyValue->GetDouble(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_Char16: {
+ wchar_t v;
+ hr = propertyValue->GetChar16(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(QString::fromWCharArray(&v, 1));
+ return S_OK;
+ }
+ case PropertyType_Boolean: {
+ boolean v;
+ hr = propertyValue->GetBoolean(&v);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(v);
+ return S_OK;
+ }
+ case PropertyType_String: {
+ HString stringProperty;
+ hr = propertyValue->GetString(stringProperty.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ result.setValue(hStringToQString(stringProperty));
+ return S_OK;
+ }
+ default:
+ qCDebug(lcQpaMime) << "Unknown property type dropped:" << type;
+ }
+ return S_OK;
+ }
+
+ // Custom data can be read via input streams
+ ComPtr<IRandomAccessStream> randomAccessStream;
+ hr = res.As(&randomAccessStream);
+ if (SUCCEEDED(hr)) {
+ UINT64 size;
+ hr = randomAccessStream->get_Size(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IInputStream> stream;
+ hr = randomAccessStream.As(&stream);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IBufferFactory> bufferFactory;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ IID_PPV_ARGS(&bufferFactory));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ UINT32 length = qBound(quint64(0), quint64(size), quint64(UINT_MAX));
+ ComPtr<IBuffer> buffer;
+ hr = bufferFactory->Create(length, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> readOp;
+ hr = stream->ReadAsync(buffer.Get(), length, InputStreamOptions_None, &readOp);
+
+ ComPtr<IBuffer> effectiveBuffer;
+ hr = QWinRTFunctions::await(readOp, effectiveBuffer.GetAddressOf());
+
+ hr = effectiveBuffer->get_Length(&length);
+
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
+ hr = effectiveBuffer.As(&byteArrayAccess);
+
+ byte *bytes;
+ hr = byteArrayAccess->Buffer(&bytes);
+ QByteArray array((char *)bytes, length);
+ result.setValue(array);
+ return S_OK;
+ }
+
+ HSTRING runtimeClass;
+ hr = res->GetRuntimeClassName(&runtimeClass);
+ Q_ASSERT_SUCCEEDED(hr);
+ HString converted;
+ converted.Set(runtimeClass);
+ qCDebug(lcQpaMime) << "Unknown drop data type received (" << hStringToQString(converted)
+ << "). Ignoring...";
+ return S_OK;
+ });
+ }
+ return result;
+}
+
+void QWinRTInternalMimeData::setDataView(const Microsoft::WRL::ComPtr<IDataPackageView> &d)
+{
+ dataView = d;
+ formats.clear();
+}
+
+static HRESULT qt_drag_enter(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
+{
+ QWinRTDrag::instance()->handleNativeDragEvent(sender, e);
+ return S_OK;
+}
+
+static HRESULT qt_drag_over(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
+{
+ QWinRTDrag::instance()->handleNativeDragEvent(sender, e);
+ return S_OK;
+}
+
+static HRESULT qt_drag_leave(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
+{
+ // Qt internally checks for new drags and auto sends leave events
+ // Also there is no QPA function for handling leave
+ Q_UNUSED(sender);
+ Q_UNUSED(e);
+ return S_OK;
+}
+
+static HRESULT qt_drop(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
+{
+ QWinRTDrag::instance()->handleNativeDragEvent(sender, e, true);
+ return S_OK;
+}
+
+#define Q_DECLARE_DRAGHANDLER(name,func) \
+class QtDragEventHandler##name : public IDragEventHandler \
+{ \
+public: \
+ virtual HRESULT STDMETHODCALLTYPE Invoke(IInspectable *sender, \
+ ABI::Windows::UI::Xaml::IDragEventArgs *e) \
+ { \
+ return qt_##func(sender, e);\
+ } \
+ \
+ STDMETHODIMP \
+ QueryInterface(REFIID riid, void FAR* FAR* ppvObj) \
+ { \
+ if (riid == IID_IUnknown || riid == IID_IDragEventHandler) { \
+ *ppvObj = this; \
+ AddRef(); \
+ return NOERROR; \
+ } \
+ *ppvObj = NULL; \
+ return ResultFromScode(E_NOINTERFACE); \
+ } \
+ \
+ STDMETHODIMP_(ULONG) \
+ AddRef(void) \
+ { \
+ return ++m_refs; \
+ } \
+ \
+ STDMETHODIMP_(ULONG) \
+ Release(void) \
+ { \
+ if (--m_refs == 0) { \
+ delete this; \
+ return 0; \
+ } \
+ return m_refs; \
+ } \
+private: \
+ULONG m_refs{0}; \
+};
+
+Q_DECLARE_DRAGHANDLER(Enter, drag_enter)
+Q_DECLARE_DRAGHANDLER(Over, drag_over)
+Q_DECLARE_DRAGHANDLER(Leave, drag_leave)
+Q_DECLARE_DRAGHANDLER(Drop, drop)
+
+#define Q_INST_DRAGHANDLER(name) QtDragEventHandler##name()
+
+Q_GLOBAL_STATIC(QWinRTDrag, gDrag);
+
+extern ComPtr<ABI::Windows::UI::Input::IPointerPoint> qt_winrt_lastPointerPoint; // qwinrtscreen.cpp
+
+QWinRTDrag::QWinRTDrag()
+ : QPlatformDrag()
+ , m_dragTarget(0)
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+ m_enter = new Q_INST_DRAGHANDLER(Enter);
+ m_over = new Q_INST_DRAGHANDLER(Over);
+ m_leave = new Q_INST_DRAGHANDLER(Leave);
+ m_drop = new Q_INST_DRAGHANDLER(Drop);
+ m_mimeData = new QWinRTInternalMimeData;
+}
+
+QWinRTDrag::~QWinRTDrag()
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+ delete m_enter;
+ delete m_over;
+ delete m_leave;
+ delete m_drop;
+ delete m_mimeData;
+}
+
+QWinRTDrag *QWinRTDrag::instance()
+{
+ return gDrag;
+}
+
+inline HRESULT resetUiElementDrag(ComPtr<IUIElement3> &elem3, EventRegistrationToken startingToken)
+{
+ return QEventDispatcherWinRT::runOnXamlThread([elem3, startingToken]() {
+ HRESULT hr;
+ hr = elem3->put_CanDrag(false);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = elem3->remove_DragStarting(startingToken);
+ Q_ASSERT_SUCCEEDED(hr);
+ return S_OK;
+ });
+}
+
+Qt::DropAction QWinRTDrag::drag(QDrag *drag)
+{
+ qCDebug(lcQpaMime) << __FUNCTION__ << drag;
+
+ if (!qt_winrt_lastPointerPoint) {
+ Q_ASSERT_X(qt_winrt_lastPointerPoint, Q_FUNC_INFO, "No pointerpoint known");
+ return Qt::IgnoreAction;
+ }
+
+ ComPtr<IUIElement3> elem3;
+ HRESULT hr = m_ui.As(&elem3);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IAsyncOperation<ABI::Windows::ApplicationModel::DataTransfer::DataPackageOperation>> op;
+ EventRegistrationToken startingToken;
+
+ hr = QEventDispatcherWinRT::runOnXamlThread([drag, &op, &hr, elem3, &startingToken, this]() {
+
+ hr = elem3->put_CanDrag(true);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ auto startingCallback = Callback<ITypedEventHandler<UIElement*, DragStartingEventArgs*>> ([drag](IInspectable *, IDragStartingEventArgs *args) {
+ qCDebug(lcQpaMime) << "Drag starting" << args;
+
+ ComPtr<IDataPackage> dataPackage;
+ HRESULT hr;
+ hr = args->get_Data(dataPackage.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ Qt::DropAction action = drag->defaultAction();
+ hr = dataPackage->put_RequestedOperation(translateFromQDragDropActions(action));
+ Q_ASSERT_SUCCEEDED(hr);
+
+#ifndef QT_WINRT_LIMITED_DRAGANDDROP
+ ComPtr<IDragStartingEventArgs2> args2;
+ hr = args->QueryInterface(IID_PPV_ARGS(&args2));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ Qt::DropActions actions = drag->supportedActions();
+ DataPackageOperation allowedOperations = DataPackageOperation_None;
+ if (actions & Qt::CopyAction)
+ allowedOperations |= DataPackageOperation_Copy;
+ if (actions & Qt::MoveAction)
+ allowedOperations |= DataPackageOperation_Move;
+ if (actions & Qt::LinkAction)
+ allowedOperations |= DataPackageOperation_Link;
+ hr = args2->put_AllowedOperations(allowedOperations);
+ Q_ASSERT_SUCCEEDED(hr);
+#endif // QT_WINRT_LIMITED_DRAGANDDROP
+ QMimeData *mimeData = drag->mimeData();
+ if (mimeData->hasText()) {
+ hr = dataPackage->SetText(qStringToHString(mimeData->text()).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ if (mimeData->hasHtml()) {
+ hr = dataPackage->SetHtmlFormat(qStringToHString(mimeData->html()).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ // ### TODO: Missing: weblink, image
+
+ if (!drag->pixmap().isNull()) {
+ const QImage image2 = drag->pixmap().toImage();
+ const QImage image = image2.convertToFormat(QImage::Format_ARGB32);
+ if (!image.isNull()) {
+ // Create IBuffer containing image
+ ComPtr<IBuffer> imageBuffer = createIBufferFromData(reinterpret_cast<const char*>(image.bits()), image.byteCount());
+
+ ComPtr<ISoftwareBitmapFactory> bitmapFactory;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Imaging_SoftwareBitmap).Get(),
+ IID_PPV_ARGS(&bitmapFactory));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<ISoftwareBitmap> bitmap;
+ hr = bitmapFactory->Create(BitmapPixelFormat_Rgba8, image.width(), image.height(), &bitmap);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = bitmap->CopyFromBuffer(imageBuffer.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IDragUI> dragUi;
+ hr = args->get_DragUI(dragUi.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = dragUi->SetContentFromSoftwareBitmap(bitmap.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ }
+
+ const QStringList formats = mimeData->formats();
+ for (auto item : formats) {
+ QByteArray data = mimeData->data(item);
+
+ ComPtr<IBuffer> buffer = createIBufferFromData(data.constData(), data.size());
+
+ // We cannot push the buffer to the data package as the result on
+ // recipient side is different from native events. It still sends a
+ // buffer, but that potentially cannot be parsed. Hence we need to create
+ // a IRandomAccessStream which gets forwarded as is to the drop side.
+ ComPtr<IRandomAccessStream> ras;
+ hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), &ras);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = ras->put_Size(data.size());
+ ComPtr<IOutputStream> outputStream;
+ hr = ras->GetOutputStreamAt(0, &outputStream);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IAsyncOperationWithProgress<UINT32,UINT32>> writeOp;
+ hr = outputStream->WriteAsync(buffer.Get(), &writeOp);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ UINT32 result;
+ hr = QWinRTFunctions::await(writeOp, &result);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ unsigned char flushResult;
+ ComPtr<IAsyncOperation<bool>> flushOp;
+ hr = outputStream->FlushAsync(&flushOp);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = QWinRTFunctions::await(flushOp, &flushResult);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = dataPackage->SetData(qStringToHString(item).Get(), ras.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ return S_OK;
+ });
+
+ hr = elem3->add_DragStarting(startingCallback.Get(), &startingToken);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = elem3->StartDragAsync(qt_winrt_lastPointerPoint.Get(), &op);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ return hr;
+ });
+ if (!op || FAILED(hr)) {
+ qCDebug(lcQpaMime) << "Drag failed:" << hr;
+ hr = resetUiElementDrag(elem3, startingToken);
+ Q_ASSERT_SUCCEEDED(hr);
+ return Qt::IgnoreAction;
+ }
+
+ DataPackageOperation nativeOperationType;
+ // Do not yield, as that can cause deadlocks when dropping inside the same app
+ hr = QWinRTFunctions::await(op, &nativeOperationType, QWinRTFunctions::ProcessThreadEvents);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = resetUiElementDrag(elem3, startingToken);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ Qt::DropAction resultAction;
+ switch (nativeOperationType) {
+ case DataPackageOperation_Link:
+ resultAction = Qt::LinkAction;
+ break;
+ case DataPackageOperation_Copy:
+ resultAction = Qt::CopyAction;
+ break;
+ case DataPackageOperation_Move:
+ resultAction = Qt::MoveAction;
+ break;
+ case DataPackageOperation_None:
+ default:
+ resultAction = Qt::IgnoreAction;
+ break;
+ }
+
+ return resultAction;
+}
+
+void QWinRTDrag::setDropTarget(QWindow *target)
+{
+ qCDebug(lcQpaMime) << __FUNCTION__ << target;
+ m_dragTarget = target;
+}
+
+QMimeData *QWinRTDrag::platformDropData()
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+ return m_mimeData;
+}
+
+void QWinRTDrag::setUiElement(ComPtr<ABI::Windows::UI::Xaml::IUIElement> &element)
+{
+ qCDebug(lcQpaMime) << __FUNCTION__;
+ m_ui = element;
+ // We set the element to always accept drops and then evaluate during
+ // runtime
+ HRESULT hr = element->put_AllowDrop(TRUE);
+ EventRegistrationToken tok;
+ hr = element->add_DragEnter(m_enter, &tok);
+ RETURN_VOID_IF_FAILED("Failed to add DragEnter handler.");
+ hr = element->add_DragOver(m_over, &tok);
+ RETURN_VOID_IF_FAILED("Failed to add DragOver handler.");
+ hr = element->add_DragLeave(m_leave, &tok);
+ RETURN_VOID_IF_FAILED("Failed to add DragLeave handler.");
+ hr = element->add_Drop(m_drop, &tok);
+ RETURN_VOID_IF_FAILED("Failed to add Drop handler.");
+}
+
+void QWinRTDrag::handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e, bool drop)
+{
+ Q_UNUSED(sender);
+
+ if (!m_dragTarget)
+ return;
+
+ HRESULT hr;
+ Point relativePoint;
+ hr = e->GetPosition(m_ui.Get(), &relativePoint);
+ RETURN_VOID_IF_FAILED("Could not query drag position.");
+ const QPoint p(relativePoint.X, relativePoint.Y);
+
+ ComPtr<IDragEventArgs2> e2;
+ hr = e->QueryInterface(IID_PPV_ARGS(&e2));
+ RETURN_VOID_IF_FAILED("Could not convert drag event args");
+
+ DragDropModifiers modifiers;
+ hr = e2->get_Modifiers(&modifiers);
+
+#ifndef QT_WINRT_LIMITED_DRAGANDDROP
+ ComPtr<IDragEventArgs3> e3;
+ hr = e->QueryInterface(IID_PPV_ARGS(&e3));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ DataPackageOperation dataOp;
+ hr = e3->get_AllowedOperations(&dataOp);
+ if (FAILED(hr))
+ qCDebug(lcQpaMime) << __FUNCTION__ << "Could not query drag operations";
+
+ const Qt::DropActions actions = translateToQDragDropActions(dataOp);
+#else // !QT_WINRT_LIMITED_DRAGANDDROP
+ const Qt::DropActions actions = Qt::LinkAction | Qt::CopyAction | Qt::MoveAction;;
+#endif // !QT_WINRT_LIMITED_DRAGANDDROP
+
+ ComPtr<IDataPackageView> dataView;
+ hr = e2->get_DataView(&dataView);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ m_mimeData->setDataView(dataView);
+
+ // We use deferral as we need to jump to the Qt thread to handle
+ // the drag event
+ ComPtr<IDragOperationDeferral> deferral;
+ hr = e2->GetDeferral(&deferral);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ DragThreadTransferData *transferData = new DragThreadTransferData;
+ transferData->moveToThread(qGuiApp->thread());
+ transferData->window = m_dragTarget;
+ transferData->point = p;
+ transferData->mime = m_mimeData;
+ transferData->actions = actions;
+ transferData->dropAction = drop;
+ transferData->nativeArgs = e;
+ transferData->deferral = deferral;
+ QMetaObject::invokeMethod(transferData, "handleDrag", Qt::QueuedConnection);
+}
+
+DragThreadTransferData::DragThreadTransferData(QObject *parent)
+ : QObject(parent)
+ , dropAction(false)
+{
+}
+
+void DragThreadTransferData::handleDrag()
+{
+ bool accepted = false;
+ Qt::DropAction acceptedAction;
+ if (dropAction) {
+ QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(window, mime, point, actions);
+ accepted = response.isAccepted();
+ acceptedAction = response.acceptedAction();
+ } else {
+ QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(window, mime, point, actions);
+ accepted = response.isAccepted();
+ acceptedAction = response.acceptedAction();
+ }
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([accepted, acceptedAction, this]() {
+ HRESULT hr;
+ hr = nativeArgs->put_Handled(accepted);
+ if (acceptedAction != Qt::IgnoreAction) {
+ ComPtr<IDragEventArgs2> e2;
+ hr = nativeArgs.As(&e2);
+ if (SUCCEEDED(hr))
+ hr = e2->put_AcceptedOperation(translateFromQDragDropActions(acceptedAction));
+ }
+ deferral->Complete();
+ return S_OK;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+ deleteLater();
+}
+
+QT_END_NAMESPACE
+
+#include "qwinrtdrag.moc"
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.h b/src/plugins/platforms/winrt/qwinrtdrag.h
new file mode 100644
index 0000000000..97079d831b
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtdrag.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformdrag.h>
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QMimeData>
+#include <QtGui/private/qdnd_p.h> // QInternalMime
+
+#include <wrl.h>
+
+namespace ABI {
+ namespace Windows {
+ namespace ApplicationModel {
+ namespace DataTransfer {
+ struct IDataPackageView;
+ }
+ }
+ namespace UI {
+ namespace Xaml {
+ struct IUIElement;
+ struct IDragEventArgs;
+ struct IDragOperationDeferral;
+ //struct IDataPackageView;
+ }
+ }
+ }
+}
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQpaMime)
+
+class QtDragEventHandlerEnter;
+class QtDragEventHandlerOver;
+class QtDragEventHandlerLeave;
+class QtDragEventHandlerDrop;
+class QWinRTInternalMimeData;
+
+class QWinRTInternalMimeData : public QInternalMimeData {
+public:
+ QWinRTInternalMimeData();
+ virtual ~QWinRTInternalMimeData();
+
+ bool hasFormat_sys(const QString &mimetype) const Q_DECL_OVERRIDE;
+ QStringList formats_sys() const Q_DECL_OVERRIDE;
+ QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const Q_DECL_OVERRIDE;
+
+ void setDataView(const Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IDataPackageView> &d);
+private:
+ Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IDataPackageView> dataView;
+ mutable QStringList formats;
+};
+
+class QWinRTDrag : public QPlatformDrag {
+public:
+ QWinRTDrag();
+ virtual ~QWinRTDrag();
+ static QWinRTDrag *instance();
+
+ QMimeData *platformDropData(void) Q_DECL_OVERRIDE;
+ Qt::DropAction drag(QDrag *) Q_DECL_OVERRIDE;
+
+ void setDropTarget(QWindow *target);
+
+ // Native integration and registration
+ void setUiElement(Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElement> &element);
+
+ void handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e, bool drop = false);
+private:
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElement> m_ui;
+ QWindow *m_dragTarget;
+ QtDragEventHandlerEnter *m_enter;
+ QtDragEventHandlerOver *m_over;
+ QtDragEventHandlerLeave *m_leave;
+ QtDragEventHandlerDrop *m_drop;
+ QWinRTInternalMimeData *m_mimeData;
+};
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp
index 8ef560ba20..42b7f7e909 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.cpp
+++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp
@@ -48,6 +48,9 @@
#include "qwinrtfontdatabase.h"
#include "qwinrttheme.h"
#include "qwinrtclipboard.h"
+#ifndef QT_NO_DRAGANDDROP
+#include "qwinrtdrag.h"
+#endif
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>
@@ -312,6 +315,17 @@ QPlatformClipboard *QWinRTIntegration::clipboard() const
return d->clipboard;
}
+#ifndef QT_NO_DRAGANDDROP
+QPlatformDrag *QWinRTIntegration::drag() const
+{
+#if _MSC_VER >= 1900
+ return QWinRTDrag::instance();
+#else
+ return QPlatformIntegration::drag();
+#endif
+}
+#endif // QT_NO_DRAGANDDROP
+
Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const
{
Q_D(const QWinRTIntegration);
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h
index 9e28beb8fa..7b4d5531fc 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.h
+++ b/src/plugins/platforms/winrt/qwinrtintegration.h
@@ -97,6 +97,10 @@ public:
QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE;
QPlatformServices *services() const Q_DECL_OVERRIDE;
QPlatformClipboard *clipboard() const Q_DECL_OVERRIDE;
+#ifndef QT_NO_DRAGANDDROP
+ QPlatformDrag *drag() const Q_DECL_OVERRIDE;
+#endif
+
Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE;
QStringList themeNames() const Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp
index aed33f6b48..ad32e63cad 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.cpp
+++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp
@@ -42,6 +42,9 @@
#include "qwinrtbackingstore.h"
#include "qwinrtinputcontext.h"
#include "qwinrtcursor.h"
+#ifndef QT_NO_DRAGANDDROP
+#include "qwinrtdrag.h"
+#endif
#include "qwinrtwindow.h"
#include <private/qeventdispatcher_winrt_p.h>
@@ -556,6 +559,9 @@ QWinRTScreen::QWinRTScreen()
ComPtr<Xaml::IUIElement> uiElement;
hr = canvas.As(&uiElement);
Q_ASSERT_SUCCEEDED(hr);
+#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP)
+ QWinRTDrag::instance()->setUiElement(uiElement);
+#endif
hr = window->put_Content(uiElement.Get());
Q_ASSERT_SUCCEEDED(hr);
hr = canvas.As(&d->canvas);
@@ -764,6 +770,10 @@ void QWinRTScreen::addWindow(QWindow *window)
QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
handleExpose();
QWindowSystemInterface::flushWindowSystemEvents();
+
+#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP)
+ QWinRTDrag::instance()->setDropTarget(window);
+#endif
}
void QWinRTScreen::removeWindow(QWindow *window)
@@ -778,6 +788,10 @@ void QWinRTScreen::removeWindow(QWindow *window)
QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
handleExpose();
QWindowSystemInterface::flushWindowSystemEvents();
+#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP)
+ if (wasTopWindow)
+ QWinRTDrag::instance()->setDropTarget(topWindow());
+#endif
}
void QWinRTScreen::raise(QWindow *window)
@@ -973,6 +987,9 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args)
return S_OK;
}
+// Required for qwinrtdrag.cpp
+ComPtr<IPointerPoint> qt_winrt_lastPointerPoint;
+
HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
{
Q_D(QWinRTScreen);
@@ -980,6 +997,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
if (FAILED(args->get_CurrentPoint(&pointerPoint)))
return E_INVALIDARG;
+ qt_winrt_lastPointerPoint = pointerPoint;
// Common traits - point, modifiers, properties
Point point;
pointerPoint->get_Position(&point);
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index 144c581015..28456f66ec 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -14,6 +14,7 @@ SOURCES = \
qwinrtbackingstore.cpp \
qwinrtclipboard.cpp \
qwinrtcursor.cpp \
+ qwinrtdrag.cpp \
qwinrteglcontext.cpp \
qwinrteventdispatcher.cpp \
qwinrtfiledialoghelper.cpp \
@@ -32,6 +33,7 @@ HEADERS = \
qwinrtbackingstore.h \
qwinrtclipboard.h \
qwinrtcursor.h \
+ qwinrtdrag.h \
qwinrteglcontext.h \
qwinrteventdispatcher.h \
qwinrtfiledialoghelper.h \
@@ -47,6 +49,15 @@ HEADERS = \
OTHER_FILES += winrt.json
+WINRT_SDK_VERSION_STRING = $$(UCRTVersion)
+WINRT_SDK_VERSION = $$member($$list($$split(WINRT_SDK_VERSION_STRING, .)), 2)
+lessThan(WINRT_SDK_VERSION, 14322): DEFINES += QT_WINRT_LIMITED_DRAGANDDROP
+
+*-msvc2013|contains(DEFINES, QT_NO_DRAGANDDROP) {
+ SOURCES -= qwinrtdrag.cpp
+ HEADERS -= qwinrtdrag.h
+}
+
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin
!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 4b0e94eda0..bc62b500e5 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtCore/QDebug>
#include "qxcbconnection.h"
@@ -264,6 +265,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
} else {
screen = createScreen(virtualDesktop, output, outputInfo.data());
qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled";
+ QHighDpiScaling::updateHighDpiScaling();
}
}
} else if (screen) {
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index 55660ce31c..0f4207c636 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -6,7 +6,7 @@ qtHaveModule(network):!contains(QT_DISABLED_FEATURES, bearermanagement): SUBDIRS
qtHaveModule(gui) {
SUBDIRS *= platforms platforminputcontexts platformthemes
!contains(QT_DISABLED_FEATURES, imageformatplugin): SUBDIRS *= imageformats
- !contains(QT_DISABLED_FEATURES, library): SUBDIRS *= generic
+ !android:!contains(QT_DISABLED_FEATURES, library): SUBDIRS *= generic
}
!winrt:!wince*:qtHaveModule(widgets):!contains(QT_DISABLED_FEATURES, printer) {
diff --git a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
index 6f5fb417c6..7e6eb7c559 100644
--- a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
+++ b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 John Layt <jlayt@kde.org>
+** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -80,6 +81,22 @@ static QPrint::InputSlot paperBinToInputSlot(int windowsId, const QString &name)
return slot;
}
+static LPDEVMODE getDevmode(HANDLE hPrinter, const QString &printerId)
+{
+ LPWSTR printerIdUtf16 = const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(printerId.utf16()));
+ // Allocate the required DEVMODE buffer
+ LONG dmSize = DocumentProperties(NULL, hPrinter, printerIdUtf16, NULL, NULL, 0);
+ if (dmSize < 0)
+ return Q_NULLPTR;
+ LPDEVMODE pDevMode = reinterpret_cast<LPDEVMODE>(malloc(dmSize));
+ // Get the default DevMode
+ LONG result = DocumentProperties(NULL, hPrinter, printerIdUtf16, pDevMode, NULL, DM_OUT_BUFFER);
+ if (result != IDOK) {
+ free(pDevMode);
+ pDevMode = Q_NULLPTR;
+ }
+ return pDevMode;
+}
QWindowsPrintDevice::QWindowsPrintDevice()
: QPlatformPrintDevice(),
@@ -197,26 +214,21 @@ QPageSize QWindowsPrintDevice::defaultPageSize() const
QPageSize pageSize;
- // Allocate the required DEVMODE buffer
- DWORD dmSize = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), NULL, NULL, 0);
- LPDEVMODE pDevMode = (LPDEVMODE)malloc(dmSize);
-
- // Get the default DevMode
- DWORD result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), pDevMode, NULL, DM_OUT_BUFFER);
-
- // Get the default paper size
- if (result == IDOK && pDevMode->dmFields & DM_PAPERSIZE) {
- // Find the supported page size that matches, in theory default should be one of them
- foreach (const QPageSize &ps, m_pageSizes) {
- if (ps.windowsId() == pDevMode->dmPaperSize) {
- pageSize = ps;
- break;
+ if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
+ // Get the default paper size
+ if (pDevMode->dmFields & DM_PAPERSIZE) {
+ // Find the supported page size that matches, in theory default should be one of them
+ foreach (const QPageSize &ps, m_pageSizes) {
+ if (ps.windowsId() == pDevMode->dmPaperSize) {
+ pageSize = ps;
+ break;
+ }
}
}
+ // Clean-up
+ free(pDevMode);
}
- // Clean-up
- free(pDevMode);
return pageSize;
}
@@ -232,20 +244,14 @@ QMarginsF QWindowsPrintDevice::printableMargins(const QPageSize &pageSize,
QScopedArrayPointer<BYTE> buffer(new BYTE[needed]);
if (GetPrinter(m_hPrinter, 2, buffer.data(), needed, &needed)) {
PPRINTER_INFO_2 info = reinterpret_cast<PPRINTER_INFO_2>(buffer.data());
- DEVMODE *devMode = info->pDevMode;
+ LPDEVMODE devMode = info->pDevMode;
bool separateDevMode = false;
if (!devMode) {
// GetPrinter() didn't include the DEVMODE. Get it a different way.
- LONG result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(),
- NULL, NULL, 0);
- devMode = (DEVMODE *)malloc(result);
- separateDevMode = true;
- result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(),
- devMode, NULL, DM_OUT_BUFFER);
- if (result != IDOK) {
- free(devMode);
+ devMode = getDevmode(m_hPrinter, m_id);
+ if (!devMode)
return margins;
- }
+ separateDevMode = true;
}
HDC pDC = CreateDC(NULL, (LPWSTR)m_id.utf16(), NULL, devMode);
@@ -297,23 +303,17 @@ int QWindowsPrintDevice::defaultResolution() const
{
int resolution = 72; // TODO Set a sensible default?
- // Allocate the required DEVMODE buffer
- DWORD dmSize = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), NULL, NULL, 0);
- LPDEVMODE pDevMode = (LPDEVMODE)malloc(dmSize);
-
- // Get the default DevMode
- DWORD result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), pDevMode, NULL, DM_OUT_BUFFER);
-
- // Get the default resolution
- if (result == IDOK && pDevMode->dmFields & DM_YRESOLUTION) {
- if (pDevMode->dmPrintQuality > 0)
- resolution = pDevMode->dmPrintQuality;
- else
- resolution = pDevMode->dmYResolution;
+ if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
+ // Get the default resolution
+ if (pDevMode->dmFields & DM_YRESOLUTION) {
+ if (pDevMode->dmPrintQuality > 0)
+ resolution = pDevMode->dmPrintQuality;
+ else
+ resolution = pDevMode->dmYResolution;
+ }
+ // Clean-up
+ free(pDevMode);
}
-
- // Clean-up
- free(pDevMode);
return resolution;
}
@@ -346,26 +346,20 @@ QPrint::InputSlot QWindowsPrintDevice::defaultInputSlot() const
{
QPrint::InputSlot inputSlot = QPlatformPrintDevice::defaultInputSlot();;
- // Allocate the required DEVMODE buffer
- DWORD dmSize = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), NULL, NULL, 0);
- LPDEVMODE pDevMode = (LPDEVMODE)malloc(dmSize);
-
- // Get the default DevMode
- DWORD result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), pDevMode, NULL, DM_OUT_BUFFER);
-
- // Get the default input slot
- if (result == IDOK && pDevMode->dmFields & DM_DEFAULTSOURCE) {
- QPrint::InputSlot tempSlot = paperBinToInputSlot(pDevMode->dmDefaultSource, QString());
- foreach (const QPrint::InputSlot &slot, supportedInputSlots()) {
- if (slot.key == tempSlot.key) {
- inputSlot = slot;
- break;
+ if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
+ // Get the default input slot
+ if (pDevMode->dmFields & DM_DEFAULTSOURCE) {
+ QPrint::InputSlot tempSlot = paperBinToInputSlot(pDevMode->dmDefaultSource, QString());
+ foreach (const QPrint::InputSlot &slot, supportedInputSlots()) {
+ if (slot.key == tempSlot.key) {
+ inputSlot = slot;
+ break;
+ }
}
}
+ // Clean-up
+ free(pDevMode);
}
-
- // Clean-up
- free(pDevMode);
return inputSlot;
}
@@ -392,23 +386,17 @@ QPrint::DuplexMode QWindowsPrintDevice::defaultDuplexMode() const
{
QPrint::DuplexMode duplexMode = QPrint::DuplexNone;
- // Allocate the required DEVMODE buffer
- DWORD dmSize = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), NULL, NULL, 0);
- LPDEVMODE pDevMode = (LPDEVMODE)malloc(dmSize);
-
- // Get the default DevMode
- DWORD result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), pDevMode, NULL, DM_OUT_BUFFER);
-
- // Get the default duplex mode
- if (result == IDOK && pDevMode->dmFields & DM_DUPLEX) {
- if (pDevMode->dmDuplex == DMDUP_VERTICAL)
- duplexMode = QPrint::DuplexLongSide;
- else if (pDevMode->dmDuplex == DMDUP_HORIZONTAL)
- duplexMode = QPrint::DuplexShortSide;
+ if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
+ // Get the default duplex mode
+ if (pDevMode->dmFields & DM_DUPLEX) {
+ if (pDevMode->dmDuplex == DMDUP_VERTICAL)
+ duplexMode = QPrint::DuplexLongSide;
+ else if (pDevMode->dmDuplex == DMDUP_HORIZONTAL)
+ duplexMode = QPrint::DuplexShortSide;
+ }
+ // Clean-up
+ free(pDevMode);
}
-
- // Clean-up
- free(pDevMode);
return duplexMode;
}
@@ -430,21 +418,13 @@ QPrint::ColorMode QWindowsPrintDevice::defaultColorMode() const
QPrint::ColorMode colorMode = QPrint::GrayScale;
- // Allocate the required DEVMODE buffer
- DWORD dmSize = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), NULL, NULL, 0);
- LPDEVMODE pDevMode = (LPDEVMODE)malloc(dmSize);
-
- // Get the default DevMode
- DWORD result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), pDevMode, NULL, DM_OUT_BUFFER);
-
- // Get the default color mode
- if (result == IDOK && pDevMode->dmFields & DM_COLOR) {
- if (pDevMode->dmColor == DMCOLOR_COLOR)
+ if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
+ // Get the default color mode
+ if (pDevMode->dmFields & DM_COLOR && pDevMode->dmColor == DMCOLOR_COLOR)
colorMode = QPrint::Color;
+ // Clean-up
+ free(pDevMode);
}
-
- // Clean-up
- free(pDevMode);
return colorMode;
}
diff --git a/src/testlib/doc/qttestlib.qdocconf b/src/testlib/doc/qttestlib.qdocconf
index 0fafc733b1..899f94ec53 100644
--- a/src/testlib/doc/qttestlib.qdocconf
+++ b/src/testlib/doc/qttestlib.qdocconf
@@ -4,7 +4,7 @@ project = QtTestLib
description = Qt Test Reference Documentation
version = $QT_VERSION
-examplesinstallpath = testlib
+examplesinstallpath = qtestlib
qhp.projects = QtTestLib
diff --git a/src/testlib/doc/src/qttestlib-manual.qdoc b/src/testlib/doc/src/qttestlib-manual.qdoc
index 62cc6c9654..fc8f3b747e 100644
--- a/src/testlib/doc/src/qttestlib-manual.qdoc
+++ b/src/testlib/doc/src/qttestlib-manual.qdoc
@@ -487,6 +487,7 @@
\nextpage {Chapter 2: Data Driven Testing}{Chapter 2}
\title Chapter 1: Writing a Unit Test
+ \brief How to write a unit test.
In this first chapter we will see how to write a simple unit test
for a class, and how to execute it.
@@ -562,6 +563,7 @@
\nextpage {Chapter 3: Simulating Gui Events}{Chapter 3}
\title Chapter 2: Data Driven Testing
+ \brief How to create data driven tests.
In this chapter we will demonstrate how to execute a test
multiple times with different test data.
@@ -667,6 +669,7 @@
\nextpage {Chapter 4: Replaying GUI Events}{Chapter 4}
\title Chapter 3: Simulating GUI Events
+ \brief Howe to simulate GUI events.
Qt Test features some mechanisms to test graphical user
interfaces. Instead of simulating native window system events,
@@ -727,6 +730,7 @@
\nextpage {Chapter 5: Writing a Benchmark}{Chapter 5}
\title Chapter 4: Replaying GUI Events
+ \brief How to replay GUI events.
In this chapter, we will show how to simulate a GUI event,
and how to store a series of GUI events as well as replay them on
@@ -806,6 +810,7 @@
\contentspage {Qt Test Tutorial}{Contents}
\title Chapter 5: Writing a Benchmark
+ \brief How to write a benchmark.
In this final chapter we will demonstrate how to write benchmarks
using Qt Test.
diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp
index 4ef2dd3f67..05ad5cef5b 100644
--- a/src/testlib/qtestblacklist.cpp
+++ b/src/testlib/qtestblacklist.cpp
@@ -52,21 +52,38 @@
QT_BEGIN_NAMESPACE
/*
- The file format is simply a grouped listing of keywords
- Ungrouped entries at the beginning apply to the whole testcase
- Groups define testfunctions or specific test data to ignore.
- After the groups come a list of entries (one per line) that define
- for which platform/os combination to ignore the test result.
- All keys in a single line have to match to blacklist the test.
-
- mac
- [testFunction]
- linux
- windows 64bit
- [testfunction2:testData]
- msvc
-
- The known keys are listed below:
+ The BLACKLIST file format is a grouped listing of keywords.
+
+ Blank lines and lines starting with # are simply ignored. An initial #-line
+ referring to this documentation is kind to readers. Comments can also be used
+ to indicate the reasons for ignoring particular cases.
+
+ A key names a platform, O/S, distribution, tool-chain or architecture; a !
+ prefix reverses what it checks. A version, joined to a key (at present, only
+ for distributions and for msvc) with a hyphen, limits the key to the specific
+ version. A keyword line matches if every key on it applies to the present
+ run. Successive lines are alternate conditions for ignoring a test.
+
+ Ungrouped lines at the beginning of a file apply to the whole testcase.
+ A group starts with a [square-bracketed] identification of a test function,
+ optionally with (after a colon, the name of) a specific data set, to ignore.
+ Subsequent lines give conditions for ignoring this test.
+
+ # See qtbase/src/testlib/qtestblacklist.cpp for format
+ osx
+
+ # QTBUG-12345
+ [testFunction]
+ linux
+ windows 64bit
+
+ # Needs basic C++11 support
+ [testfunction2:testData]
+ msvc-2010
+
+ Keys are lower-case. Distribution name and version are supported if
+ QSysInfo's productType() and productVersion() return them.
+ The other known keys are listed below:
*/
static QSet<QByteArray> keywords()
@@ -148,19 +165,30 @@ static QSet<QByteArray> keywords()
return set;
}
-static bool checkCondition(const QByteArray &condition)
+static QSet<QByteArray> activeConditions()
{
- static QSet<QByteArray> matchedConditions = keywords();
- QList<QByteArray> conds = condition.split(' ');
+ QSet<QByteArray> result = keywords();
QByteArray distributionName = QSysInfo::productType().toLower().toUtf8();
QByteArray distributionRelease = QSysInfo::productVersion().toLower().toUtf8();
if (!distributionName.isEmpty()) {
- if (matchedConditions.find(distributionName) == matchedConditions.end())
- matchedConditions.insert(distributionName);
- matchedConditions.insert(distributionName + "-" + distributionRelease);
+ if (result.find(distributionName) == result.end())
+ result.insert(distributionName);
+ if (!distributionRelease.isEmpty()) {
+ QByteArray versioned = distributionName + "-" + distributionRelease;
+ if (result.find(versioned) == result.end())
+ result.insert(versioned);
+ }
}
+ return result;
+}
+
+static bool checkCondition(const QByteArray &condition)
+{
+ static const QSet<QByteArray> matchedConditions = activeConditions();
+ QList<QByteArray> conds = condition.split(' ');
+
for (int i = 0; i < conds.size(); ++i) {
QByteArray c = conds.at(i);
bool result = c.startsWith('!');
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index dcd1268f6f..2231f12e2d 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -1258,7 +1258,7 @@ static bool debuggerPresent()
if (fd == -1)
return false;
char buffer[2048];
- ssize_t size = read(fd, buffer, sizeof(buffer));
+ ssize_t size = read(fd, buffer, sizeof(buffer) - 1);
if (size == -1) {
close(fd);
return false;
diff --git a/src/widgets/dialogs/qdialog.cpp b/src/widgets/dialogs/qdialog.cpp
index 5eb6130a45..8f3072e41c 100644
--- a/src/widgets/dialogs/qdialog.cpp
+++ b/src/widgets/dialogs/qdialog.cpp
@@ -871,6 +871,12 @@ void QDialog::adjustPosition(QWidget* w)
if (p.y() < desk.y())
p.setY(desk.y());
+ // QTBUG-52735: Manually set the correct target screen since scaling in a
+ // subsequent call to QWindow::resize() may otherwise use the wrong factor
+ // if the screen changed notification is still in an event queue.
+ if (QWindow *window = windowHandle())
+ window->setScreen(QGuiApplication::screens().at(scrn));
+
move(p);
}
diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp
index 9bb4497811..26dd49f8cf 100644
--- a/src/widgets/itemviews/qabstractitemview.cpp
+++ b/src/widgets/itemviews/qabstractitemview.cpp
@@ -3671,6 +3671,9 @@ void QAbstractItemView::startDrag(Qt::DropActions supportedActions)
defaultDropAction = Qt::CopyAction;
if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction)
d->clearOrRemove();
+ // Reset the drop indicator
+ d->dropIndicatorRect = QRect();
+ d->dropIndicatorPosition = OnItem;
}
}
#endif // QT_NO_DRAGANDDROP
diff --git a/src/widgets/kernel/qdesktopwidget.cpp b/src/widgets/kernel/qdesktopwidget.cpp
index fceb061867..ece673337a 100644
--- a/src/widgets/kernel/qdesktopwidget.cpp
+++ b/src/widgets/kernel/qdesktopwidget.cpp
@@ -46,6 +46,21 @@
QT_BEGIN_NAMESPACE
+QDesktopScreenWidget::QDesktopScreenWidget(QScreen *screen, const QRect &geometry)
+ : QWidget(Q_NULLPTR, Qt::Desktop), m_screen(screen)
+{
+ setVisible(false);
+ if (QWindow *winHandle = windowHandle())
+ winHandle->setScreen(screen);
+ setScreenGeometry(geometry);
+}
+
+void QDesktopScreenWidget::setScreenGeometry(const QRect &geometry)
+{
+ m_geometry = geometry;
+ setGeometry(geometry);
+}
+
int QDesktopScreenWidget::screenNumber() const
{
const QDesktopWidgetPrivate *desktopWidgetP
@@ -80,54 +95,76 @@ const QRect QDesktopWidget::availableGeometry(const QWidget *widget) const
return rect;
}
+QDesktopScreenWidget *QDesktopWidgetPrivate::widgetForScreen(QScreen *qScreen) const
+{
+ foreach (QDesktopScreenWidget *widget, screens) {
+ if (widget->screen() == qScreen)
+ return widget;
+ }
+ return Q_NULLPTR;
+}
+
void QDesktopWidgetPrivate::_q_updateScreens()
{
Q_Q(QDesktopWidget);
const QList<QScreen *> screenList = QGuiApplication::screens();
const int targetLength = screenList.length();
- const int oldLength = screens.length();
-
- // Add or remove screen widgets as necessary
- while (screens.size() > targetLength)
- delete screens.takeLast();
-
- for (int currentLength = screens.size(); currentLength < targetLength; ++currentLength) {
- QScreen *qScreen = screenList.at(currentLength);
- QDesktopScreenWidget *screenWidget = new QDesktopScreenWidget;
- screenWidget->setGeometry(qScreen->geometry());
- QObject::connect(qScreen, SIGNAL(geometryChanged(QRect)),
- q, SLOT(_q_updateScreens()), Qt::QueuedConnection);
- QObject::connect(qScreen, SIGNAL(availableGeometryChanged(QRect)),
- q, SLOT(_q_availableGeometryChanged()), Qt::QueuedConnection);
- QObject::connect(qScreen, SIGNAL(destroyed()),
- q, SLOT(_q_updateScreens()), Qt::QueuedConnection);
- screens.append(screenWidget);
- }
+ bool screenCountChanged = false;
+ // Re-build our screens list. This is the easiest way to later compute which signals to emit.
+ // Create new screen widgets as necessary. While iterating, keep the old list in place so
+ // that widgetForScreen works.
+ // Furthermore, we note which screens have changed, and compute the overall virtual geometry.
+ QList<QDesktopScreenWidget *> newScreens;
+ QList<int> changedScreens;
QRegion virtualGeometry;
- // update the geometry of each screen widget, determine virtual geometry,
- // set the new screen for window handle and emit change signals afterwards.
- QList<int> changedScreens;
- for (int i = 0; i < screens.length(); i++) {
- QDesktopScreenWidget *screenWidget = screens.at(i);
+ for (int i = 0; i < targetLength; ++i) {
QScreen *qScreen = screenList.at(i);
- QWindow *winHandle = screenWidget->windowHandle();
- if (winHandle && winHandle->screen() != qScreen)
- winHandle->setScreen(qScreen);
const QRect screenGeometry = qScreen->geometry();
- if (screenGeometry != screenWidget->geometry()) {
- screenWidget->setGeometry(screenGeometry);
- changedScreens.push_back(i);
+ QDesktopScreenWidget *screenWidget = widgetForScreen(qScreen);
+ if (screenWidget) {
+ // an old screen. update geometry and remember the index in the *new* list
+ if (screenGeometry != screenWidget->screenGeometry()) {
+ screenWidget->setScreenGeometry(screenGeometry);
+ changedScreens.push_back(i);
+ }
+ } else {
+ // a new screen, create a widget and connect the signals.
+ screenWidget = new QDesktopScreenWidget(qScreen, screenGeometry);
+ QObject::connect(qScreen, SIGNAL(geometryChanged(QRect)),
+ q, SLOT(_q_updateScreens()), Qt::QueuedConnection);
+ QObject::connect(qScreen, SIGNAL(availableGeometryChanged(QRect)),
+ q, SLOT(_q_availableGeometryChanged()), Qt::QueuedConnection);
+ QObject::connect(qScreen, SIGNAL(destroyed()),
+ q, SLOT(_q_updateScreens()), Qt::QueuedConnection);
+ screenCountChanged = true;
}
+ // record all the screens and the overall geometry.
+ newScreens.push_back(screenWidget);
virtualGeometry += screenGeometry;
}
+ // Now we apply the accumulated updates.
+ screens.swap(newScreens); // now [newScreens] is the old screen list
+ Q_ASSERT(screens.size() == targetLength);
q->setGeometry(virtualGeometry.boundingRect());
- if (oldLength != targetLength)
- emit q->screenCountChanged(targetLength);
+ // Delete the QDesktopScreenWidget that are not used any more.
+ foreach (QDesktopScreenWidget *screen, newScreens) {
+ if (!screens.contains(screen)) {
+ delete screen;
+ screenCountChanged = true;
+ }
+ }
+ // Finally, emit the signals.
+ if (screenCountChanged) {
+ // Notice that we trigger screenCountChanged even if a screen was removed and another one added,
+ // in which case the total number of screens did not change. This is the only way for applications
+ // to notice that a screen was swapped out against another one.
+ emit q->screenCountChanged(targetLength);
+ }
foreach (int changedScreen, changedScreens)
emit q->resized(changedScreen);
}
diff --git a/src/widgets/kernel/qdesktopwidget_p.h b/src/widgets/kernel/qdesktopwidget_p.h
index 7c68ad9b31..a590024b7c 100644
--- a/src/widgets/kernel/qdesktopwidget_p.h
+++ b/src/widgets/kernel/qdesktopwidget_p.h
@@ -61,12 +61,19 @@ QT_BEGIN_NAMESPACE
class QDesktopScreenWidget : public QWidget {
Q_OBJECT
public:
- QDesktopScreenWidget() : QWidget(Q_NULLPTR, Qt::Desktop)
- {
- setVisible(false);
- }
+ explicit QDesktopScreenWidget(QScreen *screen, const QRect &geometry);
int screenNumber() const;
+ void setScreenGeometry(const QRect &geometry);
+
+ QScreen *screen() const { return m_screen.data(); }
+ QRect screenGeometry() const { return m_geometry; }
+
+private:
+ // The widget updates its screen and geometry automatically. We need to save them separately
+ // to detect changes, and trigger the appropriate signals.
+ const QPointer<QScreen> m_screen;
+ QRect m_geometry;
};
class QDesktopWidgetPrivate : public QWidgetPrivate {
@@ -76,6 +83,7 @@ public:
~QDesktopWidgetPrivate() { qDeleteAll(screens); }
void _q_updateScreens();
void _q_availableGeometryChanged();
+ QDesktopScreenWidget *widgetForScreen(QScreen *qScreen) const;
QList<QDesktopScreenWidget *> screens;
};
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp
index 5071c56763..124c8c000a 100644
--- a/src/widgets/kernel/qopenglwidget.cpp
+++ b/src/widgets/kernel/qopenglwidget.cpp
@@ -910,8 +910,10 @@ void QOpenGLWidgetPrivate::resizeViewportFramebuffer()
if (!initialized)
return;
- if (!fbo || q->size() * q->devicePixelRatioF() != fbo->size())
+ if (!fbo || q->size() * q->devicePixelRatioF() != fbo->size()) {
recreateFbo();
+ q->update();
+ }
}
/*!
diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp
index 9025160e5c..bb6f3316d6 100644
--- a/src/widgets/kernel/qwidgetbackingstore.cpp
+++ b/src/widgets/kernel/qwidgetbackingstore.cpp
@@ -1006,8 +1006,18 @@ static QPlatformTextureList *widgetTexturesFor(QWidget *tlw, QWidget *widget)
static bool switchableWidgetComposition =
QGuiApplicationPrivate::instance()->platformIntegration()
->hasCapability(QPlatformIntegration::SwitchableWidgetComposition);
- if (!switchableWidgetComposition)
+ if (!switchableWidgetComposition
+// The Windows compositor handles fullscreen OpenGL window specially. Besides
+// having trouble with popups, it also has issues with flip-flopping between
+// OpenGL-based and normal flushing. Therefore, stick with GL for fullscreen
+// windows. (QTBUG-53515)
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) && !defined(Q_OS_WINCE)
+ || tlw->windowState().testFlag(Qt::WindowFullScreen)
+#endif
+ )
+ {
return qt_dummy_platformTextureList();
+ }
}
return 0;
@@ -1207,10 +1217,20 @@ void QWidgetBackingStore::doSync()
// We know for sure that the widget isn't overlapped if 'isMoved' is true.
if (!wd->isMoved)
wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove);
+
+ // Make a copy of the widget's dirty region, to restore it in case there is an opaque
+ // render-to-texture child that completely covers the widget, because otherwise the
+ // render-to-texture child won't be visible, due to its parent widget not being redrawn
+ // with a proper blending mask.
+ const QRegion dirtyBeforeSubtractedOpaqueChildren = wd->dirty;
+
// Scrolled and moved widgets must draw all children.
if (!wd->isScrolled && !wd->isMoved)
wd->subtractOpaqueChildren(wd->dirty, w->rect());
+ if (wd->dirty.isEmpty() && wd->textureChildSeen)
+ wd->dirty = dirtyBeforeSubtractedOpaqueChildren;
+
if (wd->dirty.isEmpty()) {
resetWidget(w);
continue;
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index 675d54f6b4..2a4f31babf 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -883,14 +883,8 @@ void QWidgetWindow::handleExposeEvent(QExposeEvent *event)
{
if (isExposed()) {
m_widget->setAttribute(Qt::WA_Mapped);
- if (!event->region().isNull()) {
- // Exposed native widgets need to be marked dirty to get them repainted correctly.
- if (m_widget->internalWinId() && !m_widget->isWindow() && m_widget->isVisible() && m_widget->updatesEnabled()) {
- if (QWidgetBackingStore *bs = m_widget->d_func()->maybeBackingStore())
- bs->markDirty(event->region(), m_widget);
- }
+ if (!event->region().isNull())
m_widget->d_func()->syncBackingStore(event->region());
- }
} else {
m_widget->setAttribute(Qt::WA_Mapped, false);
}
diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp
index 86903dc0c3..e01c8f536e 100644
--- a/src/widgets/widgets/qwidgetlinecontrol.cpp
+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp
@@ -717,7 +717,7 @@ bool QWidgetLineControl::finishChange(int validateFromState, bool update, bool e
if (m_transactions.count())
return false;
internalUndo(validateFromState);
- m_history.resize(m_undoState);
+ m_history.erase(m_history.begin() + m_undoState, m_history.end());
if (m_modifiedState > m_undoState)
m_modifiedState = -1;
m_validInput = true;
@@ -796,14 +796,14 @@ void QWidgetLineControl::internalSetText(const QString &txt, int pos, bool edite
*/
void QWidgetLineControl::addCommand(const Command &cmd)
{
- if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
- m_history.resize(m_undoState + 2);
- m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
- } else {
- m_history.resize(m_undoState + 1);
- }
+ m_history.erase(m_history.begin() + m_undoState, m_history.end());
+
+ if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator)
+ m_history.push_back(Command(Separator, m_cursor, 0, m_selstart, m_selend));
+
m_separator = false;
- m_history[m_undoState++] = cmd;
+ m_history.push_back(cmd);
+ m_undoState = int(m_history.size());
}
/*!
@@ -1957,7 +1957,7 @@ bool QWidgetLineControl::isRedoAvailable() const
// Same as with undo. Disabled for password modes.
return !m_readOnly
&& m_echoMode == QLineEdit::Normal
- && m_undoState < m_history.size();
+ && m_undoState < int(m_history.size());
}
QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h
index 34d19d1e77..5e52e29a51 100644
--- a/src/widgets/widgets/qwidgetlinecontrol_p.h
+++ b/src/widgets/widgets/qwidgetlinecontrol_p.h
@@ -67,6 +67,8 @@
#include "qplatformdefs.h"
+#include <vector>
+
#ifdef DrawText
# undef DrawText
#endif
@@ -469,7 +471,6 @@ private:
// undo/redo handling
enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection };
struct Command {
- inline Command() {}
inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {}
uint type : 4;
QChar uc;
@@ -477,7 +478,7 @@ private:
};
int m_modifiedState;
int m_undoState;
- QVector<Command> m_history;
+ std::vector<Command> m_history;
void addCommand(const Command& cmd);
inline void separate() { m_separator = true; }