battery: Load properties from UPower, and monitor for changes

This commit is contained in:
Ian Douglas Scott 2022-06-21 18:38:21 -07:00
parent ed42b4c71e
commit e46abe4dc3
4 changed files with 69 additions and 16 deletions

View file

@ -59,4 +59,17 @@ fn backlight() -> io::Result<Option<Backlight>> {
Ok(best_backlight)
}
// TODO: Cache device, max_brightness, etc.
async fn set_display_brightness(brightness: f64) -> io::Result<()> {
if let Some(backlight) = backlight()? {
if let Some(max_brightness) = backlight.max_brightness() {
let value = brightness.clamp(0., 1.) * (max_brightness as f64);
let value = value.round() as u32;
// XXX TODO
backlight.set_brightness(todo!(), value).await;
}
}
Ok(())
}
// TODO: keyboard backlight

View file

@ -15,33 +15,26 @@ async fn display_device() -> zbus::Result<DeviceProxy<'static>> {
let device_path = upower.get_display_device().await?;
DeviceProxy::builder(&connection)
.path(device_path)?
.cache_properties(zbus::CacheProperties::Yes)
.build()
.await
}
async fn foo(device: &DeviceProxy<'static>) {
let mut icon_name_stream = device.receive_icon_name_changed().await;
let mut battery_level_stream = device.receive_battery_level_changed().await;
glib::MainContext::default()
.spawn(async move { while let Some(evt) = icon_name_stream.next().await {} });
glib::MainContext::default()
.spawn(async move { while let Some(evt) = battery_level_stream.next().await {} });
}
#[derive(Default)]
struct AppModel {
icon_name: String,
battery_percent: u8,
battery_percent: f64,
time_remaining: Duration,
display_brightness: f64,
keyboard_brightness: f64,
device: Option<DeviceProxy<'static>>,
}
enum AppMsg {
SetDisplayBrightness(f64),
SetKeyboardBrightness(f64),
SetDevice(DeviceProxy<'static>),
UpdateProperties,
}
#[relm4::component]
@ -81,8 +74,9 @@ impl SimpleComponent for AppModel {
gtk4::Label {
set_halign: gtk4::Align::Start,
// XXX duration formatting
// XXX time to full, fully changed, etc.
#[watch]
set_label: &format!("{:?} until empty ({}%)", model.time_remaining, model.battery_percent),
set_label: &format!("{:?} until empty ({:.0}%)", model.time_remaining, model.battery_percent),
},
},
},
@ -188,16 +182,56 @@ impl SimpleComponent for AppModel {
let widgets = view_output!();
let sender = sender.clone();
glib::MainContext::default().spawn(async move {
match display_device().await {
Ok(device) => sender.input(AppMsg::SetDevice(device)),
Err(err) => eprintln!("Failed to open UPower display device: {}", err),
}
});
ComponentParts { model, widgets }
}
fn update(&mut self, msg: Self::Input, _sender: &ComponentSender<Self>) {
fn update(&mut self, msg: Self::Input, sender: &ComponentSender<Self>) {
match msg {
AppMsg::SetDisplayBrightness(value) => {
self.display_brightness = value;
// XXX set brightness
}
AppMsg::SetKeyboardBrightness(value) => {
self.keyboard_brightness = value;
// XXX set brightness
}
AppMsg::SetDevice(device) => {
self.device = Some(device.clone());
let sender = sender.clone();
glib::MainContext::default().spawn(async move {
let mut stream = futures::stream_select!(
device.receive_icon_name_changed().await.map(|_| ()),
device.receive_percentage_changed().await.map(|_| ()),
device.receive_time_to_empty_changed().await.map(|_| ()),
);
sender.input(AppMsg::UpdateProperties);
while let Some(()) = stream.next().await {
sender.input(AppMsg::UpdateProperties);
}
});
}
AppMsg::UpdateProperties => {
if let Some(device) = self.device.as_ref() {
if let Ok(Some(percentage)) = device.cached_percentage() {
self.battery_percent = percentage;
}
if let Ok(Some(icon_name)) = device.cached_icon_name() {
self.icon_name = icon_name;
}
if let Ok(Some(secs)) = device.cached_time_to_empty() {
self.time_remaining = Duration::from_secs(secs as u64);
}
}
}
}
}

View file

@ -5,7 +5,10 @@
use zbus::dbus_proxy;
#[dbus_proxy(interface = "org.freedesktop.UPower")]
#[dbus_proxy(
default_service = "org.freedesktop.UPower",
interface = "org.freedesktop.UPower"
)]
trait UPower {
/// EnumerateDevices method
fn enumerate_devices(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;

View file

@ -5,7 +5,10 @@
use zbus::dbus_proxy;
#[dbus_proxy(interface = "org.freedesktop.UPower.Device")]
#[dbus_proxy(
default_service = "org.freedesktop.UPower",
interface = "org.freedesktop.UPower.Device"
)]
trait Device {
/// GetHistory method
fn get_history(