From 554824aedf32c05a8f9852332aa8c702ec22873b Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Wed, 8 May 2024 17:06:00 +0200 Subject: [PATCH] feat(displays): listen to display change events with cosmic-randr --- Cargo.lock | 115 ++++++++++++++++++++++- Cargo.toml | 1 + cosmic-settings/Cargo.toml | 63 +++++++------ cosmic-settings/src/pages/display/mod.rs | 48 +++++++++- 4 files changed, 187 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c2f02e..9890ed4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -300,6 +300,15 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-event" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4172595da7ffb68640606be5723e35a353555f2829e9209437627a003725bbdb" +dependencies = [ + "loom", +] + [[package]] name = "async-executor" version = "1.11.0" @@ -1199,7 +1208,7 @@ name = "cosmic-client-toolkit" version = "0.1.0" source = "git+https://github.com/pop-os/cosmic-protocols?rev=e4e6f8c#e4e6f8ca4d7c239c02a8cdfd48a74cb0969425eb" dependencies = [ - "cosmic-protocols", + "cosmic-protocols 0.1.0 (git+https://github.com/pop-os/cosmic-protocols?rev=e4e6f8c)", "libc", "smithay-client-toolkit", "wayland-client", @@ -1273,10 +1282,40 @@ dependencies = [ "wayland-server", ] +[[package]] +name = "cosmic-protocols" +version = "0.1.0" +source = "git+https://github.com/pop-os/cosmic-protocols.git#1316f9e1148ec65351471d8a046ffc82171b066e" +dependencies = [ + "bitflags 2.5.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "wayland-server", +] + +[[package]] +name = "cosmic-randr" +version = "0.1.0" +source = "git+https://github.com/pop-os/cosmic-randr#8ad117e7c57848f113fbc87986e91209f2262b5a" +dependencies = [ + "cosmic-protocols 0.1.0 (git+https://github.com/pop-os/cosmic-protocols.git)", + "futures-lite 2.3.0", + "indexmap", + "tachyonix", + "thiserror", + "tokio", + "tracing", + "wayland-client", + "wayland-protocols-wlr", +] + [[package]] name = "cosmic-randr-shell" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-randr#12fa7ce503c832cb9565b59ff722b15b7bab3f31" +source = "git+https://github.com/pop-os/cosmic-randr#8ad117e7c57848f113fbc87986e91209f2262b5a" dependencies = [ "kdl", "slotmap", @@ -1297,6 +1336,7 @@ dependencies = [ "cosmic-bg-config", "cosmic-comp-config", "cosmic-panel-config", + "cosmic-randr", "cosmic-randr-shell", "cosmic-settings-page", "cosmic-settings-system", @@ -1326,6 +1366,7 @@ dependencies = [ "slotmap", "static_init", "sunrise", + "tachyonix", "tokio", "tracing", "tracing-subscriber", @@ -1622,6 +1663,16 @@ dependencies = [ "syn 2.0.61", ] +[[package]] +name = "diatomic-waker" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28025fb55a9d815acf7b0877555f437254f373036eec6ed265116c7a5c0825e9" +dependencies = [ + "loom", + "waker-fn", +] + [[package]] name = "digest" version = "0.10.7" @@ -3571,6 +3622,19 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "loop9" version = "0.1.5" @@ -3650,6 +3714,15 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -4637,8 +4710,17 @@ checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -4649,9 +4731,15 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.3", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.3" @@ -5397,6 +5485,19 @@ dependencies = [ "version-compare", ] +[[package]] +name = "tachyonix" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e0bf82be3359dbefbfea621d6365db00e1d7846561daad2ea74cc4cb4c9604" +dependencies = [ + "async-event", + "crossbeam-utils", + "diatomic-waker", + "futures-core", + "loom", +] + [[package]] name = "taffy" version = "0.3.11" @@ -5723,10 +5824,14 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] diff --git a/Cargo.toml b/Cargo.toml index 1acba77..a5403ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ rust-version = "1.71.0" sunrise_sunset = "1.0.1" [workspace.dependencies] +cosmic-randr = { git = "https://github.com/pop-os/cosmic-randr" } tokio = { version = "1.37.0", features = ["macros"] } [workspace.dependencies.libcosmic] diff --git a/cosmic-settings/Cargo.toml b/cosmic-settings/Cargo.toml index d837107..6a2c6c4 100644 --- a/cosmic-settings/Cargo.toml +++ b/cosmic-settings/Cargo.toml @@ -6,51 +6,52 @@ license = "GPL-3.0" rust-version = "1.65.0" [dependencies] -tokio.workspace = true +anyhow = "1.0" +ashpd = { version = "0.7", default-features = false } async-channel = "2.1.1" +chrono = "0.4.37" +clap = { version = "4.4.18", features = ["derive"] } color-eyre = "0.6.2" -cosmic-bg-config = { workspace = true } -cosmic-randr-shell = { workspace = true } -cosmic-settings-wallpaper = { path = "../pages/wallpapers" } +cosmic-bg-config.workspace = true +cosmic-comp-config.workspace = true +cosmic-panel-config.workspace = true +cosmic-randr-shell.workspace = true +cosmic-randr.workspace = true cosmic-settings-page = { path = "../page" } cosmic-settings-system = { path = "../pages/system" } cosmic-settings-time = { path = "../pages/time" } +cosmic-settings-wallpaper = { path = "../pages/wallpapers" } derivative = "2.2.0" derive_setters = "0.1.6" dirs = "5.0.1" -generator = "=0.7.5" -i18n-embed-fl = "0.7.0" -itertools = "0.12.0" -libcosmic = { workspace = true } -once_cell = "1.19.0" -regex = "1.10.3" -rust-embed = "8.2.0" -slotmap = "1.0.7" downcast-rs = "1.2.0" -cosmic-comp-config = { workspace = true } -# TODO: migrate this dependency to the pages/desktop crate. -cosmic-panel-config = { workspace = true } -chrono = "0.4.37" -sunrise = "1.0.1" -tracing = "0.1.40" -tracing-subscriber = "0.3.18" -url = "2.5.0" freedesktop-desktop-entry = "0.5.0" -notify = "6.1.1" -anyhow = "1.0" -image = "0.25" -serde = { version = "1.0.196", features = ["derive"] } -ashpd = { version = "0.7", default-features = false } -ron = "0.8" -static_init = "1.0.3" -clap = { version = "4.4.18", features = ["derive"] } -itoa = "1.0.10" futures = { package = "futures-lite", version = "2.2.0" } -xkb-data = "0.1.0" -udev = "0.8.0" +generator = "=0.7.5" hostname-validator = "1.1.1" hostname1-zbus = "0.1.0" +i18n-embed-fl = "0.7.0" +image = "0.25" +itertools = "0.12.0" +itoa = "1.0.10" +libcosmic.workspace = true +notify = "6.1.1" +once_cell = "1.19.0" +regex = "1.10.3" +ron = "0.8" +rust-embed = "8.2.0" +serde = { version = "1.0.196", features = ["derive"] } +slotmap = "1.0.7" +static_init = "1.0.3" +sunrise = "1.0.1" +tokio.workspace = true +tracing = "0.1.40" +tracing-subscriber = "0.3.18" +udev = "0.8.0" +url = "2.5.0" +xkb-data = "0.1.0" zbus = { version = "3.15.2", features = ["tokio"] } +tachyonix = "0.2.1" [dependencies.i18n-embed] version = "0.14.1" diff --git a/cosmic-settings/src/pages/display/mod.rs b/cosmic-settings/src/pages/display/mod.rs index 098ad96..77cf357 100644 --- a/cosmic-settings/src/pages/display/mod.rs +++ b/cosmic-settings/src/pages/display/mod.rs @@ -80,6 +80,8 @@ pub enum Message { Orientation(Transform), /// Status of an applied display change. RandrResult(Arc>), + /// Request to reload the page. + Refresh, /// Set the refresh rate of a display. RefreshRate(usize), /// Set the resolution of a display. @@ -118,6 +120,7 @@ pub struct Page { list: List, display_tabs: segmented_button::SingleSelectModel, active_display: OutputKey, + background_service: Option>, config: Config, cache: ViewCache, context: Option, @@ -130,6 +133,7 @@ impl Default for Page { list: List::default(), display_tabs: segmented_button::SingleSelectModel::default(), active_display: OutputKey::default(), + background_service: None, config: Config::default(), cache: ViewCache::default(), context: None, @@ -224,9 +228,43 @@ impl page::Page for Page { _page: page::Entity, sender: tokio::sync::mpsc::Sender, ) -> Command { + if let Some(task) = self.background_service.take() { + task.abort(); + } + + // 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. + let runtime = tokio::runtime::Handle::current(); + self.background_service = Some(tokio::task::spawn_blocking(move || { + runtime.block_on(async move { + let (tx, mut rx) = tachyonix::channel(5); + let Ok((mut context, mut event_queue)) = cosmic_randr::connect(tx) else { + return; + }; + + while context.dispatch(&mut event_queue).await.is_ok() { + while let Ok(message) = rx.try_recv() { + if let cosmic_randr::Message::ManagerDone = message { + let _ = sender + .send(pages::Message::Displays(Message::Refresh)) + .await; + } + } + } + }); + })); + command::future(on_enter()) } + fn on_leave(&mut self) -> Command { + if let Some(task) = self.background_service.take() { + task.abort(); + } + + Command::none() + } + #[cfg(feature = "test")] fn on_enter( &mut self, @@ -295,10 +333,6 @@ impl Page { if let Some(Err(why)) = Arc::into_inner(result) { tracing::error!(?why, "cosmic-randr error"); } - - return cosmic::command::future(async { - crate::Message::PageMessage(on_enter().await) - }); } Message::Display(display) => self.set_display(display), @@ -344,6 +378,12 @@ impl Page { Message::Position(display, x, y) => return self.set_position(display, x, y), + Message::Refresh => { + return cosmic::command::future(async move { + crate::Message::PageMessage(on_enter().await) + }); + } + Message::RefreshRate(rate) => return self.set_refresh_rate(rate), Message::Resolution(option) => return self.set_resolution(option),