summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qscreen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qscreen.cpp')
-rw-r--r--src/gui/kernel/qscreen.cpp192
1 files changed, 109 insertions, 83 deletions
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index 1e5db5c4d3..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->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()");
}
/*!
@@ -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();
@@ -779,6 +743,14 @@ void *QScreen::resolveInterface(const char *name, int revision) const
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;
}
@@ -810,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"