fix(display): avoid block on dispatch; fixing app close
This commit is contained in:
parent
f0dd262d5d
commit
7576ad1af7
2 changed files with 53 additions and 29 deletions
|
|
@ -243,6 +243,11 @@ impl cosmic::Application for SettingsApp {
|
||||||
widgets
|
widgets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_app_exit(&mut self) -> Option<Self::Message> {
|
||||||
|
self.pages.on_leave(self.active_page);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn on_escape(&mut self) -> Task<Self::Message> {
|
fn on_escape(&mut self) -> Task<Self::Message> {
|
||||||
if self.search_active {
|
if self.search_active {
|
||||||
self.search_active = false;
|
self.search_active = false;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ use once_cell::sync::Lazy;
|
||||||
use slab::Slab;
|
use slab::Slab;
|
||||||
use slotmap::{Key, SecondaryMap, SlotMap};
|
use slotmap::{Key, SecondaryMap, SlotMap};
|
||||||
use std::{collections::BTreeMap, process::ExitStatus, sync::Arc};
|
use std::{collections::BTreeMap, process::ExitStatus, sync::Arc};
|
||||||
|
use tokio::sync::oneshot;
|
||||||
|
use tokio::task::JoinHandle;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
static DPI_SCALES: &[u32] = &[50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300];
|
static DPI_SCALES: &[u32] = &[50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300];
|
||||||
|
|
@ -132,7 +134,7 @@ pub struct Page {
|
||||||
mirror_map: SecondaryMap<OutputKey, OutputKey>,
|
mirror_map: SecondaryMap<OutputKey, OutputKey>,
|
||||||
mirror_menu: widget::dropdown::multi::Model<String, Mirroring>,
|
mirror_menu: widget::dropdown::multi::Model<String, Mirroring>,
|
||||||
active_display: OutputKey,
|
active_display: OutputKey,
|
||||||
background_service: Option<tokio::task::JoinHandle<()>>,
|
background_service_cancel: Option<oneshot::Sender<()>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
cache: ViewCache,
|
cache: ViewCache,
|
||||||
// context: Option<ContextDrawer>,
|
// context: Option<ContextDrawer>,
|
||||||
|
|
@ -166,7 +168,7 @@ impl Default for Page {
|
||||||
mirror_map: SecondaryMap::new(),
|
mirror_map: SecondaryMap::new(),
|
||||||
mirror_menu: widget::dropdown::multi::model(),
|
mirror_menu: widget::dropdown::multi::model(),
|
||||||
active_display: OutputKey::default(),
|
active_display: OutputKey::default(),
|
||||||
background_service: None,
|
background_service_cancel: None,
|
||||||
config: Config::default(),
|
config: Config::default(),
|
||||||
cache: ViewCache::default(),
|
cache: ViewCache::default(),
|
||||||
// context: None,
|
// context: None,
|
||||||
|
|
@ -246,51 +248,68 @@ impl page::Page<crate::pages::Message> for Page {
|
||||||
) -> Task<crate::pages::Message> {
|
) -> Task<crate::pages::Message> {
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
if let Some(task) = self.background_service.take() {
|
use futures::pin_mut;
|
||||||
task.abort();
|
|
||||||
|
if let Some(canceller) = self.background_service_cancel.take() {
|
||||||
|
_ = canceller.send(());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
{
|
{
|
||||||
|
let (tx, mut rx) = tachyonix::channel(4);
|
||||||
|
let (canceller, cancelled) = oneshot::channel();
|
||||||
|
let runtime = tokio::runtime::Handle::current();
|
||||||
|
|
||||||
// Spawns a background service to monitor for display state changes.
|
// Spawns a background service to monitor for display state changes.
|
||||||
// This must be spawned onto its own thread because `*mut wayland_sys::client::wl_display` is not Send-able.
|
// This must be spawned onto its own thread because `*mut wayland_sys::client::wl_display` is not Send-able.
|
||||||
let runtime = tokio::runtime::Handle::current();
|
tokio::task::spawn_blocking(move || {
|
||||||
self.background_service = Some(tokio::task::spawn_blocking(move || {
|
let dispatcher = async move {
|
||||||
runtime.block_on(async move {
|
|
||||||
let (tx, mut rx) = tachyonix::channel(200);
|
|
||||||
let Ok((mut context, mut event_queue)) = cosmic_randr::connect(tx) else {
|
let Ok((mut context, mut event_queue)) = cosmic_randr::connect(tx) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
while context.dispatch(&mut event_queue).await.is_ok() {
|
loop {
|
||||||
if sender.is_closed() {
|
if context.dispatch(&mut event_queue).await.is_err() {
|
||||||
break;
|
return;
|
||||||
}
|
|
||||||
'outer: while let Ok(message) = rx.try_recv() {
|
|
||||||
if let cosmic_randr::Message::ManagerDone = message {
|
|
||||||
if matches!(
|
|
||||||
tokio::time::timeout(
|
|
||||||
Duration::from_secs(1),
|
|
||||||
sender.send(pages::Message::Displays(Message::Refresh))
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
Err(_) | Ok(Err(_))
|
|
||||||
) {
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}));
|
|
||||||
|
pin_mut!(dispatcher);
|
||||||
|
runtime.block_on(futures::future::select(cancelled, dispatcher));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Forward messages from another thread to prevent the monitoring thread from blocking.
|
||||||
|
tokio::task::spawn(async move {
|
||||||
|
while let Ok(message) = rx.recv().await {
|
||||||
|
if sender.is_closed() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let cosmic_randr::Message::ManagerDone = message {
|
||||||
|
if matches!(
|
||||||
|
tokio::time::timeout(
|
||||||
|
Duration::from_secs(1),
|
||||||
|
sender.send(pages::Message::Displays(Message::Refresh))
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
Err(_) | Ok(Err(_))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.background_service_cancel = Some(canceller);
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmic::task::future(on_enter())
|
cosmic::task::future(on_enter())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||||
if let Some(task) = self.background_service.take() {
|
if let Some(canceller) = self.background_service_cancel.take() {
|
||||||
task.abort();
|
_ = canceller.send(());
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::none()
|
Task::none()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue