#[cfg(target_os = "macos")]
use crate::util::DEFAULT_TIMEOUT;
#[cfg(target_os = "macos")]
pub fn run_with_timeout(script: &str) -> bool {
use std::sync::mpsc;
use std::thread;
let script_owned = script.to_string();
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let output = std::process::Command::new("osascript")
.args(["-l", "JavaScript", "-e", &script_owned])
.output();
let _ = tx.send(output);
});
match rx.recv_timeout(DEFAULT_TIMEOUT) {
Ok(Ok(out)) if out.status.success() => {
String::from_utf8_lossy(&out.stdout).trim() == "true"
}
_ => false,
}
}
#[cfg(target_os = "macos")]
pub fn raise_front_window(app_name: &str) -> bool {
let script = format!(
r#"
(function() {{
try {{
var se = Application("System Events");
var proc = se.processes["{app_name}"];
var seWindows = proc.windows();
if (seWindows.length > 0) {{
seWindows[0].actions["AXRaise"].perform();
return true;
}}
return false;
}} catch(e) {{
return false;
}}
}})()
"#
);
run_with_timeout(&script)
}
#[cfg(not(target_os = "macos"))]
pub fn raise_front_window(_app_name: &str) -> bool {
false
}
#[cfg(target_os = "macos")]
pub fn raise_focused_window(app_name: &str) -> bool {
let script = format!(
r#"
(function() {{
try {{
var se = Application("System Events");
var proc = se.processes["{app_name}"];
// Try to get the focused window first
var focusedWindow = proc.attributes["AXFocusedWindow"].value();
if (focusedWindow) {{
focusedWindow.actions["AXRaise"].perform();
return true;
}}
// Fallback: if AXFocusedWindow is not available, try first window
var seWindows = proc.windows();
if (seWindows.length > 0) {{
seWindows[0].actions["AXRaise"].perform();
return true;
}}
return false;
}} catch(e) {{
return false;
}}
}})()
"#
);
run_with_timeout(&script)
}
#[cfg(not(target_os = "macos"))]
#[cfg_attr(not(test), expect(dead_code))]
pub fn raise_focused_window(_app_name: &str) -> bool {
false
}
#[cfg(target_os = "macos")]
pub fn activate_app(app_name: &str) -> bool {
let script = format!(
r#"
(function() {{
try {{
var app = Application("{app_name}");
if (!app.running()) return false;
app.activate();
return true;
}} catch(e) {{
return false;
}}
}})()
"#
);
run_with_timeout(&script)
}
#[cfg(not(target_os = "macos"))]
pub fn activate_app(_app_name: &str) -> bool {
false
}
#[cfg(not(target_os = "macos"))]
#[cfg_attr(not(test), expect(dead_code))]
pub fn run_with_timeout(_script: &str) -> bool {
false
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_run_with_timeout_simple_script() {
let result = run_with_timeout("true");
#[cfg(target_os = "macos")]
assert!(result);
#[cfg(not(target_os = "macos"))]
assert!(!result);
}
#[test]
fn test_run_with_timeout_false_script() {
let result = run_with_timeout("false");
assert!(!result);
}
#[test]
fn test_raise_front_window_nonexistent_app() {
let result = raise_front_window("NonExistentApp12345");
assert!(!result);
}
#[test]
fn test_raise_focused_window_nonexistent_app() {
let result = raise_focused_window("NonExistentApp12345");
assert!(!result);
}
#[test]
fn test_activate_app_nonexistent() {
let result = activate_app("NonExistentApp12345");
assert!(!result);
}
}