removed callback patterns
Release / Build and Release (push) Successful in 22s

This commit is contained in:
2026-04-05 11:38:14 +02:00
parent fdfd54b518
commit 5c5d0148f8
2 changed files with 116 additions and 92 deletions
+115 -82
View File
@@ -2,7 +2,7 @@ use crate::config::Config;
use crate::error::{FluxoError, Result}; use crate::error::{FluxoError, Result};
use crate::modules::WaybarModule; use crate::modules::WaybarModule;
use crate::output::WaybarOutput; use crate::output::WaybarOutput;
use crate::state::{AppReceivers, AudioState}; use crate::state::{AppReceivers, AudioDeviceInfo, AudioState};
use crate::utils::{TokenValue, format_template}; use crate::utils::{TokenValue, format_template};
use libpulse_binding::callbacks::ListResult; use libpulse_binding::callbacks::ListResult;
use libpulse_binding::context::subscribe::{Facility, InterestMaskSet}; use libpulse_binding::context::subscribe::{Facility, InterestMaskSet};
@@ -230,91 +230,124 @@ fn fetch_audio_data_sync(
let _ = tx_server.send(current); let _ = tx_server.send(current);
}); });
let tx_sink = state_tx.clone(); fetch_sinks(context, state_tx);
let pending_sinks: Arc<std::sync::Mutex<Vec<String>>> = fetch_sources(context, state_tx);
Arc::new(std::sync::Mutex::new(Vec::new()));
let pending_sinks_cb = Arc::clone(&pending_sinks);
context.introspect().get_sink_info_list(move |res| {
let mut current = tx_sink.borrow().clone();
match res {
ListResult::Item(item) => {
if let Some(name) = item.name.as_ref() {
let name_str = name.to_string();
pending_sinks_cb.lock().unwrap().push(name_str);
}
let is_default = item
.name
.as_ref()
.map(|s| s.as_ref() == current.sink.name)
.unwrap_or(false);
if is_default {
current.sink.description = item
.description
.as_ref()
.map(|s| s.to_string())
.unwrap_or_default();
current.sink.volume = ((item.volume.avg().0 as f64 / Volume::NORMAL.0 as f64)
* 100.0)
.round() as u8;
current.sink.muted = item.mute;
current.sink.channels = item.volume.len();
}
let _ = tx_sink.send(current);
}
ListResult::End => {
current.available_sinks = pending_sinks_cb.lock().unwrap().drain(..).collect();
let _ = tx_sink.send(current);
}
ListResult::Error => {}
}
});
let tx_source = state_tx.clone();
let pending_sources: Arc<std::sync::Mutex<Vec<String>>> =
Arc::new(std::sync::Mutex::new(Vec::new()));
let pending_sources_cb = Arc::clone(&pending_sources);
context.introspect().get_source_info_list(move |res| {
let mut current = tx_source.borrow().clone();
match res {
ListResult::Item(item) => {
if let Some(name) = item.name.as_ref() {
let name_str = name.to_string();
if !name_str.contains(".monitor") {
pending_sources_cb.lock().unwrap().push(name_str);
}
}
let is_default = item
.name
.as_ref()
.map(|s| s.as_ref() == current.source.name)
.unwrap_or(false);
if is_default {
current.source.description = item
.description
.as_ref()
.map(|s| s.to_string())
.unwrap_or_default();
current.source.volume = ((item.volume.avg().0 as f64 / Volume::NORMAL.0 as f64)
* 100.0)
.round() as u8;
current.source.muted = item.mute;
current.source.channels = item.volume.len();
}
let _ = tx_source.send(current);
}
ListResult::End => {
current.available_sources = pending_sources_cb.lock().unwrap().drain(..).collect();
let _ = tx_source.send(current);
}
ListResult::Error => {}
}
});
Ok(()) Ok(())
} }
/// Shared bookkeeping for a device list fetch.
struct PendingList {
names: Arc<std::sync::Mutex<Vec<String>>>,
}
impl PendingList {
fn new() -> Self {
Self {
names: Arc::new(std::sync::Mutex::new(Vec::new())),
}
}
fn push(&self, name: String) {
self.names.lock().unwrap().push(name);
}
fn drain(&self) -> Vec<String> {
self.names.lock().unwrap().drain(..).collect()
}
}
/// Extract common device info from a pulse item's volume/mute/description fields.
fn device_info_from(
description: Option<&str>,
volume: &libpulse_binding::volume::ChannelVolumes,
muted: bool,
) -> (String, u8, bool, u8) {
let desc = description.unwrap_or_default().to_string();
let vol = ((volume.avg().0 as f64 / Volume::NORMAL.0 as f64) * 100.0).round() as u8;
let channels = volume.len();
(desc, vol, muted, channels)
}
fn apply_device_info(target: &mut AudioDeviceInfo, item_name: &str, info: (String, u8, bool, u8)) {
if item_name == target.name {
target.description = info.0;
target.volume = info.1;
target.muted = info.2;
target.channels = info.3;
}
}
fn fetch_sinks(context: &mut Context, state_tx: &watch::Sender<AudioState>) {
let tx = state_tx.clone();
let pending = PendingList::new();
let pending_cb = PendingList {
names: Arc::clone(&pending.names),
};
context.introspect().get_sink_info_list(move |res| {
let mut current = tx.borrow().clone();
match res {
ListResult::Item(item) => {
let name_str = item
.name
.as_ref()
.map(|s| s.to_string())
.unwrap_or_default();
if !name_str.is_empty() {
pending_cb.push(name_str.clone());
}
let info = device_info_from(
item.description.as_ref().map(|s| s.as_ref()),
&item.volume,
item.mute,
);
apply_device_info(&mut current.sink, &name_str, info);
let _ = tx.send(current);
}
ListResult::End => {
current.available_sinks = pending_cb.drain();
let _ = tx.send(current);
}
ListResult::Error => {}
}
});
}
fn fetch_sources(context: &mut Context, state_tx: &watch::Sender<AudioState>) {
let tx = state_tx.clone();
let pending = PendingList::new();
let pending_cb = PendingList {
names: Arc::clone(&pending.names),
};
context.introspect().get_source_info_list(move |res| {
let mut current = tx.borrow().clone();
match res {
ListResult::Item(item) => {
let name_str = item
.name
.as_ref()
.map(|s| s.to_string())
.unwrap_or_default();
if !name_str.is_empty() && !name_str.contains(".monitor") {
pending_cb.push(name_str.clone());
}
let info = device_info_from(
item.description.as_ref().map(|s| s.as_ref()),
&item.volume,
item.mute,
);
apply_device_info(&mut current.source, &name_str, info);
let _ = tx.send(current);
}
ListResult::End => {
current.available_sources = pending_cb.drain();
let _ = tx.send(current);
}
ListResult::Error => {}
}
});
}
pub struct AudioModule; pub struct AudioModule;
impl WaybarModule for AudioModule { impl WaybarModule for AudioModule {
+1 -10
View File
@@ -39,7 +39,7 @@ pub struct ModuleHealth {
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct AudioState { pub struct AudioState {
pub sink: AudioDeviceInfo, pub sink: AudioDeviceInfo,
pub source: AudioSourceInfo, pub source: AudioDeviceInfo,
pub available_sinks: Vec<String>, pub available_sinks: Vec<String>,
pub available_sources: Vec<String>, pub available_sources: Vec<String>,
} }
@@ -53,15 +53,6 @@ pub struct AudioDeviceInfo {
pub channels: u8, pub channels: u8,
} }
#[derive(Default, Clone)]
pub struct AudioSourceInfo {
pub name: String,
pub description: String,
pub volume: u8,
pub muted: bool,
pub channels: u8,
}
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct BtDeviceInfo { pub struct BtDeviceInfo {
pub device_alias: String, pub device_alias: String,