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