Merge remote-tracking branch 'origin/5.13' into dev
Conflicts: qmake/generators/makefile.cpp Change-Id: Ib3715e626f2fd32804c75c16ea9aa06a1216e76d
This commit is contained in:
commit
261a87f956
@ -3429,9 +3429,9 @@ MakefileGenerator::writePkgConfigFile()
|
|||||||
t << Qt::endl;
|
t << Qt::endl;
|
||||||
|
|
||||||
// requires
|
// requires
|
||||||
const QString requires = project->values("QMAKE_PKGCONFIG_REQUIRES").join(' ');
|
const QString requiresString = project->values("QMAKE_PKGCONFIG_REQUIRES").join(' ');
|
||||||
if (!requires.isEmpty()) {
|
if (!requiresString.isEmpty()) {
|
||||||
t << "Requires: " << requires << Qt::endl;
|
t << "Requires: " << requiresString << Qt::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
t << Qt::endl;
|
t << Qt::endl;
|
||||||
|
@ -433,10 +433,11 @@ public:
|
|||||||
ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); }
|
ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); }
|
||||||
ProFunctionDef(ProFunctionDef &&other) noexcept
|
ProFunctionDef(ProFunctionDef &&other) noexcept
|
||||||
: m_pro(other.m_pro), m_offset(other.m_offset) { other.m_pro = nullptr; }
|
: m_pro(other.m_pro), m_offset(other.m_offset) { other.m_pro = nullptr; }
|
||||||
~ProFunctionDef() { m_pro->deref(); }
|
~ProFunctionDef() { if (m_pro) m_pro->deref(); }
|
||||||
ProFunctionDef &operator=(const ProFunctionDef &o)
|
ProFunctionDef &operator=(const ProFunctionDef &o)
|
||||||
{
|
{
|
||||||
if (this != &o) {
|
if (this != &o) {
|
||||||
|
if (m_pro)
|
||||||
m_pro->deref();
|
m_pro->deref();
|
||||||
m_pro = o.m_pro;
|
m_pro = o.m_pro;
|
||||||
m_pro->ref();
|
m_pro->ref();
|
||||||
|
@ -468,7 +468,17 @@ inline bool QStorageIterator::next()
|
|||||||
size_t len = strlen(buffer.data());
|
size_t len = strlen(buffer.data());
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return false;
|
return false;
|
||||||
if (ptr[len - 1] == '\n')
|
while (Q_UNLIKELY(ptr[len - 1] != '\n' && !feof(fp))) {
|
||||||
|
// buffer wasn't large enough. Enlarge and try again.
|
||||||
|
// (we're readidng from the kernel, so OOM is unlikely)
|
||||||
|
buffer.resize((buffer.size() + 4096) & ~4095);
|
||||||
|
ptr = buffer.data();
|
||||||
|
if (fgets(ptr + len, buffer.size() - len, fp) == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
len += strlen(ptr + len);
|
||||||
|
Q_ASSERT(len < size_t(buffer.size()));
|
||||||
|
}
|
||||||
ptr[len - 1] = '\0';
|
ptr[len - 1] = '\0';
|
||||||
|
|
||||||
// parse the line
|
// parse the line
|
||||||
|
@ -514,10 +514,9 @@ Q_CONSTRUCTOR_FUNCTION(qt_apple_check_os_version);
|
|||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
void QMacKeyValueObserver::addObserver()
|
void QMacKeyValueObserver::addObserver(NSKeyValueObservingOptions options)
|
||||||
{
|
{
|
||||||
[object addObserver:observer forKeyPath:keyPath
|
[object addObserver:observer forKeyPath:keyPath options:options context:callback.get()];
|
||||||
options:NSKeyValueObservingOptionNew context:callback.get()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QMacKeyValueObserver::removeObserver() {
|
void QMacKeyValueObserver::removeObserver() {
|
||||||
|
@ -350,8 +350,12 @@ public:
|
|||||||
QMacKeyValueObserver() {}
|
QMacKeyValueObserver() {}
|
||||||
|
|
||||||
// Note: QMacKeyValueObserver must not outlive the object observed!
|
// Note: QMacKeyValueObserver must not outlive the object observed!
|
||||||
QMacKeyValueObserver(id object, NSString *keyPath, Callback callback)
|
QMacKeyValueObserver(id object, NSString *keyPath, Callback callback,
|
||||||
: object(object), keyPath(keyPath), callback(new Callback(callback)) { addObserver(); }
|
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew)
|
||||||
|
: object(object), keyPath(keyPath), callback(new Callback(callback))
|
||||||
|
{
|
||||||
|
addObserver(options);
|
||||||
|
}
|
||||||
|
|
||||||
QMacKeyValueObserver(const QMacKeyValueObserver &other)
|
QMacKeyValueObserver(const QMacKeyValueObserver &other)
|
||||||
: QMacKeyValueObserver(other.object, other.keyPath, *other.callback.get()) {}
|
: QMacKeyValueObserver(other.object, other.keyPath, *other.callback.get()) {}
|
||||||
@ -381,7 +385,7 @@ private:
|
|||||||
std::swap(first.callback, second.callback);
|
std::swap(first.callback, second.callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addObserver();
|
void addObserver(NSKeyValueObservingOptions options);
|
||||||
|
|
||||||
id object = nil;
|
id object = nil;
|
||||||
NSString *keyPath = nullptr;
|
NSString *keyPath = nullptr;
|
||||||
|
@ -1972,7 +1972,15 @@ inline void QCborStreamReader::preparse()
|
|||||||
if (lastError() == QCborError::NoError) {
|
if (lastError() == QCborError::NoError) {
|
||||||
type_ = cbor_value_get_type(&d->currentElement);
|
type_ = cbor_value_get_type(&d->currentElement);
|
||||||
|
|
||||||
if (type_ != CborInvalidType) {
|
if (type_ == CborInvalidType) {
|
||||||
|
// We may have reached the end.
|
||||||
|
if (d->device && d->containerStack.isEmpty()) {
|
||||||
|
d->buffer.clear();
|
||||||
|
if (d->bufferStart)
|
||||||
|
d->device->skip(d->bufferStart);
|
||||||
|
d->bufferStart = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
d->lastError = {};
|
d->lastError = {};
|
||||||
// Undo the type mapping that TinyCBOR does (we have an explicit type
|
// Undo the type mapping that TinyCBOR does (we have an explicit type
|
||||||
// for negative integer and we don't have separate types for Boolean,
|
// for negative integer and we don't have separate types for Boolean,
|
||||||
|
@ -2053,6 +2053,23 @@ inline void fetchTransformed_pixelBounds(int max, int l1, int l2, int &v)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool canUseFastMatrixPath(const qreal cx, const qreal cy, const qsizetype length, const QSpanData *data)
|
||||||
|
{
|
||||||
|
if (Q_UNLIKELY(!data->fast_matrix))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
qreal fx = (data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale;
|
||||||
|
qreal fy = (data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale;
|
||||||
|
qreal minc = std::min(fx, fy);
|
||||||
|
qreal maxc = std::max(fx, fy);
|
||||||
|
fx += std::trunc(data->m11 * fixed_scale) * length;
|
||||||
|
fy += std::trunc(data->m12 * fixed_scale) * length;
|
||||||
|
minc = std::min(minc, std::min(fx, fy));
|
||||||
|
maxc = std::max(maxc, std::max(fx, fy));
|
||||||
|
|
||||||
|
return minc >= std::numeric_limits<int>::min() && maxc <= std::numeric_limits<int>::max();
|
||||||
|
}
|
||||||
|
|
||||||
template<TextureBlendType blendType, QPixelLayout::BPP bpp, typename T>
|
template<TextureBlendType blendType, QPixelLayout::BPP bpp, typename T>
|
||||||
static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *data,
|
static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *data,
|
||||||
int y, int x, int length)
|
int y, int x, int length)
|
||||||
@ -2070,7 +2087,7 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
|
|||||||
// When templated 'fetch' should be inlined at compile time:
|
// When templated 'fetch' should be inlined at compile time:
|
||||||
const FetchPixelFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : FetchPixelFunc(fetchPixel<bpp>);
|
const FetchPixelFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : FetchPixelFunc(fetchPixel<bpp>);
|
||||||
|
|
||||||
if (data->fast_matrix) {
|
if (canUseFastMatrixPath(cx, cy, length, data)) {
|
||||||
// The increment pr x in the scanline
|
// The increment pr x in the scanline
|
||||||
int fdx = (int)(data->m11 * fixed_scale);
|
int fdx = (int)(data->m11 * fixed_scale);
|
||||||
int fdy = (int)(data->m12 * fixed_scale);
|
int fdy = (int)(data->m12 * fixed_scale);
|
||||||
@ -3026,7 +3043,7 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c
|
|||||||
|
|
||||||
uint *end = buffer + length;
|
uint *end = buffer + length;
|
||||||
uint *b = buffer;
|
uint *b = buffer;
|
||||||
if (data->fast_matrix) {
|
if (canUseFastMatrixPath(cx, cy, length, data)) {
|
||||||
// The increment pr x in the scanline
|
// The increment pr x in the scanline
|
||||||
int fdx = (int)(data->m11 * fixed_scale);
|
int fdx = (int)(data->m11 * fixed_scale);
|
||||||
int fdy = (int)(data->m12 * fixed_scale);
|
int fdy = (int)(data->m12 * fixed_scale);
|
||||||
@ -3383,7 +3400,7 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
|
|||||||
const qreal cx = x + qreal(0.5);
|
const qreal cx = x + qreal(0.5);
|
||||||
const qreal cy = y + qreal(0.5);
|
const qreal cy = y + qreal(0.5);
|
||||||
|
|
||||||
if (data->fast_matrix) {
|
if (canUseFastMatrixPath(cx, cy, length, data)) {
|
||||||
// The increment pr x in the scanline
|
// The increment pr x in the scanline
|
||||||
int fdx = (int)(data->m11 * fixed_scale);
|
int fdx = (int)(data->m11 * fixed_scale);
|
||||||
int fdy = (int)(data->m12 * fixed_scale);
|
int fdy = (int)(data->m12 * fixed_scale);
|
||||||
@ -3570,7 +3587,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
|
|||||||
QRgba64 *end = buffer + length;
|
QRgba64 *end = buffer + length;
|
||||||
QRgba64 *b = buffer;
|
QRgba64 *b = buffer;
|
||||||
|
|
||||||
if (data->fast_matrix) {
|
if (canUseFastMatrixPath(cx, cy, length, data)) {
|
||||||
// The increment pr x in the scanline
|
// The increment pr x in the scanline
|
||||||
const int fdx = (int)(data->m11 * fixed_scale);
|
const int fdx = (int)(data->m11 * fixed_scale);
|
||||||
const int fdy = (int)(data->m12 * fixed_scale);
|
const int fdy = (int)(data->m12 * fixed_scale);
|
||||||
@ -3728,7 +3745,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint64(QRgba64 *buf
|
|||||||
QRgba64 *end = buffer + length;
|
QRgba64 *end = buffer + length;
|
||||||
QRgba64 *b = buffer;
|
QRgba64 *b = buffer;
|
||||||
|
|
||||||
if (data->fast_matrix) {
|
if (canUseFastMatrixPath(cx, cy, length, data)) {
|
||||||
// The increment pr x in the scanline
|
// The increment pr x in the scanline
|
||||||
const int fdx = (int)(data->m11 * fixed_scale);
|
const int fdx = (int)(data->m11 * fixed_scale);
|
||||||
const int fdy = (int)(data->m12 * fixed_scale);
|
const int fdy = (int)(data->m12 * fixed_scale);
|
||||||
|
@ -6,6 +6,7 @@ SOURCES += main.mm \
|
|||||||
qcocoatheme.mm \
|
qcocoatheme.mm \
|
||||||
qcocoabackingstore.mm \
|
qcocoabackingstore.mm \
|
||||||
qcocoawindow.mm \
|
qcocoawindow.mm \
|
||||||
|
qcocoawindowmanager.mm \
|
||||||
qnsview.mm \
|
qnsview.mm \
|
||||||
qnswindow.mm \
|
qnswindow.mm \
|
||||||
qnswindowdelegate.mm \
|
qnswindowdelegate.mm \
|
||||||
@ -41,6 +42,7 @@ HEADERS += qcocoaintegration.h \
|
|||||||
qcocoatheme.h \
|
qcocoatheme.h \
|
||||||
qcocoabackingstore.h \
|
qcocoabackingstore.h \
|
||||||
qcocoawindow.h \
|
qcocoawindow.h \
|
||||||
|
qcocoawindowmanager.h \
|
||||||
qnsview.h \
|
qnsview.h \
|
||||||
qnswindow.h \
|
qnswindow.h \
|
||||||
qnswindowdelegate.h \
|
qnswindowdelegate.h \
|
||||||
|
@ -215,25 +215,6 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList)
|
|||||||
|
|
||||||
connect(qGuiApp, &QGuiApplication::focusWindowChanged,
|
connect(qGuiApp, &QGuiApplication::focusWindowChanged,
|
||||||
this, &QCocoaIntegration::focusWindowChanged);
|
this, &QCocoaIntegration::focusWindowChanged);
|
||||||
|
|
||||||
static auto splashScreenHider = QMacKeyValueObserver(NSApp, @"modalWindow", []{
|
|
||||||
const QWindowList allWindows = QGuiApplication::topLevelWindows();
|
|
||||||
for (QWindow *window : allWindows) {
|
|
||||||
if ((window->flags() & Qt::SplashScreen) == Qt::SplashScreen) {
|
|
||||||
QCocoaWindow *platformWindow = static_cast<QCocoaWindow*>(window->handle());
|
|
||||||
NSWindow *splashWindow = platformWindow->view().window;
|
|
||||||
if (!splashWindow)
|
|
||||||
continue;
|
|
||||||
if (NSApp.modalWindow) {
|
|
||||||
NSInteger originalLevel = splashWindow.level;
|
|
||||||
splashWindow.level = NSNormalWindowLevel;
|
|
||||||
window->setProperty("_q_levelBeforeModalSession", (qlonglong)originalLevel);
|
|
||||||
} else if (NSInteger originalLevel = window->property("_q_levelBeforeModalSession").toLongLong()) {
|
|
||||||
splashWindow.level = originalLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QCocoaIntegration::~QCocoaIntegration()
|
QCocoaIntegration::~QCocoaIntegration()
|
||||||
|
@ -118,11 +118,13 @@ class QSystemTrayIconSys
|
|||||||
public:
|
public:
|
||||||
QSystemTrayIconSys(QCocoaSystemTrayIcon *sys) {
|
QSystemTrayIconSys(QCocoaSystemTrayIcon *sys) {
|
||||||
item = [[QNSStatusItem alloc] initWithSysTray:sys];
|
item = [[QNSStatusItem alloc] initWithSysTray:sys];
|
||||||
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:item];
|
NSUserNotificationCenter.defaultUserNotificationCenter.delegate = item;
|
||||||
}
|
}
|
||||||
~QSystemTrayIconSys() {
|
~QSystemTrayIconSys() {
|
||||||
[[[item item] view] setHidden: YES];
|
[[[item item] view] setHidden: YES];
|
||||||
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
|
NSUserNotificationCenter *center = NSUserNotificationCenter.defaultUserNotificationCenter;
|
||||||
|
if (center.delegate == item)
|
||||||
|
center.delegate = nil;
|
||||||
[item release];
|
[item release];
|
||||||
}
|
}
|
||||||
QNSStatusItem *item;
|
QNSStatusItem *item;
|
||||||
@ -277,7 +279,10 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess
|
|||||||
notification.contentImage = [nsimage autorelease];
|
notification.contentImage = [nsimage autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
|
NSUserNotificationCenter *center = NSUserNotificationCenter.defaultUserNotificationCenter;
|
||||||
|
center.delegate = m_sys->item;
|
||||||
|
[center deliverNotification:notification];
|
||||||
|
[notification release];
|
||||||
}
|
}
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -454,13 +454,35 @@ NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags)
|
|||||||
if (type == Qt::ToolTip)
|
if (type == Qt::ToolTip)
|
||||||
windowLevel = NSScreenSaverWindowLevel;
|
windowLevel = NSScreenSaverWindowLevel;
|
||||||
|
|
||||||
// Any "special" window should be in at least the same level as its parent.
|
auto *transientParent = window()->transientParent();
|
||||||
if (type != Qt::Window) {
|
if (transientParent && transientParent->handle()) {
|
||||||
const QWindow * const transientParent = window()->transientParent();
|
// We try to keep windows in at least the same window level as
|
||||||
const QCocoaWindow * const transientParentWindow = transientParent ?
|
// their transient parent. Unfortunately this only works when the
|
||||||
static_cast<QCocoaWindow *>(transientParent->handle()) : nullptr;
|
// window is created. If the window level changes after that, as
|
||||||
if (transientParentWindow)
|
// a result of a call to setWindowFlags, or by changing the level
|
||||||
windowLevel = qMax([transientParentWindow->nativeWindow() level], windowLevel);
|
// of the native window, we will not pick this up, and the window
|
||||||
|
// will be left behind (or in a different window level than) its
|
||||||
|
// parent. We could KVO-observe the window level of our transient
|
||||||
|
// parent, but that requires us to know when the parent goes away
|
||||||
|
// so that we can unregister the observation before the parent is
|
||||||
|
// dealloced, something we can't do for generic NSWindows. Another
|
||||||
|
// way would be to override [NSWindow setLevel:] and notify child
|
||||||
|
// windows about the change, but that doesn't work for foreign
|
||||||
|
// windows, which can still be transient parents via fromWinId().
|
||||||
|
// One area where this problem is apparent is when AppKit tweaks
|
||||||
|
// the window level of modal windows during application activation
|
||||||
|
// and deactivation. Since we don't pick up on these window level
|
||||||
|
// changes in a generic way, we need to add logic explicitly to
|
||||||
|
// re-evaluate the window level after AppKit has done its tweaks.
|
||||||
|
|
||||||
|
auto *transientCocoaWindow = static_cast<QCocoaWindow *>(transientParent->handle());
|
||||||
|
auto *nsWindow = transientCocoaWindow->nativeWindow();
|
||||||
|
|
||||||
|
// We only upgrade the window level for "special" windows, to work
|
||||||
|
// around Qt Designer parenting the designer windows to the widget
|
||||||
|
// palette window (QTBUG-31779). This should be fixed in designer.
|
||||||
|
if (type != Qt::Window)
|
||||||
|
windowLevel = qMax(windowLevel, nsWindow.level);
|
||||||
}
|
}
|
||||||
|
|
||||||
return windowLevel;
|
return windowLevel;
|
||||||
|
63
src/plugins/platforms/cocoa/qcocoawindowmanager.h
Normal file
63
src/plugins/platforms/cocoa/qcocoawindowmanager.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the plugins 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 QCOCOAWINDOWMANAGER_H
|
||||||
|
#define QCOCOAWINDOWMANAGER_H
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
|
#include <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
class QCocoaWindowManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QCocoaWindowManager *instance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QCocoaWindowManager();
|
||||||
|
void initialize();
|
||||||
|
|
||||||
|
void modalSessionChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // QCOCOAWINDOWMANAGER_H
|
108
src/plugins/platforms/cocoa/qcocoawindowmanager.mm
Normal file
108
src/plugins/platforms/cocoa/qcocoawindowmanager.mm
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the plugins 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 "qcocoawindowmanager.h"
|
||||||
|
#include "qcocoawindow.h"
|
||||||
|
|
||||||
|
#include <QtCore/private/qcore_mac_p.h>
|
||||||
|
|
||||||
|
#include <QtGui/qguiapplication.h>
|
||||||
|
#include <QtGui/qwindow.h>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
QCocoaWindowManager *QCocoaWindowManager::instance()
|
||||||
|
{
|
||||||
|
static auto *instance = new QCocoaWindowManager;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCocoaWindowManager::QCocoaWindowManager()
|
||||||
|
{
|
||||||
|
if (NSApp) {
|
||||||
|
initialize();
|
||||||
|
} else {
|
||||||
|
static auto applicationDidFinishLaunching(QMacNotificationObserver(nil,
|
||||||
|
NSApplicationDidFinishLaunchingNotification, [this] { initialize(); }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCocoaWindowManager::initialize()
|
||||||
|
{
|
||||||
|
Q_ASSERT(NSApp);
|
||||||
|
|
||||||
|
// Whenever the modalWindow property of NSApplication changes we have a new
|
||||||
|
// modal session running. Observing the app modal window instead of our own
|
||||||
|
// event dispatcher sessions allows us to track session started by native
|
||||||
|
// APIs as well. We need to check the initial state as well, in case there
|
||||||
|
// is already a modal session running.
|
||||||
|
static auto modalSessionObserver(QMacKeyValueObserver(
|
||||||
|
NSApp, @"modalWindow", [this] { modalSessionChanged(); },
|
||||||
|
NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCocoaWindowManager::modalSessionChanged()
|
||||||
|
{
|
||||||
|
// Make sure that no window is overlapping the modal window. This can
|
||||||
|
// happen for e.g. splash screens, which have the NSPopUpMenuWindowLevel.
|
||||||
|
for (auto *window : QGuiApplication::topLevelWindows()) {
|
||||||
|
auto *platformWindow = static_cast<QCocoaWindow*>(window->handle());
|
||||||
|
if (!platformWindow)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto naturalWindowLevel = platformWindow->windowLevel(window->flags());
|
||||||
|
if (naturalWindowLevel > NSModalPanelWindowLevel) {
|
||||||
|
NSWindow *nativeWindow = platformWindow->nativeWindow();
|
||||||
|
if (NSApp.modalWindow) {
|
||||||
|
// Lower window to that of the modal windows, but no less
|
||||||
|
nativeWindow.level = NSModalPanelWindowLevel;
|
||||||
|
[nativeWindow orderBack:nil];
|
||||||
|
} else {
|
||||||
|
// Restore window's natural window level, whatever that was
|
||||||
|
nativeWindow.level = naturalWindowLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initializeWindowManager() { Q_UNUSED(QCocoaWindowManager::instance()); }
|
||||||
|
Q_CONSTRUCTOR_FUNCTION(initializeWindowManager)
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
@ -80,6 +80,11 @@ private Q_SLOTS:
|
|||||||
void addData_singleElement();
|
void addData_singleElement();
|
||||||
void addData_complex_data() { arrays_data(); }
|
void addData_complex_data() { arrays_data(); }
|
||||||
void addData_complex();
|
void addData_complex();
|
||||||
|
|
||||||
|
void duplicatedData_data() { arrays_data(); }
|
||||||
|
void duplicatedData();
|
||||||
|
void extraData_data() { arrays_data(); }
|
||||||
|
void extraData();
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FOR_CBOR_TYPE(F) \
|
#define FOR_CBOR_TYPE(F) \
|
||||||
@ -480,6 +485,28 @@ static QString parseOne(QCborStreamReader &reader)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString parse(QCborStreamReader &reader, const QByteArray &data)
|
||||||
|
{
|
||||||
|
qint64 oldPos = 0;
|
||||||
|
if (QIODevice *dev = reader.device())
|
||||||
|
oldPos = dev->pos();
|
||||||
|
|
||||||
|
QString r = parseOne(reader);
|
||||||
|
if (r.isEmpty())
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (reader.currentOffset() - oldPos != data.size())
|
||||||
|
r = QString("Number of parsed bytes (%1) not expected (%2)")
|
||||||
|
.arg(reader.currentOffset()).arg(data.size());
|
||||||
|
if (QIODevice *dev = reader.device()) {
|
||||||
|
if (dev->pos() - oldPos != data.size())
|
||||||
|
r = QString("QIODevice not advanced (%1) as expected (%2)")
|
||||||
|
.arg(dev->pos()).arg(data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
bool parseNonRecursive(QString &result, bool &printingStringChunks, QCborStreamReader &reader)
|
bool parseNonRecursive(QString &result, bool &printingStringChunks, QCborStreamReader &reader)
|
||||||
{
|
{
|
||||||
while (reader.lastError() == QCborError::NoError) {
|
while (reader.lastError() == QCborError::NoError) {
|
||||||
@ -612,13 +639,13 @@ void tst_QCborStreamReader::fixed()
|
|||||||
}
|
}
|
||||||
QVERIFY(reader.isValid());
|
QVERIFY(reader.isValid());
|
||||||
QCOMPARE(reader.lastError(), QCborError::NoError);
|
QCOMPARE(reader.lastError(), QCborError::NoError);
|
||||||
QCOMPARE(parseOne(reader), expected);
|
QCOMPARE(parse(reader, data), expected);
|
||||||
|
|
||||||
// verify that we can re-read
|
// verify that we can re-read
|
||||||
reader.reset();
|
reader.reset();
|
||||||
QVERIFY(reader.isValid());
|
QVERIFY(reader.isValid());
|
||||||
QCOMPARE(reader.lastError(), QCborError::NoError);
|
QCOMPARE(reader.lastError(), QCborError::NoError);
|
||||||
QCOMPARE(parseOne(reader), expected);
|
QCOMPARE(parse(reader, data), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QCborStreamReader::strings_data()
|
void tst_QCborStreamReader::strings_data()
|
||||||
@ -721,7 +748,7 @@ void tst_QCborStreamReader::emptyContainers()
|
|||||||
QCOMPARE(reader.lastError(), QCborError::NoError);
|
QCOMPARE(reader.lastError(), QCborError::NoError);
|
||||||
if (reader.isLengthKnown())
|
if (reader.isLengthKnown())
|
||||||
QCOMPARE(reader.length(), 0U);
|
QCOMPARE(reader.length(), 0U);
|
||||||
QCOMPARE(parseOne(reader), expected);
|
QCOMPARE(parse(reader, data), expected);
|
||||||
|
|
||||||
// verify that we can re-read
|
// verify that we can re-read
|
||||||
reader.reset();
|
reader.reset();
|
||||||
@ -729,7 +756,7 @@ void tst_QCborStreamReader::emptyContainers()
|
|||||||
QCOMPARE(reader.lastError(), QCborError::NoError);
|
QCOMPARE(reader.lastError(), QCborError::NoError);
|
||||||
if (reader.isLengthKnown())
|
if (reader.isLengthKnown())
|
||||||
QCOMPARE(reader.length(), 0U);
|
QCOMPARE(reader.length(), 0U);
|
||||||
QCOMPARE(parseOne(reader), expected);
|
QCOMPARE(parse(reader, data), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QCborStreamReader::arrays_data()
|
void tst_QCborStreamReader::arrays_data()
|
||||||
@ -758,7 +785,7 @@ static void checkContainer(int len, const QByteArray &data, const QString &expec
|
|||||||
QVERIFY(reader.isLengthKnown());
|
QVERIFY(reader.isLengthKnown());
|
||||||
QCOMPARE(reader.length(), uint(len));
|
QCOMPARE(reader.length(), uint(len));
|
||||||
}
|
}
|
||||||
QCOMPARE(parseOne(reader), expected);
|
QCOMPARE(parse(reader, data), expected);
|
||||||
|
|
||||||
// verify that we can re-read
|
// verify that we can re-read
|
||||||
reader.reset();
|
reader.reset();
|
||||||
@ -768,7 +795,7 @@ static void checkContainer(int len, const QByteArray &data, const QString &expec
|
|||||||
QVERIFY(reader.isLengthKnown());
|
QVERIFY(reader.isLengthKnown());
|
||||||
QCOMPARE(reader.length(), uint(len));
|
QCOMPARE(reader.length(), uint(len));
|
||||||
}
|
}
|
||||||
QCOMPARE(parseOne(reader), expected);
|
QCOMPARE(parse(reader, data), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QCborStreamReader::arrays()
|
void tst_QCborStreamReader::arrays()
|
||||||
@ -892,7 +919,7 @@ void tst_QCborStreamReader::validation()
|
|||||||
buffer.open(QIODevice::ReadOnly);
|
buffer.open(QIODevice::ReadOnly);
|
||||||
reader.setDevice(&buffer);
|
reader.setDevice(&buffer);
|
||||||
}
|
}
|
||||||
parseOne(reader);
|
parse(reader, data);
|
||||||
QVERIFY(reader.lastError() != QCborError::NoError);
|
QVERIFY(reader.lastError() != QCborError::NoError);
|
||||||
|
|
||||||
// next() should fail
|
// next() should fail
|
||||||
@ -997,7 +1024,7 @@ void tst_QCborStreamReader::addData_singleElement()
|
|||||||
reader.addData(data.constData() + i, 1);
|
reader.addData(data.constData() + i, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseOne(reader);
|
parse(reader, data);
|
||||||
QCOMPARE(reader.lastError(), QCborError::EndOfFile);
|
QCOMPARE(reader.lastError(), QCborError::EndOfFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1009,7 +1036,7 @@ void tst_QCborStreamReader::addData_singleElement()
|
|||||||
reader.addData(data.right(1));
|
reader.addData(data.right(1));
|
||||||
}
|
}
|
||||||
QCOMPARE(reader.lastError(), QCborError::NoError);
|
QCOMPARE(reader.lastError(), QCborError::NoError);
|
||||||
QCOMPARE(parseOne(reader), expected);
|
QCOMPARE(parse(reader, data), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QCborStreamReader::addData_complex()
|
void tst_QCborStreamReader::addData_complex()
|
||||||
@ -1085,6 +1112,69 @@ void tst_QCborStreamReader::addData_complex()
|
|||||||
"{1, [" + expected + ", " + expected + "]}");
|
"{1, [" + expected + ", " + expected + "]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QCborStreamReader::duplicatedData()
|
||||||
|
{
|
||||||
|
QFETCH_GLOBAL(bool, useDevice);
|
||||||
|
QFETCH(QByteArray, data);
|
||||||
|
QFETCH(QString, expected);
|
||||||
|
removeIndicators(expected);
|
||||||
|
|
||||||
|
// double the data up
|
||||||
|
QByteArray doubledata = data + data;
|
||||||
|
|
||||||
|
QBuffer buffer(&doubledata);
|
||||||
|
QCborStreamReader reader(doubledata);
|
||||||
|
if (useDevice) {
|
||||||
|
buffer.open(QIODevice::ReadOnly);
|
||||||
|
reader.setDevice(&buffer);
|
||||||
|
}
|
||||||
|
QVERIFY(reader.isValid());
|
||||||
|
QCOMPARE(reader.lastError(), QCborError::NoError);
|
||||||
|
QCOMPARE(parse(reader, data), expected); // yes, data
|
||||||
|
|
||||||
|
QVERIFY(reader.currentOffset() < doubledata.size());
|
||||||
|
if (useDevice) {
|
||||||
|
reader.setDevice(&buffer);
|
||||||
|
QVERIFY(reader.isValid());
|
||||||
|
QCOMPARE(reader.lastError(), QCborError::NoError);
|
||||||
|
QCOMPARE(parse(reader, data), expected);
|
||||||
|
QCOMPARE(buffer.pos(), doubledata.size());
|
||||||
|
} else {
|
||||||
|
// there's no reader.setData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QCborStreamReader::extraData()
|
||||||
|
{
|
||||||
|
QFETCH_GLOBAL(bool, useDevice);
|
||||||
|
QFETCH(QByteArray, data);
|
||||||
|
QFETCH(QString, expected);
|
||||||
|
removeIndicators(expected);
|
||||||
|
|
||||||
|
QByteArray extension(9, '\0');
|
||||||
|
|
||||||
|
// stress test everything with extra bytes (just one byte changing;
|
||||||
|
// TinyCBOR used to have a bug where the next byte got sometimes read)
|
||||||
|
for (int c = '\0'; c < 0x100; ++c) {
|
||||||
|
extension[0] = c;
|
||||||
|
QByteArray extendeddata = data + extension;
|
||||||
|
|
||||||
|
QBuffer buffer(&extendeddata);
|
||||||
|
QCborStreamReader reader(extendeddata);
|
||||||
|
if (useDevice) {
|
||||||
|
buffer.open(QIODevice::ReadOnly);
|
||||||
|
reader.setDevice(&buffer);
|
||||||
|
}
|
||||||
|
QVERIFY(reader.isValid());
|
||||||
|
QCOMPARE(reader.lastError(), QCborError::NoError);
|
||||||
|
QCOMPARE(parse(reader, data), expected); // yes, data
|
||||||
|
|
||||||
|
// if we were a parser, we could parse the next payload
|
||||||
|
if (useDevice)
|
||||||
|
QCOMPARE(buffer.readAll(), extension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QTEST_MAIN(tst_QCborStreamReader)
|
QTEST_MAIN(tst_QCborStreamReader)
|
||||||
|
|
||||||
|
@ -91,8 +91,14 @@ private slots:
|
|||||||
|
|
||||||
void toCbor_data();
|
void toCbor_data();
|
||||||
void toCbor();
|
void toCbor();
|
||||||
|
void toCborStreamWriter_data() { toCbor_data(); }
|
||||||
|
void toCborStreamWriter();
|
||||||
void fromCbor_data();
|
void fromCbor_data();
|
||||||
void fromCbor();
|
void fromCbor();
|
||||||
|
void fromCborStreamReaderByteArray_data() { fromCbor_data(); }
|
||||||
|
void fromCborStreamReaderByteArray();
|
||||||
|
void fromCborStreamReaderIODevice_data() { fromCbor_data(); }
|
||||||
|
void fromCborStreamReaderIODevice();
|
||||||
void validation_data();
|
void validation_data();
|
||||||
void validation();
|
void validation();
|
||||||
void toDiagnosticNotation_data();
|
void toDiagnosticNotation_data();
|
||||||
@ -1454,6 +1460,22 @@ void tst_QCborValue::toCbor()
|
|||||||
"\xa1\x01\xd9\xd9\xf7" + result);
|
"\xa1\x01\xd9\xd9\xf7" + result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QCborValue::toCborStreamWriter()
|
||||||
|
{
|
||||||
|
QFETCH(QCborValue, v);
|
||||||
|
QFETCH(QByteArray, result);
|
||||||
|
QFETCH(QCborValue::EncodingOptions, options);
|
||||||
|
|
||||||
|
QByteArray output;
|
||||||
|
QBuffer buffer(&output);
|
||||||
|
buffer.open(QIODevice::WriteOnly);
|
||||||
|
QCborStreamWriter writer(&buffer);
|
||||||
|
|
||||||
|
v.toCbor(writer, options);
|
||||||
|
QCOMPARE(buffer.pos(), result.size());
|
||||||
|
QCOMPARE(output, result);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QCborValue::fromCbor_data()
|
void tst_QCborValue::fromCbor_data()
|
||||||
{
|
{
|
||||||
addCommonCborData();
|
addCommonCborData();
|
||||||
@ -1484,20 +1506,11 @@ void tst_QCborValue::fromCbor_data()
|
|||||||
<< raw("\xd8\x25\x51" "\1\2\3\4""\4\3\2\0""\0\0\0\0""\0\0\0\1""\2");
|
<< raw("\xd8\x25\x51" "\1\2\3\4""\4\3\2\0""\0\0\0\0""\0\0\0\1""\2");
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QCborValue::fromCbor()
|
void fromCbor_common(void (*doCheck)(const QCborValue &, const QByteArray &))
|
||||||
{
|
{
|
||||||
QFETCH(QCborValue, v);
|
QFETCH(QCborValue, v);
|
||||||
QFETCH(QByteArray, result);
|
QFETCH(QByteArray, result);
|
||||||
|
|
||||||
auto doCheck = [](const QCborValue &v, const QByteArray &result) {
|
|
||||||
QCborParserError error;
|
|
||||||
QCborValue decoded = QCborValue::fromCbor(result, &error);
|
|
||||||
QVERIFY2(error.error == QCborError(), qPrintable(error.errorString()));
|
|
||||||
QCOMPARE(error.offset, result.size());
|
|
||||||
QVERIFY(decoded == v);
|
|
||||||
QVERIFY(v == decoded);
|
|
||||||
};
|
|
||||||
|
|
||||||
doCheck(v, result);
|
doCheck(v, result);
|
||||||
if (QTest::currentTestFailed())
|
if (QTest::currentTestFailed())
|
||||||
return;
|
return;
|
||||||
@ -1548,6 +1561,52 @@ void tst_QCborValue::fromCbor()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QCborValue::fromCbor()
|
||||||
|
{
|
||||||
|
auto doCheck = [](const QCborValue &v, const QByteArray &result) {
|
||||||
|
QCborParserError error;
|
||||||
|
QCborValue decoded = QCborValue::fromCbor(result, &error);
|
||||||
|
QVERIFY2(error.error == QCborError(), qPrintable(error.errorString()));
|
||||||
|
QCOMPARE(error.offset, result.size());
|
||||||
|
QVERIFY(decoded == v);
|
||||||
|
QVERIFY(v == decoded);
|
||||||
|
};
|
||||||
|
|
||||||
|
fromCbor_common(doCheck);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QCborValue::fromCborStreamReaderByteArray()
|
||||||
|
{
|
||||||
|
auto doCheck = [](const QCborValue &expected, const QByteArray &data) {
|
||||||
|
QCborStreamReader reader(data);
|
||||||
|
QCborValue decoded = QCborValue::fromCbor(reader);
|
||||||
|
QCOMPARE(reader.lastError(), QCborError());
|
||||||
|
QCOMPARE(reader.currentOffset(), data.size());
|
||||||
|
QVERIFY(decoded == expected);
|
||||||
|
QVERIFY(expected == decoded);
|
||||||
|
};
|
||||||
|
|
||||||
|
fromCbor_common(doCheck);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QCborValue::fromCborStreamReaderIODevice()
|
||||||
|
{
|
||||||
|
auto doCheck = [](const QCborValue &expected, const QByteArray &data) {
|
||||||
|
QBuffer buffer;
|
||||||
|
buffer.setData(data);
|
||||||
|
buffer.open(QIODevice::ReadOnly);
|
||||||
|
QCborStreamReader reader(&buffer);
|
||||||
|
QCborValue decoded = QCborValue::fromCbor(reader);
|
||||||
|
QCOMPARE(reader.lastError(), QCborError());
|
||||||
|
QCOMPARE(reader.currentOffset(), data.size());
|
||||||
|
QVERIFY(decoded == expected);
|
||||||
|
QVERIFY(expected == decoded);
|
||||||
|
QCOMPARE(buffer.pos(), reader.currentOffset());
|
||||||
|
};
|
||||||
|
|
||||||
|
fromCbor_common(doCheck);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QCborValue::validation_data()
|
void tst_QCborValue::validation_data()
|
||||||
{
|
{
|
||||||
addValidationColumns();
|
addValidationColumns();
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#endif // NO_SSL
|
#endif // NO_SSL
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "emulationdetector.h"
|
#include "emulationdetector.h"
|
||||||
@ -117,7 +118,7 @@ private:
|
|||||||
|
|
||||||
quint16 serverPort = 0;
|
quint16 serverPort = 0;
|
||||||
QThread *workerThread = nullptr;
|
QThread *workerThread = nullptr;
|
||||||
QNetworkAccessManager manager;
|
std::unique_ptr<QNetworkAccessManager> manager;
|
||||||
|
|
||||||
QTestEventLoop eventLoop;
|
QTestEventLoop eventLoop;
|
||||||
|
|
||||||
@ -131,6 +132,10 @@ private:
|
|||||||
static const Http2::RawSettings defaultServerSettings;
|
static const Http2::RawSettings defaultServerSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define STOP_ON_FAILURE \
|
||||||
|
if (QTest::currentTestFailed()) \
|
||||||
|
return;
|
||||||
|
|
||||||
const Http2::RawSettings tst_Http2::defaultServerSettings{{Http2::Settings::MAX_CONCURRENT_STREAMS_ID, 100}};
|
const Http2::RawSettings tst_Http2::defaultServerSettings{{Http2::Settings::MAX_CONCURRENT_STREAMS_ID, 100}};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -178,7 +183,7 @@ tst_Http2::~tst_Http2()
|
|||||||
|
|
||||||
void tst_Http2::init()
|
void tst_Http2::init()
|
||||||
{
|
{
|
||||||
manager.clearConnectionCache();
|
manager.reset(new QNetworkAccessManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Http2::singleRequest_data()
|
void tst_Http2::singleRequest_data()
|
||||||
@ -235,13 +240,14 @@ void tst_Http2::singleRequest()
|
|||||||
QFETCH(const QNetworkRequest::Attribute, h2Attribute);
|
QFETCH(const QNetworkRequest::Attribute, h2Attribute);
|
||||||
request.setAttribute(h2Attribute, QVariant(true));
|
request.setAttribute(h2Attribute, QVariant(true));
|
||||||
|
|
||||||
auto reply = manager.get(request);
|
auto reply = manager->get(request);
|
||||||
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
||||||
// Since we're using self-signed certificates,
|
// Since we're using self-signed certificates,
|
||||||
// ignore SSL errors:
|
// ignore SSL errors:
|
||||||
reply->ignoreSslErrors();
|
reply->ignoreSslErrors();
|
||||||
|
|
||||||
runEventLoop();
|
runEventLoop();
|
||||||
|
STOP_ON_FAILURE
|
||||||
|
|
||||||
QVERIFY(nRequests == 0);
|
QVERIFY(nRequests == 0);
|
||||||
QVERIFY(prefaceOK);
|
QVERIFY(prefaceOK);
|
||||||
@ -277,6 +283,7 @@ void tst_Http2::multipleRequests()
|
|||||||
sendRequest(i, priorities[QRandomGenerator::global()->bounded(3)]);
|
sendRequest(i, priorities[QRandomGenerator::global()->bounded(3)]);
|
||||||
|
|
||||||
runEventLoop();
|
runEventLoop();
|
||||||
|
STOP_ON_FAILURE
|
||||||
|
|
||||||
QVERIFY(nRequests == 0);
|
QVERIFY(nRequests == 0);
|
||||||
QVERIFY(prefaceOK);
|
QVERIFY(prefaceOK);
|
||||||
@ -306,7 +313,7 @@ void tst_Http2::flowControlClientSide()
|
|||||||
params.maxSessionReceiveWindowSize = Http2::defaultSessionWindowSize * 5;
|
params.maxSessionReceiveWindowSize = Http2::defaultSessionWindowSize * 5;
|
||||||
params.settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID] = Http2::defaultSessionWindowSize;
|
params.settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID] = Http2::defaultSessionWindowSize;
|
||||||
// Inform our manager about non-default settings:
|
// Inform our manager about non-default settings:
|
||||||
manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
|
manager->setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
|
||||||
|
|
||||||
const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}};
|
const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}};
|
||||||
ServerPtr srv(newServer(serverSettings, defaultConnectionType(), params));
|
ServerPtr srv(newServer(serverSettings, defaultConnectionType(), params));
|
||||||
@ -324,6 +331,7 @@ void tst_Http2::flowControlClientSide()
|
|||||||
sendRequest(i);
|
sendRequest(i);
|
||||||
|
|
||||||
runEventLoop(120000);
|
runEventLoop(120000);
|
||||||
|
STOP_ON_FAILURE
|
||||||
|
|
||||||
QVERIFY(nRequests == 0);
|
QVERIFY(nRequests == 0);
|
||||||
QVERIFY(prefaceOK);
|
QVERIFY(prefaceOK);
|
||||||
@ -364,6 +372,7 @@ void tst_Http2::flowControlServerSide()
|
|||||||
sendRequest(i, QNetworkRequest::NormalPriority, payload);
|
sendRequest(i, QNetworkRequest::NormalPriority, payload);
|
||||||
|
|
||||||
runEventLoop(120000);
|
runEventLoop(120000);
|
||||||
|
STOP_ON_FAILURE
|
||||||
|
|
||||||
QVERIFY(nRequests == 0);
|
QVERIFY(nRequests == 0);
|
||||||
QVERIFY(prefaceOK);
|
QVERIFY(prefaceOK);
|
||||||
@ -384,7 +393,7 @@ void tst_Http2::pushPromise()
|
|||||||
Http2::ProtocolParameters params;
|
Http2::ProtocolParameters params;
|
||||||
// Defaults are good, except ENABLE_PUSH:
|
// Defaults are good, except ENABLE_PUSH:
|
||||||
params.settingsFrameData[Settings::ENABLE_PUSH_ID] = 1;
|
params.settingsFrameData[Settings::ENABLE_PUSH_ID] = 1;
|
||||||
manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
|
manager->setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
|
||||||
|
|
||||||
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), params));
|
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), params));
|
||||||
srv->enablePushPromise(true, QByteArray("/script.js"));
|
srv->enablePushPromise(true, QByteArray("/script.js"));
|
||||||
@ -400,12 +409,13 @@ void tst_Http2::pushPromise()
|
|||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
|
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
|
||||||
|
|
||||||
auto reply = manager.get(request);
|
auto reply = manager->get(request);
|
||||||
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
||||||
// Since we're using self-signed certificates, ignore SSL errors:
|
// Since we're using self-signed certificates, ignore SSL errors:
|
||||||
reply->ignoreSslErrors();
|
reply->ignoreSslErrors();
|
||||||
|
|
||||||
runEventLoop();
|
runEventLoop();
|
||||||
|
STOP_ON_FAILURE
|
||||||
|
|
||||||
QVERIFY(nRequests == 0);
|
QVERIFY(nRequests == 0);
|
||||||
QVERIFY(prefaceOK);
|
QVERIFY(prefaceOK);
|
||||||
@ -423,7 +433,7 @@ void tst_Http2::pushPromise()
|
|||||||
url.setPath("/script.js");
|
url.setPath("/script.js");
|
||||||
QNetworkRequest promisedRequest(url);
|
QNetworkRequest promisedRequest(url);
|
||||||
promisedRequest.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
|
promisedRequest.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
|
||||||
reply = manager.get(promisedRequest);
|
reply = manager->get(promisedRequest);
|
||||||
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
||||||
reply->ignoreSslErrors();
|
reply->ignoreSslErrors();
|
||||||
|
|
||||||
@ -474,7 +484,7 @@ void tst_Http2::goaway()
|
|||||||
url.setPath(QString("/%1").arg(i));
|
url.setPath(QString("/%1").arg(i));
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
|
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
|
||||||
replies[i] = manager.get(request);
|
replies[i] = manager->get(request);
|
||||||
QCOMPARE(replies[i]->error(), QNetworkReply::NoError);
|
QCOMPARE(replies[i]->error(), QNetworkReply::NoError);
|
||||||
void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) =
|
void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) =
|
||||||
&QNetworkReply::error;
|
&QNetworkReply::error;
|
||||||
@ -484,6 +494,7 @@ void tst_Http2::goaway()
|
|||||||
}
|
}
|
||||||
|
|
||||||
runEventLoop(5000 + responseTimeoutMS);
|
runEventLoop(5000 + responseTimeoutMS);
|
||||||
|
STOP_ON_FAILURE
|
||||||
|
|
||||||
// No request processed, no 'replyFinished' slot calls:
|
// No request processed, no 'replyFinished' slot calls:
|
||||||
QCOMPARE(nRequests, 0);
|
QCOMPARE(nRequests, 0);
|
||||||
@ -527,6 +538,7 @@ void tst_Http2::earlyResponse()
|
|||||||
sendRequest(1, QNetworkRequest::NormalPriority, {1000000, Qt::Uninitialized});
|
sendRequest(1, QNetworkRequest::NormalPriority, {1000000, Qt::Uninitialized});
|
||||||
|
|
||||||
runEventLoop();
|
runEventLoop();
|
||||||
|
STOP_ON_FAILURE
|
||||||
|
|
||||||
QVERIFY(nRequests == 0);
|
QVERIFY(nRequests == 0);
|
||||||
QVERIFY(prefaceOK);
|
QVERIFY(prefaceOK);
|
||||||
@ -544,7 +556,7 @@ void tst_Http2::clearHTTP2State()
|
|||||||
windowUpdates = 0;
|
windowUpdates = 0;
|
||||||
prefaceOK = false;
|
prefaceOK = false;
|
||||||
serverGotSettingsACK = false;
|
serverGotSettingsACK = false;
|
||||||
manager.setProperty(Http2::http2ParametersPropertyName, QVariant());
|
manager->setProperty(Http2::http2ParametersPropertyName, QVariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Http2::runEventLoop(int ms)
|
void tst_Http2::runEventLoop(int ms)
|
||||||
@ -597,9 +609,9 @@ void tst_Http2::sendRequest(int streamNumber,
|
|||||||
|
|
||||||
QNetworkReply *reply = nullptr;
|
QNetworkReply *reply = nullptr;
|
||||||
if (payload.size())
|
if (payload.size())
|
||||||
reply = manager.post(request, payload);
|
reply = manager->post(request, payload);
|
||||||
else
|
else
|
||||||
reply = manager.get(request);
|
reply = manager->get(request);
|
||||||
|
|
||||||
reply->ignoreSslErrors();
|
reply->ignoreSslErrors();
|
||||||
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
||||||
@ -691,14 +703,29 @@ void tst_Http2::replyFinished()
|
|||||||
QVERIFY(nRequests);
|
QVERIFY(nRequests);
|
||||||
|
|
||||||
if (const auto reply = qobject_cast<QNetworkReply *>(sender())) {
|
if (const auto reply = qobject_cast<QNetworkReply *>(sender())) {
|
||||||
|
if (reply->error() != QNetworkReply::NoError)
|
||||||
|
stopEventLoop();
|
||||||
|
|
||||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||||
|
|
||||||
const QVariant http2Used(reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute));
|
const QVariant http2Used(reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute));
|
||||||
|
if (!http2Used.isValid() || !http2Used.toBool())
|
||||||
|
stopEventLoop();
|
||||||
|
|
||||||
QVERIFY(http2Used.isValid());
|
QVERIFY(http2Used.isValid());
|
||||||
QVERIFY(http2Used.toBool());
|
QVERIFY(http2Used.toBool());
|
||||||
|
|
||||||
const QVariant spdyUsed(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute));
|
const QVariant spdyUsed(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute));
|
||||||
|
if (!spdyUsed.isValid() || spdyUsed.toBool())
|
||||||
|
stopEventLoop();
|
||||||
|
|
||||||
QVERIFY(spdyUsed.isValid());
|
QVERIFY(spdyUsed.isValid());
|
||||||
QVERIFY(!spdyUsed.toBool());
|
QVERIFY(!spdyUsed.toBool());
|
||||||
|
|
||||||
const QVariant code(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute));
|
const QVariant code(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute));
|
||||||
|
if (!code.isValid() || !code.canConvert<int>() || code.value<int>() != 200)
|
||||||
|
stopEventLoop();
|
||||||
|
|
||||||
QVERIFY(code.isValid());
|
QVERIFY(code.isValid());
|
||||||
QVERIFY(code.canConvert<int>());
|
QVERIFY(code.canConvert<int>());
|
||||||
QCOMPARE(code.value<int>(), 200);
|
QCOMPARE(code.value<int>(), 200);
|
||||||
@ -716,6 +743,8 @@ void tst_Http2::replyFinishedWithError()
|
|||||||
if (const auto reply = qobject_cast<QNetworkReply *>(sender())) {
|
if (const auto reply = qobject_cast<QNetworkReply *>(sender())) {
|
||||||
// For now this is a 'generic' code, it just verifies some error was
|
// For now this is a 'generic' code, it just verifies some error was
|
||||||
// reported without testing its type.
|
// reported without testing its type.
|
||||||
|
if (reply->error() == QNetworkReply::NoError)
|
||||||
|
stopEventLoop();
|
||||||
QVERIFY(reply->error() != QNetworkReply::NoError);
|
QVERIFY(reply->error() != QNetworkReply::NoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user