diff --git a/Cargo.lock b/Cargo.lock index dd83245..421bc47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,12 +19,10 @@ dependencies = [ "ahfail-ui", "gdk", "gdk-pixbuf", - "gio", "glib", "gstreamer", "gstreamer-player", "gtk", - "libc", "pkg-config", "rand", ] @@ -44,7 +42,9 @@ dependencies = [ "gstreamer", "gstreamer-player", "gtk", + "libc", "rand", + "tempfile", "ureq", ] @@ -61,7 +61,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" dependencies = [ "atk-sys", - "bitflags", + "bitflags 1.3.2", "glib", "libc", ] @@ -96,13 +96,19 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + [[package]] name = "cairo-rs" version = "0.15.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-sys-rs", "glib", "libc", @@ -172,6 +178,22 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + [[package]] name = "field-offset" version = "0.3.6" @@ -198,6 +220,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -264,7 +292,7 @@ version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "gdk-pixbuf", "gdk-sys", @@ -280,7 +308,7 @@ version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gdk-pixbuf-sys", "gio", "glib", @@ -328,13 +356,26 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "gio" version = "0.15.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", @@ -364,7 +405,7 @@ version = "0.15.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-executor", @@ -420,7 +461,7 @@ version = "0.18.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66363bacf5e4f6eb281564adc2902e44c52ae5c45082423e7439e9012b75456" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "futures-channel", "futures-core", @@ -444,7 +485,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "224f35f36582407caf58ded74854526beeecc23d0cf64b8d1c3e00584ed6863f" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "glib", "gstreamer", @@ -471,7 +512,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f14ee02352ba73cadebe640bfb33f12fe8d03cbcad816a102d55a0251fb99bb" dependencies = [ - "bitflags", + "bitflags 1.3.2", "glib", "gstreamer", "gstreamer-player-sys", @@ -512,7 +553,7 @@ version = "0.18.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9418adfc72dafa1ad9eb106527ce4804887d101027c4528ec28c7d29cc899519" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "futures-channel", "glib", @@ -544,7 +585,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" dependencies = [ "atk", - "bitflags", + "bitflags 1.3.2", "cairo-rs", "field-offset", "futures-channel", @@ -592,6 +633,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + [[package]] name = "hashbrown" version = "0.16.1" @@ -691,6 +741,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "idna" version = "1.1.0" @@ -719,15 +775,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", + "serde", + "serde_core", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "litemap" version = "0.8.2" @@ -820,7 +896,7 @@ version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" dependencies = [ - "bitflags", + "bitflags 1.3.2", "glib", "libc", "once_cell", @@ -893,6 +969,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.111", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -945,6 +1031,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.8.5" @@ -972,7 +1064,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", ] [[package]] @@ -983,7 +1075,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys", @@ -998,6 +1090,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags 2.11.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustls" version = "0.23.40" @@ -1068,6 +1173,19 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "serde_spanned" version = "0.6.9" @@ -1165,6 +1283,19 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +[[package]] +name = "tempfile" +version = "3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -1246,6 +1377,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "untrusted" version = "0.9.0" @@ -1304,6 +1441,58 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.1", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "webpki-roots" version = "0.26.11" @@ -1435,6 +1624,100 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap", + "prettyplease", + "syn 2.0.111", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.111", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.1", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "writeable" version = "0.6.3" @@ -1543,3 +1826,9 @@ dependencies = [ "quote", "syn 2.0.111", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/crates/ahfail-gtklock/src/handler.rs b/crates/ahfail-gtklock/src/handler.rs index a8b2ee9..5aadc81 100644 --- a/crates/ahfail-gtklock/src/handler.rs +++ b/crates/ahfail-gtklock/src/handler.rs @@ -56,6 +56,13 @@ impl WindowHandler { } println!("[ahfail] Error label changed to: '{}'", text_str); + MODULE_STATE.with(|s| { + let mut st = s.borrow_mut(); + if st.volume_state.is_none() { + st.volume_state = ahfail_ui::volume::save_and_set_max(); + } + }); + MODULE_STATE.with(|state| { let state = state.borrow(); if let (Some(animation), Some(audio_uri)) = (&state.animation, &state.audio_uri) { diff --git a/crates/ahfail-gtklock/src/lib.rs b/crates/ahfail-gtklock/src/lib.rs index b105377..7838ce9 100644 --- a/crates/ahfail-gtklock/src/lib.rs +++ b/crates/ahfail-gtklock/src/lib.rs @@ -136,8 +136,12 @@ pub unsafe extern "C" fn on_idle_show(_gtklock: *mut GtkLock) {} pub unsafe extern "C" fn g_module_unload(_module: *mut c_void) { MODULE_STATE.with(|state| { let mut state = state.borrow_mut(); + if let Some(vs) = state.volume_state.take() { + ahfail_ui::volume::restore(vs); + } state.animation = None; state.audio_uri = None; state.config.deadzone = None; + state.volume_state = None; }); } \ No newline at end of file diff --git a/crates/ahfail-gtklock/src/state.rs b/crates/ahfail-gtklock/src/state.rs index 1367b21..be347d2 100644 --- a/crates/ahfail-gtklock/src/state.rs +++ b/crates/ahfail-gtklock/src/state.rs @@ -7,6 +7,7 @@ pub struct ModuleState { pub animation: Option, pub audio_uri: Option, pub config: ModuleConfig, + pub volume_state: Option, } pub struct WindowData { @@ -22,5 +23,6 @@ thread_local! { animation: None, audio_uri: None, config: ModuleConfig { deadzone: None }, + volume_state: None, }) }; } diff --git a/crates/ahfail-ui/Cargo.toml b/crates/ahfail-ui/Cargo.toml index 4e5df87..7097b94 100644 --- a/crates/ahfail-ui/Cargo.toml +++ b/crates/ahfail-ui/Cargo.toml @@ -17,3 +17,7 @@ gio = { version = "0.15", package = "gio" } gdk-pixbuf = "0.15" rand = "0.8" ureq = "2" +libc = "0.2" + +[dev-dependencies] +tempfile = "3" diff --git a/crates/ahfail-ui/src/volume.rs b/crates/ahfail-ui/src/volume.rs index ef8336b..7b3745f 100644 --- a/crates/ahfail-ui/src/volume.rs +++ b/crates/ahfail-ui/src/volume.rs @@ -1,7 +1,139 @@ -pub struct VolumeState; +use std::path::PathBuf; +use std::process::Command; +use std::fs; +use std::io::Write; -pub fn save_and_set_max() -> Option { - None +pub struct VolumeState { + pub volume: u32, + pub muted: bool, + pub lock_path: PathBuf, } -pub fn restore(_state: VolumeState) {} +/// Atomically creates lock file. Returns true if this process is first (primary). +pub fn try_acquire_lock(path: &std::path::Path) -> bool { + fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(path) + .map(|mut f| { let _ = f.write_all(b"1"); true }) + .unwrap_or(false) +} + +/// Returns lock file path: $XDG_RUNTIME_DIR/ahfail.lock or /tmp/ahfail-{uid}.lock +pub fn lock_path() -> PathBuf { + if let Ok(dir) = std::env::var("XDG_RUNTIME_DIR") { + PathBuf::from(dir).join("ahfail.lock") + } else { + PathBuf::from(format!("/tmp/ahfail-{}.lock", get_uid())) + } +} + +fn get_uid() -> u32 { + unsafe { libc::getuid() } +} + +/// If primary: save current system volume/mute state, set volume to 100% unmuted. +/// Returns Some(VolumeState) if this process is the primary (should restore on exit). +pub fn save_and_set_max() -> Option { + let path = lock_path(); + if !try_acquire_lock(&path) { return None; } + let (volume, muted) = get_current_volume(); + set_volume_max(); + Some(VolumeState { volume, muted, lock_path: path }) +} + +/// Restores volume from saved state and removes lock file. +pub fn restore(state: VolumeState) { + restore_volume(state.volume, state.muted); + let _ = fs::remove_file(&state.lock_path); +} + +#[cfg(target_os = "linux")] +fn get_current_volume() -> (u32, bool) { + let vol = Command::new("pactl") + .args(["get-sink-volume", "@DEFAULT_SINK@"]) + .output() + .ok() + .and_then(|o| parse_pactl_volume(&String::from_utf8_lossy(&o.stdout))) + .unwrap_or(100); + + let muted = Command::new("pactl") + .args(["get-sink-mute", "@DEFAULT_SINK@"]) + .output() + .ok() + .map(|o| String::from_utf8_lossy(&o.stdout).contains("yes")) + .unwrap_or(false); + + (vol, muted) +} + +#[cfg(target_os = "linux")] +fn parse_pactl_volume(output: &str) -> Option { + output.split('%').next() + .and_then(|s| s.split_whitespace().last()) + .and_then(|s| s.parse().ok()) +} + +#[cfg(target_os = "linux")] +fn set_volume_max() { + let _ = Command::new("pactl").args(["set-sink-mute", "@DEFAULT_SINK@", "0"]).status(); + let _ = Command::new("pactl").args(["set-sink-volume", "@DEFAULT_SINK@", "65536"]).status(); +} + +#[cfg(target_os = "linux")] +fn restore_volume(volume: u32, muted: bool) { + let v = ((volume as u64 * 65536) / 100) as u32; + let _ = Command::new("pactl") + .args(["set-sink-volume", "@DEFAULT_SINK@", &v.to_string()]) + .status(); + let mute_arg = if muted { "1" } else { "0" }; + let _ = Command::new("pactl").args(["set-sink-mute", "@DEFAULT_SINK@", mute_arg]).status(); +} + +#[cfg(target_os = "macos")] +fn get_current_volume() -> (u32, bool) { + let output = Command::new("osascript") + .args(["-e", "output volume of (get volume settings)"]) + .output() + .ok(); + let vol = output.as_ref() + .and_then(|o| String::from_utf8_lossy(&o.stdout).trim().parse().ok()) + .unwrap_or(100); + + let muted = Command::new("osascript") + .args(["-e", "output muted of (get volume settings)"]) + .output() + .ok() + .map(|o| String::from_utf8_lossy(&o.stdout).trim() == "true") + .unwrap_or(false); + + (vol, muted) +} + +#[cfg(target_os = "macos")] +fn set_volume_max() { + let _ = Command::new("osascript") + .args(["-e", "set volume output volume 100 without output muted"]) + .status(); +} + +#[cfg(target_os = "macos")] +fn restore_volume(volume: u32, muted: bool) { + let script = if muted { + format!("set volume output volume {} with output muted", volume) + } else { + format!("set volume output volume {} without output muted", volume) + }; + let _ = Command::new("osascript").args(["-e", &script]).status(); +} + +#[cfg(not(any(target_os = "linux", target_os = "macos")))] +fn get_current_volume() -> (u32, bool) { + (100, false) +} + +#[cfg(not(any(target_os = "linux", target_os = "macos")))] +fn set_volume_max() {} + +#[cfg(not(any(target_os = "linux", target_os = "macos")))] +fn restore_volume(_volume: u32, _muted: bool) {} diff --git a/crates/ahfail-ui/tests/volume_tests.rs b/crates/ahfail-ui/tests/volume_tests.rs new file mode 100644 index 0000000..1708ac2 --- /dev/null +++ b/crates/ahfail-ui/tests/volume_tests.rs @@ -0,0 +1,12 @@ +#[test] +fn lock_file_created_and_prevents_second_acquisition() { + let dir = tempfile::tempdir().unwrap(); + let lock_path = dir.path().join("ahfail.lock"); + + let acquired = ahfail_ui::volume::try_acquire_lock(&lock_path); + assert!(acquired); + assert!(lock_path.exists()); + + let acquired2 = ahfail_ui::volume::try_acquire_lock(&lock_path); + assert!(!acquired2); +}