1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use crate::widget::{Widget, WidgetUpdate};
use crate::protocol::{Block, ColorRGB};
use alsa::mixer::{Mixer, Selem, SelemId, SelemChannelId};
use alsa::Result;
use std::ffi::CString;
pub struct VolumeWidget {
device: CString,
#[allow(dead_code)]
mixer : CString,
selem_id: SelemId,
}
impl VolumeWidget {
fn get_volume(&self) -> Result<Option<(bool, u32)>> {
let mut handle = Mixer::open(false)?;
handle.attach(self.device.as_c_str())?;
Selem::register(&mut handle)?;
handle.load()?;
if let Some(selem) = handle.find_selem(&self.selem_id) {
let (min,max) = selem.get_playback_volume_range();
let vol = selem.get_playback_volume(SelemChannelId::FrontLeft)?;
let mute = selem.get_playback_switch(SelemChannelId::FrontLeft)?;
let vol = ((100 * (vol - min)) as f32 / (max - min) as f32).round() as u32;
return Ok(Some((mute == 0, vol)));
}
return Ok(None);
}
pub fn new(device:&str, mixer:&str, idx:u32) -> Self {
let device = CString::new(device).unwrap();
let mixer = CString::new(mixer).unwrap();
let mut selem_id = SelemId::empty();
selem_id.set_name(mixer.as_c_str());
selem_id.set_index(idx);
Self { device, mixer, selem_id }
}
}
impl Widget for VolumeWidget {
fn update(&mut self) -> Option<WidgetUpdate> {
if let Ok(Some((mute, vol))) = self.get_volume() {
let icon = if !mute { "🔊" } else {"🔇"};
let status = format!("{}%{}", vol, icon);
let mut data = Block::new().append_full_text(&status).clone();
if mute {
data.color(ColorRGB::yellow());
}
return Some(WidgetUpdate {
refresh_interval: std::time::Duration::new(1, 0),
data:Some(data)
})
}
None
}
}