🚧 Begin rewrite of cosmic-applet-audio
This commit is contained in:
parent
f3a92fbdfd
commit
2c591d1ba3
5 changed files with 167 additions and 21 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
|
@ -246,11 +246,14 @@ dependencies = [
|
||||||
"async-io",
|
"async-io",
|
||||||
"freedesktop-desktop-entry",
|
"freedesktop-desktop-entry",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"gtk4",
|
||||||
"libcosmic-widgets",
|
"libcosmic-widgets",
|
||||||
"libpulse-binding",
|
"libpulse-binding",
|
||||||
"mpris2-zbus",
|
"mpris2-zbus",
|
||||||
|
"once_cell",
|
||||||
"pulsectl-rs",
|
"pulsectl-rs",
|
||||||
"relm4",
|
"relm4-macros 0.4.4",
|
||||||
|
"tokio",
|
||||||
"tracker",
|
"tracker",
|
||||||
"zbus",
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
@ -1071,7 +1074,7 @@ version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=lucy/widgets#d004d686bd83e55f8f5058700941284ca84dc579"
|
source = "git+https://github.com/pop-os/libcosmic?branch=lucy/widgets#d004d686bd83e55f8f5058700941284ca84dc579"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"relm4",
|
"relm4",
|
||||||
"relm4-macros 0.4.1 (git+https://github.com/AaronErhardt/relm4?branch=new-approach)",
|
"relm4-macros 0.4.1",
|
||||||
"tracker",
|
"tracker",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1660,7 +1663,6 @@ dependencies = [
|
||||||
"gtk4",
|
"gtk4",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"relm4-macros 0.4.1 (git+https://github.com/AaronErhardt/relm4?rev=7404ad64ca8763f6629cadcd743947cd29e1538a)",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1674,16 +1676,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "relm4-macros"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "git+https://github.com/AaronErhardt/relm4?rev=7404ad64ca8763f6629cadcd743947cd29e1538a#7404ad64ca8763f6629cadcd743947cd29e1538a"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "relm4-macros"
|
name = "relm4-macros"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,18 @@ edition = "2021"
|
||||||
license = "LGPL-3.0-or-later"
|
license = "LGPL-3.0-or-later"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-io = "1.6.0"
|
|
||||||
futures-util = "0.3.21"
|
futures-util = "0.3.21"
|
||||||
libcosmic-widgets = { git = "https://github.com/pop-os/libcosmic", branch = "lucy/widgets" }
|
libcosmic-widgets = { git = "https://github.com/pop-os/libcosmic", branch = "lucy/widgets" }
|
||||||
libpulse-binding = "2.26.0"
|
libpulse-binding = "2.26.0"
|
||||||
pulsectl-rs = "0.3.2"
|
pulsectl-rs = "0.3.2"
|
||||||
relm4 = { git = "https://github.com/AaronErhardt/relm4", rev = "7404ad64ca8763f6629cadcd743947cd29e1538a", features = [
|
|
||||||
"macros",
|
|
||||||
] }
|
|
||||||
tracker = "0.1.1"
|
tracker = "0.1.1"
|
||||||
freedesktop-desktop-entry = "0.5.0"
|
freedesktop-desktop-entry = "0.5.0"
|
||||||
mpris2-zbus = { git = "https://github.com/pop-os/mpris2-zbus" }
|
mpris2-zbus = { git = "https://github.com/pop-os/mpris2-zbus" }
|
||||||
zbus = "2.1.1"
|
zbus = "2.1.1"
|
||||||
|
tokio = { version = "1.17.0", features = ["full"] }
|
||||||
|
relm4-macros = "0.4.4"
|
||||||
|
once_cell = "1.10.0"
|
||||||
|
gtk4 = { version = "0.4.7", features = ["v4_2"] }
|
||||||
|
async-io = "1.6.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,119 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate relm4;
|
extern crate relm4_macros;
|
||||||
|
|
||||||
mod app;
|
|
||||||
mod icons;
|
mod icons;
|
||||||
|
mod pa;
|
||||||
|
mod task;
|
||||||
|
|
||||||
use relm4::RelmApp;
|
use gtk4::{
|
||||||
|
glib::{self, clone},
|
||||||
|
prelude::*,
|
||||||
|
Align, Box as GtkBox, Button, Image, Label, ListBox, Orientation, PositionType, Revealer,
|
||||||
|
RevealerTransitionType, Scale, SelectionMode, Separator, Window,
|
||||||
|
};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use pulsectl::Handler;
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
|
static RT: Lazy<Runtime> = Lazy::new(|| Runtime::new().expect("failed to build tokio runtime"));
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
RelmApp::<app::App>::new("com.system76.cosmic.applets.audio").run(());
|
let handler =
|
||||||
|
Handler::connect("com.system76.cosmic.applets.audio").expect("failed to connect to pulse");
|
||||||
|
task::spawn_local(clone!(@strong handler.mainloop as main_loop => async move {
|
||||||
|
pa::drive_main_loop(main_loop).await
|
||||||
|
}));
|
||||||
|
view! {
|
||||||
|
window = Window {
|
||||||
|
set_title: Some("COSMIC Network Applet"),
|
||||||
|
set_default_width: 400,
|
||||||
|
set_default_height: 300,
|
||||||
|
|
||||||
|
set_child: window_box = Some(&GtkBox) {
|
||||||
|
set_orientation: Orientation::Vertical,
|
||||||
|
set_spacing: 24,
|
||||||
|
append: output_box = &GtkBox {
|
||||||
|
set_orientation: Orientation::Horizontal,
|
||||||
|
set_spacing: 16,
|
||||||
|
append: output_icon = &Image {
|
||||||
|
set_icon_name: Some("audio-speakers-symbolic"),
|
||||||
|
},
|
||||||
|
append: output_volume = &Scale::with_range(Orientation::Horizontal, 0., 100., 1.) {
|
||||||
|
set_format_value_func: |_, value| {
|
||||||
|
format!("{:.0}%", value)
|
||||||
|
},
|
||||||
|
//set_value: watch! { model.default_output.as_ref().map(|info| (info.volume.avg().0 as f64 / Volume::NORMAL.0 as f64) * 100.).unwrap_or(0.) },
|
||||||
|
set_value_pos: PositionType::Right,
|
||||||
|
set_hexpand: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append: input_box = &GtkBox {
|
||||||
|
set_orientation: Orientation::Horizontal,
|
||||||
|
set_spacing: 16,
|
||||||
|
append: input_icon = &Image {
|
||||||
|
set_icon_name: Some("audio-input-microphone-symbolic"),
|
||||||
|
},
|
||||||
|
append: input_volume = &Scale::with_range(Orientation::Horizontal, 0., 100., 1.) {
|
||||||
|
set_format_value_func: |_, value| {
|
||||||
|
format!("{:.0}%", value)
|
||||||
|
},
|
||||||
|
/*set_value: watch! {
|
||||||
|
model.default_input
|
||||||
|
.as_ref()
|
||||||
|
.map(|info| (info.volume.avg().0 as f64 / Volume::NORMAL.0 as f64) * 100.)
|
||||||
|
.unwrap_or(0.)
|
||||||
|
},*/
|
||||||
|
set_value_pos: PositionType::Right,
|
||||||
|
set_hexpand: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append: _sep = &Separator {
|
||||||
|
set_orientation: Orientation::Horizontal,
|
||||||
|
},
|
||||||
|
append: output_list_box = &GtkBox {
|
||||||
|
set_orientation: Orientation::Vertical,
|
||||||
|
append: current_output_button = &Button {
|
||||||
|
set_child: current_output = Some(&Label) {},
|
||||||
|
connect_clicked(outputs_revealer) => move |_| {
|
||||||
|
outputs_revealer.set_reveal_child(!outputs_revealer.reveals_child());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append: outputs_revealer = &Revealer {
|
||||||
|
set_transition_type: RevealerTransitionType::SlideDown,
|
||||||
|
set_child: outputs = Some(&ListBox) {
|
||||||
|
set_selection_mode: SelectionMode::None,
|
||||||
|
set_activate_on_single_click: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append: _sep = &Separator {
|
||||||
|
set_orientation: Orientation::Horizontal,
|
||||||
|
},
|
||||||
|
append: input_list_box = &GtkBox {
|
||||||
|
set_orientation: Orientation::Vertical,
|
||||||
|
append: current_input_button = &Button {
|
||||||
|
set_child: current_input = Some(&Label) {},
|
||||||
|
connect_clicked(inputs_revealer) => move |_| {
|
||||||
|
inputs_revealer.set_reveal_child(!inputs_revealer.reveals_child());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append: inputs_revealer = &Revealer {
|
||||||
|
set_transition_type: RevealerTransitionType::SlideDown,
|
||||||
|
set_child: inputs = Some(&ListBox) {
|
||||||
|
set_selection_mode: SelectionMode::None,
|
||||||
|
set_activate_on_single_click: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
append: _sep = &Separator {
|
||||||
|
set_orientation: Orientation::Horizontal,
|
||||||
|
},
|
||||||
|
append: playing_apps = &ListBox {
|
||||||
|
set_selection_mode: SelectionMode::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
applets/cosmic-applet-audio/src/pa.rs
Normal file
12
applets/cosmic-applet-audio/src/pa.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
use async_io::Timer;
|
||||||
|
use futures_util::StreamExt;
|
||||||
|
use libpulse_binding::mainloop::standard::Mainloop;
|
||||||
|
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||||
|
|
||||||
|
pub async fn drive_main_loop(main_loop: Rc<RefCell<Mainloop>>) {
|
||||||
|
let mut timer = Timer::interval(Duration::from_millis(100));
|
||||||
|
loop {
|
||||||
|
main_loop.borrow_mut().iterate(false);
|
||||||
|
timer.next().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
35
applets/cosmic-applet-audio/src/task.rs
Normal file
35
applets/cosmic-applet-audio/src/task.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
use std::future::Future;
|
||||||
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
|
pub fn spawn<O, F>(future: F) -> tokio::task::JoinHandle<O>
|
||||||
|
where
|
||||||
|
F: Future<Output = O> + Send + 'static,
|
||||||
|
O: Send + 'static,
|
||||||
|
{
|
||||||
|
crate::RT.spawn(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block_on<O, F>(future: F) -> O
|
||||||
|
where
|
||||||
|
F: Future<Output = O> + Send + 'static,
|
||||||
|
O: Send + 'static,
|
||||||
|
{
|
||||||
|
crate::RT.block_on(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_local<F: Future<Output = ()> + 'static>(future: F) {
|
||||||
|
gtk4::glib::MainContext::default().spawn_local(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_for_local<O, F>(future: F) -> Option<O>
|
||||||
|
where
|
||||||
|
O: Send + 'static,
|
||||||
|
F: Future<Output = O> + Send + 'static,
|
||||||
|
{
|
||||||
|
let (tx, rx) = oneshot::channel::<O>();
|
||||||
|
gtk4::glib::MainContext::default().spawn_local(async move {
|
||||||
|
std::mem::drop(tx.send(future.await));
|
||||||
|
});
|
||||||
|
rx.await.ok()
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue