From b8f5ed0d5aa52c93e092fa4df7ca2f44df8f03e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Fri, 29 May 2020 09:18:09 +0200 Subject: QHighDpi: Add screenForPosition() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement support for using the screen at a given position when determining the scale factor and origin. Add QHighDpiScaling::screenForPosition(), which searches for a screen at the specified device independent or native coordinates. The function returns the QScreen or nullptr if no screen was found. Add QHighDpiScaling::Point, used for representing an invalid, device independent, or native point. Change-Id: I58e4e3eebb8cdd5171e59f97833a00e7f8d9ecd6 Reviewed-by: Tor Arne Vestbø Reviewed-by: Friedemann Kleint --- src/gui/kernel/qhighdpiscaling.cpp | 61 ++++++++++++++++++++++++++++++++------ src/gui/kernel/qhighdpiscaling_p.h | 42 +++++++++++++++++++------- 2 files changed, 84 insertions(+), 19 deletions(-) diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp index 53ecf8e0ad..6a47372b0b 100644 --- a/src/gui/kernel/qhighdpiscaling.cpp +++ b/src/gui/kernel/qhighdpiscaling.cpp @@ -649,34 +649,77 @@ QDpi QHighDpiScaling::logicalDpi(const QScreen *screen) return effectiveLogicalDpi(screen->handle(), scaleFactor, roundedScaleFactor); } -QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition) +// Returns the screen containing \a position, using \a guess as a starting point +// for the search. \a guess might be nullptr. Returns nullptr if \a position is outside +// of all screens. +QScreen *QHighDpiScaling::screenForPosition(QHighDpiScaling::Point position, QScreen *guess) { + if (position.kind == QHighDpiScaling::Point::Invalid) + return nullptr; + + auto getPlatformScreenGuess = [](QScreen *maybeScreen) -> QPlatformScreen * { + if (maybeScreen) + return maybeScreen->handle(); + if (QScreen *primary = QGuiApplication::primaryScreen()) + return primary->handle(); + return nullptr; + }; + + QPlatformScreen *platformGuess = getPlatformScreenGuess(guess); + if (!platformGuess) + return nullptr; + + auto onScreen = [](QHighDpiScaling::Point position, const QPlatformScreen *platformScreen) -> bool { + return position.kind == Point::Native + ? platformScreen->geometry().contains(position.point) + : platformScreen->screen()->geometry().contains(position.point); + }; + + // is the guessed screen correct? + if (onScreen(position, platformGuess)) + return platformGuess->screen(); + + // search sibling screens + const auto screens = platformGuess->virtualSiblings(); + for (const QPlatformScreen *screen : screens) { + if (onScreen(position, screen)) + return screen->screen(); + } + + return nullptr; +} + +QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QPlatformScreen *platformScreen, QHighDpiScaling::Point position) +{ + Q_UNUSED(position) 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() }; + return { m_factor * screenSubfactor(platformScreen), platformScreen->geometry().topLeft() }; } -QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QScreen *screen, QPoint *nativePosition) +QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QScreen *screen, QHighDpiScaling::Point position) { + Q_UNUSED(position) if (!m_active) return { qreal(1), QPoint() }; if (!screen) return { m_factor, QPoint() }; // the global factor - return scaleAndOrigin(screen->handle(), nativePosition); + return scaleAndOrigin(screen->handle(), position); } -QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QWindow *window, QPoint *nativePosition) +QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QWindow *window, QHighDpiScaling::Point position) { if (!m_active) return { qreal(1), QPoint() }; + // Determine correct screen; use the screen which contains the given + // position if a valid position is passed. QScreen *screen = window ? window->screen() : QGuiApplication::primaryScreen(); - const bool searchScreen = !window || window->isTopLevel(); - return scaleAndOrigin(screen, searchScreen ? nativePosition : nullptr); + QScreen *overrideScreen = QHighDpiScaling::screenForPosition(position, screen); + QScreen *targetScreen = overrideScreen ? overrideScreen : screen; + return scaleAndOrigin(targetScreen, position); } #else diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h index 86f74b26a9..92a9a6929d 100644 --- a/src/gui/kernel/qhighdpiscaling_p.h +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -96,18 +96,29 @@ public: static bool isActive() { return m_active; } + struct Point { + enum Kind { + Invalid, + DeviceIndependent, + Native + }; + Kind kind; + QPoint point; + }; + struct ScaleAndOrigin { qreal factor; QPoint origin; }; - static ScaleAndOrigin scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition = nullptr); - static ScaleAndOrigin scaleAndOrigin(const QScreen *screen, QPoint *nativePosition = nullptr); - static ScaleAndOrigin scaleAndOrigin(const QWindow *platformScreen, QPoint *nativePosition = nullptr); + + static ScaleAndOrigin scaleAndOrigin(const QPlatformScreen *platformScreen, Point position = Point{ Point::Invalid, QPoint() }); + static ScaleAndOrigin scaleAndOrigin(const QScreen *screen, Point position = Point{ Point::Invalid, QPoint() }); + static ScaleAndOrigin scaleAndOrigin(const QWindow *platformScreen, Point position = Point{ Point::Invalid, QPoint() }); template - static qreal factor(C *context, QPoint *nativePosition = nullptr) { - return scaleAndOrigin(context, nativePosition).factor; + static qreal factor(C *context) { + return scaleAndOrigin(context).factor; } static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen); @@ -121,6 +132,7 @@ private: static qreal roundScaleFactor(qreal rawFactor); static QDpi effectiveLogicalDpi(const QPlatformScreen *screen, qreal rawFactor, qreal roundedFactor); static qreal screenSubfactor(const QPlatformScreen *screen); + static QScreen *screenForPosition(Point position, QScreen *guess); static qreal m_factor; static bool m_active; @@ -209,11 +221,21 @@ inline QRegion scale(const QRegion ®ion, qreal scaleFactor, QPoint origin = Q } template -inline QPoint position(T) { return QPoint(); } -inline QPoint position(QPoint point) { return point; } -inline QPoint position(QPointF point) { return point.toPoint(); } -inline QPoint position(QRect rect) { return rect.center(); } -inline QPoint position(QRectF rect) { return rect.center().toPoint(); } +inline QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind) { + return QHighDpiScaling::Point{ QHighDpiScaling::Point::Invalid, QPoint() }; +} +inline QHighDpiScaling::Point position(QPoint point, QHighDpiScaling::Point::Kind kind) { + return QHighDpiScaling::Point{ kind, point }; +} +inline QHighDpiScaling::Point position(QPointF point, QHighDpiScaling::Point::Kind kind) { + return QHighDpiScaling::Point{ kind, point.toPoint() }; +} +inline QHighDpiScaling::Point position(QRect rect, QHighDpiScaling::Point::Kind kind) { + return QHighDpiScaling::Point{ kind, rect.topLeft() }; +} +inline QHighDpiScaling::Point position(QRectF rect, QHighDpiScaling::Point::Kind kind) { + return QHighDpiScaling::Point{ kind, rect.topLeft().toPoint() }; +} template T fromNativePixels(const T &value, const C *context) -- cgit v1.2.3