Merge remote-tracking branch 'upstream/master' into yoda-dock-magnification

# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	cosmic-app-list/src/app.rs
#	cosmic-applet-audio/src/lib.rs
#	cosmic-applet-input-sources/Cargo.toml
#	cosmic-applet-input-sources/src/lib.rs
#	cosmic-applet-status-area/src/components/app.rs
#	cosmic-panel-button/src/lib.rs
This commit is contained in:
Lionel DARNIS 2026-08-19 22:04:42 +02:00
commit 673547dc52
119 changed files with 2247 additions and 1190 deletions

View file

@ -33,10 +33,15 @@ use cosmic::{
};
use cosmic_settings_audio_client::{self as audio_client, CosmicAudioProxy};
use futures::SinkExt;
use iced::platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup};
use mpris_subscription::{MprisRequest, MprisUpdate};
use mpris2_zbus::player::PlaybackStatus;
use std::{cell::RefCell, rc::Rc, sync::Arc};
use std::{
sync::{
Arc,
atomic::{self, AtomicU32},
},
time::Duration,
};
mod config;
mod mpris_subscription;
@ -58,11 +63,15 @@ pub struct Audio {
/// Track the applet's popup window.
popup: Option<window::Id>,
/// Varlink connection to `com.system76.CosmicSettings.Audio`.
audio_client: Option<Rc<RefCell<audio_client::Client>>>,
audio_client: Option<audio_client::Client>,
/// Known audio device state
model: model::Model,
/// Whether to expand the revealer of a source or sink device.
is_open: IsOpen,
/// Used to debounce sink volume updates.
applied_sink_volume: Arc<AtomicU32>,
/// Used to deboune source volume updates.
applied_source_volume: Arc<AtomicU32>,
/// Max slider volume for the sink device, as determined by the amplification property.
max_sink_volume: u32,
/// Max slider volume for the source device, as determined by the amplification property.
@ -140,26 +149,27 @@ enum IsOpen {
pub enum Message {
/// Connection to `com.system76.CosmicSettings`.
Client(Arc<audio_client::Client>),
Ignore,
SetSinkVolume(u32),
SetSourceVolume(u32),
ToggleSinkMute,
ToggleSourceMute,
SetDefaultSink(usize),
SetDefaultSource(usize),
OutputToggle,
InputToggle,
TogglePopup,
CloseRequested(window::Id),
ToggleMediaControlsInTopPanel(bool),
ConfigChanged(AudioAppletConfig),
Ignore,
InputToggle,
Mpris(mpris_subscription::MprisUpdate),
MprisRequest(MprisRequest),
Token(TokenUpdate),
OpenSettings,
OutputToggle,
ReattachClient(Arc<audio_client::Client>),
Rectangle(RectangleUpdate<u32>),
SetDefaultSink(usize),
SetDefaultSource(usize),
SetSinkVolume(u32),
SetSourceVolume(u32),
Subscription(audio_client::Event),
Surface(surface::Action),
Rectangle(RectangleUpdate<u32>),
ToggleMediaControlsInTopPanel(bool),
TogglePopup,
ToggleSinkMute,
ToggleSourceMute,
Token(TokenUpdate),
}
// TODO
@ -302,32 +312,45 @@ impl cosmic::Application for Audio {
self.rectangle_tracker.replace(tracker);
}
},
Message::ReattachClient(client) => {
if let Some(client) = Arc::into_inner(client) {
self.audio_client = Some(client);
}
}
Message::Ignore => {}
Message::TogglePopup => {
if let Some(p) = self.popup.take() {
return destroy_popup(p);
return cosmic::surface::surface_task(cosmic::surface::action::destroy_popup(
p,
));
} else {
let new_id = window::Id::unique();
self.popup.replace(new_id);
return cosmic::surface::surface_task(cosmic::surface::action::app_popup(
|_| Default::default(),
|app: &mut Self| {
let new_id = window::Id::unique();
app.popup.replace(new_id);
self.refresh_volume_limits();
let mut popup_settings = self.core.applet.get_popup_settings(
self.core.main_window_id().unwrap(),
new_id,
let mut popup_settings = app.core.applet.get_popup_settings(
app.core.main_window_id().unwrap(),
new_id,
None,
None,
None,
);
if let Some(r) = app.rectangle {
popup_settings.positioner.anchor_rect = Rectangle {
x: r.x as i32,
y: r.y as i32,
width: r.width as i32,
height: r.height as i32,
};
}
popup_settings
},
None,
None,
None,
);
if let Some(r) = self.rectangle {
popup_settings.positioner.anchor_rect = Rectangle {
x: r.x as i32,
y: r.y as i32,
width: r.width as i32,
height: r.height as i32,
};
}
return get_popup(popup_settings);
));
}
}
@ -355,7 +378,7 @@ impl cosmic::Application for Audio {
&& let Some(client) = self.audio_client.as_mut()
{
futures::executor::block_on(async {
_ = client.borrow_mut().conn.set_default(node_id, true).await;
_ = client.conn.set_default(node_id, true).await;
});
}
}
@ -366,7 +389,7 @@ impl cosmic::Application for Audio {
&& let Some(client) = self.audio_client.as_mut()
{
futures::executor::block_on(async {
_ = client.borrow_mut().conn.set_default(node_id, true).await;
_ = client.conn.set_default(node_id, true).await;
});
}
}
@ -374,7 +397,7 @@ impl cosmic::Application for Audio {
Message::ToggleSinkMute => {
if let Some(ref mut client) = self.audio_client {
futures::executor::block_on(async {
_ = client.borrow_mut().conn.sink_mute_toggle().await;
_ = client.conn.sink_mute_toggle().await;
});
}
}
@ -382,27 +405,43 @@ impl cosmic::Application for Audio {
Message::ToggleSourceMute => {
if let Some(ref mut client) = self.audio_client {
futures::executor::block_on(async {
_ = client.borrow_mut().conn.source_mute_toggle().await;
_ = client.conn.source_mute_toggle().await;
});
}
}
Message::SetSinkVolume(volume) => {
if let Some(ref mut client) = self.audio_client {
self.model.active_sink.volume = volume;
self.model.active_sink.volume_text = volume.to_string();
futures::executor::block_on(async {
_ = client.borrow_mut().conn.set_sink_volume(volume).await;
self.applied_sink_volume
.store(volume, atomic::Ordering::Relaxed);
self.model.active_sink.volume = volume;
self.model.active_sink.volume_text = volume.to_string();
if let Some(mut client) = self.audio_client.take() {
let volume = Arc::clone(&self.applied_sink_volume);
return cosmic::Task::future(async move {
tokio::time::sleep(Duration::from_millis(128)).await;
_ = client
.conn
.set_sink_volume(volume.load(atomic::Ordering::Relaxed))
.await;
Message::ReattachClient(Arc::new(client)).into()
});
}
}
Message::SetSourceVolume(volume) => {
if let Some(ref mut client) = self.audio_client {
self.model.active_source.volume = volume;
self.model.active_source.volume_text = volume.to_string();
futures::executor::block_on(async {
_ = client.borrow_mut().conn.set_source_volume(volume).await;
self.applied_source_volume
.store(volume, atomic::Ordering::Relaxed);
self.model.active_source.volume = volume;
self.model.active_source.volume_text = volume.to_string();
if let Some(mut client) = self.audio_client.take() {
let volume = Arc::clone(&self.applied_source_volume);
return cosmic::Task::future(async move {
tokio::time::sleep(Duration::from_millis(128)).await;
_ = client
.conn
.set_sink_volume(volume.load(atomic::Ordering::Relaxed))
.await;
Message::ReattachClient(Arc::new(client)).into()
});
}
}
@ -513,7 +552,7 @@ impl cosmic::Application for Audio {
}
Message::Client(client) => {
if let Some(client) = Arc::into_inner(client) {
self.audio_client = Some(Rc::new(RefCell::new(client)));
self.audio_client = Some(client);
self.model = model::Model::default();
}
}