diff --git a/Cargo.lock b/Cargo.lock index 35cc8eda..d071de8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -768,6 +768,7 @@ dependencies = [ "serde", "shlex", "tokio", + "tracing", "tracing-log", "tracing-subscriber", "url", @@ -971,6 +972,7 @@ dependencies = [ "nix 0.27.1", "once_cell", "rust-embed 6.8.1", + "tokio", "tracing", "tracing-log", "tracing-subscriber", @@ -990,6 +992,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -1007,6 +1010,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "quote", "syn 1.0.109", @@ -1094,7 +1098,7 @@ dependencies = [ [[package]] name = "cosmic-text" version = "0.10.0" -source = "git+https://github.com/pop-os/cosmic-text.git?branch=refactor#dd4c4cbbe2d5ed5046054b5361a6eeead50e0bb0" +source = "git+https://github.com/pop-os/cosmic-text.git#6aadfaddac7ae68c3f97c0b9b2fa75033374a650" dependencies = [ "bitflags 2.4.2", "fontdb", @@ -1106,6 +1110,7 @@ dependencies = [ "self_cell 1.0.3", "swash", "sys-locale", + "ttf-parser", "unicode-bidi", "unicode-linebreak", "unicode-script", @@ -1115,6 +1120,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "almost", "cosmic-config", @@ -1128,6 +1134,7 @@ dependencies = [ [[package]] name = "cosmic-time" version = "0.4.0" +source = "git+https://github.com/pop-os/cosmic-time#4dc1fcec44aa7471a8e707fa391f9882d23250d7" dependencies = [ "float-cmp", "libcosmic", @@ -2242,8 +2249,8 @@ dependencies = [ [[package]] name = "glyphon" -version = "0.3.0" -source = "git+https://github.com/jackpot51/glyphon.git?branch=refactor#c28dc99c86b6b598633e6623096b21632f266976" +version = "0.4.1" +source = "git+https://github.com/jackpot51/glyphon.git#abb70c0fda8cf1a5dfc314c1c778103d7ba951e6" dependencies = [ "cosmic-text", "etagere", @@ -2538,6 +2545,7 @@ dependencies = [ [[package]] name = "iced" version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "iced_accessibility", "iced_core", @@ -2552,6 +2560,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "accesskit", "accesskit_unix", @@ -2560,6 +2569,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "bitflags 1.3.2", "iced_accessibility", @@ -2577,6 +2587,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "futures", "iced_core", @@ -2589,6 +2600,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -2611,6 +2623,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2623,6 +2636,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "iced_accessibility", "iced_core", @@ -2634,6 +2648,7 @@ dependencies = [ [[package]] name = "iced_sctk" version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "enum-repr", "float-cmp", @@ -2657,6 +2672,7 @@ dependencies = [ [[package]] name = "iced_style" version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "iced_core", "once_cell", @@ -2666,6 +2682,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "bytemuck", "cosmic-text", @@ -2683,6 +2700,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -2702,6 +2720,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "iced_renderer", "iced_runtime", @@ -2957,6 +2976,7 @@ checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libcosmic" version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063" dependencies = [ "apply", "ashpd", @@ -3141,9 +3161,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" +checksum = "2994eeba8ed550fd9b47a0b38f0242bc3344e496483c6180b69139cc2fa5d1d7" dependencies = [ "hashbrown 0.14.3", ] diff --git a/Cargo.toml b/Cargo.toml index 7abd8fe6..0aae1ab7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,10 +44,10 @@ tracing-log = "0.2.0" lto = "thin" # lto = "fat" -[patch."https://github.com/pop-os/cosmic-time"] -cosmic-time = { path = "../cosmic-time" } -[patch."https://github.com/pop-os/libcosmic"] -libcosmic = { path = "../libcosmic" } -cosmic-config = { path = "../libcosmic/cosmic-config" } +# [patch."https://github.com/pop-os/cosmic-time"] +# cosmic-time = { path = "../cosmic-time" } +# [patch."https://github.com/pop-os/libcosmic"] +# libcosmic = { git = "https://github.com/pop-os/libcosmic//", branch = "refactor-config-watch" } +# cosmic-config = { git = "https://github.com/pop-os/libcosmic//", branch = "refactor-config-watch" } [patch."https://github.com/Smithay/client-toolkit"] sctk = { git = "https://github.com/smithay/client-toolkit//", package = "smithay-client-toolkit", rev = "e63ab5f" } diff --git a/cosmic-app-list/Cargo.toml b/cosmic-app-list/Cargo.toml index 764b9026..c81225c2 100644 --- a/cosmic-app-list/Cargo.toml +++ b/cosmic-app-list/Cargo.toml @@ -16,6 +16,7 @@ once_cell = "1.9" xdg = "2.4" tracing-subscriber.workspace = true tracing-log.workspace = true +tracing.workspace = true nix = "0.26" shlex = "1.1.0" anyhow = "1.0" diff --git a/cosmic-app-list/src/app.rs b/cosmic-app-list/src/app.rs index 375453d4..34c859c2 100755 --- a/cosmic-app-list/src/app.rs +++ b/cosmic-app-list/src/app.rs @@ -1122,7 +1122,7 @@ impl cosmic::Application for CosmicAppList { fn subscription(&self) -> Subscription { Subscription::batch(vec![ - wayland_subscription(self.subscription_ctr).map(Message::Wayland), + wayland_subscription().map(Message::Wayland), listen_with(|e, _| match e { cosmic::iced_runtime::core::Event::PlatformSpecific( event::PlatformSpecific::Wayland(event::wayland::Event::Seat(e, seat)), diff --git a/cosmic-app-list/src/wayland_subscription.rs b/cosmic-app-list/src/wayland_subscription.rs index da9123cb..a348573e 100644 --- a/cosmic-app-list/src/wayland_subscription.rs +++ b/cosmic-app-list/src/wayland_subscription.rs @@ -11,29 +11,31 @@ use futures::{ channel::mpsc::{unbounded, UnboundedReceiver}, SinkExt, StreamExt, }; +use once_cell::sync::Lazy; use std::{fmt::Debug, hash::Hash, thread::JoinHandle}; +use tokio::sync::Mutex; use crate::wayland_handler::wayland_handler; -pub fn wayland_subscription( - id: I, -) -> iced::Subscription { - subscription::channel(id, 50, move |mut output| async move { - let mut state = State::Ready; +pub static WAYLAND_RX: Lazy>>> = + Lazy::new(|| Mutex::new(None)); - loop { - state = start_listening(state, &mut output).await; - } - }) +pub fn wayland_subscription() -> iced::Subscription { + subscription::channel( + std::any::TypeId::of::(), + 50, + move |mut output| async move { + let mut state = State::Waiting; + + loop { + state = start_listening(state, &mut output).await; + } + }, + ) } pub enum State { - Ready, - Waiting( - UnboundedReceiver, - calloop::channel::Sender, - JoinHandle<()>, - ), + Waiting, Finished, } @@ -42,28 +44,28 @@ async fn start_listening( output: &mut futures::channel::mpsc::Sender, ) -> State { match state { - State::Ready => { - let (calloop_tx, calloop_rx) = calloop::channel::channel(); - let (toplevel_tx, toplevel_rx) = unbounded(); - let handle = std::thread::spawn(move || { - wayland_handler(toplevel_tx, calloop_rx); - }); - let tx = calloop_tx.clone(); - _ = output.send(WaylandUpdate::Init(tx)).await; - State::Waiting(toplevel_rx, calloop_tx, handle) - } - State::Waiting(mut rx, tx, handle) => { - if handle.is_finished() { - _ = output.send(WaylandUpdate::Finished).await; - return State::Finished; - } + State::Waiting => { + let mut guard = WAYLAND_RX.lock().await; + let rx = { + if guard.is_none() { + let (calloop_tx, calloop_rx) = calloop::channel::channel(); + let (toplevel_tx, toplevel_rx) = unbounded(); + let _ = std::thread::spawn(move || { + wayland_handler(toplevel_tx, calloop_rx); + }); + *guard = Some(toplevel_rx); + _ = output.send(WaylandUpdate::Init(calloop_tx)).await; + } + guard.as_mut().unwrap() + }; match rx.next().await { Some(u) => { _ = output.send(u).await; - State::Waiting(rx, tx, handle) + State::Waiting } None => { _ = output.send(WaylandUpdate::Finished).await; + tracing::error!("Wayland handler thread died"); State::Finished } } diff --git a/cosmic-applet-audio/src/main.rs b/cosmic-applet-audio/src/main.rs index 96820bd7..95f52837 100644 --- a/cosmic-applet-audio/src/main.rs +++ b/cosmic-applet-audio/src/main.rs @@ -43,8 +43,7 @@ mod pulse; const VERSION: &str = env!("CARGO_PKG_VERSION"); -#[tokio::main(flavor = "current_thread")] -pub async fn main() -> cosmic::iced::Result { +pub fn main() -> cosmic::iced::Result { tracing_subscriber::fmt::init(); let _ = tracing_log::LogTracer::init(); diff --git a/cosmic-applet-audio/src/pulse.rs b/cosmic-applet-audio/src/pulse.rs index ce52d071..93e746f4 100644 --- a/cosmic-applet-audio/src/pulse.rs +++ b/cosmic-applet-audio/src/pulse.rs @@ -4,6 +4,7 @@ use std::{rc::Rc, thread}; extern crate libpulse_binding as pulse; use cosmic::iced::{self, subscription}; use cosmic::iced_futures::futures::{self, SinkExt}; +use cosmic_time::once_cell::sync::Lazy; //use futures::channel::mpsc; use libpulse_binding::{ callbacks::ListResult, @@ -16,6 +17,10 @@ use libpulse_binding::{ proplist::Proplist, volume::ChannelVolumes, }; +use tokio::sync::{mpsc, Mutex}; + +pub static FROM_PULSE: Lazy, mpsc::Sender)>>> = + Lazy::new(|| Mutex::new(None)); pub fn connect() -> iced::Subscription { struct SomeWorker; @@ -24,7 +29,7 @@ pub fn connect() -> iced::Subscription { std::any::TypeId::of::(), 50, move |mut output| async move { - let mut state = State::Init; + let mut state = State::Connecting; loop { state = start_listening(state, &mut output).await; @@ -38,34 +43,50 @@ async fn start_listening( output: &mut futures::channel::mpsc::Sender, ) -> State { match state { - State::Init => { - let PulseHandle { - to_pulse, - from_pulse, - } = PulseHandle::new(); - _ = output.send(Event::Init(Connection(to_pulse))).await; - - State::Connecting(from_pulse) - } // Waiting for Connection to succeed - State::Connecting(mut from_pulse) => match from_pulse.recv().await { - Some(Message::Connected) => { - _ = output.send(Event::Connected).await; - State::Connected(from_pulse) - } - Some(Message::Disconnected) => { - _ = output.send(Event::Disconnected).await; + State::Connecting => { + let mut guard = FROM_PULSE.lock().await; + let (from_pulse, to_pulse) = { + if guard.is_none() { + let PulseHandle { + to_pulse, + from_pulse, + } = PulseHandle::new(); + _ = output.send(Event::Init(Connection(to_pulse.clone()))).await; - State::Connecting(from_pulse) + *guard = Some((from_pulse, to_pulse)); + } + guard.as_mut().unwrap() + }; + to_pulse + .send(Message::UpdateConnection) + .await + .expect("Failed to request connection update"); + + match from_pulse.recv().await { + Some(Message::Connected) => { + _ = output.send(Event::Connected).await; + State::Connected + } + Some(Message::Disconnected) => { + _ = output.send(Event::Disconnected).await; + + State::Connecting + } + Some(m) => { + tracing::error!("Unexpected message: {:?}", m); + State::Connecting + } + None => { + panic!("Pulse Sender dropped, something has gone wrong!"); + } } - Some(m) => { - panic!("Unexpected message: {:?}", m); - } - None => { - panic!("Pulse Sender dropped, something has gone wrong!"); - } - }, - State::Connected(mut from_pulse) => { + } + State::Connected => { + let mut guard = FROM_PULSE.lock().await; + let Some((from_pulse, _)) = guard.as_mut() else { + return State::Connecting; + }; // This is where we match messages from the pulse server to pass to the gui match from_pulse.recv().await { Some(Message::SetSinks(sinks)) => { @@ -73,35 +94,35 @@ async fn start_listening( .send(Event::MessageReceived(Message::SetSinks(sinks))) .await; - State::Connected(from_pulse) + State::Connected } Some(Message::SetSources(sources)) => { _ = output .send(Event::MessageReceived(Message::SetSources(sources))) .await; - State::Connected(from_pulse) + State::Connected } Some(Message::SetDefaultSink(sink)) => { _ = output .send(Event::MessageReceived(Message::SetDefaultSink(sink))) .await; - State::Connected(from_pulse) + State::Connected } Some(Message::SetDefaultSource(source)) => { _ = output .send(Event::MessageReceived(Message::SetDefaultSource(source))) .await; - State::Connected(from_pulse) + State::Connected } Some(Message::Disconnected) => { _ = output.send(Event::Disconnected).await; - State::Connecting(from_pulse) + State::Connecting } None => { _ = output.send(Event::Disconnected).await; - State::Connecting(from_pulse) + State::Connecting } - _ => State::Connected(from_pulse), + _ => State::Connected, } } } @@ -109,9 +130,8 @@ async fn start_listening( // #[derive(Debug)] enum State { - Init, - Connecting(tokio::sync::mpsc::Receiver), - Connected(tokio::sync::mpsc::Receiver), + Connecting, + Connected, } #[derive(Debug, Clone)] @@ -123,7 +143,7 @@ pub enum Event { } #[derive(Debug, Clone)] -pub struct Connection(tokio::sync::mpsc::Sender); +pub struct Connection(mpsc::Sender); impl Connection { pub fn send(&mut self, message: Message) { @@ -160,10 +180,7 @@ impl PulseHandle { pub fn new() -> Self { let (to_pulse, mut to_pulse_recv) = tokio::sync::mpsc::channel(10); let (from_pulse_send, from_pulse) = tokio::sync::mpsc::channel(10); - // get initial connection status - to_pulse - .try_send(Message::UpdateConnection) - .expect("Failed to send initial connection update message"); + // this thread should complete by pushing a completed message, // or fail message. This should never complete/fail without pushing // a message. This lets the iced subscription go to sleep while init @@ -197,7 +214,6 @@ impl PulseHandle { .await { tracing::error!("ERROR! {}", err); - break; } } Err(_) => Self::send_disconnected(&from_pulse_send).await, @@ -215,7 +231,6 @@ impl PulseHandle { .await { tracing::error!("ERROR! {}", err); - break; } } Err(e) => { @@ -235,7 +250,6 @@ impl PulseHandle { from_pulse_send.send(Message::SetSinks(sinks)).await { tracing::error!("ERROR! {}", err); - break; } } Err(_) => Self::send_disconnected(&from_pulse_send).await, @@ -252,7 +266,6 @@ impl PulseHandle { from_pulse_send.send(Message::SetSources(sinks)).await { tracing::error!("ERROR! {}", err); - break; } } Err(_) => Self::send_disconnected(&from_pulse_send).await, @@ -278,13 +291,13 @@ impl PulseHandle { server.is_some() ); if let Some(mut cur_server) = server.take() { - tracing::trace!("getting server info..."); if cur_server.get_server_info().is_err() { tracing::warn!("got error, server must be disconnected..."); Self::send_disconnected(&from_pulse_send).await; } else { - tracing::trace!("got server info, still connected..."); + tracing::info!("got server info, still connected..."); server = Some(cur_server); + Self::send_connected(&from_pulse_send).await; } } else { match PulseServer::connect().and_then(|server| server.init()) { @@ -298,6 +311,7 @@ impl PulseHandle { "Failed to connect to server: {:?}", err ); + Self::send_disconnected(&from_pulse_send).await; } } } diff --git a/cosmic-applet-notifications/src/main.rs b/cosmic-applet-notifications/src/main.rs index 32a90412..f4cc61cf 100644 --- a/cosmic-applet-notifications/src/main.rs +++ b/cosmic-applet-notifications/src/main.rs @@ -15,6 +15,7 @@ use cosmic::iced::{ use cosmic::iced_core::alignment::Horizontal; use cosmic::Command; +use cosmic::iced_futures::futures::executor::block_on; use cosmic::iced_style::application; use cosmic::iced_widget::{scrollable, Column}; @@ -26,11 +27,11 @@ use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline}; use std::borrow::Cow; use std::collections::HashMap; use std::path::PathBuf; +use subscriptions::notifications::NotificationsAppletProxy; use tokio::sync::mpsc::Sender; use tracing::info; -#[tokio::main(flavor = "current_thread")] -pub async fn main() -> cosmic::iced::Result { +pub fn main() -> cosmic::iced::Result { tracing_subscriber::fmt::init(); let _ = tracing_log::LogTracer::init(); // Prepare i18n @@ -43,7 +44,6 @@ pub async fn main() -> cosmic::iced::Result { static DO_NOT_DISTURB: Lazy = Lazy::new(id::Toggler::unique); -#[derive(Default)] struct Notifications { core: cosmic::app::Core, config: NotificationsConfig, @@ -55,6 +55,7 @@ struct Notifications { dbus_sender: Option>, cards: Vec<(id::Cards, Vec, bool, String, String, String)>, token_tx: Option>, + proxy: NotificationsAppletProxy<'static>, } impl Notifications { @@ -132,7 +133,14 @@ impl cosmic::Application for Notifications { core, config_helper: helper, config, - ..Default::default() + icon_name: Default::default(), + popup: None, + timeline: Default::default(), + dbus_sender: Default::default(), + cards: Vec::new(), + token_tx: Default::default(), + proxy: block_on(crate::subscriptions::notifications::get_proxy()) + .expect("Failed to get proxy"), }; _self.update_icon(); (_self, Command::none()) @@ -152,25 +160,20 @@ impl cosmic::Application for Notifications { fn subscription(&self) -> Subscription { Subscription::batch(vec![ - config_subscription::( - 0, - cosmic_notifications_config::ID.into(), - NotificationsConfig::version(), - ) - .map(|(_, res)| match res { - Ok(config) => Message::Config(config), - Err((errors, config)) => { - for err in errors { + self.core + .watch_config(cosmic_notifications_config::ID.into()) + .map(|res| { + for err in res.errors { tracing::error!("{:?}", err); } - Message::Config(config) - } - }), + Message::Config(res.config) + }), self.timeline .as_subscription() .map(|(_, now)| Message::Frame(now)), subscriptions::dbus::proxy().map(Message::DbusEvent), - subscriptions::notifications::notifications().map(Message::NotificationEvent), + subscriptions::notifications::notifications(self.proxy.clone()) + .map(Message::NotificationEvent), activation_token_subscription(0).map(Message::Token), ]) } diff --git a/cosmic-applet-notifications/src/subscriptions/notifications.rs b/cosmic-applet-notifications/src/subscriptions/notifications.rs index 8b2d9a13..09e3f53b 100644 --- a/cosmic-applet-notifications/src/subscriptions/notifications.rs +++ b/cosmic-applet-notifications/src/subscriptions/notifications.rs @@ -22,7 +22,7 @@ pub enum State { Finished, } -pub fn notifications() -> Subscription { +pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription { struct SomeWorker; subscription::channel( @@ -107,7 +107,7 @@ trait NotificationsApplet { ) -> zbus::Result<()>; } -async fn get_proxy() -> anyhow::Result> { +pub async fn get_proxy() -> anyhow::Result> { let raw_fd = std::env::var("COSMIC_NOTIFICATIONS")?; let raw_fd = raw_fd.parse::()?; diff --git a/cosmic-applet-workspaces/Cargo.toml b/cosmic-applet-workspaces/Cargo.toml index 05b6f4d8..1de199af 100644 --- a/cosmic-applet-workspaces/Cargo.toml +++ b/cosmic-applet-workspaces/Cargo.toml @@ -16,6 +16,7 @@ once_cell = "1.9" futures = "0.3.21" xdg = "2.4.0" anyhow = "1.0" +tokio = "1.35" # Application i18n i18n-embed = { version = "0.13.4", features = ["fluent-system", "desktop-requester"] } i18n-embed-fl = "0.6.4" diff --git a/cosmic-applet-workspaces/src/components/app.rs b/cosmic-applet-workspaces/src/components/app.rs index 2f440638..0dac88be 100644 --- a/cosmic-applet-workspaces/src/components/app.rs +++ b/cosmic-applet-workspaces/src/components/app.rs @@ -222,7 +222,7 @@ impl cosmic::Application for IcedWorkspacesApplet { fn subscription(&self) -> Subscription { Subscription::batch(vec![ - workspaces(0).map(Message::WorkspaceUpdate), + workspaces().map(Message::WorkspaceUpdate), event::listen_with(|e, _| match e { Mouse(mouse::Event::WheelScrolled { delta }) => Some(Message::WheelScrolled(delta)), _ => None, diff --git a/cosmic-applet-workspaces/src/wayland_subscription.rs b/cosmic-applet-workspaces/src/wayland_subscription.rs index 4b45a7b4..d3d91db4 100644 --- a/cosmic-applet-workspaces/src/wayland_subscription.rs +++ b/cosmic-applet-workspaces/src/wayland_subscription.rs @@ -5,7 +5,11 @@ use cosmic::iced::{ futures::{channel::mpsc, SinkExt, StreamExt}, subscription, }; -use std::hash::Hash; +use once_cell::sync::Lazy; +use tokio::sync::Mutex; + +pub static WAYLAND_RX: Lazy>>> = + Lazy::new(|| Mutex::new(None)); #[derive(Debug, Clone)] pub enum WorkspacesUpdate { @@ -14,16 +18,18 @@ pub enum WorkspacesUpdate { Errored, } -pub fn workspaces( - id: I, -) -> iced::Subscription { - subscription::channel(id, 50, move |mut output| async move { - let mut state = State::Ready; +pub fn workspaces() -> iced::Subscription { + subscription::channel( + std::any::TypeId::of::(), + 50, + move |mut output| async move { + let mut state = State::Waiting; - loop { - state = start_listening(state, &mut output).await; - } - }) + loop { + state = start_listening(state, &mut output).await; + } + }, + ) } async fn start_listening( @@ -31,22 +37,23 @@ async fn start_listening( output: &mut futures::channel::mpsc::Sender, ) -> State { match state { - State::Ready => { - if let Ok(watcher) = WorkspacesWatcher::new() { - _ = output - .send(WorkspacesUpdate::Started(watcher.get_sender())) - .await; - State::Waiting(watcher) - } else { - _ = output.send(WorkspacesUpdate::Errored).await; - - State::Error - } - } - State::Waiting(mut t) => { - if let Some(w) = t.workspaces().await { + State::Waiting => { + let mut guard = WAYLAND_RX.lock().await; + let rx = { + if guard.is_none() { + if let Ok(WorkspacesWatcher { rx, tx }) = WorkspacesWatcher::new() { + *guard = Some(rx); + _ = output.send(WorkspacesUpdate::Started(tx)).await; + } else { + _ = output.send(WorkspacesUpdate::Errored).await; + return State::Error; + } + } + guard.as_mut().unwrap() + }; + if let Some(w) = rx.next().await { _ = output.send(WorkspacesUpdate::Workspaces(w)).await; - State::Waiting(t) + State::Waiting } else { _ = output.send(WorkspacesUpdate::Errored).await; State::Error @@ -57,8 +64,7 @@ async fn start_listening( } pub enum State { - Ready, - Waiting(WorkspacesWatcher), + Waiting, Error, }