Align QWindowSystemInterface::handleScreenAdded() and handleScreenRemoved()

Having the logic of handleScreenRemoved() inside the QScreen destructor
was making it harder to follow the flow of adding and removing screens.

As screen management should always go though the QWSI functions, we keep
the logic there.

Change-Id: I456e77eb8fc10feae7b1f9994b25c9534ea4e430
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Tor Arne Vestbø 2022-09-09 16:41:49 +02:00
parent 2187936978
commit 3a2277cb63
3 changed files with 47 additions and 45 deletions

View File

@ -25,10 +25,8 @@ QPlatformScreen::QPlatformScreen()
QPlatformScreen::~QPlatformScreen()
{
Q_D(QPlatformScreen);
if (d->screen) {
qWarning("Manually deleting a QPlatformScreen. Call QWindowSystemInterface::handleScreenRemoved instead.");
delete d->screen;
}
Q_ASSERT_X(!d->screen, "QPlatformScreen",
"QPlatformScreens should be removed via QWindowSystemInterface::handleScreenRemoved()");
}
/*!

View File

@ -66,45 +66,13 @@ void QScreenPrivate::updateGeometry()
/*!
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()");
}
/*!

View File

@ -738,9 +738,9 @@ QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchCancelEvent, QWindow *window, ulong
The screen should be deleted by calling QWindowSystemInterface::handleScreenRemoved().
*/
void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *ps, bool isPrimary)
void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *platformScreen, bool isPrimary)
{
QScreen *screen = new QScreen(ps);
QScreen *screen = new QScreen(platformScreen);
if (isPrimary)
QGuiApplicationPrivate::screen_list.prepend(screen);
@ -767,9 +767,45 @@ void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *ps, bool isPrima
*/
void QWindowSystemInterface::handleScreenRemoved(QPlatformScreen *platformScreen)
{
// Important to keep this order since the QSceen doesn't own the platform screen.
// The QScreen destructor will take care changing the primary screen, so no need here.
delete platformScreen->screen();
QScreen *screen = platformScreen->screen();
// Remove screen
const bool wasPrimary = QGuiApplication::primaryScreen() == screen;
QGuiApplicationPrivate::screen_list.removeOne(screen);
QGuiApplicationPrivate::resetCachedDevicePixelRatio();
if (qGuiApp) {
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(screen);
if (!QGuiApplication::closingDown()) {
bool movingFromVirtualSibling = newPrimaryScreen
&& newPrimaryScreen->handle()->virtualSiblings().contains(platformScreen);
// Move any leftover windows to the primary screen
const auto allWindows = QGuiApplication::allWindows();
for (QWindow *window : allWindows) {
if (!window->isTopLevel() || window->screen() != screen)
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);
}
}
}
// Important to keep this order since the QSceen doesn't own the platform screen
delete screen;
delete platformScreen;
}