From 475bef63d7114955ec6c707d0a33663c630dae58 Mon Sep 17 00:00:00 2001 From: fufesou <13586388+fufesou@users.noreply.github.com> Date: Thu, 17 Jul 2025 08:46:32 +0800 Subject: [PATCH] fix: linux, env TERM (#12325) Signed-off-by: fufesou --- Cargo.lock | 81 ++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 1 + src/platform/linux.rs | 82 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 156 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aabff852e..a5eee545e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1790,6 +1790,15 @@ dependencies = [ "dirs-sys 0.3.7", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys 0.3.7", +] + [[package]] name = "dirs" version = "5.0.1" @@ -5090,7 +5099,16 @@ version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" dependencies = [ - "phf_shared", + "phf_shared 0.7.24", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared 0.11.3", ] [[package]] @@ -5099,8 +5117,18 @@ version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.7.24", + "phf_shared 0.7.24", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", ] [[package]] @@ -5109,17 +5137,36 @@ version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" dependencies = [ - "phf_shared", + "phf_shared 0.7.24", "rand 0.6.5", ] +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.5", +] + [[package]] name = "phf_shared" version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" dependencies = [ - "siphasher", + "siphasher 0.2.3", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.1", ] [[package]] @@ -6146,6 +6193,7 @@ dependencies = [ "system_shutdown", "tao", "tauri-winrt-notification", + "terminfo", "termios 0.3.3", "totp-rs", "tray-icon", @@ -6674,6 +6722,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -7033,8 +7087,8 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "013d134ae4a25ee744ad6129db589018558f620ddfa44043887cdd45fa08e75c" dependencies = [ - "phf", - "phf_codegen", + "phf 0.7.24", + "phf_codegen 0.7.24", "serde_json 0.9.10", ] @@ -7069,6 +7123,19 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminfo" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666cd3a6681775d22b200409aad3b089c5b99fb11ecdd8a204d9d62f8148498f" +dependencies = [ + "dirs 4.0.0", + "fnv", + "nom", + "phf 0.11.3", + "phf_codegen 0.11.3", +] + [[package]] name = "termios" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index da8c3bff0..7eb796d86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -180,6 +180,7 @@ once_cell = {version = "1.18", optional = true} nix = { version = "0.29", features = ["term", "process"]} gtk = "0.18" termios = "0.3" +terminfo = "0.8" [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.13" diff --git a/src/platform/linux.rs b/src/platform/linux.rs index f17c5b472..ec6210e29 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -10,7 +10,6 @@ use hbb_common::{ libc::{c_char, c_int, c_long, c_void}, log, message_proto::{DisplayInfo, Resolution}, - platform::linux::{CMD_PS, CMD_SH}, regex::{Captures, Regex}, }; use std::{ @@ -25,6 +24,7 @@ use std::{ }, time::{Duration, Instant}, }; +use terminfo::{capability as cap, Database}; use users::{get_user_by_name, os::unix::UserExt}; use wallpaper; @@ -33,8 +33,20 @@ type Xdo = *const c_void; pub const PA_SAMPLE_RATE: u32 = 48000; static mut UNMODIFIED: bool = true; +const INVALID_TERM_VALUES: [&str; 3] = ["", "unknown", "dumb"]; +const SHELL_PROCESSES: [&str; 4] = ["bash", "zsh", "fish", "sh"]; + lazy_static::lazy_static! { pub static ref IS_X11: bool = hbb_common::platform::linux::is_x11_or_headless(); + static ref DATABASE_XTERM_256COLOR: Option = { + match Database::from_name("xterm-256color") { + Ok(database) => Some(database), + Err(err) => { + log::error!("Failed to initialize xterm-256color database: {}", err); + None + } + } + }; } thread_local! { @@ -256,6 +268,70 @@ fn start_uinput_service() { }); } +/// Suggests the best terminal type based on the environment. +/// +/// The function prioritizes terminal types in the following order: +/// 1. `screen-256color`: Preferred when running inside `tmux` or `screen` sessions, +/// as these multiplexers often support advanced terminal features. +/// 2. `xterm-256color`: Selected if the terminal supports 256 colors, which is +/// suitable for modern terminal applications. +/// 3. `xterm`: Used as a fallback for basic terminal compatibility. +/// +/// Terminals like `linux` and `vt100` are excluded because they lack support for +/// modern features required by many applications. +fn suggest_best_term() -> String { + if is_running_in_tmux() || is_running_in_screen() { + return "screen-256color".to_string(); + } + if term_supports_256_colors("xterm-256color") { + return "xterm-256color".to_string(); + } + "xterm".to_string() +} + +fn is_running_in_tmux() -> bool { + std::env::var("TMUX").is_ok() +} + +fn is_running_in_screen() -> bool { + std::env::var("STY").is_ok() +} + +fn supports_256_colors(db: &Database) -> bool { + db.get::().map_or(false, |n| n.0 >= 256) +} + +fn term_supports_256_colors(term: &str) -> bool { + match term { + "xterm-256color" => DATABASE_XTERM_256COLOR + .as_ref() + .map_or(false, |db| supports_256_colors(db)), + _ => Database::from_name(term).map_or(false, |db| supports_256_colors(&db)), + } +} + +fn get_cur_term(uid: &str) -> Option { + if uid.is_empty() { + return None; + } + + if let Ok(term) = std::env::var("TERM") { + if !INVALID_TERM_VALUES.contains(&term.as_str()) { + return Some(term); + } + } + + for proc in SHELL_PROCESSES { + // Construct a regex pattern to match either the process name followed by '$' or 'bin/' followed by the process name. + let term = get_env("TERM", uid, &format!("{}$|bin/{}", proc, proc)); + if !INVALID_TERM_VALUES.contains(&term.as_str()) { + return Some(term); + } + } + + None +} + #[inline] fn try_start_server_(desktop: Option<&Desktop>) -> ResultType> { match desktop { @@ -273,6 +349,10 @@ fn try_start_server_(desktop: Option<&Desktop>) -> ResultType> { if !desktop.home.is_empty() { envs.push(("HOME", desktop.home.clone())); } + envs.push(( + "TERM", + get_cur_term(&desktop.uid).unwrap_or_else(|| suggest_best_term()), + )); run_as_user( vec!["--server"], Some((desktop.uid.clone(), desktop.username.clone())),