Merge remote-tracking branch 'origin/5.12' into 5.13

Conflicts:
	qmake/generators/makefile.cpp
	src/plugins/platforms/cocoa/qcocoaintegration.h
	src/plugins/platforms/cocoa/qcocoaintegration.mm

Done-With: Jörg Bornemann <joerg.bornemann@qt.io>
Change-Id: I5a61e161784cc6f947abe370aab8f2971a9cbe78
This commit is contained in:
Liang Qi 2019-06-07 13:12:57 +02:00
commit 9967a011ea
61 changed files with 739 additions and 343 deletions

View File

@ -704,6 +704,7 @@
},
"optimize_debug": {
"label": "Optimize debug build",
"autoDetect": "!features.developer-build",
"condition": "!config.msvc && !config.clang && (features.debug || features.debug_and_release) && tests.optimize_debug",
"output": [ "privateConfig" ]
},

View File

@ -20,7 +20,7 @@
# output check that "EGLFS GBM .......... yes" is present, otherwise
# eglfs will not be functional.
#
# ./configure -release -opengl es2 -device linux-rpi3-vc4-g++ \
# ./configure -release -opengl es2 -device linux-rasp-pi3-vc4-g++ \
# -device-option CROSS_COMPILE=~/raspbian/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf- \
# -sysroot ~/raspbian/sysroot \
# -prefix /usr/local/qt5pi -extprefix ~/raspbian/qt5pi -hostprefix ~/raspbian/qt5 \

View File

@ -37,8 +37,10 @@ intel_icl {
QMAKE_DIR_REPLACE_SANE = PRECOMPILED_DIR OBJECTS_DIR MOC_DIR RCC_DIR UI_DIR
load(qt_prefix_build_check)
# force_independent can be set externally. prefix_build not.
!exists($$[QT_HOST_DATA]/.qmake.cache): \
qtIsPrefixBuild($$[QT_HOST_DATA]): \
CONFIG += prefix_build force_independent
!build_pass:!isEmpty(_QMAKE_SUPER_CACHE_):force_independent {

View File

@ -2510,17 +2510,19 @@ logn("Configure summary:")
logn()
qtConfPrintReport()
load(qt_prefix_build_check)
# final notes for the user
logn()
logn("Qt is now configured for building. Just run '$$QMAKE_MAKE_NAME'.")
pfx = $$[QT_INSTALL_PREFIX]
exists($$pfx/.qmake.cache) {
qtIsPrefixBuild($$pfx) {
logn("Once everything is built, you must run '$$QMAKE_MAKE_NAME install'.")
logn("Qt will be installed into '$$system_path($$pfx)'.")
} else {
logn("Once everything is built, Qt is installed.")
logn("You should NOT run '$$QMAKE_MAKE_NAME install'.")
logn("Note that this build cannot be deployed to other machines or devices.")
} else {
logn("Once everything is built, you must run '$$QMAKE_MAKE_NAME install'.")
logn("Qt will be installed into '$$system_path($$pfx)'.")
}
logn()
logn("Prior to reconfiguration, make sure you remove any leftovers from")

View File

@ -82,6 +82,11 @@ header_module {
CONFIG += force_qt # Needed for the headers_clean tests.
!lib_bundle: \
CONFIG += qt_no_install_library
# Allow creation of .prl, .la and .pc files.
target.path = $$[QT_INSTALL_LIBS]
target.CONFIG += dummy_install
INSTALLS += target
} else {
TEMPLATE = lib
}

View File

@ -0,0 +1,21 @@
#
# W A R N I N G
# -------------
#
# This file is not part of the Qt API. It exists purely as an
# implementation detail. It may change from version to version
# without notice, or even be removed.
#
# We mean it.
#
defineTest(qtIsPrefixBuild) {
prefixdir = $$1
# qtbase non-prefix build?
exists($$prefixdir/.qmake.cache): \
return(false)
# top-level non-prefix build?
contains(prefixdir, .*/qtbase):exists($$dirname(prefixdir)/.qmake.super): \
return(false)
return(true)
}

View File

@ -518,7 +518,6 @@ bool
ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
{
ProStringList tmp;
bool did_preprocess = false;
//HEADER
const int pbVersion = pbuilderVersion();
@ -736,7 +735,6 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
QFile mkf(mkfile);
if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
writingUnixMakefileGenerator = true;
did_preprocess = true;
debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
QTextStream mkt(&mkf);
writeHeader(mkt);

View File

@ -900,7 +900,7 @@ MakefileGenerator::processPrlFile(QString &file, bool baseOnly)
bool
MakefileGenerator::processPrlFileBase(QString &origFile, const QStringRef &origName,
const QStringRef &fixedBase, int slashOff)
const QStringRef &fixedBase, int /*slashOff*/)
{
return processPrlFileCore(origFile, origName, fixedBase + Option::prl_ext);
}
@ -1120,7 +1120,8 @@ MakefileGenerator::writePrlFile()
&& project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()
&& project->isActiveConfig("create_prl")
&& (project->first("TEMPLATE") == "lib"
|| project->first("TEMPLATE") == "vclib")
|| project->first("TEMPLATE") == "vclib"
|| project->first("TEMPLATE") == "aux")
&& (!project->isActiveConfig("plugin") || project->isActiveConfig("static"))) { //write prl file
QString local_prl = prlFileName();
QString prl = fileFixify(local_prl);
@ -2400,8 +2401,15 @@ MakefileGenerator::findSubDirsSubTargets() const
st->profile = file;
}
} else {
if(!file.isEmpty() && !project->isActiveConfig("subdir_first_pro"))
st->profile = file.section(Option::dir_sep, -1) + Option::pro_ext;
if (!file.isEmpty() && !project->isActiveConfig("subdir_first_pro")) {
const QString baseName = file.section(Option::dir_sep, -1);
if (baseName.isEmpty()) {
warn_msg(WarnLogic, "Ignoring invalid SUBDIRS entry %s",
subdirs[subdir].toLatin1().constData());
continue;
}
st->profile = baseName + Option::pro_ext;
}
st->in_directory = file;
}
while(st->in_directory.endsWith(Option::dir_sep))
@ -3352,6 +3360,7 @@ MakefileGenerator::writePkgConfigFile()
if (!version.isEmpty())
t << "Version: " << version << endl;
if (project->first("TEMPLATE") == "lib") {
// libs
t << "Libs: ";
QString pkgConfiglibName;
@ -3389,6 +3398,7 @@ MakefileGenerator::writePkgConfigFile()
t << ' ' << fixLibFlags((*it).toKey()).join(' ');
t << endl;
}
}
// flags
// ### too many
@ -3430,19 +3440,23 @@ QString MakefileGenerator::installMetaFile(const ProKey &replace_rule, const QSt
|| project->isActiveConfig("no_sed_meta_install")) {
ret += "-$(INSTALL_FILE) " + escapeFilePath(src) + ' ' + escapeFilePath(dst);
} else {
ret += "-$(SED)";
QString sedargs;
const ProStringList &replace_rules = project->values(replace_rule);
for (int r = 0; r < replace_rules.size(); ++r) {
const ProString match = project->first(ProKey(replace_rules.at(r) + ".match")),
replace = project->first(ProKey(replace_rules.at(r) + ".replace"));
if (!match.isEmpty() /*&& match != replace*/) {
ret += " -e " + shellQuote("s," + match + "," + replace + ",g");
sedargs += " -e " + shellQuote("s," + match + "," + replace + ",g");
if (isWindowsShell() && project->first(ProKey(replace_rules.at(r) + ".CONFIG")).contains("path"))
ret += " -e " + shellQuote("s," + windowsifyPath(match.toQString())
sedargs += " -e " + shellQuote("s," + windowsifyPath(match.toQString())
+ "," + windowsifyPath(replace.toQString()) + ",gi");
}
}
ret += ' ' + escapeFilePath(src) + " > " + escapeFilePath(dst);
if (sedargs.isEmpty()) {
ret += "-$(INSTALL_FILE) " + escapeFilePath(src) + ' ' + escapeFilePath(dst);
} else {
ret += "-$(SED) " + sedargs + ' ' + escapeFilePath(src) + " > " + escapeFilePath(dst);
}
}
return ret;
}

View File

@ -815,7 +815,7 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file)
break;
}
cpp_state = InCode;
// ... and fall through to handle buffer[x] as such.
Q_FALLTHROUGH(); // to handle buffer[x] as such.
case InCode:
// matching quotes (string literals and character literals)
if (buffer[x] == '\'' || buffer[x] == '"') {

View File

@ -43,7 +43,7 @@ protected:
void init() override;
bool writeMakefile(QTextStream &) override;
QString escapeFilePath(const QString &path) const override { Q_ASSERT(false); return QString(); }
QString escapeFilePath(const QString &) const override { Q_ASSERT(false); return QString(); }
public:
ProjectGenerator();

View File

@ -726,7 +726,7 @@ UnixMakefileGenerator::defaultInstall(const QString &t)
}
}
}
if(project->first("TEMPLATE") == "lib") {
if (isAux || project->first("TEMPLATE") == "lib") {
QStringList types;
types << "prl" << "libtool" << "pkgconfig";
for(int i = 0; i < types.size(); ++i) {

View File

@ -48,12 +48,15 @@ void
UnixMakefileGenerator::writePrlFile(QTextStream &t)
{
MakefileGenerator::writePrlFile(t);
const ProString tmplt = project->first("TEMPLATE");
if (tmplt != "lib" && tmplt != "aux")
return;
// libtool support
if(project->isActiveConfig("create_libtool") && project->first("TEMPLATE") == "lib") { //write .la
if (project->isActiveConfig("create_libtool")) {
writeLibtoolFile();
}
// pkg-config support
if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib")
if (project->isActiveConfig("create_pc"))
writePkgConfigFile();
}
@ -1199,7 +1202,8 @@ void UnixMakefileGenerator::init2()
project->values("QMAKE_FRAMEWORK_VERSION").append(project->first("VER_MAJ"));
if (project->first("TEMPLATE") == "aux") {
// nothing
project->values("PRL_TARGET") =
project->values("TARGET").first().prepend(project->first("QMAKE_PREFIX_STATICLIB"));
} else if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
if(!project->isEmpty("QMAKE_BUNDLE")) {
ProString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");

View File

@ -1990,6 +1990,7 @@ bool VCMIDLTool::parseOption(const char* option)
break;
case 0x5eb7af2: // /header filename
offset = 5;
Q_FALLTHROUGH();
case 0x0000358: // /h filename
HeaderFileName = option + offset + 3;
break;

View File

@ -1521,6 +1521,18 @@ void VcprojGenerator::initDistributionFiles()
vcProject.DistributionFiles.Config = &(vcProject.Configuration);
}
QString VcprojGenerator::extraCompilerName(const ProString &extraCompiler,
const QStringList &inputs,
const QStringList &outputs)
{
QString name = project->values(ProKey(extraCompiler + ".name")).join(' ');
if (name.isEmpty())
name = extraCompiler.toQString();
else
name = replaceExtraCompilerVariables(name, inputs, outputs, NoShell);
return name;
}
void VcprojGenerator::initExtraCompilerOutputs()
{
ProStringList otherFilters;
@ -1538,13 +1550,16 @@ void VcprojGenerator::initExtraCompilerOutputs()
<< "YACCSOURCES";
const ProStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
for (ProStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
ProString extracompilerName = project->first(ProKey(*it + ".name"));
if (extracompilerName.isEmpty())
extracompilerName = (*it);
const ProStringList &inputVars = project->values(ProKey(*it + ".input"));
ProStringList inputFiles;
for (auto var : inputVars)
inputFiles.append(project->values(var.toKey()));
const ProStringList &outputs = project->values(ProKey(*it + ".output"));
// Create an extra compiler filter and add the files
VCFilter extraCompile;
extraCompile.Name = extracompilerName.toQString();
extraCompile.Name = extraCompilerName(it->toQString(), inputFiles.toQStringList(),
outputs.toQStringList());
extraCompile.ParseFiles = _False;
extraCompile.Filter = "";
extraCompile.Guid = QString(_GUIDExtraCompilerFiles) + "-" + (*it);
@ -1557,14 +1572,14 @@ void VcprojGenerator::initExtraCompilerOutputs()
if (!outputVar.isEmpty() && otherFilters.contains(outputVar))
continue;
QString tmp_out = project->first(ProKey(*it + ".output")).toQString();
QString tmp_out = project->first(outputs.first().toKey()).toQString();
if (project->values(ProKey(*it + ".CONFIG")).indexOf("combine") != -1) {
// Combined output, only one file result
extraCompile.addFile(Option::fixPathToTargetOS(
replaceExtraCompilerVariables(tmp_out, QString(), QString(), NoShell), false));
} else {
// One output file per input
const ProStringList &tmp_in = project->values(project->first(ProKey(*it + ".input")).toKey());
const ProStringList &tmp_in = project->values(inputVars.first().toKey());
for (int i = 0; i < tmp_in.count(); ++i) {
const QString &filename = tmp_in.at(i).toQString();
if (extraCompilerSources.contains(filename) && !otherFiltersContain(filename))
@ -1577,7 +1592,6 @@ void VcprojGenerator::initExtraCompilerOutputs()
// build steps there. So, we turn it around and add it to the input files instead,
// provided that the input file variable is not handled already (those in otherFilters
// are handled, so we avoid them).
const ProStringList &inputVars = project->values(ProKey(*it + ".input"));
for (const ProString &inputVar : inputVars) {
if (!otherFilters.contains(inputVar)) {
const ProStringList &tmp_in = project->values(inputVar.toKey());

View File

@ -74,6 +74,8 @@ protected:
bool doDepends() const override { return false; } // Never necessary
using Win32MakefileGenerator::replaceExtraCompilerVariables;
QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &, ReplaceFor) override;
QString extraCompilerName(const ProString &extraCompiler, const QStringList &inputs,
const QStringList &outputs);
bool supportsMetaBuild() override { return true; }
bool supportsMergedBuilds() override { return true; }
bool mergeBuildProject(MakefileGenerator *other) override;

View File

@ -671,7 +671,7 @@ void Win32MakefileGenerator::writeObjectsPart(QTextStream &t)
t << "OBJECTS = " << valList(escapeDependencyPaths(project->values("OBJECTS"))) << endl;
}
void Win32MakefileGenerator::writeImplicitRulesPart(QTextStream &t)
void Win32MakefileGenerator::writeImplicitRulesPart(QTextStream &)
{
}

View File

@ -1128,34 +1128,47 @@ bool QMakeEvaluator::prepareProject(const QString &inDir)
}
superdir = qdfi.path();
}
QString sdir = inDir;
QString dir = m_outputDir;
forever {
conffile = sdir + QLatin1String("/.qmake.conf");
if (!m_vfs->exists(conffile, flags))
conffile.clear();
cachefile = dir + QLatin1String("/.qmake.cache");
if (!m_vfs->exists(cachefile, flags))
cachefile.clear();
if (!conffile.isEmpty() || !cachefile.isEmpty()) {
if (dir != sdir)
m_sourceRoot = sdir;
if (!cachefile.isEmpty()) {
m_buildRoot = dir;
break;
}
if (dir == superdir)
goto no_cache;
QFileInfo qsdfi(sdir);
QFileInfo qdfi(dir);
if (qsdfi.isRoot() || qdfi.isRoot())
goto no_cache;
sdir = qsdfi.path();
if (qdfi.isRoot()) {
cachefile.clear();
break;
}
dir = qdfi.path();
}
QString sdir = inDir;
forever {
conffile = sdir + QLatin1String("/.qmake.conf");
if (!m_vfs->exists(conffile, flags))
conffile.clear();
if (!conffile.isEmpty()) {
if (sdir != m_buildRoot)
m_sourceRoot = sdir;
break;
}
QFileInfo qsdfi(sdir);
if (qsdfi.isRoot()) {
conffile.clear();
break;
}
sdir = qsdfi.path();
}
} else {
m_buildRoot = QFileInfo(cachefile).path();
}
if (!conffile.isEmpty())
m_conffile = QDir::cleanPath(conffile);
if (!cachefile.isEmpty())
m_cachefile = QDir::cleanPath(cachefile);
}
no_cache:

View File

@ -296,6 +296,9 @@ endfunction()
# qt5_add_big_resources(outfiles inputfile ... )
function(QT5_ADD_BIG_RESOURCES outfiles )
if (CMAKE_VERSION VERSION_LESS 3.9)
message(FATAL_ERROR, "qt5_add_big_resources requires CMake 3.9 or newer")
endif()
set(options)
set(oneValueArgs)
@ -326,6 +329,8 @@ function(QT5_ADD_BIG_RESOURCES outfiles )
set_target_properties(rcc_object_${outfilename} PROPERTIES AUTOMOC OFF)
set_target_properties(rcc_object_${outfilename} PROPERTIES AUTOUIC OFF)
add_dependencies(rcc_object_${outfilename} big_resources_${outfilename})
# The modification of TARGET_OBJECTS needs the following change in cmake
# https://gitlab.kitware.com/cmake/cmake/commit/93c89bc75ceee599ba7c08b8fe1ac5104942054f
add_custom_command(OUTPUT ${outfile}
COMMAND ${Qt5Core_RCC_EXECUTABLE}
ARGS ${rcc_options} --name ${outfilename} --pass 2 --temp $<TARGET_OBJECTS:rcc_object_${outfilename}> --output ${outfile} ${infile}

View File

@ -131,6 +131,8 @@ files (\c .o, \c .obj) files instead of C++ source code. This allows to
embed bigger resources, where compiling to C++ sources and then to
binaries would be too time consuming or memory intensive.
Note that this macro is only available if using \c{CMake} 3.9 or later.
\section1 Arguments
You can set additional \c{OPTIONS} that should be added to the \c{rcc} calls.

View File

@ -432,7 +432,24 @@ void QLibraryInfo::reload()
{
QLibraryInfoPrivate::reload();
}
#endif
void QLibraryInfo::sysrootify(QString *path)
{
if (!QVariant::fromValue(rawLocation(SysrootifyPrefixPath, FinalPaths)).toBool())
return;
const QString sysroot = rawLocation(SysrootPath, FinalPaths);
if (sysroot.isEmpty())
return;
if (path->length() > 2 && path->at(1) == QLatin1Char(':')
&& (path->at(2) == QLatin1Char('/') || path->at(2) == QLatin1Char('\\'))) {
path->replace(0, 2, sysroot); // Strip out the drive on Windows targets
} else {
path->prepend(sysroot);
}
}
#endif // QT_BUILD_QMAKE
/*!
Returns the location specified by \a loc.
@ -444,18 +461,8 @@ QLibraryInfo::location(LibraryLocation loc)
QString ret = rawLocation(loc, FinalPaths);
// Automatically prepend the sysroot to target paths
if (loc < SysrootPath || loc > LastHostPath) {
QString sysroot = rawLocation(SysrootPath, FinalPaths);
if (!sysroot.isEmpty()
&& QVariant::fromValue(rawLocation(SysrootifyPrefixPath, FinalPaths)).toBool()) {
if (ret.length() > 2 && ret.at(1) == QLatin1Char(':')
&& (ret.at(2) == QLatin1Char('/') || ret.at(2) == QLatin1Char('\\'))) {
ret.replace(0, 2, sysroot); // Strip out the drive on Windows targets
} else {
ret.prepend(sysroot);
}
}
}
if (loc < SysrootPath || loc > LastHostPath)
sysrootify(&ret);
return ret;
}
@ -598,6 +605,8 @@ QLibraryInfo::rawLocation(LibraryLocation loc, PathGroup group)
} else {
// we make any other path absolute to the prefix directory
baseDir = rawLocation(PrefixPath, group);
if (group == EffectivePaths)
sysrootify(&baseDir);
}
#else
if (loc == PrefixPath) {

View File

@ -107,6 +107,7 @@ public:
enum PathGroup { FinalPaths, EffectivePaths, EffectiveSourcePaths, DevicePaths };
static QString rawLocation(LibraryLocation, PathGroup);
static void reload();
static void sysrootify(QString *path);
#endif
static QStringList platformPluginArguments(const QString &platformName);

View File

@ -228,7 +228,18 @@ QUrl QFileSelector::select(const QUrl &filePath) const
QString selectedPath = d->select(equivalentPath);
ret.setPath(selectedPath.remove(0, scheme.size()));
} else {
// we need to store the original query and fragment, since toLocalFile() will strip it off
QString frag;
if (ret.hasFragment())
frag = ret.fragment();
QString query;
if (ret.hasQuery())
query= ret.query();
ret = QUrl::fromLocalFile(d->select(ret.toLocalFile()));
if (!frag.isNull())
ret.setFragment(frag);
if (!query.isNull())
ret.setQuery(query);
}
return ret;
}

View File

@ -295,13 +295,13 @@ QT_MAC_WEAK_IMPORT(_os_activity_current);
// -------------------------------------------------------------------------
#if defined( __OBJC__)
class QMacScopedObserver
class QMacNotificationObserver
{
public:
QMacScopedObserver() {}
QMacNotificationObserver() {}
template<typename Functor>
QMacScopedObserver(id object, NSNotificationName name, Functor callback) {
QMacNotificationObserver(id object, NSNotificationName name, Functor callback) {
observer = [[NSNotificationCenter defaultCenter] addObserverForName:name
object:object queue:nil usingBlock:^(NSNotification *) {
callback();
@ -309,13 +309,13 @@ public:
];
}
QMacScopedObserver(const QMacScopedObserver& other) = delete;
QMacScopedObserver(QMacScopedObserver&& other) : observer(other.observer) {
QMacNotificationObserver(const QMacNotificationObserver& other) = delete;
QMacNotificationObserver(QMacNotificationObserver&& other) : observer(other.observer) {
other.observer = nil;
}
QMacScopedObserver &operator=(const QMacScopedObserver& other) = delete;
QMacScopedObserver &operator=(QMacScopedObserver&& other) {
QMacNotificationObserver &operator=(const QMacNotificationObserver& other) = delete;
QMacNotificationObserver &operator=(QMacNotificationObserver&& other) {
if (this != &other) {
remove();
observer = other.observer;
@ -329,7 +329,7 @@ public:
[[NSNotificationCenter defaultCenter] removeObserver:observer];
observer = nil;
}
~QMacScopedObserver() { remove(); }
~QMacNotificationObserver() { remove(); }
private:
id observer = nil;

View File

@ -329,19 +329,17 @@ static int fromOffsetString(const QStringRef &offsetString, bool *valid) Q_DECL_
\brief The QDate class provides date functions.
A QDate object encodes a calendar date, i.e. year, month, and day numbers,
in the proleptic Gregorian calendar by default. It can read the current date
from the system clock. It provides functions for comparing dates, and for
manipulating dates. For example, it is possible to add and subtract days,
months, and years to dates.
A QDate object represents a particular date. This can be expressed as a
calendar date, i.e. year, month, and day numbers, in the proleptic Gregorian
calendar.
A QDate object is typically created by giving the year, month, and day
numbers explicitly. Note that QDate interprets two digit years as presented,
i.e., as years 0 through 99, without adding any offset. A QDate can also be
constructed with the static function currentDate(), which creates a QDate
object containing the system clock's date. An explicit date can also be set
using setDate(). The fromString() function returns a QDate given a string
and a date format which is used to interpret the date within the string.
numbers explicitly. Note that QDate interprets year numbers less than 100 as
presented, i.e., as years 1 through 99, without adding any offset. The
static function currentDate() creates a QDate object containing the date
read from the system clock. An explicit date can also be set using
setDate(). The fromString() function returns a QDate given a string and a
date format which is used to interpret the date within the string.
The year(), month(), and day() functions provide access to the
year, month, and day numbers. Also, dayOfWeek() and dayOfYear()
@ -375,7 +373,7 @@ static int fromOffsetString(const QStringRef &offsetString, bool *valid) Q_DECL_
every day in a contiguous range, with 24 November 4714 BCE in the Gregorian
calendar being Julian Day 0 (1 January 4713 BCE in the Julian calendar).
As well as being an efficient and accurate way of storing an absolute date,
it is suitable for converting a Date into other calendar systems such as
it is suitable for converting a date into other calendar systems such as
Hebrew, Islamic or Chinese. The Julian Day number can be obtained using
QDate::toJulianDay() and can be set using QDate::fromJulianDay().
@ -1437,12 +1435,10 @@ bool QDate::isLeapYear(int y)
Unlike QDateTime, QTime knows nothing about time zones or
daylight-saving time (DST).
A QTime object is typically created either by giving the number
of hours, minutes, seconds, and milliseconds explicitly, or by
using the static function currentTime(), which creates a QTime
object that contains the system's local time. Note that the
accuracy depends on the accuracy of the underlying operating
system; not all systems provide 1-millisecond accuracy.
A QTime object is typically created either by giving the number of hours,
minutes, seconds, and milliseconds explicitly, or by using the static
function currentTime(), which creates a QTime object that represents the
system's local time.
The hour(), minute(), second(), and msec() functions provide
access to the number of hours, minutes, seconds, and milliseconds
@ -1902,6 +1898,12 @@ int QTime::msecsTo(const QTime &t) const
Note that the accuracy depends on the accuracy of the underlying
operating system; not all systems provide 1-millisecond accuracy.
Furthermore, currentTime() only increases within each day; it shall drop by
24 hours each time midnight passes; and, beside this, changes in it may not
correspond to elapsed time, if a daylight-saving transition intervenes.
\sa QDateTime::currentDateTime(), QDateTime::curentDateTimeUtc()
*/
#if QT_CONFIG(datestring)
@ -3020,15 +3022,30 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT
provides functions for comparing datetimes and for manipulating a
datetime by adding a number of seconds, days, months, or years.
A QDateTime object is typically created either by giving a date
and time explicitly in the constructor, or by using the static
function currentDateTime() that returns a QDateTime object set
to the system clock's time. The date and time can be changed with
setDate() and setTime(). A datetime can also be set using the
setTime_t() function that takes a POSIX-standard "number of
seconds since 00:00:00 on January 1, 1970" value. The fromString()
function returns a QDateTime, given a string and a date format
used to interpret the date within the string.
QDateTime can describe datetimes with respect to \l{Qt::LocalTime}{local
time}, to \l{Qt::UTC}{UTC}, to a specified \l{{Qt::OffsetFromUTC}{offset
from UTC} or to a specified \l{{Qt::TimeZone}{time zone}, in conjunction
with the QTimeZone class. For example, a time zone of "Europe/Berlin" will
apply the daylight-saving rules as used in Germany since 1970. In contrast,
an offset from UTC of +3600 seconds is one hour ahead of UTC (usually
written in ISO standard notation as "UTC+01:00"), with no daylight-saving
offset or changes. When using either local time or a specified time zone,
time-zone transitions such as the starts and ends of daylight-saving time
(DST) are taken into account. The choice of system used to represent a
datetime is described as its "timespec".
A QDateTime object is typically created either by giving a date and time
explicitly in the constructor, or by using a static function such as
currentDateTime() or fromMSecsSinceEpoch(). The date and time can be changed
with setDate() and setTime(). A datetime can also be set using the
setMSecsSinceEpoch() function that takes the time, in milliseconds, since
00:00:00 on January 1, 1970. The fromString() function returns a QDateTime,
given a string and a date format used to interpret the date within the
string.
QDateTime::currentDateTime() returns a QDateTime that expresses the current
time with respect to local time. QDateTime::currentDateTimeUtc() returns a
QDateTime that expresses the current time with respect to UTC.
The date() and time() functions provide access to the date and
time parts of the datetime. The same information is provided in
@ -3039,18 +3056,20 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT
later.
You can increment (or decrement) a datetime by a given number of
milliseconds using addMSecs(), seconds using addSecs(), or days
using addDays(). Similarly, you can use addMonths() and addYears().
The daysTo() function returns the number of days between two datetimes,
secsTo() returns the number of seconds between two datetimes, and
msecsTo() returns the number of milliseconds between two datetimes.
milliseconds using addMSecs(), seconds using addSecs(), or days using
addDays(). Similarly, you can use addMonths() and addYears(). The daysTo()
function returns the number of days between two datetimes, secsTo() returns
the number of seconds between two datetimes, and msecsTo() returns the
number of milliseconds between two datetimes. These operations are aware of
daylight-saving time (DST) and other time-zone transitions, where
applicable.
QDateTime can store datetimes as \l{Qt::LocalTime}{local time} or
as \l{Qt::UTC}{UTC}. QDateTime::currentDateTime() returns a
QDateTime expressed as local time; use toUTC() to convert it to
UTC. You can also use timeSpec() to find out if a QDateTime
object stores a UTC time or a local time. Operations such as
addSecs() and secsTo() are aware of daylight-saving time (DST).
Use toTimeSpec() to express a datetime in local time or UTC,
toOffsetFromUtc() to express in terms of an offset from UTC, or toTimeZone()
to express it with respect to a general time zone. You can use timeSpec() to
find out what time-spec a QDateTime object stores its time relative to. When
that is Qt::TimeZone, you can use timeZone() to find out which zone it is
using.
\note QDateTime does not account for leap seconds.
@ -3064,67 +3083,55 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT
\section2 Range of Valid Dates
The range of valid values able to be stored in QDateTime is dependent on
the internal storage implementation. QDateTime is currently stored in a
qint64 as a serial msecs value encoding the date and time. This restricts
the date range to about +/- 292 million years, compared to the QDate range
of +/- 2 billion years. Care must be taken when creating a QDateTime with
extreme values that you do not overflow the storage. The exact range of
supported values varies depending on the Qt::TimeSpec and time zone.
The range of values that QDateTime can represent is dependent on the
internal storage implementation. QDateTime is currently stored in a qint64
as a serial msecs value encoding the date and time. This restricts the date
range to about +/- 292 million years, compared to the QDate range of +/- 2
billion years. Care must be taken when creating a QDateTime with extreme
values that you do not overflow the storage. The exact range of supported
values varies depending on the Qt::TimeSpec and time zone.
\section2 Use of System Timezone
\section2 Use of Timezones
QDateTime uses the system's time zone information to determine the
offset of local time from UTC. If the system is not configured
correctly or not up-to-date, QDateTime will give wrong results as
well.
QDateTime uses the system's time zone information to determine the current
local time zone and its offset from UTC. If the system is not configured
correctly or not up-to-date, QDateTime will give wrong results.
QDateTime likewise uses system-provided information to determine the offsets
of other timezones from UTC. If this information is incomplete or out of
date, QDateTime will give wrong results. See the QTimeZone documentation for
more details.
On modern Unix systems, this means QDateTime usually has accurate
information about historical transitions (including DST, see below) whenever
possible. On Windows, where the system doesn't support historical timezone
data, historical accuracy is not maintained with respect to timezone
transitions, notably including DST.
\section2 Daylight-Saving Time (DST)
QDateTime takes into account the system's time zone information
when dealing with DST. On modern Unix systems, this means it
applies the correct historical DST data whenever possible. On
Windows, where the system doesn't support historical DST data,
historical accuracy is not maintained with respect to DST.
QDateTime takes into account transitions between Standard Time and
Daylight-Saving Time. For example, if the transition is at 2am and the clock
goes forward to 3am, then there is a "missing" hour from 02:00:00 to
02:59:59.999 which QDateTime considers to be invalid. Any date arithmetic
performed will take this missing hour into account and return a valid
result. For example, adding one minute to 01:59:59 will get 03:00:00.
The range of valid dates taking DST into account is 1970-01-01 to
the present, and rules are in place for handling DST correctly
until 2037-12-31, but these could change. For dates falling
outside that range, QDateTime makes a \e{best guess} using the
rules for year 1970 or 2037, but we can't guarantee accuracy. This
means QDateTime doesn't take into account changes in a locale's
time zone before 1970, even if the system's time zone database
supports that information.
The range of valid dates taking DST into account is 1970-01-01 to the
present, and rules are in place for handling DST correctly until 2037-12-31,
but these could change. For dates falling outside that range, QDateTime
makes a \e{best guess} using the rules for year 1970 or 2037, but we can't
guarantee accuracy. This means QDateTime doesn't take into account changes
in a time zone before 1970, even if the system's time zone database provides
that information.
QDateTime takes into consideration the Standard Time to Daylight-Saving Time
transition. For example if the transition is at 2am and the clock goes
forward to 3am, then there is a "missing" hour from 02:00:00 to 02:59:59.999
which QDateTime considers to be invalid. Any date maths performed
will take this missing hour into account and return a valid result.
\section2 Offsets From UTC
\section2 Offset From UTC
A Qt::TimeSpec of Qt::OffsetFromUTC is also supported. This allows you
to define a QDateTime relative to UTC at a fixed offset of a given number
of seconds from UTC. For example, an offset of +3600 seconds is one hour
ahead of UTC and is usually written in ISO standard notation as
"UTC+01:00". Daylight-Saving Time never applies with this TimeSpec.
There is no explicit size restriction to the offset seconds, but there is
an implicit limit imposed when using the toString() and fromString()
methods which use a format of [+|-]hh:mm, effectively limiting the range
to +/- 99 hours and 59 minutes and whole minutes only. Note that currently
no time zone lies outside the range of +/- 14 hours.
\section2 Time Zone Support
A Qt::TimeSpec of Qt::TimeZone is also supported in conjunction with the
QTimeZone class. This allows you to define a datetime in a named time zone
adhering to a consistent set of daylight-saving transition rules. For
example a time zone of "Europe/Berlin" will apply the daylight-saving
rules as used in Germany since 1970. Note that the transition rules
applied depend on the platform support. See the QTimeZone documentation
for more details.
There is no explicit size restriction on an offset from UTC, but there is an
implicit limit imposed when using the toString() and fromString() methods
which use a [+|-]hh:mm format, effectively limiting the range to +/- 99
hours and 59 minutes and whole minutes only. Note that currently no time
zone lies outside the range of +/- 14 hours.
\sa QDate, QTime, QDateTimeEdit, QTimeZone
*/
@ -4247,7 +4254,7 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const
Example:
\snippet code/src_corelib_tools_qdatetime.cpp 16
\sa timeSpec(), toTimeZone(), toUTC(), toLocalTime()
\sa timeSpec(), toTimeZone(), toOffsetFromUtc()
*/
QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const

View File

@ -825,7 +825,7 @@ static QString wc2rx(const QString &wc_str, const bool enableEscaping)
if (wc[i] == QLatin1Char('^'))
rx += wc[i++];
if (i < wclen) {
if (rx[i] == QLatin1Char(']'))
if (wc[i] == QLatin1Char(']'))
rx += wc[i++];
while (i < wclen && wc[i] != QLatin1Char(']')) {
if (wc[i] == QLatin1Char('\\'))

View File

@ -51,6 +51,12 @@
#include "qlocale_tools_p.h"
#include <algorithm>
#include <errno.h>
#include <limits.h>
#if !defined(Q_OS_INTEGRITY)
#include <sys/param.h> // to use MAXSYMLINKS constant
#endif
#include <unistd.h> // to use _SC_SYMLOOP_MAX constant
QT_BEGIN_NAMESPACE
@ -1045,6 +1051,27 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecs
return last > m_tranTimes.cbegin() ? dataForTzTransition(*--last) : invalidData();
}
static long getSymloopMax()
{
#if defined(SYMLOOP_MAX)
return SYMLOOP_MAX; // if defined, at runtime it can only be greater than this, so this is a safe bet
#else
errno = 0;
long result = sysconf(_SC_SYMLOOP_MAX);
if (result >= 0)
return result;
// result is -1, meaning either error or no limit
Q_ASSERT(!errno); // ... but it can't be an error, POSIX mandates _SC_SYMLOOP_MAX
// therefore we can make up our own limit
# if defined(MAXSYMLINKS)
return MAXSYMLINKS;
# else
return 8;
# endif
#endif
}
// TODO Could cache the value and monitor the required files for any changes
QByteArray QTzTimeZonePrivate::systemTimeZoneId() const
{
@ -1062,12 +1089,18 @@ QByteArray QTzTimeZonePrivate::systemTimeZoneId() const
// On most distros /etc/localtime is a symlink to a real file so extract name from the path
if (ianaId.isEmpty()) {
const QString path = QFile::symLinkTarget(QStringLiteral("/etc/localtime"));
if (!path.isEmpty()) {
const QLatin1String zoneinfo("/zoneinfo/");
QString path = QFile::symLinkTarget(QStringLiteral("/etc/localtime"));
int index = -1;
long iteration = getSymloopMax();
// Symlink may point to another symlink etc. before being under zoneinfo/
// We stop on the first path under /zoneinfo/, even if it is itself a
// symlink, like America/Montreal pointing to America/Toronto
while (iteration-- > 0 && !path.isEmpty() && (index = path.indexOf(zoneinfo)) < 0)
path = QFile::symLinkTarget(path);
if (index >= 0) {
// /etc/localtime is a symlink to the current TZ file, so extract from path
int index = path.indexOf(QLatin1String("/zoneinfo/"));
if (index != -1)
ianaId = path.mid(index + 10).toUtf8();
ianaId = path.mid(index + zoneinfo.size()).toUtf8();
}
}

View File

@ -1008,6 +1008,8 @@ QDataStream &operator<<(QDataStream &s, const QPalette &p)
max = QPalette::HighlightedText + 1;
else if (s.version() <= QDataStream::Qt_4_3)
max = QPalette::AlternateBase + 1;
else if (s.version() <= QDataStream::Qt_5_11)
max = QPalette::ToolTipText + 1;
for (int r = 0; r < max; r++)
s << p.d->br[grp][r];
}
@ -1048,6 +1050,9 @@ QDataStream &operator>>(QDataStream &s, QPalette &p)
} else if (s.version() <= QDataStream::Qt_4_3) {
p = QPalette();
max = QPalette::AlternateBase + 1;
} else if (s.version() <= QDataStream::Qt_5_11) {
p = QPalette();
max = QPalette::ToolTipText + 1;
}
QBrush tmp;

View File

@ -218,6 +218,12 @@ QWindow::~QWindow()
QGuiApplicationPrivate::window_list.removeAll(this);
if (!QGuiApplicationPrivate::is_app_closing)
QGuiApplicationPrivate::instance()->modalWindowList.removeOne(this);
// focus_window is normally cleared in destroy(), but the window may in
// some cases end up becoming the focus window again. Clear it again
// here as a workaround. See QTBUG-75326.
if (QGuiApplicationPrivate::focus_window == this)
QGuiApplicationPrivate::focus_window = 0;
}
void QWindowPrivate::init(QScreen *targetScreen)

View File

@ -71,6 +71,24 @@
QT_BEGIN_NAMESPACE
static inline bool isValidCoord(qreal c)
{
if (sizeof(qreal) >= sizeof(double))
return qIsFinite(c) && fabs(c) < 1e128;
else
return qIsFinite(c) && fabsf(float(c)) < 1e16f;
}
static bool hasValidCoords(QPointF p)
{
return isValidCoord(p.x()) && isValidCoord(p.y());
}
static bool hasValidCoords(QRectF r)
{
return isValidCoord(r.x()) && isValidCoord(r.y()) && isValidCoord(r.width()) && isValidCoord(r.height());
}
struct QPainterPathPrivateDeleter
{
static inline void cleanup(QPainterPathPrivate *d)
@ -724,9 +742,9 @@ void QPainterPath::moveTo(const QPointF &p)
printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y());
#endif
if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) {
if (!hasValidCoords(p)) {
#ifndef QT_NO_DEBUG
qWarning("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call");
qWarning("QPainterPath::moveTo: Adding point with invalid coordinates, ignoring call");
#endif
return;
}
@ -774,9 +792,9 @@ void QPainterPath::lineTo(const QPointF &p)
printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y());
#endif
if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) {
if (!hasValidCoords(p)) {
#ifndef QT_NO_DEBUG
qWarning("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call");
qWarning("QPainterPath::lineTo: Adding point with invalid coordinates, ignoring call");
#endif
return;
}
@ -833,10 +851,9 @@ void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &
c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
#endif
if (!qt_is_finite(c1.x()) || !qt_is_finite(c1.y()) || !qt_is_finite(c2.x()) || !qt_is_finite(c2.y())
|| !qt_is_finite(e.x()) || !qt_is_finite(e.y())) {
if (!hasValidCoords(c1) || !hasValidCoords(c2) || !hasValidCoords(e)) {
#ifndef QT_NO_DEBUG
qWarning("QPainterPath::cubicTo: Adding point where x or y is NaN or Inf, ignoring call");
qWarning("QPainterPath::cubicTo: Adding point with invalid coordinates, ignoring call");
#endif
return;
}
@ -890,9 +907,9 @@ void QPainterPath::quadTo(const QPointF &c, const QPointF &e)
c.x(), c.y(), e.x(), e.y());
#endif
if (!qt_is_finite(c.x()) || !qt_is_finite(c.y()) || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) {
if (!hasValidCoords(c) || !hasValidCoords(e)) {
#ifndef QT_NO_DEBUG
qWarning("QPainterPath::quadTo: Adding point where x or y is NaN or Inf, ignoring call");
qWarning("QPainterPath::quadTo: Adding point with invalid coordinates, ignoring call");
#endif
return;
}
@ -961,10 +978,9 @@ void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength
rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength);
#endif
if ((!qt_is_finite(rect.x()) && !qt_is_finite(rect.y())) || !qt_is_finite(rect.width()) || !qt_is_finite(rect.height())
|| !qt_is_finite(startAngle) || !qt_is_finite(sweepLength)) {
if (!hasValidCoords(rect) || !isValidCoord(startAngle) || !isValidCoord(sweepLength)) {
#ifndef QT_NO_DEBUG
qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN or Inf, ignoring call");
qWarning("QPainterPath::arcTo: Adding point with invalid coordinates, ignoring call");
#endif
return;
}
@ -1067,9 +1083,9 @@ QPointF QPainterPath::currentPosition() const
*/
void QPainterPath::addRect(const QRectF &r)
{
if (!qt_is_finite(r.x()) || !qt_is_finite(r.y()) || !qt_is_finite(r.width()) || !qt_is_finite(r.height())) {
if (!hasValidCoords(r)) {
#ifndef QT_NO_DEBUG
qWarning("QPainterPath::addRect: Adding rect where a parameter is NaN or Inf, ignoring call");
qWarning("QPainterPath::addRect: Adding point with invalid coordinates, ignoring call");
#endif
return;
}
@ -1147,10 +1163,9 @@ void QPainterPath::addPolygon(const QPolygonF &polygon)
*/
void QPainterPath::addEllipse(const QRectF &boundingRect)
{
if (!qt_is_finite(boundingRect.x()) || !qt_is_finite(boundingRect.y())
|| !qt_is_finite(boundingRect.width()) || !qt_is_finite(boundingRect.height())) {
if (!hasValidCoords(boundingRect)) {
#ifndef QT_NO_DEBUG
qWarning("QPainterPath::addEllipse: Adding ellipse where a parameter is NaN or Inf, ignoring call");
qWarning("QPainterPath::addEllipse: Adding point with invalid coordinates, ignoring call");
#endif
return;
}
@ -2501,6 +2516,7 @@ QDataStream &operator<<(QDataStream &s, const QPainterPath &p)
*/
QDataStream &operator>>(QDataStream &s, QPainterPath &p)
{
bool errorDetected = false;
int size;
s >> size;
@ -2519,10 +2535,11 @@ QDataStream &operator>>(QDataStream &s, QPainterPath &p)
s >> x;
s >> y;
Q_ASSERT(type >= 0 && type <= 3);
if (!qt_is_finite(x) || !qt_is_finite(y)) {
if (!isValidCoord(qreal(x)) || !isValidCoord(qreal(y))) {
#ifndef QT_NO_DEBUG
qWarning("QDataStream::operator>>: NaN or Inf element found in path, skipping it");
qWarning("QDataStream::operator>>: Invalid QPainterPath coordinates read, skipping it");
#endif
errorDetected = true;
continue;
}
QPainterPath::Element elm = { qreal(x), qreal(y), QPainterPath::ElementType(type) };
@ -2535,6 +2552,8 @@ QDataStream &operator>>(QDataStream &s, QPainterPath &p)
p.d_func()->fillRule = Qt::FillRule(fillRule);
p.d_func()->dirtyBounds = true;
p.d_func()->dirtyControlBounds = true;
if (errorDetected)
p = QPainterPath(); // Better than to return path with possibly corrupt datastructure, which would likely cause crash
return s;
}
#endif // QT_NO_DATASTREAM

View File

@ -80,7 +80,7 @@ private:
NSOpenGLContext *m_shareContext = nil;
QSurfaceFormat m_format;
bool m_didCheckForSoftwareContext = false;
QVarLengthArray<QMacScopedObserver, 3> m_updateObservers;
QVarLengthArray<QMacNotificationObserver, 3> m_updateObservers;
QAtomicInt m_needsUpdate = false;
};

View File

@ -404,13 +404,13 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface)
m_updateObservers.clear();
if (view.layer) {
m_updateObservers.append(QMacScopedObserver(view, NSViewFrameDidChangeNotification, updateCallback));
m_updateObservers.append(QMacScopedObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback));
m_updateObservers.append(QMacNotificationObserver(view, NSViewFrameDidChangeNotification, updateCallback));
m_updateObservers.append(QMacNotificationObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback));
} else {
m_updateObservers.append(QMacScopedObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback));
m_updateObservers.append(QMacNotificationObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback));
}
m_updateObservers.append(QMacScopedObserver([NSApplication sharedApplication],
m_updateObservers.append(QMacNotificationObserver([NSApplication sharedApplication],
NSApplicationDidChangeScreenParametersNotification, updateCallback));
// If any of the observers fire at this point it's fine. We check the

View File

@ -297,13 +297,12 @@ Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
*/
Qt::MouseButton cocoaButton2QtButton(NSEvent *event)
{
switch (event.type) {
case NSEventTypeMouseMoved:
if (cocoaEvent2QtMouseEvent(event) == QEvent::MouseMove)
return Qt::NoButton;
switch (event.type) {
case NSEventTypeRightMouseUp:
case NSEventTypeRightMouseDown:
case NSEventTypeRightMouseDragged:
return Qt::RightButton;
default:

View File

@ -45,6 +45,8 @@
Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver));
#include <QtCore/private/qcore_mac_p.h>
QT_BEGIN_NAMESPACE
class QPalette;
@ -82,6 +84,7 @@ public:
private:
mutable QPalette *m_systemPalette;
QMacNotificationObserver m_systemColorObserver;
mutable QHash<QPlatformTheme::Palette, QPalette*> m_palettes;
mutable QHash<QPlatformTheme::Font, QFont*> m_fonts;
QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) *m_appearanceObserver;

View File

@ -133,10 +133,10 @@ QCocoaTheme::QCocoaTheme()
m_appearanceObserver = [[QCocoaThemeAppAppearanceObserver alloc] initWithTheme:this];
#endif
[[NSNotificationCenter defaultCenter] addObserverForName:NSSystemColorsDidChangeNotification
object:nil queue:nil usingBlock:^(NSNotification *) {
m_systemColorObserver = QMacNotificationObserver(nil,
NSSystemColorsDidChangeNotification, [this] {
handleSystemThemeChange();
}];
});
}
QCocoaTheme::~QCocoaTheme()

View File

@ -54,7 +54,7 @@ QCocoaVulkanInstance::~QCocoaVulkanInstance()
void QCocoaVulkanInstance::createOrAdoptInstance()
{
initInstance(m_instance, QByteArrayList());
initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_MVK_macos_surface"));
}
VkSurfaceKHR *QCocoaVulkanInstance::createSurface(QWindow *window)

View File

@ -277,20 +277,19 @@
nativeDrag->setLastMouseEvent(theEvent, self);
const auto modifiers = [QNSView convertKeyModifiers:theEvent.modifierFlags];
const auto buttons = currentlyPressedMouseButtons();
auto button = cocoaButton2QtButton(theEvent);
if (button == Qt::LeftButton && m_sendUpAsRightButton)
button = Qt::RightButton;
const auto eventType = cocoaEvent2QtMouseEvent(theEvent);
if (eventType == QEvent::MouseMove)
qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << buttons;
qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << m_buttons;
else
qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << buttons;
qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << m_buttons;
QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(),
timestamp, qtWindowPoint, qtScreenPoint,
buttons, button, eventType, modifiers);
m_buttons, button, eventType, modifiers);
}
- (bool)handleMouseDownEvent:(NSEvent *)theEvent

View File

@ -69,12 +69,15 @@ inline D2D1_RECT_F to_d2d_rect_f(const QRectF &qrect)
inline D2D1_SIZE_U to_d2d_size_u(const QSizeF &qsize)
{
return D2D1::SizeU(qsize.width(), qsize.height());
return D2D1::SizeU(UINT32(qRound(qsize.width())),
UINT32(qRound(qsize.height())));
}
inline D2D1_SIZE_U to_d2d_size_u(const QSize &qsize)
{
return D2D1::SizeU(qsize.width(), qsize.height());
return D2D1::SizeU(UINT32(qsize.width()),
UINT32(qsize.height()));
}
inline D2D1_POINT_2F to_d2d_point_2f(const QPointF &qpoint)

View File

@ -749,6 +749,12 @@ QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent,
QWindowsWindow *result = nullptr;
const POINT screenPoint = { screenPointIn.x(), screenPointIn.y() };
while (findPlatformWindowHelper(screenPoint, cwex_flags, this, &parent, &result)) {}
// QTBUG-40815: ChildWindowFromPointEx() can hit on special windows from
// screen recorder applications like ScreenToGif. Fall back to WindowFromPoint().
if (result == nullptr) {
if (const HWND window = WindowFromPoint(screenPoint))
result = findPlatformWindow(window);
}
return result;
}
@ -925,7 +931,7 @@ bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void
bool QWindowsContext::systemParametersInfoForScreen(unsigned action, unsigned param, void *out,
const QPlatformScreen *screen)
{
return systemParametersInfo(action, param, out, screen ? screen->logicalDpi().first : 0);
return systemParametersInfo(action, param, out, screen ? unsigned(screen->logicalDpi().first) : 0u);
}
bool QWindowsContext::systemParametersInfoForWindow(unsigned action, unsigned param, void *out,
@ -944,7 +950,8 @@ bool QWindowsContext::nonClientMetrics(NONCLIENTMETRICS *ncm, unsigned dpi)
bool QWindowsContext::nonClientMetricsForScreen(NONCLIENTMETRICS *ncm,
const QPlatformScreen *screen)
{
return nonClientMetrics(ncm, screen ? screen->logicalDpi().first : 0);
const int dpi = screen ? qRound(screen->logicalDpi().first) : 0;
return nonClientMetrics(ncm, unsigned(dpi));
}
bool QWindowsContext::nonClientMetricsForWindow(NONCLIENTMETRICS *ncm, const QPlatformWindow *win)

View File

@ -269,7 +269,10 @@ static Qt::MouseButtons queryMouseButtons()
static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos)
{
QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT);
QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
QWindow *currentWindowUnderPointer = platformWindow->hasMouseCapture() ?
QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT) : window;
while (currentWindowUnderPointer && currentWindowUnderPointer->flags() & Qt::WindowTransparentForInput)
currentWindowUnderPointer = currentWindowUnderPointer->parent();

View File

@ -91,7 +91,7 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
} else {
if (const HDC hdc = CreateDC(info.szDevice, nullptr, nullptr, nullptr)) {
const QDpi dpi = monitorDPI(hMonitor);
data->dpi = dpi.first ? dpi : deviceDPI(hdc);
data->dpi = dpi.first > 0 ? dpi : deviceDPI(hdc);
data->depth = GetDeviceCaps(hdc, BITSPIXEL);
data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE));

View File

@ -851,10 +851,12 @@ static QSize toNativeSizeConstrained(QSize dip, const QWindow *w)
{
if (QHighDpiScaling::isActive()) {
const qreal factor = QHighDpiScaling::factor(w);
if (!qFuzzyCompare(factor, qreal(1))) {
if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX)
dip.rwidth() *= factor;
dip.setWidth(qRound(qreal(dip.width()) * factor));
if (dip.height() > 0 && dip.height() < QWINDOWSIZE_MAX)
dip.rheight() *= factor;
dip.setHeight(qRound(qreal(dip.height()) * factor));
}
}
return dip;
}

View File

@ -114,7 +114,7 @@ void setVariantBool(bool value, VARIANT *variant)
void setVariantDouble(double value, VARIANT *variant)
{
variant->vt = VT_R8;
variant->boolVal = value;
variant->dblVal = value;
}
BSTR bStrFromQString(const QString &value)

View File

@ -161,18 +161,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(NotificationReceiver);
return self;
}
- (void)scrollBarStyleDidChange:(NSNotification *)notification
{
Q_UNUSED(notification);
// purge destroyed scroll bars:
QMacStylePrivate::scrollBars.removeAll(QPointer<QObject>());
QEvent event(QEvent::StyleChange);
for (const auto &o : QMacStylePrivate::scrollBars)
QCoreApplication::sendEvent(o, &event);
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
{
@ -2095,11 +2083,18 @@ QMacStyle::QMacStyle()
Q_D(QMacStyle);
QMacAutoReleasePool pool;
static QMacNotificationObserver scrollbarStyleObserver(nil,
NSPreferredScrollerStyleDidChangeNotification, []() {
// Purge destroyed scroll bars
QMacStylePrivate::scrollBars.removeAll(QPointer<QObject>());
QEvent event(QEvent::StyleChange);
for (const auto &o : QMacStylePrivate::scrollBars)
QCoreApplication::sendEvent(o, &event);
});
d->receiver = [[NotificationReceiver alloc] initWithPrivateStyle:d];
[[NSNotificationCenter defaultCenter] addObserver:d->receiver
selector:@selector(scrollBarStyleDidChange:)
name:NSPreferredScrollerStyleDidChangeNotification
object:nil];
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) {
[NSApplication.sharedApplication addObserver:d->receiver forKeyPath:@"effectiveAppearance"
@ -2113,7 +2108,6 @@ QMacStyle::~QMacStyle()
Q_D(QMacStyle);
QMacAutoReleasePool pool;
[[NSNotificationCenter defaultCenter] removeObserver:d->receiver];
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
[NSApplication.sharedApplication removeObserver:d->receiver forKeyPath:@"effectiveAppearance"];
@ -3152,7 +3146,9 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
theStroker.setCapStyle(Qt::FlatCap);
theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
path = theStroker.createStroke(path);
p->fillPath(path, QColor(0, 0, 0, 119));
const auto dark = qt_mac_applicationIsInDarkMode() ? opt->palette.dark().color().darker()
: QColor(0, 0, 0, 119);
p->fillPath(path, dark);
}
break;
case PE_FrameWindow:

View File

@ -146,7 +146,10 @@ static const int maxSizeSection = 1048575; // since section size is in a bitfiel
Not all \l{Qt::}{ItemDataRole}s will have an effect on a
QHeaderView. If you need to draw other roles, you can subclass
QHeaderView and reimplement \l{QHeaderView::}{paintEvent()}.
QHeaderView respects the following item data roles:
QHeaderView respects the following item data roles, unless they are
in conflict with the style (which can happen for styles that follow
the desktop theme):
\l{Qt::}{TextAlignmentRole}, \l{Qt::}{DisplayRole},
\l{Qt::}{FontRole}, \l{Qt::}{DecorationRole},
\l{Qt::}{ForegroundRole}, and \l{Qt::}{BackgroundRole}.

View File

@ -2769,8 +2769,16 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
buttonOption.state &= ~State_MouseOver;
}
if (comboBox->frame)
if (comboBox->frame) {
cachePainter.save();
cachePainter.setRenderHint(QPainter::Antialiasing, true);
cachePainter.translate(0.5, 0.5);
cachePainter.setPen(Qt::NoPen);
cachePainter.setBrush(buttonOption.palette.base());
cachePainter.drawRoundedRect(rect.adjusted(0, 0, -1, -1), 2, 2);
cachePainter.restore();
proxy()->drawPrimitive(PE_FrameLineEdit, &buttonOption, &cachePainter, widget);
}
// Draw button clipped
cachePainter.save();

View File

@ -1957,6 +1957,7 @@ void QPlainTextEdit::paintEvent(QPaintEvent *e)
}
QAbstractTextDocumentLayout::PaintContext context = getPaintContext();
painter.setPen(context.palette.text().color());
while (block.isValid()) {

View File

@ -61,6 +61,9 @@
#include "private/qtextdocument_p.h"
#include "qtextlist.h"
#include "private/qwidgettextcontrol_p.h"
#if QT_CONFIG(style_stylesheet)
# include "private/qstylesheetstyle_p.h"
#endif
#if QT_CONFIG(graphicsview)
#include "qgraphicssceneevent.h"
#endif
@ -3198,6 +3201,15 @@ QAbstractTextDocumentLayout::PaintContext QWidgetTextControl::getPaintContext(QW
ctx.selections = d->extraSelections;
ctx.palette = d->palette;
#if QT_CONFIG(style_stylesheet)
if (widget) {
if (auto cssStyle = qt_styleSheet(widget->style())) {
QStyleOption option;
option.initFrom(widget);
cssStyle->styleSheetPalette(widget, &option, &ctx.palette);
}
}
#endif // style_stylesheet
if (d->cursorOn && d->isEnabled) {
if (d->hideCursor)
ctx.cursorPosition = -1;

View File

@ -146,7 +146,12 @@ endif()
expect_pass(test_interface_link_libraries)
expect_pass(test_moc_macro_target)
if (NOT CMAKE_VERSION VERSION_LESS 3.9)
# The modification of TARGET_OBJECTS needs the following change in cmake
# https://gitlab.kitware.com/cmake/cmake/commit/93c89bc75ceee599ba7c08b8fe1ac5104942054f
expect_pass(test_add_big_resource)
endif()
if (NOT CMAKE_VERSION VERSION_LESS 3.8)
# With earlier CMake versions, this test would simply run moc multiple times and lead to:

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 2.8)
cmake_minimum_required(VERSION 3.9)
project(test_add_big_resource)

View File

@ -172,9 +172,9 @@ void tst_qfloat16::qNan()
QVERIFY(qIsInf(-inf));
QVERIFY(qIsInf(2.f*inf));
QVERIFY(qIsInf(inf*2.f));
// QTBUG-75812: QEMU's over-optimized arm64 flakily fails 1/inf == 0 :-(
// QTBUG-75812: QEMU/arm64 compiler over-optimizes, so flakily fails 1/inf == 0 :-(
if (qfloat16(9.785e-4f) == qfloat16(9.794e-4f))
QCOMPARE(qfloat16(1.f/inf), qfloat16(0.f));
QCOMPARE(qfloat16(1.f) / inf, qfloat16(0.f));
#ifdef Q_CC_INTEL
QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue);
#endif

View File

@ -205,15 +205,23 @@ void tst_QFileSelector::urlConvenience_data()
QString test("/test");// '/' is here so dir string can also be selector string
QString custom1("custom1");
QString testWithQueryAndFragment("/test?query#Fragment");
QTest::newRow("qrc") << QUrl("qrc:///extras/test") << (QStringList() << custom1)
<< QUrl(QString("qrc:///extras/") + QLatin1Char(selectorIndicator) + custom1 + test);
QTest::newRow("qrc with query and fragment") << QUrl(QString::fromLatin1("qrc:///extras%1").arg(testWithQueryAndFragment)) << (QStringList() << custom1)
<< QUrl(QString("qrc:///extras/") + QLatin1Char(selectorIndicator) + custom1 + testWithQueryAndFragment);
QString fileBasePath = QFINDTESTDATA("extras/test");
QString fileSelectedPath = QFINDTESTDATA(QString("extras/") + QLatin1Char(selectorIndicator)
+ custom1 + QString("/test"));
QTest::newRow("file") << QUrl::fromLocalFile(fileBasePath) << (QStringList() << custom1)
<< QUrl::fromLocalFile(fileSelectedPath);
// do not strip off the query and fragment
QString strUrlWithFragment = QString("file://") + testWithQueryAndFragment;
QTest::newRow("file with query and fragment") << QUrl(strUrlWithFragment) << (QStringList()) << QUrl(strUrlWithFragment);
strUrlWithFragment = QString("file:") + testWithQueryAndFragment;
QTest::newRow("file with query and fragment too") << QUrl(strUrlWithFragment) << (QStringList()) << QUrl(strUrlWithFragment);
// http://qt-project.org/images/qtdn/sprites-combined-latest.png is chosen as a representative real world URL
// But note that this test is checking that http urls are NOT selected so it shouldn't be checked

View File

@ -183,6 +183,7 @@ private slots:
void floatingPointPrecision();
void compatibility_Qt5();
void compatibility_Qt3();
void compatibility_Qt2();
@ -269,17 +270,17 @@ static int NColorRoles[] = {
QPalette::HighlightedText + 1, // Qt_4_0, Qt_4_1
QPalette::HighlightedText + 1, // Qt_4_2
QPalette::AlternateBase + 1, // Qt_4_3
QPalette::PlaceholderText + 1, // Qt_4_4
QPalette::PlaceholderText + 1, // Qt_4_5
QPalette::PlaceholderText + 1, // Qt_4_6
QPalette::PlaceholderText + 1, // Qt_5_0
QPalette::PlaceholderText + 1, // Qt_5_1
QPalette::PlaceholderText + 1, // Qt_5_2
QPalette::PlaceholderText + 1, // Qt_5_3
QPalette::PlaceholderText + 1, // Qt_5_4
QPalette::PlaceholderText + 1, // Qt_5_5
QPalette::PlaceholderText + 1, // Qt_5_6
0 // add the correct value for Qt_5_7 here later
QPalette::ToolTipText + 1, // Qt_4_4
QPalette::ToolTipText + 1, // Qt_4_5
QPalette::ToolTipText + 1, // Qt_4_6, Qt_4_7, Qt_4_8, Qt_4_9
QPalette::ToolTipText + 1, // Qt_5_0
QPalette::ToolTipText + 1, // Qt_5_1
QPalette::ToolTipText + 1, // Qt_5_2, Qt_5_3
QPalette::ToolTipText + 1, // Qt_5_4, Qt_5_5
QPalette::ToolTipText + 1, // Qt_5_6, Qt_5_7, Qt_5_8, Qt_5_9, Qt_5_10, Qt_5_11
QPalette::PlaceholderText + 1, // Qt_5_12
QPalette::PlaceholderText + 1, // Qt_5_13
0 // add the correct value for Qt_5_14 here later
};
// Testing get/set functions
@ -3243,6 +3244,37 @@ void tst_QDataStream::streamRealDataTypes()
}
}
void tst_QDataStream::compatibility_Qt5()
{
QLinearGradient gradient(QPointF(0,0), QPointF(1,1));
gradient.setColorAt(0, Qt::red);
gradient.setColorAt(1, Qt::blue);
QBrush brush(gradient);
QPalette palette;
palette.setBrush(QPalette::Button, brush);
palette.setColor(QPalette::Light, Qt::green);
QByteArray stream;
{
QDataStream out(&stream, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_7);
out << palette;
out << brush;
}
QBrush in_brush;
QPalette in_palette;
{
QDataStream in(stream);
in.setVersion(QDataStream::Qt_5_7);
in >> in_palette;
in >> in_brush;
}
QCOMPARE(in_brush.style(), Qt::LinearGradientPattern);
QCOMPARE(in_palette.brush(QPalette::Button).style(), Qt::LinearGradientPattern);
QCOMPARE(in_palette.color(QPalette::Light), QColor(Qt::green));
}
void tst_QDataStream::compatibility_Qt3()
{
QByteArray ba("hello");

View File

@ -834,6 +834,13 @@ void tst_QRegExp::testEscapingWildcard_data(){
QTest::newRow("a true '\\' in input") << "\\Qt;" << "\\Qt;" << true;
QTest::newRow("two true '\\' in input") << "\\\\Qt;" << "\\\\Qt;" << true;
QTest::newRow("a '\\' at the end") << "\\\\Qt;\\" << "\\\\Qt;\\" << true;
QTest::newRow("[]\\] matches ]") << "[]\\]" << "]" << true;
QTest::newRow("[]\\] matches \\") << "[]\\]" << "\\" << true;
QTest::newRow("[]\\] does not match [") << "[]\\]" << "[" << false;
QTest::newRow("[]\\]a matches ]a") << "[]\\]a" << "]a" << true;
QTest::newRow("[]\\]a matches \\a") << "[]\\]a" << "\\a" << true;
QTest::newRow("[]\\]a does not match [a") << "[]\\]a" << "[a" << false;
}
void tst_QRegExp::testEscapingWildcard(){

109
tests/auto/shared/highdpi.h Normal file
View File

@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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 General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** 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-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef HIGHDPI_H
#define HIGHDPI_H
#include <QtCore/qbytearray.h>
#include <QtCore/qpoint.h>
#include <QtCore/qrect.h>
#include <QtCore/qsize.h>
// Helpers for comparing geometries a that may go through scaling in the
// platform plugin with fuzz (pass rounded-down device pixel ratios or
// scaling factors). Error message for use with QVERIFY2() are also provided.
class HighDpi
{
public:
HighDpi() = delete;
HighDpi(const HighDpi &) = delete;
HighDpi &operator=(const HighDpi &) = delete;
HighDpi(HighDpi &&) = delete;
HighDpi &operator=(HighDpi &&) = delete;
~HighDpi() = delete;
static int manhattanDelta(const QPoint &p1, const QPoint p2)
{
return (p1 - p2).manhattanLength();
}
static bool fuzzyCompare(const QPoint &p1, const QPoint p2, int fuzz)
{
return manhattanDelta(p1, p2) <= fuzz;
}
static QByteArray msgPointMismatch(const QPoint &p1, const QPoint p2)
{
return QByteArray::number(p1.x()) + ',' + QByteArray::number(p1.y())
+ " != " + QByteArray::number(p2.x()) + ',' + QByteArray::number(p2.y())
+ ", manhattanLength=" + QByteArray::number(manhattanDelta(p1, p2));
}
// Compare a size that may go through scaling in the platform plugin with fuzz.
static inline int manhattanDelta(const QSize &s1, const QSize &s2)
{
return qAbs(s1.width() - s2.width()) + qAbs(s1.height() - s2.height());
}
static inline bool fuzzyCompare(const QSize &s1, const QSize &s2, int fuzz)
{
return manhattanDelta(s1, s2) <= fuzz;
}
static QByteArray msgSizeMismatch(const QSize &s1, const QSize &s2)
{
return QByteArray::number(s1.width()) + 'x' + QByteArray::number(s1.height())
+ " != " + QByteArray::number(s2.width()) + 'x' + QByteArray::number(s2.height())
+ ", manhattanLength=" + QByteArray::number(manhattanDelta(s1, s2));
}
// Compare a geometry that may go through scaling in the platform plugin with fuzz.
static inline bool fuzzyCompare(const QRect &r1, const QRect &r2, int fuzz)
{
return manhattanDelta(r1.topLeft(), r2.topLeft()) <= fuzz
&& manhattanDelta(r1.size(), r2.size()) <= fuzz;
}
static QByteArray msgRectMismatch(const QRect &r1, const QRect &r2)
{
return formatRect(r1) + " != " + formatRect(r2);
}
private:
static QByteArray formatRect(const QRect &r)
{
return QByteArray::number(r.width()) + 'x' + QByteArray::number(r.height())
+ (r.left() < 0 ? '-' : '+') + QByteArray::number(r.left())
+ (r.top() < 0 ? '-' : '+') + QByteArray::number(r.top());
}
};
#endif // HIGHDPI_H

View File

@ -26,6 +26,7 @@
**
****************************************************************************/
#include "../../../shared/highdpi.h"
#include <QtTest/QtTest>
@ -388,8 +389,10 @@ void tst_QDialog::toolDialogPosition()
dialog.move(QPoint(100,100));
const QPoint beforeShowPosition = dialog.pos();
dialog.show();
const int fuzz = int(dialog.devicePixelRatioF());
const QPoint afterShowPosition = dialog.pos();
QCOMPARE(afterShowPosition, beforeShowPosition);
QVERIFY2(HighDpi::fuzzyCompare(afterShowPosition, beforeShowPosition, fuzz),
HighDpi::msgPointMismatch(afterShowPosition, beforeShowPosition).constData());
}
class Dialog : public QDialog

View File

@ -2551,7 +2551,7 @@ void tst_QWizard::task183550_stretchFactor()
page2->enableVerticalExpansion();
wizard.next();
QCOMPARE(wizard.currentPage(), static_cast<QWizardPage*>(page2));
QVERIFY(page2->treeWidgetHeight() > page2->treeWidgetSizeHintHeight());
QVERIFY(page2->treeWidgetHeight() >= page2->treeWidgetSizeHintHeight());
wizard.back();
QCOMPARE(wizard.currentPage(), static_cast<QWizardPage*>(page1));

View File

@ -26,6 +26,7 @@
**
****************************************************************************/
#include "../../../shared/highdpi.h"
#include <QtTest/QtTest>
@ -51,6 +52,8 @@
#include <QPlainTextEdit>
#include <QDialog>
#include <qscreen.h>
#include <QtWidgets/private/qabstractitemdelegate_p.h>
Q_DECLARE_METATYPE(QAbstractItemDelegate::EndEditHint)
@ -223,8 +226,8 @@ private slots:
void dateTextForRole_data();
void dateTextForRole();
#ifdef QT_BUILD_INTERNAL
private:
#ifdef QT_BUILD_INTERNAL
struct RoleDelegate : public QItemDelegate
{
QString textForRole(Qt::ItemDataRole role, const QVariant &value, const QLocale &locale)
@ -234,6 +237,8 @@ private:
}
};
#endif
const int m_fuzz = int(QGuiApplication::primaryScreen()->devicePixelRatio());
};
@ -286,8 +291,8 @@ void tst_QItemDelegate::textRectangle()
QFont font;
TestItemDelegate delegate;
QRect result = delegate.textRectangle(0, rect, font, text);
QCOMPARE(result, expected);
QVERIFY2(HighDpi::fuzzyCompare(result, expected, m_fuzz),
HighDpi::msgRectMismatch(result, expected).constData());
}
void tst_QItemDelegate::sizeHint_data()

View File

@ -26,6 +26,7 @@
**
****************************************************************************/
#include "../../../shared/highdpi.h"
#include <qboxlayout.h>
#include <qapplication.h>
@ -140,19 +141,6 @@ static QByteArray msgComparisonFailed(T v1, const char *op, T v2)
return s.toLocal8Bit();
}
// Compare a window position that may go through scaling in the platform plugin with fuzz.
static inline bool qFuzzyCompareWindowPosition(const QPoint &p1, const QPoint p2, int fuzz)
{
return (p1 - p2).manhattanLength() <= fuzz;
}
static QString msgPointMismatch(const QPoint &p1, const QPoint p2)
{
QString result;
QDebug(&result) << p1 << "!=" << p2 << ", manhattanLength=" << (p1 - p2).manhattanLength();
return result;
}
class tst_QWidget : public QObject
{
Q_OBJECT
@ -418,6 +406,7 @@ private:
QPoint m_safeCursorPos;
const bool m_windowsAnimationsEnabled;
QTouchDevice *m_touchScreen;
const int m_fuzz;
};
bool tst_QWidget::ensureScreenSize(int width, int height)
@ -576,6 +565,7 @@ tst_QWidget::tst_QWidget()
, m_safeCursorPos(0, 0)
, m_windowsAnimationsEnabled(windowsAnimationsEnabled())
, m_touchScreen(QTest::createTouchDevice())
, m_fuzz(int(QGuiApplication::primaryScreen()->devicePixelRatio()))
{
if (m_windowsAnimationsEnabled) // Disable animations which can interfere with screen grabbing in moveChild(), showAndMoveChild()
setWindowsAnimationsEnabled(false);
@ -2049,10 +2039,9 @@ void tst_QWidget::windowState()
widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized);
QTest::qWait(100);
const int fuzz = int(QHighDpiScaling::factor(widget1.windowHandle()));
QVERIFY(!(widget1.windowState() & Qt::WindowMaximized));
QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz),
qPrintable(msgPointMismatch(widget1.pos(), pos)));
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
widget1.setWindowState(Qt::WindowMinimized);
@ -2073,8 +2062,8 @@ void tst_QWidget::windowState()
widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized);
QTest::qWait(100);
QVERIFY(!(widget1.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized)));
QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz),
qPrintable(msgPointMismatch(widget1.pos(), pos)));
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
widget1.setWindowState(Qt::WindowFullScreen);
@ -2095,8 +2084,8 @@ void tst_QWidget::windowState()
widget1.setWindowState(Qt::WindowNoState);
QTest::qWait(100);
VERIFY_STATE(Qt::WindowNoState);
QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz),
qPrintable(msgPointMismatch(widget1.pos(), pos)));
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
widget1.setWindowState(Qt::WindowFullScreen);
@ -2129,8 +2118,8 @@ void tst_QWidget::windowState()
QVERIFY(!(widget1.windowState() & stateMask));
QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz),
qPrintable(msgPointMismatch(widget1.pos(), pos)));
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
QTRY_COMPARE(widget1.size(), size);
}
@ -2323,7 +2312,7 @@ void tst_QWidget::resizeEvent()
{
QWidget wParent;
wParent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
wParent.resize(200, 200);
wParent.resize(m_testWidgetSize);
ResizeWidget wChild(&wParent);
wParent.show();
QVERIFY(QTest::qWaitForWindowExposed(&wParent));
@ -2341,7 +2330,7 @@ void tst_QWidget::resizeEvent()
{
ResizeWidget wTopLevel;
wTopLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
wTopLevel.resize(200, 200);
wTopLevel.resize(m_testWidgetSize);
wTopLevel.show();
QVERIFY(QTest::qWaitForWindowExposed(&wTopLevel));
if (m_platform == QStringLiteral("winrt"))
@ -2379,17 +2368,20 @@ void tst_QWidget::showMinimized()
#ifdef Q_OS_WINRT
QEXPECT_FAIL("", "Winrt does not support move and resize", Abort);
#endif
QCOMPARE(plain.pos(), pos);
QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos)));
plain.showNormal();
QVERIFY(!plain.isMinimized());
QVERIFY(plain.isVisible());
QCOMPARE(plain.pos(), pos);
QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos)));
plain.showMinimized();
QVERIFY(plain.isMinimized());
QVERIFY(plain.isVisible());
QCOMPARE(plain.pos(), pos);
QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos)));
plain.hide();
QVERIFY(plain.isMinimized());
@ -2781,7 +2773,9 @@ void tst_QWidget::setGeometry()
tlw.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
QWidget child(&tlw);
QRect tr(100,100,200,200);
const QPoint topLeft = QGuiApplication::primaryScreen()->availableGeometry().topLeft();
const QSize initialSize = 2 * m_testWidgetSize;
QRect tr(topLeft + QPoint(100,100), initialSize);
QRect cr(50,50,50,50);
tlw.setGeometry(tr);
child.setGeometry(cr);
@ -2792,8 +2786,7 @@ void tst_QWidget::setGeometry()
QCOMPARE(child.geometry(), cr);
tlw.setParent(nullptr, Qt::Window|Qt::FramelessWindowHint);
tr = QRect(0,0,100,100);
tr.moveTopLeft(QGuiApplication::primaryScreen()->availableGeometry().topLeft());
tr = QRect(topLeft, initialSize / 2);
tlw.setGeometry(tr);
QCOMPARE(tlw.geometry(), tr);
tlw.showNormal();
@ -3265,7 +3258,8 @@ void tst_QWidget::saveRestoreGeometry()
if (m_platform == QStringLiteral("winrt"))
QEXPECT_FAIL("", "WinRT does not support move/resize", Abort);
QTRY_COMPARE(widget.pos(), position);
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget.pos(), position, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(widget.pos(), position)));
QCOMPARE(widget.size(), size);
savedGeometry = widget.saveGeometry();
}
@ -3293,10 +3287,12 @@ void tst_QWidget::saveRestoreGeometry()
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QApplication::processEvents();
QTRY_COMPARE(widget.pos(), position);
QVERIFY2(HighDpi::fuzzyCompare(widget.pos(), position, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(widget.pos(), position)));
QCOMPARE(widget.size(), size);
widget.show();
QCOMPARE(widget.pos(), position);
QVERIFY2(HighDpi::fuzzyCompare(widget.pos(), position, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(widget.pos(), position)));
QCOMPARE(widget.size(), size);
}
@ -3410,6 +3406,9 @@ void tst_QWidget::restoreVersion1Geometry()
QFETCH(QSize, expectedSize);
QFETCH(QRect, expectedNormalGeometry);
if (m_platform == QLatin1String("windows") && QGuiApplication::primaryScreen()->geometry().width() > 2000)
QSKIP("Skipping due to minimum decorated window size on Windows");
// WindowActive is uninteresting for this test
const Qt::WindowStates WindowStateMask = Qt::WindowFullScreen | Qt::WindowMaximized | Qt::WindowMinimized;
@ -4990,7 +4989,8 @@ void tst_QWidget::windowMoveResize()
widget.showNormal();
QTest::qWait(10);
QTRY_COMPARE(widget.pos(), rect.topLeft());
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget.pos(), rect.topLeft(), m_fuzz),
qPrintable(HighDpi::msgPointMismatch(widget.pos(), rect.topLeft())));
// Windows: Minimum size of decorated windows.
const bool expectResizeFail = (!windowFlags && (rect.width() < 160 || rect.height() < 40))
&& m_platform == QStringLiteral("windows");

View File

@ -27,6 +27,7 @@
****************************************************************************/
#include "debugproxystyle.h"
#include "eventfilter.h"
#include <QDebug>
#include <QWidget>
@ -73,7 +74,7 @@ QDebug operator<<(QDebug debug, const QStyleOption *option)
debug << ", state=" << option->state;
#if QT_VERSION >= 0x050000
if (option->styleObject && !option->styleObject->isWidgetType())
debug << ", styleObject=" << option->styleObject;
debug << ", styleObject=" << QtDiag::formatQObject(option->styleObject);
#endif
debug << ')';
return debug;
@ -97,19 +98,19 @@ DebugProxyStyle::DebugProxyStyle(QStyle *style) : QProxyStyle(style)
void DebugProxyStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
qDebug() << __FUNCTION__ << "element=" << element << option << widget;
qDebug() << __FUNCTION__ << "element=" << element << option << QtDiag::formatQObject(widget);
QProxyStyle::drawPrimitive( element, option, painter, widget);
}
void DebugProxyStyle::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
qDebug() << __FUNCTION__ << "element=" << element << option << widget;
qDebug() << __FUNCTION__ << "element=" << element << option << QtDiag::formatQObject(widget);
QProxyStyle::drawControl(element, option, painter, widget);
}
void DebugProxyStyle::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{
qDebug() << __FUNCTION__ << "control=" << control << option << widget;
qDebug() << __FUNCTION__ << "control=" << control << option << QtDiag::formatQObject(widget);
QProxyStyle::drawComplexControl(control, option, painter, widget);
}
@ -122,21 +123,24 @@ void DebugProxyStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int a
QSize DebugProxyStyle::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const
{
const QSize result = QProxyStyle::sizeFromContents(type, option, size, widget);
qDebug() << __FUNCTION__ << size << "type=" << type << option << widget << "returns" << result;
qDebug() << __FUNCTION__ << size << "type=" << type << option
<< QtDiag::formatQObject(widget) << "returns" << result;
return result;
}
QRect DebugProxyStyle::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const
{
const QRect result = QProxyStyle::subElementRect(element, option, widget);
qDebug() << __FUNCTION__ << "element=" << element << option << widget << "returns" << result;
qDebug() << __FUNCTION__ << "element=" << element << option
<< QtDiag::formatQObject(widget) << "returns" << result;
return result;
}
QRect DebugProxyStyle::subControlRect(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QStyle::SubControl sc, const QWidget *widget) const
{
const QRect result = QProxyStyle::subControlRect(cc, opt, sc, widget);
qDebug() << __FUNCTION__ << "cc=" << cc << "sc=" << sc << opt << widget << "returns" << result;
qDebug() << __FUNCTION__ << "cc=" << cc << "sc=" << sc << opt
<< QtDiag::formatQObject(widget) << "returns" << result;
return result;
}
@ -159,7 +163,7 @@ int DebugProxyStyle::styleHint(StyleHint hint, const QStyleOption *option, const
QStyleHintReturn *returnData) const
{
const int result = QProxyStyle::styleHint(hint, option, widget, returnData);
qDebug() << __FUNCTION__ << hint << option << widget << "returnData="
qDebug() << __FUNCTION__ << hint << option << QtDiag::formatQObject(widget) << "returnData="
<< returnData << "returns" << result;
return result;
}
@ -167,7 +171,8 @@ int DebugProxyStyle::styleHint(StyleHint hint, const QStyleOption *option, const
int DebugProxyStyle::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
const int result = QProxyStyle::pixelMetric(metric, option, widget);
qDebug() << __FUNCTION__ << "metric=" << metric << option << widget << "returns" << result;
qDebug() << __FUNCTION__ << "metric=" << metric << option
<< QtDiag::formatQObject(widget) << "returns" << result;
return result;
}

View File

@ -154,7 +154,7 @@ static inline bool matchesType(const QObject *o, EventFilter::ObjectTypes types)
return types & EventFilter::OtherType;
}
static void formatObject(const QObject *o, QDebug debug)
void EventFilter::formatObject(const QObject *o, QDebug debug)
{
if (o) {
debug << o->metaObject()->className();
@ -166,32 +166,30 @@ static void formatObject(const QObject *o, QDebug debug)
}
}
QDebug operator<<(QDebug d, const formatQObject &fo)
{
EventFilter::formatObject(fo.m_object, d);
return d;
}
static void formatApplicationState(QDebug debug)
{
#if defined(HAVE_APPLICATION)
if (const QWidget *mw = QApplication::activeModalWidget()) {
debug << "\n QApplication::activeModalWidget = ";
formatObject(mw, debug);
}
if (const QWidget *pw = QApplication::activePopupWidget()) {
debug << "\n QApplication::activePopupWidget = ";
formatObject(pw, debug);
}
debug << "\n QApplication::activeWindow = ";
formatObject(QApplication::activeWindow(), debug);
if (const QWidget *mw = QApplication::activeModalWidget())
debug << "\n QApplication::activeModalWidget = " << formatQObject(mw);
if (const QWidget *pw = QApplication::activePopupWidget())
debug << "\n QApplication::activePopupWidget = " << formatQObject(pw);
debug << "\n QApplication::activeWindow = " << formatQObject(QApplication::activeWindow());
#endif // HAVE_APPLICATION
#if defined(HAVE_GUI_APPLICATION)
if (const QWindow *mw = QGuiApplication::modalWindow()) {
debug << "\n QGuiApplication::modalWindow = ";
formatObject(mw, debug);
debug << "\n QGuiApplication::modalWindow = " << formatQObject(mw);
}
const QObject *focusObject = QGuiApplication::focusObject();
const QObject *focusWindow = QGuiApplication::focusWindow();
debug << "\n QGuiApplication::focusObject = ";
formatObject(focusObject, debug);
debug << "\n QGuiApplication::focusObject = " << formatQObject(focusObject);
if (focusWindow && focusWindow != focusObject)
debug << "\n QGuiApplication::focusWindow = ";
formatObject(focusWindow, debug);
debug << "\n QGuiApplication::focusWindow = " << formatQObject(focusWindow);
#endif // HAVE_GUI_APPLICATION
}

View File

@ -33,6 +33,8 @@
#include <QtCore/QEvent>
#include <QtCore/QList>
QT_FORWARD_DECLARE_CLASS(QDebug)
namespace QtDiag {
// Event filter that can for example be installed on QApplication
@ -74,6 +76,8 @@ public:
ObjectTypes objectTypes() const { return m_objectTypes; }
void setObjectTypes(ObjectTypes objectTypes) { m_objectTypes = objectTypes; }
static void formatObject(const QObject *o, QDebug debug);
private:
void init(EventCategories eventCategories);
@ -84,6 +88,15 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(EventFilter::EventCategories)
Q_DECLARE_OPERATORS_FOR_FLAGS(EventFilter::ObjectTypes)
struct formatQObject
{
explicit formatQObject(const QObject *o) : m_object(o) {}
const QObject *m_object;
};
QDebug operator<<(QDebug d, const formatQObject &fo);
} // namespace QtDiag
#endif