Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/clients/volume/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub enum Event {
AddInput(SinkInput),
UpdateInput(SinkInput),
RemoveInput(u32),
VolumeUp(f64),
VolumeDown(f64),
}

#[derive(Debug)]
Expand Down Expand Up @@ -309,4 +311,18 @@ pub fn percent_to_volume(target_percent: f64) -> u32 {
}
}

pub fn scroll_to_volume(current_value: u32, scroll_value: f64) -> u32 {
let mut val: i32 = current_value as i32;
let scroll_delta = scroll_value * -1000.0;
trace!("base+delta: {val} + {scroll_delta} orig: scroll_value");
val += scroll_delta as i32;
if val > Volume::NORMAL.0 as i32 {
Volume::NORMAL.0 as u32
} else if val < Volume::MUTED.0 as i32 {
Volume::MUTED.0 as u32
} else {
val as u32
}
}

register_client!(Client, volume);
40 changes: 39 additions & 1 deletion src/clients/volume/sink.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use super::{ArcMutVec, Client, ConnectionState, Event, percent_to_volume, volume_to_percent};
use super::{
ArcMutVec, Client, ConnectionState, Event, percent_to_volume, scroll_to_volume,
volume_to_percent,
};
use crate::channels::SyncSenderExt;
use crate::lock;
use libpulse_binding::callbacks::ListResult;
Expand Down Expand Up @@ -54,6 +57,41 @@ impl Client {
}
}

#[instrument(level = "trace")]
pub fn set_default_volume(&self, value: f64) {
trace!("raceived volume change: {value:?}");
let mut active = None;
for sync in &*lock!(self.data.sinks) {
if sync.active {
active = Some(sync.name.to_string());
break;
}
}
if let Some(name) = active {
if let ConnectionState::Connected { introspector, .. } = &mut *lock!(self.connection) {
let (tx, rx) = mpsc::channel();

introspector.get_sink_info_by_name(&name, move |info| {
let ListResult::Item(info) = info else {
return;
};

tx.send_expect(info.volume);
});

let mut volume = rx.recv().expect("to receive info");
for v in volume.get_mut() {
let dval = v.0;
let val = scroll_to_volume(v.0, value);
trace!("changing value from: {dval:?} to: {val}");
v.0 = val;
}

introspector.set_sink_volume_by_name(&name, &volume, None);
}
}
}

#[instrument(level = "trace")]
pub fn set_sink_volume(&self, name: &str, volume_percent: f64) {
if let ConnectionState::Connected { introspector, .. } = &mut *lock!(self.connection) {
Expand Down
61 changes: 54 additions & 7 deletions src/modules/volume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ use crate::modules::{
};
use crate::{lock, module_impl, spawn};
use glib::Propagation;
use gtk::gdk::{EventMask, ScrollDirection};
use gtk::pango::EllipsizeMode;
use gtk::prelude::*;
use gtk::{Button, CellRendererText, ComboBoxText, Label, Orientation, Scale, ToggleButton};
use gtk::{
Button, CellRendererText, ComboBoxText, EventBox, Label, Orientation, Scale, ToggleButton,
};
use serde::Deserialize;
use std::collections::HashMap;
use tokio::sync::mpsc;
Expand Down Expand Up @@ -134,9 +137,11 @@ pub enum Update {

InputVolume(u32, f64),
InputMute(u32, bool),
InputVolumeUp(f64),
InputVolumeDown(f64),
}

impl Module<Button> for VolumeModule {
impl Module<EventBox> for VolumeModule {
type SendMessage = Event;
type ReceiveMessage = Update;

Expand All @@ -149,7 +154,7 @@ impl Module<Button> for VolumeModule {
mut rx: mpsc::Receiver<Self::ReceiveMessage>,
) -> color_eyre::Result<()>
where
<Self as Module<Button>>::SendMessage: Clone,
<Self as Module<EventBox>>::SendMessage: Clone,
{
let client = context.client::<volume::Client>();

Expand Down Expand Up @@ -200,6 +205,8 @@ impl Module<Button> for VolumeModule {
Update::SinkVolume(name, volume) => client.set_sink_volume(&name, volume),
Update::SinkMute(name, muted) => client.set_sink_muted(&name, muted),
Update::InputVolume(index, volume) => client.set_input_volume(index, volume),
Update::InputVolumeUp(val) => client.set_default_volume(val),
Update::InputVolumeDown(val) => client.set_default_volume(val),
Update::InputMute(index, muted) => client.set_input_muted(index, muted),
}
}
Expand All @@ -212,17 +219,17 @@ impl Module<Button> for VolumeModule {
self,
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
info: &ModuleInfo,
) -> color_eyre::Result<ModuleParts<Button>>
) -> color_eyre::Result<ModuleParts<EventBox>>
where
<Self as Module<Button>>::SendMessage: Clone,
<Self as Module<EventBox>>::SendMessage: Clone,
{
let button_label = Label::builder()
.use_markup(true)
.angle(self.layout.angle(info))
.justify(self.layout.justify.into())
.build();

let button = Button::new();
let button = Button::builder().build();
button.add(&button_label);

{
Expand Down Expand Up @@ -257,11 +264,42 @@ impl Module<Button> for VolumeModule {
},
);

let event_box = EventBox::builder()
.events(
EventMask::SCROLL_MASK
| EventMask::SMOOTH_SCROLL_MASK
| EventMask::BUTTON_MOTION_MASK,
)
.child(&button)
.build();

{
let tx = context.tx.clone();
event_box.connect_scroll_event(move |_button, scroll| {
match scroll.direction() {
ScrollDirection::Up => {
tx.send_update_spawn(Event::VolumeUp(scroll.delta().1));
}
ScrollDirection::Down => {
tx.send_update_spawn(Event::VolumeDown(scroll.delta().1));
}
ScrollDirection::Smooth => {
if scroll.scroll_deltas().unwrap_or_default().1 > 0.0 {
tx.send_update_spawn(Event::VolumeUp(scroll.delta().1));
} else {
tx.send_update_spawn(Event::VolumeDown(scroll.delta().1));
}
}
_ => {}
}
Propagation::Stop
});
}
let popup = self
.into_popup(context, info)
.into_popup_parts(vec![&button]);

Ok(ModuleParts::new(button, popup))
Ok(ModuleParts::new(event_box, popup))
}

fn into_popup(
Expand Down Expand Up @@ -356,6 +394,8 @@ impl Module<Button> for VolumeModule {
let mut inputs = HashMap::new();
let mut sinks = vec![];

let tx = context.controller_tx.clone();

context
.subscribe()
.recv_glib(&input_container, move |input_container, event| {
Expand Down Expand Up @@ -480,6 +520,13 @@ impl Module<Button> for VolumeModule {
input_container.remove(&ui.container);
}
}
Event::VolumeUp(val) => {
tx.send_spawn(Update::InputVolumeUp(val));
}

Event::VolumeDown(val) => {
tx.send_spawn(Update::InputVolumeDown(val));
}
}
});

Expand Down
Loading