audio: Use relm4 next branch

This commit is contained in:
Ian Douglas Scott 2022-06-27 18:36:28 -07:00
parent 2e04938bbd
commit 1d40fe9a23
8 changed files with 86 additions and 217 deletions

143
Cargo.lock generated
View file

@ -309,26 +309,6 @@ dependencies = [
"xdg",
]
[[package]]
name = "cosmic-applet-audio"
version = "0.1.0"
dependencies = [
"async-io",
"freedesktop-desktop-entry",
"futures",
"futures-util",
"gtk4",
"libcosmic-widgets",
"libpulse-binding",
"libpulse-glib-binding",
"mpris2-zbus",
"once_cell",
"relm4-macros 0.4.4",
"tokio",
"tracker",
"zbus",
]
[[package]]
name = "cosmic-applet-graphics"
version = "0.1.0"
@ -610,15 +590,6 @@ dependencies = [
"generic-array",
]
[[package]]
name = "dirs"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs"
version = "4.0.0"
@ -815,19 +786,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9d758e60b45e8d749c89c1b389ad8aee550f86aa12e2b9298b546dda7a82ab1"
[[package]]
name = "freedesktop-desktop-entry"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45157175a725e81f3f594382430b6b78af5f8f72db9bd51b94f0785f80fc6d29"
dependencies = [
"dirs 3.0.2",
"gettext-rs",
"memchr",
"thiserror",
"xdg",
]
[[package]]
name = "fsevent-sys"
version = "4.1.0"
@ -1058,26 +1016,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "gettext-rs"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e49ea8a8fad198aaa1f9655a2524b64b70eb06b2f3ff37da407566c93054f364"
dependencies = [
"gettext-sys",
"locale_config",
]
[[package]]
name = "gettext-sys"
version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c63ce2e00f56a206778276704bbe38564c8695249fdc8f354b4ef71c57c3839d"
dependencies = [
"cc",
"temp-dir",
]
[[package]]
name = "gio"
version = "0.15.11"
@ -1528,56 +1466,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "libpulse-binding"
version = "2.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17be42160017e0ae993c03bfdab4ecb6f82ce3f8d515bd8da8fdf18d10703663"
dependencies = [
"bitflags",
"libc",
"libpulse-sys",
"num-derive",
"num-traits",
"winapi",
]
[[package]]
name = "libpulse-glib-binding"
version = "2.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df0e7a964c9f7e95d4f073affc19adfda009fa0d55e8831dbb66c78be1d0e6e5"
dependencies = [
"glib",
"glib-sys",
"libpulse-binding",
"libpulse-mainloop-glib-sys",
]
[[package]]
name = "libpulse-mainloop-glib-sys"
version = "1.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36f61c4064926cc77ea14bb206a21ce1d5a06e175e5c0ce078804bb6c4527b28"
dependencies = [
"glib-sys",
"libpulse-sys",
"pkg-config",
]
[[package]]
name = "libpulse-sys"
version = "1.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "991e6bd0efe2a36e6534e136e7996925e4c1a8e35b7807fe533f2beffff27c30"
dependencies = [
"libc",
"num-derive",
"num-traits",
"pkg-config",
"winapi",
]
[[package]]
name = "locale_config"
version = "0.3.0"
@ -1672,18 +1560,6 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "mpris2-zbus"
version = "0.1.0"
source = "git+https://github.com/pop-os/mpris2-zbus#bcc8481ea7ccfc08aa870f28272d9093db3b1ba9"
dependencies = [
"serde",
"thiserror",
"time 0.3.9",
"zbus",
"zvariant",
]
[[package]]
name = "nanorand"
version = "0.7.0"
@ -1759,17 +1635,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-derive"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "num-integer"
version = "0.1.45"
@ -2501,12 +2366,6 @@ dependencies = [
"version-compare",
]
[[package]]
name = "temp-dir"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af547b166dd1ea4b472165569fc456cfb6818116f854690b0ff205e636523dab"
[[package]]
name = "tempfile"
version = "3.3.0"
@ -2971,7 +2830,7 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6"
dependencies = [
"dirs 4.0.0",
"dirs",
]
[[package]]

View file

@ -1,6 +1,5 @@
[workspace]
members = [
"applets/cosmic-applet-audio",
"applets/cosmic-applet-graphics",
"applets/cosmic-applet-network",
"applets/cosmic-applet-notifications",
@ -13,5 +12,6 @@ members = [
]
exclude = [
"applets/cosmic-applet-audio",
"applets/cosmic-applet-battery",
]

View file

@ -7,7 +7,7 @@ license = "GPL-3.0-or-later"
[dependencies]
futures = "0.3.21"
futures-util = "0.3.21"
libcosmic-widgets = { git = "https://github.com/pop-os/libcosmic" }
libcosmic-widgets = { git = "https://github.com/pop-os/libcosmic", branch = "relm4-next" }
libpulse-binding = "2.26.0"
libpulse-glib-binding = "2.25.0"
tracker = "0.1.1"
@ -15,9 +15,10 @@ freedesktop-desktop-entry = "0.5.0"
mpris2-zbus = { git = "https://github.com/pop-os/mpris2-zbus" }
zbus = "2.1.1"
tokio = { version = "1.17.0", features = ["full"] }
relm4-macros = "0.4.4"
relm4 = { git = "https://github.com/relm4/relm4", branch = "next", features = ["macros"] }
relm4-macros = { git = "https://github.com/relm4/relm4", branch = "next" }
once_cell = "1.10.0"
gtk4 = { version = "0.4.7", features = ["v4_2"] }
gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_2"] }
async-io = "1.6.0"
[features]

View file

@ -2,17 +2,10 @@ use crate::icons::{parse_desktop_icons, DesktopApplication};
use futures_util::StreamExt;
use libcosmic_widgets::LabeledItem;
use libpulse_binding::{
context::subscribe::{Facility, InterestMaskSet, Operation},
context::{subscribe::{Facility, InterestMaskSet, Operation}, State},
volume::Volume,
};
use mpris2_zbus::media_player::MediaPlayer;
use pulsectl::{
controllers::{
types::{ApplicationInfo, DeviceInfo},
AppControl, DeviceControl, SinkController, SourceController,
},
Handler,
};
use relm4::{
component,
gtk::{
@ -22,12 +15,14 @@ use relm4::{
Align, Box as GtkBox, Button, Image, Label, ListBox, Orientation, PositionType, Revealer,
RevealerTransitionType, Scale, Separator, Window,
},
view, ComponentParts, RelmContainerExt, Sender, SimpleComponent,
view, ComponentParts, ComponentSender, RelmContainerExt, Sender, SimpleComponent, send,
};
use std::{collections::HashMap, rc::Rc};
use tracker::track;
use zbus::Connection;
use crate::pa::{DeviceInfo, PA};
pub enum AppInput {
Inputs,
Outputs,
@ -59,7 +54,7 @@ pub struct App {
#[do_not_track]
desktop_icons: HashMap<DesktopApplication, String>,
#[do_not_track]
handler: Handler,
pa: PA,
}
impl Default for App {
@ -74,15 +69,8 @@ impl Default for App {
let outputs = output_controller.list_devices().unwrap_or_default();
let now_playing = Vec::new();
let desktop_icons = parse_desktop_icons();
let handler = Handler::connect("com.system76.cosmic.applets.audio")
.expect("failed to connect to pulse");
relm4::spawn_local(clone!(@weak handler.mainloop as main_loop => async move {
let mut timer = async_io::Timer::interval(std::time::Duration::from_millis(100));
loop {
main_loop.borrow_mut().iterate(false);
timer.next().await;
}
}));
// XXX handle no pulseaudio daemon?
let pa = PA::new().unwrap();
Self {
default_input,
inputs,
@ -90,7 +78,7 @@ impl Default for App {
outputs,
now_playing,
desktop_icons,
handler,
pa,
tracker: 0,
}
}
@ -142,23 +130,27 @@ impl App {
}
fn subscribe_for_updates(&self, input: &Sender<AppInput>) {
let mut context = self.handler.context.borrow_mut();
let input_clone = input.clone();
context.set_subscribe_callback(Some(Box::new(move |facility, operation, _idx| {
self.pa.set_subscribe_callback(move |facility, operation, _idx| {
if !matches!(operation, Some(Operation::Changed)) {
return;
}
match facility {
Some(Facility::Sink) => {
send!(input_clone, AppInput::OutputVolume);
input_clone.send(AppInput::OutputVolume);
}
Some(Facility::Source) => {
send!(input_clone, AppInput::InputVolume);
input_clone.send(AppInput::InputVolume);
}
_ => {}
}
})));
context.subscribe(InterestMaskSet::SINK | InterestMaskSet::SOURCE, |_| {});
});
self.pa.set_state_callback(move |pa, state| {
if state == State::Ready {
pa.subscribe(InterestMaskSet::SINK | InterestMaskSet::SOURCE);
}
});
}
fn refresh_input_list(&mut self) {
let mut input_controller =
@ -277,7 +269,8 @@ impl App {
append: media_buttons = &GtkBox {
set_halign: Align::End,
append: pause_button = &Button {
set_child: pause_button_img = Some(&Image) {
#[wrap(Some)]
set_child: pause_button_img = &Image {
set_icon_name: Some("media-playback-pause-symbolic"),
set_pixel_size: 24,
},
@ -309,89 +302,95 @@ impl SimpleComponent for App {
set_default_width: 400,
set_default_height: 300,
&GtkBox {
GtkBox {
set_orientation: Orientation::Vertical,
set_spacing: 24,
&GtkBox {
GtkBox {
set_orientation: Orientation::Horizontal,
set_spacing: 16,
&Image {
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.) },
#[watch]
set_value: 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
}
},
&GtkBox {
GtkBox {
set_orientation: Orientation::Horizontal,
set_spacing: 16,
&Image {
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.)
},
#[watch]
set_value: 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
}
},
&Separator {
Separator {
set_orientation: Orientation::Horizontal,
},
&GtkBox {
GtkBox {
set_orientation: Orientation::Vertical,
&Button {
set_child: current_output = Some(&Label) {
set_text: watch! { model.get_default_output_name() }
Button {
#[wrap(Some)]
set_child: current_output = &Label {
#[watch]
set_text: model.get_default_output_name()
},
connect_clicked(input, outputs_revealer) => move |_| {
send!(input, AppInput::Outputs);
connect_clicked[sender, outputs_revealer] => move |_| {
sender.input(AppInput::Outputs);
outputs_revealer.set_reveal_child(!outputs_revealer.reveals_child());
}
},
append: outputs_revealer = &Revealer {
set_transition_type: RevealerTransitionType::SlideDown,
set_child: outputs = Some(&ListBox) {
#[wrap(Some)]
set_child: outputs = &ListBox {
set_selection_mode: gtk::SelectionMode::None,
set_activate_on_single_click: true
}
}
},
&Separator {
Separator {
set_orientation: Orientation::Horizontal,
},
&GtkBox {
GtkBox {
set_orientation: Orientation::Vertical,
&Button {
set_child: current_input = Some(&Label) {
set_text: watch! { model.get_default_input_name() }
Button {
#[wrap(Some)]
set_child: current_input = &Label {
#[watch]
set_text: model.get_default_input_name()
},
connect_clicked(input, inputs_revealer) => move |_| {
send!(input, AppInput::Inputs);
connect_clicked[sender, inputs_revealer] => move |_| {
sender.input(AppInput::Inputs);
inputs_revealer.set_reveal_child(!inputs_revealer.reveals_child());
}
},
append: inputs_revealer = &Revealer {
set_transition_type: RevealerTransitionType::SlideDown,
set_child: inputs = Some(&ListBox) {
#[wrap(Some)]
set_child: inputs = &ListBox {
set_selection_mode: gtk::SelectionMode::None,
set_activate_on_single_click: true
}
}
},
&Separator {
Separator {
set_orientation: Orientation::Horizontal,
},
append: playing_apps = &ListBox {
@ -401,15 +400,14 @@ impl SimpleComponent for App {
}
}
fn init_parts(
fn init(
_init_params: Self::InitParams,
root: &Self::Root,
input: &Sender<Self::Input>,
_output: &Sender<Self::Output>,
sender: &ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = App::default();
let widgets = view_output!();
model.subscribe_for_updates(input);
model.subscribe_for_updates(&sender.input);
ComponentParts { model, widgets }
}
@ -417,8 +415,7 @@ impl SimpleComponent for App {
fn update(
&mut self,
msg: Self::Input,
_input: &Sender<Self::Input>,
_output: &Sender<Self::Output>,
_sender: &ComponentSender<Self>,
) {
self.reset();
match msg {

View file

@ -82,7 +82,8 @@ fn app(application: &Application) {
set_default_width: 400,
set_default_height: 300,
set_child: window_box = Some(&GtkBox) {
#[wrap(Some)]
set_child: window_box = &GtkBox {
set_orientation: Orientation::Vertical,
set_spacing: 24,
append: output_box = &GtkBox {
@ -119,14 +120,16 @@ fn app(application: &Application) {
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 |_| {
#[wrap(Some)]
set_child: current_output = &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) {
#[wrap(Some)]
set_child: outputs = &ListBox {
set_selection_mode: SelectionMode::None,
set_activate_on_single_click: true
}
@ -138,14 +141,16 @@ fn app(application: &Application) {
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 |_| {
#[wrap(Some)]
set_child: current_input = &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) {
#[wrap(Some)]
set_child: inputs = &ListBox {
set_selection_mode: SelectionMode::None,
set_activate_on_single_click: true
}

View file

@ -19,6 +19,7 @@ pub struct DeviceInfo {
pub name: Option<String>,
pub description: Option<String>,
pub volume: ChannelVolumes,
pub index: u32,
}
pub struct ServerInfo {
@ -104,6 +105,7 @@ impl PA {
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 => {
sender.take().unwrap().send(Ok(items.take().unwrap()));
@ -132,6 +134,7 @@ impl PA {
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 => {
@ -163,6 +166,7 @@ impl PA {
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 => {
sender.take().unwrap().send(Ok(items.take().unwrap()));
@ -191,6 +195,7 @@ impl PA {
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 => {

3
debian/rules vendored
View file

@ -13,12 +13,13 @@ override_dh_shlibdeps:
override_dh_auto_clean:
if test "${CLEAN}" = "1"; then \
cargo clean; \
cargo clean --manifest-path applets/cosmic-applet-audio/Cargo.toml; \
cargo clean --manifest-path applets/cosmic-applet-battery/Cargo.toml; \
fi
if ! ischroot && test "${VENDOR}" = "1"; then \
mkdir -p .cargo; \
cargo vendor --sync Cargo.toml --sync applets/cosmic-applet-battery/Cargo.toml | head -n -1 > .cargo/config; \
cargo vendor --sync Cargo.toml --sync applets/cosmic-applet-audio/Cargo.toml applets/cosmic-applet-battery/Cargo.toml | head -n -1 > .cargo/config; \
echo 'directory = "vendor"' >> .cargo/config; \
tar pcf vendor.tar vendor; \
rm -rf vendor; \

View file

@ -28,6 +28,7 @@ workspaces_button_id := 'com.system76.CosmicPanelWorkspacesButton'
all: _extract_vendor
cargo build {{cargo_args}}
cargo build --manifest-path applets/cosmic-applet-audio/Cargo.toml {{cargo_args}}
cargo build --manifest-path applets/cosmic-applet-battery/Cargo.toml {{cargo_args}}
# Installs files into the system
@ -42,7 +43,7 @@ install:
# audio
install -Dm0644 applets/cosmic-applet-audio/data/icons/{{audio_id}}.svg {{iconsdir}}/{{audio_id}}.svg
install -Dm0644 applets/cosmic-applet-audio/data/{{audio_id}}.desktop {{sharedir}}/applications/{{audio_id}}.desktop
install -Dm0755 target/release/cosmic-applet-audio {{bindir}}/cosmic-applet-audio
install -Dm0755 applets/cosmic-applet-audio/target/release/cosmic-applet-audio {{bindir}}/cosmic-applet-audio
# battery
install -Dm0644 applets/cosmic-applet-battery/data/icons/{{battery_id}}.svg {{iconsdir}}/{{battery_id}}.svg