diff options
Diffstat (limited to 'src/gui/kernel/qscreen.cpp')
-rw-r--r-- | src/gui/kernel/qscreen.cpp | 188 |
1 files changed, 109 insertions, 79 deletions
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index ac33185900..83641e7676 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -37,100 +37,42 @@ QT_BEGIN_NAMESPACE \inmodule QtGui */ -QScreen::QScreen(QPlatformScreen *screen) +QScreen::QScreen(QPlatformScreen *platformScreen) : QObject(*new QScreenPrivate(), nullptr) { Q_D(QScreen); - d->platformScreen = screen; - d->platformScreen->d_func()->screen = this; - d->orientation = d->platformScreen->orientation(); - d->logicalDpi = QPlatformScreen::overrideDpi(d->platformScreen->logicalDpi()); + d->platformScreen = platformScreen; + platformScreen->d_func()->screen = this; - d->refreshRate = d->platformScreen->refreshRate(); + 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; - d->updateHighDpi(); + d->updateGeometry(); d->updatePrimaryOrientation(); // derived from the geometry } -void QScreenPrivate::updateLogicalDpi() +void QScreenPrivate::updateGeometry() { - Q_Q(QScreen); - logicalDpi = QPlatformScreen::overrideDpi(q->handle()->logicalDpi()); - updateGeometriesWithSignals(); // updates geometries based on scale factor -} - -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); - - if (geometryChanged || availableGeometryChanged) { - const auto siblings = q->virtualSiblings(); - for (QScreen* sibling : siblings) - emit sibling->virtualGeometryChanged(sibling->virtualGeometry()); - } - - if (geometryChanged) - emit q->physicalDotsPerInchChanged(q->physicalDotsPerInch()); + 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()"); } /*! @@ -150,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 { @@ -413,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; } @@ -512,8 +461,8 @@ 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 QTimer. Instead use QWindow::requestUpdate(). + \warning Avoid using the screen's refresh rate to drive animations via a + timer such as QChronoTimer. Instead use QWindow::requestUpdate(). \sa QWindow::requestUpdate() */ @@ -754,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(); @@ -775,6 +739,18 @@ void *QScreen::resolveInterface(const char *name, int revision) const QT_NATIVE_INTERFACE_RETURN_IF(QWebOSScreen, platformScreen); #endif +#if defined(Q_OS_WIN32) + QT_NATIVE_INTERFACE_RETURN_IF(QWindowsScreen, platformScreen); +#endif + +#if defined(Q_OS_ANDROID) + QT_NATIVE_INTERFACE_RETURN_IF(QAndroidScreen, platformScreen); +#endif + +#if QT_CONFIG(wayland) + QT_NATIVE_INTERFACE_RETURN_IF(QWaylandScreen, platformScreen); +#endif + return nullptr; } @@ -806,6 +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" |