From b51fc8a1b0a8a3dac4bfae73fbfda94a7c6fdb7e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 5 Oct 2019 21:41:09 +0200 Subject: [PATCH] Use global poll for UpowerBattery --- src/widget.rs | 14 +-- src/widgets/audio/alsa_sound.rs | 2 + src/widgets/audio/pulse_sound.rs | 2 + src/widgets/backlight.rs | 2 + src/widgets/bar_widget.rs | 6 +- src/widgets/battery.rs | 155 +++++++++++++++++-------------- src/widgets/calendar.rs | 2 +- src/widgets/clock.rs | 2 +- src/widgets/date.rs | 2 +- src/widgets/launcher.rs | 2 +- 10 files changed, 106 insertions(+), 83 deletions(-) diff --git a/src/widget.rs b/src/widget.rs index 827fb7e..8d18feb 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -48,7 +48,7 @@ impl WaitContext { } pub trait Widget { - fn wait(&self, ctx: &mut WaitContext); + fn wait(&mut self, ctx: &mut WaitContext); fn enter(&mut self); fn leave(&mut self); fn size(&self) -> (u32, u32); @@ -81,8 +81,8 @@ impl VerticalLayout { } impl Widget for VerticalLayout { - fn wait(&self, ctx: &mut WaitContext) { - for child in &self.children { + fn wait(&mut self, ctx: &mut WaitContext) { + for child in &mut self.children { child.wait(ctx); } } @@ -192,8 +192,8 @@ impl HorizontalLayout { } impl Widget for HorizontalLayout { - fn wait(&self, ctx: &mut WaitContext) { - for child in &self.children { + fn wait(&mut self, ctx: &mut WaitContext) { + for child in &mut self.children { child.wait(ctx); } } @@ -309,7 +309,7 @@ impl Margin { } impl Widget for Margin { - fn wait(&self, ctx: &mut WaitContext) { + fn wait(&mut self, ctx: &mut WaitContext) { self.child.wait(ctx) } fn enter(&mut self) { @@ -386,7 +386,7 @@ impl Fixed { } impl Widget for Fixed { - fn wait(&self, ctx: &mut WaitContext) { + fn wait(&mut self, ctx: &mut WaitContext) { self.child.wait(ctx) } fn enter(&mut self) { diff --git a/src/widgets/audio/alsa_sound.rs b/src/widgets/audio/alsa_sound.rs index 88efa21..4079143 100644 --- a/src/widgets/audio/alsa_sound.rs +++ b/src/widgets/audio/alsa_sound.rs @@ -1,5 +1,6 @@ use crate::color::Color; use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl}; +use crate::widget::WaitContext; use alsa::mixer::{Mixer, Selem, SelemChannelId, SelemId}; @@ -83,6 +84,7 @@ impl Alsa { } impl BarWidgetImpl for Alsa { + fn wait(&mut self, _: &mut WaitContext) {} fn name(&self) -> &str { "volume" } diff --git a/src/widgets/audio/pulse_sound.rs b/src/widgets/audio/pulse_sound.rs index 9f2e3e1..b8f8a79 100644 --- a/src/widgets/audio/pulse_sound.rs +++ b/src/widgets/audio/pulse_sound.rs @@ -1,6 +1,7 @@ use crate::cmd::Cmd; use crate::color::Color; use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl}; +use crate::widget::WaitContext; use std::cell::RefCell; use std::collections::HashMap; @@ -502,6 +503,7 @@ impl PulseAudio { } impl BarWidgetImpl for PulseAudio { + fn wait(&mut self, _: &mut WaitContext) {} fn name(&self) -> &str { "volume" } diff --git a/src/widgets/backlight.rs b/src/widgets/backlight.rs index 763b689..c8a350a 100644 --- a/src/widgets/backlight.rs +++ b/src/widgets/backlight.rs @@ -1,5 +1,6 @@ use crate::color::Color; use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl}; +use crate::widget::WaitContext; use std::fs::OpenOptions; use std::io::{Error, ErrorKind}; @@ -93,6 +94,7 @@ impl Backlight { } impl BarWidgetImpl for Backlight { + fn wait(&mut self, _: &mut WaitContext) {} fn name(&self) -> &str { "backlight" } diff --git a/src/widgets/bar_widget.rs b/src/widgets/bar_widget.rs index 2de4d0b..46cd15b 100644 --- a/src/widgets/bar_widget.rs +++ b/src/widgets/bar_widget.rs @@ -5,6 +5,7 @@ use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget, W use std::sync::{Arc, Mutex}; pub trait BarWidgetImpl { + fn wait(&mut self, ctx: &mut WaitContext); fn name(&self) -> &str; fn value(&self) -> f32; fn color(&self) -> Color; @@ -61,13 +62,14 @@ impl BarWidget { } impl Widget for BarWidget { - fn wait(&self, _: &mut WaitContext) {} + fn wait(&mut self, ctx: &mut WaitContext) { + self.bar_impl.wait(ctx); + } fn enter(&mut self) {} fn leave(&mut self) {} fn size(&self) -> (u32, u32) { (self.length, self.font_size) } - fn draw( &mut self, ctx: &mut DrawContext, diff --git a/src/widgets/battery.rs b/src/widgets/battery.rs index 374aa7a..421263d 100644 --- a/src/widgets/battery.rs +++ b/src/widgets/battery.rs @@ -1,10 +1,12 @@ use crate::cmd::Cmd; use crate::color::Color; use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl}; +use crate::widget::WaitContext; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; -use std::thread; + +use nix::poll::{PollFd, PollFlags}; use dbus; @@ -35,14 +37,27 @@ fn get_upower_property( }) } -pub struct UpowerBattery { - device_path: String, - inner: Arc>, +// The widget is created on a different thread than where it will be used, so +// we need it to be Send. However, dbus::Connection has a void*, so it's not +// auto-derived. So, we make a small wrapper where we make it Send. +struct DbusConnection(dbus::Connection); + +impl std::convert::AsRef for DbusConnection { + fn as_ref(&self) -> &dbus::Connection { + return &self.0 + } } -pub struct UpowerBatteryInner { +unsafe impl Send for DbusConnection {} + +pub struct UpowerBattery { + device_path: String, + sender: Sender, + dirty: Arc>, state: UpowerBatteryState, capacity: f64, + con: DbusConnection, + watch: dbus::Watch, } enum UpowerBatteryState { @@ -55,12 +70,26 @@ enum UpowerBatteryState { } impl UpowerBattery { - pub fn from_device(device: &str) -> Result { + pub fn from_device(dirty: Arc>, sender: Sender, device: &str) -> Result { + let con = dbus::Connection::get_private(dbus::BusType::System) + .map_err(|_| ::std::io::Error::new( + ::std::io::ErrorKind::Other, + "unable to open dbus", + ))?; let device_path = format!("/org/freedesktop/UPower/devices/battery_{}", device); - let con = dbus::Connection::get_private(dbus::BusType::System).map_err(|_| { - ::std::io::Error::new(::std::io::ErrorKind::Other, "could not get dbus connection") - })?; + let rule = format!( + "type='signal',\ + path='{}',\ + interface='org.freedesktop.DBus.Properties',\ + member='PropertiesChanged'", + &device_path + ); + con.add_match(&rule) + .map_err(|_| ::std::io::Error::new( + ::std::io::ErrorKind::Other, + "unable to add match rule to dbus connection", + ))?; let upower_type: dbus::arg::Variant = match get_upower_property(&con, &device_path, "Type")?.get1() { Some(v) => v, @@ -111,12 +140,22 @@ impl UpowerBattery { } }; + let fds = con.watch_fds(); + if fds.len() != 1 { + return Err(::std::io::Error::new( + ::std::io::ErrorKind::Other, + "expected 1 watch fd from dbus", + )); + } + Ok(UpowerBattery { device_path, - inner: Arc::new(Mutex::new(UpowerBatteryInner { - capacity: capacity, - state: state, - })), + con: DbusConnection(con), + dirty, + sender, + capacity: capacity, + state: state, + watch: fds[0], }) } @@ -126,76 +165,52 @@ impl UpowerBattery { sender: Sender, ) -> Result, ::std::io::Error> { BarWidget::new(font_size, length, move |dirty| { - let d = UpowerBattery::from_device("BAT0")?; - let path = d.device_path.clone(); - let inner = d.inner.clone(); - let _ = thread::Builder::new() - .name("battery_monitor".to_string()) - .spawn(move || { - let con = dbus::Connection::get_private(dbus::BusType::System) - .expect("Failed to establish D-Bus connection."); - let rule = format!( - "type='signal',\ - path='{}',\ - interface='org.freedesktop.DBus.Properties',\ - member='PropertiesChanged'", - path - ); - - // First we're going to get an (irrelevant) NameAcquired event. - con.incoming(10_000).next(); - - con.add_match(&rule) - .expect("Failed to add D-Bus match rule."); - - loop { - if con.incoming(10_000).next().is_some() { - let capacity = get_upower_property(&con, &path, "Percentage") - .unwrap() - .get1::>() - .unwrap() - .0; - let state = match get_upower_property(&con, &path, "State") - .unwrap() - .get1::>() - .unwrap() - .0 - { - 1 => UpowerBatteryState::Charging, - 2 => UpowerBatteryState::Discharging, - 3 => UpowerBatteryState::Empty, - 4 => UpowerBatteryState::Full, - 5 => UpowerBatteryState::NotCharging, - 6 => UpowerBatteryState::Discharging, - _ => UpowerBatteryState::Unknown, - }; - let mut inner = inner.lock().unwrap(); - inner.state = state; - inner.capacity = capacity; - *dirty.lock().unwrap() = true; - sender.send(Cmd::Draw).unwrap(); - } - } - }); - + let d = UpowerBattery::from_device(dirty, sender, "BAT0")?; Ok(Box::new(d)) }) } } impl BarWidgetImpl for UpowerBattery { + fn wait(&mut self, ctx: &mut WaitContext) { + for _ in self.con.as_ref().watch_handle(self.watch.fd(), dbus::WatchEvent::Readable as u32) { + let capacity = get_upower_property(self.con.as_ref(), &self.device_path, "Percentage") + .unwrap() + .get1::>() + .unwrap() + .0; + let state = match get_upower_property(self.con.as_ref(), &self.device_path, "State") + .unwrap() + .get1::>() + .unwrap() + .0 + { + 1 => UpowerBatteryState::Charging, + 2 => UpowerBatteryState::Discharging, + 3 => UpowerBatteryState::Empty, + 4 => UpowerBatteryState::Full, + 5 => UpowerBatteryState::NotCharging, + 6 => UpowerBatteryState::Discharging, + _ => UpowerBatteryState::Unknown, + }; + self.state = state; + self.capacity = capacity; + *self.dirty.lock().unwrap() = true; + self.sender.send(Cmd::Draw).unwrap(); + } + + ctx.fds.push(PollFd::new(self.watch.fd(), PollFlags::POLLIN)); + } fn name(&self) -> &str { "battery" } fn value(&self) -> f32 { - let inner = self.inner.lock().unwrap(); - (inner.capacity as f32) / 100.0 + (self.capacity as f32) / 100.0 } fn color(&self) -> Color { - let inner = self.inner.lock().unwrap(); - match inner.state { + match self.state { UpowerBatteryState::Discharging | UpowerBatteryState::Unknown => { - if inner.capacity > 10.0 { + if self.capacity > 10.0 { Color::new(1.0, 1.0, 1.0, 1.0) } else { Color::new(1.0, 0.5, 0.0, 1.0) diff --git a/src/widgets/calendar.rs b/src/widgets/calendar.rs index 74bf13b..16ee667 100644 --- a/src/widgets/calendar.rs +++ b/src/widgets/calendar.rs @@ -177,7 +177,7 @@ impl Calendar { } impl Widget for Calendar { - fn wait(&self, _: &mut WaitContext) {} + fn wait(&mut self, _: &mut WaitContext) {} fn enter(&mut self) {} fn leave(&mut self) {} diff --git a/src/widgets/clock.rs b/src/widgets/clock.rs index cb56aee..b925ea4 100644 --- a/src/widgets/clock.rs +++ b/src/widgets/clock.rs @@ -26,7 +26,7 @@ impl Clock { } impl Widget for Clock { - fn wait(&self, ctx: &mut WaitContext) { + fn wait(&mut self, ctx: &mut WaitContext) { let target = (self.cur_time + Duration::seconds(60)) .with_second(0) .unwrap() diff --git a/src/widgets/date.rs b/src/widgets/date.rs index f6a843d..38cb500 100644 --- a/src/widgets/date.rs +++ b/src/widgets/date.rs @@ -27,7 +27,7 @@ impl Date { } impl Widget for Date { - fn wait(&self, _: &mut WaitContext) {} + fn wait(&mut self, _: &mut WaitContext) {} fn enter(&mut self) {} fn leave(&mut self) {} fn size(&self) -> (u32, u32) { diff --git a/src/widgets/launcher.rs b/src/widgets/launcher.rs index 64855ef..1b5aa53 100644 --- a/src/widgets/launcher.rs +++ b/src/widgets/launcher.rs @@ -192,7 +192,7 @@ fn wlcopy(s: &str) -> Result<(), String> { } impl Widget for Launcher { - fn wait(&self, _: &mut WaitContext) {} + fn wait(&mut self, _: &mut WaitContext) {} fn enter(&mut self) {} fn leave(&mut self) { self.input = "".to_string();