Merge remote-tracking branch 'origin/5.14' into 5.15

Conflicts:
	src/gui/rhi/qshader.cpp
	tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp

Change-Id: I1c4ae718eb3592a0a0a90af9d11553f3ab68cad5
This commit is contained in:
Qt Forward Merge Bot 2019-11-15 01:00:11 +01:00 committed by Edward Welbourne
commit adc7bbe910
33 changed files with 359 additions and 76 deletions

View File

@ -209,6 +209,7 @@ sub classNames {
$$clean = 1; $$clean = 1;
$$requires = ""; $$requires = "";
my $suspended = 0;
my $ihdrbase = basename($iheader); my $ihdrbase = basename($iheader);
my $parsable = ""; my $parsable = "";
@ -221,9 +222,11 @@ sub classNames {
$$clean = 0 if ($line =~ m/^#pragma qt_sync_skip_header_check/); $$clean = 0 if ($line =~ m/^#pragma qt_sync_skip_header_check/);
return @ret if($line =~ m/^#pragma qt_sync_stop_processing/); return @ret if($line =~ m/^#pragma qt_sync_stop_processing/);
push(@ret, $1) if($line =~ m/^#pragma qt_class\(([^)]*)\)[\r\n]*$/); push(@ret, $1) if($line =~ m/^#pragma qt_class\(([^)]*)\)[\r\n]*$/);
$suspended = 1 if ($line =~ m/^#pragma qt_sync_suspend_processing/);
$suspended = 0 if ($line =~ m/^#pragma qt_sync_resume_processing/);
$line = 0; $line = 0;
} }
if($line) { if ($line && !$suspended) {
$line =~ s,//.*$,,; #remove c++ comments $line =~ s,//.*$,,; #remove c++ comments
$line .= ";" if($line =~ m/^Q_[A-Z_0-9]*\(.*\)[\r\n]*$/); #qt macro $line .= ";" if($line =~ m/^Q_[A-Z_0-9]*\(.*\)[\r\n]*$/); #qt macro
$line .= ";" if($line =~ m/^QT_(BEGIN|END)_HEADER[\r\n]*$/); #qt macro $line .= ";" if($line =~ m/^QT_(BEGIN|END)_HEADER[\r\n]*$/); #qt macro

View File

@ -609,8 +609,11 @@ defineTest(qtConfOutput_prepareOptions) {
qtConfAddNote("Available Android host does not match host architecture.") qtConfAddNote("Available Android host does not match host architecture.")
} }
} else { } else {
!exists($$ndk_tc_pfx/$$ndk_host/*): \ !exists($$ndk_tc_pfx/$$ndk_host/*) {
qtConfFatalError("Specified Android NDK host is invalid.") err = "Specified Android NDK host '$$ndk_host' is invalid. Expected files in the following directory to exist:"
err += '$${ndk_tc_pfx}/$${ndk_host}/'
qtConfFatalError($$err)
}
} }
android_abis = $$eval(config.input.android-abis) android_abis = $$eval(config.input.android-abis)

View File

@ -58,6 +58,7 @@
#include <QInputDialog> #include <QInputDialog>
#include <QMenuBar> #include <QMenuBar>
#include <QMessageBox> #include <QMessageBox>
#include <QCloseEvent>
//! [0] //! [0]
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)

View File

@ -5,6 +5,7 @@ QMAKE_OBJCXXFLAGS_PRECOMPILE = -x objective-c++-header -c ${QMAKE_PCH_INPUT}
QMAKE_OBJCXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE QMAKE_OBJCXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE
QMAKE_XCODE_GCC_VERSION = com.apple.compilers.llvm.clang.1_0 QMAKE_XCODE_GCC_VERSION = com.apple.compilers.llvm.clang.1_0
QMAKE_LFLAGS_LTCG_SEPARATE_DEBUG_INFO = -Wl,-object_path_lto,${OBJECTS_DIR}/${TARGET}_lto.o
QMAKE_CXXFLAGS += -stdlib=libc++ QMAKE_CXXFLAGS += -stdlib=libc++
QMAKE_LFLAGS += -stdlib=libc++ QMAKE_LFLAGS += -stdlib=libc++

View File

@ -63,6 +63,22 @@ contains(TEMPLATE, ".*app"):!build_pass:!android-embedded {
QML_ROOT_PATH = $$_PRO_FILE_PWD_ QML_ROOT_PATH = $$_PRO_FILE_PWD_
FILE_CONTENT += " \"qml-root-path\": $$emitString($$QML_ROOT_PATH)," FILE_CONTENT += " \"qml-root-path\": $$emitString($$QML_ROOT_PATH),"
FILE_CONTENT += " \"stdcpp-path\": $$emitString($$ANDROID_STDCPP_PATH)," FILE_CONTENT += " \"stdcpp-path\": $$emitString($$ANDROID_STDCPP_PATH),"
!isEmpty(RESOURCES) {
# Make sure that qmake generated qrc files are accounted for
load(resources_functions)
qtFlattenResources()
for(resource, RESOURCES) {
contains(resource, ".*\\qmake_qmake_immediate.qrc$") {
# They will be created for each architecture, since they could be different
# we need to account for all of them
for (arch, ANDROID_ABIS): \
rescopy += $$absolute_path("qmake_qmake_immediate.qrc", $$OUT_PWD/$$arch)
} else {
contains(resource, ".*\\.qrc$"): rescopy += $$absolute_path($$resource, $$_PRO_FILE_PWD_)
}
}
FILE_CONTENT += " \"qrcFiles\": $$emitString($$join(rescopy, ",")),"
}
FILE_CONTENT += "" FILE_CONTENT += ""
FILE_CONTENT += " \"application-binary\": $$emitString($$TARGET)" FILE_CONTENT += " \"application-binary\": $$emitString($$TARGET)"
FILE_CONTENT += "}" FILE_CONTENT += "}"

View File

@ -1,6 +1,12 @@
static:no-static-ltcg { static:no-static-ltcg {
# Static library but no-static-ltcg enabled: skip LTCG # Static library but no-static-ltcg enabled: skip LTCG
} else: CONFIG(release, debug|release) { } else: CONFIG(release, debug|release) {
separate_debug_info {
# Evaluate single-$ variable references that have no valid value at mkspec loading time
QMAKE_LFLAGS_LTCG_SEPARATE_DEBUG_INFO ~= s/\\$\\{/\$\$\{/
eval(QMAKE_LFLAGS_LTCG += $$QMAKE_LFLAGS_LTCG_SEPARATE_DEBUG_INFO)
}
# We need fat object files when creating static libraries on some platforms # We need fat object files when creating static libraries on some platforms
# so the linker will know to load a particular object from the library # so the linker will know to load a particular object from the library
# in the first place. On others, we have special ar and nm to create the symbol # in the first place. On others, we have special ar and nm to create the symbol

View File

@ -68,6 +68,7 @@
( ( __clang_major__ >= 4 ) || \ ( ( __clang_major__ >= 4 ) || \
( ( __clang_major__ == 3 ) && ( __clang_minor__ >= 2 ) ) ) ) ) && \ ( ( __clang_major__ == 3 ) && ( __clang_minor__ >= 2 ) ) ) ) ) && \
defined( __OPTIMIZE__ ) && \ defined( __OPTIMIZE__ ) && \
!defined( __EMSCRIPTEN__ ) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#ifdef __clang__ #ifdef __clang__

View File

@ -179,7 +179,7 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
The \c QtProject/qtlogging.ini file is looked up in all directories returned The \c QtProject/qtlogging.ini file is looked up in all directories returned
by QStandardPaths::GenericConfigLocation. by QStandardPaths::GenericConfigLocation.
Set the \c QT_LOGGING_DEBUG environment variable to find out where you logging Set the \c QT_LOGGING_DEBUG environment variable to find out where your logging
rules are loaded from. rules are loaded from.
\section2 Installing a Custom Filter \section2 Installing a Custom Filter

View File

@ -305,7 +305,6 @@ static QString locatePlugin(const QString& fileName)
paths.append(fileName.left(slash)); // don't include the '/' paths.append(fileName.left(slash)); // don't include the '/'
} else { } else {
paths = QCoreApplication::libraryPaths(); paths = QCoreApplication::libraryPaths();
paths.prepend(QStringLiteral(".")); // search in current dir first
} }
for (const QString &path : qAsConst(paths)) { for (const QString &path : qAsConst(paths)) {

View File

@ -633,7 +633,13 @@ bool QTimeZonePrivate::isValidId(const QByteArray &ianaId)
// Somewhat slack hand-rolled version: // Somewhat slack hand-rolled version:
const int MinSectionLength = 1; const int MinSectionLength = 1;
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
// Android has its own naming of zones.
// "Canada/East-Saskatchewan" has a 17-character second component.
const int MaxSectionLength = 17;
#else
const int MaxSectionLength = 14; const int MaxSectionLength = 14;
#endif
int sectionLength = 0; int sectionLength = 0;
for (const char *it = ianaId.begin(), * const end = ianaId.end(); it != end; ++it, ++sectionLength) { for (const char *it = ianaId.begin(), * const end = ianaId.end(); it != end; ++it, ++sectionLength) {
const char ch = *it; const char ch = *it;

View File

@ -79,6 +79,14 @@ qtConfig(png) {
HEADERS += image/qpnghandler_p.h HEADERS += image/qpnghandler_p.h
SOURCES += image/qpnghandler.cpp SOURCES += image/qpnghandler.cpp
QMAKE_USE_PRIVATE += libpng QMAKE_USE_PRIVATE += libpng
win32:mingw {
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86048
GCC_VERSION = "$${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.$${QMAKE_GCC_PATCH_VERSION}"
equals(GCC_VERSION, "8.1.0") {
QMAKE_CXXFLAGS += -fno-reorder-blocks-and-partition
}
}
} }
# SIMD # SIMD

View File

@ -853,7 +853,14 @@ private:
qint64 m_numericId; qint64 m_numericId;
}; };
Q_DECLARE_TYPEINFO(QPointingDeviceUniqueId, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QPointingDeviceUniqueId, Q_MOVABLE_TYPE);
#if 0
#pragma qt_sync_suspend_processing
#endif
template <> class QList<QPointingDeviceUniqueId> {}; // to prevent instantiation: use QVector instead template <> class QList<QPointingDeviceUniqueId> {}; // to prevent instantiation: use QVector instead
#if 0
#pragma qt_sync_resume_processing
#endif
Q_GUI_EXPORT bool operator==(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs) noexcept; Q_GUI_EXPORT bool operator==(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs) noexcept;
inline bool operator!=(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs) noexcept inline bool operator!=(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs) noexcept

View File

@ -694,9 +694,12 @@ static QSize fixInitialSize(QSize size, const QWindow *w,
However if the given window already has geometry which the application has However if the given window already has geometry which the application has
initialized, it takes priority. initialized, it takes priority.
*/ */
QRect QPlatformWindow::initialGeometry(const QWindow *w, QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry,
const QRect &initialGeometry, int defaultWidth, int defaultHeight) int defaultWidth, int defaultHeight,
const QScreen **resultingScreenReturn)
{ {
if (resultingScreenReturn)
*resultingScreenReturn = w->screen();
if (!w->isTopLevel()) { if (!w->isTopLevel()) {
const qreal factor = QHighDpiScaling::factor(w); const qreal factor = QHighDpiScaling::factor(w);
const QSize size = fixInitialSize(QHighDpi::fromNative(initialGeometry.size(), factor), const QSize size = fixInitialSize(QHighDpi::fromNative(initialGeometry.size(), factor),
@ -712,6 +715,8 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w,
: QGuiApplication::screenAt(initialGeometry.center()); : QGuiApplication::screenAt(initialGeometry.center());
if (!screen) if (!screen)
return initialGeometry; return initialGeometry;
if (resultingScreenReturn)
*resultingScreenReturn = screen;
// initialGeometry refers to window's screen // initialGeometry refers to window's screen
QRect rect(QHighDpi::fromNativePixels(initialGeometry, w)); QRect rect(QHighDpi::fromNativePixels(initialGeometry, w));
if (wp->resizeAutomatic) if (wp->resizeAutomatic)

View File

@ -63,6 +63,7 @@ QT_BEGIN_NAMESPACE
class QPlatformScreen; class QPlatformScreen;
class QPlatformWindowPrivate; class QPlatformWindowPrivate;
class QScreen;
class QWindow; class QWindow;
class QIcon; class QIcon;
class QRegion; class QRegion;
@ -142,8 +143,9 @@ public:
virtual void invalidateSurface(); virtual void invalidateSurface();
static QRect initialGeometry(const QWindow *w, static QRect initialGeometry(const QWindow *w, const QRect &initialGeometry,
const QRect &initialGeometry, int defaultWidth, int defaultHeight); int defaultWidth, int defaultHeight,
const QScreen **resultingScreenReturn = nullptr);
virtual void requestUpdate(); virtual void requestUpdate();
bool hasPendingUpdateRequest() const; bool hasPendingUpdateRequest() const;

View File

@ -345,10 +345,10 @@ void QShader::removeShader(const QShaderKey &key)
static void writeShaderKey(QDataStream *ds, const QShaderKey &k) static void writeShaderKey(QDataStream *ds, const QShaderKey &k)
{ {
*ds << k.source(); *ds << int(k.source());
*ds << k.sourceVersion().version(); *ds << k.sourceVersion().version();
*ds << k.sourceVersion().flags(); *ds << k.sourceVersion().flags();
*ds << k.sourceVariant(); *ds << int(k.sourceVariant());
} }
/*! /*!
@ -366,7 +366,7 @@ QByteArray QShader::serialized() const
return QByteArray(); return QByteArray();
ds << QShaderPrivate::QSB_VERSION; ds << QShaderPrivate::QSB_VERSION;
ds << d->stage; ds << int(d->stage);
ds << d->desc.toCbor(); ds << d->desc.toCbor();
ds << d->shaders.count(); ds << d->shaders.count();
for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) { for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) {

View File

@ -160,6 +160,10 @@ void QTextMarkdownImporter::import(QTextDocument *doc, const QString &markdown)
m_paragraphMargin = m_doc->defaultFont().pointSize() * 2 / 3; m_paragraphMargin = m_doc->defaultFont().pointSize() * 2 / 3;
m_cursor = new QTextCursor(doc); m_cursor = new QTextCursor(doc);
doc->clear(); doc->clear();
if (doc->defaultFont().pointSize() != -1)
m_monoFont.setPointSize(doc->defaultFont().pointSize());
else
m_monoFont.setPixelSize(doc->defaultFont().pixelSize());
qCDebug(lcMD) << "default font" << doc->defaultFont() << "mono font" << m_monoFont; qCDebug(lcMD) << "default font" << doc->defaultFont() << "mono font" << m_monoFont;
QByteArray md = markdown.toUtf8(); QByteArray md = markdown.toUtf8();
md_parse(md.constData(), MD_SIZE(md.size()), &callbacks, this); md_parse(md.constData(), MD_SIZE(md.size()), &callbacks, this);

View File

@ -113,16 +113,16 @@ void QLibInputTouch::processTouchMotion(libinput_event_touch *e)
DeviceState *state = deviceState(e); DeviceState *state = deviceState(e);
QWindowSystemInterface::TouchPoint *tp = state->point(slot); QWindowSystemInterface::TouchPoint *tp = state->point(slot);
if (tp) { if (tp) {
Qt::TouchPointState tmpState = Qt::TouchPointMoved;
const QPointF p = getPos(e); const QPointF p = getPos(e);
if (tp->area.center() != p) { if (tp->area.center() == p)
tmpState = Qt::TouchPointStationary;
else
tp->area.moveCenter(p); tp->area.moveCenter(p);
// 'down' may be followed by 'motion' within the same "frame". // 'down' may be followed by 'motion' within the same "frame".
// Handle this by compressing and keeping the Pressed state until the 'frame'. // Handle this by compressing and keeping the Pressed state until the 'frame'.
if (tp->state != Qt::TouchPointPressed) if (tp->state != Qt::TouchPointPressed && tp->state != Qt::TouchPointReleased)
tp->state = Qt::TouchPointMoved; tp->state = tmpState;
} else {
tp->state = Qt::TouchPointStationary;
}
} else { } else {
qWarning("Inconsistent touch state (got 'motion' without 'down')"); qWarning("Inconsistent touch state (got 'motion' without 'down')");
} }

View File

@ -628,17 +628,13 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
#endif #endif
} }
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(130000)
- (void)addInteraction:(id<UIInteraction>)interaction - (void)addInteraction:(id<UIInteraction>)interaction
{ {
if (__builtin_available(iOS 13.0, *)) { if ([NSStringFromClass(interaction.class) isEqualToString:@"UITextInteraction"])
if ([interaction isKindOfClass:UITextInteraction.class]) return;
return; // Prevent iOS from adding UITextInteraction
}
[super addInteraction:interaction]; [super addInteraction:interaction];
} }
#endif
@end @end

View File

@ -274,6 +274,8 @@ struct QWindowsContextPrivate {
const HRESULT m_oleInitializeResult; const HRESULT m_oleInitializeResult;
QWindow *m_lastActiveWindow = nullptr; QWindow *m_lastActiveWindow = nullptr;
bool m_asyncExpose = false; bool m_asyncExpose = false;
HPOWERNOTIFY m_powerNotification = nullptr;
HWND m_powerDummyWindow = nullptr;
}; };
QWindowsContextPrivate::QWindowsContextPrivate() QWindowsContextPrivate::QWindowsContextPrivate()
@ -314,6 +316,13 @@ QWindowsContext::~QWindowsContext()
#if QT_CONFIG(tabletevent) #if QT_CONFIG(tabletevent)
d->m_tabletSupport.reset(); // Destroy internal window before unregistering classes. d->m_tabletSupport.reset(); // Destroy internal window before unregistering classes.
#endif #endif
if (d->m_powerNotification)
UnregisterPowerSettingNotification(d->m_powerNotification);
if (d->m_powerDummyWindow)
DestroyWindow(d->m_powerDummyWindow);
unregisterWindowClasses(); unregisterWindowClasses();
if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE)
OleUninitialize(); OleUninitialize();
@ -381,6 +390,55 @@ bool QWindowsContext::initPointer(unsigned integrationOptions)
return true; return true;
} }
extern "C" LRESULT QT_WIN_CALLBACK qWindowsPowerWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message != WM_POWERBROADCAST || wParam != PBT_POWERSETTINGCHANGE)
return DefWindowProc(hwnd, message, wParam, lParam);
static bool initialized = false; // ignore the initial change
if (!initialized) {
initialized = true;
return DefWindowProc(hwnd, message, wParam, lParam);
}
auto setting = reinterpret_cast<const POWERBROADCAST_SETTING *>(lParam);
if (setting) {
auto data = reinterpret_cast<const DWORD *>(&setting->Data);
if (*data == 1) {
// Repaint the windows when returning from sleeping display mode.
const auto tlw = QGuiApplication::topLevelWindows();
for (auto w : tlw) {
if (w->isVisible() && w->windowState() != Qt::WindowMinimized) {
if (auto tw = QWindowsWindow::windowsWindowOf(w)) {
if (HWND hwnd = tw->handle()) {
InvalidateRect(hwnd, nullptr, false);
}
}
}
}
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
bool QWindowsContext::initPowerNotificationHandler()
{
if (d->m_powerNotification)
return false;
d->m_powerDummyWindow = createDummyWindow(QStringLiteral("QtPowerDummyWindow"), L"QtPowerDummyWindow", qWindowsPowerWindowProc);
if (!d->m_powerDummyWindow)
return false;
d->m_powerNotification = RegisterPowerSettingNotification(d->m_powerDummyWindow, &GUID_MONITOR_POWER_ON, DEVICE_NOTIFY_WINDOW_HANDLE);
if (!d->m_powerNotification) {
DestroyWindow(d->m_powerDummyWindow);
d->m_powerDummyWindow = nullptr;
return false;
}
return true;
}
void QWindowsContext::setTabletAbsoluteRange(int a) void QWindowsContext::setTabletAbsoluteRange(int a)
{ {
#if QT_CONFIG(tabletevent) #if QT_CONFIG(tabletevent)

View File

@ -176,6 +176,8 @@ public:
bool initTablet(unsigned integrationOptions); bool initTablet(unsigned integrationOptions);
bool initPointer(unsigned integrationOptions); bool initPointer(unsigned integrationOptions);
bool initPowerNotificationHandler();
int defaultDPI() const; int defaultDPI() const;
QString registerWindowClass(const QWindow *w); QString registerWindowClass(const QWindow *w);

View File

@ -258,6 +258,8 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramL
m_context.initTouch(m_options); m_context.initTouch(m_options);
QPlatformCursor::setCapability(QPlatformCursor::OverrideCursor); QPlatformCursor::setCapability(QPlatformCursor::OverrideCursor);
m_context.initPowerNotificationHandler();
} }
QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate() QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate()

View File

@ -759,7 +759,10 @@ QWindowsWindowData
const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w); const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w);
const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight); const QScreen *screen{};
const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry,
defaultWindowWidth, defaultWindowHeight,
&screen);
if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
title = topLevel ? qAppName() : w->objectName(); title = topLevel ? qAppName() : w->objectName();
@ -769,7 +772,9 @@ QWindowsWindowData
// Capture events before CreateWindowEx() returns. The context is cleared in // Capture events before CreateWindowEx() returns. The context is cleared in
// the QWindowsWindow constructor. // the QWindowsWindow constructor.
const QWindowCreationContextPtr context(new QWindowCreationContext(w, data.geometry, rect, data.customMargins, style, exStyle)); const QWindowCreationContextPtr context(new QWindowCreationContext(w, screen, data.geometry,
rect, data.customMargins,
style, exStyle));
QWindowsContext::instance()->setWindowCreationContext(context); QWindowsContext::instance()->setWindowCreationContext(context);
const bool hasFrame = (style & (WS_DLGFRAME | WS_THICKFRAME)); const bool hasFrame = (style & (WS_DLGFRAME | WS_THICKFRAME));
@ -879,10 +884,10 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang
// Scaling helpers for size constraints. // Scaling helpers for size constraints.
static QSize toNativeSizeConstrained(QSize dip, const QWindow *w) static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
{ {
if (QHighDpiScaling::isActive()) { if (QHighDpiScaling::isActive()) {
const qreal factor = QHighDpiScaling::factor(w); const qreal factor = QHighDpiScaling::factor(s);
if (!qFuzzyCompare(factor, qreal(1))) { if (!qFuzzyCompare(factor, qreal(1))) {
if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX) if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX)
dip.setWidth(qRound(qreal(dip.width()) * factor)); dip.setWidth(qRound(qreal(dip.width()) * factor));
@ -995,11 +1000,12 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co
return true; return true;
} }
void QWindowsGeometryHint::frameSizeConstraints(const QWindow *w, const QMargins &margins, void QWindowsGeometryHint::frameSizeConstraints(const QWindow *w, const QScreen *screen,
const QMargins &margins,
QSize *minimumSize, QSize *maximumSize) QSize *minimumSize, QSize *maximumSize)
{ {
*minimumSize = toNativeSizeConstrained(w->minimumSize(), w); *minimumSize = toNativeSizeConstrained(w->minimumSize(), screen);
*maximumSize = toNativeSizeConstrained(w->maximumSize(), w); *maximumSize = toNativeSizeConstrained(w->maximumSize(), screen);
const int maximumWidth = qMax(maximumSize->width(), minimumSize->width()); const int maximumWidth = qMax(maximumSize->width(), minimumSize->width());
const int maximumHeight = qMax(maximumSize->height(), minimumSize->height()); const int maximumHeight = qMax(maximumSize->height(), minimumSize->height());
@ -1017,12 +1023,13 @@ void QWindowsGeometryHint::frameSizeConstraints(const QWindow *w, const QMargins
} }
void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w, void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w,
const QScreen *screen,
const QMargins &margins, const QMargins &margins,
MINMAXINFO *mmi) MINMAXINFO *mmi)
{ {
QSize minimumSize; QSize minimumSize;
QSize maximumSize; QSize maximumSize;
frameSizeConstraints(w, margins, &minimumSize, &maximumSize); frameSizeConstraints(w, screen, margins, &minimumSize, &maximumSize);
qCDebug(lcQpaWindows).nospace() << '>' << __FUNCTION__ << '<' << " min=" qCDebug(lcQpaWindows).nospace() << '>' << __FUNCTION__ << '<' << " min="
<< minimumSize.width() << ',' << minimumSize.height() << minimumSize.width() << ',' << minimumSize.height()
<< " max=" << maximumSize.width() << ',' << maximumSize.height() << " max=" << maximumSize.width() << ',' << maximumSize.height()
@ -1041,6 +1048,13 @@ void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w,
qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__ << " out " << *mmi; qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__ << " out " << *mmi;
} }
void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w,
const QMargins &margins,
MINMAXINFO *mmi)
{
applyToMinMaxInfo(w, w->screen(), margins, mmi);
}
bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w) bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
{ {
return qt_window_private(const_cast<QWindow *>(w))->positionPolicy return qt_window_private(const_cast<QWindow *>(w))->positionPolicy
@ -1226,11 +1240,12 @@ void QWindowsForeignWindow::setVisible(bool visible)
\ingroup qt-lighthouse-win \ingroup qt-lighthouse-win
*/ */
QWindowCreationContext::QWindowCreationContext(const QWindow *w, QWindowCreationContext::QWindowCreationContext(const QWindow *w, const QScreen *s,
const QRect &geometryIn, const QRect &geometry, const QRect &geometryIn, const QRect &geometry,
const QMargins &cm, const QMargins &cm,
DWORD style, DWORD exStyle) : DWORD style, DWORD exStyle) :
window(w), window(w),
screen(s),
requestedGeometryIn(geometryIn), requestedGeometryIn(geometryIn),
requestedGeometry(geometry), requestedGeometry(geometry),
obtainedPos(geometryIn.topLeft()), obtainedPos(geometryIn.topLeft()),
@ -1270,7 +1285,7 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
void QWindowCreationContext::applyToMinMaxInfo(MINMAXINFO *mmi) const void QWindowCreationContext::applyToMinMaxInfo(MINMAXINFO *mmi) const
{ {
QWindowsGeometryHint::applyToMinMaxInfo(window, margins + customMargins, mmi); QWindowsGeometryHint::applyToMinMaxInfo(window, screen, margins + customMargins, mmi);
} }
/*! /*!

View File

@ -66,9 +66,12 @@ struct QWindowsGeometryHint
static QMargins frame(const QWindow *w, const QRect &geometry, static QMargins frame(const QWindow *w, const QRect &geometry,
DWORD style, DWORD exStyle); DWORD style, DWORD exStyle);
static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result); static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);
static void applyToMinMaxInfo(const QWindow *w, const QScreen *screen,
const QMargins &margins, MINMAXINFO *mmi);
static void applyToMinMaxInfo(const QWindow *w, const QMargins &margins, static void applyToMinMaxInfo(const QWindow *w, const QMargins &margins,
MINMAXINFO *mmi); MINMAXINFO *mmi);
static void frameSizeConstraints(const QWindow *w, const QMargins &margins, static void frameSizeConstraints(const QWindow *w, const QScreen *screen,
const QMargins &margins,
QSize *minimumSize, QSize *maximumSize); QSize *minimumSize, QSize *maximumSize);
static inline QPoint mapToGlobal(HWND hwnd, const QPoint &); static inline QPoint mapToGlobal(HWND hwnd, const QPoint &);
static inline QPoint mapToGlobal(const QWindow *w, const QPoint &); static inline QPoint mapToGlobal(const QWindow *w, const QPoint &);
@ -80,13 +83,16 @@ struct QWindowsGeometryHint
struct QWindowCreationContext struct QWindowCreationContext
{ {
explicit QWindowCreationContext(const QWindow *w, explicit QWindowCreationContext(const QWindow *w, const QScreen *s,
const QRect &geometryIn, const QRect &geometry, const QRect &geometryIn, const QRect &geometry,
const QMargins &customMargins, const QMargins &customMargins,
DWORD style, DWORD exStyle); DWORD style, DWORD exStyle);
void applyToMinMaxInfo(MINMAXINFO *mmi) const; void applyToMinMaxInfo(MINMAXINFO *mmi) const;
const QWindow *window; const QWindow *window;
// The screen to use to scale size constraints, etc. Might differ from the
// screen of the window after QPlatformWindow::initialGeometry() (QTBUG-77307).
const QScreen *screen;
QRect requestedGeometryIn; // QWindow scaled QRect requestedGeometryIn; // QWindow scaled
QRect requestedGeometry; // after QPlatformWindow::initialGeometry() QRect requestedGeometry; // after QPlatformWindow::initialGeometry()
QPoint obtainedPos; QPoint obtainedPos;

View File

@ -277,8 +277,9 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
} }
break; break;
case UIA_ValuePatternId: case UIA_ValuePatternId:
// All accessible controls return text(QAccessible::Value) (which may be empty). // All non-static controls support the Value pattern.
*pRetVal = new QWindowsUiaValueProvider(id()); if (accessible->role() != QAccessible::StaticText)
*pRetVal = new QWindowsUiaValueProvider(id());
break; break;
case UIA_RangeValuePatternId: case UIA_RangeValuePatternId:
// Controls providing a numeric value within a range (e.g., sliders, scroll bars, dials). // Controls providing a numeric value within a range (e.g., sliders, scroll bars, dials).

View File

@ -164,6 +164,7 @@ struct Options
QString applicationBinary; QString applicationBinary;
QString rootPath; QString rootPath;
QStringList qmlImportPaths; QStringList qmlImportPaths;
QStringList qrcFiles;
// Versioning // Versioning
QString versionName; QString versionName;
@ -976,7 +977,10 @@ bool readInputFile(Options *options)
} }
} }
} }
{
const QJsonValue qrcFiles = jsonObject.value(QLatin1String("qrcFiles"));
options->qrcFiles = qrcFiles.toString().split(QLatin1Char(','), QString::SkipEmptyParts);
}
options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QLatin1String("/AndroidManifest.xml")); options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QLatin1String("/AndroidManifest.xml"));
if (options->packageName.isEmpty()) if (options->packageName.isEmpty())
options->packageName = cleanPackageName(QLatin1String("org.qtproject.example.%1").arg(options->applicationBinary)); options->packageName = cleanPackageName(QLatin1String("org.qtproject.example.%1").arg(options->applicationBinary));
@ -1709,22 +1713,28 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
} }
QString rootPath = options->rootPath; QString rootPath = options->rootPath;
if (rootPath.isEmpty()) if (!options->qrcFiles.isEmpty()) {
rootPath = QFileInfo(options->inputFileName).absolutePath(); qmlImportScanner += QLatin1String(" -qrcFiles");
else for (const QString &qrcFile : options->qrcFiles)
rootPath = QFileInfo(rootPath).absoluteFilePath(); qmlImportScanner += QLatin1Char(' ') + shellQuote(qrcFile);
} else {
if (rootPath.isEmpty())
rootPath = QFileInfo(options->inputFileName).absolutePath();
else
rootPath = QFileInfo(rootPath).absoluteFilePath();
if (!rootPath.endsWith(QLatin1Char('/'))) if (!rootPath.endsWith(QLatin1Char('/')))
rootPath += QLatin1Char('/'); rootPath += QLatin1Char('/');
qmlImportScanner += QLatin1String(" -rootPath %1").arg(shellQuote(rootPath));
}
QStringList importPaths; QStringList importPaths;
importPaths += shellQuote(options->qtInstallDirectory + QLatin1String("/qml")); importPaths += shellQuote(options->qtInstallDirectory + QLatin1String("/qml"));
importPaths += shellQuote(rootPath); if (!rootPath.isEmpty())
importPaths += shellQuote(rootPath);
for (const QString &qmlImportPath : qAsConst(options->qmlImportPaths)) for (const QString &qmlImportPath : qAsConst(options->qmlImportPaths))
importPaths += shellQuote(qmlImportPath); importPaths += shellQuote(qmlImportPath);
qmlImportScanner += QLatin1String(" -importPath %1").arg(importPaths.join(QLatin1Char(' ')));
qmlImportScanner += QLatin1String(" -rootPath %1 -importPath %2")
.arg(shellQuote(rootPath), importPaths.join(QLatin1Char(' ')));
if (options->verbose) { if (options->verbose) {
fprintf(stdout, "Running qmlimportscanner with the following command: %s\n", fprintf(stdout, "Running qmlimportscanner with the following command: %s\n",
@ -1946,7 +1956,8 @@ bool readDependencies(Options *options)
} }
} }
if (!options->rootPath.isEmpty() && !scanImports(options, &usedDependencies)) if ((!options->rootPath.isEmpty() || options->qrcFiles.isEmpty()) &&
!scanImports(options, &usedDependencies))
return false; return false;
return true; return true;

View File

@ -233,7 +233,9 @@ void QTreeView::setModel(QAbstractItemModel *model)
d->viewItems.clear(); d->viewItems.clear();
d->expandedIndexes.clear(); d->expandedIndexes.clear();
d->hiddenIndexes.clear(); d->hiddenIndexes.clear();
d->geometryRecursionBlock = true; // do not update geometries due to signals from the headers
d->header->setModel(model); d->header->setModel(model);
d->geometryRecursionBlock = false;
QAbstractItemView::setModel(model); QAbstractItemView::setModel(model);
// QAbstractItemView connects to a private slot // QAbstractItemView connects to a private slot

View File

@ -85,6 +85,7 @@ QLabelPrivate::QLabelPrivate()
shortcutId(0), shortcutId(0),
#endif #endif
textformat(Qt::AutoText), textformat(Qt::AutoText),
effectiveTextFormat(Qt::PlainText),
textInteractionFlags(Qt::LinksAccessibleByMouse), textInteractionFlags(Qt::LinksAccessibleByMouse),
sizePolicy(), sizePolicy(),
margin(0), margin(0),
@ -94,7 +95,6 @@ QLabelPrivate::QLabelPrivate()
scaledcontents(false), scaledcontents(false),
textLayoutDirty(false), textLayoutDirty(false),
textDirty(false), textDirty(false),
isRichText(false),
isTextLabel(false), isTextLabel(false),
hasShortcut(/*???*/), hasShortcut(/*???*/),
#ifndef QT_NO_CURSOR #ifndef QT_NO_CURSOR
@ -294,8 +294,14 @@ void QLabel::setText(const QString &text)
d->text = text; d->text = text;
d->isTextLabel = true; d->isTextLabel = true;
d->textDirty = true; d->textDirty = true;
d->isRichText = d->textformat == Qt::RichText if (d->textformat == Qt::AutoText) {
|| (d->textformat == Qt::AutoText && Qt::mightBeRichText(d->text)); if (Qt::mightBeRichText(d->text))
d->effectiveTextFormat = Qt::RichText;
else
d->effectiveTextFormat = Qt::PlainText;
} else {
d->effectiveTextFormat = d->textformat;
}
d->control = oldControl; d->control = oldControl;
@ -306,7 +312,7 @@ void QLabel::setText(const QString &text)
d->control = nullptr; d->control = nullptr;
} }
if (d->isRichText) { if (d->effectiveTextFormat != Qt::PlainText) {
setMouseTracking(true); setMouseTracking(true);
} else { } else {
// Note: mouse tracking not disabled intentionally // Note: mouse tracking not disabled intentionally
@ -1478,14 +1484,19 @@ void QLabelPrivate::ensureTextPopulated() const
if (control) { if (control) {
QTextDocument *doc = control->document(); QTextDocument *doc = control->document();
if (textDirty) { if (textDirty) {
#ifndef QT_NO_TEXTHTMLPARSER if (effectiveTextFormat == Qt::PlainText) {
if (isRichText)
doc->setHtml(text);
else
doc->setPlainText(text); doc->setPlainText(text);
#else #if QT_CONFIG(texthtmlparser)
doc->setPlainText(text); } else if (effectiveTextFormat == Qt::RichText) {
doc->setHtml(text);
#endif #endif
#if QT_CONFIG(textmarkdownreader)
} else if (effectiveTextFormat == Qt::MarkdownText) {
doc->setMarkdown(text);
#endif
} else {
doc->setPlainText(text);
}
doc->setUndoRedoEnabled(false); doc->setUndoRedoEnabled(false);
#ifndef QT_NO_SHORTCUT #ifndef QT_NO_SHORTCUT
@ -1623,7 +1634,7 @@ QMenu *QLabelPrivate::createStandardContextMenu(const QPoint &pos)
{ {
QString linkToCopy; QString linkToCopy;
QPoint p; QPoint p;
if (control && isRichText) { if (control && effectiveTextFormat != Qt::PlainText) {
p = layoutPoint(pos); p = layoutPoint(pos);
linkToCopy = control->document()->documentLayout()->anchorAt(p); linkToCopy = control->document()->documentLayout()->anchorAt(p);
} }

View File

@ -93,8 +93,8 @@ public:
#endif #endif
inline bool needTextControl() const { inline bool needTextControl() const {
return isTextLabel return isTextLabel
&& (isRichText && (effectiveTextFormat != Qt::PlainText
|| (!isRichText && (textInteractionFlags & (Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard)))); || (textInteractionFlags & (Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard)));
} }
void ensureTextPopulated() const; void ensureTextPopulated() const;
@ -134,6 +134,7 @@ public:
int shortcutId; int shortcutId;
#endif #endif
Qt::TextFormat textformat; Qt::TextFormat textformat;
Qt::TextFormat effectiveTextFormat;
Qt::TextInteractionFlags textInteractionFlags; Qt::TextInteractionFlags textInteractionFlags;
mutable QSizePolicy sizePolicy; mutable QSizePolicy sizePolicy;
int margin; int margin;
@ -143,7 +144,6 @@ public:
uint scaledcontents : 1; uint scaledcontents : 1;
mutable uint textLayoutDirty : 1; mutable uint textLayoutDirty : 1;
mutable uint textDirty : 1; mutable uint textDirty : 1;
mutable uint isRichText : 1;
mutable uint isTextLabel : 1; mutable uint isTextLabel : 1;
mutable uint hasShortcut : 1; mutable uint hasShortcut : 1;
#ifndef QT_NO_CURSOR #ifndef QT_NO_CURSOR

View File

@ -2,10 +2,6 @@
[dataStreamTest] [dataStreamTest]
android android
# QTBUG-69128
[isTimeZoneIdAvailable]
android
# QTBUG-69129 # QTBUG-69129
[specificTransition] [specificTransition]
android android
@ -75,10 +71,14 @@ android
android android
[transitionEachZone:Asia/Chita@1970] [transitionEachZone:Asia/Chita@1970]
android android
[transitionEachZone:Asia/Choibalsan@1970]
android
[transitionEachZone:Asia/Dushanbe@1970] [transitionEachZone:Asia/Dushanbe@1970]
android android
[transitionEachZone:Asia/Ho_Chi_Minh@1970] [transitionEachZone:Asia/Ho_Chi_Minh@1970]
android android
[transitionEachZone:Asia/Hovd@1970]
android
[transitionEachZone:Asia/Kathmandu@1970] [transitionEachZone:Asia/Kathmandu@1970]
android android
[transitionEachZone:Asia/Katmandu@1970] [transitionEachZone:Asia/Katmandu@1970]
@ -109,6 +109,10 @@ android
android android
[transitionEachZone:Asia/Thimphu@1970] [transitionEachZone:Asia/Thimphu@1970]
android android
[transitionEachZone:Asia/Ulaanbaatar@1970]
android
[transitionEachZone:Asia/Ulan_Bator@1970]
android
[transitionEachZone:Asia/Ust-Nera@1970] [transitionEachZone:Asia/Ust-Nera@1970]
android android
[transitionEachZone:Atlantic/Cape_Verde@1970] [transitionEachZone:Atlantic/Cape_Verde@1970]

View File

@ -818,6 +818,10 @@ void tst_QTimeZone::isValidId_data()
QTest::addColumn<QByteArray>("input"); QTest::addColumn<QByteArray>("input");
QTest::addColumn<bool>("valid"); QTest::addColumn<bool>("valid");
// a-z, A-Z, 0-9, '.', '-', '_' are valid chars
// Can't start with '-'
// Parts separated by '/', each part min 1 and max of 14 chars
// (Android has parts with lengths up to 17, so tolerates this as a special case.)
#define TESTSET(name, section, valid) \ #define TESTSET(name, section, valid) \
QTest::newRow(name " front") << QByteArray(section "/xyz/xyz") << valid; \ QTest::newRow(name " front") << QByteArray(section "/xyz/xyz") << valid; \
QTest::newRow(name " middle") << QByteArray("xyz/" section "/xyz") << valid; \ QTest::newRow(name " middle") << QByteArray("xyz/" section "/xyz") << valid; \
@ -828,11 +832,16 @@ void tst_QTimeZone::isValidId_data()
// Parts separated by '/', each part min 1 and max of 14 chars // Parts separated by '/', each part min 1 and max of 14 chars
TESTSET("empty", "", false); TESTSET("empty", "", false);
TESTSET("minimal", "m", true); TESTSET("minimal", "m", true);
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
TESTSET("maximal", "East-Saskatchewan", true); // Android actually uses this
TESTSET("too long", "North-Saskatchewan", false); // ... but thankfully not this.
#else
TESTSET("maximal", "12345678901234", true); TESTSET("maximal", "12345678901234", true);
TESTSET("maximal twice", "12345678901234/12345678901234", true); TESTSET("maximal twice", "12345678901234/12345678901234", true);
TESTSET("too long", "123456789012345", false); TESTSET("too long", "123456789012345", false);
TESTSET("too-long/maximal", "123456789012345/12345678901234", false); TESTSET("too-long/maximal", "123456789012345/12345678901234", false);
TESTSET("maximal/too-long", "12345678901234/123456789012345", false); TESTSET("maximal/too-long", "12345678901234/123456789012345", false);
#endif
TESTSET("bad hyphen", "-hyphen", false); TESTSET("bad hyphen", "-hyphen", false);
TESTSET("good hyphen", "hy-phen", true); TESTSET("good hyphen", "hy-phen", true);
@ -879,6 +888,31 @@ void tst_QTimeZone::isValidId_data()
TESTSET("invalid char ' '", " ", false); TESTSET("invalid char ' '", " ", false);
#undef TESTSET #undef TESTSET
QTest::newRow("az alone") << QByteArray("az") << true;
QTest::newRow("AZ alone") << QByteArray("AZ") << true;
QTest::newRow("09 alone") << QByteArray("09") << true;
QTest::newRow("a/z alone") << QByteArray("a/z") << true;
QTest::newRow("a.z alone") << QByteArray("a.z") << true;
QTest::newRow("a-z alone") << QByteArray("a-z") << true;
QTest::newRow("a_z alone") << QByteArray("a_z") << true;
QTest::newRow(".z alone") << QByteArray(".z") << true;
QTest::newRow("_z alone") << QByteArray("_z") << true;
QTest::newRow("a z alone") << QByteArray("a z") << false;
QTest::newRow("a\\z alone") << QByteArray("a\\z") << false;
QTest::newRow("a,z alone") << QByteArray("a,z") << false;
QTest::newRow("/z alone") << QByteArray("/z") << false;
QTest::newRow("-z alone") << QByteArray("-z") << false;
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
QTest::newRow("long alone") << QByteArray("12345678901234567") << true;
QTest::newRow("over-long alone") << QByteArray("123456789012345678") << false;
#else
QTest::newRow("long alone") << QByteArray("12345678901234") << true;
QTest::newRow("over-long alone") << QByteArray("123456789012345") << false;
#endif
#else
QSKIP("This test requires a Qt -developer-build.");
#endif // QT_BUILD_INTERNAL #endif // QT_BUILD_INTERNAL
} }
@ -889,8 +923,6 @@ void tst_QTimeZone::isValidId()
QFETCH(bool, valid); QFETCH(bool, valid);
QCOMPARE(QTimeZonePrivate::isValidId(input), valid); QCOMPARE(QTimeZonePrivate::isValidId(input), valid);
#else
QSKIP("This test requires a Qt -developer-build.");
#endif #endif
} }

View File

@ -2868,6 +2868,7 @@ public:
}; };
Node *root; Node *root;
bool crash = false;
EvilModel(QObject *parent = nullptr): QAbstractItemModel(parent), root(new Node) EvilModel(QObject *parent = nullptr): QAbstractItemModel(parent), root(new Node)
{} {}
@ -2876,6 +2877,11 @@ public:
delete root; delete root;
} }
void setCrash()
{
crash = true;
}
void change() void change()
{ {
emit layoutAboutToBeChanged(); emit layoutAboutToBeChanged();
@ -2944,6 +2950,10 @@ public:
QVariant data(const QModelIndex &idx, int role) const override QVariant data(const QModelIndex &idx, int role) const override
{ {
if (crash) {
QTest::qFail("Should not get here...", __FILE__, __LINE__);
return QVariant();
}
if (idx.isValid() && role == Qt::DisplayRole) { if (idx.isValid() && role == Qt::DisplayRole) {
Node *parentNode = root; Node *parentNode = root;
if (idx.isValid()) { if (idx.isValid()) {
@ -2963,6 +2973,7 @@ void tst_QTreeView::evilModel_data()
{ {
QTest::addColumn<bool>("visible"); QTest::addColumn<bool>("visible");
QTest::newRow("visible") << false; QTest::newRow("visible") << false;
QTest::newRow("visible") << true;
} }
void tst_QTreeView::evilModel() void tst_QTreeView::evilModel()
@ -3132,6 +3143,9 @@ void tst_QTreeView::evilModel()
model.change(); model.change();
view.setRootIndex(secondLevel); view.setRootIndex(secondLevel);
model.setCrash();
view.setModel(nullptr);
} }
void tst_QTreeView::indexRowSizeHint() void tst_QTreeView::indexRowSizeHint()

View File

@ -29,6 +29,10 @@
#include <QGuiApplication> #include <QGuiApplication>
#include <QColorSpace> #include <QColorSpace>
// Run this with
// QT_LOGGING_RULES="qt.gui.icc=false"
// to reduce noise and increase speed.
extern "C" int LLVMFuzzerTestOneInput(const char *data, size_t size) { extern "C" int LLVMFuzzerTestOneInput(const char *data, size_t size) {
static int c = 0; static int c = 0;
static QGuiApplication a(c, nullptr); static QGuiApplication a(c, nullptr);

View File

@ -32,6 +32,7 @@
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
#include <QtCore/QSharedPointer> #include <QtCore/QSharedPointer>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QRect>
#include <QtCore/QVector> #include <QtCore/QVector>
#include <QtCore/qt_windows.h> #include <QtCore/qt_windows.h>
@ -54,14 +55,76 @@ struct DumpContext {
if (style & styleConstant) \ if (style & styleConstant) \
str << ' ' << #styleConstant; str << ' ' << #styleConstant;
static QTextStream &operator<<(QTextStream &str, const QPoint &p)
{
str << p.x() << ", " << p.y();
return str;
}
static QTextStream &operator<<(QTextStream &str, const QSize &s)
{
str << s.width() << 'x' << s.height();
return str;
}
static QTextStream &operator<<(QTextStream &str, const QRect &rect)
{
str << rect.size() << forcesign << rect.x() << rect.y() << noforcesign;
return str;
}
static inline QSize qsizeFromRECT(const RECT &rect)
{
return QSize(rect.right -rect.left, rect.bottom - rect.top);
}
static inline QRect qrectFromRECT(const RECT &rect)
{
return QRect(QPoint(rect.left, rect.top), qsizeFromRECT(rect));
}
static QRect getFrameGeometry(HWND hwnd)
{
RECT rect;
return GetWindowRect(hwnd, &rect) ? qrectFromRECT(rect) : QRect();
}
static QPoint getClientAreaScreenPos(HWND hwnd)
{
POINT clientPos{0, 0};
return ClientToScreen(hwnd, &clientPos) ? QPoint(clientPos.x, clientPos.y) : QPoint();
}
static QRect getClientAreaGeometry(HWND hwnd)
{
RECT clientRect;
return GetClientRect(hwnd, &clientRect)
? QRect(getClientAreaScreenPos(hwnd), qsizeFromRECT(clientRect)) : QRect();
}
static bool isTopLevel(HWND hwnd)
{
auto parent = GetParent(hwnd);
return !parent || parent == GetDesktopWindow();
}
static void formatNativeWindow(HWND hwnd, QTextStream &str) static void formatNativeWindow(HWND hwnd, QTextStream &str)
{ {
str << hex << showbase << quintptr(hwnd) << noshowbase << dec; str << hex << showbase << quintptr(hwnd) << noshowbase << dec;
RECT rect;
if (GetWindowRect(hwnd, &rect)) { const bool topLevel = isTopLevel(hwnd);
str << ' ' << (rect.right - rect.left) << 'x' << (rect.bottom - rect.top) if (topLevel)
<< forcesign << rect.left << rect.top << noforcesign; str << " [top]";
const auto frameGeometry = getFrameGeometry(hwnd);
const auto clientGeometry = getClientAreaGeometry(hwnd);
str << ' ' << frameGeometry;
if (!topLevel)
str << " local: " << (clientGeometry.topLeft() - getClientAreaScreenPos(GetParent(hwnd)));
if (clientGeometry != frameGeometry) {
str << " client: " << clientGeometry << " frame: "
<< (clientGeometry.topLeft() - frameGeometry.topLeft());
} }
if (IsWindowVisible(hwnd)) if (IsWindowVisible(hwnd))
str << " [visible]"; str << " [visible]";