summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qglobal.cpp4
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp3
-rw-r--r--src/corelib/io/qloggingcategory.cpp8
-rw-r--r--src/gui/kernel/qevent.cpp7
-rw-r--r--src/network/access/qhttpmultipart.cpp2
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp8
-rw-r--r--src/network/access/qnetworkcookiejar.cpp2
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp88
-rw-r--r--src/network/access/qnetworkreplyhttpimpl_p.h4
-rw-r--r--src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp2
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp20
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro11
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm31
-rw-r--r--src/plugins/platforms/direct2d/direct2d.pro3
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.cpp22
-rw-r--r--src/plugins/platforms/windows/windows.pro3
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp4
-rw-r--r--src/widgets/kernel/qshortcut.cpp4
-rw-r--r--tests/auto/auto.pro5
-rw-r--r--tests/auto/corelib/global/qlogging/BLACKLIST3
-rw-r--r--tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp11
-rw-r--r--tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp236
-rw-r--r--tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp28
24 files changed, 407 insertions, 106 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index f2f807e1d9..36b7560398 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -4296,6 +4296,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*!
\macro qDebug(const char *message, ...)
\relates <QtGlobal>
+ \threadsafe
Calls the message handler with the debug message \a message. If no
message handler has been installed, the message is printed to
@@ -4332,6 +4333,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*!
\macro qInfo(const char *message, ...)
\relates <QtGlobal>
+ \threadsafe
\since 5.5
Calls the message handler with the informational message \a message. If no
@@ -4369,6 +4371,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*!
\macro qWarning(const char *message, ...)
\relates <QtGlobal>
+ \threadsafe
Calls the message handler with the warning message \a message. If no
message handler has been installed, the message is printed to
@@ -4406,6 +4409,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*!
\macro qCritical(const char *message, ...)
\relates <QtGlobal>
+ \threadsafe
Calls the message handler with the critical message \a message. If no
message handler has been installed, the message is printed to
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 35ddb41215..944ca232ee 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -595,6 +595,9 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
params.dwSize = sizeof(params);
params.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
params.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;
+ params.dwSecurityQosFlags = SECURITY_ANONYMOUS;
+ params.lpSecurityAttributes = NULL;
+ params.hTemplateFile = NULL;
const HANDLE handle =
CreateFile2((const wchar_t*)entry.nativeFilePath().utf16(), 0,
FILE_SHARE_READ, OPEN_EXISTING, &params);
diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp
index 4256d4b6e1..b029274329 100644
--- a/src/corelib/io/qloggingcategory.cpp
+++ b/src/corelib/io/qloggingcategory.cpp
@@ -445,6 +445,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*!
\macro qCDebug(category)
\relates QLoggingCategory
+ \threadsafe
\since 5.2
Returns an output stream for debug messages in the logging category
@@ -469,6 +470,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*!
\macro qCDebug(category, const char *message, ...)
\relates QLoggingCategory
+ \threadsafe
\since 5.3
Logs a debug message \a message in the logging category \a category.
@@ -490,6 +492,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*!
\macro qCInfo(category)
\relates QLoggingCategory
+ \threadsafe
\since 5.5
Returns an output stream for informational messages in the logging category
@@ -514,6 +517,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*!
\macro qCInfo(category, const char *message, ...)
\relates QLoggingCategory
+ \threadsafe
\since 5.5
Logs an informational message \a message in the logging category \a category.
@@ -535,6 +539,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*!
\macro qCWarning(category)
\relates QLoggingCategory
+ \threadsafe
\since 5.2
Returns an output stream for warning messages in the logging category
@@ -559,6 +564,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*!
\macro qCWarning(category, const char *message, ...)
\relates QLoggingCategory
+ \threadsafe
\since 5.3
Logs a warning message \a message in the logging category \a category.
@@ -580,6 +586,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*!
\macro qCCritical(category)
\relates QLoggingCategory
+ \threadsafe
\since 5.2
Returns an output stream for critical messages in the logging category
@@ -604,6 +611,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*!
\macro qCCritical(category, const char *message, ...)
\relates QLoggingCategory
+ \threadsafe
\since 5.3
Logs a critical message \a message in the logging category \a category.
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 1b03801ffc..916b13df44 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -2335,6 +2335,13 @@ QVariant QInputMethodQueryEvent::value(Qt::InputMethodQuery query) const
cursor and touchpad. Qt recognizes these by their names. Otherwise, if the
tablet is configured to use the evdev driver, there will be only one device
and applications may not be able to distinguish the stylus from the eraser.
+
+ \section1 Notes for Windows Users
+
+ Tablet support currently requires the WACOM windows driver providing the DLL
+ \c{wintab32.dll} to be installed. It is contained in older packages,
+ for example \c{pentablet_5.3.5-3.exe}.
+
*/
/*!
diff --git a/src/network/access/qhttpmultipart.cpp b/src/network/access/qhttpmultipart.cpp
index 303c145394..58d306d5f9 100644
--- a/src/network/access/qhttpmultipart.cpp
+++ b/src/network/access/qhttpmultipart.cpp
@@ -476,6 +476,8 @@ bool QHttpMultiPartIODevice::isSequential() const
bool QHttpMultiPartIODevice::reset()
{
+ // Reset QIODevice's data
+ QIODevice::reset();
for (int a = 0; a < multiPart->parts.count(); a++)
if (!multiPart->parts[a].d->reset())
return false;
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 52dd86cd1e..2dc3f80998 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -607,8 +607,14 @@ void QHttpNetworkConnectionChannel::handleStatus()
if (redirectUrl.isValid())
reply->setRedirectUrl(redirectUrl);
- if (qobject_cast<QHttpNetworkConnection *>(connection))
+ if ((statusCode == 307 || statusCode == 308) && !resetUploadData()) {
+ // Couldn't reset the upload data, which means it will be unable to POST the data -
+ // this would lead to a long wait until it eventually failed and then retried.
+ // Instead of doing that we fail here instead, resetUploadData will already have emitted
+ // a ContentReSendError, so we're done.
+ } else if (qobject_cast<QHttpNetworkConnection *>(connection)) {
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ }
break;
}
case 401: // auth required
diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp
index 232c2b47a5..f62a03b11d 100644
--- a/src/network/access/qnetworkcookiejar.cpp
+++ b/src/network/access/qnetworkcookiejar.cpp
@@ -140,7 +140,7 @@ void QNetworkCookieJar::setAllCookies(const QList<QNetworkCookie> &cookieList)
static inline bool isParentPath(const QString &path, const QString &reference)
{
- if (path.startsWith(reference)) {
+ if ((path.isEmpty() && reference == QLatin1String("/")) || path.startsWith(reference)) {
//The cookie-path and the request-path are identical.
if (path.length() == reference.length())
return true;
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index c1575bc812..1e68ee52dc 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -165,6 +165,16 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
}
}
+#if QT_CONFIG(bearermanagement)
+static bool isSessionNeeded(const QUrl &url)
+{
+ // Connections to the local machine does not require a session
+ QString host = url.host().toLower();
+ return !QHostAddress(host).isLoopback() && host != QLatin1String("localhost")
+ && host != QSysInfo::machineHostName().toLower();
+}
+#endif // bearer management
+
QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manager,
const QNetworkRequest& request,
QNetworkAccessManager::Operation& operation,
@@ -1109,10 +1119,15 @@ QNetworkAccessManager::Operation QNetworkReplyHttpImplPrivate::getRedirectOperat
switch (currentOp) {
case QNetworkAccessManager::HeadOperation:
return QNetworkAccessManager::HeadOperation;
+ case QNetworkAccessManager::PostOperation:
+ // We MUST keep using POST when being redirected with 307 or 308.
+ if (statusCode == 307 || statusCode == 308)
+ return QNetworkAccessManager::PostOperation;
+ break;
default:
break;
}
- // For now, we're always returning GET for anything other than HEAD
+ // Use GET for everything else.
return QNetworkAccessManager::GetOperation;
}
@@ -1187,11 +1202,30 @@ void QNetworkReplyHttpImplPrivate::followRedirect()
{
Q_Q(QNetworkReplyHttpImpl);
+ rawHeaders.clear();
cookedHeaders.clear();
if (managerPrivate->thread)
managerPrivate->thread->disconnect();
+#if QT_CONFIG(bearermanagement)
+ // If the original request didn't need a session (i.e. it was to localhost)
+ // then we might not have a session open, to which to redirect, if the
+ // new URL is remote. When this happens, we need to open the session now:
+ if (managerPrivate && isSessionNeeded(url)) {
+ if (auto session = managerPrivate->getNetworkSession()) {
+ if (session->state() != QNetworkSession::State::Connected || !session->isOpen()) {
+ startWaitForSession(session);
+ // Need to set 'request' to the redirectRequest so that when QNAM restarts
+ // the request after the session starts it will not repeat the previous request.
+ request = redirectRequest;
+ // Return now, QNAM will start the request when the session has started.
+ return;
+ }
+ }
+ }
+#endif // bearer management
+
QMetaObject::invokeMethod(q, "start", Qt::QueuedConnection,
Q_ARG(QNetworkRequest, redirectRequest));
}
@@ -1776,10 +1810,8 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest)
}
// This is not ideal.
- const QString host = url.host();
- if (host == QLatin1String("localhost") ||
- QHostAddress(host).isLoopback()) {
- // Don't need an open session for localhost access.
+ if (!isSessionNeeded(url)) {
+ // Don't need to check for an open session if we don't need one.
postRequest(newHttpRequest);
return true;
}
@@ -1803,6 +1835,34 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest)
#endif
}
+#if QT_CONFIG(bearermanagement)
+bool QNetworkReplyHttpImplPrivate::startWaitForSession(QSharedPointer<QNetworkSession> &session)
+{
+ Q_Q(QNetworkReplyHttpImpl);
+ state = WaitingForSession;
+
+ if (session) {
+ QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)),
+ q, SLOT(_q_networkSessionFailed()), Qt::QueuedConnection);
+
+ if (!session->isOpen()) {
+ QVariant isBackground = request.attribute(QNetworkRequest::BackgroundRequestAttribute,
+ QVariant::fromValue(false));
+ session->setSessionProperty(QStringLiteral("ConnectInBackground"), isBackground);
+ session->open();
+ }
+ return true;
+ }
+ const Qt::ConnectionType connection = synchronous ? Qt::DirectConnection : Qt::QueuedConnection;
+ qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
+ QMetaObject::invokeMethod(q, "_q_error", connection,
+ Q_ARG(QNetworkReply::NetworkError, QNetworkReply::NetworkSessionFailedError),
+ Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "Network session error.")));
+ QMetaObject::invokeMethod(q, "_q_finished", connection);
+ return false;
+}
+#endif // QT_CONFIG(bearermanagement)
+
void QNetworkReplyHttpImplPrivate::_q_startOperation()
{
Q_Q(QNetworkReplyHttpImpl);
@@ -1830,24 +1890,8 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation()
// backend failed to start because the session state is not Connected.
// QNetworkAccessManager will call reply->backend->start() again for us when the session
// state changes.
- state = WaitingForSession;
-
- if (session) {
- QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)),
- q, SLOT(_q_networkSessionFailed()), Qt::QueuedConnection);
-
- if (!session->isOpen()) {
- session->setSessionProperty(QStringLiteral("ConnectInBackground"), isBackground);
- session->open();
- }
- } else {
- qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
- QMetaObject::invokeMethod(q, "_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection,
- Q_ARG(QNetworkReply::NetworkError, QNetworkReply::NetworkSessionFailedError),
- Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "Network session error.")));
- QMetaObject::invokeMethod(q, "_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection);
+ if (!startWaitForSession(session))
return;
- }
} else if (session) {
QObject::connect(session.data(), SIGNAL(stateChanged(QNetworkSession::State)),
q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)),
diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
index 26b16e8386..9d47f65ce7 100644
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
@@ -161,6 +161,10 @@ signals:
class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate
{
+#if QT_CONFIG(bearermanagement)
+ bool startWaitForSession(QSharedPointer<QNetworkSession> &session);
+#endif
+
public:
static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& prio);
diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
index 809aa68365..b5a0a5bbeb 100644
--- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
+++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
@@ -520,7 +520,7 @@ static inline int fromBase8(const char *s, const char *end)
{
int result = 0;
while (*s && s != end) {
- if (*s <= '0' || *s >= '7')
+ if (*s < '0' || *s > '7')
return 0;
result *= 8;
result += *s - '0';
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp
index 06624415d3..e4d670239f 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/androidjniaccessibility.cpp
@@ -104,11 +104,11 @@ namespace QtAndroidAccessibility
static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId)
{
QAccessibleInterface *iface = interfaceFromId(objectId);
- if (iface) {
+ if (iface && iface->isValid()) {
jintArray jArray = env->NewIntArray(jsize(iface->childCount()));
for (int i = 0; i < iface->childCount(); ++i) {
QAccessibleInterface *child = iface->child(i);
- if (child) {
+ if (child && child->isValid()) {
QAccessible::Id ifaceId = QAccessible::uniqueId(child);
jint jid = ifaceId;
env->SetIntArrayRegion(jArray, i, 1, &jid);
@@ -123,9 +123,9 @@ namespace QtAndroidAccessibility
static jint parentId(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
{
QAccessibleInterface *iface = interfaceFromId(objectId);
- if (iface) {
+ if (iface && iface->isValid()) {
QAccessibleInterface *parent = iface->parent();
- if (parent) {
+ if (parent && parent->isValid()) {
if (parent->role() == QAccessible::Application)
return -1;
return QAccessible::uniqueId(parent);
@@ -151,7 +151,7 @@ namespace QtAndroidAccessibility
static jint hitTest(JNIEnv */*env*/, jobject /*thiz*/, jfloat x, jfloat y)
{
QAccessibleInterface *root = interfaceFromId(-1);
- if (root) {
+ if (root && root->isValid()) {
QPoint pos = QHighDpi::fromNativePixels(QPoint(int(x), int(y)), root->window());
QAccessibleInterface *child = root->childAt(pos.x(), pos.y());
@@ -170,7 +170,7 @@ namespace QtAndroidAccessibility
{
// qDebug() << "A11Y: CLICK: " << objectId;
QAccessibleInterface *iface = interfaceFromId(objectId);
- if (iface && iface->actionInterface()) {
+ if (iface && iface->isValid() && iface->actionInterface()) {
if (iface->actionInterface()->actionNames().contains(QAccessibleActionInterface::pressAction()))
iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
else
@@ -182,13 +182,17 @@ namespace QtAndroidAccessibility
static jboolean scrollForward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
{
QAccessibleInterface *iface = interfaceFromId(objectId);
- return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::increaseAction());
+ if (iface && iface->isValid())
+ return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::increaseAction());
+ return false;
}
static jboolean scrollBackward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
{
QAccessibleInterface *iface = interfaceFromId(objectId);
- return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::decreaseAction());
+ if (iface && iface->isValid())
+ return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::decreaseAction());
+ return false;
}
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index 55a9d76b67..5354bdafbc 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -1,6 +1,6 @@
TARGET = qcocoa
-OBJECTIVE_SOURCES += main.mm \
+SOURCES += main.mm \
qcocoaintegration.mm \
qcocoascreen.mm \
qcocoatheme.mm \
@@ -32,9 +32,8 @@ OBJECTIVE_SOURCES += main.mm \
qcocoasystemtrayicon.mm \
qcocoaintrospection.mm \
qcocoakeymapper.mm \
- qcocoamimetypes.mm
-
-SOURCES += messages.cpp
+ qcocoamimetypes.mm \
+ messages.cpp
HEADERS += qcocoaintegration.h \
qcocoascreen.h \
@@ -70,7 +69,7 @@ HEADERS += qcocoaintegration.h \
qcocoamimetypes.h
qtConfig(opengl.*) {
- OBJECTIVE_SOURCES += qcocoaglcontext.mm
+ SOURCES += qcocoaglcontext.mm
HEADERS += qcocoaglcontext.h
}
@@ -89,7 +88,7 @@ CONFIG += no_app_extension_api_only
qtHaveModule(widgets) {
QT_FOR_CONFIG += widgets
- OBJECTIVE_SOURCES += \
+ SOURCES += \
qpaintengine_mac.mm \
qprintengine_mac.mm \
qcocoaprintersupport.mm \
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 6af22facf9..13e9d8809e 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -92,7 +92,6 @@
QT_USE_NAMESPACE
-@class QT_MANGLE_NAMESPACE(QNSMenu);
@class QT_MANGLE_NAMESPACE(QNSImageView);
@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject <NSUserNotificationCenterDelegate>
@@ -123,16 +122,8 @@ QT_USE_NAMESPACE
-(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton;
@end
-@interface QT_MANGLE_NAMESPACE(QNSMenu) : NSMenu <NSMenuDelegate> {
- QPlatformMenu *qmenu;
-}
--(QPlatformMenu*)menu;
--(id)initWithQMenu:(QPlatformMenu*)qmenu;
-@end
-
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSStatusItem);
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSImageView);
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSMenu);
QT_BEGIN_NAMESPACE
class QSystemTrayIconSys
@@ -447,26 +438,4 @@ QT_END_NAMESPACE
@end
-class QSystemTrayIconQMenu : public QPlatformMenu
-{
-public:
- void doAboutToShow() { emit aboutToShow(); }
-private:
- QSystemTrayIconQMenu();
-};
-
-@implementation QNSMenu
--(id)initWithQMenu:(QPlatformMenu*)qm {
- self = [super init];
- if (self) {
- self->qmenu = qm;
- [self setDelegate:self];
- }
- return self;
-}
--(QPlatformMenu*)menu {
- return qmenu;
-}
-@end
-
#endif // QT_NO_SYSTEMTRAYICON
diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro
index 87405ae19f..99b5491912 100644
--- a/src/plugins/platforms/direct2d/direct2d.pro
+++ b/src/plugins/platforms/direct2d/direct2d.pro
@@ -2,9 +2,10 @@ TARGET = qdirect2d
QT += \
core-private gui-private \
- eventdispatcher_support-private accessibility_support-private \
+ eventdispatcher_support-private \
fontdatabase_support-private theme_support-private
+qtConfig(accessibility): QT += accessibility_support-private
qtConfig(vulkan): QT += vulkan_support-private
LIBS += -ldwmapi -ld2d1 -ld3d11 -ldwrite -lVersion -lgdi32
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 289a61336f..9912e03cb9 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -47,7 +47,9 @@
#include "qwindowsmenu.h"
#include "qwindowsmime.h"
#include "qwindowsinputcontext.h"
-#include "qwindowstabletsupport.h"
+#if QT_CONFIG(tabletevent)
+# include "qwindowstabletsupport.h"
+#endif
#include "qwindowstheme.h"
#include <private/qguiapplication_p.h>
#ifndef QT_NO_ACCESSIBILITY
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
index b1f0062979..fba4e8f386 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
@@ -352,16 +352,26 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L
{
PACKET proximityBuffer[1]; // we are only interested in the first packet in this case
const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer);
- if (!totalPacks)
- return false;
+
if (!LOWORD(lParam)) {
qCDebug(lcQpaTablet) << "leave proximity for device #" << m_currentDevice;
- QWindowSystemInterface::handleTabletLeaveProximityEvent(proximityBuffer[0].pkTime,
- m_devices.at(m_currentDevice).currentDevice,
- m_devices.at(m_currentDevice).currentPointerType,
- m_devices.at(m_currentDevice).uniqueId);
+ if (totalPacks > 0) {
+ QWindowSystemInterface::handleTabletLeaveProximityEvent(proximityBuffer[0].pkTime,
+ m_devices.at(m_currentDevice).currentDevice,
+ m_devices.at(m_currentDevice).currentPointerType,
+ m_devices.at(m_currentDevice).uniqueId);
+ } else {
+ QWindowSystemInterface::handleTabletLeaveProximityEvent(m_devices.at(m_currentDevice).currentDevice,
+ m_devices.at(m_currentDevice).currentPointerType,
+ m_devices.at(m_currentDevice).uniqueId);
+
+ }
return true;
}
+
+ if (!totalPacks)
+ return false;
+
const UINT currentCursor = proximityBuffer[0].pkCursor;
UINT physicalCursorId;
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId);
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
index 4d788d91f8..174bc7b609 100644
--- a/src/plugins/platforms/windows/windows.pro
+++ b/src/plugins/platforms/windows/windows.pro
@@ -2,9 +2,10 @@ TARGET = qwindows
QT += \
core-private gui-private \
- eventdispatcher_support-private accessibility_support-private \
+ eventdispatcher_support-private \
fontdatabase_support-private theme_support-private
+qtConfig(accessibility): QT += accessibility_support-private
qtConfig(vulkan): QT += vulkan_support-private
LIBS += -lgdi32 -ldwmapi
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index affc2a0dd6..c8a668b72c 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -915,7 +915,9 @@ void QXcbWindow::hide()
if (QWindow *childWindow = childWindowAt(enterWindow, cursorPos))
enterWindow = childWindow;
const QPoint localPos = enterWindow->mapFromGlobal(cursorPos);
- QWindowSystemInterface::handleEnterEvent(enterWindow, localPos, cursorPos);
+ QWindowSystemInterface::handleEnterEvent(enterWindow,
+ localPos * QHighDpiScaling::factor(enterWindow),
+ nativePos);
}
}
}
diff --git a/src/widgets/kernel/qshortcut.cpp b/src/widgets/kernel/qshortcut.cpp
index 0585a59e89..f944a7097b 100644
--- a/src/widgets/kernel/qshortcut.cpp
+++ b/src/widgets/kernel/qshortcut.cpp
@@ -289,8 +289,10 @@ static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidge
// not the QMenu.) Since we can also reach this code by climbing the menu
// hierarchy (see below), or when the shortcut is not a key-equivalent, we
// need to check whether the QPA menu is actually disabled.
+ // When there is no QPA menu, there will be no QCocoaMenuDelegate checking
+ // for the actual shortcuts. We can then fallback to our own logic.
QPlatformMenu *pm = menu->platformMenu();
- if (!pm || !pm->isEnabled())
+ if (pm && !pm->isEnabled())
continue;
#endif
QAction *a = menu->menuAction();
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 0f8129cb74..3caa6a3b65 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -43,3 +43,8 @@ else:!qtConfig(process): SUBDIRS -= tools
SUBDIRS -= dbus
}
}
+
+# QTBUG-63915
+boot2qt: {
+ contains(QT_ARCH, arm64): SUBDIRS -= dbus
+}
diff --git a/tests/auto/corelib/global/qlogging/BLACKLIST b/tests/auto/corelib/global/qlogging/BLACKLIST
new file mode 100644
index 0000000000..1dcee92361
--- /dev/null
+++ b/tests/auto/corelib/global/qlogging/BLACKLIST
@@ -0,0 +1,3 @@
+[qMessagePattern:backtrace depth,separator]
+# QTBUG-63915
+b2qt 64bit
diff --git a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp
index a0459021be..ed5d0c69a0 100644
--- a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp
+++ b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp
@@ -340,6 +340,17 @@ void tst_QNetworkCookieJar::cookiesForUrl_data()
QTest::newRow("no-match-domain-dot") << allCookies << "http://example.com" << result;
result += cookieDot;
QTest::newRow("match-domain-dot") << allCookies << "http://example.com." << result;
+
+ // Root path in cookie, empty url path
+ allCookies.clear();
+ QNetworkCookie rootCookie;
+ rootCookie.setName("a");
+ rootCookie.setPath("/");
+ rootCookie.setDomain("qt-project.org");
+ allCookies += rootCookie;
+ result.clear();
+ result += rootCookie;
+ QTest::newRow("root-path-match") << allCookies << "http://qt-project.org" << result;
}
void tst_QNetworkCookieJar::cookiesForUrl()
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index 16f06b2d15..d22850ba4e 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -490,6 +490,11 @@ private Q_SLOTS:
void ioHttpCookiesDuringRedirect();
void ioHttpRedirect_data();
void ioHttpRedirect();
+ void ioHttpRedirectFromLocalToRemote();
+ void ioHttpRedirectPost_data();
+ void ioHttpRedirectPost();
+ void ioHttpRedirectMultipartPost_data();
+ void ioHttpRedirectMultipartPost();
#ifndef QT_NO_SSL
void putWithServerClosingConnectionImmediately();
#endif
@@ -516,6 +521,17 @@ bool tst_QNetworkReply::seedCreated = false;
QFAIL(qPrintable(errorMsg)); \
} while (0)
+static bool validateRedirectedResponseHeaders(QNetworkReplyPtr reply)
+{
+ // QTBUG-61300: previously we were mixing 'raw' headers from all responses
+ // along the redirect chain. The simplest test is to check/verify we have
+ // no 'location' header anymore.
+ Q_ASSERT(reply.data());
+
+ return !reply->hasRawHeader("location")
+ && !reply->header(QNetworkRequest::LocationHeader).isValid();
+}
+
#ifndef QT_NO_SSL
static void setupSslServer(QSslSocket* serverSocket)
{
@@ -530,7 +546,7 @@ static void setupSslServer(QSslSocket* serverSocket)
}
#endif
-// Does not work for POST/PUT!
+// Does not work for PUT! Limited support for POST.
class MiniHttpServer: public QTcpServer
{
Q_OBJECT
@@ -545,6 +561,10 @@ public:
bool multiple;
int totalConnections;
+ bool hasContent = false;
+ int contentRead = 0;
+ int contentLength = 0;
+
MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0, bool useipv6 = false)
: dataToTransmit(data), doClose(true), doSsl(ssl), ipv6(useipv6),
multiple(false), totalConnections(0)
@@ -621,6 +641,18 @@ private:
this, SLOT(slotError(QAbstractSocket::SocketError)));
}
+ void parseContentLength()
+ {
+ int index = receivedData.indexOf("Content-Length:");
+ index += sizeof("Content-Length:") - 1;
+ const auto end = std::find(receivedData.cbegin() + index, receivedData.cend(), '\r');
+ auto num = receivedData.mid(index, std::distance(receivedData.cbegin() + index, end));
+ bool ok;
+ contentLength = num.toInt(&ok);
+ if (!ok)
+ contentLength = -1;
+ }
+
private slots:
#ifndef QT_NO_SSL
void slotSslErrors(const QList<QSslError>& errors)
@@ -642,12 +674,20 @@ public slots:
{
Q_ASSERT(!client.isNull());
receivedData += client->readAll();
- int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
+ const int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
if (doubleEndlPos != -1) {
+ const int endOfHeader = doubleEndlPos + 4;
+ hasContent = receivedData.startsWith("POST");
+ if (hasContent && contentLength == 0)
+ parseContentLength();
+ contentRead = receivedData.length() - endOfHeader;
+ if (hasContent && contentRead < contentLength)
+ return;
+
// multiple requests incoming. remove the bytes of the current one
if (multiple)
- receivedData.remove(0, doubleEndlPos+4);
+ receivedData.remove(0, endOfHeader);
reply();
}
@@ -8106,6 +8146,7 @@ void tst_QNetworkReply::ioHttpSingleRedirect()
// Reply url is set to the redirect url
QCOMPARE(reply->url(), redirectUrl);
QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QVERIFY(validateRedirectedResponseHeaders(reply));
}
void tst_QNetworkReply::ioHttpChangeMaxRedirects()
@@ -8154,6 +8195,7 @@ void tst_QNetworkReply::ioHttpChangeMaxRedirects()
QCOMPARE(redSpy2.count(), 2);
QCOMPARE(reply2->url(), server3Url);
QCOMPARE(reply2->error(), QNetworkReply::NoError);
+ QVERIFY(validateRedirectedResponseHeaders(reply2));
}
void tst_QNetworkReply::ioHttpRedirectErrors_data()
@@ -8167,7 +8209,9 @@ void tst_QNetworkReply::ioHttpRedirectErrors_data()
"location: http://localhost:%1\r\n\r\n");
QTest::newRow("too-many-redirects") << "http://localhost" << tempRedirectReply << QNetworkReply::TooManyRedirectsError;
+#if QT_CONFIG(ssl)
QTest::newRow("insecure-redirect") << "https://localhost" << tempRedirectReply << QNetworkReply::InsecureRedirectError;
+#endif
QTest::newRow("unknown-redirect") << "http://localhost"<< tempRedirectReply.replace("http", "bad_protocol") << QNetworkReply::ProtocolUnknownError;
}
@@ -8178,7 +8222,7 @@ void tst_QNetworkReply::ioHttpRedirectErrors()
QFETCH(QNetworkReply::NetworkError, error);
QUrl localhost(url);
- MiniHttpServer server("", localhost.scheme() == "https");
+ MiniHttpServer server("", localhost.scheme() == QLatin1String("https"));
localhost.setPort(server.serverPort());
@@ -8228,11 +8272,13 @@ void tst_QNetworkReply::ioHttpRedirectPolicy_data()
QTest::addColumn<int>("statusCode");
QTest::newRow("manual-nossl") << QNetworkRequest::ManualRedirectPolicy << false << 0 << 307;
- QTest::newRow("manual-ssl") << QNetworkRequest::ManualRedirectPolicy << true << 0 << 307;
QTest::newRow("nolesssafe-nossl") << QNetworkRequest::NoLessSafeRedirectPolicy << false << 1 << 200;
- QTest::newRow("nolesssafe-ssl") << QNetworkRequest::NoLessSafeRedirectPolicy << true << 1 << 200;
QTest::newRow("same-origin-nossl") << QNetworkRequest::SameOriginRedirectPolicy << false << 1 << 200;
+#if QT_CONFIG(ssl)
+ QTest::newRow("manual-ssl") << QNetworkRequest::ManualRedirectPolicy << true << 0 << 307;
+ QTest::newRow("nolesssafe-ssl") << QNetworkRequest::NoLessSafeRedirectPolicy << true << 1 << 200;
QTest::newRow("same-origin-ssl") << QNetworkRequest::SameOriginRedirectPolicy << true << 1 << 200;
+#endif
}
void tst_QNetworkReply::ioHttpRedirectPolicy()
@@ -8240,10 +8286,6 @@ void tst_QNetworkReply::ioHttpRedirectPolicy()
QFETCH(const QNetworkRequest::RedirectPolicy, policy);
QFETCH(const bool, ssl);
-#ifdef QT_NO_SSL
- if (ssl)
- QSKIP("SSL is not supported");
-#endif
QFETCH(const int, redirectCount);
QFETCH(const int, statusCode);
@@ -8251,11 +8293,7 @@ void tst_QNetworkReply::ioHttpRedirectPolicy()
// Setup HTTP server.
SameOriginRedirector redirectServer("", ssl);
- QUrl url(QLatin1String(
-#ifndef QT_NO_SSL
- ssl ? "https://localhost" :
-#endif
- "http://localhost"));
+ QUrl url(QLatin1String(ssl ? "https://localhost" : "http://localhost"));
url.setPort(redirectServer.serverPort());
redirectServer.responses.push_back(httpEmpty200Response);
@@ -8278,6 +8316,7 @@ void tst_QNetworkReply::ioHttpRedirectPolicy()
QCOMPARE(finishedSpy.count(), 1);
QCOMPARE(redirectSpy.count(), redirectCount);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode);
+ QVERIFY(validateRedirectedResponseHeaders(reply) || statusCode != 200);
}
void tst_QNetworkReply::ioHttpRedirectPolicyErrors_data()
@@ -8291,27 +8330,35 @@ void tst_QNetworkReply::ioHttpRedirectPolicyErrors_data()
// 1. NoLessSafeRedirectsPolicy
QTest::newRow("nolesssafe-nossl-nossl-too-many") << QNetworkRequest::NoLessSafeRedirectPolicy
<< false << QString("http://localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError;
+#if QT_CONFIG(ssl)
QTest::newRow("nolesssafe-ssl-ssl-too-many") << QNetworkRequest::NoLessSafeRedirectPolicy
<< true << QString("https:/localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError;
QTest::newRow("nolesssafe-ssl-nossl-insecure-redirect") << QNetworkRequest::NoLessSafeRedirectPolicy
<< true << QString("http://localhost:%1") << 50 << QNetworkReply::InsecureRedirectError;
+#endif
// 2. SameOriginRedirectsPolicy
QTest::newRow("same-origin-nossl-nossl-too-many") << QNetworkRequest::SameOriginRedirectPolicy
<< false << QString("http://localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError;
+#if QT_CONFIG(ssl)
QTest::newRow("same-origin-ssl-ssl-too-many") << QNetworkRequest::SameOriginRedirectPolicy
<< true << QString("https://localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError;
QTest::newRow("same-origin-https-http-wrong-protocol") << QNetworkRequest::SameOriginRedirectPolicy
<< true << QString("http://localhost:%1") << 50 << QNetworkReply::InsecureRedirectError;
+#endif
QTest::newRow("same-origin-http-https-wrong-protocol") << QNetworkRequest::SameOriginRedirectPolicy
<< false << QString("https://localhost:%1") << 50 << QNetworkReply::InsecureRedirectError;
QTest::newRow("same-origin-http-http-wrong-host") << QNetworkRequest::SameOriginRedirectPolicy
<< false << QString("http://not-so-localhost:%1") << 50 << QNetworkReply::InsecureRedirectError;
+#if QT_CONFIG(ssl)
QTest::newRow("same-origin-https-https-wrong-host") << QNetworkRequest::SameOriginRedirectPolicy
<< true << QString("https://not-so-localhost:%1") << 50 << QNetworkReply::InsecureRedirectError;
+#endif
QTest::newRow("same-origin-http-http-wrong-port") << QNetworkRequest::SameOriginRedirectPolicy
<< false << QString("http://localhost/%1") << 50 << QNetworkReply::InsecureRedirectError;
+#if QT_CONFIG(ssl)
QTest::newRow("same-origin-https-https-wrong-port") << QNetworkRequest::SameOriginRedirectPolicy
<< true << QString("https://localhost/%1") << 50 << QNetworkReply::InsecureRedirectError;
+#endif
}
void tst_QNetworkReply::ioHttpRedirectPolicyErrors()
@@ -8325,20 +8372,11 @@ void tst_QNetworkReply::ioHttpRedirectPolicyErrors()
QFETCH(const int, maxRedirects);
QFETCH(const QNetworkReply::NetworkError, expectedError);
-#ifdef QT_NO_SSL
- if (ssl || location.contains("https"))
- QSKIP("SSL required to run this test");
-#endif
-
// Setup the server.
MiniHttpServer server("", ssl);
server.setDataToTransmit(tempRedirectReplyStr().arg(location.arg(server.serverPort())).toLatin1());
- QUrl url(QLatin1String(
-#ifndef QT_NO_SSL
- ssl ? "https://localhost" :
-#endif
- "http://localhost"));
+ QUrl url(QLatin1String(ssl ? "https://localhost" : "http://localhost"));
url.setPort(server.serverPort());
QNetworkRequest request(url);
@@ -8411,6 +8449,7 @@ void tst_QNetworkReply::ioHttpUserVerifiedRedirect()
waitForFinish(reply);
QCOMPARE(finishedSpy.count(), 1);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode);
+ QVERIFY(validateRedirectedResponseHeaders(reply) || statusCode != 200);
}
void tst_QNetworkReply::ioHttpCookiesDuringRedirect()
@@ -8438,6 +8477,7 @@ void tst_QNetworkReply::ioHttpCookiesDuringRedirect()
QVERIFY(waitForFinish(reply) == Success);
QVERIFY(target.receivedData.contains("\r\nCookie: hello=world\r\n"));
+ QVERIFY(validateRedirectedResponseHeaders(reply));
}
void tst_QNetworkReply::ioHttpRedirect_data()
@@ -8476,6 +8516,152 @@ void tst_QNetworkReply::ioHttpRedirect()
QCOMPARE(waitForFinish(reply), int(Success));
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+ QVERIFY(validateRedirectedResponseHeaders(reply));
+}
+
+void tst_QNetworkReply::ioHttpRedirectFromLocalToRemote()
+{
+ QUrl targetUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
+
+ QString redirectReply = tempRedirectReplyStr().arg(targetUrl.toString());
+ MiniHttpServer redirectServer(redirectReply.toLatin1(), false);
+ QUrl url("http://localhost/");
+ url.setPort(redirectServer.serverPort());
+
+ QFile reference(testDataDir + "/rfc3252.txt");
+ QVERIFY(reference.open(QIODevice::ReadOnly));
+ QNetworkRequest request(url);
+
+ auto oldRedirectPolicy = manager.redirectPolicy();
+ manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy);
+ QNetworkReplyPtr reply(manager.get(request));
+ // Restore previous policy
+ manager.setRedirectPolicy(oldRedirectPolicy);
+
+ QCOMPARE(waitForFinish(reply), int(Success));
+
+ QCOMPARE(reply->url(), targetUrl);
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
+ QCOMPARE(reply->readAll(), reference.readAll());
+}
+
+void tst_QNetworkReply::ioHttpRedirectPost_data()
+{
+ QTest::addColumn<QString>("status");
+ QTest::addColumn<QByteArray>("data");
+ QTest::addColumn<QString>("contentType");
+
+ QByteArray data;
+ data = "hello world";
+ QTest::addRow("307") << "307 Temporary Redirect" << data << "text/plain";
+ QString permanentRedirect = "308 Permanent Redirect";
+ QTest::addRow("308") << permanentRedirect << data << "text/plain";
+
+ // Some data from ::putToFile_data
+ data = "";
+ QTest::newRow("empty") << permanentRedirect << data << "application/octet-stream";
+
+ data = QByteArray("abcd\0\1\2\abcd",12);
+ QTest::newRow("with-nul") << permanentRedirect << data << "application/octet-stream";
+
+ data = QByteArray(4097, '\4');
+ QTest::newRow("4k+1") << permanentRedirect << data << "application/octet-stream";
+
+ data = QByteArray(128*1024+1, '\177');
+ QTest::newRow("128k+1") << permanentRedirect << data << "application/octet-stream";
+
+ data = QByteArray(2*1024*1024+1, '\177');
+ QTest::newRow("2MB+1") << permanentRedirect << data << "application/octet-stream";
+}
+
+void tst_QNetworkReply::ioHttpRedirectPost()
+{
+ QFETCH(QString, status);
+ QFETCH(QByteArray, data);
+ QFETCH(QString, contentType);
+
+ QUrl targetUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
+
+ QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n"
+ "Content-Type: text/plain\r\n"
+ "location: %2\r\n"
+ "\r\n").arg(status, targetUrl.toString());
+ MiniHttpServer redirectServer(redirectReply.toLatin1());
+ QUrl url("http://localhost/");
+ url.setPort(redirectServer.serverPort());
+ QNetworkRequest request(url);
+ request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, contentType);
+ auto oldRedirectPolicy = manager.redirectPolicy();
+ manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy);
+
+ QNetworkReplyPtr reply(manager.post(request, data));
+ // Restore previous policy:
+ manager.setRedirectPolicy(oldRedirectPolicy);
+
+ QCOMPARE(waitForFinish(reply), int(Success));
+ QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
+}
+
+void tst_QNetworkReply::ioHttpRedirectMultipartPost_data()
+{
+ postToHttpMultipart_data();
+}
+
+void tst_QNetworkReply::ioHttpRedirectMultipartPost()
+{
+ // Note: This code is heavily based on postToHttpMultipart
+ QFETCH(QUrl, url);
+
+ static QSet<QByteArray> boundaries;
+
+ QNetworkReplyPtr reply;
+
+ QFETCH(QHttpMultiPart *, multiPart);
+ QFETCH(QByteArray, expectedReplyData);
+ QFETCH(QByteArray, contentType);
+
+ QString redirectReply = tempRedirectReplyStr().arg(url.toString());
+ MiniHttpServer redirectServer(redirectReply.toLatin1());
+ QUrl redirectUrl("http://localhost/");
+ redirectUrl.setPort(redirectServer.serverPort());
+ QNetworkRequest request(redirectUrl);
+
+ // Restore policy when we leave this scope:
+ struct PolicyRestorer
+ {
+ QNetworkAccessManager &qnam;
+ QNetworkRequest::RedirectPolicy policy;
+ PolicyRestorer(QNetworkAccessManager &qnam)
+ : qnam(qnam), policy(qnam.redirectPolicy())
+ { qnam.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); }
+ ~PolicyRestorer() { qnam.setRedirectPolicy(policy); }
+ } policyRestorer(manager);
+
+ // hack for testing the setting of the content-type header by hand:
+ if (contentType == "custom") {
+ QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
+ request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
+ }
+
+ QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
+ boundaries.insert(multiPart->boundary());
+
+ RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST"));
+ multiPart->deleteLater();
+
+ QCOMPARE(reply->url(), url);
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 OK
+
+ QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
+ QVERIFY(multiPart->boundary().count() < 70);
+ QByteArray replyData = reply->readAll();
+
+ expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
+// QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
+ QCOMPARE(replyData, expectedReplyData);
}
#ifndef QT_NO_SSL
diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
index da37a9a968..5247d02427 100644
--- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
+++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
@@ -135,6 +135,7 @@ private slots:
void menuSize_Scrolling_data();
void menuSize_Scrolling();
void tearOffMenuNotDisplayed();
+ void QTBUG_61039_menu_shortcuts();
protected slots:
void onActivated(QAction*);
@@ -1644,5 +1645,32 @@ void tst_QMenu::tearOffMenuNotDisplayed()
QVERIFY(!torn->isVisible());
}
+void tst_QMenu::QTBUG_61039_menu_shortcuts()
+{
+ QAction *actionKamen = new QAction("Action Kamen");
+ actionKamen->setShortcut(QKeySequence(QLatin1String("K")));
+
+ QAction *actionJoe = new QAction("Action Joe");
+ actionJoe->setShortcut(QKeySequence(QLatin1String("Ctrl+J")));
+
+ QMenu menu;
+ menu.addAction(actionKamen);
+ menu.addAction(actionJoe);
+ QVERIFY(!menu.platformMenu());
+
+ QWidget widget;
+ widget.addAction(menu.menuAction());
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowActive(&widget));
+
+ QSignalSpy actionKamenSpy(actionKamen, &QAction::triggered);
+ QTest::keyClick(&widget, Qt::Key_K);
+ QTRY_COMPARE(actionKamenSpy.count(), 1);
+
+ QSignalSpy actionJoeSpy(actionJoe, &QAction::triggered);
+ QTest::keyClick(&widget, Qt::Key_J, Qt::ControlModifier);
+ QTRY_COMPARE(actionJoeSpy.count(), 1);
+}
+
QTEST_MAIN(tst_QMenu)
#include "tst_qmenu.moc"