randR method added for actual integration with X11 #7
@@ -7,3 +7,4 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
x11rb = { version = "0.13", features = ["randr"] }
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
/// X11 RandR gamma adjustment method
|
||||
/// Ported from legacy/src/gamma-randr.c
|
||||
|
||||
use crate::colorramp::colorramp_fill;
|
||||
use crate::gamma::GammaMethod;
|
||||
use crate::types::ColorSetting;
|
||||
use std::fmt;
|
||||
use x11rb::connection::Connection;
|
||||
use x11rb::protocol::randr;
|
||||
use x11rb::protocol::xproto;
|
||||
use x11rb::rust_connection::RustConnection;
|
||||
|
||||
const RANDR_VERSION_MAJOR: u32 = 1;
|
||||
const RANDR_VERSION_MINOR: u32 = 3;
|
||||
|
||||
/// State for a single CRTC
|
||||
struct CrtcState {
|
||||
crtc: randr::Crtc,
|
||||
ramp_size: u16,
|
||||
saved_ramps: Vec<u16>, // R, G, B ramps concatenated (3 * ramp_size)
|
||||
}
|
||||
|
||||
/// X11 RandR gamma adjustment method
|
||||
pub struct RandrGammaMethod {
|
||||
conn: Option<RustConnection>,
|
||||
screen_num: Option<i32>,
|
||||
preferred_screen: usize,
|
||||
crtc_filter: Vec<usize>, // If non-empty, only adjust these CRTC indices
|
||||
crtcs: Vec<CrtcState>,
|
||||
}
|
||||
|
||||
impl RandrGammaMethod {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
conn: None,
|
||||
screen_num: None,
|
||||
preferred_screen: 0,
|
||||
crtc_filter: Vec::new(),
|
||||
crtcs: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set which screen to use (None = use default)
|
||||
pub fn set_screen(&mut self, screen: i32) {
|
||||
self.screen_num = Some(screen);
|
||||
}
|
||||
|
||||
/// Set which CRTCs to adjust (empty = all)
|
||||
pub fn set_crtcs(&mut self, crtc_indices: Vec<usize>) {
|
||||
self.crtc_filter = crtc_indices;
|
||||
}
|
||||
|
||||
fn get_screen_root(&self) -> Result<xproto::Window, String> {
|
||||
let conn = self.conn.as_ref().ok_or("Not connected to X server")?;
|
||||
|
||||
let screen_num = self.screen_num.unwrap_or(self.preferred_screen as i32);
|
||||
let setup = conn.setup();
|
||||
let screen = setup
|
||||
.roots
|
||||
.get(screen_num as usize)
|
||||
.ok_or_else(|| format!("Screen {} could not be found", screen_num))?;
|
||||
|
||||
Ok(screen.root)
|
||||
}
|
||||
|
||||
fn set_temperature_for_crtc(
|
||||
&self,
|
||||
crtc_state: &CrtcState,
|
||||
setting: &ColorSetting,
|
||||
preserve: bool,
|
||||
) -> Result<(), String> {
|
||||
let conn = self.conn.as_ref().ok_or("Not connected to X server")?;
|
||||
let ramp_size = crtc_state.ramp_size as usize;
|
||||
|
||||
/* Create new gamma ramps */
|
||||
let mut gamma_r = vec![0u16; ramp_size];
|
||||
let mut gamma_g = vec![0u16; ramp_size];
|
||||
let mut gamma_b = vec![0u16; ramp_size];
|
||||
|
||||
if preserve {
|
||||
/* Initialize from saved state */
|
||||
gamma_r.copy_from_slice(&crtc_state.saved_ramps[0..ramp_size]);
|
||||
gamma_g.copy_from_slice(&crtc_state.saved_ramps[ramp_size..2 * ramp_size]);
|
||||
gamma_b.copy_from_slice(&crtc_state.saved_ramps[2 * ramp_size..3 * ramp_size]);
|
||||
} else {
|
||||
/* Initialize to linear (pure state) */
|
||||
for i in 0..ramp_size {
|
||||
let value = ((i as f64 / ramp_size as f64) * 65536.0) as u16;
|
||||
gamma_r[i] = value;
|
||||
gamma_g[i] = value;
|
||||
gamma_b[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply color temperature adjustment */
|
||||
colorramp_fill(&mut gamma_r, &mut gamma_g, &mut gamma_b, setting);
|
||||
|
||||
/* Set gamma ramps */
|
||||
randr::set_crtc_gamma(
|
||||
conn,
|
||||
crtc_state.crtc,
|
||||
&gamma_r,
|
||||
&gamma_g,
|
||||
&gamma_b,
|
||||
)
|
||||
.map_err(|e| format!("Failed to set CRTC gamma: {}", e))?
|
||||
.check()
|
||||
.map_err(|e| format!("RANDR Set CRTC Gamma returned error: {:?}", e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RandrGammaMethod {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl GammaMethod for RandrGammaMethod {
|
||||
fn init(&mut self) -> Result<(), String> {
|
||||
/* Open X server connection */
|
||||
let (conn, preferred_screen) = RustConnection::connect(None)
|
||||
.map_err(|e| format!("Failed to connect to X server: {}", e))?;
|
||||
|
||||
self.preferred_screen = preferred_screen;
|
||||
|
||||
/* Query RandR version */
|
||||
let ver_reply = randr::query_version(&conn, RANDR_VERSION_MAJOR, RANDR_VERSION_MINOR)
|
||||
.map_err(|e| format!("Failed to query RANDR version: {}", e))?
|
||||
.reply()
|
||||
.map_err(|e| format!("RANDR Query Version returned error: {}", e))?;
|
||||
|
||||
if ver_reply.major_version != RANDR_VERSION_MAJOR
|
||||
|| ver_reply.minor_version < RANDR_VERSION_MINOR
|
||||
{
|
||||
return Err(format!(
|
||||
"Unsupported RANDR version ({}.{})",
|
||||
ver_reply.major_version, ver_reply.minor_version
|
||||
));
|
||||
}
|
||||
|
||||
self.conn = Some(conn);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start(&mut self) -> Result<(), String> {
|
||||
let conn = self.conn.as_ref().ok_or("Not initialized")?;
|
||||
let root = self.get_screen_root()?;
|
||||
|
||||
/* Get screen resources (list of CRTCs) */
|
||||
let res_reply = randr::get_screen_resources_current(conn, root)
|
||||
.map_err(|e| format!("Failed to get screen resources: {}", e))?
|
||||
.reply()
|
||||
.map_err(|e| format!("RANDR Get Screen Resources Current returned error: {}", e))?;
|
||||
|
||||
let crtcs = res_reply.crtcs;
|
||||
|
||||
/* Save CRTC state and gamma ramps */
|
||||
for crtc in crtcs {
|
||||
/* Get gamma ramp size */
|
||||
let gamma_size_reply = randr::get_crtc_gamma_size(conn, crtc)
|
||||
.map_err(|e| format!("Failed to get CRTC gamma size: {}", e))?
|
||||
.reply()
|
||||
.map_err(|e| format!("RANDR Get CRTC Gamma Size returned error: {}", e))?;
|
||||
|
||||
let ramp_size = gamma_size_reply.size;
|
||||
|
||||
if ramp_size == 0 {
|
||||
eprintln!("Warning: CRTC has gamma ramp size 0, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get current gamma ramps */
|
||||
let gamma_get_reply = randr::get_crtc_gamma(conn, crtc)
|
||||
.map_err(|e| format!("Failed to get CRTC gamma: {}", e))?
|
||||
.reply()
|
||||
.map_err(|e| format!("RANDR Get CRTC Gamma returned error: {}", e))?;
|
||||
|
||||
/* Save gamma ramps (R, G, B concatenated) */
|
||||
let mut saved_ramps = Vec::with_capacity(3 * ramp_size as usize);
|
||||
saved_ramps.extend_from_slice(&gamma_get_reply.red);
|
||||
saved_ramps.extend_from_slice(&gamma_get_reply.green);
|
||||
saved_ramps.extend_from_slice(&gamma_get_reply.blue);
|
||||
|
||||
self.crtcs.push(CrtcState {
|
||||
crtc,
|
||||
ramp_size,
|
||||
saved_ramps,
|
||||
});
|
||||
}
|
||||
|
||||
if self.crtcs.is_empty() {
|
||||
return Err("No usable CRTCs found".to_string());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_temperature(&mut self, setting: &ColorSetting, preserve: bool) -> Result<(), String> {
|
||||
/* If no CRTC filter is set, adjust all CRTCs */
|
||||
if self.crtc_filter.is_empty() {
|
||||
for crtc_state in &self.crtcs {
|
||||
self.set_temperature_for_crtc(crtc_state, setting, preserve)?;
|
||||
}
|
||||
} else {
|
||||
/* Only adjust specified CRTCs */
|
||||
for &crtc_idx in &self.crtc_filter {
|
||||
if crtc_idx >= self.crtcs.len() {
|
||||
return Err(format!(
|
||||
"CRTC {} does not exist. Valid CRTCs are [0-{}]",
|
||||
crtc_idx,
|
||||
self.crtcs.len() - 1
|
||||
));
|
||||
}
|
||||
self.set_temperature_for_crtc(&self.crtcs[crtc_idx], setting, preserve)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn restore(&mut self) {
|
||||
if let Some(conn) = &self.conn {
|
||||
/* Restore original gamma ramps for all CRTCs */
|
||||
for crtc_state in &self.crtcs {
|
||||
let ramp_size = crtc_state.ramp_size as usize;
|
||||
let gamma_r = &crtc_state.saved_ramps[0..ramp_size];
|
||||
let gamma_g = &crtc_state.saved_ramps[ramp_size..2 * ramp_size];
|
||||
let gamma_b = &crtc_state.saved_ramps[2 * ramp_size..3 * ramp_size];
|
||||
|
||||
match randr::set_crtc_gamma(conn, crtc_state.crtc, gamma_r, gamma_g, gamma_b) {
|
||||
Ok(cookie) => {
|
||||
if let Err(e) = cookie.check() {
|
||||
eprintln!("Warning: Failed to restore CRTC gamma: {:?}", e);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Warning: Failed to send restore CRTC gamma request: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"randr"
|
||||
}
|
||||
|
||||
fn print_help(&self) {
|
||||
println!("Adjust gamma ramps with the X RANDR extension.");
|
||||
println!();
|
||||
println!(" screen=N X screen to apply adjustments to");
|
||||
println!(" crtc=N List of comma separated CRTCs to apply adjustments to");
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RandrGammaMethod {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "RandR")
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RandrGammaMethod {
|
||||
fn drop(&mut self) {
|
||||
self.restore();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod colorramp;
|
||||
pub mod gamma;
|
||||
pub mod gamma_randr;
|
||||
pub mod location;
|
||||
pub mod solar;
|
||||
pub mod types;
|
||||
|
||||
+5
-1
@@ -1,11 +1,13 @@
|
||||
mod colorramp;
|
||||
mod gamma;
|
||||
mod gamma_randr;
|
||||
mod location;
|
||||
mod solar;
|
||||
mod types;
|
||||
|
||||
use clap::{Parser, ValueEnum};
|
||||
use gamma::{DummyGammaMethod, GammaMethod};
|
||||
use gamma_randr::RandrGammaMethod;
|
||||
use location::{LocationProvider, ManualLocationProvider};
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use types::*;
|
||||
@@ -19,6 +21,7 @@ const FADE_LENGTH: i32 = 40;
|
||||
|
||||
#[derive(Debug, Clone, Copy, ValueEnum)]
|
||||
enum GammaMethodChoice {
|
||||
Randr,
|
||||
Dummy,
|
||||
}
|
||||
|
||||
@@ -31,7 +34,7 @@ struct Args {
|
||||
location: Option<String>,
|
||||
|
||||
/// Gamma adjustment method
|
||||
#[arg(short = 'm', long, default_value = "dummy")]
|
||||
#[arg(short = 'm', long, default_value = "randr")]
|
||||
method: GammaMethodChoice,
|
||||
|
||||
/// One-shot mode (set temperature and exit)
|
||||
@@ -239,6 +242,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
/* Set up gamma method */
|
||||
let mut gamma_method: Box<dyn GammaMethod> = match args.method {
|
||||
GammaMethodChoice::Randr => Box::new(RandrGammaMethod::new()),
|
||||
GammaMethodChoice::Dummy => Box::new(DummyGammaMethod::new()),
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
use redshift_rebooted::gamma::GammaMethod;
|
||||
use redshift_rebooted::gamma_randr::RandrGammaMethod;
|
||||
use redshift_rebooted::types::*;
|
||||
|
||||
#[test]
|
||||
fn test_randr_gamma_method_creation() {
|
||||
// Test that RandrGammaMethod can be created
|
||||
let method = RandrGammaMethod::new();
|
||||
assert_eq!(method.name(), "randr", "RandrGammaMethod name should be 'randr'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_randr_gamma_method_default() {
|
||||
// Test that RandrGammaMethod can be created with Default trait
|
||||
let method = RandrGammaMethod::default();
|
||||
assert_eq!(method.name(), "randr", "Default RandrGammaMethod name should be 'randr'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_randr_gamma_method_display_trait() {
|
||||
let method = RandrGammaMethod::new();
|
||||
let display_string = format!("{}", method);
|
||||
assert_eq!(display_string, "RandR", "RandrGammaMethod should display as 'RandR'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_randr_gamma_method_init_no_display() {
|
||||
// Test init when DISPLAY is not set or X11 is not available
|
||||
// This may fail gracefully or succeed depending on environment
|
||||
let mut method = RandrGammaMethod::new();
|
||||
|
||||
// We don't assert success/failure here because it depends on environment
|
||||
// Just verify it doesn't panic
|
||||
let _ = method.init();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_randr_gamma_method_set_screen() {
|
||||
// Test the set_screen configuration method
|
||||
let mut method = RandrGammaMethod::new();
|
||||
method.set_screen(0);
|
||||
// If we got here without panicking, the method works
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_randr_gamma_method_set_crtcs() {
|
||||
// Test the set_crtcs configuration method
|
||||
let mut method = RandrGammaMethod::new();
|
||||
method.set_crtcs(vec![0, 1]);
|
||||
// If we got here without panicking, the method works
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_randr_gamma_method_restore_without_init() {
|
||||
// Test that restore doesn't panic even if not initialized
|
||||
let mut method = RandrGammaMethod::new();
|
||||
method.restore();
|
||||
// Should not panic
|
||||
}
|
||||
|
||||
// Integration test - only runs if X11 is available
|
||||
#[test]
|
||||
#[ignore] // Use `cargo test -- --ignored` to run this
|
||||
fn test_randr_gamma_method_full_lifecycle_x11() {
|
||||
// This test requires X11 to be available
|
||||
let mut method = RandrGammaMethod::new();
|
||||
|
||||
// Try to initialize
|
||||
if method.init().is_err() {
|
||||
eprintln!("X11 not available, skipping integration test");
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to start
|
||||
if method.start().is_err() {
|
||||
eprintln!("Could not start RandR method, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to set a temperature
|
||||
let setting = ColorSetting {
|
||||
temperature: 5000,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
if let Err(e) = method.set_temperature(&setting, false) {
|
||||
eprintln!("Could not set temperature: {}", e);
|
||||
}
|
||||
|
||||
// Restore
|
||||
method.restore();
|
||||
}
|
||||
|
||||
// Integration test - test preserve flag
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_randr_gamma_method_preserve_flag_x11() {
|
||||
let mut method = RandrGammaMethod::new();
|
||||
|
||||
if method.init().is_err() || method.start().is_err() {
|
||||
eprintln!("X11 not available, skipping integration test");
|
||||
return;
|
||||
}
|
||||
|
||||
let setting = ColorSetting {
|
||||
temperature: 4000,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 0.9,
|
||||
};
|
||||
|
||||
// Test without preserve
|
||||
if let Err(e) = method.set_temperature(&setting, false) {
|
||||
eprintln!("Could not set temperature without preserve: {}", e);
|
||||
}
|
||||
|
||||
// Test with preserve
|
||||
if let Err(e) = method.set_temperature(&setting, true) {
|
||||
eprintln!("Could not set temperature with preserve: {}", e);
|
||||
}
|
||||
|
||||
method.restore();
|
||||
}
|
||||
|
||||
// Integration test - test multiple temperature changes
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_randr_gamma_method_multiple_changes_x11() {
|
||||
let mut method = RandrGammaMethod::new();
|
||||
|
||||
if method.init().is_err() || method.start().is_err() {
|
||||
eprintln!("X11 not available, skipping integration test");
|
||||
return;
|
||||
}
|
||||
|
||||
let temperatures = [6500, 5000, 3500, 4500, 6500];
|
||||
|
||||
for temp in temperatures {
|
||||
let setting = ColorSetting {
|
||||
temperature: temp,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
if let Err(e) = method.set_temperature(&setting, false) {
|
||||
eprintln!("Could not set temperature {}: {}", temp, e);
|
||||
}
|
||||
}
|
||||
|
||||
method.restore();
|
||||
}
|
||||
|
||||
// Integration test - test extreme temperatures
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_randr_gamma_method_extreme_temperatures_x11() {
|
||||
let mut method = RandrGammaMethod::new();
|
||||
|
||||
if method.init().is_err() || method.start().is_err() {
|
||||
eprintln!("X11 not available, skipping integration test");
|
||||
return;
|
||||
}
|
||||
|
||||
// Test minimum temperature
|
||||
let min_setting = ColorSetting {
|
||||
temperature: MIN_TEMP,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
if let Err(e) = method.set_temperature(&min_setting, false) {
|
||||
eprintln!("Could not set minimum temperature: {}", e);
|
||||
}
|
||||
|
||||
// Test maximum temperature
|
||||
let max_setting = ColorSetting {
|
||||
temperature: MAX_TEMP,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
if let Err(e) = method.set_temperature(&max_setting, false) {
|
||||
eprintln!("Could not set maximum temperature: {}", e);
|
||||
}
|
||||
|
||||
// Restore to neutral
|
||||
let neutral_setting = ColorSetting {
|
||||
temperature: NEUTRAL_TEMP,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
if let Err(e) = method.set_temperature(&neutral_setting, false) {
|
||||
eprintln!("Could not restore neutral temperature: {}", e);
|
||||
}
|
||||
|
||||
method.restore();
|
||||
}
|
||||
|
||||
// Integration test - test various gamma values
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_randr_gamma_method_gamma_values_x11() {
|
||||
let mut method = RandrGammaMethod::new();
|
||||
|
||||
if method.init().is_err() || method.start().is_err() {
|
||||
eprintln!("X11 not available, skipping integration test");
|
||||
return;
|
||||
}
|
||||
|
||||
let gamma_values = [
|
||||
[1.0, 1.0, 1.0],
|
||||
[0.8, 0.8, 0.8],
|
||||
[1.2, 1.2, 1.2],
|
||||
[1.0, 0.9, 0.9],
|
||||
];
|
||||
|
||||
for gamma in gamma_values {
|
||||
let setting = ColorSetting {
|
||||
temperature: 6500,
|
||||
gamma,
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
if let Err(e) = method.set_temperature(&setting, false) {
|
||||
eprintln!("Could not set gamma {:?}: {}", gamma, e);
|
||||
}
|
||||
}
|
||||
|
||||
method.restore();
|
||||
}
|
||||
|
||||
// Integration test - test brightness values
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_randr_gamma_method_brightness_values_x11() {
|
||||
let mut method = RandrGammaMethod::new();
|
||||
|
||||
if method.init().is_err() || method.start().is_err() {
|
||||
eprintln!("X11 not available, skipping integration test");
|
||||
return;
|
||||
}
|
||||
|
||||
let brightness_values = [1.0, 0.8, 0.6, 0.9, 1.0];
|
||||
|
||||
for brightness in brightness_values {
|
||||
let setting = ColorSetting {
|
||||
temperature: 6500,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness,
|
||||
};
|
||||
|
||||
if let Err(e) = method.set_temperature(&setting, false) {
|
||||
eprintln!("Could not set brightness {}: {}", brightness, e);
|
||||
}
|
||||
}
|
||||
|
||||
method.restore();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_randr_gamma_method_as_trait_object() {
|
||||
// Test that RandrGammaMethod can be used as a trait object
|
||||
let method: Box<dyn GammaMethod> = Box::new(RandrGammaMethod::new());
|
||||
assert_eq!(method.name(), "randr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_randr_gamma_method_drop() {
|
||||
// Test that RandrGammaMethod's Drop implementation doesn't panic
|
||||
{
|
||||
let _method = RandrGammaMethod::new();
|
||||
// When _method goes out of scope, Drop should run
|
||||
}
|
||||
// If we got here, Drop didn't panic
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
use redshift_rebooted::gamma::*;
|
||||
use redshift_rebooted::types::*;
|
||||
|
||||
#[test]
|
||||
fn test_dummy_gamma_method_lifecycle() {
|
||||
// Test that DummyGammaMethod can be initialized and started
|
||||
let mut method = DummyGammaMethod::new();
|
||||
|
||||
// Init should succeed
|
||||
assert!(method.init().is_ok(), "DummyGammaMethod init should succeed");
|
||||
|
||||
// Start should succeed
|
||||
assert!(method.start().is_ok(), "DummyGammaMethod start should succeed");
|
||||
|
||||
// Name should be "dummy"
|
||||
assert_eq!(method.name(), "dummy", "DummyGammaMethod name should be 'dummy'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dummy_gamma_method_set_temperature() {
|
||||
let mut method = DummyGammaMethod::new();
|
||||
method.init().unwrap();
|
||||
method.start().unwrap();
|
||||
|
||||
// Create a color setting
|
||||
let setting = ColorSetting {
|
||||
temperature: 3500,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
// Set temperature should succeed (even though it's a no-op)
|
||||
assert!(
|
||||
method.set_temperature(&setting, false).is_ok(),
|
||||
"DummyGammaMethod set_temperature should succeed"
|
||||
);
|
||||
|
||||
// Test with preserve flag
|
||||
assert!(
|
||||
method.set_temperature(&setting, true).is_ok(),
|
||||
"DummyGammaMethod set_temperature with preserve should succeed"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dummy_gamma_method_restore() {
|
||||
let mut method = DummyGammaMethod::new();
|
||||
method.init().unwrap();
|
||||
method.start().unwrap();
|
||||
|
||||
// Restore should not panic (it's a no-op for dummy)
|
||||
method.restore();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dummy_gamma_method_various_temperatures() {
|
||||
let mut method = DummyGammaMethod::new();
|
||||
method.init().unwrap();
|
||||
method.start().unwrap();
|
||||
|
||||
// Test with various temperature values
|
||||
let temperatures = [1000, 2500, 3500, 5000, 6500, 10000, 25000];
|
||||
|
||||
for temp in temperatures {
|
||||
let setting = ColorSetting {
|
||||
temperature: temp,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
assert!(
|
||||
method.set_temperature(&setting, false).is_ok(),
|
||||
"DummyGammaMethod should handle temperature {}K",
|
||||
temp
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dummy_gamma_method_various_gamma_values() {
|
||||
let mut method = DummyGammaMethod::new();
|
||||
method.init().unwrap();
|
||||
method.start().unwrap();
|
||||
|
||||
// Test with various gamma values
|
||||
let gamma_values = [
|
||||
[0.5, 0.5, 0.5],
|
||||
[1.0, 1.0, 1.0],
|
||||
[1.5, 1.5, 1.5],
|
||||
[1.0, 0.8, 0.8],
|
||||
];
|
||||
|
||||
for gamma in gamma_values {
|
||||
let setting = ColorSetting {
|
||||
temperature: 6500,
|
||||
gamma,
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
assert!(
|
||||
method.set_temperature(&setting, false).is_ok(),
|
||||
"DummyGammaMethod should handle gamma {:?}",
|
||||
gamma
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dummy_gamma_method_various_brightness_values() {
|
||||
let mut method = DummyGammaMethod::new();
|
||||
method.init().unwrap();
|
||||
method.start().unwrap();
|
||||
|
||||
// Test with various brightness values
|
||||
let brightness_values = [0.1, 0.5, 0.75, 1.0];
|
||||
|
||||
for brightness in brightness_values {
|
||||
let setting = ColorSetting {
|
||||
temperature: 6500,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness,
|
||||
};
|
||||
|
||||
assert!(
|
||||
method.set_temperature(&setting, false).is_ok(),
|
||||
"DummyGammaMethod should handle brightness {}",
|
||||
brightness
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dummy_gamma_method_multiple_calls() {
|
||||
let mut method = DummyGammaMethod::new();
|
||||
method.init().unwrap();
|
||||
method.start().unwrap();
|
||||
|
||||
// Test calling set_temperature multiple times (simulating continual mode)
|
||||
let setting1 = ColorSetting {
|
||||
temperature: 6500,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
let setting2 = ColorSetting {
|
||||
temperature: 3500,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
assert!(method.set_temperature(&setting1, false).is_ok());
|
||||
assert!(method.set_temperature(&setting2, false).is_ok());
|
||||
assert!(method.set_temperature(&setting1, false).is_ok());
|
||||
assert!(method.set_temperature(&setting2, false).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gamma_method_trait_object() {
|
||||
// Test that GammaMethod can be used as a trait object
|
||||
let mut method: Box<dyn GammaMethod> = Box::new(DummyGammaMethod::new());
|
||||
|
||||
assert!(method.init().is_ok());
|
||||
assert!(method.start().is_ok());
|
||||
|
||||
let setting = ColorSetting {
|
||||
temperature: 4500,
|
||||
gamma: [1.0, 1.0, 1.0],
|
||||
brightness: 1.0,
|
||||
};
|
||||
|
||||
assert!(method.set_temperature(&setting, false).is_ok());
|
||||
method.restore();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gamma_method_default_color_setting() {
|
||||
let mut method = DummyGammaMethod::new();
|
||||
method.init().unwrap();
|
||||
method.start().unwrap();
|
||||
|
||||
// Test with default ColorSetting
|
||||
let setting = ColorSetting::default();
|
||||
|
||||
assert_eq!(setting.temperature, NEUTRAL_TEMP);
|
||||
assert_eq!(setting.gamma, [1.0, 1.0, 1.0]);
|
||||
assert_eq!(setting.brightness, 1.0);
|
||||
|
||||
assert!(
|
||||
method.set_temperature(&setting, false).is_ok(),
|
||||
"DummyGammaMethod should handle default ColorSetting"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dummy_gamma_method_display_trait() {
|
||||
let method = DummyGammaMethod::new();
|
||||
let display_string = format!("{}", method);
|
||||
assert_eq!(display_string, "Dummy", "DummyGammaMethod should display as 'Dummy'");
|
||||
}
|
||||
Reference in New Issue
Block a user