audio: Set icon based on volume and mute status of output
This commit is contained in:
parent
3884f08504
commit
0e7baf704b
3 changed files with 51 additions and 29 deletions
|
|
@ -82,9 +82,8 @@ fn app(application: &Application) {
|
||||||
set_application: Some(application),
|
set_application: Some(application),
|
||||||
set_title: Some("COSMIC Network Applet"),
|
set_title: Some("COSMIC Network Applet"),
|
||||||
#[wrap(Some)]
|
#[wrap(Some)]
|
||||||
set_child = &libcosmic_applet::AppletButton {
|
set_child: button = &libcosmic_applet::AppletButton {
|
||||||
// TODO: adjust based on volume, mute
|
set_button_icon_name: "audio-volume-medium-symbolic",
|
||||||
set_button_icon_name: "multimedia-volume-control-symbolic",
|
|
||||||
#[wrap(Some)]
|
#[wrap(Some)]
|
||||||
set_popover_child: window_box = &GtkBox {
|
set_popover_child: window_box = &GtkBox {
|
||||||
set_orientation: Orientation::Vertical,
|
set_orientation: Orientation::Vertical,
|
||||||
|
|
@ -180,11 +179,26 @@ fn app(application: &Application) {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
glib::MainContext::default().spawn_local(
|
glib::MainContext::default().spawn_local(
|
||||||
clone!(@weak outputs, @weak current_output, @weak output_volume, @strong pa => async move {
|
clone!(@weak outputs, @weak current_output, @weak output_volume, @strong pa, @strong button, => async move {
|
||||||
while let Some(()) = refresh_output_rx.next().await {
|
while let Some(()) = refresh_output_rx.next().await {
|
||||||
output::refresh_output_widgets(&pa, &outputs);
|
output::refresh_output_widgets(&pa, &outputs);
|
||||||
let default_output = output::refresh_default_output(&pa, ¤t_output).await;
|
let default_output = output::refresh_default_output(&pa, ¤t_output).await;
|
||||||
volume::update_volume(&default_output, &output_volume);
|
volume::update_volume(&default_output, &output_volume);
|
||||||
|
button.set_button_icon_name({
|
||||||
|
let volume = default_output.volume.avg().0 as f64 / Volume::NORMAL.0 as f64;
|
||||||
|
// XXX correct cutoffs?
|
||||||
|
if default_output.mute {
|
||||||
|
"audio-volume-muted"
|
||||||
|
} else if volume > 1.0 {
|
||||||
|
"audio-volume-overamplified-symbolic"
|
||||||
|
} else if volume > 0.66 {
|
||||||
|
"audio-volume-high-symbolic"
|
||||||
|
} else if volume > 0.33 {
|
||||||
|
"audio-volume-medium-symbolic"
|
||||||
|
} else {
|
||||||
|
"audio-volume-low-symbolic"
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use gtk4::glib;
|
||||||
use libpulse_binding::{
|
use libpulse_binding::{
|
||||||
callbacks::ListResult,
|
callbacks::ListResult,
|
||||||
context::{
|
context::{
|
||||||
introspect::{Introspector, SinkInfo},
|
introspect::{Introspector, SinkInfo, SourceInfo},
|
||||||
subscribe::{Facility, InterestMaskSet, Operation},
|
subscribe::{Facility, InterestMaskSet, Operation},
|
||||||
Context, FlagSet, State,
|
Context, FlagSet, State,
|
||||||
},
|
},
|
||||||
|
|
@ -19,9 +19,34 @@ pub struct DeviceInfo {
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub volume: ChannelVolumes,
|
pub volume: ChannelVolumes,
|
||||||
|
pub mute: bool,
|
||||||
pub index: u32,
|
pub index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&SinkInfo<'a>> for DeviceInfo {
|
||||||
|
fn from(info: &SinkInfo<'a>) -> Self {
|
||||||
|
Self {
|
||||||
|
name: info.name.clone().map(|x| x.into_owned()),
|
||||||
|
description: info.description.clone().map(|x| x.into_owned()),
|
||||||
|
volume: info.volume,
|
||||||
|
mute: info.mute,
|
||||||
|
index: info.index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&SourceInfo<'a>> for DeviceInfo {
|
||||||
|
fn from(info: &SourceInfo<'a>) -> Self {
|
||||||
|
Self {
|
||||||
|
name: info.name.clone().map(|x| x.into_owned()),
|
||||||
|
description: info.description.clone().map(|x| x.into_owned()),
|
||||||
|
volume: info.volume,
|
||||||
|
mute: info.mute,
|
||||||
|
index: info.index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ServerInfo {
|
pub struct ServerInfo {
|
||||||
pub default_sink_name: Option<String>,
|
pub default_sink_name: Option<String>,
|
||||||
pub default_source_name: Option<String>,
|
pub default_source_name: Option<String>,
|
||||||
|
|
@ -105,12 +130,7 @@ impl PA {
|
||||||
PAFut::new(|waker| {
|
PAFut::new(|waker| {
|
||||||
self.introspect()
|
self.introspect()
|
||||||
.get_sink_info_list(move |result| match result {
|
.get_sink_info_list(move |result| match result {
|
||||||
ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo {
|
ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo::from(item)),
|
||||||
name: item.name.clone().map(|x| x.into_owned()),
|
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
|
||||||
volume: item.volume,
|
|
||||||
index: item.index,
|
|
||||||
}),
|
|
||||||
ListResult::End => waker.wake(Ok(items.take().unwrap())),
|
ListResult::End => waker.wake(Ok(items.take().unwrap())),
|
||||||
ListResult::Error => waker.wake(Err(())),
|
ListResult::Error => waker.wake(Err(())),
|
||||||
})
|
})
|
||||||
|
|
@ -130,12 +150,7 @@ impl PA {
|
||||||
self.introspect()
|
self.introspect()
|
||||||
.get_sink_info_by_name(&name, move |result| match result {
|
.get_sink_info_by_name(&name, move |result| match result {
|
||||||
ListResult::Item(item) => {
|
ListResult::Item(item) => {
|
||||||
sink = Some(DeviceInfo {
|
sink = Some(DeviceInfo::from(item));
|
||||||
name: item.name.clone().map(|x| x.into_owned()),
|
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
|
||||||
volume: item.volume,
|
|
||||||
index: item.index,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
ListResult::End => waker.wake(sink.take().ok_or(())),
|
ListResult::End => waker.wake(sink.take().ok_or(())),
|
||||||
ListResult::Error => waker.wake(Err(())),
|
ListResult::Error => waker.wake(Err(())),
|
||||||
|
|
@ -158,12 +173,7 @@ impl PA {
|
||||||
PAFut::new(|waker| {
|
PAFut::new(|waker| {
|
||||||
self.introspect()
|
self.introspect()
|
||||||
.get_source_info_list(move |result| match result {
|
.get_source_info_list(move |result| match result {
|
||||||
ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo {
|
ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo::from(item)),
|
||||||
name: item.name.clone().map(|x| x.into_owned()),
|
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
|
||||||
volume: item.volume,
|
|
||||||
index: item.index,
|
|
||||||
}),
|
|
||||||
ListResult::End => waker.wake(Ok(items.take().unwrap())),
|
ListResult::End => waker.wake(Ok(items.take().unwrap())),
|
||||||
ListResult::Error => waker.wake(Err(())),
|
ListResult::Error => waker.wake(Err(())),
|
||||||
})
|
})
|
||||||
|
|
@ -183,12 +193,7 @@ impl PA {
|
||||||
self.introspect()
|
self.introspect()
|
||||||
.get_source_info_by_name(&name, move |result| match result {
|
.get_source_info_by_name(&name, move |result| match result {
|
||||||
ListResult::Item(item) => {
|
ListResult::Item(item) => {
|
||||||
source = Some(DeviceInfo {
|
source = Some(DeviceInfo::from(item));
|
||||||
name: item.name.clone().map(|x| x.into_owned()),
|
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
|
||||||
volume: item.volume,
|
|
||||||
index: item.index,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
ListResult::End => waker.wake(source.take().ok_or(())),
|
ListResult::End => waker.wake(source.take().ok_or(())),
|
||||||
ListResult::Error => waker.wake(Err(())),
|
ListResult::Error => waker.wake(Err(())),
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// TODO: Use `Volume::ui_max()`?
|
||||||
|
// * Make sure volumes greater than this are handled properly.
|
||||||
|
|
||||||
use gtk4::{glib, prelude::*, subclass::prelude::*};
|
use gtk4::{glib, prelude::*, subclass::prelude::*};
|
||||||
use libpulse_binding::volume::{ChannelVolumes, Volume};
|
use libpulse_binding::volume::{ChannelVolumes, Volume};
|
||||||
use std::{
|
use std::{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue