diff --git a/control/Cargo.lock b/control/Cargo.lock index faa7788..a63f9e1 100644 --- a/control/Cargo.lock +++ b/control/Cargo.lock @@ -37,7 +37,7 @@ dependencies = [ [[package]] name = "dynamiclight-control" -version = "1.0.3" +version = "1.0.4" dependencies = [ "dirs", "getrandom 0.3.4", diff --git a/control/Cargo.toml b/control/Cargo.toml index 3d547f2..4e37b80 100644 --- a/control/Cargo.toml +++ b/control/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dynamiclight-control" -version = "1.0.3" +version = "1.0.4" edition = "2021" license = "MIT" rust-version = "1.99" diff --git a/package.json b/package.json index 6a31037..57fe07a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dynamiclight", - "version": "1.0.3", + "version": "1.0.4", "private": true, "license": "MIT", "author": "mskutin", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index b3d05f5..2014172 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1227,7 +1227,7 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "dynamiclight" -version = "1.0.3" +version = "1.0.4" dependencies = [ "cc", "chrono", @@ -1256,7 +1256,7 @@ dependencies = [ [[package]] name = "dynamiclight-control" -version = "1.0.3" +version = "1.0.4" dependencies = [ "dirs 6.0.0", "getrandom 0.3.4", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5a4d2fa..27d946b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dynamiclight" -version = "1.0.3" +version = "1.0.4" description = "Local USB monitor backlight controller" authors = ["mskutin"] license = "MIT" diff --git a/src-tauri/src/engine.rs b/src-tauri/src/engine.rs index 6fa5f9d..6bd2435 100644 --- a/src-tauri/src/engine.rs +++ b/src-tauri/src/engine.rs @@ -555,6 +555,7 @@ impl Engine { | SystemEvent::Locked(true) | SystemEvent::DisplayOff(true) | SystemEvent::Away(Away::OtherUser | Away::Remote) + | SystemEvent::Ending(true) ) { self.extension = None; self.external_cue = None; @@ -597,6 +598,16 @@ impl Engine { .close(self.life.pause_reason(&self.state.settings)); } } + SystemEvent::Ending(ending) => { + if ending == self.life.ending { + return; + } + self.life.ending = ending; + if ending && self.state.settings.off_on_quit { + self.black(); + self.controller.close("Computer shutting down"); + } + } SystemEvent::SourcesChanged => { if self.state.capturing && self.state.settings.mode == "blend" { self.lose_blend_source(true); diff --git a/src-tauri/src/lifecycle.rs b/src-tauri/src/lifecycle.rs index 60d85ca..55b3dec 100644 --- a/src-tauri/src/lifecycle.rs +++ b/src-tauri/src/lifecycle.rs @@ -12,6 +12,10 @@ pub enum SystemEvent { /// Only Windows reports it. #[cfg_attr(not(target_os = "windows"), allow(dead_code))] Away(Away), + /// Windows is about to end the session (shutdown, restart, sign-out); `false` + /// when something cancelled it. Only Windows reports it. + #[cfg_attr(not(target_os = "windows"), allow(dead_code))] + Ending(bool), SourcesChanged, #[cfg(target_os = "linux")] AudioChanged, @@ -41,6 +45,7 @@ pub struct Lifecycle { pub display_off: bool, pub locked: bool, pub away: Away, + pub ending: bool, } impl Lifecycle { pub fn pause_reason(&self, s: &Settings) -> &'static str { @@ -52,6 +57,8 @@ impl Lifecycle { "Remote desktop session" } else if self.away == Away::OtherUser { "Another Windows user is active" + } else if self.ending && s.off_on_quit { + "Computer shutting down" } else if self.locked && s.off_on_lock { "Computer locked" } else if self.display_off && s.off_on_display_sleep { @@ -154,4 +161,19 @@ mod tests { std::fs::write(&path, b"invalid").unwrap(); assert!(SavedIntent::load(&path).is_err()); } + + #[test] + fn ending_session_pauses_only_when_the_strip_goes_off_on_quit() { + let mut life = Lifecycle { + requested: true, + ..Default::default() + }; + let mut s = Settings::default(); + assert!(life.active(&s)); + life.ending = true; + s.off_on_quit = true; + assert_eq!(life.pause_reason(&s), "Computer shutting down"); + s.off_on_quit = false; + assert!(life.active(&s)); + } } diff --git a/src-tauri/src/lifecycle_windows.rs b/src-tauri/src/lifecycle_windows.rs index 71c711d..a211797 100644 --- a/src-tauri/src/lifecycle_windows.rs +++ b/src-tauri/src/lifecycle_windows.rs @@ -95,10 +95,18 @@ unsafe extern "system" fn window_proc( WM_DISPLAYCHANGE => handle.system_event(SystemEvent::SourcesChanged, false), // Windows shutdown/restart/sign-out: turn the strip off before the process is // killed, otherwise USB power keeps the last frame lit. - WM_QUERYENDSESSION => return LRESULT(1), + // The strip goes dark already on the query: when the session really ends, + // tao's window calls exit(0) on its own WM_ENDSESSION at once, which would + // kill this process before the USB frame below is written. + WM_QUERYENDSESSION => { + handle.system_event(SystemEvent::Ending(true), true); + return LRESULT(1); + } WM_ENDSESSION if wparam.0 != 0 => { let _ = handle.request(crate::engine::Action::Shutdown); } + // Something cancelled the shutdown: light up again. + WM_ENDSESSION => handle.system_event(SystemEvent::Ending(false), false), _ => {} } } diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index dbd9423..24e33ca 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "DynamicLight", - "version": "1.0.3", + "version": "1.0.4", "identifier": "com.dynamiclight.desktop", "build": { "frontendDist": "../src/ui"