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 } ;
58use 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 } ;
711use 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
1228impl 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 ) ]
2541pub struct Page {
2642 entity : page:: Entity ,
43+ model : model:: Model ,
44+ client : Option < Rc < RefCell < audio_client:: Client > > > ,
2745}
2846
2947impl 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
61124impl 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
67153pub 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