Commit 6f2ef923 authored by Lindsay Roberts's avatar Lindsay Roberts

Fix view geometry updates when screens added/removed

Screen geometry changed events could end up connected to the wrong
views, or not at all. This could cause greeters not to be visible (and
as such desktop contents visible), greeters at the wrong size or
position and/or overlapped.

We map Qt screens() by index to our own list of m_views, but Qt is free
to reorder screens, and when screens are removed, what used to be e.g.
index 0 could be removed, leading to connect() pointer to pointer
mappings being incorrect. Since we also set geometry on add/remove this
can lead to us changing to the correct geometry then back to geometry
that is not covered by active screen, essentially making the greeter
invisible, and no valid greeter visible.

Since there is no uniqueness constraint for lambda connections, we can
also end up with multiple screens updating different geometries on the
same view, or repeated signals from the same screen.

Fix this by only connecting screens once, and having the receiving
lambda resolve the index to index mapping so connections are persistant
with the life of the screen.

BUG: 347934
parent 59601361
......@@ -123,7 +123,7 @@ UnlockApp::UnlockApp(int &argc, char **argv)
// It's a queued connection to give the QML part time to eventually execute code connected to Authenticator::succeeded if any
connect(m_authenticator, &Authenticator::succeeded, this, &QCoreApplication::quit, Qt::QueuedConnection);
initialize();
connect(this, &UnlockApp::screenAdded, this, &UnlockApp::desktopResized);
connect(this, &UnlockApp::screenAdded, this, &UnlockApp::onScreenAdded);
connect(this, &UnlockApp::screenRemoved, this, &UnlockApp::desktopResized);
if (QX11Info::isPlatformX11()) {
......@@ -275,6 +275,44 @@ void UnlockApp::loadWallpaperPlugin(KQuickAddons::QuickViewSharedEngine *view)
);
}
void UnlockApp::onScreenAdded(QScreen *screen)
{
// Lambda connections can not have uniqueness constraints, ensure
// geometry change signals are only connected once
connect(screen, &QScreen::geometryChanged, this, [this, screen] (const QRect& geo) { screenGeometryChanged(screen, geo); });
desktopResized();
}
void UnlockApp::screenGeometryChanged(QScreen *screen, const QRect &geo)
{
// We map screens() to m_views by index and Qt is free to
// reorder screens, so pointer to pointer connections
// may not remain matched by index, perform index
// mapping in the change event itself
const int screenIndex = QGuiApplication::screens().indexOf(screen);
if (screenIndex < 0) {
qCWarning(KSCREENLOCKER_GREET) << "Screen not found, not updating geometry" << screen;
return;
}
if (screenIndex >= m_views.size()) {
qCWarning(KSCREENLOCKER_GREET) << "Screen index out of range, not updating geometry" << screenIndex;
return;
}
KQuickAddons::QuickViewSharedEngine* view = m_views[screenIndex];
view->setGeometry(geo);
KWayland::Client::PlasmaShellSurface *plasmaSurface = view->property("plasmaShellSurface").value<KWayland::Client::PlasmaShellSurface *>();
if (plasmaSurface) {
plasmaSurface->setPosition(view->geometry().topLeft());
}
}
void UnlockApp::initialViewSetup()
{
for (QScreen *screen : screens())
connect(screen, &QScreen::geometryChanged, this, [this, screen] (const QRect& geo) { screenGeometryChanged(screen, geo); });
desktopResized();
}
void UnlockApp::desktopResized()
{
const int nScreens = screens().count();
......@@ -388,16 +426,6 @@ void UnlockApp::desktopResized()
});
}
connect(screen,
&QScreen::geometryChanged,
view,
[view, plasmaSurface](const QRect &geo) {
view->setGeometry(geo);
if (plasmaSurface) {
plasmaSurface->setPosition(view->geometry().topLeft());
}
}
);
// on Wayland we may not use fullscreen as that puts all windows on one screen
if (m_testing || plasmaSurface || QX11Info::isPlatformX11()) {
......
......@@ -52,6 +52,8 @@ public:
explicit UnlockApp(int &argc, char **argv);
~UnlockApp() override;
void initialViewSetup();
void setTesting(bool enable);
void setTheme(const QString &theme);
void setImmediateLock(bool immediateLock);
......@@ -68,6 +70,7 @@ public:
public Q_SLOTS:
void desktopResized();
void onScreenAdded(QScreen *screen);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
......@@ -85,6 +88,7 @@ private:
void initializeWayland();
void shareEvent(QEvent *e, KQuickAddons::QuickViewSharedEngine *from);
void loadWallpaperPlugin(KQuickAddons::QuickViewSharedEngine *view);
void screenGeometryChanged(QScreen *screen, const QRect &geo);
Authenticator *createAuthenticator();
QWindow *getActiveScreen();
......
......@@ -181,7 +181,7 @@ int main(int argc, char* argv[])
}
}
app.desktopResized();
app.initialViewSetup();
// This allow ksmserver to know when the application has actually finished setting itself up.
// Crucial for blocking until it is ready, ensuring locking happens before sleep, e.g.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment