diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/bin/sctd.rs | 51 | ||||
| -rw-r--r-- | src/lib.rs | 55 | ||||
| -rw-r--r-- | src/platform.rs | 5 | ||||
| -rw-r--r-- | src/platform/linux.rs | 34 | ||||
| -rw-r--r-- | src/platform/macos.rs | 44 |
5 files changed, 132 insertions, 57 deletions
diff --git a/src/bin/sctd.rs b/src/bin/sctd.rs index 81e65e5..d691586 100644 --- a/src/bin/sctd.rs +++ b/src/bin/sctd.rs @@ -6,9 +6,9 @@ extern crate clap; extern crate spa; use chrono::prelude::*; -use clap::{value_t_or_exit, App, Arg}; +use clap::{Arg, Command}; use env_logger::Env; -use spa::calc_sunrise_and_set; +use spa::{sunrise_and_set, StdFloatOps}; use std::thread; use std::time::Duration; @@ -16,51 +16,62 @@ fn main() { let env = Env::default().filter_or("SCTD_LOG_LEVEL", "info"); env_logger::init_from_env(env); - let matches = App::new("sctd") - .version("0.3.0") + let matches = Command::new("sctd") + .version(option_env!("CARGO_PKG_VERSION").unwrap_or("N/A")) .about("set color temperature daemon") .arg( - Arg::with_name("latitude") + Arg::new("latitude") .long("latitude") - .takes_value(true) + .value_name("LATITUDE") + .help("Latitude coordinate") .allow_hyphen_values(true), ) .arg( - Arg::with_name("longitude") + Arg::new("longitude") .long("longitude") - .takes_value(true) + .value_name("LONGITUDE") + .help("Longitude coordinate") .allow_hyphen_values(true), ) - .arg(Arg::with_name("reset").long("reset")) + .arg( + Arg::new("reset") + .long("reset") + .help("Reset temperature") + .action(clap::ArgAction::SetTrue), + ) .get_matches(); - if matches.is_present("reset") { + if matches.get_flag("reset") { sctd::reset_temp(); } else { - let latitude = value_t_or_exit!(matches, "latitude", f64); - let longitude = value_t_or_exit!(matches, "longitude", f64); + let latitude: f64 = matches + .get_one::<String>("latitude") + .expect("latitude is required") + .parse() + .expect("latitude must be a valid number"); + let longitude: f64 = matches + .get_one::<String>("longitude") + .expect("longitude is required") + .parse() + .expect("longitude must be a valid number"); let mut temp = 0; loop { let utc: DateTime<Utc> = Utc::now(); - match calc_sunrise_and_set(utc, latitude, longitude) { + match sunrise_and_set::<StdFloatOps>(utc, latitude, longitude) { Ok(ss) => { let new_temp = sctd::get_temp(utc, &ss, latitude, longitude) as u32; if new_temp != temp { temp = new_temp; - info!("setting temperature to {}", temp); + info!("setting temperature to {temp}"); sctd::set_temp(temp); } else { - debug!( - "skipping temperature change as it hasn't changed ({})", - temp - ); + debug!("skipping temperature change as it hasn't changed ({temp})"); } } Err(e) => { error!( - "error calculating sunrise and sunset for {}, {}: {:?}", - latitude, longitude, e + "error calculating sunrise and sunset for {latitude}, {longitude}: {e:?}" ); } } @@ -3,14 +3,16 @@ extern crate log; extern crate spa; +mod platform; + use chrono::prelude::*; -use spa::{calc_solar_position, SunriseAndSet}; -use std::os::raw::{c_ushort, c_void}; -use std::ptr; -use x11::xlib::{XCloseDisplay, XDefaultScreen, XFree, XOpenDisplay, XRootWindow}; -use x11::xrandr::{ - XRRAllocGamma, XRRCrtcGamma, XRRGetCrtcGammaSize, XRRGetScreenResourcesCurrent, XRRSetCrtcGamma, -}; +use spa::{solar_position, StdFloatOps, SunriseAndSet}; + +#[cfg(target_os = "linux")] +use platform::linux as os; + +#[cfg(target_os = "macos")] +use platform::macos as os; const LOW_TEMP: f64 = 3500f64; const HIGH_TEMP: f64 = 5500f64; @@ -26,52 +28,31 @@ pub struct WhitePoint { } pub fn set_temp(temp: u32) { - let ratio: f64 = (temp % 500) as f64 / 500f64; - unsafe { - let display = XOpenDisplay(ptr::null_mut()); - let screen = XDefaultScreen(display); - let root = XRootWindow(display, screen); - let resource = XRRGetScreenResourcesCurrent(display, root); - - for x in 0..(*resource).ncrtc { - let crtcxid = (*resource).crtcs.offset(x as isize); - let size = XRRGetCrtcGammaSize(display, *crtcxid); - let crtc_gamma: *mut XRRCrtcGamma = XRRAllocGamma(size); - let gamma = avg(temp, ratio); - - for i in 0..size { - let g = (65535f64 * i as f64) / size as f64; - *((*crtc_gamma).red as *mut c_ushort).offset(i as isize) = (g * gamma.red) as u16; - *((*crtc_gamma).green as *mut c_ushort).offset(i as isize) = - (g * gamma.green) as u16; - *((*crtc_gamma).blue as *mut c_ushort).offset(i as isize) = (g * gamma.blue) as u16; - } - XRRSetCrtcGamma(display, *crtcxid, crtc_gamma); - XFree(crtc_gamma as *mut c_void); - } - XCloseDisplay(display); - } + os::set_temp(temp); } pub fn reset_temp() { - set_temp(HIGH_TEMP as u32); + os::set_temp(HIGH_TEMP as u32); } fn get_transition_progress_from_elevation(elevation: f64) -> f64 { if elevation < TRANSITION_LOW { - return 0.0; + 0.0 } else if elevation < TRANSITION_HIGH { (TRANSITION_LOW - elevation) / (TRANSITION_LOW - TRANSITION_HIGH) } else { - return 1.0; + 1.0 } } pub fn get_temp(utc: DateTime<Utc>, ss: &SunriseAndSet, lat: f64, lon: f64) -> f64 { match *ss { SunriseAndSet::Daylight(_, _) => { - let elevation = 90f64 - calc_solar_position(utc, lat, lon).unwrap().zenith_angle; - debug!("elevation: {}", elevation); + let elevation = 90f64 + - solar_position::<StdFloatOps>(utc, lat, lon) + .unwrap() + .zenith_angle; + debug!("elevation: {elevation}"); let progress = get_transition_progress_from_elevation(elevation); LOW_TEMP + (progress * (HIGH_TEMP - LOW_TEMP)) } diff --git a/src/platform.rs b/src/platform.rs new file mode 100644 index 0000000..204fd43 --- /dev/null +++ b/src/platform.rs @@ -0,0 +1,5 @@ +#[cfg(target_os = "linux")] +pub mod linux; + +#[cfg(target_os = "macos")] +pub mod macos; diff --git a/src/platform/linux.rs b/src/platform/linux.rs new file mode 100644 index 0000000..ec0fc6a --- /dev/null +++ b/src/platform/linux.rs @@ -0,0 +1,34 @@ +use std::os::raw::{c_ushort, c_void}; +use std::ptr; +use x11::xlib::{XCloseDisplay, XDefaultScreen, XFree, XOpenDisplay, XRootWindow}; +use x11::xrandr::{ + XRRAllocGamma, XRRCrtcGamma, XRRGetCrtcGammaSize, XRRGetScreenResourcesCurrent, XRRSetCrtcGamma, +}; + +pub fn set_temp(temp: u32) { + let ratio: f64 = (temp % 500) as f64 / 500f64; + unsafe { + let display = XOpenDisplay(ptr::null_mut()); + let screen = XDefaultScreen(display); + let root = XRootWindow(display, screen); + let resource = XRRGetScreenResourcesCurrent(display, root); + + for x in 0..(*resource).ncrtc { + let crtcxid = (*resource).crtcs.offset(x as isize); + let size = XRRGetCrtcGammaSize(display, *crtcxid); + let crtc_gamma: *mut XRRCrtcGamma = XRRAllocGamma(size); + let gamma = crate::avg(temp, ratio); + + for i in 0..size { + let g = (65535f64 * i as f64) / size as f64; + *((*crtc_gamma).red as *mut c_ushort).offset(i as isize) = (g * gamma.red) as u16; + *((*crtc_gamma).green as *mut c_ushort).offset(i as isize) = + (g * gamma.green) as u16; + *((*crtc_gamma).blue as *mut c_ushort).offset(i as isize) = (g * gamma.blue) as u16; + } + XRRSetCrtcGamma(display, *crtcxid, crtc_gamma); + XFree(crtc_gamma as *mut c_void); + } + XCloseDisplay(display); + } +} diff --git a/src/platform/macos.rs b/src/platform/macos.rs new file mode 100644 index 0000000..0292250 --- /dev/null +++ b/src/platform/macos.rs @@ -0,0 +1,44 @@ +use core_graphics::display::CGDisplay; + +pub fn set_temp(temp: u32) { + use std::os::raw::c_int; + + let ratio: f64 = (temp % 500) as f64 / 500f64; + let gamma = crate::avg(temp, ratio); + + let main_display = CGDisplay::main(); + + extern "C" { + fn CGSetDisplayTransferByTable( + display: u32, + table_size: u32, + red_table: *const f32, + green_table: *const f32, + blue_table: *const f32, + ) -> c_int; + fn CGDisplayGammaTableCapacity(display: u32) -> u32; + } + + let table_size = unsafe { CGDisplayGammaTableCapacity(main_display.id) } as usize; + + let mut red_table = vec![0.0; table_size]; + let mut green_table = vec![0.0; table_size]; + let mut blue_table = vec![0.0; table_size]; + + for i in 0..table_size { + let value = (i as f32) / (table_size as f32 - 1.0); + red_table[i] = (value * gamma.red as f32).min(1.0); + green_table[i] = (value * gamma.green as f32).min(1.0); + blue_table[i] = (value * gamma.blue as f32).min(1.0); + } + + unsafe { + CGSetDisplayTransferByTable( + main_display.id, + table_size as u32, + red_table.as_ptr(), + green_table.as_ptr(), + blue_table.as_ptr(), + ); + } +} |
