use std::process::Command;
use std::sync::atomic::{AtomicU16, Ordering};
use std::sync::{Arc, LazyLock, Mutex};
#[cfg(feature = "wayland-backend")]
use crate::backend::WAYLAND_THREAD;
use crate::utils::eq_ignore_case;
use crate::{debug, ensure_hyprsunset_running, error, trace, warn};
static TEMP_LOCK: LazyLock<Arc<Mutex<()>>> = LazyLock::new(|| Arc::new(Mutex::new(())));
static LAST_TEMP: AtomicU16 = AtomicU16::new(0);
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum TempBackend {
Hyprctl,
Xsct,
#[cfg(feature = "wayland-backend")]
Wayland,
None,
}
impl std::str::FromStr for TempBackend {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
s if eq_ignore_case(s, "hyprctl") => {
warn!(
"hyprctl backend has been superseded by wayland, it may be removed in the next release"
);
Ok(Self::Hyprctl)
},
s if eq_ignore_case(s, "gammastep") => Err(
"gammastep backend has been deprecated, use wayland or xset instead".to_string(),
),
s if eq_ignore_case(s, "xsct") => Ok(Self::Xsct),
s if eq_ignore_case(s, "redshift") => {
Err("redshift backend has been deprecated, use wayland or xset instead".to_string())
},
#[cfg(feature = "wayland-backend")]
s if eq_ignore_case(s, "wayland") => Ok(Self::Wayland),
#[cfg(not(feature = "wayland-backend"))]
s if eq_ignore_case(s, "wayland") => {
Err("hinoirisetr was compiled without wayland support".to_string())
},
s if eq_ignore_case(s, "none") => Ok(Self::None),
_ => Err(format!("Invalid GammaBackend: {s}")),
}
}
}
pub fn apply_temp(temp: u16, backends: &[TempBackend]) {
trace!("apply_temp({temp})");
let _lock = TEMP_LOCK.lock().unwrap();
let last_temp = LAST_TEMP.load(Ordering::SeqCst);
if last_temp == temp {
trace!("Settings unchanged, skipping application");
return;
}
debug!("applying temperature: {temp}");
if temp != last_temp {
for backend in backends {
match backend {
TempBackend::Hyprctl => match ensure_hyprsunset_running() {
Ok(()) => {
let _ = Command::new("hyprctl")
.args(["hyprsunset", "temperature", &temp.to_string()])
.output();
trace!("hyprctl hyprsunset temperature {temp}");
},
Err(err) => {
error!("Error while starting hyprsunset: {err}");
},
},
TempBackend::Xsct => {
let _ = Command::new("xsct").args([&temp.to_string()]).output();
trace!("xsct {temp}");
},
TempBackend::None => {},
#[cfg(feature = "wayland-backend")]
TempBackend::Wayland => {
let guard = WAYLAND_THREAD.read().unwrap();
if let Some(ref thread) = *guard {
thread.set_temperature(temp.into());
}
},
}
}
LAST_TEMP.store(temp, Ordering::SeqCst);
}
}
pub fn reset_cache() {
LAST_TEMP.store(0, Ordering::SeqCst);
}