Moar speed

This commit is contained in:
Kenny Levinsen
2023-02-06 18:34:07 +01:00
parent 69959e86dc
commit 6f0ca36826
18 changed files with 497 additions and 981 deletions
+112
View File
@@ -0,0 +1,112 @@
use std::{
thread,
sync::{Arc, Mutex},
};
use crate::{
color::Color,
fonts::FontMap,
event::{Event, Events, PointerButton},
widgets::bar_widget::{BarWidget, BarWidgetImpl},
};
use alsa::mixer::{
Mixer, Selem, SelemChannelId, SelemId,
};
#[inline]
fn alsa_volume_to_f32(volume: i64, min: i64, max: i64) -> f32 {
(volume - min) as f32 / (max - min) as f32
}
#[inline]
fn f32_to_alsa_volume(volume: f32, min: i64, max: i64) -> i64 {
min + ((max - min) as f32 * volume) as i64
}
fn get_master_volume(selem: &mut Selem) -> f32 {
let (min, max) = selem.get_playback_volume_range();
selem
.get_playback_volume(SelemChannelId::mono())
.map(|volume| alsa_volume_to_f32(volume, min, max))
.unwrap()
}
fn get_mute(selem: &mut Selem) -> bool {
let res = selem.get_playback_switch(SelemChannelId::FrontLeft);
false
}
fn set_master_volume(selem: &mut Selem, volume: f32) {
let (min, max) = selem.get_playback_volume_range();
let volume = f32_to_alsa_volume(volume, min, max);
selem.set_playback_volume_all(volume).unwrap();
}
fn start_monitor(inner: Arc<Mutex<Inner>>) {
thread::Builder::new()
.name("audiomon".to_string())
.spawn(move || {
let mixer = Mixer::new("default", true).unwrap();
let id = SelemId::new("Master", 0);
let mut selem = mixer.find_selem(&id).unwrap();
let mut inner = inner.lock().unwrap();
inner.volume = get_master_volume(&mut selem);
inner.mute = get_mute(&mut selem);
})
.unwrap();
}
struct Inner {
volume: f32,
mute: bool,
}
pub struct AlsaAudio {
inner: Arc<Mutex<Inner>>,
}
impl AlsaAudio {
pub fn new(fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
let inner = Arc::new(Mutex::new(Inner{
mute: false,
volume: 0.,
}));
start_monitor(inner.clone());
let dev = AlsaAudio{ inner };
BarWidget::new(Box::new(dev), fm, font, size)
}
}
impl BarWidgetImpl for AlsaAudio {
fn name(&self) -> &'static str {
"audio"
}
fn get_dirty(&self) -> bool {
true
}
fn value(&mut self) -> f32 {
let inner = self.inner.lock().unwrap();
inner.volume
}
fn color(&self) -> Color {
let inner = self.inner.lock().unwrap();
if inner.mute {
Color::DARKORANGE
} else {
Color::WHITE
}
}
fn click(&mut self, pos: f32, btn: PointerButton) {
let inner = self.inner.lock().unwrap();
match btn {
// PointerButton::Left => inner.set_master_volume(pos),
//PointerButton::Right => Some(Change::ToggleMute),
//PointerButton::ScrollVertical(val) => Some(Change::VolumeInc((val / 512.) as f32)),
//PointerButton::ScrollHorizontal(val) => Some(Change::VolumeInc((val / 100.) as f32)),
_ => (),
};
}
}
+1 -1
View File
@@ -45,7 +45,7 @@ impl BarWidgetImpl for Backlight {
fn name(&self) -> &'static str {
"backlight"
}
fn value(&self) -> f32 {
fn value(&mut self) -> f32 {
if self.cur > self.max {
// what.
return 1.0;
+2 -3
View File
@@ -14,7 +14,7 @@ pub trait BarWidgetImpl {
false
}
fn name(&self) -> &'static str;
fn value(&self) -> f32;
fn value(&mut self) -> f32;
fn color(&self) -> Color;
fn click(&mut self, _pos: f32, _btn: PointerButton) {}
}
@@ -50,9 +50,8 @@ impl Widget for BarWidget {
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
let font = fonts.get_font(self.font, self.size);
let fg = Color::WHITE;
let bg = Color::BLACK;
font.draw_text(view, bg, fg, self.inner_widget.name())
font.draw_text(view, fg, self.inner_widget.name())
.unwrap();
let size = self.size.ceil() as u32;
let bar_offset = 4 * size;
+93 -67
View File
@@ -1,81 +1,111 @@
use std::{
sync::{Arc, Mutex},
thread,
error::Error,
time::Duration,
};
use dbus::blocking::{
stdintf::org_freedesktop_dbus::{Properties, PropertiesPropertiesChanged},
LocalConnection,
};
use crate::{
color::Color,
event::{Event, Events},
fonts::FontMap,
event::{Event, Events},
widgets::bar_widget::{BarWidget, BarWidgetImpl},
};
use upower_dbus::BatteryState;
enum UpowerBatteryState {
Charging,
Discharging,
Empty,
Full,
NotCharging,
Unknown,
}
struct InnerBattery {
value: f32,
state: BatteryState,
state: UpowerBatteryState,
dirty: bool,
}
async fn monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) -> Result<(), Box<dyn Error>> {
use zbus::Connection;
use upower_dbus::UPowerProxy;
use tokio_stream::StreamExt;
let conn = Connection::system().await?;
let proxy = UPowerProxy::new(&conn).await?;
let device = proxy.get_display_device().await?;
let local_inner = inner.clone();
let local_events = events.clone();
let mut percent_stream = device.receive_percentage_changed().await;
let a = tokio::spawn(async move {
while let Some(percent) = percent_stream.next().await {
let percent = percent.get().await.unwrap() as f32 / 100.;
let mut inner = local_inner.lock().unwrap();
inner.value = percent;
inner.dirty = true;
drop(inner);
let mut events = local_events.lock().unwrap();
events.add_event(Event::PowerUpdate);
}
});
let local_inner = inner.clone();
let local_events = events.clone();
let mut state_stream = device.receive_state_changed().await;
let b = tokio::spawn(async move {
while let Some(state) = state_stream.next().await {
let state = state.get().await.unwrap();
let mut inner = local_inner.lock().unwrap();
inner.state = state;
inner.dirty = true;
drop(inner);
let mut events = local_events.lock().unwrap();
events.add_event(Event::PowerUpdate);
}
});
a.await?;
b.await?;
Ok(())
}
fn start_monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) {
use tokio::runtime;
thread::Builder::new()
.name("battmon".to_string())
.spawn(move || {
let rt = runtime::Builder::new_current_thread()
.enable_io()
.build()
let conn = LocalConnection::new_system().unwrap();
let device_path = "/org/freedesktop/UPower/devices/DisplayDevice";
let proxy = conn.with_proxy(
"org.freedesktop.UPower",
device_path,
Duration::from_millis(500),
);
let capacity: f64 = proxy
.get("org.freedesktop.UPower.Device", "Percentage")
.expect("unable to get property");
let state: u32 = proxy
.get("org.freedesktop.UPower.Device", "State")
.expect("unable to get state");
{
let mut inner = inner.lock().unwrap();
inner.value = capacity as f32 / 100.;
inner.state = match state {
1 => UpowerBatteryState::Charging,
2 => UpowerBatteryState::Discharging,
3 => UpowerBatteryState::Empty,
4 => UpowerBatteryState::Full,
5 => UpowerBatteryState::NotCharging,
6 => UpowerBatteryState::Discharging,
_ => UpowerBatteryState::Unknown,
}
}
proxy
.match_signal(
move |c: PropertiesPropertiesChanged,
_: &LocalConnection,
_: &dbus::Message| {
if c.interface_name != "org.freedesktop.UPower.Device" {
return true;
}
let mut inner = inner.lock().unwrap();
for (key, value) in c.changed_properties {
match key.as_str() {
"State" => {
inner.state = match value.0.as_u64().unwrap() {
1 => UpowerBatteryState::Charging,
2 => UpowerBatteryState::Discharging,
3 => UpowerBatteryState::Empty,
4 => UpowerBatteryState::Full,
5 => UpowerBatteryState::NotCharging,
6 => UpowerBatteryState::Discharging,
_ => UpowerBatteryState::Unknown,
};
inner.dirty = true;
let mut events = events.lock().unwrap();
events.add_event(Event::PowerUpdate);
}
"Percentage" => {
inner.value = value.0.as_f64().unwrap() as f32 / 100.;
inner.dirty = true;
let mut events = events.lock().unwrap();
events.add_event(Event::PowerUpdate);
}
_ => (),
}
}
true
},
)
.unwrap();
rt.block_on(async move { monitor(inner, events).await }).unwrap();
loop {
conn.process(Duration::from_millis(60000)).unwrap();
}
})
.unwrap();
}
@@ -89,7 +119,7 @@ impl Battery {
let battery = Battery {
inner: Arc::new(Mutex::new(InnerBattery {
value: 0.,
state: BatteryState::Unknown,
state: UpowerBatteryState::Unknown,
dirty: false,
})),
};
@@ -105,7 +135,7 @@ impl BarWidgetImpl for Battery {
fn name(&self) -> &'static str {
"battery"
}
fn value(&self) -> f32 {
fn value(&mut self) -> f32 {
let mut inner = self.inner.lock().unwrap();
inner.dirty = false;
inner.value
@@ -113,15 +143,11 @@ impl BarWidgetImpl for Battery {
fn color(&self) -> Color {
let inner = self.inner.lock().unwrap();
match inner.state {
BatteryState::Charging | BatteryState::FullyCharged => Color::LIGHTGREEN,
BatteryState::PendingCharge => Color::LIGHTRED,
_ => if inner.value > 0.25 {
Color::WHITE
} else if inner.value > 0.1 {
Color::DARKORANGE
} else {
Color::RED
}
UpowerBatteryState::Charging | UpowerBatteryState::Full => Color::LIGHTGREEN,
UpowerBatteryState::NotCharging => Color::LIGHTRED,
_ if inner.value > 0.25 => Color::WHITE,
_ if inner.value > 0.1 => Color::DARKORANGE,
_ => Color::RED,
}
}
}
+1 -6
View File
@@ -52,7 +52,6 @@ impl Calendar {
orig: NaiveDate,
mut time: NaiveDate,
) {
let black = Color::BLACK;
let white = Color::WHITE;
let dim = Color::GREY80;
let dimmer = Color::GREY75;
@@ -85,7 +84,6 @@ impl Calendar {
y_off * (self.size * LINE_HEIGHT).ceil() as u32
+ (self.size * 1.).ceil() as u32,
)),
black,
white,
&wk_chr,
)
@@ -100,7 +98,6 @@ impl Calendar {
year_font
.draw_text(
&mut view.offset(((self.size * 17.).ceil() as u32, 0)),
black,
dim,
&format!("{:}", time.year()),
)
@@ -124,7 +121,7 @@ impl Calendar {
_ => panic!("impossible value"),
};
cal_font
.draw_text(&mut view, black, white, month_str)
.draw_text(&mut view, white, month_str)
.unwrap();
let mut done = false;
@@ -152,7 +149,6 @@ impl Calendar {
y_off * (self.size * LINE_HEIGHT).ceil() as u32
+ (self.size * MONTH_FACTOR).ceil() as u32,
)),
black,
dimmer,
&format!("{:02}", wk.week()),
)
@@ -177,7 +173,6 @@ impl Calendar {
y_off * (self.size * LINE_HEIGHT).ceil() as u32
+ (self.size * MONTH_FACTOR).ceil() as u32,
)),
black,
c,
&format!("{:02}", time.day()),
)
-2
View File
@@ -54,14 +54,12 @@ impl<'a> Widget for Clock {
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
let time = Local::now().naive_local();
let fg = Color::WHITE;
let bg = Color::BLACK;
let digit = self.digit_width;
let colon = self.colon_width;
let font = fonts.get_font(self.font, self.size);
font.draw_text_fixed_width(
view,
bg,
fg,
&[digit, digit, colon, digit, digit],
&format!("{:02}:{:02}", time.hour(), time.minute()),
-2
View File
@@ -50,11 +50,9 @@ impl<'a> Widget for Date {
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
let time = Local::now().naive_local();
let fg = Color::WHITE;
let bg = Color::BLACK;
let font = fonts.get_font(self.font, self.size);
font.draw_text(
view,
bg,
fg,
&format!(
"{}, {:02}/{:02}/{:4}",
+7 -13
View File
@@ -287,7 +287,6 @@ impl InterfaceWidget for Launcher {
view: &mut BufferView,
) -> Geometry {
let fg = Color::WHITE;
let bg = Color::BLACK;
let line_height = intf.size.ceil() as u32;
@@ -299,14 +298,13 @@ impl InterfaceWidget for Launcher {
let mut x_max = font
.auto_draw_text_with_cursor(
&mut prompt_line,
bg,
fg,
&format!(" {}", &intf.prompt.input),
intf.prompt.cursor + 3,
)
.unwrap();
font.auto_draw_text(&mut prompt_line, bg, fg, ">")
font.auto_draw_text(&mut prompt_line, fg, ">")
.unwrap();
// Draw entries
@@ -336,13 +334,13 @@ impl InterfaceWidget for Launcher {
}
x_max = max(
x_max,
font.auto_draw_text_individual_colors(&mut line, bg, &colors, &m.name)
font.auto_draw_text_individual_colors(&mut line, &colors, &m.name)
.unwrap(),
);
} else {
x_max = max(
x_max,
font.auto_draw_text(&mut line, bg, dimfg, &m.name)
font.auto_draw_text(&mut line, dimfg, &m.name)
.unwrap(),
);
}
@@ -386,7 +384,6 @@ impl InterfaceWidget for Shell {
view: &mut BufferView,
) -> Geometry {
let fg = Color::WHITE;
let bg = Color::BLACK;
let line_height = intf.size.ceil() as u32;
@@ -399,13 +396,12 @@ impl InterfaceWidget for Shell {
let x_max = font
.auto_draw_text_with_cursor(
&mut prompt_line,
bg,
fg,
&format!(" {}", &intf.prompt.input),
intf.prompt.cursor + 3,
)
.unwrap();
font.auto_draw_text(&mut prompt_line, bg, Color::BUFF, "!")
font.auto_draw_text(&mut prompt_line, Color::BUFF, "!")
.unwrap();
Geometry {
@@ -447,7 +443,6 @@ impl InterfaceWidget for Calc {
view: &mut BufferView,
) -> Geometry {
let fg = Color::WHITE;
let bg = Color::BLACK;
let line_height = intf.size.ceil() as u32;
@@ -460,20 +455,19 @@ impl InterfaceWidget for Calc {
let res_off = font
.auto_draw_text_with_cursor(
&mut prompt_line,
bg,
fg,
&format!(" {} ", &intf.prompt.input),
intf.prompt.cursor + 3,
)
.unwrap();
font.auto_draw_text(&mut prompt_line, bg, Color::BUFF, "=")
font.auto_draw_text(&mut prompt_line, Color::BUFF, "=")
.unwrap();
if let Some(res) = &self.result {
let resfg = Color::LIGHTORANGE;
let mut result_line = view.offset((res_off.0, prompt_offset));
font.auto_draw_text(&mut result_line, bg, resfg, &format!(" = {}", &res))
font.auto_draw_text(&mut result_line, resfg, &format!(" = {}", &res))
.unwrap();
}
@@ -484,7 +478,7 @@ impl InterfaceWidget for Calc {
}
prompt_offset -= line_height;
let mut result_line = view.offset((0, prompt_offset));
font.auto_draw_text(&mut result_line, bg, dimfg, &m)
font.auto_draw_text(&mut result_line, dimfg, &m)
.unwrap();
}
+4 -2
View File
@@ -1,4 +1,5 @@
mod audio;
//mod alsaaudio;
mod pulseaudio;
mod backlight;
mod bar_widget;
mod battery;
@@ -10,7 +11,8 @@ mod line;
mod widget;
mod layout;
pub use audio::Audio;
//pub use alsaaudio::AlsaAudio;
pub use pulseaudio::PulseAudio;
pub use backlight::Backlight;
pub use battery::Battery;
pub use calendar::Calendar;
@@ -177,7 +177,7 @@ enum Change {
ToggleMute,
}
pub struct InnerAudio {
struct InnerAudio {
volume: f32,
channel_volume: Option<ChannelVolumes>,
mute: bool,
@@ -186,14 +186,14 @@ pub struct InnerAudio {
pipe: RawFd,
}
pub struct Audio {
pub struct PulseAudio {
inner: Arc<Mutex<InnerAudio>>,
}
impl Audio {
impl PulseAudio {
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
let (a, b) = pipe().unwrap();
let audio = Audio {
let audio = PulseAudio {
inner: Arc::new(Mutex::new(InnerAudio{
volume: 0.0,
channel_volume: None,
@@ -208,15 +208,17 @@ impl Audio {
}
}
impl BarWidgetImpl for Audio {
impl BarWidgetImpl for PulseAudio {
fn get_dirty(&self) -> bool {
self.inner.lock().unwrap().dirty
}
fn name(&self) -> &'static str {
"volume"
}
fn value(&self) -> f32 {
self.inner.lock().unwrap().volume
fn value(&mut self) -> f32 {
let mut inner = self.inner.lock().unwrap();
inner.dirty = false;
inner.volume
}
fn color(&self) -> Color {
match self.inner.lock().unwrap().mute {