[plasma/xdg-desktop-portal-kde/Plasma/6.6] src: session: release all sessions when the portal frontend disappears

David Redondo <[email protected]> Tue, 4 Aug 2026 14:25:26 +0000 (UTC)
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 867386a6e43d9b63fd23fca27d6f3f0b43a740b9 by David Redondo.
Committed on 04/08/2026 at 14:22.
Pushed by davidre into branch 'Plasma/6.6'.

session: release all sessions when the portal frontend disappears

Every session in this backend is created on behalf of the single portal
frontend (org.freedesktop.portal.Desktop). If it drops off the bus without
cleanly closing its sessions - for example if it crashes - nothing tears them
down. For an InputCapture session that means KWin keeps diverting all pointer
and keyboard input into the now ownerless EIS channel, so the desktop renders
normally but accepts no input until KWin is killed.

Watch the frontend centrally and close every session if it disappears, which
drives the existing Session::closed teardown for each. This covers all session
types rather than only input capture.

BUG: 523515


(cherry picked from commit e0cf8bf311a7baad8933797ec2fca0b94eb7d3d5)

Co-authored-by: Marcus Renheim <[email protected]>

(cherry picked from commit b4d3f6cd01edd5302030f2b8292ed82315069f27)

Co-authored-by: David Redondo <[email protected]>

M  +10   -0    src/desktopportal.cpp
M  +2    -0    src/desktopportal.h
M  +13   -0    src/session.cpp
M  +1    -0    src/session.h

https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/commit/867386a6e43d9b63fd23fca27d6f3f0b43a740b9

diff --git a/src/desktopportal.cpp b/src/desktopportal.cpp
index 24667ff6..b99f6223 100644
--- a/src/desktopportal.cpp
+++ b/src/desktopportal.cpp
@@ -8,6 +8,10 @@
 
 #include "desktopportal.h"
 #include "desktopportal_debug.h"
+#include "session.h"
+
+#include <QDBusConnection>
+#include <QDBusServiceWatcher>
 
 #include "access.h"
 #include "account.h"
@@ -42,6 +46,7 @@ DesktopPortal::DesktopPortal(QObject *parent)
     , m_print(new PrintPortal(this))
     , m_settings(new SettingsPortal(this))
     , m_dynamicLauncher(new DynamicLauncherPortal(this))
+    , m_frontendWatcher(QStringLiteral("org.freedesktop.portal.Desktop"), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration)
 {
     const QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP");
     if (xdgCurrentDesktop.compare("KDE", Qt::CaseInsensitive) == 0) {
@@ -57,6 +62,11 @@ DesktopPortal::DesktopPortal(QObject *parent)
         WaylandIntegration::init();
     }
     new UsbPortal(this);
+
+    // Fail-safe: close all sessions if the portal frontend disappears without closing them.
+    connect(&m_frontendWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [] {
+        Session::closeAll();
+    });
 }
 
 #include "moc_desktopportal.cpp"
diff --git a/src/desktopportal.h b/src/desktopportal.h
index cf3a7e3d..55ca4be6 100644
--- a/src/desktopportal.h
+++ b/src/desktopportal.h
@@ -10,6 +10,7 @@
 #define XDG_DESKTOP_PORTAL_KDE_DESKTOP_PORTAL_H
 
 #include <QDBusContext>
+#include <QDBusServiceWatcher>
 #include <QObject>
 
 class AccessPortal;
@@ -48,6 +49,7 @@ private:
     ScreenCastPortal *m_screenCast = nullptr;
     RemoteDesktopPortal *m_remoteDesktop = nullptr;
     DynamicLauncherPortal *const m_dynamicLauncher;
+    QDBusServiceWatcher m_frontendWatcher;
 };
 
 #endif // XDG_DESKTOP_PORTAL_KDE_DESKTOP_PORTAL_H
diff --git a/src/session.cpp b/src/session.cpp
index ae3aab43..ca56418b 100644
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -68,6 +68,19 @@ Session *Session::getSession(const QString &sessionHandle)
     return sessionList.value(sessionHandle);
 }
 
+void Session::closeAll()
+{
+    // Iterate over a copy: close() removes the session from sessionList.
+    const auto sessions = sessionList.values();
+    if (sessions.isEmpty()) {
+        return;
+    }
+    qCInfo(XdgSessionKdeSession) << "Closing" << sessions.count() << "session(s) after the portal frontend disappeared";
+    for (Session *session : sessions) {
+        session->close();
+    }
+}
+
 void Session::Close()
 {
     close();
diff --git a/src/session.h b/src/session.h
index 3446f387..5a19b136 100644
--- a/src/session.h
+++ b/src/session.h
@@ -39,6 +39,7 @@ public:
     virtual SessionType type() const = 0;
 
     static Session *getSession(const QString &sessionHandle);
+    static void closeAll();
     template<typename T>
     static T *getSession(const QString &sessionHandle)
     {