Skip to content

Commit 96e90bf

Browse files
committed
feat(sound): rebase with varlink sound settings API
1 parent c06b184 commit 96e90bf

21 files changed

Lines changed: 818 additions & 4674 deletions

File tree

Cargo.lock

Lines changed: 122 additions & 305 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["cosmic-settings", "crates/*", "page", "pages/*", "subscriptions/*"]
2+
members = ["cosmic-settings", "page", "pages/*", "subscriptions/*"]
33
default-members = ["cosmic-settings"]
44
resolver = "3"
55

cosmic-settings/Cargo.toml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ cosmic-settings-airplane-mode-subscription = { path = "../subscriptions/airplane
3636
cosmic-settings-bluetooth-subscription = { path = "../subscriptions/bluetooth", optional = true }
3737
cosmic-settings-network-manager-subscription = { path = "../subscriptions/network-manager", optional = true }
3838
cosmic-settings-upower-subscription = { path = "../subscriptions/upower", optional = true }
39-
cosmic-settings-sound-subscription = { path = "../subscriptions/sound", optional = true, features = [
40-
"auto-profile-init",
41-
] }
4239
cosmic-settings-wallpaper = { path = "../pages/wallpapers" }
4340
cosmic-settings-daemon-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", optional = true }
4441
derive_setters = "0.1.9"
@@ -98,6 +95,14 @@ gettext-rs = { version = "0.7.7", features = [
9895
num-traits = "0.2"
9996
pwhash = "1"
10097
which = "8.0.0"
98+
zlink = "0.4.1"
99+
intmap = "3.1.3"
100+
101+
[dependencies.cosmic-settings-audio-client]
102+
git = "https://github.com/pop-os/cosmic-settings-daemon"
103+
branch = "varlink"
104+
features = ["codec"]
105+
optional = true
101106

102107
[dependencies.icu]
103108
version = "2.1.1"
@@ -181,7 +186,7 @@ page-region = [
181186
"dep:zbus",
182187
"dep:accounts-zbus",
183188
]
184-
page-sound = ["dep:cosmic-settings-sound-subscription"]
189+
page-sound = ["dep:cosmic-settings-audio-client"]
185190
page-users = ["xdg-portal", "dep:accounts-zbus", "dep:zbus", "dep:zbus_polkit"]
186191
page-window-management = ["cosmic-comp-config", "dep:cosmic-settings-config"]
187192
page-workspaces = ["cosmic-comp-config"]

cosmic-settings/src/pages/sound/device_profiles.rs

Lines changed: 107 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
// Copyright 2025 System76 <info@system76.com>
22
// SPDX-License-Identifier: GPL-3.0-only
33

4-
use cosmic::{Apply, widget};
4+
use super::model;
5+
use cosmic::iced::futures;
6+
use cosmic::{Apply, iced, widget};
7+
use cosmic_settings_audio_client::{self as audio_client, CosmicAudioProxy};
58
use cosmic_settings_page::{self as page, Section, section};
6-
use cosmic_settings_sound_subscription::{self as subscription};
9+
use futures::executor::block_on;
10+
use futures::{SinkExt, StreamExt};
711
use slotmap::SlotMap;
12+
use std::cell::RefCell;
13+
use std::rc::Rc;
14+
use std::sync::Arc;
815

916
#[derive(Clone, Debug)]
10-
pub enum Message {}
17+
pub enum Message {
18+
/// Varlink client connection to the audio settings daemon.
19+
Client(Arc<audio_client::Client>),
20+
/// Set the profile of a sound device.
21+
SetProfile(u32, u32),
22+
/// Audio events from the audio settings daemon.
23+
Subscription(audio_client::Event),
24+
/// Surface Action
25+
Surface(cosmic::surface::Action),
26+
}
1127

1228
impl From<Message> for crate::pages::Message {
1329
fn from(message: Message) -> Self {
@@ -24,6 +40,8 @@ impl From<Message> for crate::Message {
2440
#[derive(Default)]
2541
pub struct Page {
2642
entity: page::Entity,
43+
model: model::Model,
44+
client: Option<Rc<RefCell<audio_client::Client>>>,
2745
}
2846

2947
impl page::AutoBind<crate::pages::Message> for Page {}
@@ -41,55 +59,115 @@ impl page::Page<crate::pages::Message> for Page {
4159
Some(vec![sections.insert(view())])
4260
}
4361

44-
fn on_leave(&mut self) -> cosmic::Task<crate::pages::Message> {
45-
cosmic::Task::done(crate::pages::Message::Sound(super::Message::Reload))
46-
}
47-
4862
fn set_id(&mut self, entity: cosmic_settings_page::Entity) {
4963
self.entity = entity;
5064
}
5165

52-
fn subscription(
53-
&self,
54-
_core: &cosmic::Core,
55-
) -> cosmic::iced::Subscription<crate::pages::Message> {
56-
cosmic::iced::Subscription::run(subscription::watch)
57-
.map(|message| super::Message::Subscription(message).into())
66+
fn on_leave(&mut self) -> cosmic::Task<crate::pages::Message> {
67+
*self = Page {
68+
entity: self.entity,
69+
..Page::default()
70+
};
71+
cosmic::Task::none()
72+
}
73+
74+
fn subscription(&self, _core: &cosmic::Core) -> iced::Subscription<crate::pages::Message> {
75+
iced::Subscription::run(|| {
76+
iced::stream::channel(
77+
1,
78+
move |mut emitter: futures::channel::mpsc::Sender<crate::pages::Message>| async move {
79+
loop {
80+
let mut client = match audio_client::connect().await {
81+
Ok(client) => client,
82+
Err(why) => {
83+
if let zlink::Error::Io(ref why) = why
84+
&& why.kind() == std::io::ErrorKind::NotFound
85+
{
86+
tracing::error!(
87+
"cosmic-settings-daemon varlink service not found. Restarting cosmic-settings-daemon"
88+
);
89+
_ = std::process::Command::new("killall")
90+
.args(&["-2", "cosmic-settings-daemon"])
91+
.status();
92+
} else {
93+
tracing::error!(
94+
?why,
95+
"failed to connect to cosmic-settings's varlink service"
96+
);
97+
}
98+
99+
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
100+
continue;
101+
}
102+
};
103+
104+
if let Ok(Ok(mut stream)) = client.recv_events().await {
105+
_ = emitter.send(Message::Client(Arc::new(client)).into()).await;
106+
while let Some(message) = stream.next().await {
107+
match message {
108+
Ok(event) => {
109+
_ = emitter.send(Message::Subscription(event).into()).await;
110+
}
111+
Err(why) => {
112+
tracing::error!(?why, "event error");
113+
}
114+
}
115+
}
116+
}
117+
}
118+
},
119+
)
120+
})
58121
}
59122
}
60123

61124
impl Page {
62-
pub fn update(&mut self, _message: Message) -> cosmic::Task<crate::app::Message> {
125+
pub fn update(&mut self, message: Message) -> cosmic::Task<crate::app::Message> {
126+
match message {
127+
Message::Subscription(event) => {
128+
self.model.update(event);
129+
}
130+
131+
Message::Surface(a) => return cosmic::task::message(crate::app::Message::Surface(a)),
132+
133+
Message::SetProfile(id, index) => {
134+
if let Some(client) = self.client.clone() {
135+
block_on(async move {
136+
_ = client.borrow_mut().conn.set_profile(id, index, true).await;
137+
});
138+
}
139+
}
140+
141+
Message::Client(client) => {
142+
if let Some(client) = Arc::into_inner(client) {
143+
self.client = Some(Rc::new(RefCell::new(client)));
144+
self.model = model::Model::default();
145+
}
146+
}
147+
}
148+
63149
cosmic::Task::none()
64150
}
65151
}
66152

67153
pub fn view() -> Section<crate::pages::Message> {
68-
Section::default().view::<Page>(move |binder, _page, _section| {
69-
let sound_page_id = binder.find_page_by_id("sound").unwrap().0;
70-
let sound_page = binder.page[sound_page_id]
71-
.downcast_ref::<super::Page>()
72-
.unwrap();
73-
74-
let devices = sound_page
75-
.model
76-
.device_profile_dropdowns
77-
.iter()
78-
.cloned()
79-
.map(|(device_id, name, active_profile, indexes, descriptions)| {
154+
Section::default().view::<Page>(move |_, page, _section| {
155+
let devices = page.model.device_profile_dropdowns.iter().cloned().map(
156+
|(device_id, name, active_profile, indexes, descriptions)| {
80157
let dropdown = widget::dropdown::popup_dropdown(
81158
descriptions,
82159
active_profile,
83-
move |id| super::Message::SetProfile(device_id, indexes[id]),
160+
move |id| Message::SetProfile(device_id, indexes[id]),
84161
cosmic::iced::window::Id::RESERVED,
85-
super::Message::Surface,
162+
Message::Surface,
86163
crate::Message::from,
87164
)
88165
.apply(cosmic::Element::from)
89166
.map(crate::pages::Message::from);
90167

91168
widget::settings::item::builder(name).control(dropdown)
92-
});
169+
},
170+
);
93171

94172
widget::settings::section().extend(devices).into()
95173
})

0 commit comments

Comments
 (0)