Skip to content

Commit 47130d5

Browse files
committed
improve refreshing
1 parent 0d060d7 commit 47130d5

File tree

3 files changed

+153
-111
lines changed

3 files changed

+153
-111
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
dark-mode = Dark Mode
22
gamma-curve = Gamma Curve
3+
refresh = Refresh

src/app.rs

Lines changed: 72 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::HashMap;
22
use std::time;
33

4-
use crate::config::Config;
4+
use crate::config::{self, Config};
55
use crate::monitor::{DisplayId, EventToSub, Monitor};
66
use crate::{fl, monitor};
77
use cosmic::app::{Core, Task};
@@ -15,7 +15,8 @@ use cosmic::iced::{Alignment, Length, Limits, Subscription, stream};
1515
use cosmic::iced_runtime::core::window;
1616
use cosmic::iced_winit::commands::popup::{destroy_popup, get_popup};
1717
use cosmic::widget::{
18-
Row, button, column, divider, horizontal_space, icon, mouse_area, row, slider, text, toggler,
18+
Button, Row, button, column, divider, horizontal_space, icon, mouse_area, row, slider, text,
19+
toggler,
1920
};
2021
use cosmic::{Element, iced_runtime};
2122
use tokio::sync::watch::Sender;
@@ -52,6 +53,7 @@ pub enum Message {
5253
ShowSettings(bool),
5354
Ready((HashMap<DisplayId, Monitor>, Sender<EventToSub>)),
5455
BrightnessWasUpdated(DisplayId, u16),
56+
UpdateMonitors(HashMap<DisplayId, Monitor>),
5557
Refresh,
5658
}
5759

@@ -168,6 +170,18 @@ impl Window {
168170
vec
169171
}
170172

173+
fn refresh_view(&self) -> Vec<Element<Message>> {
174+
let mut vec = Vec::with_capacity(2);
175+
176+
let text = text::body(fl!("refresh"))
177+
.width(Length::Fill)
178+
.height(Length::Fixed(24.0))
179+
.align_y(Alignment::Center);
180+
vec.push(menu_button(text).on_press(Message::Refresh).into());
181+
182+
vec
183+
}
184+
171185
fn dark_mode_view(&self) -> Vec<Element<Message>> {
172186
let mut vec = Vec::with_capacity(2);
173187
if !self.monitors.is_empty() {
@@ -192,6 +206,51 @@ impl Window {
192206

193207
vec
194208
}
209+
210+
fn apply_gamma_curves(&mut self) {
211+
for (monitor_id, monitor) in self.monitors.iter_mut() {
212+
if let Some((_id, gamma)) = self
213+
.config
214+
.gamma_curves
215+
.iter()
216+
.find(|(id, _)| id == monitor_id)
217+
{
218+
monitor.gamma_curve = *gamma;
219+
}
220+
}
221+
}
222+
223+
fn refresh(&mut self) {
224+
self.send(EventToSub::Refresh { all: true });
225+
if let Some(config_handler) = &self.config_handler {
226+
if let Ok(c) = config::Config::get_entry(config_handler) {
227+
self.config = c;
228+
self.apply_gamma_curves();
229+
}
230+
}
231+
if let Some(last_dirty) = self.last_config_dirty {
232+
if time::Instant::now().duration_since(last_dirty) > time::Duration::from_secs(5) {
233+
for (id, mon) in self.monitors.iter() {
234+
if let Some((_id, gamma)) = self
235+
.config
236+
.gamma_curves
237+
.iter_mut()
238+
.find(|(mon_id, _gamma)| mon_id == id)
239+
{
240+
*gamma = mon.gamma_curve
241+
} else {
242+
self.config.gamma_curves.push((id.clone(), mon.gamma_curve))
243+
}
244+
}
245+
if let Some(config_handler) = &self.config_handler {
246+
self.config
247+
.write_entry(config_handler)
248+
.unwrap_or_else(|e| error!("{e:?}"));
249+
}
250+
self.last_config_dirty = None;
251+
}
252+
}
253+
}
195254
}
196255

197256
impl cosmic::Application for Window {
@@ -228,37 +287,19 @@ impl cosmic::Application for Window {
228287

229288
match message {
230289
Message::Refresh => {
231-
if let Some(last_dirty) = self.last_config_dirty {
232-
if time::Instant::now().duration_since(last_dirty)
233-
> time::Duration::from_secs(5)
234-
{
235-
for (id, mon) in self.monitors.iter() {
236-
if let Some((_id, gamma)) = self
237-
.config
238-
.gamma_curves
239-
.iter_mut()
240-
.find(|(mon_id, _gamma)| mon_id == id)
241-
{
242-
*gamma = mon.gamma_curve
243-
} else {
244-
self.config.gamma_curves.push((id.clone(), mon.gamma_curve))
245-
}
246-
}
247-
if let Some(config_handler) = &self.config_handler {
248-
self.config
249-
.write_entry(config_handler)
250-
.unwrap_or_else(|e| error!("{e:?}"));
251-
}
252-
self.last_config_dirty = None;
253-
}
254-
}
290+
self.refresh();
291+
}
292+
Message::UpdateMonitors(mon) => {
293+
self.monitors = mon;
294+
self.apply_gamma_curves();
255295
}
256296
Message::TogglePopup => {
257297
self.show_settings = false;
258298
return if let Some(p) = self.popup.take() {
259299
destroy_popup(p)
260300
} else {
261-
self.send(EventToSub::Refresh);
301+
self.send(EventToSub::Refresh { all: false });
302+
// self.refresh();
262303

263304
let new_id = Id::unique();
264305
self.popup.replace(new_id);
@@ -323,16 +364,7 @@ impl cosmic::Application for Window {
323364
}
324365
Message::Ready((mon, sender)) => {
325366
self.monitors = mon;
326-
for (monitor_id, monitor) in self.monitors.iter_mut() {
327-
if let Some((_id, gamma)) = self
328-
.config
329-
.gamma_curves
330-
.iter()
331-
.find(|(id, _)| id == monitor_id)
332-
{
333-
monitor.gamma_curve = *gamma;
334-
}
335-
}
367+
self.apply_gamma_curves();
336368
self.sender.replace(sender);
337369
}
338370
Message::BrightnessWasUpdated(id, value) => {
@@ -376,15 +408,13 @@ impl cosmic::Application for Window {
376408
}
377409

378410
fn view_window(&self, _id: Id) -> Element<Self::Message> {
379-
let mut col = column()
411+
let col = column()
380412
.padding([8, 0])
381413
.extend(self.sliders_view())
414+
.extend(self.refresh_view())
382415
.extend(self.dark_mode_view())
383416
.extend(self.settings_collapsible_view())
384417
.extend(self.settings_view());
385-
// if self.show_settings {
386-
// col = col.extend(self.settings_view())
387-
// }
388418
self.core.applet.popup_container(col).into()
389419
}
390420

@@ -398,20 +428,11 @@ impl cosmic::Application for Window {
398428
.watch_config(THEME_MODE_ID)
399429
.map(|u| Message::ThemeModeConfigChanged(u.config)),
400430
Subscription::run(monitor::sub),
401-
Subscription::run(refresh_sub),
431+
// Subscription::run(refresh_sub),
402432
])
403433
}
404434
}
405435

406-
fn refresh_sub() -> impl Stream<Item = Message> {
407-
stream::channel(10, |mut output| async move {
408-
loop {
409-
tokio::time::sleep(time::Duration::from_secs(10)).await;
410-
output.send(Message::Refresh).await.unwrap();
411-
}
412-
})
413-
}
414-
415436
fn brightness_icon(brightness: f32) -> &'static str {
416437
if brightness > 0.66 {
417438
ICON_HIGH

src/monitor.rs

Lines changed: 80 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -46,89 +46,48 @@ impl Monitor {
4646

4747
#[derive(Debug, Clone)]
4848
pub enum EventToSub {
49-
Refresh,
49+
Refresh { all: bool },
5050
Set(DisplayId, u16),
5151
}
5252

5353
enum State {
54-
Waiting,
5554
Fetch,
5655
Ready(HashMap<String, Arc<Mutex<Display>>>, Receiver<EventToSub>),
5756
}
5857

5958
pub fn sub() -> impl Stream<Item = Message> {
6059
stream::channel(100, |mut output| async move {
61-
let mut state = State::Waiting;
62-
let mut failed_attempts = 0;
63-
64-
let mut duration = Duration::from_millis(50);
60+
let mut state = State::Fetch;
61+
let mut monitors_id: String = String::new();
6562

6663
loop {
6764
match &mut state {
68-
State::Waiting => {
69-
tokio::time::sleep(duration).await;
70-
duration *= 2;
71-
state = State::Fetch;
72-
}
7365
State::Fetch => {
74-
let mut res = HashMap::new();
75-
76-
let mut displays = HashMap::new();
77-
78-
debug!("start enumerate");
79-
80-
let mut some_failed = false;
81-
for mut display in Display::enumerate() {
82-
let brightness = match display.handle.get_vcp_feature(BRIGHTNESS_CODE) {
83-
Ok(v) => v.value(),
84-
// on my machine, i get this error when starting the session
85-
// can't get_vcp_feature: DDC/CI error: Expected DDC/CI length bit
86-
// This go away after the third attempt
87-
Err(e) => {
88-
error!("can't get_vcp_feature: {e}");
89-
some_failed = true;
90-
continue;
91-
}
92-
};
93-
debug_assert!(brightness <= 100);
94-
let curve = 1.0;
95-
let curved_brightness = (brightness as f32 / 100.0).powf(curve);
96-
97-
let mon = Monitor {
98-
name: display.info.model_name.clone().unwrap_or_default(),
99-
brightness: curved_brightness,
100-
gamma_curve: curve,
101-
};
102-
103-
res.insert(display.info.id.clone(), mon);
104-
displays.insert(display.info.id.clone(), Arc::new(Mutex::new(display)));
105-
}
106-
107-
if some_failed {
108-
failed_attempts += 1;
109-
}
110-
111-
// On some monitors this error is permanent
112-
// So we mark the app as ready if at least one monitor is loaded after 5 attempts
113-
if some_failed && failed_attempts < 5 {
114-
state = State::Waiting;
115-
continue;
116-
}
117-
118-
debug!("end enumerate");
119-
120-
let (tx, mut rx) = tokio::sync::watch::channel(EventToSub::Refresh);
66+
let (monitors, displays) = fetch_displays(5).await;
67+
let (tx, mut rx) =
68+
tokio::sync::watch::channel(EventToSub::Refresh { all: true });
12169
rx.mark_unchanged();
12270

123-
output.send(Message::Ready((res, tx))).await.unwrap();
71+
monitors_id = get_monitors_id(&monitors);
72+
73+
output.send(Message::Ready((monitors, tx))).await.unwrap();
12474
state = State::Ready(displays, rx);
12575
}
12676
State::Ready(displays, rx) => {
12777
rx.changed().await.unwrap();
12878

12979
let last = rx.borrow_and_update().clone();
13080
match last {
131-
EventToSub::Refresh => {
81+
EventToSub::Refresh { all } => {
82+
if all {
83+
let (mon, dis) = fetch_displays(1).await;
84+
let id = get_monitors_id(&mon);
85+
if id != monitors_id {
86+
*displays = dis;
87+
monitors_id = id;
88+
output.send(Message::UpdateMonitors(mon)).await.unwrap();
89+
}
90+
}
13291
for (id, display) in displays {
13392
let res = display
13493
.lock()
@@ -174,3 +133,64 @@ pub fn sub() -> impl Stream<Item = Message> {
174133
}
175134
})
176135
}
136+
137+
fn get_monitors_id(monitors: &HashMap<String, Monitor>) -> String {
138+
let mut monitors_id = String::new();
139+
let mut keys = monitors.keys().collect::<Vec<_>>();
140+
keys.sort();
141+
for key in keys {
142+
monitors_id = monitors_id + key;
143+
}
144+
monitors_id
145+
}
146+
147+
async fn fetch_displays(
148+
attempts: u32,
149+
) -> (
150+
HashMap<String, Monitor>,
151+
HashMap<String, Arc<Mutex<Display>>>,
152+
) {
153+
let mut res = HashMap::new();
154+
let mut displays = HashMap::new();
155+
156+
let mut failed_attempts = 0;
157+
let mut duration = Duration::from_millis(50);
158+
159+
let mut some_failed = false;
160+
for mut display in Display::enumerate() {
161+
let brightness = match display.handle.get_vcp_feature(BRIGHTNESS_CODE) {
162+
Ok(v) => v.value(),
163+
// on my machine, i get this error when starting the session
164+
// can't get_vcp_feature: DDC/CI error: Expected DDC/CI length bit
165+
// This go away after the third attempt
166+
Err(e) => {
167+
error!("can't get_vcp_feature: {e}");
168+
some_failed = true;
169+
continue;
170+
}
171+
};
172+
debug_assert!(brightness <= 100);
173+
174+
let mon = Monitor {
175+
name: display.info.model_name.clone().unwrap_or_default(),
176+
brightness: brightness as f32 / 100.0,
177+
gamma_curve: 1.0,
178+
};
179+
180+
res.insert(display.info.id.clone(), mon);
181+
displays.insert(display.info.id.clone(), Arc::new(Mutex::new(display)));
182+
}
183+
184+
if some_failed {
185+
failed_attempts += 1;
186+
}
187+
188+
// On some monitors this error is permanent
189+
// So we mark the app as ready if at least one monitor is loaded after 5 attempts
190+
if some_failed && failed_attempts < attempts {
191+
tokio::time::sleep(duration).await;
192+
duration *= 2;
193+
}
194+
195+
(res, displays)
196+
}

0 commit comments

Comments
 (0)