shell: resolve logind session via User.Display, re-register after sessiond restart
SessionEvents asked loginctl for -p ObjectPath, which is not a property — it returned empty on every boot, so external lock signals were never monitored and the shell had no unlock ingress. Resolve the graphical session the way lockhint.rs does; not GetSession(auto) (this shell is a session-less user unit) and not the /session/auto alias (PropertiesChanged only fires on the concrete path). SessiondBridge read root.registered to decide whether to re-register on reconnect, but the disconnect branch had already cleared it, so the shell never re-registered after a sessiond restart. Latch it.
This commit is contained in:
parent
45fc69b56a
commit
4ed8f3dd74
2 changed files with 33 additions and 22 deletions
|
|
@ -76,38 +76,43 @@ Singleton {
|
|||
signal sleepInhibitorAcquired()
|
||||
|
||||
// --- Session path resolution -------------------------------------------
|
||||
// The logind session D-Bus object path contains the session ID with dots
|
||||
// replaced by underscores (session "3" -> /org/freedesktop/login1/session/_3,
|
||||
// session "c1" -> /org/freedesktop/login1/session/_c1). We resolve it once
|
||||
// at startup by asking logind for the current session's object path.
|
||||
// Resolve the graphical session's REAL object path via the user's `Display`
|
||||
// session. sessiond resolves exactly this way; see the two measured traps
|
||||
// documented on `resolve_session_path` in src/sessiond/lockhint.rs:
|
||||
//
|
||||
// Not `auto`. `GetSession("auto")` resolves to the CALLER's session, and
|
||||
// this shell is a systemd user unit under user@1000.service, outside any
|
||||
// session scope — it has no session of its own to name.
|
||||
//
|
||||
// Not the `auto` path either. /org/freedesktop/login1/session/auto is an
|
||||
// alias, not an object: PropertiesChanged only fires on the concrete
|
||||
// path, so monitoring the alias subscribes to something never delivered.
|
||||
//
|
||||
// The user's `Display` session is the graphical one by definition, whoever
|
||||
// asks. The previous probe here asked for a `-p ObjectPath` property that
|
||||
// loginctl does not have, so it returned empty on every boot and external
|
||||
// lock signals were never monitored at all.
|
||||
Process {
|
||||
id: sessionResolver
|
||||
running: true
|
||||
command: ["sh", "-c",
|
||||
// loginctl list-sessions -p Name gives the first session's user;
|
||||
// show-session with no argument operates on the caller's session.
|
||||
// -p ObjectPath gives the D-Bus path directly, no encoding needed.
|
||||
"loginctl show-session -p ObjectPath 2>/dev/null | head -1"]
|
||||
"busctl --system get-property org.freedesktop.login1 "
|
||||
+ "/org/freedesktop/login1/user/_$(id -u) "
|
||||
+ "org.freedesktop.login1.User Display 2>/dev/null"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const raw = text.trim();
|
||||
// loginctl outputs ObjectPath=/org/freedesktop/login1/session/_3
|
||||
const match = raw.match(/^ObjectPath=(.+)$/);
|
||||
if (match && match[1].length > 0) {
|
||||
root.sessionPath = match[1];
|
||||
// `(so) "1" "/org/freedesktop/login1/session/_31"` — the object
|
||||
// path is the second quoted field.
|
||||
const path = raw.split('"')[3];
|
||||
if (path && path.startsWith("/org/freedesktop/login1/session/")) {
|
||||
root.sessionPath = path;
|
||||
console.log("[session-events] session path:", root.sessionPath);
|
||||
sessionLockMonitor.running = true;
|
||||
} else if (raw.length > 0) {
|
||||
// Some logind versions print just the path without the key.
|
||||
if (raw.startsWith("/org/freedesktop/login1/session/")) {
|
||||
root.sessionPath = raw;
|
||||
console.log("[session-events] session path (bare):", root.sessionPath);
|
||||
sessionLockMonitor.running = true;
|
||||
console.log("[session-events] could not parse Display session from:", raw);
|
||||
} else {
|
||||
console.log("[session-events] could not parse session path from:", raw);
|
||||
}
|
||||
} else {
|
||||
console.log("[session-events] no session path returned; "
|
||||
console.log("[session-events] no Display session for this user; "
|
||||
+ "external lock signals will not be monitored");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ Singleton {
|
|||
|
||||
// Registered = shell_ready was answered ok on the CURRENT connection.
|
||||
property bool registered: false
|
||||
// Latched copy of `registered` taken when the connection drops. The
|
||||
// disconnect branch clears `registered` before the reconnect branch runs,
|
||||
// so reconnect cannot read it directly to decide whether to re-register.
|
||||
property bool wasRegistered: false
|
||||
// sessiond held the session lock when we registered; we owe it a lock
|
||||
// and a locked_ack.
|
||||
property bool oweLock: false
|
||||
|
|
@ -112,8 +116,9 @@ Singleton {
|
|||
onConnectionStateChanged: {
|
||||
if (sock.connected) {
|
||||
console.log("[sessiond-bridge] connected");
|
||||
const wasRegistered = root.registered;
|
||||
const wasRegistered = root.wasRegistered;
|
||||
root.registered = false;
|
||||
root.wasRegistered = false;
|
||||
root.ackSent = false;
|
||||
if (wasRegistered) {
|
||||
root.shellReady(function(mustLock) {
|
||||
|
|
@ -126,6 +131,7 @@ Singleton {
|
|||
}
|
||||
} else {
|
||||
console.log("[sessiond-bridge] disconnected");
|
||||
root.wasRegistered = root.registered;
|
||||
root.registered = false;
|
||||
root.pendingReady = null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue