From 97f3018be07e4b3b5485485003361430f2e418b8 Mon Sep 17 00:00:00 2001 From: Jorge <103663493+jorgedanisc@users.noreply.github.com> Date: Tue, 18 Nov 2025 13:43:35 +0000 Subject: [PATCH] fix: update laptop detection logic to be more reliable (#348) --- src-tauri/src/helpers/clamshell.rs | 44 ++++++++----------- src-tauri/src/lib.rs | 2 +- .../settings/ClamshellMicrophoneSelector.tsx | 19 ++++---- 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src-tauri/src/helpers/clamshell.rs b/src-tauri/src/helpers/clamshell.rs index 120750c..0553031 100644 --- a/src-tauri/src/helpers/clamshell.rs +++ b/src-tauri/src/helpers/clamshell.rs @@ -26,31 +26,23 @@ pub fn is_clamshell() -> Result { Ok(stdout.contains("\"AppleClamshellState\" = Yes")) } -/// Checks if the Mac has a built-in display (i.e., is a laptop) +/// Checks if the Mac is a laptop by detecting battery presence /// -/// This queries the macOS IORegistry for built-in displays. -/// Returns true if a built-in display is found (MacBook), false otherwise (Mac Mini, Mac Studio, etc.) +/// This uses pmset to check for battery information. +/// Returns true if a battery is detected (laptop), false otherwise (desktop) #[cfg(target_os = "macos")] #[tauri::command] -pub fn has_builtin_display() -> Result { - let output = Command::new("ioreg") - .args(["-l", "-w", "0", "-r", "-c", "IODisplayConnect"]) +pub fn is_laptop() -> Result { + let output = Command::new("pmset") + .arg("-g") + .arg("batt") .output() - .map_err(|e| format!("Failed to execute ioreg: {}", e))?; - - if !output.status.success() { - return Err(format!( - "ioreg command failed with status: {}", - output.status - )); - } - + .map_err(|e| e.to_string())?; + let stdout = String::from_utf8_lossy(&output.stdout); - - // Look for built-in display indicators - // Built-in displays typically have AppleDisplay or AppleBacklightDisplay - Ok(stdout.contains("AppleBacklightDisplay") - || (stdout.contains("built-in") && stdout.contains("IODisplayConnect"))) + + // Check if InternalBattery is present (laptops have batteries, desktops typically don't) + Ok(stdout.contains("InternalBattery")) } /// Stub implementation for non-macOS platforms @@ -62,10 +54,10 @@ pub fn is_clamshell() -> Result { } /// Stub implementation for non-macOS platforms -/// Always returns false since built-in display detection is macOS-specific +/// Always returns false since laptop detection is macOS-specific #[cfg(not(target_os = "macos"))] #[tauri::command] -pub fn has_builtin_display() -> Result { +pub fn is_laptop() -> Result { Ok(false) } @@ -84,9 +76,11 @@ mod tests { #[test] #[cfg(target_os = "macos")] - fn test_has_builtin_display() { - let result = has_builtin_display(); + fn test_is_laptop() { + let result = is_laptop(); assert!(result.is_ok()); - let _ = result.unwrap(); + if let Ok(is_laptop) = result { + println!("Is laptop: {}", is_laptop); + } } } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index efc66e3..96c72be 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -352,7 +352,7 @@ pub fn run() { commands::audio::set_clamshell_microphone, commands::audio::get_clamshell_microphone, helpers::clamshell::is_clamshell, - helpers::clamshell::has_builtin_display, + helpers::clamshell::is_laptop, commands::transcription::set_model_unload_timeout, commands::transcription::get_model_load_status, commands::transcription::unload_model_manually, diff --git a/src/components/settings/ClamshellMicrophoneSelector.tsx b/src/components/settings/ClamshellMicrophoneSelector.tsx index 8722955..06117da 100644 --- a/src/components/settings/ClamshellMicrophoneSelector.tsx +++ b/src/components/settings/ClamshellMicrophoneSelector.tsx @@ -22,25 +22,24 @@ export const ClamshellMicrophoneSelector: React.FC(false); + const [isLaptop, setIsLaptop] = useState(false); useEffect(() => { - // Check if the device has a built-in display (i.e., is a laptop) - const checkBuiltinDisplay = async () => { + const checkIsLaptop = async () => { try { - const result = await invoke("has_builtin_display"); - setHasBuiltinDisplay(result); + const result = await invoke("is_laptop"); + setIsLaptop(result); } catch (error) { - console.error("Failed to check for built-in display:", error); - setHasBuiltinDisplay(false); + console.error("Failed to check if device is laptop:", error); + setIsLaptop(false); } }; - checkBuiltinDisplay(); + checkIsLaptop(); }, []); - // Only render on devices with built-in displays (laptops) - if (!hasBuiltinDisplay) { + // Only render on laptops + if (!isLaptop) { return null; }