From 800c0d3fc4c4cd9a61c8495c5e690bc089b97442 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Sun, 7 May 2023 01:18:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=88=97=E5=87=BA?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=99=A8=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/Cargo.lock | 307 +++++++++++++++- src-tauri/Cargo.toml | 1 + .../{display_config.rs => display_state.rs} | 8 +- src-tauri/src/display/manager.rs | 327 ++++++++++-------- src-tauri/src/display/mod.rs | 7 +- src-tauri/src/main.rs | 9 + src/App.tsx | 3 + .../displays/display-state-card.tsx | 36 ++ .../displays/display-state-index.tsx | 52 +++ src/models/display-state.model.ts | 16 + 10 files changed, 594 insertions(+), 172 deletions(-) rename src-tauri/src/display/{display_config.rs => display_state.rs} (84%) create mode 100644 src/components/displays/display-state-card.tsx create mode 100644 src/components/displays/display-state-index.tsx create mode 100644 src/models/display-state.model.ts diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 04e9739..f2fcfba 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -14,7 +14,7 @@ version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ - "memchr", + "memchr 2.5.0", ] [[package]] @@ -23,7 +23,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" dependencies = [ - "memchr", + "memchr 2.5.0", ] [[package]] @@ -157,7 +157,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" dependencies = [ - "memchr", + "memchr 2.5.0", "serde", ] @@ -349,7 +349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ "bytes", - "memchr", + "memchr 2.5.0", ] [[package]] @@ -373,10 +373,16 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.4", "libc", ] +[[package]] +name = "core-foundation-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -571,6 +577,72 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "ddc" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba69f2c53e320fc4abad17cb02bbbf04d1a36f18e9907f347589ec5991b3c6c5" +dependencies = [ + "mccs", +] + +[[package]] +name = "ddc-hi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6747b17c926a2aa34739b30f1a6cc726e3a7baf0e2f69a4c03a95cf5de94de" +dependencies = [ + "anyhow", + "ddc", + "ddc-i2c", + "ddc-macos", + "ddc-winapi", + "edid", + "log", + "mccs", + "mccs-caps", + "mccs-db", + "nvapi", +] + +[[package]] +name = "ddc-i2c" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ef18fac9fd5c11d0c7b85a80887b01f7361b49edb2b4627243928b90ce2691b" +dependencies = [ + "ddc", + "i2c", + "i2c-linux", + "resize-slice", +] + +[[package]] +name = "ddc-macos" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cbaf316c113cfc30da8856c8104dfb4168b73fdd78562d1542e358fe8299dea" +dependencies = [ + "core-foundation", + "core-foundation-sys 0.8.4", + "core-graphics", + "ddc", + "io-kit-sys", + "mach 0.3.2", + "thiserror", +] + +[[package]] +name = "ddc-winapi" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "015df0d6d814ea948e012977760324da6d103ec8d67c971c75a6daa3b4fc943f" +dependencies = [ + "ddc", + "widestring", + "winapi", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -656,6 +728,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +[[package]] +name = "edid" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ce75530893d834dcfe3bb67ce0e7dec489484e7cb4423ca31618af4bab24fe" +dependencies = [ + "nom", +] + [[package]] name = "either" version = "1.8.1" @@ -921,7 +1002,7 @@ dependencies = [ "futures-macro", "futures-sink", "futures-task", - "memchr", + "memchr 2.5.0", "pin-project-lite", "pin-utils", "slab", @@ -1292,6 +1373,39 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "i2c" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60c7b7bdd7b3a985fdcf94a0d7d98e7a47fde8b7f22fb55ce1a91cc104a2ce9a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "i2c-linux" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0268a871aaa071221d6c2875ebedcf64710e59b0d87c68c8faf5e98b87dd2a4" +dependencies = [ + "bitflags", + "i2c", + "i2c-linux-sys", + "resize-slice", + "udev", +] + +[[package]] +name = "i2c-linux-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cd060ed0016621d3da4ed3a23b0158084de90d1f3a8e59f3d391aacd3bbcf8" +dependencies = [ + "bitflags", + "byteorder", + "libc", +] + [[package]] name = "iana-time-zone" version = "0.1.56" @@ -1299,7 +1413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" dependencies = [ "android_system_properties", - "core-foundation-sys", + "core-foundation-sys 0.8.4", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", @@ -1362,7 +1476,7 @@ dependencies = [ "globset", "lazy_static", "log", - "memchr", + "memchr 2.5.0", "regex", "same-file", "thread_local", @@ -1412,6 +1526,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-kit-sys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f21dcc74995dd4cd090b147e79789f8d65959cbfb5f0b118002db869ea3bd0a0" +dependencies = [ + "core-foundation-sys 0.6.2", + "mach 0.2.3", +] + [[package]] name = "io-lifetimes" version = "1.0.10" @@ -1555,6 +1679,16 @@ version = "0.2.142" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "line-wrap" version = "0.1.1" @@ -1573,6 +1707,12 @@ dependencies = [ "cc", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.3.7" @@ -1619,6 +1759,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "mach" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" +dependencies = [ + "libc", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -1657,6 +1815,38 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "mccs" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6090d6b3ded42fed158b660a6b9cdaa1924f3eef6c6598e82a9ca9b70a1988cd" +dependencies = [ + "void", +] + +[[package]] +name = "mccs-caps" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb961d01a3bb07969cfa276be2ab88c31d0fefa77a872696832732d6e9ec094" +dependencies = [ + "mccs", + "nom", +] + +[[package]] +name = "mccs-db" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cdaa8fe19a1a1918becc1b8cbbbdc1058bc71411dff4de0a6ec6b5269f49d38" +dependencies = [ + "mccs", + "nom", + "serde", + "serde_derive", + "serde_yaml", +] + [[package]] name = "mdns-sd" version = "0.7.3" @@ -1670,6 +1860,15 @@ dependencies = [ "socket2", ] +[[package]] +name = "memchr" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" +dependencies = [ + "libc", +] + [[package]] name = "memchr" version = "2.5.0" @@ -1747,6 +1946,15 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "nom" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" +dependencies = [ + "memchr 1.0.2", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1818,6 +2026,28 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "nvapi" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c63de8cd8362e2c38d1a48dea6ae68e6293a8d8d22a52180d0f8dcc779b3158" +dependencies = [ + "i2c", + "log", + "nvapi-sys", + "void", +] + +[[package]] +name = "nvapi-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b29e9a9393c69ee856bfcf5f76ed1ef32d2c0dd6f58558fd43334278fc1e7ea7" +dependencies = [ + "bitflags", + "winapi", +] + [[package]] name = "objc" version = "0.2.7" @@ -2224,7 +2454,7 @@ version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" dependencies = [ - "memchr", + "memchr 2.5.0", ] [[package]] @@ -2359,7 +2589,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ "aho-corasick 1.0.1", - "memchr", + "memchr 2.5.0", "regex-syntax 0.7.1", ] @@ -2384,6 +2614,15 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +[[package]] +name = "resize-slice" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3cb2f74a9891e76958b9e0ccd269a25b466c3ae3bb3efd71db157248308c4a" +dependencies = [ + "uninitialized", +] + [[package]] name = "rustc_version" version = "0.4.0" @@ -2560,6 +2799,18 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "serde_yaml" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8099d3df28273c99a1728190c7a9f19d444c941044f64adf986bee7ec53051" +dependencies = [ + "dtoa", + "linked-hash-map", + "serde", + "yaml-rust", +] + [[package]] name = "serialize-to-javascript" version = "0.1.1" @@ -3014,7 +3265,7 @@ dependencies = [ "infer", "json-patch 1.0.0", "kuchiki", - "memchr", + "memchr 2.5.0", "phf 0.10.1", "proc-macro2", "quote", @@ -3079,6 +3330,7 @@ dependencies = [ "color_space", "core-foundation", "core-graphics", + "ddc-hi", "display-info", "env_logger", "futures", @@ -3348,6 +3600,16 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "udev" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47504d1a49b2ea1b133e7ddd1d9f0a83cf03feb9b440c2c470d06db4589cf301" +dependencies = [ + "libc", + "libudev-sys", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -3381,6 +3643,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "uninitialized" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74c1aa4511c38276c548406f0b1f5f8b793f000cfb51e18f278a102abd057e81" + [[package]] name = "url" version = "2.3.1" @@ -3453,6 +3721,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "vswhom" version = "0.1.0" @@ -3918,7 +4192,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" dependencies = [ - "memchr", + "memchr 2.5.0", ] [[package]] @@ -4009,3 +4283,12 @@ dependencies = [ "libc", "quick-xml", ] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 38390b5..9d7ad0d 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -35,6 +35,7 @@ core-foundation = "0.9.3" tokio-stream = "0.1.14" mdns-sd = "0.7.2" futures = "0.3.28" +ddc-hi = "0.4.1" [features] # this feature is used for production builds or when `devPath` points to the filesystem diff --git a/src-tauri/src/display/display_config.rs b/src-tauri/src/display/display_state.rs similarity index 84% rename from src-tauri/src/display/display_config.rs rename to src-tauri/src/display/display_state.rs index b14c0c4..315df69 100644 --- a/src-tauri/src/display/display_config.rs +++ b/src-tauri/src/display/display_state.rs @@ -3,8 +3,7 @@ use std::time::SystemTime; use serde::{Deserialize, Serialize}; #[derive(Clone, Copy, Serialize, Deserialize, Debug)] -pub struct DisplayConfig { - pub id: usize, +pub struct DisplayState { pub brightness: u16, pub max_brightness: u16, pub min_brightness: u16, @@ -17,10 +16,9 @@ pub struct DisplayConfig { pub last_modified_at: SystemTime, } -impl DisplayConfig { - pub fn default(index: usize) -> Self { +impl DisplayState { + pub fn default() -> Self { Self { - id: index, brightness: 30, contrast: 50, mode: 0, diff --git a/src-tauri/src/display/manager.rs b/src-tauri/src/display/manager.rs index 99627d0..7481cbc 100644 --- a/src-tauri/src/display/manager.rs +++ b/src-tauri/src/display/manager.rs @@ -6,182 +6,205 @@ use std::{ time::{Duration, SystemTime}, }; -use base64::Config; use ddc_hi::Display; use paris::{error, info, warn}; -use tauri::async_runtime::Mutex; -use tokio::sync::{broadcast, OwnedMutexGuard}; -use tracing::warn; +use tokio::sync::{OnceCell, OwnedMutexGuard, RwLock}; -use crate::{display::Brightness, models, rpc}; - -use super::{display_config::DisplayConfig, DisplayBrightness}; +use super::display_state::DisplayState; use ddc_hi::Ddc; -pub struct Manager { - displays: Arc>>>>, +pub struct DisplayHandler { + pub state: Arc>, + pub controller: Arc>, } -impl Manager { - pub fn global() -> &'static Self { - static DISPLAY_MANAGER: once_cell::sync::OnceCell = - once_cell::sync::OnceCell::new(); +pub struct DisplayManager { + displays: Arc>>>>, +} - DISPLAY_MANAGER.get_or_init(|| Self::create()) +impl DisplayManager { + pub async fn global() -> &'static Self { + static DISPLAY_MANAGER: OnceCell = OnceCell::const_new(); + + DISPLAY_MANAGER.get_or_init(|| Self::create()).await } - pub fn create() -> Self { + pub async fn create() -> Self { let instance = Self { - displays: Arc::new(Mutex::new(HashMap::new())), + displays: Arc::new(RwLock::new(Vec::new())), }; + instance.fetch_displays().await; instance } - pub async fn subscribe_display_brightness(&self) { - let rpc = rpc::Manager::global().await; + async fn fetch_displays(&self) { + let mut displays = self.displays.write().await; + displays.clear(); - let mut rx = rpc.client().subscribe_change_display_brightness_rx(); + let controllers = Display::enumerate(); - loop { - if let Ok(display_brightness) = rx.recv().await { - if let Err(err) = self.set_display_brightness(display_brightness).await { - error!("set_display_brightness failed. {:?}", err); - } - } + for display in controllers { + let controller = Arc::new(RwLock::new(display)); + let state = Arc::new(RwLock::new(DisplayState::default())); + displays.push(Arc::new(RwLock::new(DisplayHandler { controller, state }))); } } - fn read_display_config_by_ddc(index: usize) -> anyhow::Result { - let mut displays = Display::enumerate(); - match displays.get_mut(index) { - Some(display) => { - let mut config = DisplayConfig::default(index); - match display.handle.get_vcp_feature(0x10) { - Ok(value) => { - config.max_brightness = value.maximum(); - config.min_brightness = 0; - config.brightness = value.value(); - } - Err(_) => {} - }; - match display.handle.get_vcp_feature(0x12) { - Ok(value) => { - config.max_contrast = value.maximum(); - config.min_contrast = 0; - config.contrast = value.value(); - } - Err(_) => {} - }; - match display.handle.get_vcp_feature(0xdc) { - Ok(value) => { - config.max_mode = value.maximum(); - config.min_mode = 0; - config.mode = value.value(); - } - Err(_) => {} - }; - - Ok(config) - } - None => anyhow::bail!("display#{} is missed.", index), + pub async fn get_displays(&self) -> Vec { + let displays = self.displays.read().await; + let mut states = Vec::new(); + for display in displays.iter() { + let state = display.read().await.state.read().await.clone(); + states.push(state); } + states } - async fn get_display(&self, index: usize) -> anyhow::Result> { - let mut displays = self.displays.lock().await; - match displays.get_mut(&index) { - Some(config) => { - let mut config = config.to_owned().lock_owned().await; - if config.last_modified_at > SystemTime::now().sub(Duration::from_secs(10)) { - info!("cached"); - return Ok(config); - } - return match Self::read_display_config_by_ddc(index) { - Ok(config) => { - let id = config.id; - let value = Arc::new(Mutex::new(config)); - let valueGuard = value.clone().lock_owned().await; - displays.insert(id, value); - info!("read form ddc"); - Ok(valueGuard) - } - Err(err) => { - warn!( - "can not read config from display by ddc, use CACHED value. {:?}", - err - ); - config.last_modified_at = SystemTime::now(); - Ok(config) - } - }; - } - None => { - let config = Self::read_display_config_by_ddc(index).map_err(|err| { - anyhow::anyhow!( - "can not read config from display by ddc,use DEFAULT value. {:?}", - err - ) - })?; - let id = config.id; - let value = Arc::new(Mutex::new(config)); - let valueGuard = value.clone().lock_owned().await; - displays.insert(id, value); - Ok(valueGuard) - } - } - } + // pub async fn subscribe_display_brightness(&self) { + // let rpc = rpc::Manager::global().await; - pub async fn set_display_brightness( - &self, - display_brightness: DisplayBrightness, - ) -> anyhow::Result<()> { - match Display::enumerate().get_mut(display_brightness.display_index) { - Some(display) => { - match self.get_display(display_brightness.display_index).await { - Ok(mut config) => { - let curr = config.brightness; - info!("curr_brightness: {:?}", curr); - let mut target = match display_brightness.brightness { - Brightness::Relative(v) => curr.wrapping_add_signed(v), - Brightness::Absolute(v) => v, - }; - if target.gt(&config.max_brightness) { - target = config.max_brightness; - } else if target.lt(&config.min_brightness) { - target = config.min_brightness; - } - config.brightness = target; - display - .handle - .set_vcp_feature(0x10, target as u16) - .map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?; + // let mut rx = rpc.client().subscribe_change_display_brightness_rx(); - let rpc = rpc::Manager::global().await; + // loop { + // if let Ok(display_brightness) = rx.recv().await { + // if let Err(err) = self.set_display_brightness(display_brightness).await { + // error!("set_display_brightness failed. {:?}", err); + // } + // } + // } + // } - rpc.publish_desktop_cmd( - format!("display{}/brightness", display_brightness.display_index) - .as_str(), - target.to_be_bytes().to_vec(), - ) - .await; - } - Err(err) => { - info!( - "can not get display#{} brightness. {:?}", - display_brightness.display_index, err - ); - if let Brightness::Absolute(v) = display_brightness.brightness { - display.handle.set_vcp_feature(0x10, v).map_err(|err| { - anyhow::anyhow!("can not set brightness. {:?}", err) - })?; - }; - } - }; - } - None => { - warn!("display#{} is not found.", display_brightness.display_index); - } - } - Ok(()) - } + // fn read_display_config_by_ddc(index: usize) -> anyhow::Result { + // let mut displays = Display::enumerate(); + // match displays.get_mut(index) { + // Some(display) => { + // let mut config = DisplayState::default(index); + // match display.handle.get_vcp_feature(0x10) { + // Ok(value) => { + // config.max_brightness = value.maximum(); + // config.min_brightness = 0; + // config.brightness = value.value(); + // } + // Err(_) => {} + // }; + // match display.handle.get_vcp_feature(0x12) { + // Ok(value) => { + // config.max_contrast = value.maximum(); + // config.min_contrast = 0; + // config.contrast = value.value(); + // } + // Err(_) => {} + // }; + // match display.handle.get_vcp_feature(0xdc) { + // Ok(value) => { + // config.max_mode = value.maximum(); + // config.min_mode = 0; + // config.mode = value.value(); + // } + // Err(_) => {} + // }; + + // Ok(config) + // } + // None => anyhow::bail!("display#{} is missed.", index), + // } + // } + + // async fn get_display(&self, index: usize) -> anyhow::Result> { + // let mut displays = self.displays.lock().await; + // match displays.get_mut(&index) { + // Some(config) => { + // let mut config = config.to_owned().lock_owned().await; + // if config.last_modified_at > SystemTime::now().sub(Duration::from_secs(10)) { + // info!("cached"); + // return Ok(config); + // } + // return match Self::read_display_config_by_ddc(index) { + // Ok(config) => { + // let id = config.id; + // let value = Arc::new(Mutex::new(config)); + // let valueGuard = value.clone().lock_owned().await; + // displays.insert(id, value); + // info!("read form ddc"); + // Ok(valueGuard) + // } + // Err(err) => { + // warn!( + // "can not read config from display by ddc, use CACHED value. {:?}", + // err + // ); + // config.last_modified_at = SystemTime::now(); + // Ok(config) + // } + // }; + // } + // None => { + // let config = Self::read_display_config_by_ddc(index).map_err(|err| { + // anyhow::anyhow!( + // "can not read config from display by ddc,use DEFAULT value. {:?}", + // err + // ) + // })?; + // let id = config.id; + // let value = Arc::new(Mutex::new(config)); + // let valueGuard = value.clone().lock_owned().await; + // displays.insert(id, value); + // Ok(valueGuard) + // } + // } + // } + + // pub async fn set_display_brightness( + // &self, + // display_brightness: DisplayBrightness, + // ) -> anyhow::Result<()> { + // match Display::enumerate().get_mut(display_brightness.display_index) { + // Some(display) => { + // match self.get_display(display_brightness.display_index).await { + // Ok(mut config) => { + // let curr = config.brightness; + // info!("curr_brightness: {:?}", curr); + // let mut target = match display_brightness.brightness { + // Brightness::Relative(v) => curr.wrapping_add_signed(v), + // Brightness::Absolute(v) => v, + // }; + // if target.gt(&config.max_brightness) { + // target = config.max_brightness; + // } else if target.lt(&config.min_brightness) { + // target = config.min_brightness; + // } + // config.brightness = target; + // display + // .handle + // .set_vcp_feature(0x10, target as u16) + // .map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?; + + // let rpc = rpc::Manager::global().await; + + // rpc.publish_desktop_cmd( + // format!("display{}/brightness", display_brightness.display_index) + // .as_str(), + // target.to_be_bytes().to_vec(), + // ) + // .await; + // } + // Err(err) => { + // info!( + // "can not get display#{} brightness. {:?}", + // display_brightness.display_index, err + // ); + // if let Brightness::Absolute(v) = display_brightness.brightness { + // display.handle.set_vcp_feature(0x10, v).map_err(|err| { + // anyhow::anyhow!("can not set brightness. {:?}", err) + // })?; + // }; + // } + // }; + // } + // None => { + // warn!("display#{} is not found.", display_brightness.display_index); + // } + // } + // Ok(()) + // } } diff --git a/src-tauri/src/display/mod.rs b/src-tauri/src/display/mod.rs index 7d27b12..8499385 100644 --- a/src-tauri/src/display/mod.rs +++ b/src-tauri/src/display/mod.rs @@ -1,11 +1,12 @@ // mod brightness; // mod manager; -mod display_config; +mod display_state; +mod manager; -pub use display_config::*; +pub use display_state::*; // pub use brightness::*; -// pub use manager::*; +pub use manager::*; diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 8b17901..e30b2f2 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -9,6 +9,7 @@ pub mod screenshot; mod screenshot_manager; use ambient_light::{Border, ColorCalibration, LedStripConfig, LedStripConfigGroup}; +use display::{DisplayManager, DisplayState}; use display_info::DisplayInfo; use paris::{error, info, warn}; use rpc::{BoardInfo, MqttRpc, UdpRpc}; @@ -203,6 +204,13 @@ async fn get_boards() -> Result, String> { Ok(boards) } +#[tauri::command] +async fn get_displays() -> Vec { + let display_manager = DisplayManager::global().await; + + display_manager.get_displays().await +} + #[tokio::main] async fn main() { env_logger::init(); @@ -230,6 +238,7 @@ async fn main() { set_color_calibration, read_config, get_boards, + get_displays ]) .register_uri_scheme_protocol("ambient-light", move |_app, request| { let response = ResponseBuilder::new().header("Access-Control-Allow-Origin", "*"); diff --git a/src/App.tsx b/src/App.tsx index 9352b99..752360a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,6 +6,7 @@ import { invoke } from '@tauri-apps/api'; import { setLedStripStore } from './stores/led-strip.store'; import { LedStripConfigContainer } from './models/led-strip-config'; import { InfoIndex } from './components/info/info-index'; +import { DisplayStateIndex } from './components/displays/display-state-index'; function App() { createEffect(() => { @@ -23,11 +24,13 @@ function App() {
+ diff --git a/src/components/displays/display-state-card.tsx b/src/components/displays/display-state-card.tsx new file mode 100644 index 0000000..43234c9 --- /dev/null +++ b/src/components/displays/display-state-card.tsx @@ -0,0 +1,36 @@ +import { Component, ParentComponent } from 'solid-js'; +import { DisplayState } from '../../models/display-state.model'; + +type DisplayStateCardProps = { + state: DisplayState; +}; + +type ItemProps = { + label: string; +}; + +const Item: ParentComponent = (props) => { + return ( +
+
{props.label}
+
{props.children}
+
+ ); +}; + +export const DisplayStateCard: Component = (props) => { + return ( +
+ {props.state.brightness} + {props.state.max_brightness} + {props.state.min_brightness} + {props.state.contrast} + {props.state.max_contrast} + {props.state.min_contrast} + {props.state.max_mode} + {props.state.min_mode} + {props.state.mode} + {props.state.last_modified_at.toISOString()} +
+ ); +}; diff --git a/src/components/displays/display-state-index.tsx b/src/components/displays/display-state-index.tsx new file mode 100644 index 0000000..549e87c --- /dev/null +++ b/src/components/displays/display-state-index.tsx @@ -0,0 +1,52 @@ +import { Component, For, createEffect, createSignal } from 'solid-js'; +import { listen } from '@tauri-apps/api/event'; +import debug from 'debug'; +import { invoke } from '@tauri-apps/api'; +import { DisplayState, RawDisplayState } from '../../models/display-state.model'; +import { DisplayStateCard } from './display-state-card'; + +const logger = debug('app:components:displays:display-state-index'); + +export const DisplayStateIndex: Component = () => { + const [states, setStates] = createSignal([]); + + createEffect(() => { + const unlisten = listen('displays_changed', (ev) => { + logger('displays_changed', ev); + setStates( + ev.payload.map((it) => ({ + ...it, + last_modified_at: new Date(it.last_modified_at.secs_since_epoch * 1000), + })), + ); + }); + + invoke('get_displays').then((states) => { + logger('get_displays', states); + setStates( + states.map((it) => ({ + ...it, + last_modified_at: new Date(it.last_modified_at.secs_since_epoch * 1000), + })), + ); + }); + + return () => { + unlisten.then((unlisten) => unlisten()); + }; + }); + return ( +
    + + {(state, index) => ( +
  1. + + + #{index() + 1} + +
  2. + )} +
    +
+ ); +}; diff --git a/src/models/display-state.model.ts b/src/models/display-state.model.ts new file mode 100644 index 0000000..90b2954 --- /dev/null +++ b/src/models/display-state.model.ts @@ -0,0 +1,16 @@ +export type DisplayState = { + brightness: number; + max_brightness: number; + min_brightness: number; + contrast: number; + max_contrast: number; + min_contrast: number; + mode: number; + max_mode: number; + min_mode: number; + last_modified_at: Date; +}; + +export type RawDisplayState = DisplayState & { + last_modified_at: { secs_since_epoch: number }; +};