From cbf94402816bb0a20e7b1fa21b3ab7f524d65105 Mon Sep 17 00:00:00 2001 From: Saverio Miroddi Date: Fri, 21 Aug 2026 18:28:12 +0200 Subject: [PATCH] Prefer active X11 session display (#15933) * Prefer active X11 session display * Update linux.rs * fix(linux): keep the logind display only when it is a local one `get_display_from_session` returns the value pam_systemd was handed at session creation, and logind never updates it afterwards. That value is not always a usable local display: it can be qualified with this host (`myhost:0`), name an X forwarding endpoint (`localhost:10.0`), or be a bare `:`. Taking it unconditionally is worse than taking nothing, because a non-empty `self.display` suppresses every fallback below it, `get_display_by_user` and the `:0` default alike. The stripping at the end of `get_display_x11` does not save the last two cases either: it leaves `:` as is and turns `localhost:10.0` into a local looking `:10.0`, either of which is then exported as DISPLAY and leaves the session unreachable, where before this PR the host got a working `:0`. Strip this host so `myhost:0` is still accepted as `:0`, leave `localhost` in place, and require a display number after the colon. Anything else falls through to the existing chain. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01TKJxvTT6NQDEcnkWBx5bLA * docs(agents): prefer a little duplication over a restructure The "Be minimally invasive" rules already ask for purely additive diffs, but not in the case where the addition would otherwise reshape an existing function so the two can share code. Repeating a few lines is the better diff there. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01TKJxvTT6NQDEcnkWBx5bLA --------- Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) --- AGENTS.md | 1 + src/platform/linux.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 21e631f1d..fe8b73ec7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -71,6 +71,7 @@ * Prefer purely additive changes: layer new (`#[cfg]`-gated) blocks or new functions around existing code instead of restructuring it. The ideal diff for a fix adds lines and modifies/deletes none. * Do not extract or reshape existing code just to enable your new code; look for a mechanism that leaves existing lines untouched (e.g. hide/show an existing object instead of refactoring its construction into a helper for rebuilding). +* Accept a little duplication over a restructure. A new function that repeats a few lines of an existing one is a better diff than reshaping the original so both can share it. * Put new logic in self-contained functions in the module it belongs to (platform-specific logic in `src/platform/`, with `use` inside the function body to avoid churning shared import blocks). Call sites in shared files (`src/tray.rs`, `src/core_main.rs`, `src/server/connection.rs`, …) should be thin one-line hooks. ## Reviewing a PR diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 4fba6e669..f0979c2d1 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -2058,6 +2058,21 @@ mod desktop { sleep_millis(300); } + if self.display.is_empty() { + // logind stores the value pam_systemd was handed at session creation, which is not + // necessarily a local display: it can be qualified with this host (`myhost:0`) or + // name an X forwarding endpoint (`localhost:10.0`), and some setups record a bare + // `:`. Strip this host, then require a display number. `localhost` is deliberately + // left in place: a non-empty display here suppresses every fallback below, both + // `get_display_by_user` and the `:0` default, so anything not local must not pass. + let display = Self::get_display_from_session(&self.sid) + .replace(&hbb_common::whoami::hostname(), ""); + if display.strip_prefix(':').map_or(false, |number| { + number.starts_with(|c: char| c.is_ascii_digit()) + }) { + self.display = display; + } + } if self.display.is_empty() { self.display = Self::get_display_by_user(&self.username); } @@ -2070,6 +2085,34 @@ mod desktop { .replace("localhost", ""); } + fn get_display_from_session(session: &str) -> String { + if session.is_empty() { + return String::new(); + } + + match Command::new(CMD_LOGINCTL.as_str()) + .args(["show-session", "-p", "Display", session]) + .output() + { + Ok(output) if output.status.success() => String::from_utf8_lossy(&output.stdout) + .trim() + .strip_prefix("Display=") + .unwrap_or_default() + .to_owned(), + Ok(output) => { + log::debug!( + "Failed to get display for session {session}: {}", + output.status + ); + String::new() + } + Err(err) => { + log::debug!("Failed to get display for session {session}: {err}"); + String::new() + } + } + } + fn get_home(&mut self) { self.home = "".to_string();