From 4f1a215159a2a11580847b111e483fdc276f36ec Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Thu, 9 Jan 2025 23:54:30 +0100 Subject: [PATCH 1/5] attempt to fix crash on amd --- src/app.rs | 17 ++-- src/monitor.rs | 222 ++++++++++++++++++++++++++++++------------------- 2 files changed, 146 insertions(+), 93 deletions(-) diff --git a/src/app.rs b/src/app.rs index b7abad8..0b2b5e1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,6 +4,7 @@ use cosmic::app::{Core, Task}; use cosmic::applet::padded_control; use cosmic::cosmic_config::CosmicConfigEntry; use cosmic::cosmic_theme::{ThemeMode, THEME_MODE_ID}; +use cosmic::iced::futures::executor::block_on; use cosmic::iced::window::Id; use cosmic::iced::{Alignment, Length, Limits, Subscription}; use cosmic::iced_runtime::core::window; @@ -15,7 +16,7 @@ use cosmic::{iced_runtime, Element}; // use tokio::sync::mpsc::Sender; use crate::monitor::{DisplayId, EventToSub, Monitor}; use crate::{fl, monitor}; -use tokio::sync::watch::Sender; +use tokio::sync::mpsc::Sender; const ID: &str = "io.github.maciekk64.CosmicExtAppletExternalMonitorBrightness"; const ICON_HIGH: &str = "cosmic-applet-battery-display-brightness-high-symbolic"; @@ -41,15 +42,13 @@ pub enum Message { ThemeModeConfigChanged(ThemeMode), SetDarkMode(bool), Ready((HashMap, Sender)), - BrightnessWasUpdated(DisplayId, u16), + BrightnessWasUpdated(HashMap), } impl Window { pub fn send(&self, e: EventToSub) { if let Some(sender) = &self.sender { - sender.send(e).unwrap(); - - // block_on(sender.send(e)).unwrap(); + block_on(sender.send(e)).unwrap(); } } } @@ -139,9 +138,11 @@ impl cosmic::Application for Window { self.monitors = mon; self.sender.replace(sender); } - Message::BrightnessWasUpdated(id, value) => { - if let Some(monitor) = self.monitors.get_mut(&id) { - monitor.brightness = value; + Message::BrightnessWasUpdated(updates) => { + for (id, value) in updates { + if let Some(monitor) = self.monitors.get_mut(&id) { + monitor.brightness = value; + } } } } diff --git a/src/monitor.rs b/src/monitor.rs index 69f1a3e..58d938a 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -9,7 +9,7 @@ use cosmic::iced::{ stream, }; use ddc_hi::{Ddc, Display}; -use tokio::sync::watch::Receiver; +use tokio::time::sleep; use crate::app::Message; @@ -30,110 +30,162 @@ pub enum EventToSub { } enum State { - Waiting, - Fetch, - Ready(HashMap>>, Receiver), + Fetching, + Ready, } +const MAX_WAITING: Duration = Duration::from_secs(4); +const DEFAULT_WAITING: Duration = Duration::from_millis(50); + pub fn sub() -> impl Stream { stream::channel(100, |mut output| async move { - let mut state = State::Waiting; + let displays = Arc::new(Mutex::new(HashMap::new())); + + let mut rx = { + let mut res = HashMap::new(); + + for display in Display::enumerate() { + let mon = Monitor { + name: display.info.model_name.clone().unwrap_or_default(), + brightness: 0, + }; + + res.insert(display.info.id.clone(), mon); + displays + .lock() + .unwrap() + .insert(display.info.id.clone(), display); + } + + let (tx, rx) = tokio::sync::mpsc::channel(100); + output.send(Message::Ready((res, tx))).await.unwrap(); + rx + }; + + let mut state = State::Fetching; + let mut duration = DEFAULT_WAITING; - let mut duration = Duration::from_millis(50); + let mut request_buff = Vec::new(); loop { match &mut state { - State::Waiting => { + State::Fetching => { tokio::time::sleep(duration).await; - duration *= 2; - state = State::Fetch; - } - State::Fetch => { - let mut res = HashMap::new(); - - let mut displays = HashMap::new(); - - debug!("start enumerate"); - - for mut display in Display::enumerate() { - let brightness = match display.handle.get_vcp_feature(BRIGHTNESS_CODE) { - Ok(v) => v.value(), - Err(e) => { - // on my machine, i get this error when starting the session - // can't get_vcp_feature: DDC/CI error: Expected DDC/CI length bit - // This go away after the third attempt - error!("can't get_vcp_feature: {e}"); - state = State::Waiting; - break; - } - }; - let mon = Monitor { - name: display.info.model_name.clone().unwrap_or_default(), - brightness, - }; + let (error, res) = { + let displays = displays.clone(); + + let j = tokio::task::spawn_blocking(move || { + let mut res = HashMap::new(); + + let mut displays = displays.lock().unwrap(); - res.insert(display.info.id.clone(), mon); - displays.insert(display.info.id.clone(), Arc::new(Mutex::new(display))); + debug!("start enumerate"); + for (id, display) in displays.iter_mut() { + match display.handle.get_vcp_feature(BRIGHTNESS_CODE) { + Ok(v) => { + res.insert(id.clone(), v.value()); + } + Err(e) => { + // on my machine, i get this error when starting the session + // can't get_vcp_feature: DDC/CI error: Expected DDC/CI length bit + // This go away after the third attempt + error!("can't get_vcp_feature: {e}"); + continue; + } + }; + } + (res.len() != displays.len(), res) + }); + + j.await.unwrap() + }; + + output + .send(Message::BrightnessWasUpdated(res)) + .await + .unwrap(); + + if error { + duration *= 2; + if duration > MAX_WAITING { + state = State::Ready; + duration = DEFAULT_WAITING; + } + } else { + duration = DEFAULT_WAITING; + state = State::Ready; + } + } + State::Ready => { + if let Some(e) = rx.recv().await { + request_buff.push(e); } - if let State::Waiting = state { - continue; + while let Ok(e) = rx.try_recv() { + request_buff.push(e); } - debug!("end enumerate"); + let mut set = HashMap::new(); + let mut refresh = false; - let (tx, mut rx) = tokio::sync::watch::channel(EventToSub::Refresh); - rx.mark_unchanged(); + for request in request_buff.drain(..) { + match request { + EventToSub::Refresh => refresh = true, + EventToSub::Set(id, value) => { + set.insert(id, value); + } + } + } - output.send(Message::Ready((res, tx))).await.unwrap(); - state = State::Ready(displays, rx); - } - State::Ready(displays, rx) => { - rx.changed().await.unwrap(); - - let last = rx.borrow_and_update().clone(); - match last { - EventToSub::Refresh => { - for (id, display) in displays { - let res = display - .lock() - .unwrap() - .handle - .get_vcp_feature(BRIGHTNESS_CODE); - - match res { - Ok(value) => { - output - .send(Message::BrightnessWasUpdated( - id.clone(), - value.value(), - )) - .await - .unwrap(); + if refresh { + let displays = displays.clone(); + + let j = tokio::task::spawn_blocking(move || { + let mut res = HashMap::new(); + + for (id, display) in displays.lock().unwrap().iter_mut() { + match display.handle.get_vcp_feature(BRIGHTNESS_CODE) { + Ok(v) => { + res.insert(id.clone(), v.value()); } - Err(err) => error!("{:?}", err), - } + Err(e) => { + // on my machine, i get this error when starting the session + // can't get_vcp_feature: DDC/CI error: Expected DDC/CI length bit + // This go away after the third attempt + error!("can't get_vcp_feature: {e}"); + continue; + } + }; } - } - EventToSub::Set(id, value) => { - let display = displays.get_mut(&id).unwrap().clone(); - - let j = tokio::task::spawn_blocking(move || { - if let Err(err) = display - .lock() - .unwrap() - .handle - .set_vcp_feature(BRIGHTNESS_CODE, value) - { - error!("{:?}", err); - } - }); - - j.await.unwrap(); - tokio::time::sleep(Duration::from_millis(50)).await; - } + res + }); + + let res = j.await.unwrap(); + + output + .send(Message::BrightnessWasUpdated(res)) + .await + .unwrap(); } + + let displays = displays.clone(); + + let j = tokio::task::spawn_blocking(move || { + for (id, value) in set.drain() { + let mut displays = displays.lock().unwrap(); + + let display = displays.get_mut(&id).unwrap(); + + debug!("set {} to {}", id, value); + if let Err(err) = display.handle.set_vcp_feature(BRIGHTNESS_CODE, value) + { + error!("{:?}", err); + } + } + }); + j.await.unwrap(); + sleep(Duration::from_millis(50)).await; } } } From 50a4e5b04a9545422abc15592a18f9772477c180 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sat, 11 Jan 2025 02:49:21 +0100 Subject: [PATCH 2/5] filter by cap --- src/monitor.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/monitor.rs b/src/monitor.rs index 58d938a..748d124 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -44,7 +44,20 @@ pub fn sub() -> impl Stream { let mut rx = { let mut res = HashMap::new(); - for display in Display::enumerate() { + for mut display in Display::enumerate() { + match display.handle.capabilities() { + Ok(cap) => { + if !cap.vcp_features.contains_key(&BRIGHTNESS_CODE) { + info!("BRIGHTNESS_CODE capabilities not found"); + continue; + } + } + Err(e) => { + error!("can't get capabilities {e}"); + continue; + } + } + let mon = Monitor { name: display.info.model_name.clone().unwrap_or_default(), brightness: 0, From 8271df2e5c3192150e2f862637e31ef5e05b41d8 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sat, 11 Jan 2025 06:20:10 +0100 Subject: [PATCH 3/5] Revert "filter by cap" This reverts commit 50a4e5b04a9545422abc15592a18f9772477c180. --- src/monitor.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/monitor.rs b/src/monitor.rs index 748d124..58d938a 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -44,20 +44,7 @@ pub fn sub() -> impl Stream { let mut rx = { let mut res = HashMap::new(); - for mut display in Display::enumerate() { - match display.handle.capabilities() { - Ok(cap) => { - if !cap.vcp_features.contains_key(&BRIGHTNESS_CODE) { - info!("BRIGHTNESS_CODE capabilities not found"); - continue; - } - } - Err(e) => { - error!("can't get capabilities {e}"); - continue; - } - } - + for display in Display::enumerate() { let mon = Monitor { name: display.info.model_name.clone().unwrap_or_default(), brightness: 0, From 41c49ae8eb56ec9aa8ba9ab24f4fa2442b1b1f3b Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sat, 11 Jan 2025 06:27:35 +0100 Subject: [PATCH 4/5] disable refresh --- src/monitor.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/monitor.rs b/src/monitor.rs index 58d938a..0c1500a 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -45,6 +45,9 @@ pub fn sub() -> impl Stream { let mut res = HashMap::new(); for display in Display::enumerate() { + let info = &display.info; + info!("{:?}", info); + let mon = Monitor { name: display.info.model_name.clone().unwrap_or_default(), brightness: 0, @@ -62,7 +65,7 @@ pub fn sub() -> impl Stream { rx }; - let mut state = State::Fetching; + let mut state = State::Ready; let mut duration = DEFAULT_WAITING; let mut request_buff = Vec::new(); @@ -138,7 +141,7 @@ pub fn sub() -> impl Stream { } } - if refresh { + if false { let displays = displays.clone(); let j = tokio::task::spawn_blocking(move || { From 438915265a0c8c184863ed76907945f262bc6768 Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Sat, 11 Jan 2025 06:32:47 +0100 Subject: [PATCH 5/5] Update monitor.rs --- src/monitor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/monitor.rs b/src/monitor.rs index 0c1500a..9b9e5d2 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -141,7 +141,7 @@ pub fn sub() -> impl Stream { } } - if false { + if refresh { let displays = displays.clone(); let j = tokio::task::spawn_blocking(move || {