feat: 支持列出显示器。
This commit is contained in:
@ -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,
|
@ -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<Mutex<HashMap<usize, Arc<Mutex<DisplayConfig>>>>>,
|
||||
pub struct DisplayHandler {
|
||||
pub state: Arc<RwLock<DisplayState>>,
|
||||
pub controller: Arc<RwLock<Display>>,
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn global() -> &'static Self {
|
||||
static DISPLAY_MANAGER: once_cell::sync::OnceCell<Manager> =
|
||||
once_cell::sync::OnceCell::new();
|
||||
pub struct DisplayManager {
|
||||
displays: Arc<RwLock<Vec<Arc<RwLock<DisplayHandler>>>>>,
|
||||
}
|
||||
|
||||
DISPLAY_MANAGER.get_or_init(|| Self::create())
|
||||
impl DisplayManager {
|
||||
pub async fn global() -> &'static Self {
|
||||
static DISPLAY_MANAGER: OnceCell<DisplayManager> = 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<DisplayConfig> {
|
||||
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<DisplayState> {
|
||||
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<OwnedMutexGuard<DisplayConfig>> {
|
||||
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<DisplayState> {
|
||||
// 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<OwnedMutexGuard<DisplayState>> {
|
||||
// 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(())
|
||||
// }
|
||||
}
|
||||
|
@ -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::*;
|
||||
|
||||
|
||||
|
||||
|
@ -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<Vec<BoardInfo>, String> {
|
||||
Ok(boards)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn get_displays() -> Vec<DisplayState> {
|
||||
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", "*");
|
||||
|
Reference in New Issue
Block a user