diff options
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 3 | ||||
-rw-r--r-- | src/gui/kernel/qhighdpiscaling.cpp | 80 | ||||
-rw-r--r-- | src/gui/kernel/qhighdpiscaling_p.h | 12 | ||||
-rw-r--r-- | src/gui/kernel/qplatformscreen.cpp | 18 | ||||
-rw-r--r-- | src/gui/kernel/qwindow.cpp | 16 | ||||
-rw-r--r-- | src/plugins/platforms/android/androidjnimain.cpp | 2 | ||||
-rw-r--r-- | tests/manual/highdpi/highdpi.pro | 3 | ||||
-rw-r--r-- | tests/manual/highdpi/main.cpp | 127 |
8 files changed, 153 insertions, 108 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 8e4290b8e8..fe0bbbc15a 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1118,6 +1118,9 @@ void QGuiApplicationPrivate::createPlatformIntegration() // this flag. QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true); + + QHighDpiScaling::initHighDPiScaling(); + // Load the platform integration QString platformPluginPath = QLatin1String(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH")); diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp index 54d06a8572..a1387f781b 100644 --- a/src/gui/kernel/qhighdpiscaling.cpp +++ b/src/gui/kernel/qhighdpiscaling.cpp @@ -43,6 +43,7 @@ #include "qwindow_p.h" // for QWINDOWSIZE_MAX #include "qguiapplication.h" #include "qscreen.h" +#include "qplatformintegration.h" #include "private/qscreen_p.h" #include <QtCore/qdebug.h> @@ -68,7 +69,7 @@ static inline qreal initialScaleFactor() /*! \class QHighDpiScaling - \since 5.4 + \since 5.6 \internal \preliminary \ingroup qpa @@ -76,12 +77,26 @@ static inline qreal initialScaleFactor() \brief Collection of utility functions for UI scaling. */ -qreal QHighDpiScaling::m_factor = initialScaleFactor(); -bool QHighDpiScaling::m_autoFactor = qgetenv("QT_SCALE_FACTOR").toLower() == "auto"; -bool QHighDpiScaling::m_active = m_autoFactor || !qFuzzyCompare(QHighDpiScaling::m_factor, qreal(1)); -bool QHighDpiScaling::m_perWindowActive = false; -void QHighDpiScaling::setFactor(qreal factor) +qreal QHighDpiScaling::m_factor; + +bool QHighDpiScaling::m_active; //"overall active" - is there any scale factor set. +bool QHighDpiScaling::m_perScreenActive; + +void QHighDpiScaling::initHighDPiScaling() +{ + QHighDpiScaling::m_factor = initialScaleFactor(); + bool usePlatformPluginPixelDensity = qEnvironmentVariableIsSet("QT_AUTO_SCREEN_SCALE_FACTOR"); + + // m_active below is "overall active" - is there any scale factor set. + QHighDpiScaling::m_active = !qFuzzyCompare(m_factor, qreal(1)) || usePlatformPluginPixelDensity; + QHighDpiScaling::m_perScreenActive = usePlatformPluginPixelDensity; +} + +/* + Sets the global scale factor which is applied to all windows. +*/ +void QHighDpiScaling::setGlobalFactor(qreal factor) { if (qFuzzyCompare(factor, QHighDpiScaling::m_factor)) return; @@ -97,14 +112,16 @@ void QHighDpiScaling::setFactor(qreal factor) static const char *scaleFactorProperty = "_q_scaleFactor"; -void QHighDpiScaling::setWindowFactor(QWindow *window, qreal factor) +/* + Sets a per-screen scale factor. +*/ +void QHighDpiScaling::setScreenFactor(QScreen *screen, qreal factor) { m_active = true; - m_perWindowActive = true; - window->setProperty(scaleFactorProperty, QVariant(factor)); + m_perScreenActive = true; + screen->setProperty(scaleFactorProperty, QVariant(factor)); } - /* QPoint QXcbScreen::mapToNative(const QPoint &pos) const @@ -141,31 +158,46 @@ QPoint QHighDpiScaling::mapPositionFromNative(const QPoint &pos, const QPlatform return (pos - topLeft) / scaleFactor + topLeft; } +qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) +{ + qreal factor = qreal(1.0); + if (m_perScreenActive && screen) { + factor *= screen->pixelDensity(); + QVariant screenFactor = screen->screen()->property(scaleFactorProperty); + if (screenFactor.isValid()) + factor *= screenFactor.toReal(); + } + return factor; +} qreal QHighDpiScaling::factor(const QScreen *screen) { - if (m_autoFactor && screen && screen->handle()) - return screen->handle()->pixelDensity(); - return m_factor; + // Fast path for when scaling in Qt is not used at all. + if (!m_active) + return qreal(1.0); + + // The effective factor for a given screen is the product of the + // screen and global sub-factors + qreal factor = m_factor; + if (screen) + factor *= screenSubfactor(screen->handle()); + return factor; } qreal QHighDpiScaling::factor(const QPlatformScreen *platformScreen) { - if (m_autoFactor && platformScreen) - return platformScreen->pixelDensity(); - return m_factor; + if (!m_active) + return qreal(1.0); + + return m_factor * screenSubfactor(platformScreen); } qreal QHighDpiScaling::factor(const QWindow *window) { - qreal f = m_factor; - if (m_autoFactor && window && window->screen() && window->screen()->handle()) - f = window->screen()->handle()->pixelDensity(); - if (!m_perWindowActive || window == 0) - return f; - - QVariant windowFactor = window->property(scaleFactorProperty); - return f * (windowFactor.isValid() ? windowFactor.toReal() : 1); + if (!m_active || !window) + return qreal(1.0); + + return factor(window->screen()); } QPoint QHighDpiScaling::origin(const QScreen *screen) diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h index 2350ca6fdb..a5d4c40a07 100644 --- a/src/gui/kernel/qhighdpiscaling_p.h +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -83,6 +83,10 @@ class QPlatformScreen; class Q_GUI_EXPORT QHighDpiScaling { public: + static void initHighDPiScaling(); + static void setGlobalFactor(qreal factor); + static void setScreenFactor(QScreen *window, qreal factor); + static bool isActive() { return m_active; } static qreal factor(const QWindow *window); static qreal factor(const QScreen *screen); @@ -91,13 +95,12 @@ public: static QPoint origin(const QPlatformScreen *platformScreen); static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen); static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen); - static void setFactor(qreal factor); - static void setWindowFactor(QWindow *window, qreal factor); private: + static qreal screenSubfactor(const QPlatformScreen *screen); + static qreal m_factor; - static bool m_autoFactor; static bool m_active; - static bool m_perWindowActive; + static bool m_perScreenActive; }; // Coordinate system conversion functions: @@ -157,7 +160,6 @@ inline QRect toNative(const QRect &rect, qreal scaleFactor, const QPoint &origin } - inline QRect fromNative(const QRect &rect, const QScreen *screen, const QPoint &screenOrigin) { return toNative(rect, QHighDpiScaling::factor(screen), screenOrigin); diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp index bda7280e81..ccb0452629 100644 --- a/src/gui/kernel/qplatformscreen.cpp +++ b/src/gui/kernel/qplatformscreen.cpp @@ -159,9 +159,11 @@ QDpi QPlatformScreen::logicalDpi() const /*! Reimplement this function in subclass to return the device pixel ratio for the screen. This is the ratio between physical pixels and the - device-independent pixels of the windowing system. + device-independent pixels of the windowing system. The default + implementation returns 1.0. - \sa QPlatformWindow::devicePixelRatio(); + \sa QPlatformWindow::devicePixelRatio() + \sa QPlatformScreen::pixelDensity() */ qreal QPlatformScreen::devicePixelRatio() const { @@ -171,7 +173,17 @@ qreal QPlatformScreen::devicePixelRatio() const /*! Reimplement this function in subclass to return the pixel density of the screen. This is the scale factor needed to make a low-dpi application - usable on this screen. The default implementation returns 1.0. + usable on this screen. The default implementation returns 1.0. In + addition the platform integration must return true for the PlatformScreenPixelDensity + Capability for this value to have an effect. + + Returning something else than 1 from this function causes Qt to + apply the scale factor to the application's coordinate system. + This is different from devicePixelRatio, which reports a scale + factor already applied by the windowing system. A platform plugin + typically implements one (or none) of these two functions. + + \sa QPlatformWindow::devicePixelRatio() */ qreal QPlatformScreen::pixelDensity() const { diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index d84035e29c..4465a9aeb4 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1086,17 +1086,13 @@ qreal QWindow::devicePixelRatio() const { Q_D(const QWindow); - // Get the platform scale factor. If there is no platform window - // use the app global devicePixelRatio, which is the the highest - // devicePixelRatio found on the system screens, and will be - // correct for single-display systems (a very common case). - qreal ratio = d->platformWindow ? d->platformWindow->devicePixelRatio() - : qApp->devicePixelRatio(); - - // - ratio *= QHighDpiScaling::factor(this); + // If there is no platform window use the app global devicePixelRatio, + // which is the the highest devicePixelRatio found on the system + // screens, and will be correct for single-display systems (a very common case). + if (!d->platformWindow) + return qApp->devicePixelRatio(); - return ratio; + return d->platformWindow->devicePixelRatio() * QHighDpiScaling::factor(this); } /*! diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index cf9a96b993..184fc58cf0 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -574,7 +574,7 @@ static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/, m_density = density; if (m_highDpiScalingEnabled) - QHighDpiScaling::setFactor(density); + QHighDpiScaling::setGlobalFactor(density); if (!m_androidPlatformIntegration) { QAndroidPlatformIntegration::setDefaultDisplayMetrics(desktopWidthPixels, diff --git a/tests/manual/highdpi/highdpi.pro b/tests/manual/highdpi/highdpi.pro index f6d49033ce..842d98f110 100644 --- a/tests/manual/highdpi/highdpi.pro +++ b/tests/manual/highdpi/highdpi.pro @@ -2,8 +2,9 @@ TEMPLATE = app TARGET = highdpi INCLUDEPATH += . QT += widgets gui-private -CONFIG+=console +CONFIG +=console CONFIG -= app_bundle +CONFIG += c++11 # Input SOURCES += main.cpp diff --git a/tests/manual/highdpi/main.cpp b/tests/manual/highdpi/main.cpp index b6305ba1d4..fb5ff33232 100644 --- a/tests/manual/highdpi/main.cpp +++ b/tests/manual/highdpi/main.cpp @@ -56,69 +56,64 @@ #include <QDebug> #include <private/qhighdpiscaling_p.h> -class ScaleFactorSetter : public QWidget +class ScreenScaleFactorSetter : public QWidget { Q_OBJECT public: - ScaleFactorSetter(); - QLabel *label; - QSlider *slider; - QLabel *scaleFactorLabel; - QHBoxLayout *layout; -private Q_SLOTS: - void scaleFactorChanged(int scaleFactor); + ScreenScaleFactorSetter(); }; -// Shows a slider which sets the scale factor for all windows. -ScaleFactorSetter::ScaleFactorSetter() +ScreenScaleFactorSetter::ScreenScaleFactorSetter() { - label = new QLabel("Scale Factor"); - slider = new QSlider(); - slider->setOrientation(Qt::Horizontal); - slider->setMinimum(1); - slider->setMaximum(40); - slider->setValue(10); - slider->setTracking(true); - slider->setTickInterval(5); - slider->setTickPosition(QSlider::TicksBelow); - scaleFactorLabel = new QLabel("1.0"); - - layout = new QHBoxLayout(); - layout->addWidget(label); - layout->addWidget(slider); - layout->addWidget(scaleFactorLabel); - setLayout(layout); + setWindowTitle("screen scale factors"); + setObjectName("controller"); // make WindowScaleFactorSetter skip this window - connect(slider, SIGNAL(valueChanged(int)), this, SLOT(scaleFactorChanged(int))); -} + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); -void ScaleFactorSetter::scaleFactorChanged(int scaleFactor) -{ - // slider value is scale factor times ten; - qreal scalefactorF = qreal(scaleFactor) / 10.0; - - // update label, add ".0" if needed. - QString number = QString::number(scalefactorF); - if (!number.contains(".")) - number.append(".0"); - scaleFactorLabel->setText(number); - - // set scale factor on all top-level windows - QWindowList windows = QGuiApplication::topLevelWindows(); - foreach (QWindow *window, windows) { - - // skip this controller window - if (window == this->windowHandle()) - continue; - - qDebug() << "set scale factor on" << window; - qreal oldFactor = QHighDpiScaling::factor(window); - QHighDpiScaling::setWindowFactor(window, scalefactorF); - qreal newFactor = QHighDpiScaling::factor(window); - qDebug() << "factor was / is" << oldFactor << newFactor; - - // resize window to keep showing the same amount of content. - window->resize(window->size() / oldFactor * newFactor); + // set up one scale control line per screen + QList<QScreen *> screens = QGuiApplication::screens(); + foreach (QScreen *screen, screens) { + // create scale control line + QHBoxLayout *row = new QHBoxLayout; + QSize screenSize = screen->geometry().size(); + QString screenId = screen->name() + " " + QString::number(screenSize.width()) + + " " + QString::number(screenSize.height()); + QLabel *label = new QLabel(screenId); + QSlider *slider = new QSlider(); + slider->setOrientation(Qt::Horizontal); + slider->setMinimum(1); + slider->setMaximum(40); + slider->setValue(10); + slider->setTracking(true); + slider->setTickInterval(5); + slider->setTickPosition(QSlider::TicksBelow); + QLabel *scaleFactorLabel = new QLabel("1.0"); + + // set up layouts + row->addWidget(label); + row->addWidget(slider); + row->addWidget(scaleFactorLabel); + layout->addLayout(row); + + // handle slider value change + connect(slider, &QSlider::valueChanged, [scaleFactorLabel, screen](int scaleFactor){ + // slider value is scale factor times ten; + qreal scalefactorF = qreal(scaleFactor) / 10.0; + + // update label, add ".0" if needed. + QString number = QString::number(scalefactorF); + if (!number.contains(".")) + number.append(".0"); + scaleFactorLabel->setText(number); + + // set scale factor for screen + qreal oldFactor = QHighDpiScaling::factor(screen); + QHighDpiScaling::setScreenFactor(screen, scalefactorF); + qreal newFactor = QHighDpiScaling::factor(screen); + + qDebug() << "factor was / is" << oldFactor << newFactor; + }); } } @@ -272,7 +267,7 @@ public: int dy = 50; int maxX = 500; - for (int iconIndex = QStyle::SP_TitleBarMenuButton; iconIndex < QStyle::SP_MediaVolumeMuted; ++iconIndex) { + for (uint iconIndex = QStyle::SP_TitleBarMenuButton; iconIndex < QStyle::SP_MediaVolumeMuted; ++iconIndex) { QIcon icon = qApp->style()->standardIcon(QStyle::StandardPixmap(iconIndex)); QPainter p(this); p.drawPixmap(x, y, icon.pixmap(dx - 5, dy - 5)); @@ -607,11 +602,15 @@ int main(int argc, char **argv) QCoreApplication::setApplicationVersion(QT_VERSION_STR); QCommandLineParser parser; - parser.setApplicationDescription("High DPI tester"); + parser.setApplicationDescription("High DPI tester. Pass one or more of the options to\n" + "test various high-dpi aspects. \n" + "--sceen-scale-factor is a special option and opens a configuration" + " window for setting window and screen scale factors."); parser.addHelpOption(); parser.addVersionOption(); - QCommandLineOption scaleFactorOption("window-scale-factor", "Show Scale Factor Slider"); - parser.addOption(scaleFactorOption); + QCommandLineOption screenScaleFactorOption("screen-scale-factor", "Show screen scale factor setter."); + parser.addOption(screenScaleFactorOption); + QCommandLineOption pixmapPainterOption("pixmap", "Test pixmap painter"); parser.addOption(pixmapPainterOption); QCommandLineOption labelOption("label", "Test Labels"); @@ -633,13 +632,13 @@ int main(int argc, char **argv) QCommandLineOption linePainterOption("linepainter", "Test line painting"); parser.addOption(linePainterOption); - parser.process(app); - QScopedPointer<ScaleFactorSetter> scaleFactorSetter; - if (parser.isSet(scaleFactorOption)) { - scaleFactorSetter.reset(new ScaleFactorSetter); - scaleFactorSetter->show(); + // special screen scale factor controller + QScopedPointer<ScreenScaleFactorSetter> screeScaleFactorSetter; + if (parser.isSet(screenScaleFactorOption)) { + screeScaleFactorSetter.reset(new ScreenScaleFactorSetter); + screeScaleFactorSetter->show(); } QScopedPointer<PixmapPainter> pixmapPainter; |