fix: make all subscriptions resistant to being restarted
many of the errors we've been seeing the last few days are because of subscriptions which are restarting
This commit is contained in:
parent
ebe688c747
commit
d4e0dd8fb8
12 changed files with 184 additions and 138 deletions
30
Cargo.lock
generated
30
Cargo.lock
generated
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
10
Cargo.toml
10
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" }
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1122,7 +1122,7 @@ impl cosmic::Application for CosmicAppList {
|
|||
|
||||
fn subscription(&self) -> Subscription<Message> {
|
||||
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)),
|
||||
|
|
|
|||
|
|
@ -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<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||
id: I,
|
||||
) -> iced::Subscription<WaylandUpdate> {
|
||||
subscription::channel(id, 50, move |mut output| async move {
|
||||
let mut state = State::Ready;
|
||||
pub static WAYLAND_RX: Lazy<Mutex<Option<UnboundedReceiver<WaylandUpdate>>>> =
|
||||
Lazy::new(|| Mutex::new(None));
|
||||
|
||||
loop {
|
||||
state = start_listening(state, &mut output).await;
|
||||
}
|
||||
})
|
||||
pub fn wayland_subscription() -> iced::Subscription<WaylandUpdate> {
|
||||
subscription::channel(
|
||||
std::any::TypeId::of::<WaylandUpdate>(),
|
||||
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<WaylandUpdate>,
|
||||
calloop::channel::Sender<WaylandRequest>,
|
||||
JoinHandle<()>,
|
||||
),
|
||||
Waiting,
|
||||
Finished,
|
||||
}
|
||||
|
||||
|
|
@ -42,28 +44,28 @@ async fn start_listening(
|
|||
output: &mut futures::channel::mpsc::Sender<WaylandUpdate>,
|
||||
) -> 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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Mutex<Option<(mpsc::Receiver<Message>, mpsc::Sender<Message>)>>> =
|
||||
Lazy::new(|| Mutex::new(None));
|
||||
|
||||
pub fn connect() -> iced::Subscription<Event> {
|
||||
struct SomeWorker;
|
||||
|
|
@ -24,7 +29,7 @@ pub fn connect() -> iced::Subscription<Event> {
|
|||
std::any::TypeId::of::<SomeWorker>(),
|
||||
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<Event>,
|
||||
) -> 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<Message>),
|
||||
Connected(tokio::sync::mpsc::Receiver<Message>),
|
||||
Connecting,
|
||||
Connected,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -123,7 +143,7 @@ pub enum Event {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Connection(tokio::sync::mpsc::Sender<Message>);
|
||||
pub struct Connection(mpsc::Sender<Message>);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||
|
||||
#[derive(Default)]
|
||||
struct Notifications {
|
||||
core: cosmic::app::Core,
|
||||
config: NotificationsConfig,
|
||||
|
|
@ -55,6 +55,7 @@ struct Notifications {
|
|||
dbus_sender: Option<Sender<subscriptions::dbus::Input>>,
|
||||
cards: Vec<(id::Cards, Vec<Notification>, bool, String, String, String)>,
|
||||
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
||||
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<Message> {
|
||||
Subscription::batch(vec![
|
||||
config_subscription::<u64, NotificationsConfig>(
|
||||
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),
|
||||
])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub enum State {
|
|||
Finished,
|
||||
}
|
||||
|
||||
pub fn notifications() -> Subscription<Notification> {
|
||||
pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<Notification> {
|
||||
struct SomeWorker;
|
||||
|
||||
subscription::channel(
|
||||
|
|
@ -107,7 +107,7 @@ trait NotificationsApplet {
|
|||
) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
async fn get_proxy() -> anyhow::Result<NotificationsAppletProxy<'static>> {
|
||||
pub async fn get_proxy() -> anyhow::Result<NotificationsAppletProxy<'static>> {
|
||||
let raw_fd = std::env::var("COSMIC_NOTIFICATIONS")?;
|
||||
let raw_fd = raw_fd.parse::<RawFd>()?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ impl cosmic::Application for IcedWorkspacesApplet {
|
|||
|
||||
fn subscription(&self) -> Subscription<Message> {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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<Mutex<Option<mpsc::Receiver<WorkspaceList>>>> =
|
||||
Lazy::new(|| Mutex::new(None));
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum WorkspacesUpdate {
|
||||
|
|
@ -14,16 +18,18 @@ pub enum WorkspacesUpdate {
|
|||
Errored,
|
||||
}
|
||||
|
||||
pub fn workspaces<I: 'static + Hash + Copy + Send + Sync>(
|
||||
id: I,
|
||||
) -> iced::Subscription<WorkspacesUpdate> {
|
||||
subscription::channel(id, 50, move |mut output| async move {
|
||||
let mut state = State::Ready;
|
||||
pub fn workspaces() -> iced::Subscription<WorkspacesUpdate> {
|
||||
subscription::channel(
|
||||
std::any::TypeId::of::<WorkspacesUpdate>(),
|
||||
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<WorkspacesUpdate>,
|
||||
) -> 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,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue