Skip to content

Commit 580b24e

Browse files
tglmanJakeStanger
authored andcommitted
feat: add support to change the volume scrolling on the volume icon
1 parent 2da4408 commit 580b24e

File tree

3 files changed

+109
-8
lines changed

3 files changed

+109
-8
lines changed

src/clients/volume/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub enum Event {
2929
AddInput(SinkInput),
3030
UpdateInput(SinkInput),
3131
RemoveInput(u32),
32+
VolumeUp(f64),
33+
VolumeDown(f64),
3234
}
3335

3436
#[derive(Debug)]
@@ -309,4 +311,18 @@ pub fn percent_to_volume(target_percent: f64) -> u32 {
309311
}
310312
}
311313

314+
pub fn scroll_to_volume(current_value: u32, scroll_value: f64) -> u32 {
315+
let mut val: i32 = current_value as i32;
316+
let scroll_delta = scroll_value * -1000.0;
317+
trace!("base+delta: {val} + {scroll_delta} orig: scroll_value");
318+
val += scroll_delta as i32;
319+
if val > Volume::NORMAL.0 as i32 {
320+
Volume::NORMAL.0 as u32
321+
} else if val < Volume::MUTED.0 as i32 {
322+
Volume::MUTED.0 as u32
323+
} else {
324+
val as u32
325+
}
326+
}
327+
312328
register_client!(Client, volume);

src/clients/volume/sink.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use super::{ArcMutVec, Client, ConnectionState, Event, percent_to_volume, volume_to_percent};
1+
use super::{
2+
ArcMutVec, Client, ConnectionState, Event, percent_to_volume, scroll_to_volume,
3+
volume_to_percent,
4+
};
25
use crate::channels::SyncSenderExt;
36
use crate::lock;
47
use libpulse_binding::callbacks::ListResult;
@@ -54,6 +57,41 @@ impl Client {
5457
}
5558
}
5659

60+
#[instrument(level = "trace")]
61+
pub fn set_default_volume(&self, value: f64) {
62+
trace!("raceived volume change: {value:?}");
63+
let mut active = None;
64+
for sync in &*lock!(self.data.sinks) {
65+
if sync.active {
66+
active = Some(sync.name.to_string());
67+
break;
68+
}
69+
}
70+
if let Some(name) = active {
71+
if let ConnectionState::Connected { introspector, .. } = &mut *lock!(self.connection) {
72+
let (tx, rx) = mpsc::channel();
73+
74+
introspector.get_sink_info_by_name(&name, move |info| {
75+
let ListResult::Item(info) = info else {
76+
return;
77+
};
78+
79+
tx.send_expect(info.volume);
80+
});
81+
82+
let mut volume = rx.recv().expect("to receive info");
83+
for v in volume.get_mut() {
84+
let dval = v.0;
85+
let val = scroll_to_volume(v.0, value);
86+
trace!("changing value from: {dval:?} to: {val}");
87+
v.0 = val;
88+
}
89+
90+
introspector.set_sink_volume_by_name(&name, &volume, None);
91+
}
92+
}
93+
}
94+
5795
#[instrument(level = "trace")]
5896
pub fn set_sink_volume(&self, name: &str, volume_percent: f64) {
5997
if let ConnectionState::Connected { introspector, .. } = &mut *lock!(self.connection) {

src/modules/volume.rs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ use crate::modules::{
77
};
88
use crate::{lock, module_impl, spawn};
99
use glib::Propagation;
10+
use gtk::gdk::{EventMask, ScrollDirection};
1011
use gtk::pango::EllipsizeMode;
1112
use gtk::prelude::*;
12-
use gtk::{Button, CellRendererText, ComboBoxText, Label, Orientation, Scale, ToggleButton};
13+
use gtk::{
14+
Button, CellRendererText, ComboBoxText, EventBox, Label, Orientation, Scale, ToggleButton,
15+
};
1316
use serde::Deserialize;
1417
use std::collections::HashMap;
1518
use tokio::sync::mpsc;
@@ -134,9 +137,11 @@ pub enum Update {
134137

135138
InputVolume(u32, f64),
136139
InputMute(u32, bool),
140+
InputVolumeUp(f64),
141+
InputVolumeDown(f64),
137142
}
138143

139-
impl Module<Button> for VolumeModule {
144+
impl Module<EventBox> for VolumeModule {
140145
type SendMessage = Event;
141146
type ReceiveMessage = Update;
142147

@@ -149,7 +154,7 @@ impl Module<Button> for VolumeModule {
149154
mut rx: mpsc::Receiver<Self::ReceiveMessage>,
150155
) -> color_eyre::Result<()>
151156
where
152-
<Self as Module<Button>>::SendMessage: Clone,
157+
<Self as Module<EventBox>>::SendMessage: Clone,
153158
{
154159
let client = context.client::<volume::Client>();
155160

@@ -200,6 +205,8 @@ impl Module<Button> for VolumeModule {
200205
Update::SinkVolume(name, volume) => client.set_sink_volume(&name, volume),
201206
Update::SinkMute(name, muted) => client.set_sink_muted(&name, muted),
202207
Update::InputVolume(index, volume) => client.set_input_volume(index, volume),
208+
Update::InputVolumeUp(val) => client.set_default_volume(val),
209+
Update::InputVolumeDown(val) => client.set_default_volume(val),
203210
Update::InputMute(index, muted) => client.set_input_muted(index, muted),
204211
}
205212
}
@@ -212,17 +219,17 @@ impl Module<Button> for VolumeModule {
212219
self,
213220
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
214221
info: &ModuleInfo,
215-
) -> color_eyre::Result<ModuleParts<Button>>
222+
) -> color_eyre::Result<ModuleParts<EventBox>>
216223
where
217-
<Self as Module<Button>>::SendMessage: Clone,
224+
<Self as Module<EventBox>>::SendMessage: Clone,
218225
{
219226
let button_label = Label::builder()
220227
.use_markup(true)
221228
.angle(self.layout.angle(info))
222229
.justify(self.layout.justify.into())
223230
.build();
224231

225-
let button = Button::new();
232+
let button = Button::builder().build();
226233
button.add(&button_label);
227234

228235
{
@@ -257,11 +264,42 @@ impl Module<Button> for VolumeModule {
257264
},
258265
);
259266

267+
let event_box = EventBox::builder()
268+
.events(
269+
EventMask::SCROLL_MASK
270+
| EventMask::SMOOTH_SCROLL_MASK
271+
| EventMask::BUTTON_MOTION_MASK,
272+
)
273+
.child(&button)
274+
.build();
275+
276+
{
277+
let tx = context.tx.clone();
278+
event_box.connect_scroll_event(move |_button, scroll| {
279+
match scroll.direction() {
280+
ScrollDirection::Up => {
281+
tx.send_update_spawn(Event::VolumeUp(scroll.delta().1));
282+
}
283+
ScrollDirection::Down => {
284+
tx.send_update_spawn(Event::VolumeDown(scroll.delta().1));
285+
}
286+
ScrollDirection::Smooth => {
287+
if scroll.scroll_deltas().unwrap_or_default().1 > 0.0 {
288+
tx.send_update_spawn(Event::VolumeUp(scroll.delta().1));
289+
} else {
290+
tx.send_update_spawn(Event::VolumeDown(scroll.delta().1));
291+
}
292+
}
293+
_ => {}
294+
}
295+
Propagation::Stop
296+
});
297+
}
260298
let popup = self
261299
.into_popup(context, info)
262300
.into_popup_parts(vec![&button]);
263301

264-
Ok(ModuleParts::new(button, popup))
302+
Ok(ModuleParts::new(event_box, popup))
265303
}
266304

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

397+
let tx = context.controller_tx.clone();
398+
359399
context
360400
.subscribe()
361401
.recv_glib(&input_container, move |input_container, event| {
@@ -480,6 +520,13 @@ impl Module<Button> for VolumeModule {
480520
input_container.remove(&ui.container);
481521
}
482522
}
523+
Event::VolumeUp(val) => {
524+
tx.send_spawn(Update::InputVolumeUp(val));
525+
}
526+
527+
Event::VolumeDown(val) => {
528+
tx.send_spawn(Update::InputVolumeDown(val));
529+
}
483530
}
484531
});
485532

0 commit comments

Comments
 (0)