diff options
Diffstat (limited to 'src/gui/kernel')
-rw-r--r-- | src/gui/kernel/qevent.cpp | 56 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 44 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication.h | 3 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication_p.h | 1 | ||||
-rw-r--r-- | src/gui/kernel/qguivariant.cpp | 1 | ||||
-rw-r--r-- | src/gui/kernel/qhighdpiscaling.cpp | 337 | ||||
-rw-r--r-- | src/gui/kernel/qhighdpiscaling_p.h | 43 | ||||
-rw-r--r-- | src/gui/kernel/qopenglcontext.cpp | 3 | ||||
-rw-r--r-- | src/gui/kernel/qplatformintegration.cpp | 3 | ||||
-rw-r--r-- | src/gui/kernel/qplatformintegration.h | 3 | ||||
-rw-r--r-- | src/gui/kernel/qplatformscreen.cpp | 22 | ||||
-rw-r--r-- | src/gui/kernel/qplatformscreen.h | 3 | ||||
-rw-r--r-- | src/gui/kernel/qscreen.cpp | 13 | ||||
-rw-r--r-- | src/gui/kernel/qsurface.cpp | 6 | ||||
-rw-r--r-- | src/gui/kernel/qsurfaceformat.cpp | 12 | ||||
-rw-r--r-- | src/gui/kernel/qtouchdevice.cpp | 32 | ||||
-rw-r--r-- | src/gui/kernel/qwindowsysteminterface.cpp | 4 |
17 files changed, 442 insertions, 144 deletions
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 96f61e7ae9..8e5945be41 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -535,13 +535,6 @@ Qt::MouseEventFlags QMouseEvent::flags() const */ /*! - \fn QPointF QMouseEvent::posF() const - \obsolete - - Use localPos() instead. -*/ - -/*! \class QHoverEvent \ingroup events \inmodule QtGui @@ -750,12 +743,14 @@ QHoverEvent::~QHoverEvent() \l inverted always returns false. */ +#if QT_DEPRECATED_SINCE(5, 15) /*! \fn Qt::Orientation QWheelEvent::orientation() const \obsolete Use angleDelta() instead. */ +#endif #if QT_CONFIG(wheelevent) #if QT_DEPRECATED_SINCE(5, 15) @@ -936,6 +931,7 @@ QWheelEvent::~QWheelEvent() \endlist */ +#if QT_DEPRECATED_SINCE(5, 15) /*! \fn int QWheelEvent::delta() const \obsolete @@ -999,6 +995,7 @@ QWheelEvent::~QWheelEvent() This function has been deprecated, use globalPosition() instead. */ +#endif /*! \fn Qt::ScrollPhase QWheelEvent::phase() const @@ -1102,16 +1099,6 @@ QKeyEvent::~QKeyEvent() } /*! - \fn QKeyEvent *QKeyEvent::createExtendedKeyEvent(Type type, int key, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString& text, bool autorep, ushort count) - \internal -*/ - -/*! - \fn bool QKeyEvent::hasExtendedInfo() const - \internal -*/ - -/*! \fn quint32 QKeyEvent::nativeScanCode() const \since 4.2 @@ -2539,7 +2526,7 @@ Qt::MouseButtons QTabletEvent::buttons() const globalPos() can differ significantly from the current position QCursor::pos(). - \sa globalX(), globalY(), hiResGlobalPos() + \sa globalX(), globalY() */ /*! @@ -2584,15 +2571,6 @@ Qt::MouseButtons QTabletEvent::buttons() const */ /*! - \fn const QPointF &QTabletEvent::hiResGlobalPos() const - - The high precision coordinates delivered from the tablet expressed. - Sub pixeling information is in the fractional part of the QPointF. - - \sa globalPos(), hiResGlobalX(), hiResGlobalY() -*/ - -/*! \fn qreal &QTabletEvent::hiResGlobalX() const The high precision x position of the tablet device. @@ -2674,10 +2652,10 @@ Qt::MouseButtons QTabletEvent::buttons() const \sa Qt::NativeGestureType, QGestureEvent */ +#if QT_DEPRECATED_SINCE(5, 10) /*! \deprecated The QTouchDevice parameter is now required */ -#if QT_DEPRECATED_SINCE(5, 10) QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QPointF &localPos, const QPointF &windowPos, const QPointF &screenPos, qreal realValue, ulong sequenceId, quint64 intValue) : QInputEvent(QEvent::NativeGesture), mGestureType(type), @@ -4279,18 +4257,6 @@ QWindowStateChangeEvent::~QWindowStateChangeEvent() QGraphicsItem::acceptTouchEvents() */ -/*! \enum QTouchEvent::DeviceType - \obsolete - - This enum represents the type of device that generated a QTouchEvent. - - This enum has been deprecated. Use QTouchDevice::DeviceType instead. - \omitvalue TouchPad - \omitvalue TouchScreen - - \sa QTouchDevice::DeviceType, QTouchDevice::type(), QTouchEvent::device() -*/ - /*! Constructs a QTouchEvent with the given \a eventType, \a device, and \a touchPoints. The \a touchPointStates and \a modifiers @@ -4330,16 +4296,6 @@ QTouchEvent::~QTouchEvent() This is typically a QWidget or a QQuickItem. May be 0 when no specific target is available. */ -/*! \fn QTouchEvent::DeviceType QTouchEvent::deviceType() const - \obsolete - - Returns the touch device Type, which is of type \l {QTouchEvent::DeviceType} {DeviceType}. - - This function has been deprecated. Use QTouchDevice::type() instead. - - \sa QTouchDevice::type(), QTouchEvent::device() -*/ - /*! \fn QTouchEvent::TouchPoint::TouchPoint(TouchPoint &&other) Move-constructs a TouchPoint instance, making it point to the same diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index a7fe2ec50a..432618968f 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -146,6 +146,8 @@ QString QGuiApplicationPrivate::styleOverride; Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive; +Qt::HighDpiScaleFactorRoundingPolicy QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = + Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor; bool QGuiApplicationPrivate::highDpiScalingUpdated = false; QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow; @@ -687,6 +689,8 @@ QGuiApplication::~QGuiApplication() QGuiApplicationPrivate::lastCursorPosition = {qInf(), qInf()}; QGuiApplicationPrivate::currentMousePressWindow = QGuiApplicationPrivate::currentMouseWindow = nullptr; QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive; + QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = + Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor; QGuiApplicationPrivate::highDpiScalingUpdated = false; QGuiApplicationPrivate::currentDragWindow = nullptr; QGuiApplicationPrivate::tabletDevicePoints.clear(); @@ -3495,6 +3499,46 @@ Qt::ApplicationState QGuiApplication::applicationState() } /*! + \since 5.14 + + Sets the high-DPI scale factor rounding policy for the application. The + policy decides how non-integer scale factors (such as Windows 150%) are + handled, for applications that have AA_EnableHighDpiScaling enabled. + + The two principal options are whether fractional scale factors should + be rounded to an integer or not. Keeping the scale factor as-is will + make the user interface size match the OS setting exactly, but may cause + painting errors, for example with the Windows style. + + If rounding is wanted, then which type of rounding should be decided + next. Mathematically correct rounding is supported but may not give + the best visual results: Consider if you want to render 1.5x as 1x + ("small UI") or as 2x ("large UI"). See the Qt::HighDpiScaleFactorRoundingPolicy + enum for a complete list of all options. + + This function must be called before creating the application object, + and can be overridden by setting the QT_SCALE_FACTOR_ROUNDING_POLICY + environment variable. The QGuiApplication::highDpiScaleFactorRoundingPolicy() + accessor will reflect the environment, if set. + + The default value is Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor. +*/ +void QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy) +{ + QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = policy; +} + +/*! + \since 5.14 + + Returns the high-DPI scale factor rounding policy. +*/ +Qt::HighDpiScaleFactorRoundingPolicy QGuiApplication::highDpiScaleFactorRoundingPolicy() +{ + return QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy; +} + +/*! \since 5.2 \fn void QGuiApplication::applicationStateChanged(Qt::ApplicationState state) diff --git a/src/gui/kernel/qguiapplication.h b/src/gui/kernel/qguiapplication.h index 5ea72fa0f6..fc74c5299a 100644 --- a/src/gui/kernel/qguiapplication.h +++ b/src/gui/kernel/qguiapplication.h @@ -156,6 +156,9 @@ public: static Qt::ApplicationState applicationState(); + static void setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy); + static Qt::HighDpiScaleFactorRoundingPolicy highDpiScaleFactorRoundingPolicy(); + static int exec(); bool notify(QObject *, QEvent *) override; diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index afca7579ea..e28607bad6 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -223,6 +223,7 @@ public: static QWindow *currentMouseWindow; static QWindow *currentMousePressWindow; static Qt::ApplicationState applicationState; + static Qt::HighDpiScaleFactorRoundingPolicy highDpiScaleFactorRoundingPolicy; static bool highDpiScalingUpdated; static QPointer<QWindow> currentDragWindow; diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index 090217187e..edca8d9423 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -68,7 +68,6 @@ #include "qdebug.h" #include "qmap.h" #include "qdatetime.h" -#include "qeasingcurve.h" #include "qlist.h" #include "qstring.h" #include "qstringlist.h" diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp index 0fea416404..c031885d5d 100644 --- a/src/gui/kernel/qhighdpiscaling.cpp +++ b/src/gui/kernel/qhighdpiscaling.cpp @@ -46,6 +46,9 @@ #include <private/qguiapplication_p.h> #include <QtCore/qdebug.h> +#include <QtCore/qmetaobject.h> + +#include <algorithm> QT_BEGIN_NAMESPACE @@ -53,9 +56,29 @@ Q_LOGGING_CATEGORY(lcScaling, "qt.scaling"); #ifndef QT_NO_HIGHDPISCALING static const char legacyDevicePixelEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; +static const char legacyAutoScreenEnvVar[] = "QT_AUTO_SCREEN_SCALE_FACTOR"; + +static const char enableHighDpiScalingEnvVar[] = "QT_ENABLE_HIGHDPI_SCALING"; static const char scaleFactorEnvVar[] = "QT_SCALE_FACTOR"; -static const char autoScreenEnvVar[] = "QT_AUTO_SCREEN_SCALE_FACTOR"; static const char screenFactorsEnvVar[] = "QT_SCREEN_SCALE_FACTORS"; +static const char scaleFactorRoundingPolicyEnvVar[] = "QT_SCALE_FACTOR_ROUNDING_POLICY"; +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) +{ + bool ok = false; + int value = qEnvironmentVariableIntValue(name, &ok); + return ok ? value > 0 : defaultValue; +} static inline qreal initialGlobalScaleFactor() { @@ -69,17 +92,24 @@ static inline qreal initialGlobalScaleFactor() result = f; } } else { + // Check for deprecated environment variables. if (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar)) { qWarning("Warning: %s is deprecated. Instead use:\n" " %s to enable platform plugin controlled per-screen factors.\n" - " %s to set per-screen factors.\n" + " %s to set per-screen DPI.\n" " %s to set the application global scale factor.", - legacyDevicePixelEnvVar, autoScreenEnvVar, screenFactorsEnvVar, scaleFactorEnvVar); + legacyDevicePixelEnvVar, legacyAutoScreenEnvVar, screenFactorsEnvVar, scaleFactorEnvVar); int dpr = qEnvironmentVariableIntValue(legacyDevicePixelEnvVar); if (dpr > 0) result = dpr; } + + if (qEnvironmentVariableIsSet(legacyAutoScreenEnvVar)) { + qWarning("Warning: %s is deprecated. Instead use:\n" + " %s to enable platform plugin controlled per-screen factors.", + legacyAutoScreenEnvVar, enableHighDpiScalingEnvVar); + } } return result; } @@ -226,7 +256,6 @@ bool QHighDpiScaling::m_usePixelDensity = false; // use scale factor from platfo bool QHighDpiScaling::m_pixelDensityScalingActive = false; // pixel density scale factor > 1 bool QHighDpiScaling::m_globalScalingActive = false; // global scale factor is active bool QHighDpiScaling::m_screenFactorSet = false; // QHighDpiScaling::setScreenFactor has been used -QDpi QHighDpiScaling::m_logicalDpi = QDpi(-1,-1); // The scaled logical DPI of the primary screen /* Initializes the QHighDpiScaling global variables. Called before the @@ -238,16 +267,214 @@ static inline bool usePixelDensity() // Determine if we should set a scale factor based on the pixel density // reported by the platform plugin. There are several enablers and several // disablers. A single disable may veto all other enablers. + + // First, check of there is an explicit disable. if (QCoreApplication::testAttribute(Qt::AA_DisableHighDpiScaling)) return false; bool screenEnvValueOk; - const int screenEnvValue = qEnvironmentVariableIntValue(autoScreenEnvVar, &screenEnvValueOk); + const int screenEnvValue = qEnvironmentVariableIntValue(legacyAutoScreenEnvVar, &screenEnvValueOk); if (screenEnvValueOk && screenEnvValue < 1) return false; + bool enableEnvValueOk; + const int enableEnvValue = qEnvironmentVariableIntValue(enableHighDpiScalingEnvVar, &enableEnvValueOk); + if (enableEnvValueOk && enableEnvValue < 1) + return false; + + // Then return if there was an enable. return QCoreApplication::testAttribute(Qt::AA_EnableHighDpiScaling) || (screenEnvValueOk && screenEnvValue > 0) - || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) && - qgetenv(legacyDevicePixelEnvVar).compare("auto", Qt::CaseInsensitive) == 0); + || (enableEnvValueOk && enableEnvValue > 0) + || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) && qgetenv(legacyDevicePixelEnvVar).toLower() == "auto"); +} + +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) { + qreal platformPhysicalDpi = screen->screen()->physicalDotsPerInch(); + factor = qreal(platformPhysicalDpi) / qreal(platformBaseDpi.first); + } else { + const QDpi platformLogicalDpi = QPlatformScreen::overrideDpi(screen->logicalDpi()); + factor = qreal(platformLogicalDpi.first) / qreal(platformBaseDpi.first); + } + + return factor; +} + +template <class EnumType> +struct EnumLookup +{ + const char *name; + EnumType value; +}; + +template <class EnumType> +static bool operator==(const EnumLookup<EnumType> &e1, const EnumLookup<EnumType> &e2) +{ + return qstricmp(e1.name, e2.name) == 0; +} + +template <class EnumType> +static QByteArray joinEnumValues(const EnumLookup<EnumType> *i1, const EnumLookup<EnumType> *i2) +{ + QByteArray result; + for (; i1 < i2; ++i1) { + if (!result.isEmpty()) + result += QByteArrayLiteral(", "); + result += i1->name; + } + return result; +} + +using ScaleFactorRoundingPolicyLookup = EnumLookup<Qt::HighDpiScaleFactorRoundingPolicy>; + +static const ScaleFactorRoundingPolicyLookup scaleFactorRoundingPolicyLookup[] = +{ + {"Round", Qt::HighDpiScaleFactorRoundingPolicy::Round}, + {"Ceil", Qt::HighDpiScaleFactorRoundingPolicy::Ceil}, + {"Floor", Qt::HighDpiScaleFactorRoundingPolicy::Floor}, + {"RoundPreferFloor", Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor}, + {"PassThrough", Qt::HighDpiScaleFactorRoundingPolicy::PassThrough} +}; + +static Qt::HighDpiScaleFactorRoundingPolicy + lookupScaleFactorRoundingPolicy(const QByteArray &v) +{ + auto end = std::end(scaleFactorRoundingPolicyLookup); + auto it = std::find(std::begin(scaleFactorRoundingPolicyLookup), end, + ScaleFactorRoundingPolicyLookup{v.constData(), Qt::HighDpiScaleFactorRoundingPolicy::Unset}); + return it != end ? it->value : Qt::HighDpiScaleFactorRoundingPolicy::Unset; +} + +using DpiAdjustmentPolicyLookup = EnumLookup<QHighDpiScaling::DpiAdjustmentPolicy>; + +static const DpiAdjustmentPolicyLookup dpiAdjustmentPolicyLookup[] = +{ + {"AdjustDpi", QHighDpiScaling::DpiAdjustmentPolicy::Enabled}, + {"DontAdjustDpi", QHighDpiScaling::DpiAdjustmentPolicy::Disabled}, + {"AdjustUpOnly", QHighDpiScaling::DpiAdjustmentPolicy::UpOnly} +}; + +static QHighDpiScaling::DpiAdjustmentPolicy + lookupDpiAdjustmentPolicy(const QByteArray &v) +{ + auto end = std::end(dpiAdjustmentPolicyLookup); + auto it = std::find(std::begin(dpiAdjustmentPolicyLookup), end, + DpiAdjustmentPolicyLookup{v.constData(), QHighDpiScaling::DpiAdjustmentPolicy::Unset}); + return it != end ? it->value : QHighDpiScaling::DpiAdjustmentPolicy::Unset; +} + +qreal QHighDpiScaling::roundScaleFactor(qreal rawFactor) +{ + // Apply scale factor rounding policy. Using mathematically correct rounding + // may not give the most desirable visual results, especially for + // critical fractions like .5. In general, rounding down results in visual + // 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); + } + } + + // Apply rounding policy. + qreal roundedFactor = rawFactor; + switch (scaleFactorRoundingPolicy) { + case Qt::HighDpiScaleFactorRoundingPolicy::Round: + roundedFactor = qRound(rawFactor); + break; + case Qt::HighDpiScaleFactorRoundingPolicy::Ceil: + roundedFactor = qCeil(rawFactor); + break; + case Qt::HighDpiScaleFactorRoundingPolicy::Floor: + roundedFactor = qFloor(rawFactor); + break; + case Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor: + // Round up for .75 and higher. This favors "small UI" over "large UI". + roundedFactor = rawFactor - qFloor(rawFactor) < 0.75 + ? qFloor(rawFactor) : qCeil(rawFactor); + break; + case Qt::HighDpiScaleFactorRoundingPolicy::PassThrough: + case Qt::HighDpiScaleFactorRoundingPolicy::Unset: + break; + } + + // Don't round down to to zero; clamp the minimum (rounded) factor to 1. + // This is not a common case but can happen if a display reports a very + // low DPI. + if (scaleFactorRoundingPolicy != Qt::HighDpiScaleFactorRoundingPolicy::PassThrough) + roundedFactor = qMax(roundedFactor, qreal(1)); + + return roundedFactor; +} + +QDpi QHighDpiScaling::effectiveLogicalDpi(const QPlatformScreen *screen, qreal rawFactor, qreal roundedFactor) +{ + // Apply DPI adjustment policy, if needed. If enabled this will change the + // reported logical DPI to account for the difference between the rounded + // scale factor and the actual scale factor. The effect is that text size + // will be correct for the screen dpi, but may be (slightly) out of sync + // 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) + return baseDpi; + if (dpiAdjustmentPolicy == DpiAdjustmentPolicy::UpOnly && dpiAdjustmentFactor < 1) + return baseDpi; + + return QDpi(baseDpi.first * dpiAdjustmentFactor, baseDpi.second * dpiAdjustmentFactor); } void QHighDpiScaling::initHighDpiScaling() @@ -260,8 +487,6 @@ void QHighDpiScaling::initHighDpiScaling() m_pixelDensityScalingActive = false; //set in updateHighDpiScaling below - // we update m_active in updateHighDpiScaling, but while we create the - // screens, we have to assume that m_usePixelDensity implies scaling m_active = m_globalScalingActive || m_usePixelDensity; } @@ -283,20 +508,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; } } @@ -305,23 +529,15 @@ 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; } } - m_active = m_globalScalingActive || m_screenFactorSet || m_pixelDensityScalingActive; - - QScreen *primaryScreen = QGuiApplication::primaryScreen(); - if (!primaryScreen) - return; - QPlatformScreen *platformScreen = primaryScreen->handle(); - qreal sf = screenSubfactor(platformScreen); - QDpi primaryDpi = platformScreen->logicalDpi(); - m_logicalDpi = QDpi(primaryDpi.first / sf, primaryDpi.second / sf); + m_active = m_globalScalingActive || m_usePixelDensity; } /* @@ -353,7 +569,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()) @@ -421,41 +644,55 @@ 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) { - qreal pixelDensity = screen->pixelDensity(); - - // Pixel density reported by the screen is sometimes not precise enough, - // so recalculate it: divide px (physical pixels) by dp (device-independent pixels) - // for both width and height, and then use the average if it is different from - // the one initially reported by the screen - QRect screenGeometry = screen->geometry(); - qreal wFactor = qreal(screenGeometry.width()) / qRound(screenGeometry.width() / pixelDensity); - qreal hFactor = qreal(screenGeometry.height()) / qRound(screenGeometry.height() / pixelDensity); - qreal averageDensity = (wFactor + hFactor) / 2; - if (!qFuzzyCompare(pixelDensity, averageDensity)) - pixelDensity = averageDensity; - - factor *= pixelDensity; - } - 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; } -QDpi QHighDpiScaling::logicalDpi() +QDpi QHighDpiScaling::logicalDpi(const QScreen *screen) { - return m_logicalDpi; + // (Note: m_active test is performed at call site.) + if (!screen || !screen->handle()) + return QDpi(96, 96); + + if (!m_usePixelDensity) + return QPlatformScreen::overrideDpi(screen->handle()->logicalDpi()); + + const qreal scaleFactor = rawScaleFactor(screen->handle()); + const qreal roundedScaleFactor = roundScaleFactor(scaleFactor); + return effectiveLogicalDpi(screen->handle(), scaleFactor, roundedScaleFactor); } QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition) { if (!m_active) return { qreal(1), QPoint() }; + if (!platformScreen) + return { m_factor, QPoint() }; // the global factor const QPlatformScreen *actualScreen = nativePosition ? platformScreen->screenForPosition(*nativePosition) : platformScreen; return { m_factor * screenSubfactor(actualScreen), actualScreen->geometry().topLeft() }; diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h index 50221926c6..f58944a7d2 100644 --- a/src/gui/kernel/qhighdpiscaling_p.h +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -59,6 +59,7 @@ #include <QtCore/qloggingcategory.h> #include <QtGui/qregion.h> #include <QtGui/qscreen.h> +#include <QtGui/qvector2d.h> #include <QtGui/qwindow.h> QT_BEGIN_NAMESPACE @@ -71,11 +72,27 @@ typedef QPair<qreal, qreal> QDpi; #ifndef QT_NO_HIGHDPISCALING class Q_GUI_EXPORT QHighDpiScaling { + Q_GADGET public: + enum class DpiAdjustmentPolicy { + Unset, + Enabled, + Disabled, + UpOnly + }; + Q_ENUM(DpiAdjustmentPolicy) + + QHighDpiScaling() = delete; + ~QHighDpiScaling() = delete; + QHighDpiScaling(const QHighDpiScaling &) = delete; + QHighDpiScaling &operator=(const QHighDpiScaling &) = delete; + QHighDpiScaling(QHighDpiScaling &&) = delete; + QHighDpiScaling &operator=(QHighDpiScaling &&) = delete; + 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; } @@ -97,9 +114,12 @@ public: static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen); static QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window); static QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window); - static QDpi logicalDpi(); + static QDpi logicalDpi(const QScreen *screen); private: + static qreal rawScaleFactor(const QPlatformScreen *screen); + static qreal roundScaleFactor(qreal rawFactor); + static QDpi effectiveLogicalDpi(const QPlatformScreen *screen, qreal rawFactor, qreal roundedFactor); static qreal screenSubfactor(const QPlatformScreen *screen); static qreal m_factor; @@ -117,13 +137,26 @@ private: namespace QHighDpi { -template <typename T> -inline T scale(const T &value, qreal scaleFactor, QPoint origin = QPoint(0, 0)) +inline qreal scale(qreal value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0)) +{ + return value * scaleFactor; +} + +inline QSize scale(const QSize &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0)) +{ + return value * scaleFactor; +} + +inline QSizeF scale(const QSizeF &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0)) { - Q_UNUSED(origin) return value * scaleFactor; } +inline QVector2D scale(const QVector2D &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0)) +{ + return value * float(scaleFactor); +} + inline QPointF scale(const QPointF &pos, qreal scaleFactor, QPointF origin = QPointF(0, 0)) { return (pos - origin) * scaleFactor + origin; diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 10adee438b..6f51fe3095 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -976,11 +976,8 @@ bool QOpenGLContext::makeCurrent(QSurface *surface) if (!surface->surfaceHandle()) return false; if (!surface->supportsOpenGL()) { -#ifndef Q_OS_WASM // ### work around the WASM platform plugin using QOpenGLContext with raster surfaces. - // see QTBUG-70076 qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface" << surface; return false; -#endif } if (!d->platformGLContext->makeCurrent(surface->surfaceHandle())) diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 490cfc6178..b3d3db0751 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -244,6 +244,9 @@ QPlatformServices *QPlatformIntegration::services() const \value TopStackedNativeChildWindows The platform supports native child windows via QWindowContainer without having to punch a transparent hole in the backingstore. (since 5.10) + + \value OpenGLOnRasterSurface The platform supports making a QOpenGLContext current + in combination with a QWindow of type RasterSurface. */ /*! diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index b764bd2617..d9f349555a 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -105,7 +105,8 @@ public: AllGLFunctionsQueryable, ApplicationIcon, SwitchableWidgetComposition, - TopStackedNativeChildWindows + TopStackedNativeChildWindows, + OpenGLOnRasterSurface }; virtual ~QPlatformIntegration() { } diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp index 9c5876550a..f3213bf5ea 100644 --- a/src/gui/kernel/qplatformscreen.cpp +++ b/src/gui/kernel/qplatformscreen.cpp @@ -193,6 +193,28 @@ QDpi QPlatformScreen::logicalDpi() const 25.4 * s.height() / ps.height()); } +// Helper function for accessing the platform screen logical dpi +// which accounts for QT_FONT_DPI. +QPair<qreal, qreal> QPlatformScreen::overrideDpi(const QPair<qreal, qreal> &in) +{ + static const int overrideDpi = qEnvironmentVariableIntValue("QT_FONT_DPI"); + return overrideDpi > 0 ? QDpi(overrideDpi, overrideDpi) : in; +} + +/*! + Reimplement to return the base logical DPI for the platform. This + DPI value should correspond to a standard-DPI (1x) display. The + default implementation returns 96. + + QtGui will use this value (together with logicalDpi) to compute + the scale factor when high-DPI scaling is enabled: + factor = logicalDPI / baseDPI +*/ +QDpi QPlatformScreen::logicalBaseDpi() const +{ + return QDpi(96, 96); +} + /*! Reimplement this function in subclass to return the device pixel ratio for the screen. This is the ratio between physical pixels and the diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h index b9ecc80320..d7378aed51 100644 --- a/src/gui/kernel/qplatformscreen.h +++ b/src/gui/kernel/qplatformscreen.h @@ -115,6 +115,7 @@ public: virtual QSizeF physicalSize() const; virtual QDpi logicalDpi() const; + virtual QDpi logicalBaseDpi() const; virtual qreal devicePixelRatio() const; virtual qreal pixelDensity() const; @@ -160,6 +161,8 @@ public: // The platform screen's geometry in device independent coordinates QRect deviceIndependentGeometry() const; + static QDpi overrideDpi(const QDpi &in); + protected: void resizeMaximizedWindows(); diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index c79f597414..7adf3db1b8 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -84,8 +84,11 @@ void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen) platformScreen->d_func()->screen = q; orientation = platformScreen->orientation(); geometry = platformScreen->deviceIndependentGeometry(); - availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), QHighDpiScaling::factor(platformScreen), geometry.topLeft()); - logicalDpi = platformScreen->logicalDpi(); + availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), + QHighDpiScaling::factor(platformScreen), geometry.topLeft()); + + logicalDpi = QPlatformScreen::overrideDpi(platformScreen->logicalDpi()); + refreshRate = platformScreen->refreshRate(); // safeguard ourselves against buggy platform behavior... if (refreshRate < 1.0) @@ -285,7 +288,7 @@ qreal QScreen::logicalDotsPerInchX() const { Q_D(const QScreen); if (QHighDpiScaling::isActive()) - return QHighDpiScaling::logicalDpi().first; + return QHighDpiScaling::logicalDpi(this).first; return d->logicalDpi.first; } @@ -301,7 +304,7 @@ qreal QScreen::logicalDotsPerInchY() const { Q_D(const QScreen); if (QHighDpiScaling::isActive()) - return QHighDpiScaling::logicalDpi().second; + return QHighDpiScaling::logicalDpi(this).second; return d->logicalDpi.second; } @@ -320,7 +323,7 @@ qreal QScreen::logicalDotsPerInchY() const qreal QScreen::logicalDotsPerInch() const { Q_D(const QScreen); - QDpi dpi = QHighDpiScaling::isActive() ? QHighDpiScaling::logicalDpi() : d->logicalDpi; + QDpi dpi = QHighDpiScaling::isActive() ? QHighDpiScaling::logicalDpi(this) : d->logicalDpi; return (dpi.first + dpi.second) * qreal(0.5); } diff --git a/src/gui/kernel/qsurface.cpp b/src/gui/kernel/qsurface.cpp index 415e64b39c..709f28d431 100644 --- a/src/gui/kernel/qsurface.cpp +++ b/src/gui/kernel/qsurface.cpp @@ -39,6 +39,8 @@ #include "qsurface.h" #include "qopenglcontext.h" +#include <qpa/qplatformintegration.h> +#include <QtGui/private/qguiapplication_p.h> QT_BEGIN_NAMESPACE @@ -103,6 +105,10 @@ QT_BEGIN_NAMESPACE bool QSurface::supportsOpenGL() const { SurfaceType type = surfaceType(); + if (type == RasterSurface) { + QPlatformIntegration *integ = QGuiApplicationPrivate::instance()->platformIntegration(); + return integ->hasCapability(QPlatformIntegration::OpenGLOnRasterSurface); + } return type == OpenGLSurface || type == RasterGLSurface; } diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp index 2e2738ec81..238886220b 100644 --- a/src/gui/kernel/qsurfaceformat.cpp +++ b/src/gui/kernel/qsurfaceformat.cpp @@ -554,10 +554,6 @@ int QSurfaceFormat::alphaBufferSize() const /*! Set the desired \a size in bits of the red channel of the color buffer. - - \note On Mac OSX, be sure to set the buffer size of all color channels, - otherwise this setting will have no effect. If one of the buffer sizes is not set, - the current bit-depth of the screen is used. */ void QSurfaceFormat::setRedBufferSize(int size) { @@ -569,10 +565,6 @@ void QSurfaceFormat::setRedBufferSize(int size) /*! Set the desired \a size in bits of the green channel of the color buffer. - - \note On Mac OSX, be sure to set the buffer size of all color channels, - otherwise this setting will have no effect. If one of the buffer sizes is not set, - the current bit-depth of the screen is used. */ void QSurfaceFormat::setGreenBufferSize(int size) { @@ -584,10 +576,6 @@ void QSurfaceFormat::setGreenBufferSize(int size) /*! Set the desired \a size in bits of the blue channel of the color buffer. - - \note On Mac OSX, be sure to set the buffer size of all color channels, - otherwise this setting will have no effect. If one of the buffer sizes is not set, - the current bit-depth of the screen is used. */ void QSurfaceFormat::setBlueBufferSize(int size) { diff --git a/src/gui/kernel/qtouchdevice.cpp b/src/gui/kernel/qtouchdevice.cpp index 511e92566e..ea187f54aa 100644 --- a/src/gui/kernel/qtouchdevice.cpp +++ b/src/gui/kernel/qtouchdevice.cpp @@ -44,6 +44,7 @@ #include <QCoreApplication> #include <private/qdebug_p.h> +#include <private/qlocking_p.h> QT_BEGIN_NAMESPACE @@ -201,15 +202,20 @@ void QTouchDevice::setName(const QString &name) d->name = name; } -typedef QList<const QTouchDevice *> TouchDevices; -Q_GLOBAL_STATIC(TouchDevices, deviceList) static QBasicMutex devicesMutex; -static void cleanupDevicesList() +struct TouchDevices { + TouchDevices(); + QList<const QTouchDevice *> list; +}; +Q_GLOBAL_STATIC(TouchDevices, deviceList) + +TouchDevices::TouchDevices() { - QMutexLocker lock(&devicesMutex); - qDeleteAll(*deviceList()); - deviceList()->clear(); + qAddPostRoutine([]{ + const auto locker = qt_scoped_lock(devicesMutex); + qDeleteAll(qExchange(deviceList->list, {})); + }); } /*! @@ -223,7 +229,7 @@ static void cleanupDevicesList() QList<const QTouchDevice *> QTouchDevice::devices() { QMutexLocker lock(&devicesMutex); - return *deviceList(); + return deviceList->list; } /*! @@ -232,13 +238,13 @@ QList<const QTouchDevice *> QTouchDevice::devices() bool QTouchDevicePrivate::isRegistered(const QTouchDevice *dev) { QMutexLocker locker(&devicesMutex); - return deviceList()->contains(dev); + return deviceList->list.contains(dev); } const QTouchDevice *QTouchDevicePrivate::deviceById(quint8 id) { QMutexLocker locker(&devicesMutex); - for (const QTouchDevice *dev : *deviceList()) + for (const QTouchDevice *dev : qAsConst(deviceList->list)) if (QTouchDevicePrivate::get(const_cast<QTouchDevice *>(dev))->id == id) return dev; return nullptr; @@ -250,9 +256,7 @@ const QTouchDevice *QTouchDevicePrivate::deviceById(quint8 id) void QTouchDevicePrivate::registerDevice(const QTouchDevice *dev) { QMutexLocker lock(&devicesMutex); - if (deviceList()->isEmpty()) - qAddPostRoutine(cleanupDevicesList); - deviceList()->append(dev); + deviceList->list.append(dev); } /*! @@ -261,9 +265,7 @@ void QTouchDevicePrivate::registerDevice(const QTouchDevice *dev) void QTouchDevicePrivate::unregisterDevice(const QTouchDevice *dev) { QMutexLocker lock(&devicesMutex); - bool wasRemoved = deviceList()->removeOne(dev); - if (wasRemoved && deviceList()->isEmpty()) - qRemovePostRoutine(cleanupDevicesList); + deviceList->list.removeOne(dev); } #ifndef QT_NO_DEBUG_STREAM diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 4b8cb3646a..40a298226a 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -857,8 +857,8 @@ void QWindowSystemInterface::handleScreenGeometryChange(QScreen *screen, const Q void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal dpiX, qreal dpiY) { - QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e = - new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, dpiX, dpiY); // ### tja + const QDpi effectiveDpi = QPlatformScreen::overrideDpi(QDpi{dpiX, dpiY}); + auto e = new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, effectiveDpi.first, effectiveDpi.second); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } |