Read high-dpi env. variables in initHighDpiScaling()
Move all environment access to initHighDpiScaling(), which makes it so that all environment access happens at one point in time during QGuiApplication construction. Replace the “qt.scaling” logging category with “qt.highdpi”, and log each recognized env. variable. Further logging of DPI and computed scale factors will be introduced later on. This also enables auto-testing of the environment variable settings, since the auto-test can now control when the environment is read by (re-)creating the application object. Change-Id: I4e62a9c0050438357a58ace5b50fb7c5950c87ce Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
a5573cfbd5
commit
4d1f13f354
@ -49,10 +49,11 @@
|
||||
#include <QtCore/qmetaobject.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcScaling, "qt.scaling");
|
||||
Q_LOGGING_CATEGORY(lcHighDpi, "qt.highdpi");
|
||||
|
||||
#ifndef QT_NO_HIGHDPISCALING
|
||||
|
||||
@ -68,30 +69,38 @@ static const char usePhysicalDpiEnvVar[] = "QT_USE_PHYSICAL_DPI";
|
||||
// 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)
|
||||
static std::optional<QString> qEnvironmentVariableOptionalString(const char *name)
|
||||
{
|
||||
bool ok = false;
|
||||
int value = qEnvironmentVariableIntValue(name, &ok);
|
||||
return ok ? value > 0 : defaultValue;
|
||||
if (!qEnvironmentVariableIsSet(name))
|
||||
return std::nullopt;
|
||||
|
||||
return std::optional(qEnvironmentVariable(name));
|
||||
}
|
||||
|
||||
static inline qreal initialGlobalScaleFactor()
|
||||
static std::optional<QByteArray> qEnvironmentVariableOptionalByteArray(const char *name)
|
||||
{
|
||||
if (!qEnvironmentVariableIsSet(name))
|
||||
return std::nullopt;
|
||||
|
||||
qreal result = 1;
|
||||
if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) {
|
||||
bool ok;
|
||||
const qreal f = qEnvironmentVariable(scaleFactorEnvVar).toDouble(&ok);
|
||||
if (ok && f > 0) {
|
||||
qCDebug(lcScaling) << "Apply " << scaleFactorEnvVar << f;
|
||||
result = f;
|
||||
}
|
||||
}
|
||||
return std::optional(qgetenv(name));
|
||||
}
|
||||
|
||||
return result;
|
||||
static std::optional<int> qEnvironmentVariableOptionalInt(const char *name)
|
||||
{
|
||||
bool ok = false;
|
||||
const int value = qEnvironmentVariableIntValue(name, &ok);
|
||||
auto opt = ok ? std::optional(value) : std::nullopt;
|
||||
return opt;
|
||||
}
|
||||
|
||||
static std::optional<qreal> qEnvironmentVariableOptionalReal(const char *name)
|
||||
{
|
||||
if (!qEnvironmentVariableIsSet(name))
|
||||
return std::nullopt;
|
||||
|
||||
bool ok = false;
|
||||
const qreal value = qEnvironmentVariable(name).toDouble(&ok);
|
||||
return ok ? std::optional(value) : std::nullopt;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -275,35 +284,16 @@ bool QHighDpiScaling::m_usePlatformPluginDpi = false; // use scale factor based
|
||||
bool QHighDpiScaling::m_platformPluginDpiScalingActive = false; // platform plugin DPI gives a scale factor > 1
|
||||
bool QHighDpiScaling::m_globalScalingActive = false; // global scale factor is active
|
||||
bool QHighDpiScaling::m_screenFactorSet = false; // QHighDpiScaling::setScreenFactor has been used
|
||||
|
||||
/*
|
||||
Initializes the QHighDpiScaling global variables. Called before the
|
||||
platform plugin is created.
|
||||
*/
|
||||
|
||||
static inline bool usePlatformPluginDpi()
|
||||
{
|
||||
// Determine if we should set a scale factor based on the logical DPI
|
||||
// reported by the platform plugin.
|
||||
|
||||
bool enableEnvValueOk;
|
||||
const int enableEnvValue = qEnvironmentVariableIntValue(enableHighDpiScalingEnvVar, &enableEnvValueOk);
|
||||
if (enableEnvValueOk && enableEnvValue < 1)
|
||||
return false;
|
||||
|
||||
// Enable by default
|
||||
return true;
|
||||
}
|
||||
bool QHighDpiScaling::m_usePhysicalDpi = false;
|
||||
QHighDpiScaling::DpiAdjustmentPolicy QHighDpiScaling::m_dpiAdjustmentPolicy = QHighDpiScaling::DpiAdjustmentPolicy::Unset;
|
||||
QString QHighDpiScaling::m_screenFactorsSpec;
|
||||
|
||||
qreal QHighDpiScaling::rawScaleFactor(const QPlatformScreen *screen)
|
||||
{
|
||||
// Determine if physical DPI should be used
|
||||
static const bool usePhysicalDpi = qEnvironmentVariableAsBool(usePhysicalDpiEnvVar, false);
|
||||
|
||||
// Calculate scale factor beased on platform screen DPI values
|
||||
qreal factor;
|
||||
QDpi platformBaseDpi = screen->logicalBaseDpi();
|
||||
if (usePhysicalDpi) {
|
||||
if (QHighDpiScaling::m_usePhysicalDpi) {
|
||||
QSize sz = screen->geometry().size();
|
||||
QSizeF psz = screen->physicalSize();
|
||||
qreal platformPhysicalDpi = ((sz.height() / psz.height()) + (sz.width() / psz.width())) * qreal(25.4 * 0.5);
|
||||
@ -387,32 +377,9 @@ qreal QHighDpiScaling::roundScaleFactor(qreal rawFactor)
|
||||
// sizes that are smaller than the ideal size, and opposite for rounding up.
|
||||
// Rounding down is then preferable since "small UI" is a more acceptable
|
||||
// high-DPI experience than "large UI".
|
||||
static auto scaleFactorRoundingPolicy = Qt::HighDpiScaleFactorRoundingPolicy::Unset;
|
||||
|
||||
// Determine rounding policy
|
||||
if (scaleFactorRoundingPolicy == Qt::HighDpiScaleFactorRoundingPolicy::Unset) {
|
||||
// Check environment
|
||||
if (qEnvironmentVariableIsSet(scaleFactorRoundingPolicyEnvVar)) {
|
||||
QByteArray policyText = qgetenv(scaleFactorRoundingPolicyEnvVar);
|
||||
auto policyEnumValue = lookupScaleFactorRoundingPolicy(policyText);
|
||||
if (policyEnumValue != Qt::HighDpiScaleFactorRoundingPolicy::Unset) {
|
||||
scaleFactorRoundingPolicy = policyEnumValue;
|
||||
} else {
|
||||
auto values = joinEnumValues(std::begin(scaleFactorRoundingPolicyLookup),
|
||||
std::end(scaleFactorRoundingPolicyLookup));
|
||||
qWarning("Unknown scale factor rounding policy: %s. Supported values are: %s.",
|
||||
policyText.constData(), values.constData());
|
||||
}
|
||||
}
|
||||
|
||||
// Check application object if no environment value was set.
|
||||
if (scaleFactorRoundingPolicy == Qt::HighDpiScaleFactorRoundingPolicy::Unset) {
|
||||
scaleFactorRoundingPolicy = QGuiApplication::highDpiScaleFactorRoundingPolicy();
|
||||
} else {
|
||||
// Make application setting reflect environment
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(scaleFactorRoundingPolicy);
|
||||
}
|
||||
}
|
||||
Qt::HighDpiScaleFactorRoundingPolicy scaleFactorRoundingPolicy =
|
||||
QGuiApplication::highDpiScaleFactorRoundingPolicy();
|
||||
|
||||
// Apply rounding policy.
|
||||
qreal roundedFactor = rawFactor;
|
||||
@ -452,56 +419,107 @@ QDpi QHighDpiScaling::effectiveLogicalDpi(const QPlatformScreen *screen, qreal r
|
||||
// with the rest of the UI. The amount of out-of-synch-ness depends on how
|
||||
// well user code handles a non-standard DPI values, but since the
|
||||
// adjustment is small (typically +/- 48 max) this might be OK.
|
||||
static auto dpiAdjustmentPolicy = DpiAdjustmentPolicy::Unset;
|
||||
|
||||
// Determine adjustment policy.
|
||||
if (dpiAdjustmentPolicy == DpiAdjustmentPolicy::Unset) {
|
||||
if (qEnvironmentVariableIsSet(dpiAdjustmentPolicyEnvVar)) {
|
||||
QByteArray policyText = qgetenv(dpiAdjustmentPolicyEnvVar);
|
||||
auto policyEnumValue = lookupDpiAdjustmentPolicy(policyText);
|
||||
if (policyEnumValue != DpiAdjustmentPolicy::Unset) {
|
||||
dpiAdjustmentPolicy = policyEnumValue;
|
||||
} else {
|
||||
auto values = joinEnumValues(std::begin(dpiAdjustmentPolicyLookup),
|
||||
std::end(dpiAdjustmentPolicyLookup));
|
||||
qWarning("Unknown DPI adjustment policy: %s. Supported values are: %s.",
|
||||
policyText.constData(), values.constData());
|
||||
}
|
||||
}
|
||||
if (dpiAdjustmentPolicy == DpiAdjustmentPolicy::Unset)
|
||||
dpiAdjustmentPolicy = DpiAdjustmentPolicy::UpOnly;
|
||||
}
|
||||
|
||||
// Apply adjustment policy.
|
||||
const QDpi baseDpi = screen->logicalBaseDpi();
|
||||
const qreal dpiAdjustmentFactor = rawFactor / roundedFactor;
|
||||
|
||||
// Return the base DPI for cases where there is no adjustment
|
||||
if (dpiAdjustmentPolicy == DpiAdjustmentPolicy::Disabled)
|
||||
if (QHighDpiScaling::m_dpiAdjustmentPolicy == DpiAdjustmentPolicy::Disabled)
|
||||
return baseDpi;
|
||||
if (dpiAdjustmentPolicy == DpiAdjustmentPolicy::UpOnly && dpiAdjustmentFactor < 1)
|
||||
if (QHighDpiScaling::m_dpiAdjustmentPolicy == DpiAdjustmentPolicy::UpOnly && dpiAdjustmentFactor < 1)
|
||||
return baseDpi;
|
||||
|
||||
return QDpi(baseDpi.first * dpiAdjustmentFactor, baseDpi.second * dpiAdjustmentFactor);
|
||||
}
|
||||
|
||||
/*
|
||||
Determine and apply global/initial configuration which do not depend on
|
||||
having access to QScreen objects - this function is called before they
|
||||
have been created. Screen-dependent configuration happens later in
|
||||
updateHighDpiScaling().
|
||||
*/
|
||||
void QHighDpiScaling::initHighDpiScaling()
|
||||
{
|
||||
// Determine if there is a global scale factor set.
|
||||
m_factor = initialGlobalScaleFactor();
|
||||
// Read environment variables
|
||||
static const char* envDebugStr = "environment variable set:";
|
||||
std::optional<int> envEnableHighDpiScaling = qEnvironmentVariableOptionalInt(enableHighDpiScalingEnvVar);
|
||||
if (envEnableHighDpiScaling.has_value())
|
||||
qCDebug(lcHighDpi) << envDebugStr << enableHighDpiScalingEnvVar << envEnableHighDpiScaling.value();
|
||||
|
||||
std::optional<qreal> envScaleFactor = qEnvironmentVariableOptionalReal(scaleFactorEnvVar);
|
||||
if (envScaleFactor.has_value())
|
||||
qCDebug(lcHighDpi) << envDebugStr << scaleFactorEnvVar << envScaleFactor.value();
|
||||
|
||||
std::optional<QString> envScreenFactors = qEnvironmentVariableOptionalString(screenFactorsEnvVar);
|
||||
if (envScreenFactors.has_value())
|
||||
qCDebug(lcHighDpi) << envDebugStr << screenFactorsEnvVar << envScreenFactors.value();
|
||||
|
||||
std::optional<int> envUsePhysicalDpi = qEnvironmentVariableOptionalInt(usePhysicalDpiEnvVar);
|
||||
if (envUsePhysicalDpi.has_value())
|
||||
qCDebug(lcHighDpi) << envDebugStr << usePhysicalDpiEnvVar << envUsePhysicalDpi.value();
|
||||
|
||||
std::optional<QByteArray> envScaleFactorRoundingPolicy = qEnvironmentVariableOptionalByteArray(scaleFactorRoundingPolicyEnvVar);
|
||||
if (envScaleFactorRoundingPolicy.has_value())
|
||||
qCDebug(lcHighDpi) << envDebugStr << scaleFactorRoundingPolicyEnvVar << envScaleFactorRoundingPolicy.value();
|
||||
|
||||
std::optional<QByteArray> envDpiAdjustmentPolicy = qEnvironmentVariableOptionalByteArray(dpiAdjustmentPolicyEnvVar);
|
||||
if (envDpiAdjustmentPolicy.has_value())
|
||||
qCDebug(lcHighDpi) << envDebugStr << dpiAdjustmentPolicyEnvVar << envDpiAdjustmentPolicy.value();
|
||||
|
||||
// High-dpi scaling is enabled by default; check for global disable.
|
||||
m_usePlatformPluginDpi = envEnableHighDpiScaling.value_or(1) > 0;
|
||||
m_platformPluginDpiScalingActive = false; // see updateHighDpiScaling()
|
||||
|
||||
// Check for glabal scale factor (different from 1)
|
||||
m_factor = envScaleFactor.value_or(qreal(1));
|
||||
m_globalScalingActive = !qFuzzyCompare(m_factor, qreal(1));
|
||||
|
||||
m_usePlatformPluginDpi = usePlatformPluginDpi();
|
||||
// Store the envScreenFactors string for later use. The string format
|
||||
// supports using screen names, which means that screen DPI cannot
|
||||
// be resolved at this point.
|
||||
QHighDpiScaling::m_screenFactorsSpec = envScreenFactors.value_or(QString());
|
||||
|
||||
m_platformPluginDpiScalingActive = false; //set in updateHighDpiScaling below
|
||||
m_usePhysicalDpi = envUsePhysicalDpi.value_or(0) > 0;
|
||||
|
||||
// Resolve HighDpiScaleFactorRoundingPolicy to QGuiApplication::highDpiScaleFactorRoundingPolicy
|
||||
if (envScaleFactorRoundingPolicy.has_value()) {
|
||||
QByteArray policyText = envScaleFactorRoundingPolicy.value();
|
||||
auto policyEnumValue = lookupScaleFactorRoundingPolicy(policyText);
|
||||
if (policyEnumValue != Qt::HighDpiScaleFactorRoundingPolicy::Unset) {
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(policyEnumValue);
|
||||
} else {
|
||||
auto values = joinEnumValues(std::begin(scaleFactorRoundingPolicyLookup),
|
||||
std::end(scaleFactorRoundingPolicyLookup));
|
||||
qWarning("Unknown scale factor rounding policy: %s. Supported values are: %s.",
|
||||
policyText.constData(), values.constData());
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve DpiAdjustmentPolicy to m_dpiAdjustmentPolicy
|
||||
if (envDpiAdjustmentPolicy.has_value()) {
|
||||
QByteArray policyText = envScaleFactorRoundingPolicy.value();
|
||||
auto policyEnumValue = lookupDpiAdjustmentPolicy(policyText);
|
||||
if (policyEnumValue != DpiAdjustmentPolicy::Unset) {
|
||||
QHighDpiScaling::m_dpiAdjustmentPolicy = policyEnumValue;
|
||||
} else {
|
||||
auto values = joinEnumValues(std::begin(dpiAdjustmentPolicyLookup),
|
||||
std::end(dpiAdjustmentPolicyLookup));
|
||||
qWarning("Unknown DPI adjustment policy: %s. Supported values are: %s.",
|
||||
policyText.constData(), values.constData());
|
||||
}
|
||||
}
|
||||
|
||||
// Set initial active state
|
||||
m_active = m_globalScalingActive || m_usePlatformPluginDpi;
|
||||
}
|
||||
|
||||
/*
|
||||
Update configuration based on available screens and screen properties.
|
||||
This function may be called whenever the screen configuration changed.
|
||||
*/
|
||||
void QHighDpiScaling::updateHighDpiScaling()
|
||||
{
|
||||
m_usePlatformPluginDpi = usePlatformPluginDpi();
|
||||
|
||||
if (m_usePlatformPluginDpi && !m_platformPluginDpiScalingActive ) {
|
||||
const auto screens = QGuiApplication::screens();
|
||||
for (QScreen *screen : screens) {
|
||||
@ -511,10 +529,9 @@ void QHighDpiScaling::updateHighDpiScaling()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (qEnvironmentVariableIsSet(screenFactorsEnvVar)) {
|
||||
if (!m_screenFactorsSpec.isNull()) {
|
||||
int i = 0;
|
||||
const QString spec = qEnvironmentVariable(screenFactorsEnvVar);
|
||||
const auto specs = QStringView{spec}.split(u';');
|
||||
const auto specs = QStringView{m_screenFactorsSpec}.split(u';');
|
||||
for (const auto &spec : specs) {
|
||||
int equalsPos = spec.lastIndexOf(QLatin1Char('='));
|
||||
qreal factor = 0;
|
||||
|
@ -64,7 +64,7 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcScaling);
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcHighDpi);
|
||||
|
||||
class QScreen;
|
||||
class QPlatformScreen;
|
||||
@ -138,6 +138,9 @@ private:
|
||||
static bool m_platformPluginDpiScalingActive;
|
||||
static bool m_globalScalingActive;
|
||||
static bool m_screenFactorSet;
|
||||
static bool m_usePhysicalDpi;
|
||||
static QString m_screenFactorsSpec;
|
||||
static DpiAdjustmentPolicy m_dpiAdjustmentPolicy;
|
||||
};
|
||||
|
||||
namespace QHighDpi {
|
||||
|
Loading…
Reference in New Issue
Block a user