From bea442ed960f513288cf857e8ee9a5c61f742dfa Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Sun, 17 Dec 2023 23:51:43 +0000 Subject: [PATCH 1/2] refactor: update gtk/glib, remove glib channels This is a major refactor which updates GTK, GLib and GTK Layer Shell to their latest versions. GLib channels, previously used for receiving events on the GLib Main Context thread have been deprecated and a new method for running Futures on the main thread has been added instead. This commit also replaces all the deprecated code with this. As part of the above, a bug was uncovered related to creating the GLib main context inside the Tokio runtime. Spawning of Tokio tasks has been refactored to fix this. --- Cargo.lock | 134 +++++++++++++++------------- Cargo.toml | 6 +- src/bar.rs | 38 ++++---- src/bridge_channel.rs | 44 --------- src/clients/clipboard.rs | 3 +- src/clients/compositor/hyprland.rs | 3 +- src/clients/compositor/sway.rs | 3 +- src/clients/music/mpd.rs | 3 +- src/clients/music/mpris.rs | 3 +- src/clients/system_tray.rs | 3 +- src/clients/wayland/client.rs | 3 +- src/config/common.rs | 9 +- src/dynamic_value/dynamic_bool.rs | 24 ++--- src/dynamic_value/dynamic_string.rs | 20 ++--- src/image/provider.rs | 14 +-- src/ipc/server.rs | 19 ++-- src/macros.rs | 49 ++++++++++ src/main.rs | 64 ++++++++++--- src/modules/clipboard.rs | 33 +++---- src/modules/clock.rs | 23 ++--- src/modules/custom/button.rs | 1 - src/modules/custom/image.rs | 2 - src/modules/custom/label.rs | 1 - src/modules/custom/mod.rs | 17 ++-- src/modules/custom/progress.rs | 14 ++- src/modules/custom/slider.rs | 18 ++-- src/modules/focused.rs | 8 +- src/modules/label.rs | 9 +- src/modules/launcher/item.rs | 5 +- src/modules/launcher/mod.rs | 29 +++--- src/modules/mod.rs | 93 ++++++++++--------- src/modules/music/mod.rs | 36 ++++---- src/modules/script.rs | 8 +- src/modules/sysinfo.rs | 7 +- src/modules/tray.rs | 13 ++- src/modules/upower.rs | 43 +++++---- src/modules/workspaces.rs | 7 +- src/popup.rs | 44 ++++----- src/style.rs | 34 +++---- 39 files changed, 424 insertions(+), 463 deletions(-) delete mode 100644 src/bridge_channel.rs diff --git a/Cargo.lock b/Cargo.lock index fd2f619f..1197efe1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -247,21 +247,20 @@ checksum = "2ce4f10ea3abcd6617873bae9f91d1c5332b4a778bd9ce34d0cd517474c1de82" [[package]] name = "atk" -version = "0.17.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba16453d10c712284061a05f6510f75abeb92b56ba88dfeb48c74775020cc22" +checksum = "b4af014b17dd80e8af9fa689b2d4a211ddba6eb583c1622f35d0cb543f6b17e4" dependencies = [ "atk-sys", - "bitflags 1.3.2", "glib", "libc", ] [[package]] name = "atk-sys" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf0a7ca572fbd5762fd8f8cd65a581e06767bc1234913fe1f43e370cff6e90" +checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" dependencies = [ "glib-sys", "gobject-sys", @@ -364,11 +363,11 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cairo-rs" -version = "0.17.10" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3603c4028a5e368d09b51c8b624b9a46edcd7c3778284077a6125af73c9f0a" +checksum = "f33613627f0dea6a731b0605101fad59ba4f193a52c96c4687728d822605a8a1" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cairo-sys-rs", "glib", "libc", @@ -378,9 +377,9 @@ dependencies = [ [[package]] name = "cairo-sys-rs" -version = "0.17.10" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "691d0c66b1fb4881be80a760cb8fe76ea97218312f9dfe2c9cc0f496ca279cb1" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" dependencies = [ "glib-sys", "libc", @@ -1104,11 +1103,10 @@ dependencies = [ [[package]] name = "gdk" -version = "0.17.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1df5ea52cccd7e3a0897338b5564968274b52f5fd12601e0afa44f454c74d3" +checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646" dependencies = [ - "bitflags 1.3.2", "cairo-rs", "gdk-pixbuf", "gdk-sys", @@ -1120,11 +1118,10 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.17.10" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695d6bc846438c5708b07007537b9274d883373dd30858ca881d7d71b5540717" +checksum = "446f32b74d22c33b7b258d4af4ffde53c2bf96ca2e29abdf1a785fe59bd6c82c" dependencies = [ - "bitflags 1.3.2", "gdk-pixbuf-sys", "gio", "glib", @@ -1134,9 +1131,9 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" -version = "0.17.10" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9285ec3c113c66d7d0ab5676599176f1f42f4944ca1b581852215bf5694870cb" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" dependencies = [ "gio-sys", "glib-sys", @@ -1147,9 +1144,9 @@ dependencies = [ [[package]] name = "gdk-sys" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2152de9d38bc67a17b3fe49dc0823af5bf874df59ea088c5f28f31cf103de703" +checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1191,11 +1188,10 @@ checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "gio" -version = "0.17.10" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6973e92937cf98689b6a054a9e56c657ed4ff76de925e36fc331a15f0c5d30a" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" dependencies = [ - "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", @@ -1211,9 +1207,9 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.17.10" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ccf87c30a12c469b6d958950f6a9c09f2be20b7773f7e70d20b867fdf2628c3" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" dependencies = [ "glib-sys", "gobject-sys", @@ -1224,11 +1220,11 @@ dependencies = [ [[package]] name = "glib" -version = "0.17.10" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fad45ba8d4d2cea612b432717e834f48031cd8853c8aaf43b2c79fec8d144b" +checksum = "951bbd7fdc5c044ede9f05170f05a3ae9479239c3afdfe2d22d537a3add15c4e" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "futures-channel", "futures-core", "futures-executor", @@ -1247,24 +1243,23 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.17.10" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca5c79337338391f1ab8058d6698125034ce8ef31b72a442437fa6c8580de26" +checksum = "72793962ceece3863c2965d7f10c8786323b17c7adea75a515809fa20ab799a5" dependencies = [ - "anyhow", "heck 0.4.1", - "proc-macro-crate", + "proc-macro-crate 2.0.1", "proc-macro-error", "proc-macro2", "quote 1.0.32", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "glib-sys" -version = "0.17.10" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d80aa6ea7bba0baac79222204aa786a6293078c210abe69ef1336911d4bdc4f0" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" dependencies = [ "libc", "system-deps", @@ -1272,9 +1267,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.17.10" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd34c3317740a6358ec04572c1bcfd3ac0b5b6529275fae255b237b314bb8062" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" dependencies = [ "glib-sys", "libc", @@ -1283,12 +1278,11 @@ dependencies = [ [[package]] name = "gtk" -version = "0.17.1" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c4222ab92b08d4d0bab90ddb6185b4e575ceeea8b8cdf00b938d7b6661d966" +checksum = "93c4f5e0e20b60e10631a5f06da7fe3dda744b05ad0ea71fee2f47adf865890c" dependencies = [ "atk", - "bitflags 1.3.2", "cairo-rs", "field-offset", "futures-channel", @@ -1299,16 +1293,15 @@ dependencies = [ "gtk-sys", "gtk3-macros", "libc", - "once_cell", "pango", "pkg-config", ] [[package]] name = "gtk-layer-shell" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992f5fedb31835424a5280acd162bf348995f617d26969fde8d3dfd389b3ff5f" +checksum = "19fd93acba7b8ea8918fc564843a22cd1eeffe234b85a8c7d5732c611a425bb0" dependencies = [ "bitflags 2.4.0", "gdk", @@ -1321,9 +1314,9 @@ dependencies = [ [[package]] name = "gtk-layer-shell-sys" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5754bcfaadfc3529116af6ae93559b267d88647f965382153a4b8ea9372be75a" +checksum = "90e46fa9aa7c926630b2483cc3d47de26a51173fc2fddb65737e5d813d4be448" dependencies = [ "gdk-sys", "glib-sys", @@ -1334,9 +1327,9 @@ dependencies = [ [[package]] name = "gtk-sys" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d8eb6a4b93e5a7e6980f7348d08c1cd93d31fae07cf97f20678c5ec41de3d7e" +checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" dependencies = [ "atk-sys", "cairo-sys-rs", @@ -1352,16 +1345,15 @@ dependencies = [ [[package]] name = "gtk3-macros" -version = "0.17.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3efb84d682c9a39c10bd9f24f5a4b9c15cc8c7edc45c19cb2ca2c4fc38b2d95e" +checksum = "c6063efb63db582968fb7df72e1ae68aa6360dcfb0a75143f34fc7d616bad75e" dependencies = [ - "anyhow", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote 1.0.32", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] @@ -2144,11 +2136,10 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "pango" -version = "0.17.10" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35be456fc620e61f62dff7ff70fbd54dcbaf0a4b920c0f16de1107c47d921d48" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" dependencies = [ - "bitflags 1.3.2", "gio", "glib", "libc", @@ -2158,9 +2149,9 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.17.10" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da69f9f3850b0d8990d462f8c709561975e95f689c1cdf0fecdebde78b35195" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" dependencies = [ "glib-sys", "gobject-sys", @@ -2314,7 +2305,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.14", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +dependencies = [ + "toml_datetime", + "toml_edit 0.20.2", ] [[package]] @@ -3205,7 +3206,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.14", ] [[package]] @@ -3230,6 +3231,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -4029,7 +4041,7 @@ version = "3.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote 1.0.32", "regex", @@ -4068,7 +4080,7 @@ version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote 1.0.32", "syn 1.0.109", diff --git a/Cargo.toml b/Cargo.toml index 73a6d31d..df5961c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,9 +63,9 @@ workspaces = ["futures-util"] [dependencies] # core -gtk = "0.17.0" -gtk-layer-shell = "0.6.0" -glib = "0.17.10" +gtk = "0.18.1" +gtk-layer-shell = "0.8.0" +glib = "0.18.4" tokio = { version = "1.35.0", features = [ "macros", "rt-multi-thread", diff --git a/src/bar.rs b/src/bar.rs index 67a29101..76beed39 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -5,9 +5,11 @@ use crate::modules::{ use crate::popup::Popup; use crate::{Config, Ironbar}; use color_eyre::Result; +use glib::Propagation; use gtk::gdk::Monitor; use gtk::prelude::*; use gtk::{Application, ApplicationWindow, IconTheme, Orientation, Window, WindowType}; +use gtk_layer_shell::LayerShell; use std::cell::RefCell; use std::rc::Rc; use std::time::Duration; @@ -81,7 +83,7 @@ impl Bar { window.connect_destroy_event(|_, _| { info!("Shutting down"); gtk::main_quit(); - Inhibit(false) + Propagation::Proceed }); Bar { @@ -161,42 +163,38 @@ impl Bar { ) { let position = self.position; - gtk_layer_shell::init_for_window(win); - gtk_layer_shell::set_monitor(win, monitor); - gtk_layer_shell::set_layer(win, gtk_layer_shell::Layer::Top); - gtk_layer_shell::set_namespace(win, env!("CARGO_PKG_NAME")); + win.init_layer_shell(); + win.set_monitor(monitor); + win.set_layer(gtk_layer_shell::Layer::Top); + win.set_namespace(env!("CARGO_PKG_NAME")); if exclusive_zone { - gtk_layer_shell::auto_exclusive_zone_enable(win); + win.auto_exclusive_zone_enable(); } - gtk_layer_shell::set_margin(win, gtk_layer_shell::Edge::Top, margin.top); - gtk_layer_shell::set_margin(win, gtk_layer_shell::Edge::Bottom, margin.bottom); - gtk_layer_shell::set_margin(win, gtk_layer_shell::Edge::Left, margin.left); - gtk_layer_shell::set_margin(win, gtk_layer_shell::Edge::Right, margin.right); + win.set_layer_shell_margin(gtk_layer_shell::Edge::Top, margin.top); + win.set_layer_shell_margin(gtk_layer_shell::Edge::Bottom, margin.bottom); + win.set_layer_shell_margin(gtk_layer_shell::Edge::Left, margin.left); + win.set_layer_shell_margin(gtk_layer_shell::Edge::Right, margin.right); let bar_orientation = position.get_orientation(); - gtk_layer_shell::set_anchor( - win, + win.set_anchor( gtk_layer_shell::Edge::Top, position == BarPosition::Top || (bar_orientation == Orientation::Vertical && anchor_to_edges), ); - gtk_layer_shell::set_anchor( - win, + win.set_anchor( gtk_layer_shell::Edge::Bottom, position == BarPosition::Bottom || (bar_orientation == Orientation::Vertical && anchor_to_edges), ); - gtk_layer_shell::set_anchor( - win, + win.set_anchor( gtk_layer_shell::Edge::Left, position == BarPosition::Left || (bar_orientation == Orientation::Horizontal && anchor_to_edges), ); - gtk_layer_shell::set_anchor( - win, + win.set_anchor( gtk_layer_shell::Edge::Right, position == BarPosition::Right || (bar_orientation == Orientation::Horizontal && anchor_to_edges), @@ -221,7 +219,7 @@ impl Bar { win.hide(); hotspot_window.show(); }); - Inhibit(false) + Propagation::Proceed }); } @@ -232,7 +230,7 @@ impl Bar { hotspot_win.hide(); win.show(); - Inhibit(false) + Propagation::Proceed }); } } diff --git a/src/bridge_channel.rs b/src/bridge_channel.rs deleted file mode 100644 index 101eb10a..00000000 --- a/src/bridge_channel.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::send; -use tokio::spawn; -use tokio::sync::mpsc; - -/// MPSC async -> GTK sync channel. -/// The sender uses `tokio::sync::mpsc` -/// while the receiver uses `glib::MainContext::channel`. -/// -/// This makes it possible to send events asynchronously -/// and receive them on the main thread, -/// allowing UI updates to be handled on the receiving end. -pub struct BridgeChannel { - async_tx: mpsc::Sender, - sync_rx: glib::Receiver, -} - -impl BridgeChannel { - /// Creates a new channel - pub fn new() -> Self { - let (async_tx, mut async_rx) = mpsc::channel(32); - let (sync_tx, sync_rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); - - spawn(async move { - while let Some(val) = async_rx.recv().await { - send!(sync_tx, val); - } - }); - - Self { async_tx, sync_rx } - } - - /// Gets a clone of the sender. - pub fn create_sender(&self) -> mpsc::Sender { - self.async_tx.clone() - } - - /// Attaches a callback to the receiver. - pub fn recv(self, f: F) -> glib::SourceId - where - F: FnMut(T) -> glib::Continue + 'static, - { - self.sync_rx.attach(None, f) - } -} diff --git a/src/clients/clipboard.rs b/src/clients/clipboard.rs index 383c8af8..614c7e33 100644 --- a/src/clients/clipboard.rs +++ b/src/clients/clipboard.rs @@ -1,10 +1,9 @@ use super::wayland::{self, ClipboardItem}; -use crate::{arc_mut, lock, try_send}; +use crate::{arc_mut, lock, spawn, try_send}; use indexmap::map::Iter; use indexmap::IndexMap; use lazy_static::lazy_static; use std::sync::{Arc, Mutex}; -use tokio::spawn; use tokio::sync::mpsc; use tracing::{debug, trace}; diff --git a/src/clients/compositor/hyprland.rs b/src/clients/compositor/hyprland.rs index 6342ec1b..f0f1ccf0 100644 --- a/src/clients/compositor/hyprland.rs +++ b/src/clients/compositor/hyprland.rs @@ -1,5 +1,5 @@ use super::{Visibility, Workspace, WorkspaceClient, WorkspaceUpdate}; -use crate::{arc_mut, lock, send}; +use crate::{arc_mut, lock, send, spawn_blocking}; use color_eyre::Result; use hyprland::data::{Workspace as HWorkspace, Workspaces}; use hyprland::dispatch::{Dispatch, DispatchType, WorkspaceIdentifierWithSpecial}; @@ -8,7 +8,6 @@ use hyprland::prelude::*; use hyprland::shared::{HyprDataVec, WorkspaceType}; use lazy_static::lazy_static; use tokio::sync::broadcast::{channel, Receiver, Sender}; -use tokio::task::spawn_blocking; use tracing::{debug, error, info}; pub struct EventClient { diff --git a/src/clients/compositor/sway.rs b/src/clients/compositor/sway.rs index cde04e53..40f1b24e 100644 --- a/src/clients/compositor/sway.rs +++ b/src/clients/compositor/sway.rs @@ -1,12 +1,11 @@ use super::{Visibility, Workspace, WorkspaceClient, WorkspaceUpdate}; -use crate::{await_sync, send}; +use crate::{await_sync, send, spawn}; use async_once::AsyncOnce; use color_eyre::Report; use futures_util::StreamExt; use lazy_static::lazy_static; use std::sync::Arc; use swayipc_async::{Connection, Event, EventType, Node, WorkspaceChange, WorkspaceEvent}; -use tokio::spawn; use tokio::sync::broadcast::{channel, Receiver, Sender}; use tokio::sync::Mutex; use tracing::{info, trace}; diff --git a/src/clients/music/mpd.rs b/src/clients/music/mpd.rs index 742b1725..2d2ffaa5 100644 --- a/src/clients/music/mpd.rs +++ b/src/clients/music/mpd.rs @@ -1,7 +1,7 @@ use super::{ MusicClient, PlayerState, PlayerUpdate, ProgressTick, Status, Track, TICK_INTERVAL_MS, }; -use crate::{await_sync, send}; +use crate::{await_sync, send, spawn}; use color_eyre::Result; use lazy_static::lazy_static; use mpd_client::client::{Connection, ConnectionEvent, Subsystem}; @@ -17,7 +17,6 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use std::time::Duration; use tokio::net::{TcpStream, UnixStream}; -use tokio::spawn; use tokio::sync::broadcast; use tokio::sync::Mutex; use tokio::time::sleep; diff --git a/src/clients/music/mpris.rs b/src/clients/music/mpris.rs index 2cbc5a24..103bd21a 100644 --- a/src/clients/music/mpris.rs +++ b/src/clients/music/mpris.rs @@ -1,6 +1,6 @@ use super::{MusicClient, PlayerState, PlayerUpdate, Status, Track, TICK_INTERVAL_MS}; use crate::clients::music::ProgressTick; -use crate::{arc_mut, lock, send}; +use crate::{arc_mut, lock, send, spawn_blocking}; use color_eyre::Result; use lazy_static::lazy_static; use mpris::{DBusError, Event, Metadata, PlaybackStatus, Player, PlayerFinder}; @@ -10,7 +10,6 @@ use std::thread::sleep; use std::time::Duration; use std::{cmp, string}; use tokio::sync::broadcast; -use tokio::task::spawn_blocking; use tracing::{debug, error, trace}; lazy_static! { diff --git a/src/clients/system_tray.rs b/src/clients/system_tray.rs index 5978338a..0c700c02 100644 --- a/src/clients/system_tray.rs +++ b/src/clients/system_tray.rs @@ -1,4 +1,4 @@ -use crate::{arc_mut, lock, send, Ironbar}; +use crate::{arc_mut, lock, send, spawn, Ironbar}; use async_once::AsyncOnce; use color_eyre::Report; use lazy_static::lazy_static; @@ -8,7 +8,6 @@ use system_tray::message::menu::TrayMenu; use system_tray::message::tray::StatusNotifierItem; use system_tray::message::{NotifierItemCommand, NotifierItemMessage}; use system_tray::StatusNotifierWatcher; -use tokio::spawn; use tokio::sync::{broadcast, mpsc}; use tracing::{debug, error, trace}; diff --git a/src/clients/wayland/client.rs b/src/clients/wayland/client.rs index 2c562107..c4ddb627 100644 --- a/src/clients/wayland/client.rs +++ b/src/clients/wayland/client.rs @@ -3,7 +3,7 @@ use super::wlr_foreign_toplevel::manager::ToplevelManagerState; use super::wlr_foreign_toplevel::ToplevelEvent; use super::Environment; use crate::error::ERR_CHANNEL_RECV; -use crate::send; +use crate::{send, spawn_blocking}; use cfg_if::cfg_if; use color_eyre::Report; use smithay_client_toolkit::output::{OutputInfo, OutputState}; @@ -15,7 +15,6 @@ use smithay_client_toolkit::seat::SeatState; use std::collections::HashMap; use std::sync::mpsc; use tokio::sync::broadcast; -use tokio::task::spawn_blocking; use tracing::{debug, error, trace}; use wayland_client::globals::registry_queue_init; use wayland_client::protocol::wl_seat::WlSeat; diff --git a/src/config/common.rs b/src/config/common.rs index b22b38ef..3e3cc850 100644 --- a/src/config/common.rs +++ b/src/config/common.rs @@ -1,5 +1,6 @@ use crate::dynamic_value::{dynamic_string, DynamicBool}; use crate::script::{Script, ScriptInput}; +use glib::Propagation; use gtk::gdk::ScrollDirection; use gtk::prelude::*; use gtk::{EventBox, Orientation, Revealer, RevealerTransitionType}; @@ -75,7 +76,7 @@ impl CommonConfig { script.run_as_oneshot(None); } - Inhibit(false) + Propagation::Proceed }); let scroll_up_script = self.on_scroll_up.map(Script::new_polling); @@ -93,7 +94,7 @@ impl CommonConfig { script.run_as_oneshot(None); } - Inhibit(false) + Propagation::Proceed }); macro_rules! install_oneshot { @@ -101,7 +102,7 @@ impl CommonConfig { $option.map(Script::new_polling).map(|script| { container.$method(move |_, _| { script.run_as_oneshot(None); - Inhibit(false) + Propagation::Proceed }); }) }; @@ -114,7 +115,6 @@ impl CommonConfig { let container = container.clone(); dynamic_string(&tooltip, move |string| { container.set_tooltip_text(Some(&string)); - Continue(true) }); } } @@ -136,7 +136,6 @@ impl CommonConfig { container.show_all(); } revealer.set_reveal_child(success); - Continue(true) }); } diff --git a/src/dynamic_value/dynamic_bool.rs b/src/dynamic_value/dynamic_bool.rs index 2afde471..711a92a4 100644 --- a/src/dynamic_value/dynamic_bool.rs +++ b/src/dynamic_value/dynamic_bool.rs @@ -1,11 +1,10 @@ use crate::script::Script; -use crate::send; +use crate::{glib_recv_mpsc, spawn, try_send}; #[cfg(feature = "ipc")] -use crate::Ironbar; +use crate::{send_async, Ironbar}; use cfg_if::cfg_if; -use glib::Continue; use serde::Deserialize; -use tokio::spawn; +use tokio::sync::mpsc; #[derive(Debug, Deserialize, Clone)] #[serde(untagged)] @@ -18,9 +17,9 @@ pub enum DynamicBool { } impl DynamicBool { - pub fn subscribe(self, f: F) + pub fn subscribe(self, mut f: F) where - F: FnMut(bool) -> Continue + 'static, + F: FnMut(bool) + 'static, { let value = match self { Self::Unknown(input) => { @@ -40,16 +39,16 @@ impl DynamicBool { _ => self, }; - let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); + let (tx, mut rx) = mpsc::channel(32); - rx.attach(None, f); + glib_recv_mpsc!(rx, val => f(val)); spawn(async move { match value { DynamicBool::Script(script) => { script .run(None, |_, success| { - send!(tx, success); + try_send!(tx, success); }) .await; } @@ -62,7 +61,7 @@ impl DynamicBool { while let Ok(value) = rx.recv().await { let has_value = value.map(|s| is_truthy(&s)).unwrap_or_default(); - send!(tx, has_value); + send_async!(tx, has_value); } } DynamicBool::Unknown(_) => unreachable!(), @@ -71,7 +70,10 @@ impl DynamicBool { } } -/// Check if a string ironvar is 'truthy' +/// Check if a string ironvar is 'truthy', +/// i.e should be evaluated to true. +/// +/// This loosely follows the common JavaScript cases. #[cfg(feature = "ipc")] fn is_truthy(string: &str) -> bool { !(string.is_empty() || string == "0" || string == "false") diff --git a/src/dynamic_value/dynamic_string.rs b/src/dynamic_value/dynamic_string.rs index cdfbd5c0..7654f97e 100644 --- a/src/dynamic_value/dynamic_string.rs +++ b/src/dynamic_value/dynamic_string.rs @@ -1,9 +1,8 @@ use crate::script::{OutputStream, Script}; #[cfg(feature = "ipc")] use crate::Ironbar; -use crate::{arc_mut, lock, send}; -use gtk::prelude::*; -use tokio::spawn; +use crate::{arc_mut, glib_recv_mpsc, lock, spawn, try_send}; +use tokio::sync::mpsc; /// A segment of a dynamic string, /// containing either a static string @@ -24,17 +23,16 @@ enum DynamicStringSegment { /// ```rs /// dynamic_string(&text, move |string| { /// label.set_markup(&string); -/// Continue(true) /// }); /// ``` -pub fn dynamic_string(input: &str, f: F) +pub fn dynamic_string(input: &str, mut f: F) where - F: FnMut(String) -> Continue + 'static, + F: FnMut(String) + 'static, { let tokens = parse_input(input); let label_parts = arc_mut!(vec![]); - let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); + let (tx, mut rx) = mpsc::channel(32); for (i, segment) in tokens.into_iter().enumerate() { match segment { @@ -57,7 +55,7 @@ where let _: String = std::mem::replace(&mut label_parts[i], out); let string = label_parts.join(""); - send!(tx, string); + try_send!(tx, string); } }) .await; @@ -82,7 +80,7 @@ where let _: String = std::mem::replace(&mut label_parts[i], value); let string = label_parts.join(""); - send!(tx, string); + try_send!(tx, string); } } }); @@ -90,12 +88,12 @@ where } } - rx.attach(None, f); + glib_recv_mpsc!(rx , val => f(val)); // initialize { let label_parts = lock!(label_parts).join(""); - send!(tx, label_parts); + try_send!(tx, label_parts); } } diff --git a/src/image/provider.rs b/src/image/provider.rs index 397ba62b..defefb61 100644 --- a/src/image/provider.rs +++ b/src/image/provider.rs @@ -1,4 +1,6 @@ use crate::desktop_file::get_desktop_icon_name; +#[cfg(feature = "http")] +use crate::{glib_recv_mpsc, send_async, spawn}; use cfg_if::cfg_if; use color_eyre::{Help, Report, Result}; use gtk::cairo::Surface; @@ -7,13 +9,13 @@ use gtk::gdk_pixbuf::Pixbuf; use gtk::prelude::*; use gtk::{IconLookupFlags, IconTheme}; use std::path::{Path, PathBuf}; +#[cfg(feature = "http")] +use tokio::sync::mpsc; use tracing::warn; cfg_if!( if #[cfg(feature = "http")] { - use crate::send; use gtk::gio::{Cancellable, MemoryInputStream}; - use tokio::spawn; use tracing::error; } ); @@ -143,18 +145,18 @@ impl<'a> ImageProvider<'a> { #[cfg(feature = "http")] if let ImageLocation::Remote(url) = &self.location { let url = url.clone(); - let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); + let (tx, mut rx) = mpsc::channel(64); spawn(async move { let bytes = Self::get_bytes_from_http(url).await; if let Ok(bytes) = bytes { - send!(tx, bytes); + send_async!(tx, bytes); } }); { let size = self.size; - rx.attach(None, move |bytes| { + glib_recv_mpsc!(rx, bytes => { let stream = MemoryInputStream::from_bytes(&bytes); let scale = image.scale_factor(); @@ -175,8 +177,6 @@ impl<'a> ImageProvider<'a> { Err(err) => error!("{err:?}"), _ => {} } - - Continue(false) }); } } else { diff --git a/src/ipc/server.rs b/src/ipc/server.rs index 78721f44..26c76b32 100644 --- a/src/ipc/server.rs +++ b/src/ipc/server.rs @@ -3,20 +3,17 @@ use std::path::Path; use std::rc::Rc; use color_eyre::{Report, Result}; -use glib::Continue; use gtk::prelude::*; use gtk::Application; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::{UnixListener, UnixStream}; -use tokio::spawn; use tokio::sync::mpsc::{self, Receiver, Sender}; use tracing::{debug, error, info, warn}; -use crate::bridge_channel::BridgeChannel; use crate::ipc::{Command, Response}; use crate::modules::PopupButton; use crate::style::load_css; -use crate::{read_lock, send_async, try_send, write_lock, Ironbar}; +use crate::{glib_recv_mpsc, read_lock, send_async, spawn, try_send, write_lock, Ironbar}; use super::Ipc; @@ -25,8 +22,7 @@ impl Ipc { /// /// Once started, the server will begin accepting connections. pub fn start(&self, application: &Application, ironbar: Rc) { - let bridge = BridgeChannel::::new(); - let cmd_tx = bridge.create_sender(); + let (cmd_tx, mut cmd_rx) = mpsc::channel(32); let (res_tx, mut res_rx) = mpsc::channel(32); let path = self.path.clone(); @@ -68,10 +64,9 @@ impl Ipc { }); let application = application.clone(); - bridge.recv(move |command| { - let res = Self::handle_command(command, &application, ironbar.clone()); + glib_recv_mpsc!(cmd_rx, command => { + let res = Self::handle_command(command, &application, &ironbar); try_send!(res_tx, res); - Continue(true) }); } @@ -109,11 +104,7 @@ impl Ipc { /// Takes an input command, runs it and returns with the appropriate response. /// /// This runs on the main thread, allowing commands to interact with GTK. - fn handle_command( - command: Command, - application: &Application, - ironbar: Rc, - ) -> Response { + fn handle_command(command: Command, application: &Application, ironbar: &Ironbar) -> Response { match command { Command::Inspect => { gtk::Window::set_interactive_debugging(true); diff --git a/src/macros.rs b/src/macros.rs index 5e5e99fd..deb8975f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -43,6 +43,55 @@ macro_rules! try_send { }; } +/// Spawns a `GLib` future on the local thread, and calls `rx.recv()` +/// in a loop. +/// +/// This allows use of `GObjects` and futures in the same context. +/// +/// For use with receivers which return a `Result`. +/// +/// # Example +/// +/// ```rs +/// let (tx, mut rx) = broadcast::channel(32); +/// glib_recv(rx, msg => println!("{msg}")); +/// ``` +#[macro_export] +macro_rules! glib_recv { + ($rx:expr, $val:ident => $expr:expr) => { + glib::spawn_future_local(async move { + while let Ok($val) = $rx.recv().await { + $expr + } + }); + }; +} + +/// Spawns a `GLib` future on the local thread, and calls `rx.recv()` +/// in a loop. +/// +/// This allows use of `GObjects` and futures in the same context. +/// +/// For use with receivers which return an `Option`, +/// such as Tokio's `mpsc` channel. +/// +/// # Example +/// +/// ```rs +/// let (tx, mut rx) = broadcast::channel(32); +/// glib_recv_mpsc(rx, msg => println!("{msg}")); +/// ``` +#[macro_export] +macro_rules! glib_recv_mpsc { + ($rx:expr, $val:ident => $expr:expr) => { + glib::spawn_future_local(async move { + while let Some($val) = $rx.recv().await { + $expr + } + }); + }; +} + /// Locks a `Mutex`. /// Panics if the `Mutex` cannot be locked. /// diff --git a/src/main.rs b/src/main.rs index 033c9b5b..0fee3d94 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,9 @@ use std::path::PathBuf; use std::process::exit; use std::rc::Rc; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::mpsc; #[cfg(feature = "ipc")] -use std::sync::{Arc, RwLock}; +use std::sync::RwLock; +use std::sync::{mpsc, Arc}; use cfg_if::cfg_if; #[cfg(feature = "cli")] @@ -21,8 +21,8 @@ use glib::PropertySet; use gtk::gdk::Display; use gtk::prelude::*; use gtk::Application; -use tokio::runtime::Handle; -use tokio::task::{block_in_place, spawn_blocking}; +use tokio::runtime::{Handle, Runtime}; +use tokio::task::{block_in_place, JoinHandle}; use tracing::{debug, error, info, warn}; use universal_config::ConfigLoader; @@ -36,7 +36,6 @@ use crate::ironvar::VariableManager; use crate::style::load_css; mod bar; -mod bridge_channel; #[cfg(feature = "cli")] mod cli; mod clients; @@ -60,13 +59,12 @@ mod style; const GTK_APP_ID: &str = "dev.jstanger.ironbar"; const VERSION: &str = env!("CARGO_PKG_VERSION"); -#[tokio::main] -async fn main() { +fn main() { let _guard = logging::install_logging(); cfg_if! { if #[cfg(feature = "cli")] { - run_with_args().await; + run_with_args(); } else { start_ironbar(); } @@ -74,16 +72,19 @@ async fn main() { } #[cfg(feature = "cli")] -async fn run_with_args() { +fn run_with_args() { let args = cli::Args::parse(); match args.command { Some(command) => { - let ipc = ipc::Ipc::new(); - match ipc.send(command).await { - Ok(res) => cli::handle_response(res), - Err(err) => error!("{err:?}"), - }; + let rt = create_runtime(); + rt.block_on(async move { + let ipc = ipc::Ipc::new(); + match ipc.send(command).await { + Ok(res) => cli::handle_response(res), + Err(err) => error!("{err:?}"), + }; + }); } None => start_ironbar(), } @@ -91,6 +92,10 @@ async fn run_with_args() { static COUNTER: AtomicUsize = AtomicUsize::new(1); +lazy_static::lazy_static! { + static ref RUNTIME: Arc = Arc::new(create_runtime()); +} + #[cfg(feature = "ipc")] lazy_static::lazy_static! { static ref VARIABLE_MANAGER: Arc> = arc_rw!(VariableManager::new()); @@ -184,6 +189,12 @@ impl Ironbar { app.run_with_args(&Vec::<&str>::new()); } + /// Gets the current Tokio runtime. + #[must_use] + pub fn runtime() -> Arc { + RUNTIME.clone() + } + /// Gets a `usize` ID value that is unique to the entire Ironbar instance. /// This is just a static `AtomicUsize` that increments every time this function is called. pub fn unique_id() -> usize { @@ -323,6 +334,31 @@ fn create_bars(app: &Application, display: &Display, config: &Config) -> Result< Ok(all_bars) } +fn create_runtime() -> Runtime { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .expect("tokio to create a valid runtime") +} + +/// Calls `spawn` on the Tokio runtime. +pub fn spawn(f: F) -> JoinHandle +where + F: Future + Send + 'static, + F::Output: Send + 'static, +{ + Ironbar::runtime().spawn(f) +} + +/// Calls `spawn_blocking` on the Tokio runtime. +pub fn spawn_blocking(f: F) -> JoinHandle +where + F: FnOnce() -> R + Send + 'static, + R: Send + 'static, +{ + Ironbar::runtime().spawn_blocking(f) +} + /// Blocks on a `Future` until it resolves. /// /// This is not an `async` operation diff --git a/src/modules/clipboard.rs b/src/modules/clipboard.rs index e52afa5a..cdc72fb8 100644 --- a/src/modules/clipboard.rs +++ b/src/modules/clipboard.rs @@ -5,7 +5,8 @@ use crate::image::new_icon_button; use crate::modules::{ Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext, }; -use crate::try_send; +use crate::{glib_recv, spawn, try_send}; +use glib::Propagation; use gtk::gdk_pixbuf::Pixbuf; use gtk::gio::{Cancellable, MemoryInputStream}; use gtk::prelude::*; @@ -13,8 +14,7 @@ use gtk::{Button, EventBox, Image, Label, Orientation, RadioButton, Widget}; use serde::Deserialize; use std::collections::HashMap; use std::sync::Arc; -use tokio::spawn; -use tokio::sync::mpsc::{Receiver, Sender}; +use tokio::sync::{broadcast, mpsc}; use tracing::{debug, error}; #[derive(Debug, Deserialize, Clone)] @@ -72,8 +72,8 @@ impl Module