From 4b83609ee85d90f6e3583846da13631d18094393 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 28 Jun 2024 13:52:18 -0700 Subject: [PATCH] battery: Use `settings_daemon` for display brightness This shares a subscription with cosmic-osd, avoiding some duplication. It's also important that things like selection of the display brightness device are done consistency, and handling this in cosmic-settings-daemon is one way to ensure consistency. --- Cargo.lock | 29 ++--- cosmic-applet-battery/src/app.rs | 103 ++++++++------- cosmic-applet-battery/src/backlight.rs | 165 ------------------------- cosmic-applet-battery/src/lib.rs | 2 - 4 files changed, 76 insertions(+), 223 deletions(-) delete mode 100644 cosmic-applet-battery/src/backlight.rs diff --git a/Cargo.lock b/Cargo.lock index b28ea2da..d5af8c82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,12 +5,12 @@ version = 3 [[package]] name = "accesskit" version = "0.12.2" -source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#5f9b61c8264000d001499c902562422e13efa7a8" +source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#26f729169cd849970af02be62289606c63572d2d" [[package]] name = "accesskit_consumer" version = "0.17.0" -source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#5f9b61c8264000d001499c902562422e13efa7a8" +source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#26f729169cd849970af02be62289606c63572d2d" dependencies = [ "accesskit", ] @@ -18,7 +18,7 @@ dependencies = [ [[package]] name = "accesskit_unix" version = "0.7.1" -source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#5f9b61c8264000d001499c902562422e13efa7a8" +source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#26f729169cd849970af02be62289606c63572d2d" dependencies = [ "accesskit", "accesskit_consumer", @@ -1238,7 +1238,7 @@ dependencies = [ [[package]] name = "cosmic-dbus-networkmanager" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#badfc6a0bbe7c93927fe32692795699a675ae4c4" +source = "git+https://github.com/pop-os/dbus-settings-bindings#1fdfcc8045e6732fc54b2c945008e89999a6cf71" dependencies = [ "bitflags 2.5.0", "derive_builder", @@ -1316,7 +1316,7 @@ dependencies = [ [[package]] name = "cosmic-settings-daemon" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#badfc6a0bbe7c93927fe32692795699a675ae4c4" +source = "git+https://github.com/pop-os/dbus-settings-bindings#1fdfcc8045e6732fc54b2c945008e89999a6cf71" dependencies = [ "zbus 4.2.2", ] @@ -1324,7 +1324,7 @@ dependencies = [ [[package]] name = "cosmic-settings-subscriptions" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-settings-subscriptions#a223eb4d32773e7b1170696f8b2d2d7ab54fa2e1" +source = "git+https://github.com/pop-os/cosmic-settings-subscriptions#3a4e58559149fd5bf4d1d2c93229b2920ce03695" dependencies = [ "futures", "iced_futures", @@ -1332,6 +1332,7 @@ dependencies = [ "log", "rustix 0.38.34", "tokio", + "tokio-stream", "upower_dbus", "zbus 4.2.2", ] @@ -1510,7 +1511,7 @@ version = "0.19.0" source = "git+https://github.com/gfx-rs/wgpu?rev=20fda69#20fda698341efbdc870b8027d6d49f5bf3f36109" dependencies = [ "bitflags 2.5.0", - "libloading 0.8.3", + "libloading 0.7.4", "winapi", ] @@ -1773,7 +1774,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.3", + "libloading 0.7.4", ] [[package]] @@ -2607,7 +2608,7 @@ dependencies = [ "bitflags 2.5.0", "com", "libc", - "libloading 0.8.3", + "libloading 0.7.4", "thiserror", "widestring", "winapi", @@ -4023,7 +4024,7 @@ dependencies = [ [[package]] name = "mpris2-zbus" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#badfc6a0bbe7c93927fe32692795699a675ae4c4" +source = "git+https://github.com/pop-os/dbus-settings-bindings#1fdfcc8045e6732fc54b2c945008e89999a6cf71" dependencies = [ "futures-util", "serde", @@ -5308,7 +5309,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smithay-client-toolkit" version = "0.18.0" -source = "git+https://github.com/smithay/client-toolkit//?rev=3bed072#3bed072b966022f5f929d12f3aff089b1ace980b" +source = "git+https://github.com/smithay/client-toolkit?rev=3bed072#3bed072b966022f5f929d12f3aff089b1ace980b" dependencies = [ "bitflags 2.5.0", "bytemuck", @@ -5533,7 +5534,7 @@ dependencies = [ [[package]] name = "switcheroo-control" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#badfc6a0bbe7c93927fe32692795699a675ae4c4" +source = "git+https://github.com/pop-os/dbus-settings-bindings#1fdfcc8045e6732fc54b2c945008e89999a6cf71" dependencies = [ "zbus 4.2.2", ] @@ -6077,7 +6078,7 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "upower_dbus" version = "0.3.2" -source = "git+https://github.com/pop-os/dbus-settings-bindings?branch=upower#eb5cd58587db538fee38da45d560dc92631b8f99" +source = "git+https://github.com/pop-os/dbus-settings-bindings#1fdfcc8045e6732fc54b2c945008e89999a6cf71" dependencies = [ "serde", "serde_repr", @@ -6536,7 +6537,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.3", + "libloading 0.7.4", "log", "metal", "naga", diff --git a/cosmic-applet-battery/src/app.rs b/cosmic-applet-battery/src/app.rs index 76ba0dfa..3240509d 100644 --- a/cosmic-applet-battery/src/app.rs +++ b/cosmic-applet-battery/src/app.rs @@ -2,9 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::backend::{power_profile_subscription, Power, PowerProfileRequest, PowerProfileUpdate}; -use crate::backlight::{ - screen_backlight_subscription, ScreenBacklightRequest, ScreenBacklightUpdate, -}; use crate::config; use crate::dgpu::{dgpu_subscription, Entry, GpuUpdate}; use crate::fl; @@ -28,9 +25,14 @@ use cosmic::iced_widget::{Column, Row}; use cosmic::widget::{divider, horizontal_space, icon, scrollable, vertical_space}; use cosmic::Command; use cosmic::{Element, Theme}; -use cosmic_settings_subscriptions::upower::{ - device::{device_subscription, DeviceDbusEvent}, - kbdbacklight::{kbd_backlight_subscription, KeyboardBacklightRequest, KeyboardBacklightUpdate}, +use cosmic_settings_subscriptions::{ + settings_daemon, + upower::{ + device::{device_subscription, DeviceDbusEvent}, + kbdbacklight::{ + kbd_backlight_subscription, KeyboardBacklightRequest, KeyboardBacklightUpdate, + }, + }, }; use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline}; @@ -79,14 +81,16 @@ struct CosmicBatteryApplet { gpus: HashMap, time_remaining: Duration, kbd_brightness: Option, - screen_brightness: f64, + max_screen_brightness: i32, + screen_brightness: i32, popup: Option, - screen_sender: Option>, + settings_daemon_sender: Option>, kbd_sender: Option>, power_profile: Power, power_profile_sender: Option>, timeline: Timeline, token_tx: Option>, + zbus_connection: Option, } impl CosmicBatteryApplet { @@ -119,14 +123,18 @@ impl CosmicBatteryApplet { format!("cosmic-applet-battery-level-{battery_percent}-{limited}{charging}symbolic",); } - fn update_display(&mut self, mut percent: f64) { - percent = percent.clamp(0.01, 1.0); - self.screen_brightness = percent; - let screen_brightness = if self.screen_brightness < 0.011 { + fn screen_brightness_percent(&self) -> f64 { + (self.screen_brightness as f64 / self.max_screen_brightness.max(1) as f64).clamp(0.01, 1.0) + } + + fn update_display(&mut self) { + let percent = self.screen_brightness_percent(); + + let screen_brightness = if percent < 0.011 { "off" - } else if self.screen_brightness < 0.333 { + } else if percent < 0.333 { "low" - } else if self.screen_brightness < 0.666 { + } else if percent < 0.666 { "medium" } else { "high" @@ -156,9 +164,7 @@ enum Message { SetScreenBrightness(i32), SetChargingLimit(chain::Toggler, bool), UpdateKbdBrightness(Option), - UpdateScreenBrightness(f64), InitKbdBacklight(UnboundedSender), - InitScreenBacklight(UnboundedSender, f64), GpuOn(PathBuf, String, Option>), GpuOff(PathBuf), ToggleGpuApps(PathBuf), @@ -169,6 +175,8 @@ enum Message { Frame(Instant), Token(TokenUpdate), OpenSettings, + SettingsDaemon(settings_daemon::Event), + ZbusConnection(zbus::Result), } impl cosmic::Application for CosmicBatteryApplet { @@ -193,7 +201,9 @@ impl cosmic::Application for CosmicBatteryApplet { ..Default::default() }, - Command::none(), + cosmic::iced::Command::perform(zbus::Connection::session(), |res| { + cosmic::app::Message::App(Message::ZbusConnection(res)) + }), ) } @@ -219,9 +229,14 @@ impl cosmic::Application for CosmicBatteryApplet { } } Message::SetScreenBrightness(brightness) => { - self.update_display((brightness as f64 / 100.0).clamp(0.01, 1.0)); - if let Some(tx) = &self.screen_sender { - let _ = tx.send(ScreenBacklightRequest::Set(self.screen_brightness)); + let brightness = ((brightness as f64 / 100.0) * self.max_screen_brightness.max(1) as f64) as i32; + self.screen_brightness = brightness; + self.update_display(); + //self.update_display((brightness as f64 / 100.0).clamp(0.01, 1.0)); + if let Some(tx) = &self.settings_daemon_sender { + let _ = tx.send(settings_daemon::Request::SetDisplayBrightness( + self.screen_brightness, + )); } } Message::SetChargingLimit(chain, enable) => { @@ -238,9 +253,6 @@ impl cosmic::Application for CosmicBatteryApplet { if let Some(tx) = &self.kbd_sender { let _ = tx.send(KeyboardBacklightRequest::Get); } - if let Some(tx) = &self.screen_sender { - let _ = tx.send(ScreenBacklightRequest::Get); - } self.timeline = Timeline::new(); let new_id = window::Id::unique(); @@ -278,14 +290,6 @@ impl cosmic::Application for CosmicBatteryApplet { Message::InitKbdBacklight(tx) => { self.kbd_sender = Some(tx); } - Message::InitScreenBacklight(tx, brightness) => { - let _ = tx.send(ScreenBacklightRequest::Get); - self.screen_sender = Some(tx); - self.update_display(brightness); - } - Message::UpdateScreenBrightness(b) => { - self.update_display(b); - } Message::InitProfile(tx, profile) => { self.power_profile_sender.replace(tx); self.power_profile = profile; @@ -295,9 +299,6 @@ impl cosmic::Application for CosmicBatteryApplet { if let Some(tx) = &self.kbd_sender { let _ = tx.send(KeyboardBacklightRequest::Get); } - if let Some(tx) = &self.screen_sender { - let _ = tx.send(ScreenBacklightRequest::Get); - } } Message::SelectProfile(profile) => { if let Some(tx) = self.power_profile_sender.as_ref() { @@ -360,6 +361,24 @@ impl cosmic::Application for CosmicBatteryApplet { data.toggled = !data.toggled; } } + Message::ZbusConnection(Err(err)) => { + tracing::error!("Failed to connect to session dbus: {}", err); + } + Message::ZbusConnection(Ok(conn)) => { + self.zbus_connection = Some(conn); + } + Message::SettingsDaemon(event) => match dbg!(event) { + settings_daemon::Event::Sender(tx) => { + self.settings_daemon_sender = Some(tx); + } + settings_daemon::Event::MaxDisplayBrightness(max_brightness) => { + // XXX option + self.max_screen_brightness = max_brightness; + } + settings_daemon::Event::DisplayBrightness(brightness) => { + self.screen_brightness = brightness; + } + }, } Command::none() } @@ -513,10 +532,10 @@ impl cosmic::Application for CosmicBatteryApplet { .symbolic(true), slider( 1..=100, - (self.screen_brightness * 100.0) as i32, + (dbg!(self.screen_brightness_percent()) * 100.0) as i32, Message::SetScreenBrightness ), - text(format!("{:.0}%", self.screen_brightness * 100.0)) + text(format!("{:.0}%", self.screen_brightness_percent() * 100.)) .size(16) .width(Length::Fixed(40.0)) .horizontal_alignment(Horizontal::Right) @@ -655,7 +674,7 @@ impl cosmic::Application for CosmicBatteryApplet { } fn subscription(&self) -> Subscription { - Subscription::batch(vec![ + let mut subscriptions = vec![ device_subscription(0).map( |DeviceDbusEvent::Update { on_battery, @@ -671,10 +690,6 @@ impl cosmic::Application for CosmicBatteryApplet { KeyboardBacklightUpdate::Brightness(b) => Message::UpdateKbdBrightness(b), KeyboardBacklightUpdate::Sender(tx) => Message::InitKbdBacklight(tx), }), - screen_backlight_subscription(0).map(|e| match e { - ScreenBacklightUpdate::Update(b) => Message::UpdateScreenBrightness(b), - ScreenBacklightUpdate::Init(tx, b) => Message::InitScreenBacklight(tx, b), - }), power_profile_subscription(0).map(|event| match event { PowerProfileUpdate::Update { profile } => Message::Profile(profile), PowerProfileUpdate::Init(tx, p) => Message::InitProfile(p, tx), @@ -688,7 +703,11 @@ impl cosmic::Application for CosmicBatteryApplet { .as_subscription() .map(|(_, now)| Message::Frame(now)), activation_token_subscription(0).map(Message::Token), - ]) + ]; + if let Some(conn) = self.zbus_connection.clone() { + subscriptions.push(settings_daemon::subscription(conn).map(Message::SettingsDaemon)); + } + Subscription::batch(subscriptions) } fn on_close_requested(&self, id: window::Id) -> Option { diff --git a/cosmic-applet-battery/src/backlight.rs b/cosmic-applet-battery/src/backlight.rs deleted file mode 100644 index 3258c2a8..00000000 --- a/cosmic-applet-battery/src/backlight.rs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2023 System76 -// SPDX-License-Identifier: GPL-3.0-only - -// TODO: use udev to monitor for brightness changes? -// How should key bindings be handled? Need something like gnome-settings-daemon? - -use std::{ - fmt::Debug, - fs::File, - hash::Hash, - io::{self, Read}, - os::unix::ffi::OsStrExt, - path::Path, - str::{self, FromStr}, -}; - -use cosmic::iced::{self, futures::SinkExt, subscription}; -use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; - -const BACKLIGHT_SYSDIR: &str = "/sys/class/backlight"; - -#[zbus::proxy( - default_service = "org.freedesktop.login1", - interface = "org.freedesktop.login1.Session", - default_path = "/org/freedesktop/login1/session/auto" -)] -trait LogindSession { - fn set_brightness(&self, subsystem: &str, name: &str, brightness: u32) -> zbus::Result<()>; -} - -#[derive(Clone)] -pub struct Backlight(String); - -impl Backlight { - pub async fn brightness(&self) -> Option { - self.prop("brightness").await - } - - // XXX cache value. Async? - pub async fn max_brightness(&self) -> Option { - self.prop("max_brightness").await - } - - pub async fn set_brightness( - &self, - session: &LogindSessionProxy<'_>, - value: u32, - ) -> zbus::Result<()> { - session.set_brightness("backlight", &self.0, value).await - } - - async fn prop(&self, name: &str) -> Option { - let path = Path::new(BACKLIGHT_SYSDIR).join(&self.0).join(name); - let mut file = File::open(path).ok()?; - let mut s = String::new(); - file.read_to_string(&mut s).ok()?; - s.trim().parse().ok() - } -} - -// Choose backlight with most "precision". This is what `light` does. -pub async fn backlight() -> io::Result> { - let mut best_backlight = None; - let mut best_max_brightness = 0; - let mut dir_stream = tokio::fs::read_dir(BACKLIGHT_SYSDIR).await?; - while let Ok(Some(entry)) = dir_stream.next_entry().await { - if let Ok(filename) = str::from_utf8(entry.file_name().as_bytes()) { - let backlight = Backlight(filename.to_string()); - if let Some(max_brightness) = backlight.max_brightness().await { - if max_brightness > best_max_brightness { - best_backlight = Some(backlight); - best_max_brightness = max_brightness; - } - } - } - } - Ok(best_backlight) -} - -pub fn screen_backlight_subscription( - id: I, -) -> iced::Subscription { - subscription::channel(id, 50, move |mut output| async move { - let mut state = State::Ready; - - loop { - state = start_listening(state, &mut output).await; - } - }) -} - -pub enum State { - Ready, - Waiting( - Backlight, - LogindSessionProxy<'static>, - UnboundedReceiver, - ), - Finished, -} - -async fn start_listening( - state: State, - output: &mut futures::channel::mpsc::Sender, -) -> State { - match state { - State::Ready => { - let conn = match zbus::Connection::system().await { - Ok(conn) => conn, - Err(_) => return State::Finished, - }; - let screen_proxy = match LogindSessionProxy::builder(&conn).build().await { - Ok(p) => p, - Err(_) => return State::Finished, - }; - let backlight = match backlight().await { - Ok(Some(b)) => b, - _ => return State::Finished, - }; - let (tx, rx) = unbounded_channel(); - - let b = (backlight.brightness().await.unwrap_or_default() as f64 - / backlight.max_brightness().await.unwrap_or(1) as f64) - .clamp(0., 1.); - _ = output.send(ScreenBacklightUpdate::Init(tx, b)).await; - - State::Waiting(backlight, screen_proxy, rx) - } - State::Waiting(backlight, proxy, mut rx) => match rx.recv().await { - Some(req) => match req { - ScreenBacklightRequest::Get => { - if let Some(max_brightness) = backlight.max_brightness().await { - let value = (backlight.brightness().await.unwrap_or_default() as f64 - / max_brightness as f64) - .clamp(0., 1.); - _ = output.send(ScreenBacklightUpdate::Update(value)).await; - } - State::Waiting(backlight, proxy, rx) - } - ScreenBacklightRequest::Set(value) => { - if let Some(max_brightness) = backlight.max_brightness().await { - let value = value.clamp(0., 1.) * (max_brightness as f64); - let value = value.round() as u32; - let _ = backlight.set_brightness(&proxy, value).await; - } - State::Waiting(backlight, proxy, rx) - } - }, - None => State::Finished, - }, - State::Finished => iced::futures::future::pending().await, - } -} - -#[derive(Debug, Clone)] -pub enum ScreenBacklightUpdate { - Update(f64), - Init(UnboundedSender, f64), -} - -#[derive(Debug, Clone)] -pub enum ScreenBacklightRequest { - Get, - Set(f64), -} diff --git a/cosmic-applet-battery/src/lib.rs b/cosmic-applet-battery/src/lib.rs index 7a997358..a778f191 100644 --- a/cosmic-applet-battery/src/lib.rs +++ b/cosmic-applet-battery/src/lib.rs @@ -1,8 +1,6 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -#[rustfmt::skip] -mod backlight; mod app; mod backend; mod config;