diff options
Diffstat (limited to 'src/gui/kernel/qscreen.cpp')
-rw-r--r-- | src/gui/kernel/qscreen.cpp | 252 |
1 files changed, 122 insertions, 130 deletions
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index e6f408875e..83641e7676 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qscreen.h" #include "qscreen_p.h" @@ -73,100 +37,42 @@ QT_BEGIN_NAMESPACE \inmodule QtGui */ -QScreen::QScreen(QPlatformScreen *screen) +QScreen::QScreen(QPlatformScreen *platformScreen) : QObject(*new QScreenPrivate(), nullptr) { Q_D(QScreen); - d->setPlatformScreen(screen); -} - -void QScreenPrivate::updateGeometriesWithSignals() -{ - const QRect oldGeometry = geometry; - const QRect oldAvailableGeometry = availableGeometry; - updateHighDpi(); - emitGeometryChangeSignals(oldGeometry != geometry, oldAvailableGeometry != availableGeometry); -} - -void QScreenPrivate::emitGeometryChangeSignals(bool geometryChanged, bool availableGeometryChanged) -{ - Q_Q(QScreen); - if (geometryChanged) - emit q->geometryChanged(geometry); - if (availableGeometryChanged) - emit q->availableGeometryChanged(availableGeometry); + d->platformScreen = platformScreen; + platformScreen->d_func()->screen = this; - if (geometryChanged || availableGeometryChanged) { - const auto siblings = q->virtualSiblings(); - for (QScreen* sibling : siblings) - emit sibling->virtualGeometryChanged(sibling->virtualGeometry()); - } + d->orientation = platformScreen->orientation(); + d->logicalDpi = QPlatformScreen::overrideDpi(platformScreen->logicalDpi()); + d->refreshRate = platformScreen->refreshRate(); + // safeguard ourselves against buggy platform behavior... + if (d->refreshRate < 1.0) + d->refreshRate = 60.0; - if (geometryChanged) - emit q->physicalDotsPerInchChanged(q->physicalDotsPerInch()); + d->updateGeometry(); + d->updatePrimaryOrientation(); // derived from the geometry } -void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen) +void QScreenPrivate::updateGeometry() { - Q_Q(QScreen); - platformScreen = screen; - platformScreen->d_func()->screen = q; - orientation = platformScreen->orientation(); - - logicalDpi = QPlatformScreen::overrideDpi(platformScreen->logicalDpi()); - - refreshRate = platformScreen->refreshRate(); - // safeguard ourselves against buggy platform behavior... - if (refreshRate < 1.0) - refreshRate = 60.0; - - updateHighDpi(); - updatePrimaryOrientation(); // derived from the geometry + qreal scaleFactor = QHighDpiScaling::factor(platformScreen); + QRect nativeGeometry = platformScreen->geometry(); + geometry = QRect(nativeGeometry.topLeft(), QHighDpi::fromNative(nativeGeometry.size(), scaleFactor)); + availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), scaleFactor, geometry.topLeft()); } - /*! Destroys the screen. + + \internal */ QScreen::~QScreen() { - // Remove screen - const bool wasPrimary = QGuiApplication::primaryScreen() == this; - QGuiApplicationPrivate::screen_list.removeOne(this); - QGuiApplicationPrivate::resetCachedDevicePixelRatio(); - - if (!qGuiApp) - return; - - QScreen *newPrimaryScreen = QGuiApplication::primaryScreen(); - if (wasPrimary && newPrimaryScreen) - emit qGuiApp->primaryScreenChanged(newPrimaryScreen); - - // Allow clients to manage windows that are affected by the screen going - // away, before we fall back to moving them to the primary screen. - emit qApp->screenRemoved(this); - - if (QGuiApplication::closingDown()) - return; - - bool movingFromVirtualSibling = newPrimaryScreen - && newPrimaryScreen->handle()->virtualSiblings().contains(handle()); - - // Move any leftover windows to the primary screen - const auto allWindows = QGuiApplication::allWindows(); - for (QWindow *window : allWindows) { - if (!window->isTopLevel() || window->screen() != this) - continue; - - const bool wasVisible = window->isVisible(); - window->setScreen(newPrimaryScreen); - - // Re-show window if moved from a virtual sibling screen. Otherwise - // leave it up to the application developer to show the window. - if (movingFromVirtualSibling) - window->setVisible(wasVisible); - } + Q_ASSERT_X(!QGuiApplicationPrivate::screen_list.contains(this), "QScreen", + "QScreens should be removed via QWindowSystemInterface::handleScreenRemoved()"); } /*! @@ -186,6 +92,10 @@ QPlatformScreen *QScreen::handle() const For example, on X11 these correspond to the XRandr screen names, typically "VGA1", "HDMI1", etc. + + \note The user presentable string is not guaranteed to match the + result of any native APIs, and should not be used to uniquely identify + a screen. */ QString QScreen::name() const { @@ -449,9 +359,12 @@ QList<QScreen *> QScreen::virtualSiblings() const Q_D(const QScreen); const QList<QPlatformScreen *> platformScreens = d->platformScreen->virtualSiblings(); QList<QScreen *> screens; - screens.reserve(platformScreens.count()); - for (QPlatformScreen *platformScreen : platformScreens) - screens << platformScreen->screen(); + screens.reserve(platformScreens.size()); + for (QPlatformScreen *platformScreen : platformScreens) { + // Only consider platform screens that have been added + if (auto *knownScreen = platformScreen->screen()) + screens << knownScreen; + } return screens; } @@ -547,6 +460,11 @@ Qt::ScreenOrientation QScreen::orientation() const /*! \property QScreen::refreshRate \brief the approximate vertical refresh rate of the screen in Hz + + \warning Avoid using the screen's refresh rate to drive animations via a + timer such as QChronoTimer. Instead use QWindow::requestUpdate(). + + \sa QWindow::requestUpdate() */ qreal QScreen::refreshRate() const { @@ -785,8 +703,23 @@ QPixmap QScreen::grabWindow(WId window, int x, int y, int width, int height) result.setDevicePixelRatio(result.devicePixelRatio() * factor); return result; } + +/*! + \fn template <typename QNativeInterface> QNativeInterface *QScreen::nativeInterface() const + + Returns a native interface of the given type for the screen. + + This function provides access to platform specific functionality + of QScreen, as defined in the QNativeInterface namespace: + + \annotatedlist native-interfaces-qscreen + + If the requested interface is not available a \nullptr is returned. + */ + void *QScreen::resolveInterface(const char *name, int revision) const { + using namespace QNativeInterface; using namespace QNativeInterface::Private; auto *platformScreen = handle(); @@ -806,17 +739,22 @@ void *QScreen::resolveInterface(const char *name, int revision) const QT_NATIVE_INTERFACE_RETURN_IF(QWebOSScreen, platformScreen); #endif - return nullptr; -} +#if defined(Q_OS_WIN32) + QT_NATIVE_INTERFACE_RETURN_IF(QWindowsScreen, platformScreen); +#endif -#ifndef QT_NO_DEBUG_STREAM +#if defined(Q_OS_ANDROID) + QT_NATIVE_INTERFACE_RETURN_IF(QAndroidScreen, platformScreen); +#endif -static inline void formatRect(QDebug &debug, const QRect r) -{ - debug << r.width() << 'x' << r.height() - << Qt::forcesign << r.x() << r.y() << Qt::noforcesign; +#if QT_CONFIG(wayland) + QT_NATIVE_INTERFACE_RETURN_IF(QWaylandScreen, platformScreen); +#endif + + return nullptr; } +#ifndef QT_NO_DEBUG_STREAM Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QScreen *screen) { const QDebugStateSaver saver(debug); @@ -827,10 +765,8 @@ Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QScreen *screen) if (debug.verbosity() > 2) { if (screen == QGuiApplication::primaryScreen()) debug << ", primary"; - debug << ", geometry="; - formatRect(debug, screen->geometry()); - debug << ", available="; - formatRect(debug, screen->availableGeometry()); + debug << ", geometry=" << screen->geometry(); + debug << ", available=" << screen->availableGeometry(); debug << ", logical DPI=" << screen->logicalDotsPerInchX() << ',' << screen->logicalDotsPerInchY() << ", physical DPI=" << screen->physicalDotsPerInchX() @@ -846,4 +782,60 @@ Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QScreen *screen) } #endif // !QT_NO_DEBUG_STREAM +QScreenPrivate::UpdateEmitter::UpdateEmitter(QScreen *screen) +{ + initialState.platformScreen = screen->handle(); + + // Use public APIs to read out current state, rather + // than accessing the QScreenPrivate members, so that + // we detect any changes to the high-DPI scale factors + // that may be applied in the getters. + + initialState.logicalDpi = QDpi{ + screen->logicalDotsPerInchX(), + screen->logicalDotsPerInchY() + }; + initialState.geometry = screen->geometry(); + initialState.availableGeometry = screen->availableGeometry(); + initialState.primaryOrientation = screen->primaryOrientation(); +} + +QScreenPrivate::UpdateEmitter::~UpdateEmitter() +{ + QScreen *screen = initialState.platformScreen->screen(); + + const auto logicalDotsPerInch = QDpi{ + screen->logicalDotsPerInchX(), + screen->logicalDotsPerInchY() + }; + if (logicalDotsPerInch != initialState.logicalDpi) + emit screen->logicalDotsPerInchChanged(screen->logicalDotsPerInch()); + + const auto geometry = screen->geometry(); + const auto geometryChanged = geometry != initialState.geometry; + if (geometryChanged) + emit screen->geometryChanged(geometry); + + const auto availableGeometry = screen->availableGeometry(); + const auto availableGeometryChanged = availableGeometry != initialState.availableGeometry; + if (availableGeometryChanged) + emit screen->availableGeometryChanged(availableGeometry); + + if (geometryChanged || availableGeometryChanged) { + const auto siblings = screen->virtualSiblings(); + for (QScreen* sibling : siblings) + emit sibling->virtualGeometryChanged(sibling->virtualGeometry()); + } + + if (geometryChanged) { + emit screen->physicalDotsPerInchChanged(screen->physicalDotsPerInch()); + + const auto primaryOrientation = screen->primaryOrientation(); + if (primaryOrientation != initialState.primaryOrientation) + emit screen->primaryOrientationChanged(primaryOrientation); + } +} + QT_END_NAMESPACE + +#include "moc_qscreen.cpp" |