Update QT_SCREEN_SCALE_FACTORS

Store name->factor associations in a global QHash instead of on the
QScreen object, making them survive QScreen object deletion, for
example on disconnect/ connect cycles.

Make factors set with QT_SCREEN_SCALE_FACTORS override the screen
factors computed from platform plugin DPI values. This matches the use
case for QT_SCREEN_SCALE_FACTORS (but not the general scale factors
combine by multiplication”principle)

Done-with: Friedemann Kleint <Friedemann.Kleint@qt.io>
Task-number: QTBUG-53022
Change-Id: I12771249314ab0c073e609d62f57ac0d18d3b6ce
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
This commit is contained in:
Friedemann Kleint 2019-02-27 08:46:47 +01:00 committed by Morten Johan Sørvig
parent 70a893e9be
commit 35da4eeba2
2 changed files with 46 additions and 17 deletions

View File

@ -63,6 +63,12 @@ static const char scaleFactorRoundingPolicyEnvVar[] = "QT_SCALE_FACTOR_ROUNDING_
static const char dpiAdjustmentPolicyEnvVar[] = "QT_DPI_ADJUSTMENT_POLICY";
static const char usePhysicalDpiEnvVar[] = "QT_USE_PHYSICAL_DPI";
// Per-screen scale factors for named screens set with QT_SCREEN_SCALE_FACTORS
// are stored here. Use a global hash to keep the factor across screen
// disconnect/connect cycles where the screen object may be deleted.
typedef QHash<QString, qreal> QScreenScaleFactorHash;
Q_GLOBAL_STATIC(QScreenScaleFactorHash, qNamedScreenScaleFactors);
// Reads and interprets the given environment variable as a bool,
// returns the default value if not set.
static bool qEnvironmentVariableAsBool(const char *name, bool defaultValue)
@ -480,20 +486,19 @@ void QHighDpiScaling::updateHighDpiScaling()
int i = 0;
const auto specs = qgetenv(screenFactorsEnvVar).split(';');
for (const QByteArray &spec : specs) {
QScreen *screen = 0;
int equalsPos = spec.lastIndexOf('=');
double factor = 0;
qreal factor = 0;
if (equalsPos > 0) {
// support "name=factor"
QByteArray name = spec.mid(0, equalsPos);
QByteArray f = spec.mid(equalsPos + 1);
bool ok;
factor = f.toDouble(&ok);
if (ok) {
if (ok && factor > 0 ) {
const auto screens = QGuiApplication::screens();
for (QScreen *s : screens) {
if (s->name() == QString::fromLocal8Bit(name)) {
screen = s;
setScreenFactor(s, factor);
break;
}
}
@ -502,11 +507,11 @@ void QHighDpiScaling::updateHighDpiScaling()
// listing screens in order
bool ok;
factor = spec.toDouble(&ok);
if (ok && i < QGuiApplication::screens().count())
screen = QGuiApplication::screens().at(i);
if (ok && factor > 0 && i < QGuiApplication::screens().count()) {
QScreen *screen = QGuiApplication::screens().at(i);
setScreenFactor(screen, factor);
}
}
if (screen)
setScreenFactor(screen, factor);
++i;
}
}
@ -542,7 +547,14 @@ void QHighDpiScaling::setScreenFactor(QScreen *screen, qreal factor)
m_screenFactorSet = true;
m_active = true;
}
screen->setProperty(scaleFactorProperty, QVariant(factor));
// Prefer associating the factor with screen name over the object
// since the screen object may be deleted on screen disconnects.
const QString name = screen->name();
if (name.isEmpty())
screen->setProperty(scaleFactorProperty, QVariant(factor));
else
qNamedScreenScaleFactors()->insert(name, factor);
// hack to force re-evaluation of screen geometry
if (screen->handle())
@ -610,15 +622,32 @@ QPoint QHighDpiScaling::mapPositionFromGlobal(const QPoint &pos, const QPoint &w
qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen)
{
qreal factor = qreal(1.0);
if (screen) {
if (m_usePixelDensity)
factor *= roundScaleFactor(rawScaleFactor(screen));
if (m_screenFactorSet) {
QVariant screenFactor = screen->screen()->property(scaleFactorProperty);
if (screenFactor.isValid())
factor *= screenFactor.toReal();
if (!screen)
return factor;
// Unlike the other code where factors are combined by multiplication,
// factors from QT_SCREEN_SCALE_FACTORS takes precedence over the factor
// computed from platform plugin DPI. The rationale is that the user is
// setting the factor to override erroneous DPI values.
bool screenPropertyUsed = false;
if (m_screenFactorSet) {
// Check if there is a factor set on the screen object or associated
// with the screen name. These are mutually exclusive, so checking
// order is not significant.
QVariant byIndex = screen->screen()->property(scaleFactorProperty);
auto byNameIt = qNamedScreenScaleFactors()->constFind(screen->name());
if (byIndex.isValid()) {
screenPropertyUsed = true;
factor = byIndex.toReal();
} else if (byNameIt != qNamedScreenScaleFactors()->cend()) {
screenPropertyUsed = true;
factor = *byNameIt;
}
}
if (!screenPropertyUsed && m_usePixelDensity)
factor = roundScaleFactor(rawScaleFactor(screen));
return factor;
}

View File

@ -102,7 +102,7 @@ public:
static void initHighDpiScaling();
static void updateHighDpiScaling();
static void setGlobalFactor(qreal factor);
static void setScreenFactor(QScreen *window, qreal factor);
static void setScreenFactor(QScreen *screen, qreal factor);
static bool isActive() { return m_active; }