Use global poll for UpowerBattery

This commit is contained in:
Kenny Levinsen
2019-10-05 22:42:26 +02:00
parent 0de3da162b
commit b51fc8a1b0
10 changed files with 106 additions and 83 deletions
+7 -7
View File
@@ -48,7 +48,7 @@ impl WaitContext {
} }
pub trait Widget { pub trait Widget {
fn wait(&self, ctx: &mut WaitContext); fn wait(&mut self, ctx: &mut WaitContext);
fn enter(&mut self); fn enter(&mut self);
fn leave(&mut self); fn leave(&mut self);
fn size(&self) -> (u32, u32); fn size(&self) -> (u32, u32);
@@ -81,8 +81,8 @@ impl VerticalLayout {
} }
impl Widget for VerticalLayout { impl Widget for VerticalLayout {
fn wait(&self, ctx: &mut WaitContext) { fn wait(&mut self, ctx: &mut WaitContext) {
for child in &self.children { for child in &mut self.children {
child.wait(ctx); child.wait(ctx);
} }
} }
@@ -192,8 +192,8 @@ impl HorizontalLayout {
} }
impl Widget for HorizontalLayout { impl Widget for HorizontalLayout {
fn wait(&self, ctx: &mut WaitContext) { fn wait(&mut self, ctx: &mut WaitContext) {
for child in &self.children { for child in &mut self.children {
child.wait(ctx); child.wait(ctx);
} }
} }
@@ -309,7 +309,7 @@ impl Margin {
} }
impl Widget for Margin { impl Widget for Margin {
fn wait(&self, ctx: &mut WaitContext) { fn wait(&mut self, ctx: &mut WaitContext) {
self.child.wait(ctx) self.child.wait(ctx)
} }
fn enter(&mut self) { fn enter(&mut self) {
@@ -386,7 +386,7 @@ impl Fixed {
} }
impl Widget for Fixed { impl Widget for Fixed {
fn wait(&self, ctx: &mut WaitContext) { fn wait(&mut self, ctx: &mut WaitContext) {
self.child.wait(ctx) self.child.wait(ctx)
} }
fn enter(&mut self) { fn enter(&mut self) {
+2
View File
@@ -1,5 +1,6 @@
use crate::color::Color; use crate::color::Color;
use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl}; use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl};
use crate::widget::WaitContext;
use alsa::mixer::{Mixer, Selem, SelemChannelId, SelemId}; use alsa::mixer::{Mixer, Selem, SelemChannelId, SelemId};
@@ -83,6 +84,7 @@ impl Alsa {
} }
impl BarWidgetImpl for Alsa { impl BarWidgetImpl for Alsa {
fn wait(&mut self, _: &mut WaitContext) {}
fn name(&self) -> &str { fn name(&self) -> &str {
"volume" "volume"
} }
+2
View File
@@ -1,6 +1,7 @@
use crate::cmd::Cmd; use crate::cmd::Cmd;
use crate::color::Color; use crate::color::Color;
use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl}; use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl};
use crate::widget::WaitContext;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
@@ -502,6 +503,7 @@ impl PulseAudio {
} }
impl BarWidgetImpl for PulseAudio { impl BarWidgetImpl for PulseAudio {
fn wait(&mut self, _: &mut WaitContext) {}
fn name(&self) -> &str { fn name(&self) -> &str {
"volume" "volume"
} }
+2
View File
@@ -1,5 +1,6 @@
use crate::color::Color; use crate::color::Color;
use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl}; use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl};
use crate::widget::WaitContext;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::{Error, ErrorKind}; use std::io::{Error, ErrorKind};
@@ -93,6 +94,7 @@ impl Backlight {
} }
impl BarWidgetImpl for Backlight { impl BarWidgetImpl for Backlight {
fn wait(&mut self, _: &mut WaitContext) {}
fn name(&self) -> &str { fn name(&self) -> &str {
"backlight" "backlight"
} }
+4 -2
View File
@@ -5,6 +5,7 @@ use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget, W
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
pub trait BarWidgetImpl { pub trait BarWidgetImpl {
fn wait(&mut self, ctx: &mut WaitContext);
fn name(&self) -> &str; fn name(&self) -> &str;
fn value(&self) -> f32; fn value(&self) -> f32;
fn color(&self) -> Color; fn color(&self) -> Color;
@@ -61,13 +62,14 @@ impl BarWidget {
} }
impl Widget for 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 enter(&mut self) {}
fn leave(&mut self) {} fn leave(&mut self) {}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
(self.length, self.font_size) (self.length, self.font_size)
} }
fn draw( fn draw(
&mut self, &mut self,
ctx: &mut DrawContext, ctx: &mut DrawContext,
+69 -54
View File
@@ -1,10 +1,12 @@
use crate::cmd::Cmd; use crate::cmd::Cmd;
use crate::color::Color; use crate::color::Color;
use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl}; use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl};
use crate::widget::WaitContext;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread;
use nix::poll::{PollFd, PollFlags};
use dbus; use dbus;
@@ -35,14 +37,27 @@ fn get_upower_property(
}) })
} }
pub struct UpowerBattery { // The widget is created on a different thread than where it will be used, so
device_path: String, // we need it to be Send. However, dbus::Connection has a void*, so it's not
inner: Arc<Mutex<UpowerBatteryInner>>, // auto-derived. So, we make a small wrapper where we make it Send.
struct DbusConnection(dbus::Connection);
impl std::convert::AsRef<dbus::Connection> 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<Cmd>,
dirty: Arc<Mutex<bool>>,
state: UpowerBatteryState, state: UpowerBatteryState,
capacity: f64, capacity: f64,
con: DbusConnection,
watch: dbus::Watch,
} }
enum UpowerBatteryState { enum UpowerBatteryState {
@@ -55,12 +70,26 @@ enum UpowerBatteryState {
} }
impl UpowerBattery { impl UpowerBattery {
pub fn from_device(device: &str) -> Result<Self, ::std::io::Error> { pub fn from_device(dirty: Arc<Mutex<bool>>, sender: Sender<Cmd>, device: &str) -> Result<Self, ::std::io::Error> {
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 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<u32> = let upower_type: dbus::arg::Variant<u32> =
match get_upower_property(&con, &device_path, "Type")?.get1() { match get_upower_property(&con, &device_path, "Type")?.get1() {
Some(v) => v, 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 { Ok(UpowerBattery {
device_path, device_path,
inner: Arc::new(Mutex::new(UpowerBatteryInner { con: DbusConnection(con),
dirty,
sender,
capacity: capacity, capacity: capacity,
state: state, state: state,
})), watch: fds[0],
}) })
} }
@@ -126,36 +165,21 @@ impl UpowerBattery {
sender: Sender<Cmd>, sender: Sender<Cmd>,
) -> Result<Box<BarWidget>, ::std::io::Error> { ) -> Result<Box<BarWidget>, ::std::io::Error> {
BarWidget::new(font_size, length, move |dirty| { BarWidget::new(font_size, length, move |dirty| {
let d = UpowerBattery::from_device("BAT0")?; let d = UpowerBattery::from_device(dirty, sender, "BAT0")?;
let path = d.device_path.clone(); Ok(Box::new(d))
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. impl BarWidgetImpl for UpowerBattery {
con.incoming(10_000).next(); fn wait(&mut self, ctx: &mut WaitContext) {
for _ in self.con.as_ref().watch_handle(self.watch.fd(), dbus::WatchEvent::Readable as u32) {
con.add_match(&rule) let capacity = get_upower_property(self.con.as_ref(), &self.device_path, "Percentage")
.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() .unwrap()
.get1::<dbus::arg::Variant<f64>>() .get1::<dbus::arg::Variant<f64>>()
.unwrap() .unwrap()
.0; .0;
let state = match get_upower_property(&con, &path, "State") let state = match get_upower_property(self.con.as_ref(), &self.device_path, "State")
.unwrap() .unwrap()
.get1::<dbus::arg::Variant<u32>>() .get1::<dbus::arg::Variant<u32>>()
.unwrap() .unwrap()
@@ -169,33 +193,24 @@ impl UpowerBattery {
6 => UpowerBatteryState::Discharging, 6 => UpowerBatteryState::Discharging,
_ => UpowerBatteryState::Unknown, _ => UpowerBatteryState::Unknown,
}; };
let mut inner = inner.lock().unwrap(); self.state = state;
inner.state = state; self.capacity = capacity;
inner.capacity = capacity; *self.dirty.lock().unwrap() = true;
*dirty.lock().unwrap() = true; self.sender.send(Cmd::Draw).unwrap();
sender.send(Cmd::Draw).unwrap();
}
}
});
Ok(Box::new(d))
})
}
} }
impl BarWidgetImpl for UpowerBattery { ctx.fds.push(PollFd::new(self.watch.fd(), PollFlags::POLLIN));
}
fn name(&self) -> &str { fn name(&self) -> &str {
"battery" "battery"
} }
fn value(&self) -> f32 { fn value(&self) -> f32 {
let inner = self.inner.lock().unwrap(); (self.capacity as f32) / 100.0
(inner.capacity as f32) / 100.0
} }
fn color(&self) -> Color { fn color(&self) -> Color {
let inner = self.inner.lock().unwrap(); match self.state {
match inner.state {
UpowerBatteryState::Discharging | UpowerBatteryState::Unknown => { UpowerBatteryState::Discharging | UpowerBatteryState::Unknown => {
if inner.capacity > 10.0 { if self.capacity > 10.0 {
Color::new(1.0, 1.0, 1.0, 1.0) Color::new(1.0, 1.0, 1.0, 1.0)
} else { } else {
Color::new(1.0, 0.5, 0.0, 1.0) Color::new(1.0, 0.5, 0.0, 1.0)
+1 -1
View File
@@ -177,7 +177,7 @@ impl Calendar {
} }
impl Widget for Calendar { impl Widget for Calendar {
fn wait(&self, _: &mut WaitContext) {} fn wait(&mut self, _: &mut WaitContext) {}
fn enter(&mut self) {} fn enter(&mut self) {}
fn leave(&mut self) {} fn leave(&mut self) {}
+1 -1
View File
@@ -26,7 +26,7 @@ impl Clock {
} }
impl Widget for 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)) let target = (self.cur_time + Duration::seconds(60))
.with_second(0) .with_second(0)
.unwrap() .unwrap()
+1 -1
View File
@@ -27,7 +27,7 @@ impl Date {
} }
impl Widget for Date { impl Widget for Date {
fn wait(&self, _: &mut WaitContext) {} fn wait(&mut self, _: &mut WaitContext) {}
fn enter(&mut self) {} fn enter(&mut self) {}
fn leave(&mut self) {} fn leave(&mut self) {}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
+1 -1
View File
@@ -192,7 +192,7 @@ fn wlcopy(s: &str) -> Result<(), String> {
} }
impl Widget for Launcher { impl Widget for Launcher {
fn wait(&self, _: &mut WaitContext) {} fn wait(&mut self, _: &mut WaitContext) {}
fn enter(&mut self) {} fn enter(&mut self) {}
fn leave(&mut self) { fn leave(&mut self) {
self.input = "".to_string(); self.input = "".to_string();