aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-09 03:35:14 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-09 03:35:35 +0300
commit36b2e2f5463139a284483732131ce44977881239 (patch)
treecc839f9f462d74222265fcbf634de98f9aaed2fc /src
parentadbaae68daee7577b2dc93bd12507bfb67a2ca84 (diff)
fix: use drawn cursor by default in wsl
refs #930
Diffstat (limited to 'src')
-rw-r--r--src/client/mod.rs8
-rw-r--r--src/main.rs2
-rw-r--r--src/platform/fallback.rs4
-rw-r--r--src/platform/linux.rs33
-rw-r--r--src/platform/macos.rs4
-rw-r--r--src/platform/windows.rs4
6 files changed, 51 insertions, 4 deletions
diff --git a/src/client/mod.rs b/src/client/mod.rs
index bdc67880..90a73ec8 100644
--- a/src/client/mod.rs
+++ b/src/client/mod.rs
@@ -453,7 +453,9 @@ fn write_terminal_restore_postlude(
fn should_draw_host_cursor(mode: crate::config::HostCursorModeConfig) -> bool {
match mode {
- crate::config::HostCursorModeConfig::Auto => cfg!(windows),
+ crate::config::HostCursorModeConfig::Auto => {
+ crate::platform::should_draw_host_cursor_by_default()
+ }
crate::config::HostCursorModeConfig::Native => false,
crate::config::HostCursorModeConfig::Drawn => true,
}
@@ -2198,10 +2200,10 @@ mod tests {
}
#[test]
- fn host_cursor_policy_auto_uses_drawn_cursor_on_windows() {
+ fn host_cursor_policy_auto_uses_platform_default() {
assert_eq!(
should_draw_host_cursor(crate::config::HostCursorModeConfig::Auto),
- cfg!(windows)
+ crate::platform::should_draw_host_cursor_by_default()
);
}
diff --git a/src/main.rs b/src/main.rs
index deb332b9..575e23f8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -259,7 +259,7 @@ const DEFAULT_CONFIG: &str = r##"# herdr configuration
# mouse_capture = true
# Host cursor policy: "auto", "native", or "drawn".
-# "auto" draws Herdr's own cursor on Windows to avoid ConPTY cursor flicker, and uses the native terminal cursor elsewhere.
+# "auto" draws Herdr's own cursor on native Windows builds and WSL to avoid ConPTY cursor flicker, and uses the native terminal cursor elsewhere.
# "native" always uses the outer terminal cursor. "drawn" always draws Herdr's cursor as terminal cell content.
# host_cursor = "auto"
diff --git a/src/platform/fallback.rs b/src/platform/fallback.rs
index 382ccf5e..6b5700cc 100644
--- a/src/platform/fallback.rs
+++ b/src/platform/fallback.rs
@@ -6,6 +6,10 @@ use super::{ClipboardImage, ForegroundJob, Signal};
/// Unsupported platform stub.
pub fn raise_server_nofile_limit() {}
+pub(crate) fn should_draw_host_cursor_by_default() -> bool {
+ false
+}
+
fn raw_command_argv(command: &str, flag: &str) -> Vec<std::ffi::OsString> {
vec!["/bin/sh".into(), flag.into(), command.into()]
}
diff --git a/src/platform/linux.rs b/src/platform/linux.rs
index be0c97b9..2013873f 100644
--- a/src/platform/linux.rs
+++ b/src/platform/linux.rs
@@ -14,6 +14,7 @@ use super::{
};
const FOREGROUND_MEMBERS_CACHE_TTL: Duration = Duration::from_millis(250);
+const WSL_MARKER_ENV_VARS: &[&str] = &["WSL_DISTRO_NAME", "WSL_INTEROP"];
#[derive(Debug, Clone, PartialEq, Eq)]
struct ProcGroupMember {
@@ -39,6 +40,30 @@ static FOREGROUND_MEMBERS_CACHE: Mutex<ForegroundMembersCache> =
pub fn raise_server_nofile_limit() {}
+pub(crate) fn should_draw_host_cursor_by_default() -> bool {
+ running_inside_wsl()
+}
+
+fn running_inside_wsl() -> bool {
+ proc_file_indicates_wsl("/proc/sys/kernel/osrelease")
+ || proc_file_indicates_wsl("/proc/version")
+ || WSL_MARKER_ENV_VARS
+ .iter()
+ .any(|key| std::env::var_os(key).is_some())
+ || std::path::Path::new("/run/WSL").exists()
+}
+
+fn proc_file_indicates_wsl(path: &str) -> bool {
+ std::fs::read_to_string(path)
+ .map(|text| text_indicates_wsl(&text))
+ .unwrap_or(false)
+}
+
+fn text_indicates_wsl(text: &str) -> bool {
+ let text = text.to_ascii_lowercase();
+ text.contains("microsoft") || text.contains("wsl")
+}
+
fn raw_command_argv(command: &str, flag: &str) -> Vec<std::ffi::OsString> {
vec!["/bin/sh".into(), flag.into(), command.into()]
}
@@ -713,6 +738,14 @@ mod tests {
}
#[test]
+ fn wsl_marker_detection_matches_kernel_release_text() {
+ assert!(text_indicates_wsl("5.15.167.4-microsoft-standard-WSL2"));
+ assert!(text_indicates_wsl("4.4.0-19041-Microsoft"));
+ assert!(!text_indicates_wsl("6.8.0-64-generic"));
+ assert!(!text_indicates_wsl(""));
+ }
+
+ #[test]
fn foreground_members_indexes_by_process_group() {
let by_group = foreground_members(&[
(10, "shell", 10),
diff --git a/src/platform/macos.rs b/src/platform/macos.rs
index f2441f06..70eea7ec 100644
--- a/src/platform/macos.rs
+++ b/src/platform/macos.rs
@@ -16,6 +16,10 @@ const PROC_PGRP_ONLY: u32 = 2;
const SERVER_NOFILE_LIMIT_TARGET: libc::rlim_t = 8192;
const CF_STRING_ENCODING_UTF8: u32 = 0x0800_0100;
+pub(crate) fn should_draw_host_cursor_by_default() -> bool {
+ false
+}
+
fn raw_command_argv(command: &str, flag: &str) -> Vec<std::ffi::OsString> {
vec!["/bin/sh".into(), flag.into(), command.into()]
}
diff --git a/src/platform/windows.rs b/src/platform/windows.rs
index 49a68111..a44ebafd 100644
--- a/src/platform/windows.rs
+++ b/src/platform/windows.rs
@@ -38,6 +38,10 @@ use super::{ClipboardImage, ForegroundJob, Signal};
const STILL_ACTIVE: u32 = 259;
+pub(crate) fn should_draw_host_cursor_by_default() -> bool {
+ true
+}
+
#[derive(Debug, Clone, PartialEq, Eq)]
struct WindowsProcessEntry {
pid: u32,