diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 1ceedf460550340da2270d8cb9719ab38b3fb466..3e3af6ede30e5411ddabdaa1d8c62447aba1e7e9 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -496,6 +496,7 @@ public: AA_UseSoftwareOpenGL = 17, AA_ShareOpenGLContexts = 18, AA_SetPalette = 19, + AA_NoHighDpiScaling = 20, // Add new attributes before this line AA_AttributeCount diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index c5617c1616fff4d5b2125673c2120815492b0e41..aeff9502feb969706deee46931f03012df89fa91 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -197,6 +197,11 @@ \value AA_SetPalette Indicates whether a palette was explicitly set on the QApplication/QGuiApplication. This value has been added in Qt 5.5. + \value AA_NoHighDpiScaling Disables all high-DPI scaling in Qt, exposing window + system coordinates. Note that the window system may do its own scaling, + so this does not guarantee that QPaintDevice::devicePixelRatio() will + be equal to 1. This value has been added in Qt 5.6. + The following values are obsolete: \value AA_ImmediateWidgetCreation This attribute is no longer fully diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index af6a41760808c42a73265a3dd939aeb7b1e4cb20..73a5a7b6ab243a67734b7d03063908b9d1ed478f 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -75,7 +75,9 @@ HEADERS += \ kernel/qplatformgraphicsbuffer.h \ kernel/qplatformgraphicsbufferhelper.h \ kernel/qinputdevicemanager_p.h \ - kernel/qinputdevicemanager_p_p.h + kernel/qinputdevicemanager_p_p.h \ + kernel/qhighdpiscaling_p.h + SOURCES += \ kernel/qgenericpluginfactory.cpp \ @@ -131,7 +133,9 @@ SOURCES += \ kernel/qrasterwindow.cpp \ kernel/qplatformgraphicsbuffer.cpp \ kernel/qplatformgraphicsbufferhelper.cpp \ - kernel/qinputdevicemanager.cpp + kernel/qinputdevicemanager.cpp \ + kernel/qhighdpiscaling.cpp + contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) { HEADERS += \ diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp index 6ed750eda12215b2150f9d586ba0d5d5ad9c22b4..dbf2b3c21ff5348c34975d1edf5df92a72d5b82b 100644 --- a/src/gui/kernel/qcursor.cpp +++ b/src/gui/kernel/qcursor.cpp @@ -43,6 +43,7 @@ #include <qpa/qplatformcursor.h> #include <private/qguiapplication_p.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -177,9 +178,14 @@ QT_BEGIN_NAMESPACE */ QPoint QCursor::pos(const QScreen *screen) { - if (screen) - if (const QPlatformCursor *cursor = screen->handle()->cursor()) - return cursor->pos(); + if (screen) { + if (const QPlatformCursor *cursor = screen->handle()->cursor()) { + const QPlatformScreen *ps = screen->handle(); + QPoint nativePos = cursor->pos(); + ps = ps->screenForPosition(nativePos); + return QHighDpi::fromNativePixels(nativePos, ps->screen()); + } + } return QGuiApplicationPrivate::lastCursorPosition.toPoint(); } @@ -231,12 +237,12 @@ void QCursor::setPos(QScreen *screen, int x, int y) { if (screen) { if (QPlatformCursor *cursor = screen->handle()->cursor()) { - const QPoint pos = QPoint(x, y); + const QPoint devicePos = QHighDpi::toNativePixels(QPoint(x, y), screen); // Need to check, since some X servers generate null mouse move // events, causing looping in applications which call setPos() on // every mouse move event. - if (pos != cursor->pos()) - cursor->setPos(pos); + if (devicePos != cursor->pos()) + cursor->setPos(devicePos); } } } diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 2a451453d07bcbefaa64f904050ef7817899c448..00b0c464dfc7dae5da53407eede6505deb08e46a 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -959,8 +959,10 @@ QWindow *QGuiApplication::topLevelAt(const QPoint &pos) QList<QScreen *>::const_iterator end = screens.constEnd(); while (screen != end) { - if ((*screen)->geometry().contains(pos)) - return (*screen)->handle()->topLevelAt(pos); + if ((*screen)->geometry().contains(pos)) { + const QPoint devicePosition = QHighDpi::toNativePixels(pos, *screen); + return (*screen)->handle()->topLevelAt(devicePosition); + } ++screen; } return 0; @@ -1116,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")); @@ -1178,6 +1183,8 @@ void QGuiApplicationPrivate::createPlatformIntegration() if (!icon.isEmpty()) forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon); + + QHighDpiScaling::updateHighDpiScaling(); } /*! @@ -1822,7 +1829,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo points << point; QEvent::Type type; - QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type); + QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type); QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers); fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; @@ -2032,6 +2039,11 @@ void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterf window->d_func()->setTopLevelScreen(screen, false /* recreate */); else // Fall back to default behavior, and try to find some appropriate screen window->setScreen(0); + // we may have changed scaling, so trigger resize event if needed + if (window->handle()) { + QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window), QRect()); + processGeometryChangeEvent(&gce); + } } } diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..19e3045fc95b3e64630f1bc1073736fed25c8284 --- /dev/null +++ b/src/gui/kernel/qhighdpiscaling.cpp @@ -0,0 +1,320 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhighdpiscaling_p.h" +#include "qguiapplication.h" +#include "qscreen.h" +#include "qplatformintegration.h" +#include "private/qscreen_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcScaling, "qt.scaling"); + +static const char legacyDevicePixelEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; +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 inline qreal initialScaleFactor() +{ + + qreal result = 1; + if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) { + bool ok; + const qreal f = qgetenv(scaleFactorEnvVar).toDouble(&ok); + if (ok && f > 0) { + qCDebug(lcScaling) << "Apply " << scaleFactorEnvVar << f; + result = f; + } + } else { + if (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar)) { + qWarning() << "Warning:" << legacyDevicePixelEnvVar << "is deprecated. Instead use:"; + qWarning() << " " << autoScreenEnvVar << "to enable platform plugin controlled per-screen factors."; + qWarning() << " " << screenFactorsEnvVar << "to set per-screen factors."; + qWarning() << " " << scaleFactorEnvVar << "to set the application global scale factor."; + + int dpr = qEnvironmentVariableIntValue(legacyDevicePixelEnvVar); + if (dpr > 0) + result = dpr; + } + } + return result; +} + +/*! + \class QHighDpiScaling + \since 5.6 + \internal + \preliminary + \ingroup qpa + + \brief Collection of utility functions for UI scaling. + + QHighDpiScaling implements utility functions for high-dpi scaling for use + on operating systems that provide limited support for native scaling. In + addition this functionality can be used for simulation and testing purposes. + + The functions support scaling between the device independent coordinate + system used by Qt applications and the native coordinate system used by + the platform plugins. Intended usage locations are the low level / platform + plugin interfacing parts of QtGui, for example the QWindow, QScreen and + QWindowSystemInterface implementation. + + The coordinate system scaling is enabled by setting one or more scale + factors. These will then be factored into the value returned by the + devicePixelRatio() accessors (any native scale factor will also be + included in this value). Several setters are available: + + - A process-global scale factor + - QT_SCALE_FACTOR (environment variable) + - QHighDpiScaling::setGlobalFactor() + + - A per-screen scale factor + - QT_AUTO_SCALE_FACTOR (environment variable) + Setting this to a true-ish value will make QHighDpiScaling + call QPlatformScreen::pixelDensity() + - QHighDpiScaling::setScreenFactor(screen, factor); + - QT_SCREEN_SCALE_FACTORS (environment variable) + Set this to a semicolon-separated list of scale factors + (matching the order of QGuiApplications::screens()), + or to a list of name=value pairs (where name matches + QScreen::name()). + + All scale factors are of type qreal. + + The main scaling functions for use in QtGui are: + T toNativePixels(T, QWindow *) + T fromNativePixels(T, QWindow*) + Where T is QPoint, QSize, QRect etc. +*/ + +qreal QHighDpiScaling::m_factor = 1.0; +bool QHighDpiScaling::m_active = false; //"overall active" - is there any scale factor set. +bool QHighDpiScaling::m_usePixelDensity = false; // use scale factor from platform plugin +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 + platform plugin is created. +*/ +void QHighDpiScaling::initHighDpiScaling() +{ + if (QCoreApplication::testAttribute(Qt::AA_NoHighDpiScaling)) { + m_factor = 1; + m_active = false; + return; + } + m_factor = initialScaleFactor(); + bool usePlatformPluginPixelDensity = qEnvironmentVariableIsSet(autoScreenEnvVar) + || qgetenv(legacyDevicePixelEnvVar).toLower() == "auto"; + + m_globalScalingActive = !qFuzzyCompare(m_factor, qreal(1)); + m_usePixelDensity = usePlatformPluginPixelDensity; + 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; +} + +void QHighDpiScaling::updateHighDpiScaling() +{ + if (QCoreApplication::testAttribute(Qt::AA_NoHighDpiScaling)) + return; + + if (m_usePixelDensity && !m_pixelDensityScalingActive) { + Q_FOREACH (QScreen *screen, QGuiApplication::screens()) { + if (!qFuzzyCompare(screenSubfactor(screen->handle()), qreal(1))) { + m_pixelDensityScalingActive = true; + break; + } + } + } + if (qEnvironmentVariableIsSet(screenFactorsEnvVar)) { + int i = 0; + Q_FOREACH (const QByteArray &spec, qgetenv(screenFactorsEnvVar).split(';')) { + QScreen *screen = 0; + int equalsPos = spec.lastIndexOf('='); + double 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) { + Q_FOREACH (QScreen *s, QGuiApplication::screens()) { + if (s->name() == QString::fromLocal8Bit(name)) { + screen = s; + break; + } + } + } + } else { + // listing screens in order + bool ok; + factor = spec.toDouble(&ok); + if (ok && i < QGuiApplication::screens().count()) + screen = QGuiApplication::screens().at(i); + } + if (screen) + setScreenFactor(screen, factor); + ++i; + } + } + m_active = m_globalScalingActive || m_screenFactorSet || m_pixelDensityScalingActive; + + QPlatformScreen *primaryScreen = QGuiApplication::primaryScreen()->handle(); + qreal sf = screenSubfactor(primaryScreen); + QDpi primaryDpi = primaryScreen->logicalDpi(); + m_logicalDpi = QDpi(primaryDpi.first / sf, primaryDpi.second / sf); +} + +/* + Sets the global scale factor which is applied to all windows. +*/ +void QHighDpiScaling::setGlobalFactor(qreal factor) +{ + if (qFuzzyCompare(factor, m_factor)) + return; + if (!QGuiApplication::allWindows().isEmpty()) + qWarning() << Q_FUNC_INFO << "QHighDpiScaling::setFactor: Should only be called when no windows exist."; + + m_globalScalingActive = !qFuzzyCompare(factor, qreal(1)); + m_factor = m_globalScalingActive ? factor : qreal(1); + m_active = m_globalScalingActive || m_screenFactorSet || m_pixelDensityScalingActive; + Q_FOREACH (QScreen *screen, QGuiApplication::screens()) + screen->d_func()->updateHighDpi(); +} + +static const char scaleFactorProperty[] = "_q_scaleFactor"; + +/* + Sets a per-screen scale factor. +*/ +void QHighDpiScaling::setScreenFactor(QScreen *screen, qreal factor) +{ + m_screenFactorSet = true; + m_active = true; + screen->setProperty(scaleFactorProperty, QVariant(factor)); + + // hack to force re-evaluation of screen geometry + if (screen->handle()) + screen->d_func()->setPlatformScreen(screen->handle()); // updates geometries based on scale factor +} + +QPoint QHighDpiScaling::mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen) +{ + if (!platformScreen) + return pos; + const qreal scaleFactor = factor(platformScreen); + const QPoint topLeft = platformScreen->geometry().topLeft(); + return (pos - topLeft) * scaleFactor + topLeft; +} + +QPoint QHighDpiScaling::mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen) +{ + if (!platformScreen) + return pos; + const qreal scaleFactor = factor(platformScreen); + const QPoint topLeft = platformScreen->geometry().topLeft(); + return (pos - topLeft) / scaleFactor + topLeft; +} + +qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) +{ + qreal factor = qreal(1.0); + if (screen) { + if (m_usePixelDensity) + factor *= screen->pixelDensity(); + if (m_screenFactorSet) { + QVariant screenFactor = screen->screen()->property(scaleFactorProperty); + if (screenFactor.isValid()) + factor *= screenFactor.toReal(); + } + } + return factor; +} + +QDpi QHighDpiScaling::logicalDpi() +{ + return m_logicalDpi; +} + +qreal QHighDpiScaling::factor(const QScreen *screen) +{ + // 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_active) + return qreal(1.0); + + return m_factor * screenSubfactor(platformScreen); +} + +qreal QHighDpiScaling::factor(const QWindow *window) +{ + if (!m_active) + return qreal(1.0); + + return factor(window ? window->screen() : QGuiApplication::primaryScreen()); +} + +QPoint QHighDpiScaling::origin(const QScreen *screen) +{ + return screen->geometry().topLeft(); +} + +QPoint QHighDpiScaling::origin(const QPlatformScreen *platformScreen) +{ + return platformScreen->geometry().topLeft(); +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h new file mode 100644 index 0000000000000000000000000000000000000000..c79540d9e477c4753ae713b6e4ecc5b7ce02779d --- /dev/null +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -0,0 +1,470 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHIGHDPISCALING_P_H +#define QHIGHDPISCALING_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QtCore/qmargins.h> +#include <QtCore/qrect.h> +#include <QtCore/qvector.h> +#include <QtCore/qloggingcategory.h> +#include <QtGui/qregion.h> +#include <QtGui/qscreen.h> +#include <QtGui/qwindow.h> + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(lcScaling); + +class QScreen; +class QPlatformScreen; +typedef QPair<qreal, qreal> QDpi; + +class Q_GUI_EXPORT QHighDpiScaling { +public: + static void initHighDpiScaling(); + static void updateHighDpiScaling(); + 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); + static qreal factor(const QPlatformScreen *platformScreen); + static QPoint origin(const QScreen *screen); + 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 QDpi logicalDpi(); + +private: + static qreal screenSubfactor(const QPlatformScreen *screen); + + static qreal m_factor; + static bool m_active; + static bool m_usePixelDensity; + static bool m_globalScalingActive; + static bool m_pixelDensityScalingActive; + static bool m_screenFactorSet; + static QDpi m_logicalDpi; +}; + +// Coordinate system conversion functions: +// QHighDpi::fromNativePixels : from physical(screen/backing) to logical pixels +// QHighDpi::toNativePixels : from logical to physical pixels + +namespace QHighDpi { + +inline QPointF fromNative(const QPointF &pos, qreal scaleFactor, const QPointF &origin) +{ + return (pos - origin) / scaleFactor + origin; +} + +inline QPointF toNative(const QPointF &pos, qreal scaleFactor, const QPointF &origin) +{ + return (pos - origin) * scaleFactor + origin; +} + +inline QPoint fromNative(const QPoint &pos, qreal scaleFactor, const QPoint &origin) +{ + return (pos - origin) / scaleFactor + origin; +} + +inline QPoint toNative(const QPoint &pos, qreal scaleFactor, const QPoint &origin) +{ + return (pos - origin) * scaleFactor + origin; +} + +inline QPoint fromNative(const QPoint &pos, qreal scaleFactor) +{ + return pos / scaleFactor; +} + +inline QPoint toNative(const QPoint &pos, qreal scaleFactor) +{ + return pos * scaleFactor; +} + +inline QSize fromNative(const QSize &size, qreal scaleFactor) +{ + return size / scaleFactor; // TODO: should we round up? +} + +inline QSize toNative(const QSize &size, qreal scaleFactor) +{ + return size * scaleFactor; +} + +inline QSizeF fromNative(const QSizeF &size, qreal scaleFactor) +{ + return size / scaleFactor; +} + +inline QSizeF toNative(const QSizeF &size, qreal scaleFactor) +{ + return size * scaleFactor; +} + +inline QRect fromNative(const QRect &rect, qreal scaleFactor, const QPoint &origin) +{ + return QRect(fromNative(rect.topLeft(), scaleFactor, origin), fromNative(rect.size(), scaleFactor)); +} + +inline QRect toNative(const QRect &rect, qreal scaleFactor, const QPoint &origin) +{ + return QRect(toNative(rect.topLeft(), scaleFactor, origin), toNative(rect.size(), scaleFactor)); + +} + +inline QRect fromNative(const QRect &rect, const QScreen *screen, const QPoint &screenOrigin) +{ + return toNative(rect, QHighDpiScaling::factor(screen), screenOrigin); +} + +inline QRect fromNativeScreenGeometry(const QRect &nativeScreenGeometry, const QScreen *screen) +{ + return QRect(nativeScreenGeometry.topLeft(), + fromNative(nativeScreenGeometry.size(), QHighDpiScaling::factor(screen))); +} + +inline QPoint fromNativeLocalPosition(const QPoint &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos / scaleFactor; +} + +inline QPoint toNativeLocalPosition(const QPoint &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos * scaleFactor; +} + +inline QPointF fromNativeLocalPosition(const QPointF &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos / scaleFactor; +} + +inline QPointF toNativeLocalPosition(const QPointF &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos * scaleFactor; +} + +inline QRect fromNativePixels(const QRect &pixelRect, const QPlatformScreen *platformScreen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(platformScreen); + const QPoint origin = QHighDpiScaling::origin(platformScreen); + return QRect(fromNative(pixelRect.topLeft(), scaleFactor, origin), + fromNative(pixelRect.size(), scaleFactor)); +} + +inline QRect toNativePixels(const QRect &pointRect, const QPlatformScreen *platformScreen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(platformScreen); + const QPoint origin = QHighDpiScaling::origin(platformScreen); + return QRect(toNative(pointRect.topLeft(), scaleFactor, origin), + toNative(pointRect.size(), scaleFactor)); +} + +inline QRect fromNativePixels(const QRect &pixelRect, const QScreen *screen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(screen); + const QPoint origin = QHighDpiScaling::origin(screen); + return QRect(fromNative(pixelRect.topLeft(), scaleFactor, origin), + fromNative(pixelRect.size(), scaleFactor)); +} + +inline QRect toNativePixels(const QRect &pointRect, const QScreen *screen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(screen); + const QPoint origin = QHighDpiScaling::origin(screen); + return QRect(toNative(pointRect.topLeft(), scaleFactor, origin), + toNative(pointRect.size(), scaleFactor)); +} + +inline QRect fromNativePixels(const QRect &pixelRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return fromNativePixels(pixelRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRect(pixelRect.topLeft() / scaleFactor, fromNative(pixelRect.size(), scaleFactor)); + } +} + +inline QRectF toNativePixels(const QRectF &pointRect, const QScreen *screen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(screen); + const QPoint origin = QHighDpiScaling::origin(screen); + return QRectF(toNative(pointRect.topLeft(), scaleFactor, origin), + toNative(pointRect.size(), scaleFactor)); +} + +inline QRect toNativePixels(const QRect &pointRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return toNativePixels(pointRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRect(pointRect.topLeft() * scaleFactor, toNative(pointRect.size(), scaleFactor)); + } +} + +inline QRectF fromNativePixels(const QRectF &pixelRect, const QScreen *screen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(screen); + const QPoint origin = QHighDpiScaling::origin(screen); + return QRectF(fromNative(pixelRect.topLeft(), scaleFactor, origin), + fromNative(pixelRect.size(), scaleFactor)); +} + +inline QRectF fromNativePixels(const QRectF &pixelRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return fromNativePixels(pixelRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRectF(pixelRect.topLeft() / scaleFactor, pixelRect.size() / scaleFactor); + } +} + +inline QRectF toNativePixels(const QRectF &pointRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return toNativePixels(pointRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRectF(pointRect.topLeft() * scaleFactor, pointRect.size() * scaleFactor); + } +} + +inline QSize fromNativePixels(const QSize &pixelSize, const QWindow *window) +{ + return pixelSize / QHighDpiScaling::factor(window); +} + +inline QSize toNativePixels(const QSize &pointSize, const QWindow *window) +{ + return pointSize * QHighDpiScaling::factor(window); +} + +inline QSizeF fromNativePixels(const QSizeF &pixelSize, const QWindow *window) +{ + return pixelSize / QHighDpiScaling::factor(window); +} + +inline QSizeF toNativePixels(const QSizeF &pointSize, const QWindow *window) +{ + return pointSize * QHighDpiScaling::factor(window); +} + +inline QPoint fromNativePixels(const QPoint &pixelPoint, const QScreen *screen) +{ + return fromNative(pixelPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); +} + +inline QPoint fromNativePixels(const QPoint &pixelPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return fromNativePixels(pixelPoint, window->screen()); + else + return pixelPoint / QHighDpiScaling::factor(window); +} + +inline QPoint toNativePixels(const QPoint &pointPoint, const QScreen *screen) +{ + return toNative(pointPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); +} + +inline QPoint toNativePixels(const QPoint &pointPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return toNativePixels(pointPoint, window->screen()); + else + return pointPoint * QHighDpiScaling::factor(window); +} + +inline QPointF fromNativePixels(const QPointF &pixelPoint, const QScreen *screen) +{ + return fromNative(pixelPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); +} + +inline QPointF fromNativePixels(const QPointF &pixelPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return fromNativePixels(pixelPoint, window->screen()); + else + return pixelPoint / QHighDpiScaling::factor(window); +} + +inline QPointF toNativePixels(const QPointF &pointPoint, const QScreen *screen) +{ + return toNative(pointPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); +} + +inline QPointF toNativePixels(const QPointF &pointPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return toNativePixels(pointPoint, window->screen()); + else + return pointPoint * QHighDpiScaling::factor(window); +} + +inline QMargins fromNativePixels(const QMargins &pixelMargins, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QMargins(pixelMargins.left() / scaleFactor, pixelMargins.top() / scaleFactor, + pixelMargins.right() / scaleFactor, pixelMargins.bottom() / scaleFactor); +} + +inline QMargins toNativePixels(const QMargins &pointMargins, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QMargins(pointMargins.left() * scaleFactor, pointMargins.top() * scaleFactor, + pointMargins.right() * scaleFactor, pointMargins.bottom() * scaleFactor); +} + +inline QRegion fromNativeLocalRegion(const QRegion &pixelRegion, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pixelRegion; + + qreal scaleFactor = QHighDpiScaling::factor(window); + QRegion pointRegion; + foreach (const QRect &rect, pixelRegion.rects()) { + pointRegion += QRect(fromNative(rect.topLeft(), scaleFactor), + fromNative(rect.size(), scaleFactor)); + } + return pointRegion; +} + +inline QRegion toNativeLocalRegion(const QRegion &pointRegion, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pointRegion; + + qreal scaleFactor = QHighDpiScaling::factor(window); + QRegion pixelRegon; + foreach (const QRect &rect, pointRegion.rects()) { + pixelRegon += QRect(toNative(rect.topLeft(), scaleFactor), + toNative(rect.size(), scaleFactor)); + } + return pixelRegon; +} + +// Any T that has operator/() +template <typename T> +T fromNativePixels(const T &pixelValue, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pixelValue; + + return pixelValue / QHighDpiScaling::factor(window); + +} + + //##### ????? +template <typename T> +T fromNativePixels(const T &pixelValue, const QScreen *screen) +{ + if (!QHighDpiScaling::isActive()) + return pixelValue; + + return pixelValue / QHighDpiScaling::factor(screen); + +} + +// Any T that has operator*() +template <typename T> +T toNativePixels(const T &pointValue, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pointValue; + + return pointValue * QHighDpiScaling::factor(window); +} + +template <typename T> +T toNativePixels(const T &pointValue, const QScreen *screen) +{ + if (!QHighDpiScaling::isActive()) + return pointValue; + + return pointValue * QHighDpiScaling::factor(screen); +} + + +// Any QVector<T> where T has operator/() +template <typename T> +QVector<T> fromNativePixels(const QVector<T> &pixelValues, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pixelValues; + + QVector<T> pointValues; + foreach (const T& pixelValue, pixelValues) + pointValues.append(pixelValue / QHighDpiScaling::factor(window)); + return pointValues; +} + +// Any QVector<T> where T has operator*() +template <typename T> +QVector<T> toNativePixels(const QVector<T> &pointValues, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pointValues; + + QVector<T> pixelValues; + foreach (const T& pointValue, pointValues) + pixelValues.append(pointValue * QHighDpiScaling::factor(window)); + return pixelValues; +} + +} // namespace QHighDpi + +QT_END_NAMESPACE + +#endif // QHIGHDPISCALING_P_H diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 4d973d47a5bd2f47d9928211977eda7f4a0c9463..e935907a62c5cef79262c1952ea7ad451f6113a7 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -39,7 +39,6 @@ #include <qpa/qplatformtheme.h> #include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qpixmap_raster_p.h> -#include <qpa/qplatformscreen_p.h> #include <private/qdnd_p.h> #include <private/qsimpledrag_p.h> @@ -450,7 +449,7 @@ QList<int> QPlatformIntegration::possibleKeys(const QKeyEvent *) const void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary) { QScreen *screen = new QScreen(ps); - ps->d_func()->screen = screen; + if (isPrimary) { QGuiApplicationPrivate::screen_list.prepend(screen); } else { @@ -469,8 +468,9 @@ void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary) */ void QPlatformIntegration::destroyScreen(QPlatformScreen *screen) { - QGuiApplicationPrivate::screen_list.removeOne(screen->d_func()->screen); - delete screen->d_func()->screen; + QScreen *qScreen = screen->screen(); + QGuiApplicationPrivate::screen_list.removeOne(qScreen); + delete qScreen; delete screen; } diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp index 9aab102de34669f2497e69a604bb078728c944de..2fb53fe16bcbdc14362b983506b62d57c3fc14c6 100644 --- a/src/gui/kernel/qplatformscreen.cpp +++ b/src/gui/kernel/qplatformscreen.cpp @@ -40,6 +40,7 @@ #include <qpa/qplatformintegration.h> #include <QtGui/qscreen.h> #include <QtGui/qwindow.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -96,6 +97,23 @@ QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const return 0; } +/*! + Find the sibling screen corresponding to \a globalPos. + + Returns this screen if no suitable screen is found at the position. + */ +const QPlatformScreen *QPlatformScreen::screenForPosition(const QPoint &point) const +{ + if (!geometry().contains(point)) { + Q_FOREACH (const QPlatformScreen* screen, virtualSiblings()) { + if (screen->geometry().contains(point)) + return screen; + } + } + return this; +} + + /*! Returns a list of all the platform screens that are part of the same virtual desktop. @@ -156,17 +174,37 @@ 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 device-independent pixels. + 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. The default + implementation returns 1.0. - \sa QPlatformWindow::devicePixelRatio(); + \sa QPlatformWindow::devicePixelRatio() + \sa QPlatformScreen::pixelDensity() */ qreal QPlatformScreen::devicePixelRatio() const { return 1.0; } +/*! + 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. + + Returning something else than 1.0 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 +{ + return 1.0; +} + /*! Reimplement this function in subclass to return the vertical refresh rate of the screen, in Hz. @@ -290,8 +328,8 @@ void QPlatformScreen::resizeMaximizedWindows() // 'screen()' still has the old geometry info while 'this' has the new geometry info const QRect oldGeometry = screen()->geometry(); const QRect oldAvailableGeometry = screen()->availableGeometry(); - const QRect newGeometry = geometry(); - const QRect newAvailableGeometry = availableGeometry(); + const QRect newGeometry = deviceIndependentGeometry(); + const QRect newAvailableGeometry = QHighDpi::fromNative(availableGeometry(), QHighDpiScaling::factor(this), newGeometry.topLeft()); // make sure maximized and fullscreen windows are updated for (int i = 0; i < windows.size(); ++i) { @@ -393,6 +431,13 @@ QRect QPlatformScreen::mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation return rect; } +QRect QPlatformScreen::deviceIndependentGeometry() const +{ + qreal scaleFactor = QHighDpiScaling::factor(this); + QRect nativeGeometry = geometry(); + return QRect(nativeGeometry.topLeft(), QHighDpi::fromNative(nativeGeometry.size(), scaleFactor)); +} + /*! Returns a hint about this screen's subpixel layout structure. diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h index 2e33107fc37172b00c7dab54c8b7cc2882c20376..b32f9cf97c5f6cf02d886becc33ff220459f0526 100644 --- a/src/gui/kernel/qplatformscreen.h +++ b/src/gui/kernel/qplatformscreen.h @@ -103,6 +103,7 @@ public: virtual QSizeF physicalSize() const; virtual QDpi logicalDpi() const; virtual qreal devicePixelRatio() const; + virtual qreal pixelDensity() const; virtual qreal refreshRate() const; @@ -112,6 +113,7 @@ public: virtual QWindow *topLevelAt(const QPoint &point) const; virtual QList<QPlatformScreen *> virtualSiblings() const; + const QPlatformScreen *screenForPosition(const QPoint &point) const; QScreen *screen() const; @@ -131,6 +133,9 @@ public: static QTransform transformBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &target); static QRect mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect); + // The platform screen's geometry in device independent coordinates + QRect deviceIndependentGeometry() const; + protected: void resizeMaximizedWindows(); @@ -139,7 +144,7 @@ protected: private: Q_DISABLE_COPY(QPlatformScreen) - friend class QPlatformIntegration; + friend class QScreenPrivate; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index 114fcf8062c6295b51169b5be98cb3071e42efc8..d10bd1e9ebe8e04feb596699b2b8f28e06f20137 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -39,8 +39,10 @@ #include <qpa/qwindowsysteminterface.h> #include <QtGui/qwindow.h> #include <QtGui/qscreen.h> +#include <private/qhighdpiscaling_p.h> #include <private/qwindow_p.h> + QT_BEGIN_NAMESPACE /*! @@ -481,13 +483,25 @@ QString QPlatformWindow::formatWindowTitle(const QString &title, const QString & QPlatformScreen *QPlatformWindow::screenForGeometry(const QRect &newGeometry) const { QPlatformScreen *currentScreen = screen(); - if (!parent() && currentScreen && !currentScreen->geometry().intersects(newGeometry)) { + QPlatformScreen *fallback = currentScreen; + QPoint center = newGeometry.center(); + if (!parent() && currentScreen && !currentScreen->geometry().contains(center)) { Q_FOREACH (QPlatformScreen* screen, currentScreen->virtualSiblings()) { - if (screen->geometry().intersects(newGeometry)) + if (screen->geometry().contains(center)) return screen; + if (screen->geometry().intersects(newGeometry)) + fallback = screen; } } - return currentScreen; + return fallback; +} + +/*! + Returns a size with both dimensions bounded to [0, QWINDOWSIZE_MAX] +*/ +QSize QPlatformWindow::constrainWindowSize(const QSize &size) +{ + return size.expandedTo(QSize(0, 0)).boundedTo(QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX)); } /*! @@ -565,7 +579,7 @@ void QPlatformWindow::invalidateSurface() QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry, int defaultWidth, int defaultHeight) { - QRect rect(initialGeometry); + QRect rect(QHighDpi::fromNativePixels(initialGeometry, w)); if (rect.width() == 0) { const int minWidth = w->minimumWidth(); rect.setWidth(minWidth > 0 ? minWidth : defaultWidth); @@ -593,7 +607,7 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, } } } - return rect; + return QHighDpi::toNativePixels(rect, w); } /*! @@ -626,6 +640,69 @@ void QPlatformWindow::requestUpdate() wp->updateTimer = w->startTimer(timeout, Qt::PreciseTimer); } +/*! + Returns the QWindow minimum size. +*/ +QSize QPlatformWindow::windowMinimumSize() const +{ + return constrainWindowSize(QHighDpi::toNativePixels(window()->minimumSize(), window())); +} + +/*! + Returns the QWindow maximum size. +*/ +QSize QPlatformWindow::windowMaximumSize() const +{ + return constrainWindowSize(QHighDpi::toNativePixels(window()->maximumSize(), window())); +} + +/*! + Returns the QWindow base size. +*/ +QSize QPlatformWindow::windowBaseSize() const +{ + return QHighDpi::toNativePixels(window()->baseSize(), window()); +} + +/*! + Returns the QWindow size increment. +*/ +QSize QPlatformWindow::windowSizeIncrement() const +{ + QSize increment = window()->sizeIncrement(); + if (!QHighDpiScaling::isActive()) + return increment; + + // Normalize the increment. If not set the increment can be + // (-1, -1) or (0, 0). Make that (1, 1) which is scalable. + if (increment.isEmpty()) + increment = QSize(1, 1); + + return QHighDpi::toNativePixels(increment, window()); +} + +/*! + Returns the QWindow geometry. +*/ +QRect QPlatformWindow::windowGeometry() const +{ + return QHighDpi::toNativePixels(window()->geometry(), window()); +} + +/*! + Returns the closest acceptable geometry for a given geometry before + a resize/move event for platforms that support it, for example to + implement heightForWidth(). +*/ +QRectF QPlatformWindow::windowClosestAcceptableGeometry(const QRectF &nativeRect) const +{ + QWindow *qWindow = window(); + const QRectF rectF = QHighDpi::fromNativePixels(nativeRect, qWindow); + const QRectF correctedGeometryF = qt_window_private(qWindow)->closestAcceptableGeometry(rectF); + return !correctedGeometryF.isEmpty() && rectF != correctedGeometryF + ? QHighDpi::toNativePixels(correctedGeometryF, qWindow) : nativeRect; +} + /*! \class QPlatformWindow \since 4.8 diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index c7c1efdc58e5a4f0013e34cd93166608993441c5..692ae862db55b91d982d850c175db422eb06c124 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -130,9 +130,20 @@ public: const QRect &initialGeometry, int defaultWidth, int defaultHeight); virtual void requestUpdate(); + + // Window property accessors. Platform plugins should use these + // instead of accessing QWindow directly. + QSize windowMinimumSize() const; + QSize windowMaximumSize() const; + QSize windowBaseSize() const; + QSize windowSizeIncrement() const; + QRect windowGeometry() const; + QRectF windowClosestAcceptableGeometry(const QRectF &nativeRect) const; + protected: static QString formatWindowTitle(const QString &title, const QString &separator); QPlatformScreen *screenForGeometry(const QRect &newGeometry) const; + static QSize constrainWindowSize(const QSize &size); QScopedPointer<QPlatformWindowPrivate> d_ptr; private: diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index 8398f02a5b81a3f82081fe7ab57916cc2594fdfb..407b4ee9b638a6ced5755c1eb39433e6f2e52456 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -36,6 +36,7 @@ #include "qpixmap.h" #include "qguiapplication_p.h" #include <qpa/qplatformscreen.h> +#include <qpa/qplatformscreen_p.h> #include <QtCore/QDebug> #include <QtCore/private/qobject_p.h> @@ -63,8 +64,33 @@ QT_BEGIN_NAMESPACE */ QScreen::QScreen(QPlatformScreen *screen) - : QObject(*new QScreenPrivate(screen), 0) + : QObject(*new QScreenPrivate(), 0) { + Q_D(QScreen); + d->setPlatformScreen(screen); +} + +void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen) +{ + Q_Q(QScreen); + platformScreen = 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(); + refreshRate = platformScreen->refreshRate(); + // safeguard ourselves against buggy platform behavior... + if (refreshRate < 1.0) + refreshRate = 60.0; + + updatePrimaryOrientation(); + + filteredOrientation = orientation; + if (filteredOrientation == Qt::PrimaryOrientation) + filteredOrientation = primaryOrientation; + + updateHighDpi(); } @@ -208,6 +234,8 @@ qreal QScreen::physicalDotsPerInch() const qreal QScreen::logicalDotsPerInchX() const { Q_D(const QScreen); + if (QHighDpiScaling::isActive()) + return QHighDpiScaling::logicalDpi().first; return d->logicalDpi.first; } @@ -222,6 +250,8 @@ qreal QScreen::logicalDotsPerInchX() const qreal QScreen::logicalDotsPerInchY() const { Q_D(const QScreen); + if (QHighDpiScaling::isActive()) + return QHighDpiScaling::logicalDpi().second; return d->logicalDpi.second; } @@ -240,7 +270,7 @@ qreal QScreen::logicalDotsPerInchY() const qreal QScreen::logicalDotsPerInch() const { Q_D(const QScreen); - QDpi dpi = d->logicalDpi; + QDpi dpi = QHighDpiScaling::isActive() ? QHighDpiScaling::logicalDpi() : d->logicalDpi; return (dpi.first + dpi.second) * qreal(0.5); } @@ -259,7 +289,7 @@ qreal QScreen::logicalDotsPerInch() const qreal QScreen::devicePixelRatio() const { Q_D(const QScreen); - return d->platformScreen->devicePixelRatio(); + return d->platformScreen->devicePixelRatio() * QHighDpiScaling::factor(this); } /*! diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h index f60fafcf63b226885530904ede3945c1f1a6a038..a6018128e2171293b54b55fb3126547567900a11 100644 --- a/src/gui/kernel/qscreen.h +++ b/src/gui/kernel/qscreen.h @@ -154,6 +154,7 @@ private: friend class QGuiApplicationPrivate; friend class QPlatformIntegration; friend class QPlatformScreen; + friend class QHighDpiScaling; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/gui/kernel/qscreen_p.h b/src/gui/kernel/qscreen_p.h index d341b71932e3ee8eb329c4e9b62a6cf24609bf36..4492eddd45cda4094d9d4b3ff614493d1cbccbb4 100644 --- a/src/gui/kernel/qscreen_p.h +++ b/src/gui/kernel/qscreen_p.h @@ -47,6 +47,7 @@ #include <QtGui/qscreen.h> #include <qpa/qplatformscreen.h> +#include "qhighdpiscaling_p.h" #include <QtCore/private/qobject_p.h> @@ -54,25 +55,19 @@ QT_BEGIN_NAMESPACE class QScreenPrivate : public QObjectPrivate { + Q_DECLARE_PUBLIC(QScreen) public: - QScreenPrivate(QPlatformScreen *screen) - : platformScreen(screen) + QScreenPrivate() + : platformScreen(0) , orientationUpdateMask(0) { - orientation = platformScreen->orientation(); - geometry = platformScreen->geometry(); - availableGeometry = platformScreen->availableGeometry(); - logicalDpi = platformScreen->logicalDpi(); - refreshRate = platformScreen->refreshRate(); - // safeguard ourselves against buggy platform behavior... - if (refreshRate < 1.0) - refreshRate = 60.0; - - updatePrimaryOrientation(); + } - filteredOrientation = orientation; - if (filteredOrientation == Qt::PrimaryOrientation) - filteredOrientation = primaryOrientation; + void setPlatformScreen(QPlatformScreen *screen); + void updateHighDpi() + { + geometry = platformScreen->deviceIndependentGeometry(); + availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), QHighDpiScaling::factor(platformScreen), geometry.topLeft()); } void updatePrimaryOrientation(); diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 81e00c8d953a090936c9f15cdec5637c9352fa0c..e93e964c6bc9f8916f380c973c0aaa47615fef03 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -47,6 +47,7 @@ #ifndef QT_NO_ACCESSIBILITY # include "qaccessible.h" #endif +#include "qhighdpiscaling_p.h" #include <private/qevent_p.h> @@ -1085,13 +1086,13 @@ qreal QWindow::devicePixelRatio() const { Q_D(const QWindow); - // If there is no platform window, do the second best thing and - // return the app global devicePixelRatio. This is the highest - // devicePixelRatio found on the system screens, and will be - // correct for single-display systems (a very common case). + // 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 d->platformWindow->devicePixelRatio(); + + return d->platformWindow->devicePixelRatio() * QHighDpiScaling::factor(this); } /*! @@ -1431,7 +1432,13 @@ void QWindow::setGeometry(const QRect &rect) d->positionPolicy = QWindowPrivate::WindowFrameExclusive; if (d->platformWindow) { - d->platformWindow->setGeometry(rect); + QRect nativeRect; + QScreen *newScreen = d->screenForGeometry(rect); + if (newScreen && isTopLevel()) + nativeRect = QHighDpi::toNativePixels(rect, newScreen); + else + nativeRect = QHighDpi::toNativePixels(rect, this); + d->platformWindow->setGeometry(nativeRect); } else { d->geometry = rect; @@ -1446,6 +1453,30 @@ void QWindow::setGeometry(const QRect &rect) } } +/* + This is equivalent to QPlatformWindow::screenForGeometry, but in platform + independent coordinates. The duplication is unfortunate, but there is a + chicken and egg problem here: we cannot convert to native coordinates + before we know which screen we are on. +*/ +QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry) +{ + Q_Q(QWindow); + QScreen *currentScreen = q->screen(); + QScreen *fallback = currentScreen; + QPoint center = newGeometry.center(); + if (!q->parent() && currentScreen && !currentScreen->geometry().contains(center)) { + Q_FOREACH (QScreen* screen, currentScreen->virtualSiblings()) { + if (screen->geometry().contains(center)) + return screen; + if (screen->geometry().intersects(newGeometry)) + fallback = screen; + } + } + return fallback; +} + + /*! Returns the geometry of the window, excluding its window frame. @@ -1455,7 +1486,7 @@ QRect QWindow::geometry() const { Q_D(const QWindow); if (d->platformWindow) - return d->platformWindow->geometry(); + return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this); return d->geometry; } @@ -1468,7 +1499,7 @@ QMargins QWindow::frameMargins() const { Q_D(const QWindow); if (d->platformWindow) - return d->platformWindow->frameMargins(); + return QHighDpi::fromNativePixels(d->platformWindow->frameMargins(), this); return QMargins(); } @@ -1482,7 +1513,7 @@ QRect QWindow::frameGeometry() const Q_D(const QWindow); if (d->platformWindow) { QMargins m = frameMargins(); - return d->platformWindow->geometry().adjusted(-m.left(), -m.top(), m.right(), m.bottom()); + return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this).adjusted(-m.left(), -m.top(), m.right(), m.bottom()); } return d->geometry; } @@ -1499,7 +1530,7 @@ QPoint QWindow::framePosition() const Q_D(const QWindow); if (d->platformWindow) { QMargins margins = frameMargins(); - return d->platformWindow->geometry().topLeft() - QPoint(margins.left(), margins.top()); + return QHighDpi::fromNativePixels(d->platformWindow->geometry().topLeft(), this) - QPoint(margins.left(), margins.top()); } return d->geometry.topLeft(); } @@ -1515,7 +1546,7 @@ void QWindow::setFramePosition(const QPoint &point) d->positionPolicy = QWindowPrivate::WindowFrameInclusive; d->positionAutomatic = false; if (d->platformWindow) { - d->platformWindow->setGeometry(QRect(point, size())); + d->platformWindow->setGeometry(QHighDpi::toNativePixels(QRect(point, size()), this)); } else { d->geometry.moveTopLeft(point); } @@ -1575,7 +1606,7 @@ void QWindow::resize(const QSize &newSize) { Q_D(QWindow); if (d->platformWindow) { - d->platformWindow->setGeometry(QRect(position(), newSize)); + d->platformWindow->setGeometry(QHighDpi::toNativePixels(QRect(position(), newSize), this)); } else { const QSize oldSize = d->geometry.size(); d->geometry.setSize(newSize); diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 4fc63acf28f16ba1c41f2f0194c45ee335039217..23a6d800c01d3e2152cd75b4b22563f157816fca 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -136,6 +136,7 @@ public: void connectToScreen(QScreen *topLevelScreen); void disconnectFromScreen(); void emitScreenChangedRecursion(QScreen *newScreen); + QScreen *screenForGeometry(const QRect &rect); virtual void clearFocusObject(); virtual QRectF closestAcceptableGeometry(const QRectF &rect) const; diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 17bce6c70fdf9cf3c097e4a9fe872c226c424e19..5877467830aac19c8d2bd4104ecf84d02c1b8b0d 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -40,6 +40,7 @@ #include <qpa/qplatformdrag.h> #include <qpa/qplatformintegration.h> #include <qdebug.h> +#include "qhighdpiscaling_p.h" QT_BEGIN_NAMESPACE @@ -139,7 +140,7 @@ void QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState */ void QWindowSystemInterface::handleGeometryChange(QWindow *tlw, const QRect &newRect, const QRect &oldRect) { - QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw,newRect, oldRect); + QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw, QHighDpi::fromNativePixels(newRect, tlw), QHighDpi::fromNativePixels(oldRect, tlw)); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -168,7 +169,7 @@ void QWindowSystemInterface::handleMouseEvent(QWindow *w, ulong timestamp, const Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { QWindowSystemInterfacePrivate::MouseEvent * e = - new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, local, global, b, mods, source); + new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -185,7 +186,7 @@ void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, ulong timest QWindowSystemInterfacePrivate::MouseEvent * e = new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, QWindowSystemInterfacePrivate::FrameStrutMouse, - local, global, b, mods, source); + QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -366,14 +367,14 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con // Simple case: vertical deltas only: if (angleDelta.y() != 0 && angleDelta.x() == 0) { - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); return; } // Simple case: horizontal deltas only: if (angleDelta.y() == 0 && angleDelta.x() != 0) { - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); return; } @@ -381,12 +382,12 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con // Both horizontal and vertical deltas: Send two wheel events. // The first event contains the Qt 5 pixel and angle delta as points, // and in addition the Qt 4 compatibility vertical angle delta. - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); // The second event contains null pixel and angle points and the // Qt 4 compatibility horizontal angle delta. - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -449,7 +450,10 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *w, QTouchDevice *device, handleTouchEvent(w, time, device, points, mods); } -QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, QEvent::Type *type) +QList<QTouchEvent::TouchPoint> + QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, + const QWindow *window, + QEvent::Type *type) { QList<QTouchEvent::TouchPoint> touchPoints; Qt::TouchPointStates states; @@ -465,16 +469,16 @@ QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints p.setState(point->state); const QPointF screenPos = point->area.center(); - p.setScreenPos(screenPos); - p.setScreenRect(point->area); + p.setScreenPos(QHighDpi::fromNativePixels(screenPos, window)); + p.setScreenRect(QHighDpi::fromNativePixels(point->area, window)); // The local pos and rect are not set, they will be calculated // when the event gets processed by QGuiApplication. - p.setNormalizedPos(point->normalPosition); - p.setVelocity(point->velocity); + p.setNormalizedPos(QHighDpi::fromNativePixels(point->normalPosition, window)); + p.setVelocity(QHighDpi::fromNativePixels(point->velocity, window)); p.setFlags(point->flags); - p.setRawScreenPositions(point->rawPositions); + p.setRawScreenPositions(QHighDpi::fromNativePixels(point->rawPositions, window)); touchPoints.append(p); ++point; @@ -492,6 +496,27 @@ QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints return touchPoints; } +QList<QWindowSystemInterface::TouchPoint> + QWindowSystemInterfacePrivate::toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList, + const QWindow *window) +{ + QList<QWindowSystemInterface::TouchPoint> newList; + newList.reserve(pointList.size()); + foreach (const QTouchEvent::TouchPoint &pt, pointList) { + QWindowSystemInterface::TouchPoint p; + p.id = pt.id(); + p.flags = pt.flags(); + p.normalPosition = QHighDpi::toNativeLocalPosition(pt.normalizedPos(), window); + p.area = QHighDpi::toNativePixels(pt.screenRect(), window); + p.pressure = pt.pressure(); + p.state = pt.state(); + p.velocity = pt.velocity(); + p.rawPositions = pt.rawScreenPositions(); + newList.append(p); + } + return newList; +} + void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTouchDevice *device, const QList<TouchPoint> &points, Qt::KeyboardModifiers mods) { @@ -502,7 +527,7 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTo return; QEvent::Type type; - QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type); + QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, tlw, &type); QWindowSystemInterfacePrivate::TouchEvent *e = new QWindowSystemInterfacePrivate::TouchEvent(tlw, timestamp, type, device, touchPoints, mods); @@ -535,14 +560,14 @@ void QWindowSystemInterface::handleScreenOrientationChange(QScreen *screen, Qt:: void QWindowSystemInterface::handleScreenGeometryChange(QScreen *screen, const QRect &geometry, const QRect &availableGeometry) { QWindowSystemInterfacePrivate::ScreenGeometryEvent *e = - new QWindowSystemInterfacePrivate::ScreenGeometryEvent(screen, geometry, availableGeometry); + new QWindowSystemInterfacePrivate::ScreenGeometryEvent(screen, QHighDpi::fromNativeScreenGeometry(geometry, screen), QHighDpi::fromNative(availableGeometry, screen, geometry.topLeft())); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal dpiX, qreal dpiY) { QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e = - new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, dpiX, dpiY); + new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, dpiX, dpiY); // ### tja QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -561,7 +586,7 @@ void QWindowSystemInterface::handleThemeChange(QWindow *tlw) void QWindowSystemInterface::handleExposeEvent(QWindow *tlw, const QRegion ®ion) { - QWindowSystemInterfacePrivate::ExposeEvent *e = new QWindowSystemInterfacePrivate::ExposeEvent(tlw, region); + QWindowSystemInterfacePrivate::ExposeEvent *e = new QWindowSystemInterfacePrivate::ExposeEvent(tlw, QHighDpi::fromNativeLocalRegion(region, tlw)); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -646,12 +671,12 @@ int QWindowSystemInterface::windowSystemEventsQueued() #ifndef QT_NO_DRAGANDDROP QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions) { - return QGuiApplicationPrivate::processDrag(w, dropData, p,supportedActions); + return QGuiApplicationPrivate::processDrag(w, dropData, QHighDpi::fromNativeLocalPosition(p, w) ,supportedActions); } QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions) { - return QGuiApplicationPrivate::processDrop(w, dropData, p,supportedActions); + return QGuiApplicationPrivate::processDrop(w, dropData, QHighDpi::fromNativeLocalPosition(p, w),supportedActions); } #endif // QT_NO_DRAGANDDROP @@ -685,8 +710,11 @@ void QWindowSystemInterface::handleTabletEvent(QWindow *w, ulong timestamp, cons Qt::KeyboardModifiers modifiers) { QWindowSystemInterfacePrivate::TabletEvent *e = - new QWindowSystemInterfacePrivate::TabletEvent(w, timestamp, local, global, device, pointerType, buttons, pressure, - xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers); + new QWindowSystemInterfacePrivate::TabletEvent(w,timestamp, + QHighDpi::fromNativeLocalPosition(local, w), + QHighDpi::fromNativePixels(global, w), + device, pointerType, buttons, pressure, + xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -838,7 +866,6 @@ Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int return QWindowSystemInterface::tryHandleShortcutEventToObject(o, timestamp, k, mods, text, autorep, count); } - Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *w, QTouchDevice *device, const QList<QTouchEvent::TouchPoint> &points, Qt::KeyboardModifiers mods = Qt::NoModifier) @@ -883,4 +910,5 @@ bool QWindowSystemEventHandler::sendEvent(QWindowSystemInterfacePrivate::WindowS return true; } + QT_END_NAMESPACE diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index 71609713050d35d200b950ab678aab3e3194ea0b..cbc3bad7cda7f0767d7b4c25949402f21c505614 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -488,7 +488,12 @@ public: static QWaitCondition eventsFlushed; static QMutex flushEventMutex; - static QList<QTouchEvent::TouchPoint> convertTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, QEvent::Type *type); + static QList<QTouchEvent::TouchPoint> + fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, + const QWindow *window, QEvent::Type *type = Q_NULLPTR); + static QList<QWindowSystemInterface::TouchPoint> + toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList, + const QWindow *window); static void installWindowSystemEventHandler(QWindowSystemEventHandler *handler); static void removeWindowSystemEventhandler(QWindowSystemEventHandler *handler); diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index 19074e4c47c4831a79d3256c67b2372e6254932c..4136c29d4e004f370003925027a1712723c45163 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -38,10 +38,13 @@ #include <qpa/qplatformintegration.h> #include <qscreen.h> #include <qdebug.h> +#include <qscopedpointer.h> #include <private/qguiapplication_p.h> #include <private/qwindow_p.h> +#include <private/qhighdpiscaling_p.h> + QT_BEGIN_NAMESPACE class QBackingStorePrivate @@ -54,6 +57,7 @@ public: QWindow *window; QPlatformBackingStore *platformBackingStore; + QScopedPointer<QImage> highDpiBackingstore; QRegion staticContents; QSize size; }; @@ -102,7 +106,7 @@ void QBackingStore::flush(const QRegion ®ion, QWindow *win, const QPoint &off } #endif - d_ptr->platformBackingStore->flush(win, region, offset); + d_ptr->platformBackingStore->flush(win, QHighDpi::toNativeLocalRegion(region, d_ptr->window), offset); } /*! @@ -112,7 +116,12 @@ void QBackingStore::flush(const QRegion ®ion, QWindow *win, const QPoint &off */ QPaintDevice *QBackingStore::paintDevice() { - return d_ptr->platformBackingStore->paintDevice(); + QPaintDevice *device = d_ptr->platformBackingStore->paintDevice(); + + if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) + return d_ptr->highDpiBackingstore.data(); + + return device; } /*! @@ -150,7 +159,36 @@ QWindow* QBackingStore::window() const void QBackingStore::beginPaint(const QRegion ®ion) { - d_ptr->platformBackingStore->beginPaint(region); + if (d_ptr->highDpiBackingstore && + d_ptr->highDpiBackingstore->devicePixelRatio() != d_ptr->window->devicePixelRatio()) + resize(size()); + + d_ptr->platformBackingStore->beginPaint(QHighDpi::toNativeLocalRegion(region, d_ptr->window)); + + // When QtGui is applying a high-dpi scale factor the backing store + // creates a "large" backing store image. This image needs to be + // painted on as a high-dpi image, which is done by setting + // devicePixelRatio. Do this on a separate image instance that shares + // the image data to avoid having the new devicePixelRatio be propagated + // back to the platform plugin. + QPaintDevice *device = d_ptr->platformBackingStore->paintDevice(); + if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) { + QImage *source = static_cast<QImage *>(device); + const bool needsNewImage = d_ptr->highDpiBackingstore.isNull() + || source->data_ptr() != d_ptr->highDpiBackingstore->data_ptr() + || source->size() != d_ptr->highDpiBackingstore->size() + || source->devicePixelRatio() != d_ptr->highDpiBackingstore->devicePixelRatio(); + if (needsNewImage) { + qCDebug(lcScaling) << "QBackingStore::beginPaint new backingstore for" << d_ptr->window; + qCDebug(lcScaling) << " source size" << source->size() << "dpr" << source->devicePixelRatio(); + d_ptr->highDpiBackingstore.reset( + new QImage(source->bits(), source->width(), source->height(), source->format())); + qreal targetDevicePixelRatio = d_ptr->window->devicePixelRatio(); + d_ptr->highDpiBackingstore->setDevicePixelRatio(targetDevicePixelRatio); + qCDebug(lcScaling) <<" destination size" << d_ptr->highDpiBackingstore->size() + << "dpr" << targetDevicePixelRatio; + } + } } /*! @@ -171,7 +209,7 @@ void QBackingStore::endPaint() void QBackingStore::resize(const QSize &size) { d_ptr->size = size; - d_ptr->platformBackingStore->resize(size, d_ptr->staticContents); + d_ptr->platformBackingStore->resize(QHighDpi::toNativePixels(size, d_ptr->window), d_ptr->staticContents); } /*! @@ -194,7 +232,7 @@ bool QBackingStore::scroll(const QRegion &area, int dx, int dy) Q_UNUSED(dx); Q_UNUSED(dy); - return d_ptr->platformBackingStore->scroll(area, dx, dy); + return d_ptr->platformBackingStore->scroll(QHighDpi::toNativeLocalRegion(area, d_ptr->window), QHighDpi::toNativePixels(dx, d_ptr->window), QHighDpi::toNativePixels(dy, d_ptr->window)); } void QBackingStore::setStaticContents(const QRegion ®ion) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 06c42ff0416ed09c461fb470e7ece3db744dc5a5..9195c1e5fa40a28af92028fcd855b840f115cab1 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -68,6 +68,7 @@ #include "private/qstylesheetstyle_p.h" #include "private/qstyle_p.h" #include "qfileinfo.h" +#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/qinputmethod.h> #include <QtGui/qopenglcontext.h> #include <QtGui/private/qopenglcontext_p.h> @@ -12774,7 +12775,7 @@ void QWidgetPrivate::setMask_sys(const QRegion ®ion) Q_Q(QWidget); if (const QWindow *window = q->windowHandle()) if (QPlatformWindow *platformWindow = window->handle()) - platformWindow->setMask(region); + platformWindow->setMask(QHighDpi::toNativeLocalRegion(region, window)); } /*! diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 01d6d8985729e37748e4b0474c91177249c9b823..633e7108530ff690eca7a234e9f8417a711f5554 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -45,6 +45,7 @@ #include <qpa/qplatformtheme.h> #include <qpa/qplatformwindow.h> #include <private/qgesturemanager_p.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -671,7 +672,7 @@ void QWidgetWindow::updateNormalGeometry() // Ask platform window, default to widget geometry. QRect normalGeometry; if (const QPlatformWindow *pw = handle()) - normalGeometry = pw->normalGeometry(); + normalGeometry = QHighDpi::fromNativePixels(pw->normalGeometry(), this); if (!normalGeometry.isValid() && effectiveState(m_widget->windowState()) == Qt::WindowNoState) normalGeometry = m_widget->geometry(); if (normalGeometry.isValid())