feat: add separate toggle for temp/gamma

This commit is contained in:
Vladimir Rubin 2025-06-14 20:30:05 +03:00
parent 753588c6d3
commit 16b9811f00
Signed by: vavakado
GPG key ID: CAB744727F36B524
3 changed files with 147 additions and 84 deletions

View file

@ -82,14 +82,32 @@ Values in hours (023):
Unix socket at `/tmp/hinoirisetr.sock` accepts newline-terminated commands: Unix socket at `/tmp/hinoirisetr.sock` accepts newline-terminated commands:
- **disable** - **disable**
Pause automatic adjustments; keeps current settings. Pause automatic adjustments; sets day settings.
- **disable_temp**
Pause automatic temperature adjustments; sets day settings.
- **disable_gamma**
Pause automatic gamma adjustments; sets day settings.
- **enable** - **enable**
Resume automatic adjustments. Resume automatic adjustments.
- **enable_temp**
Resume automatic temperature adjustments.
- **enable_gamma**
Resume automatic gamma adjustments.
- **toggle** - **toggle**
Switch between enabled/disabled states. Switch between enabled/disabled states.
- **toggle_temp**
Switch between enabled/disabled temperature adjustments.
- **toggle_gamma**
Switch between enabled/disabled gamma adjustments.
- **status** - **status**
Returns current state: Returns current state:
`dimming is <enabled|disabled> temp: <K>K, gamma: <%>` `dimming is <enabled|disabled> temp: <K>K, gamma: <%>`

View file

@ -429,16 +429,14 @@ pub fn compute_settings(now: Time, config: &Config) -> (u16, u16) {
} }
/// Apply given temperature (Kelvin) and gamma (%) via hyprctl commands /// Apply given temperature (Kelvin) and gamma (%) via hyprctl commands
pub fn apply_settings(temp: u16, gamma: u16, config: &Config) { pub fn apply_temp(temp: u16, config: &Config) {
trace!("apply_settings({temp}, {gamma})"); trace!("apply_temp({temp})");
let last_temp = LAST_TEMP.load(Ordering::SeqCst); let last_temp = LAST_TEMP.load(Ordering::SeqCst);
let last_gamma = LAST_GAMMA.load(Ordering::SeqCst); if last_temp == temp {
if last_temp == temp && last_gamma == gamma {
trace!("Settings unchanged, skipping application"); trace!("Settings unchanged, skipping application");
return; return;
} }
debug!("applying temperature: {temp}"); debug!("applying temperature: {temp}");
debug!("applying gamma: {gamma}");
if temp != last_temp { if temp != last_temp {
match config.temp_backend { match config.temp_backend {
@ -467,6 +465,16 @@ pub fn apply_settings(temp: u16, gamma: u16, config: &Config) {
} }
LAST_TEMP.store(temp, Ordering::SeqCst); LAST_TEMP.store(temp, Ordering::SeqCst);
} }
}
pub fn apply_gamma(gamma: u16, config: &Config) {
trace!("apply_gamma({gamma})");
let last_gamma = LAST_GAMMA.load(Ordering::SeqCst);
if last_gamma == gamma {
trace!("Settings unchanged, skipping application");
return;
}
debug!("applying gamma: {gamma}");
if gamma != last_gamma { if gamma != last_gamma {
match config.gamma_backend { match config.gamma_backend {

View file

@ -9,8 +9,8 @@ use std::time::{Duration, UNIX_EPOCH};
use hinoirisetr::notify::InitializedNotificationSystem; use hinoirisetr::notify::InitializedNotificationSystem;
use hinoirisetr::time::Time; use hinoirisetr::time::Time;
use hinoirisetr::{ use hinoirisetr::{
Config, GammaBackend, TempBackend, apply_settings, compute_settings, debug, error, info, Config, GammaBackend, TempBackend, apply_gamma, apply_temp, compute_settings, debug, error,
reset_cache, trace, warn, info, reset_cache, trace, warn,
}; };
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::UnixListener; use tokio::net::UnixListener;
@ -34,36 +34,43 @@ async fn config_reloader(notify: Arc<Notify>) {
loop { loop {
trace!("config poll tick"); trace!("config poll tick");
let config_path = get_config_path(); let config_path = get_config_path();
if config_path.exists() { if config_path.exists()
if let Ok(current_modified) = std::fs::metadata(&config_path) && let Ok(current_modified) = std::fs::metadata(&config_path)
.and_then(|m| m.modified()) .and_then(|m| m.modified())
.map(|t| t.duration_since(UNIX_EPOCH).unwrap().as_secs()) .map(|t| t.duration_since(UNIX_EPOCH).unwrap().as_secs())
{ {
let last: u64 = LAST_MODIFIED.load(Ordering::SeqCst); let last: u64 = LAST_MODIFIED.load(Ordering::SeqCst);
if 0 != last { if 0 != last {
if current_modified > last { if current_modified > last {
trace!("{current_modified}"); trace!("{current_modified}");
trace!("{last}"); trace!("{last}");
debug!("Config file modified, reloading..."); debug!("Config file modified, reloading...");
reload_config(Arc::clone(&notify)).await;
}
} else {
// File is new, reload to capture initial state
debug!("Config file detected, reloading...");
reload_config(Arc::clone(&notify)).await; reload_config(Arc::clone(&notify)).await;
} }
} else {
// File is new, reload to capture initial state
debug!("Config file detected, reloading...");
reload_config(Arc::clone(&notify)).await;
} }
} }
sleep(Duration::from_secs(5)).await; sleep(Duration::from_secs(5)).await;
} }
} }
async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) { async fn socket_server(
disabled_temp: Arc<AtomicBool>,
disabled_gamma: Arc<AtomicBool>,
notify: Arc<Notify>,
) {
let listener = UnixListener::bind(SOCKET_PATH).expect("Failed to bind socket"); let listener = UnixListener::bind(SOCKET_PATH).expect("Failed to bind socket");
match std::fs::set_permissions(SOCKET_PATH, std::fs::Permissions::from_mode(0o600)) { match std::fs::set_permissions(SOCKET_PATH, std::fs::Permissions::from_mode(0o600)) {
Ok(_) => {trace!("socket file permissions set");}, Ok(_) => {
Err(e) => {error!("Failed to set socket file permissions: {e}");}, trace!("socket file permissions set");
}
Err(e) => {
error!("Failed to set socket file permissions: {e}");
}
}; };
trace!("socket server bound"); trace!("socket server bound");
@ -85,55 +92,64 @@ async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) {
if let Ok(Some(line)) = lines.next_line().await { if let Ok(Some(line)) = lines.next_line().await {
match line.trim() { match line.trim() {
"disable_temp" => {
trace!("disable_gamma dispatched");
disabled_temp.store(true, Ordering::SeqCst);
notify.notify_one();
debug!("temp dimming is disabled");
}
"disable_gamma" => {
trace!("disable_gamma dispatched");
disabled_gamma.store(true, Ordering::SeqCst);
notify.notify_one();
debug!("gamma dimming is disabled");
}
"disable" => { "disable" => {
trace!("disable dispatched"); trace!("disable dispatched");
let config = *config_guard().await; disabled_temp.store(true, Ordering::SeqCst);
let disabled_clone = Arc::clone(&disabled); disabled_gamma.store(true, Ordering::SeqCst);
let notify_state = match hinoirisetr::notify::InitializedNotificationSystem::new(
"hinoirisetr",
) {
Ok(not) => NotifyState::Enabled(not),
Err(_) => NotifyState::Disabled,
};
disabled.store(true, Ordering::SeqCst);
notify.notify_one(); notify.notify_one();
debug!("dimming is disabled"); debug!("dimming is disabled");
// Spawn a background task to remind after timeout
println!("{}", config.disable_timeout);
if config.disable_timeout != 0 {
debug!("Spawning dimming timeout task");
tokio::spawn(async move {
let timeout_secs = config.disable_timeout;
tokio::time::sleep(Duration::from_secs(timeout_secs.into())).await;
if disabled_clone.load(Ordering::SeqCst) {
warn!("You've had dimming disabled for too long!");
// Show notification
if let NotifyState::Enabled(ref not) = notify_state {
let _ = not.show_notification(
"Dimming Reminder",
"You have dimming disabled!",
"notification-icon",
(config.notification_timeout as i32) * 5,
);
}
}
});
}
} }
"enable" => { "enable_temp" => {
trace!("enable dispatched"); trace!("enable dispatched");
disabled.store(false, Ordering::SeqCst); disabled_temp.store(false, Ordering::SeqCst);
notify.notify_one(); notify.notify_one();
debug!("dimming is enabled"); debug!("dimming is enabled");
} }
"enable_gamma" => {
trace!("enable_gamma dispatched");
disabled_gamma.store(false, Ordering::SeqCst);
notify.notify_one();
debug!("gamma dimming is enabled");
}
"enable" => {
trace!("enable dispatched");
disabled_temp.store(false, Ordering::SeqCst);
disabled_gamma.store(false, Ordering::SeqCst);
notify.notify_one();
debug!("dimming is enabled");
}
"toggle_temp" => {
trace!("toggle dispatched");
let now = !disabled_temp.load(Ordering::SeqCst);
disabled_temp.store(now, Ordering::SeqCst);
notify.notify_one();
debug!("temp dimming is {}", if now { "enabled" } else { "disabled" });
}
"toggle_gamma" => {
trace!("toggle_gamma dispatched");
let now = !disabled_gamma.load(Ordering::SeqCst);
disabled_gamma.store(now, Ordering::SeqCst);
notify.notify_one();
debug!("gamma dimming is {}", if now { "enabled" } else { "disabled" });
}
"toggle" => { "toggle" => {
trace!("toggle dispatched"); trace!("toggle dispatched");
let now = !disabled.load(Ordering::SeqCst); let now = !disabled_temp.load(Ordering::SeqCst);
disabled.store(now, Ordering::SeqCst); disabled_temp.store(now, Ordering::SeqCst);
disabled_gamma.store(now, Ordering::SeqCst);
notify.notify_one(); notify.notify_one();
debug!("dimming is {}", if now { "enabled" } else { "disabled" }); debug!("dimming is {}", if now { "enabled" } else { "disabled" });
} }
@ -143,14 +159,17 @@ async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) {
let now = get_time(); let now = get_time();
let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await); let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await);
let status = format!( let status = format!(
"dimming is {} - temp: {}K, gamma: {}%", "dimming - temp: {}, gamma: {}",
if disabled.load(Ordering::SeqCst) { if disabled_temp.load(Ordering::SeqCst) {
"disabled" "disabled".to_string()
} else { } else {
"enabled" format!("{cur_temp}K")
}, },
cur_temp, if disabled_gamma.load(Ordering::SeqCst) {
cur_gamma "disabled".to_string()
} else {
format!("{cur_gamma}%")
}
); );
if let Err(e) = writer.write(status.as_bytes()).await { if let Err(e) = writer.write(status.as_bytes()).await {
@ -170,11 +189,19 @@ async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) {
let now = get_time(); let now = get_time();
let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await); let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await);
let body = if disabled.load(Ordering::SeqCst) { let status = format!(
"disabled".to_string() "dimming - temp: {}, gamma: {}",
} else { if disabled_temp.load(Ordering::SeqCst) {
format!("temp: {cur_temp}K, gamma: {cur_gamma}%") "disabled".to_string()
}; } else {
format!("{cur_temp}K")
},
if disabled_gamma.load(Ordering::SeqCst) {
"disabled".to_string()
} else {
format!("{cur_gamma}%")
}
);
match notification { match notification {
NotifyState::Enabled(ref not) => { NotifyState::Enabled(ref not) => {
@ -182,7 +209,7 @@ async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) {
let timeout = config_guard().await.notification_timeout; let timeout = config_guard().await.notification_timeout;
match not.show_notification( match not.show_notification(
"Sunsetting", "Sunsetting",
&body, &status,
"notification-icon", "notification-icon",
timeout as i32, timeout as i32,
) { ) {
@ -231,7 +258,8 @@ async fn main() {
std::process::exit(1); std::process::exit(1);
} }
let disabled = Arc::new(AtomicBool::new(false)); let disabled_temp = Arc::new(AtomicBool::new(false));
let disabled_gamma = Arc::new(AtomicBool::new(false));
let notify = Arc::new(Notify::new()); let notify = Arc::new(Notify::new());
// load config // load config
@ -305,10 +333,11 @@ async fn main() {
// Spawn control socket server // Spawn control socket server
{ {
let disabled = Arc::clone(&disabled); let disabled_temp = Arc::clone(&disabled_temp);
let disabled_gamma = Arc::clone(&disabled_gamma);
let notify = Arc::clone(&notify); let notify = Arc::clone(&notify);
tokio::spawn(async move { tokio::spawn(async move {
socket_server(disabled, notify).await; socket_server(disabled_temp, disabled_gamma, notify).await;
}); });
} }
@ -339,7 +368,8 @@ async fn main() {
{ {
let now = get_time(); let now = get_time();
let (temp, gamma) = compute_settings(now, &*config_guard().await); let (temp, gamma) = compute_settings(now, &*config_guard().await);
apply_settings(temp, gamma, &*config_guard().await); apply_temp(temp, &*config_guard().await);
apply_gamma(gamma, &*config_guard().await);
trace!("initial settings applied: {temp}K, {gamma}%"); trace!("initial settings applied: {temp}K, {gamma}%");
} }
@ -347,16 +377,23 @@ async fn main() {
tokio::select! { tokio::select! {
_ = async { _ = async {
loop { loop {
if disabled.load(Ordering::SeqCst) { let now = get_time();
apply_settings( let (temp, gamma) = compute_settings(now, &*config_guard().await);
if disabled_temp.load(Ordering::SeqCst) {
apply_temp(
config_guard().await.temp_day, config_guard().await.temp_day,
&*config_guard().await,
);
} else {
apply_temp(temp, &*config_guard().await);
}
if disabled_gamma.load(Ordering::SeqCst) {
apply_gamma(
config_guard().await.gamma_day, config_guard().await.gamma_day,
&*config_guard().await, &*config_guard().await,
); );
} else { } else {
let now = get_time(); apply_gamma(gamma, &*config_guard().await);
let (temp, gamma) = compute_settings(now, &*config_guard().await);
apply_settings(temp, gamma, &*config_guard().await);
} }
notify.notified().await; notify.notified().await;