mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-04-19 19:34:24 +02:00
Merge pull request #380 from JakeStanger/refactor/update-gtk
Update GTK-related crates, replace GLib channels with Tokio channels, refactor Tokio runtime code
This commit is contained in:
commit
29eeefbd24
39 changed files with 430 additions and 469 deletions
134
Cargo.lock
generated
134
Cargo.lock
generated
|
@ -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]]
|
||||
|
@ -2120,11 +2112,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",
|
||||
|
@ -2134,9 +2125,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",
|
||||
|
@ -2290,7 +2281,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]]
|
||||
|
@ -3181,7 +3182,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
"toml_edit 0.19.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3206,6 +3207,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"
|
||||
|
@ -4005,7 +4017,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",
|
||||
|
@ -4044,7 +4056,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",
|
||||
|
|
|
@ -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",
|
||||
|
|
38
src/bar.rs
38
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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T> {
|
||||
async_tx: mpsc::Sender<T>,
|
||||
sync_rx: glib::Receiver<T>,
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> BridgeChannel<T> {
|
||||
/// 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<T> {
|
||||
self.async_tx.clone()
|
||||
}
|
||||
|
||||
/// Attaches a callback to the receiver.
|
||||
pub fn recv<F>(self, f: F) -> glib::SourceId
|
||||
where
|
||||
F: FnMut(T) -> glib::Continue + 'static,
|
||||
{
|
||||
self.sync_rx.attach(None, f)
|
||||
}
|
||||
}
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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! {
|
||||
|
@ -245,7 +244,7 @@ impl MusicClient for Client {
|
|||
|
||||
fn set_volume_percent(&self, vol: u8) -> Result<()> {
|
||||
if let Some(player) = Self::get_player(self) {
|
||||
player.set_volume(vol as f64 / 100.0)?;
|
||||
player.set_volume(f64::from(vol) / 100.0)?;
|
||||
} else {
|
||||
error!("Could not find player");
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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<F>(self, f: F)
|
||||
pub fn subscribe<F>(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")
|
||||
|
|
|
@ -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<F>(input: &str, f: F)
|
||||
pub fn dynamic_string<F>(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<Ironbar>) {
|
||||
let bridge = BridgeChannel::<Command>::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<Ironbar>,
|
||||
) -> Response {
|
||||
fn handle_command(command: Command, application: &Application, ironbar: &Ironbar) -> Response {
|
||||
match command {
|
||||
Command::Inspect => {
|
||||
gtk::Window::set_interactive_debugging(true);
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
64
src/main.rs
64
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<Runtime> = Arc::new(create_runtime());
|
||||
}
|
||||
|
||||
#[cfg(feature = "ipc")]
|
||||
lazy_static::lazy_static! {
|
||||
static ref VARIABLE_MANAGER: Arc<RwLock<VariableManager>> = 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> {
|
||||
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: F) -> JoinHandle<F::Output>
|
||||
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, R>(f: F) -> JoinHandle<R>
|
||||
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
|
||||
|
|
|
@ -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<Button> for ClipboardModule {
|
|||
fn spawn_controller(
|
||||
&self,
|
||||
_info: &ModuleInfo,
|
||||
tx: Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
mut rx: Receiver<Self::ReceiveMessage>,
|
||||
tx: mpsc::Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
mut rx: mpsc::Receiver<Self::ReceiveMessage>,
|
||||
) -> color_eyre::Result<()> {
|
||||
let max_items = self.max_items;
|
||||
|
||||
|
@ -129,19 +129,14 @@ impl Module<Button> for ClipboardModule {
|
|||
let button = new_icon_button(&self.icon, info.icon_theme, self.icon_size);
|
||||
button.style_context().add_class("btn");
|
||||
|
||||
let tx = context.tx.clone();
|
||||
button.connect_clicked(move |button| {
|
||||
try_send!(
|
||||
context.tx,
|
||||
ModuleUpdateEvent::TogglePopup(button.popup_id())
|
||||
);
|
||||
try_send!(tx, ModuleUpdateEvent::TogglePopup(button.popup_id()));
|
||||
});
|
||||
|
||||
// we need to bind to the receiver as the channel does not open
|
||||
// until the popup is first opened.
|
||||
context.widget_rx.attach(None, |_| Continue(true));
|
||||
|
||||
let rx = context.subscribe();
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup(context.controller_tx, rx, info)
|
||||
.into_popup_parts(vec![&button]);
|
||||
|
||||
Ok(ModuleParts::new(button, popup))
|
||||
|
@ -149,8 +144,8 @@ impl Module<Button> for ClipboardModule {
|
|||
|
||||
fn into_popup(
|
||||
self,
|
||||
tx: Sender<Self::ReceiveMessage>,
|
||||
rx: glib::Receiver<Self::SendMessage>,
|
||||
tx: mpsc::Sender<Self::ReceiveMessage>,
|
||||
mut rx: broadcast::Receiver<Self::SendMessage>,
|
||||
_info: &ModuleInfo,
|
||||
) -> Option<gtk::Box>
|
||||
where
|
||||
|
@ -168,7 +163,7 @@ impl Module<Button> for ClipboardModule {
|
|||
|
||||
{
|
||||
let hidden_option = hidden_option.clone();
|
||||
rx.attach(None, move |event| {
|
||||
glib_recv!(rx, event => {
|
||||
match event {
|
||||
ControllerEvent::Add(id, item) => {
|
||||
debug!("Adding new value with ID {}", id);
|
||||
|
@ -234,7 +229,7 @@ impl Module<Button> for ClipboardModule {
|
|||
try_send!(tx, UIEvent::Copy(id));
|
||||
}
|
||||
|
||||
Inhibit(true)
|
||||
Propagation::Stop
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -293,8 +288,6 @@ impl Module<Button> for ClipboardModule {
|
|||
hidden_option.set_active(true);
|
||||
}
|
||||
}
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,10 @@ use std::env;
|
|||
|
||||
use chrono::{DateTime, Local, Locale};
|
||||
use color_eyre::Result;
|
||||
use glib::Continue;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Align, Button, Calendar, Label, Orientation};
|
||||
use serde::Deserialize;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::config::CommonConfig;
|
||||
|
@ -15,7 +13,7 @@ use crate::gtk_helpers::IronbarGtkExt;
|
|||
use crate::modules::{
|
||||
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext,
|
||||
};
|
||||
use crate::{send_async, try_send};
|
||||
use crate::{glib_recv, send_async, spawn, try_send};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ClockModule {
|
||||
|
@ -104,24 +102,22 @@ impl Module<Button> for ClockModule {
|
|||
label.set_angle(info.bar_position.get_angle());
|
||||
button.add(&label);
|
||||
|
||||
let tx = context.tx.clone();
|
||||
button.connect_clicked(move |button| {
|
||||
try_send!(
|
||||
context.tx,
|
||||
ModuleUpdateEvent::TogglePopup(button.popup_id())
|
||||
);
|
||||
try_send!(tx, ModuleUpdateEvent::TogglePopup(button.popup_id()));
|
||||
});
|
||||
|
||||
let format = self.format.clone();
|
||||
let locale = Locale::try_from(self.locale.as_str()).unwrap_or(Locale::POSIX);
|
||||
|
||||
context.widget_rx.attach(None, move |date| {
|
||||
let mut rx = context.subscribe();
|
||||
glib_recv!(rx, date => {
|
||||
let date_string = format!("{}", date.format_localized(&format, locale));
|
||||
label.set_label(&date_string);
|
||||
Continue(true)
|
||||
});
|
||||
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup(context.controller_tx.clone(), context.subscribe(), info)
|
||||
.into_popup_parts(vec![&button]);
|
||||
|
||||
Ok(ModuleParts::new(button, popup))
|
||||
|
@ -130,7 +126,7 @@ impl Module<Button> for ClockModule {
|
|||
fn into_popup(
|
||||
self,
|
||||
_tx: mpsc::Sender<Self::ReceiveMessage>,
|
||||
rx: glib::Receiver<Self::SendMessage>,
|
||||
mut rx: broadcast::Receiver<Self::SendMessage>,
|
||||
_info: &ModuleInfo,
|
||||
) -> Option<gtk::Box> {
|
||||
let container = gtk::Box::new(Orientation::Vertical, 0);
|
||||
|
@ -147,10 +143,9 @@ impl Module<Button> for ClockModule {
|
|||
let format = self.format_popup;
|
||||
let locale = Locale::try_from(self.locale.as_str()).unwrap_or(Locale::POSIX);
|
||||
|
||||
rx.attach(None, move |date| {
|
||||
glib_recv!(rx, date => {
|
||||
let date_string = format!("{}", date.format_localized(&format, locale));
|
||||
clock.set_label(&date_string);
|
||||
Continue(true)
|
||||
});
|
||||
|
||||
container.show_all();
|
||||
|
|
|
@ -30,7 +30,6 @@ impl CustomWidget for ButtonWidget {
|
|||
|
||||
dynamic_string(&text, move |string| {
|
||||
label.set_markup(&string);
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,6 @@ impl CustomWidget for ImageWidget {
|
|||
dynamic_string(&self.src, move |src| {
|
||||
ImageProvider::parse(&src, &icon_theme, false, self.size)
|
||||
.map(|image| image.load_into_image(gtk_image.clone()));
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ impl CustomWidget for LabelWidget {
|
|||
let label = label.clone();
|
||||
dynamic_string(&self.label, move |string| {
|
||||
label.set_markup(&string);
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -16,15 +16,14 @@ use crate::modules::{
|
|||
wrap_widget, Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext,
|
||||
};
|
||||
use crate::script::Script;
|
||||
use crate::send_async;
|
||||
use crate::{send_async, spawn};
|
||||
use color_eyre::{Report, Result};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Button, IconTheme, Orientation};
|
||||
use serde::Deserialize;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
use tracing::{debug, error};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
|
@ -59,7 +58,7 @@ pub enum Widget {
|
|||
|
||||
#[derive(Clone)]
|
||||
struct CustomWidgetContext<'a> {
|
||||
tx: &'a Sender<ExecEvent>,
|
||||
tx: &'a mpsc::Sender<ExecEvent>,
|
||||
bar_orientation: Orientation,
|
||||
icon_theme: &'a IconTheme,
|
||||
popup_buttons: Rc<RefCell<Vec<Button>>>,
|
||||
|
@ -159,8 +158,8 @@ impl Module<gtk::Box> for CustomModule {
|
|||
fn spawn_controller(
|
||||
&self,
|
||||
_info: &ModuleInfo,
|
||||
tx: Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
mut rx: Receiver<Self::ReceiveMessage>,
|
||||
tx: mpsc::Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
mut rx: mpsc::Receiver<Self::ReceiveMessage>,
|
||||
) -> Result<()> {
|
||||
spawn(async move {
|
||||
while let Some(event) = rx.recv().await {
|
||||
|
@ -213,7 +212,7 @@ impl Module<gtk::Box> for CustomModule {
|
|||
});
|
||||
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup(context.controller_tx.clone(), context.subscribe(), info)
|
||||
.into_popup_parts_owned(popup_buttons.take());
|
||||
|
||||
Ok(ModuleParts {
|
||||
|
@ -224,8 +223,8 @@ impl Module<gtk::Box> for CustomModule {
|
|||
|
||||
fn into_popup(
|
||||
self,
|
||||
tx: Sender<Self::ReceiveMessage>,
|
||||
_rx: glib::Receiver<Self::SendMessage>,
|
||||
tx: mpsc::Sender<Self::ReceiveMessage>,
|
||||
_rx: broadcast::Receiver<Self::SendMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Option<gtk::Box>
|
||||
where
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use gtk::prelude::*;
|
||||
use gtk::ProgressBar;
|
||||
use serde::Deserialize;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::error;
|
||||
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
use crate::modules::custom::set_length;
|
||||
use crate::script::{OutputStream, Script, ScriptInput};
|
||||
use crate::{build, send};
|
||||
use crate::{build, glib_recv_mpsc, spawn, try_send};
|
||||
|
||||
use super::{try_get_orientation, CustomWidget, CustomWidgetContext};
|
||||
|
||||
|
@ -47,13 +47,13 @@ impl CustomWidget for ProgressWidget {
|
|||
let script = Script::from(value);
|
||||
let progress = progress.clone();
|
||||
|
||||
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||
let (tx, mut rx) = mpsc::channel(128);
|
||||
|
||||
spawn(async move {
|
||||
script
|
||||
.run(None, move |stream, _success| match stream {
|
||||
OutputStream::Stdout(out) => match out.parse::<f64>() {
|
||||
Ok(value) => send!(tx, value),
|
||||
Ok(value) => try_send!(tx, value),
|
||||
Err(err) => error!("{err:?}"),
|
||||
},
|
||||
OutputStream::Stderr(err) => error!("{err:?}"),
|
||||
|
@ -61,10 +61,7 @@ impl CustomWidget for ProgressWidget {
|
|||
.await;
|
||||
});
|
||||
|
||||
rx.attach(None, move |value| {
|
||||
progress.set_fraction(value / self.max);
|
||||
Continue(true)
|
||||
});
|
||||
glib_recv_mpsc!(rx, value => progress.set_fraction(value / self.max));
|
||||
}
|
||||
|
||||
if let Some(text) = self.label {
|
||||
|
@ -73,7 +70,6 @@ impl CustomWidget for ProgressWidget {
|
|||
|
||||
dynamic_string(&text, move |string| {
|
||||
progress.set_text(Some(&string));
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
use glib::Propagation;
|
||||
use std::cell::Cell;
|
||||
use std::ops::Neg;
|
||||
|
||||
use gtk::prelude::*;
|
||||
use gtk::Scale;
|
||||
use serde::Deserialize;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::error;
|
||||
|
||||
use crate::modules::custom::set_length;
|
||||
use crate::script::{OutputStream, Script, ScriptInput};
|
||||
use crate::{build, send, try_send};
|
||||
use crate::{build, glib_recv_mpsc, spawn, try_send};
|
||||
|
||||
use super::{try_get_orientation, CustomWidget, CustomWidgetContext, ExecEvent};
|
||||
|
||||
|
@ -77,7 +78,7 @@ impl CustomWidget for SliderWidget {
|
|||
};
|
||||
|
||||
scale.set_value(value + delta);
|
||||
Inhibit(false)
|
||||
Propagation::Proceed
|
||||
});
|
||||
|
||||
scale.connect_change_value(move |_, _, val| {
|
||||
|
@ -97,7 +98,7 @@ impl CustomWidget for SliderWidget {
|
|||
prev_value.set(val);
|
||||
}
|
||||
|
||||
Inhibit(false)
|
||||
Propagation::Proceed
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -105,13 +106,13 @@ impl CustomWidget for SliderWidget {
|
|||
let script = Script::from(value);
|
||||
let scale = scale.clone();
|
||||
|
||||
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||
let (tx, mut rx) = mpsc::channel(128);
|
||||
|
||||
spawn(async move {
|
||||
script
|
||||
.run(None, move |stream, _success| match stream {
|
||||
OutputStream::Stdout(out) => match out.parse() {
|
||||
Ok(value) => send!(tx, value),
|
||||
Ok(value) => try_send!(tx, value),
|
||||
Err(err) => error!("{err:?}"),
|
||||
},
|
||||
OutputStream::Stderr(err) => error!("{err:?}"),
|
||||
|
@ -119,10 +120,7 @@ impl CustomWidget for SliderWidget {
|
|||
.await;
|
||||
});
|
||||
|
||||
rx.attach(None, move |value| {
|
||||
scale.set_value(value);
|
||||
Continue(true)
|
||||
});
|
||||
glib_recv_mpsc!(rx, value => scale.set_value(value));
|
||||
}
|
||||
|
||||
scale
|
||||
|
|
|
@ -3,13 +3,11 @@ use crate::config::{CommonConfig, TruncateMode};
|
|||
use crate::gtk_helpers::IronbarGtkExt;
|
||||
use crate::image::ImageProvider;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::{lock, send_async, try_send};
|
||||
use crate::{glib_recv, lock, send_async, spawn, try_send};
|
||||
use color_eyre::Result;
|
||||
use glib::Continue;
|
||||
use gtk::prelude::*;
|
||||
use gtk::Label;
|
||||
use serde::Deserialize;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tracing::debug;
|
||||
|
||||
|
@ -141,7 +139,7 @@ impl Module<gtk::Box> for FocusedModule {
|
|||
|
||||
{
|
||||
let icon_theme = icon_theme.clone();
|
||||
context.widget_rx.attach(None, move |data| {
|
||||
glib_recv!(context.subscribe(), data => {
|
||||
if let Some((name, id)) = data {
|
||||
if self.show_icon {
|
||||
match ImageProvider::parse(&id, &icon_theme, true, self.icon_size)
|
||||
|
@ -160,8 +158,6 @@ impl Module<gtk::Box> for FocusedModule {
|
|||
icon.hide();
|
||||
label.hide();
|
||||
}
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use crate::config::CommonConfig;
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::try_send;
|
||||
use crate::{glib_recv, try_send};
|
||||
use color_eyre::Result;
|
||||
use glib::Continue;
|
||||
use gtk::prelude::*;
|
||||
use gtk::Label;
|
||||
use serde::Deserialize;
|
||||
|
@ -42,7 +41,6 @@ impl Module<Label> for LabelModule {
|
|||
) -> Result<()> {
|
||||
dynamic_string(&self.label, move |string| {
|
||||
try_send!(tx, ModuleUpdateEvent::Update(string));
|
||||
Continue(true)
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
@ -58,10 +56,7 @@ impl Module<Label> for LabelModule {
|
|||
|
||||
{
|
||||
let label = label.clone();
|
||||
context.widget_rx.attach(None, move |string| {
|
||||
label.set_markup(&string);
|
||||
Continue(true)
|
||||
});
|
||||
glib_recv!(context.subscribe(), string => label.set_markup(&string));
|
||||
}
|
||||
|
||||
Ok(ModuleParts {
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::modules::launcher::{ItemEvent, LauncherUpdate};
|
|||
use crate::modules::ModuleUpdateEvent;
|
||||
use crate::{read_lock, try_send};
|
||||
use color_eyre::{Report, Result};
|
||||
use glib::Propagation;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Button, IconTheme};
|
||||
use indexmap::IndexMap;
|
||||
|
@ -258,7 +259,7 @@ impl ItemButton {
|
|||
try_send!(tx, ModuleUpdateEvent::ClosePopup);
|
||||
}
|
||||
|
||||
Inhibit(false)
|
||||
Propagation::Proceed
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -273,9 +274,9 @@ impl ItemButton {
|
|||
let (x, y) = ev.position();
|
||||
|
||||
let close = match bar_position {
|
||||
BarPosition::Top => y + THRESHOLD < alloc.height() as f64,
|
||||
BarPosition::Top => y + THRESHOLD < f64::from(alloc.height()),
|
||||
BarPosition::Bottom => y > THRESHOLD,
|
||||
BarPosition::Left => x + THRESHOLD < alloc.width() as f64,
|
||||
BarPosition::Left => x + THRESHOLD < f64::from(alloc.width()),
|
||||
BarPosition::Right => x > THRESHOLD,
|
||||
};
|
||||
|
||||
|
@ -283,7 +284,7 @@ impl ItemButton {
|
|||
try_send!(tx, ModuleUpdateEvent::ClosePopup);
|
||||
}
|
||||
|
||||
Inhibit(false)
|
||||
Propagation::Proceed
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -10,17 +10,15 @@ use crate::modules::launcher::item::AppearanceOptions;
|
|||
use crate::modules::{
|
||||
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext,
|
||||
};
|
||||
use crate::{arc_mut, lock, send_async, try_send, write_lock};
|
||||
use crate::{arc_mut, glib_recv, lock, send_async, spawn, try_send, write_lock};
|
||||
use color_eyre::{Help, Report};
|
||||
use glib::Continue;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Button, Orientation};
|
||||
use indexmap::IndexMap;
|
||||
use serde::Deserialize;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::Arc;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
use tracing::{debug, error, trace};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
|
@ -92,8 +90,8 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
fn spawn_controller(
|
||||
&self,
|
||||
_info: &ModuleInfo,
|
||||
tx: Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
mut rx: Receiver<Self::ReceiveMessage>,
|
||||
tx: mpsc::Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
mut rx: mpsc::Receiver<Self::ReceiveMessage>,
|
||||
) -> crate::Result<()> {
|
||||
let items = self
|
||||
.favorites
|
||||
|
@ -338,7 +336,9 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
|
||||
let mut buttons = IndexMap::<String, ItemButton>::new();
|
||||
|
||||
context.widget_rx.attach(None, move |event| {
|
||||
let tx = context.tx.clone();
|
||||
let mut rx = context.subscribe();
|
||||
glib_recv!(rx, event => {
|
||||
match event {
|
||||
LauncherUpdate::AddItem(item) => {
|
||||
debug!("Adding item with id {}", item.app_id);
|
||||
|
@ -351,7 +351,7 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
appearance_options,
|
||||
&icon_theme,
|
||||
bar_position,
|
||||
&context.tx,
|
||||
&tx,
|
||||
&controller_tx,
|
||||
);
|
||||
|
||||
|
@ -411,13 +411,12 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
}
|
||||
LauncherUpdate::Hover(_) => {}
|
||||
};
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
let rx = context.subscribe();
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup(context.controller_tx, rx, info)
|
||||
.into_popup_parts(vec![]); // since item buttons are dynamic, they pass their geometry directly
|
||||
|
||||
Ok(ModuleParts {
|
||||
|
@ -428,8 +427,8 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
|
||||
fn into_popup(
|
||||
self,
|
||||
controller_tx: Sender<Self::ReceiveMessage>,
|
||||
rx: glib::Receiver<Self::SendMessage>,
|
||||
controller_tx: mpsc::Sender<Self::ReceiveMessage>,
|
||||
mut rx: broadcast::Receiver<Self::SendMessage>,
|
||||
_info: &ModuleInfo,
|
||||
) -> Option<gtk::Box> {
|
||||
const MAX_WIDTH: i32 = 250;
|
||||
|
@ -445,7 +444,7 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
|
||||
{
|
||||
let container = container.clone();
|
||||
rx.attach(None, move |event| {
|
||||
glib_recv!(rx, event => {
|
||||
match event {
|
||||
LauncherUpdate::AddItem(item) => {
|
||||
let app_id = item.app_id.clone();
|
||||
|
@ -532,8 +531,6 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::cell::RefCell;
|
||||
use std::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
|
||||
use color_eyre::Result;
|
||||
|
@ -6,14 +7,13 @@ use glib::IsA;
|
|||
use gtk::gdk::{EventMask, Monitor};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Application, Button, EventBox, IconTheme, Orientation, Revealer, Widget};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::bridge_channel::BridgeChannel;
|
||||
use crate::config::{BarPosition, CommonConfig, TransitionType};
|
||||
use crate::gtk_helpers::{IronbarGtkExt, WidgetGeometry};
|
||||
use crate::popup::Popup;
|
||||
use crate::send;
|
||||
use crate::{glib_recv_mpsc, send};
|
||||
|
||||
#[cfg(feature = "clipboard")]
|
||||
pub mod clipboard;
|
||||
|
@ -56,8 +56,8 @@ pub struct ModuleInfo<'a> {
|
|||
pub icon_theme: &'a IconTheme,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ModuleUpdateEvent<T> {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ModuleUpdateEvent<T: Clone> {
|
||||
/// Sends an update to the module UI.
|
||||
Update(T),
|
||||
/// Toggles the open state of the popup.
|
||||
|
@ -71,12 +71,25 @@ pub enum ModuleUpdateEvent<T> {
|
|||
ClosePopup,
|
||||
}
|
||||
|
||||
pub struct WidgetContext<TSend, TReceive> {
|
||||
pub struct WidgetContext<TSend, TReceive>
|
||||
where
|
||||
TSend: Clone,
|
||||
{
|
||||
pub id: usize,
|
||||
pub tx: mpsc::Sender<ModuleUpdateEvent<TSend>>,
|
||||
pub update_tx: broadcast::Sender<TSend>,
|
||||
pub controller_tx: mpsc::Sender<TReceive>,
|
||||
pub widget_rx: glib::Receiver<TSend>,
|
||||
pub popup_rx: glib::Receiver<TSend>,
|
||||
|
||||
_update_rx: broadcast::Receiver<TSend>,
|
||||
}
|
||||
|
||||
impl<TSend, TReceive> WidgetContext<TSend, TReceive>
|
||||
where
|
||||
TSend: Clone,
|
||||
{
|
||||
pub fn subscribe(&self) -> broadcast::Receiver<TSend> {
|
||||
self.update_tx.subscribe()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ModuleParts<W: IsA<Widget>> {
|
||||
|
@ -151,18 +164,22 @@ where
|
|||
info: &ModuleInfo,
|
||||
tx: mpsc::Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
rx: mpsc::Receiver<Self::ReceiveMessage>,
|
||||
) -> Result<()>;
|
||||
) -> Result<()>
|
||||
where
|
||||
<Self as Module<W>>::SendMessage: Clone;
|
||||
|
||||
fn into_widget(
|
||||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Result<ModuleParts<W>>;
|
||||
) -> Result<ModuleParts<W>>
|
||||
where
|
||||
<Self as Module<W>>::SendMessage: Clone;
|
||||
|
||||
fn into_popup(
|
||||
self,
|
||||
_tx: mpsc::Sender<Self::ReceiveMessage>,
|
||||
_rx: glib::Receiver<Self::SendMessage>,
|
||||
_rx: broadcast::Receiver<Self::SendMessage>,
|
||||
_info: &ModuleInfo,
|
||||
) -> Option<gtk::Box>
|
||||
where
|
||||
|
@ -184,22 +201,21 @@ pub fn create_module<TModule, TWidget, TSend, TRec>(
|
|||
where
|
||||
TModule: Module<TWidget, SendMessage = TSend, ReceiveMessage = TRec>,
|
||||
TWidget: IsA<Widget>,
|
||||
TSend: Clone + Send + 'static,
|
||||
TSend: Debug + Clone + Send + 'static,
|
||||
{
|
||||
let (w_tx, w_rx) = glib::MainContext::channel::<TSend>(glib::PRIORITY_DEFAULT);
|
||||
let (p_tx, p_rx) = glib::MainContext::channel::<TSend>(glib::PRIORITY_DEFAULT);
|
||||
let (ui_tx, ui_rx) = mpsc::channel::<ModuleUpdateEvent<TSend>>(64);
|
||||
let (controller_tx, controller_rx) = mpsc::channel::<TRec>(64);
|
||||
|
||||
let channel = BridgeChannel::<ModuleUpdateEvent<TSend>>::new();
|
||||
let (ui_tx, ui_rx) = mpsc::channel::<TRec>(16);
|
||||
let (tx, rx) = broadcast::channel(64);
|
||||
|
||||
module.spawn_controller(info, channel.create_sender(), ui_rx)?;
|
||||
module.spawn_controller(info, ui_tx.clone(), controller_rx)?;
|
||||
|
||||
let context = WidgetContext {
|
||||
id,
|
||||
widget_rx: w_rx,
|
||||
popup_rx: p_rx,
|
||||
tx: channel.create_sender(),
|
||||
controller_tx: ui_tx,
|
||||
tx: ui_tx,
|
||||
update_tx: tx.clone(),
|
||||
controller_tx,
|
||||
_update_rx: rx,
|
||||
};
|
||||
|
||||
let module_name = TModule::name();
|
||||
|
@ -209,27 +225,16 @@ where
|
|||
module_parts.widget.add_class("widget");
|
||||
module_parts.widget.add_class(module_name);
|
||||
|
||||
let has_popup = if let Some(popup_content) = module_parts.popup.clone() {
|
||||
if let Some(popup_content) = module_parts.popup.clone() {
|
||||
popup_content
|
||||
.container
|
||||
.style_context()
|
||||
.add_class(&format!("popup-{module_name}"));
|
||||
|
||||
register_popup_content(popup, id, instance_name, popup_content);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
setup_receiver(
|
||||
channel,
|
||||
w_tx,
|
||||
p_tx,
|
||||
popup.clone(),
|
||||
module_name,
|
||||
id,
|
||||
has_popup,
|
||||
);
|
||||
setup_receiver(tx, ui_rx, popup.clone(), module_name, id);
|
||||
|
||||
Ok(module_parts)
|
||||
}
|
||||
|
@ -250,28 +255,22 @@ fn register_popup_content(
|
|||
/// Handles opening/closing popups
|
||||
/// and communicating update messages between controllers and widgets/popups.
|
||||
fn setup_receiver<TSend>(
|
||||
channel: BridgeChannel<ModuleUpdateEvent<TSend>>,
|
||||
w_tx: glib::Sender<TSend>,
|
||||
p_tx: glib::Sender<TSend>,
|
||||
tx: broadcast::Sender<TSend>,
|
||||
mut rx: mpsc::Receiver<ModuleUpdateEvent<TSend>>,
|
||||
popup: Rc<RefCell<Popup>>,
|
||||
name: &'static str,
|
||||
id: usize,
|
||||
has_popup: bool,
|
||||
) where
|
||||
TSend: Clone + Send + 'static,
|
||||
TSend: Debug + Clone + Send + 'static,
|
||||
{
|
||||
// some rare cases can cause the popup to incorrectly calculate its size on first open.
|
||||
// we can fix that by just force re-rendering it on its first open.
|
||||
let mut has_popup_opened = false;
|
||||
|
||||
channel.recv(move |ev| {
|
||||
glib_recv_mpsc!(rx, ev => {
|
||||
match ev {
|
||||
ModuleUpdateEvent::Update(update) => {
|
||||
if has_popup {
|
||||
send!(p_tx, update.clone());
|
||||
}
|
||||
|
||||
send!(w_tx, update);
|
||||
send!(tx, update);
|
||||
}
|
||||
ModuleUpdateEvent::TogglePopup(button_id) => {
|
||||
debug!("Toggling popup for {} [#{}]", name, id);
|
||||
|
@ -321,8 +320,6 @@ fn setup_receiver<TSend>(
|
|||
popup.hide();
|
||||
}
|
||||
}
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,11 @@ use std::sync::Arc;
|
|||
use std::time::Duration;
|
||||
|
||||
use color_eyre::Result;
|
||||
use glib::{Continue, PropertySet};
|
||||
use glib::{Propagation, PropertySet};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Button, IconTheme, Label, Orientation, Scale};
|
||||
use regex::Regex;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
use tracing::error;
|
||||
|
||||
use crate::clients::music::{
|
||||
|
@ -21,7 +20,7 @@ use crate::modules::PopupButton;
|
|||
use crate::modules::{
|
||||
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext,
|
||||
};
|
||||
use crate::{send_async, try_send};
|
||||
use crate::{glib_recv, send_async, spawn, try_send};
|
||||
|
||||
pub use self::config::MusicModule;
|
||||
use self::config::PlayerType;
|
||||
|
@ -91,8 +90,8 @@ impl Module<Button> for MusicModule {
|
|||
fn spawn_controller(
|
||||
&self,
|
||||
_info: &ModuleInfo,
|
||||
tx: Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
mut rx: Receiver<Self::ReceiveMessage>,
|
||||
tx: mpsc::Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
mut rx: mpsc::Receiver<Self::ReceiveMessage>,
|
||||
) -> Result<()> {
|
||||
let format = self.format.clone();
|
||||
|
||||
|
@ -213,11 +212,13 @@ impl Module<Button> for MusicModule {
|
|||
|
||||
{
|
||||
let button = button.clone();
|
||||
let tx = context.tx.clone();
|
||||
|
||||
context.widget_rx.attach(None, move |event| {
|
||||
let tx = context.tx.clone();
|
||||
let mut rx = context.subscribe();
|
||||
|
||||
glib_recv!(rx, event => {
|
||||
let ControllerEvent::Update(mut event) = event else {
|
||||
return Continue(true);
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Some(event) = event.take() {
|
||||
|
@ -248,13 +249,12 @@ impl Module<Button> for MusicModule {
|
|||
button.hide();
|
||||
try_send!(tx, ModuleUpdateEvent::ClosePopup);
|
||||
}
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
};
|
||||
|
||||
let rx = context.subscribe();
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup(context.controller_tx, rx, info)
|
||||
.into_popup_parts(vec![&button]);
|
||||
|
||||
Ok(ModuleParts::new(button, popup))
|
||||
|
@ -262,8 +262,8 @@ impl Module<Button> for MusicModule {
|
|||
|
||||
fn into_popup(
|
||||
self,
|
||||
tx: Sender<Self::ReceiveMessage>,
|
||||
rx: glib::Receiver<Self::SendMessage>,
|
||||
tx: mpsc::Sender<Self::ReceiveMessage>,
|
||||
mut rx: broadcast::Receiver<Self::SendMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Option<gtk::Box> {
|
||||
let icon_theme = info.icon_theme;
|
||||
|
@ -355,7 +355,7 @@ impl Module<Button> for MusicModule {
|
|||
let tx_vol = tx.clone();
|
||||
volume_slider.connect_change_value(move |_, _, val| {
|
||||
try_send!(tx_vol, PlayerCommand::Volume(val as u8));
|
||||
Inhibit(false)
|
||||
Propagation::Proceed
|
||||
});
|
||||
|
||||
let progress_box = gtk::Box::new(Orientation::Horizontal, 5);
|
||||
|
@ -380,7 +380,7 @@ impl Module<Button> for MusicModule {
|
|||
let drag_lock = drag_lock.clone();
|
||||
progress.connect_button_press_event(move |_, _| {
|
||||
drag_lock.set(true);
|
||||
Inhibit(false)
|
||||
Propagation::Proceed
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -391,7 +391,7 @@ impl Module<Button> for MusicModule {
|
|||
try_send!(tx, PlayerCommand::Seek(Duration::from_secs_f64(value)));
|
||||
|
||||
drag_lock.set(false);
|
||||
Inhibit(false)
|
||||
Propagation::Proceed
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -402,7 +402,7 @@ impl Module<Button> for MusicModule {
|
|||
let image_size = self.cover_image_size;
|
||||
|
||||
let mut prev_cover = None;
|
||||
rx.attach(None, move |event| {
|
||||
glib_recv!(rx, event => {
|
||||
match event {
|
||||
ControllerEvent::Update(Some(update)) => {
|
||||
// only update art when album changes
|
||||
|
@ -460,7 +460,7 @@ impl Module<Button> for MusicModule {
|
|||
btn_next.set_sensitive(enable_next);
|
||||
|
||||
if let Some(volume) = update.status.volume_percent {
|
||||
volume_slider.set_value(volume as f64);
|
||||
volume_slider.set_value(f64::from(volume));
|
||||
volume_box.show();
|
||||
} else {
|
||||
volume_box.hide();
|
||||
|
@ -487,8 +487,6 @@ impl Module<Button> for MusicModule {
|
|||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use crate::config::CommonConfig;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::script::{OutputStream, Script, ScriptMode};
|
||||
use crate::try_send;
|
||||
use crate::{glib_recv, spawn, try_send};
|
||||
use color_eyre::{Help, Report, Result};
|
||||
use gtk::prelude::*;
|
||||
use gtk::Label;
|
||||
use serde::Deserialize;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tracing::error;
|
||||
|
||||
|
@ -89,10 +88,7 @@ impl Module<Label> for ScriptModule {
|
|||
|
||||
{
|
||||
let label = label.clone();
|
||||
context.widget_rx.attach(None, move |s| {
|
||||
label.set_markup(s.as_str());
|
||||
Continue(true)
|
||||
});
|
||||
glib_recv!(context.subscribe(), s => label.set_markup(s.as_str()));
|
||||
}
|
||||
|
||||
Ok(ModuleParts {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::config::CommonConfig;
|
||||
use crate::gtk_helpers::IronbarGtkExt;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::send_async;
|
||||
use crate::{glib_recv, send_async, spawn};
|
||||
use color_eyre::Result;
|
||||
use gtk::prelude::*;
|
||||
use gtk::Label;
|
||||
|
@ -10,7 +10,6 @@ use serde::Deserialize;
|
|||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use sysinfo::{ComponentExt, CpuExt, DiskExt, NetworkExt, RefreshKind, System, SystemExt};
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tokio::time::sleep;
|
||||
|
@ -205,7 +204,7 @@ impl Module<gtk::Box> for SysInfoModule {
|
|||
|
||||
{
|
||||
let formats = self.format;
|
||||
context.widget_rx.attach(None, move |info| {
|
||||
glib_recv!(context.subscribe(), info => {
|
||||
for (format, label) in formats.iter().zip(labels.clone()) {
|
||||
let format_compiled = re.replace_all(format, |caps: &Captures| {
|
||||
info.get(&caps[1])
|
||||
|
@ -215,8 +214,6 @@ impl Module<gtk::Box> for SysInfoModule {
|
|||
|
||||
label.set_markup(format_compiled.as_ref());
|
||||
}
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::clients::system_tray::get_tray_event_client;
|
||||
use crate::config::CommonConfig;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::{await_sync, try_send};
|
||||
use crate::{await_sync, glib_recv, spawn, try_send};
|
||||
use color_eyre::Result;
|
||||
use glib::ffi::g_strfreev;
|
||||
use glib::translate::ToGlibPtr;
|
||||
|
@ -20,7 +20,6 @@ use std::ptr;
|
|||
use system_tray::message::menu::{MenuItem as MenuItemInfo, MenuType};
|
||||
use system_tray::message::tray::StatusNotifierItem;
|
||||
use system_tray::message::{NotifierItemCommand, NotifierItemMessage};
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
|
||||
|
@ -58,9 +57,9 @@ fn get_icon_theme_search_paths(icon_theme: &IconTheme) -> HashSet<String> {
|
|||
|
||||
/// Attempts to get a GTK `Image` component
|
||||
/// for the status notifier item's icon.
|
||||
fn get_image_from_icon_name(item: &StatusNotifierItem, icon_theme: IconTheme) -> Option<Image> {
|
||||
fn get_image_from_icon_name(item: &StatusNotifierItem, icon_theme: &IconTheme) -> Option<Image> {
|
||||
if let Some(path) = item.icon_theme_path.as_ref() {
|
||||
if !path.is_empty() && !get_icon_theme_search_paths(&icon_theme).contains(path) {
|
||||
if !path.is_empty() && !get_icon_theme_search_paths(icon_theme).contains(path) {
|
||||
icon_theme.append_search_path(path);
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +208,7 @@ impl Module<MenuBar> for TrayModule {
|
|||
let icon_theme = info.icon_theme.clone();
|
||||
|
||||
// listen for UI updates
|
||||
context.widget_rx.attach(None, move |update| {
|
||||
glib_recv!(context.subscribe(), update => {
|
||||
match update {
|
||||
NotifierItemMessage::Update {
|
||||
item,
|
||||
|
@ -221,7 +220,7 @@ impl Module<MenuBar> for TrayModule {
|
|||
let menu_item = MenuItem::new();
|
||||
menu_item.style_context().add_class("item");
|
||||
|
||||
get_image_from_icon_name(&item, icon_theme.clone())
|
||||
get_image_from_icon_name(&item, &icon_theme)
|
||||
.or_else(|| get_image_from_pixmap(&item))
|
||||
.map_or_else(
|
||||
|| {
|
||||
|
@ -262,8 +261,6 @@ impl Module<MenuBar> for TrayModule {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@ use futures_lite::stream::StreamExt;
|
|||
use gtk::{prelude::*, Button};
|
||||
use gtk::{Label, Orientation};
|
||||
use serde::Deserialize;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
use upower_dbus::BatteryState;
|
||||
use zbus;
|
||||
|
||||
|
@ -16,7 +15,7 @@ use crate::modules::PopupButton;
|
|||
use crate::modules::{
|
||||
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext,
|
||||
};
|
||||
use crate::{await_sync, error, send_async, try_send};
|
||||
use crate::{await_sync, error, glib_recv, send_async, spawn, try_send};
|
||||
|
||||
const DAY: i64 = 24 * 60 * 60;
|
||||
const HOUR: i64 = 60 * 60;
|
||||
|
@ -62,8 +61,8 @@ impl Module<gtk::Button> for UpowerModule {
|
|||
fn spawn_controller(
|
||||
&self,
|
||||
_info: &ModuleInfo,
|
||||
tx: Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
_rx: Receiver<Self::ReceiveMessage>,
|
||||
tx: mpsc::Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
||||
_rx: mpsc::Receiver<Self::ReceiveMessage>,
|
||||
) -> Result<()> {
|
||||
spawn(async move {
|
||||
// await_sync due to strange "higher-ranked lifetime error"
|
||||
|
@ -174,29 +173,28 @@ impl Module<gtk::Button> for UpowerModule {
|
|||
container.add(&label);
|
||||
button.add(&container);
|
||||
|
||||
let tx = context.tx.clone();
|
||||
button.connect_clicked(move |button| {
|
||||
try_send!(
|
||||
context.tx,
|
||||
ModuleUpdateEvent::TogglePopup(button.popup_id())
|
||||
);
|
||||
try_send!(tx, ModuleUpdateEvent::TogglePopup(button.popup_id()));
|
||||
});
|
||||
|
||||
label.set_angle(info.bar_position.get_angle());
|
||||
let format = self.format.clone();
|
||||
|
||||
context
|
||||
.widget_rx
|
||||
.attach(None, move |properties: UpowerProperties| {
|
||||
let format = format.replace("{percentage}", &properties.percentage.to_string());
|
||||
let icon_name = String::from("icon:") + &properties.icon_name;
|
||||
ImageProvider::parse(&icon_name, &icon_theme, false, self.icon_size)
|
||||
.map(|provider| provider.load_into_image(icon.clone()));
|
||||
label.set_markup(format.as_ref());
|
||||
Continue(true)
|
||||
});
|
||||
let mut rx = context.subscribe();
|
||||
glib_recv!(rx, properties => {
|
||||
let format = format.replace("{percentage}", &properties.percentage.to_string());
|
||||
let icon_name = String::from("icon:") + &properties.icon_name;
|
||||
|
||||
ImageProvider::parse(&icon_name, &icon_theme, false, self.icon_size)
|
||||
.map(|provider| provider.load_into_image(icon.clone()));
|
||||
|
||||
label.set_markup(format.as_ref());
|
||||
});
|
||||
|
||||
let rx = context.subscribe();
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup(context.controller_tx, rx, info)
|
||||
.into_popup_parts(vec![&button]);
|
||||
|
||||
Ok(ModuleParts::new(button, popup))
|
||||
|
@ -204,8 +202,8 @@ impl Module<gtk::Button> for UpowerModule {
|
|||
|
||||
fn into_popup(
|
||||
self,
|
||||
_tx: Sender<Self::ReceiveMessage>,
|
||||
rx: glib::Receiver<Self::SendMessage>,
|
||||
_tx: mpsc::Sender<Self::ReceiveMessage>,
|
||||
mut rx: broadcast::Receiver<Self::SendMessage>,
|
||||
_info: &ModuleInfo,
|
||||
) -> Option<gtk::Box>
|
||||
where
|
||||
|
@ -219,7 +217,7 @@ impl Module<gtk::Button> for UpowerModule {
|
|||
label.add_class("upower-details");
|
||||
container.add(&label);
|
||||
|
||||
rx.attach(None, move |properties| {
|
||||
glib_recv!(rx, properties => {
|
||||
let state = u32_to_battery_state(properties.state);
|
||||
let format = match state {
|
||||
Ok(BatteryState::Charging | BatteryState::PendingCharge) => {
|
||||
|
@ -246,7 +244,6 @@ impl Module<gtk::Button> for UpowerModule {
|
|||
};
|
||||
|
||||
label.set_markup(&format);
|
||||
Continue(true)
|
||||
});
|
||||
|
||||
container.show_all();
|
||||
|
|
|
@ -2,14 +2,13 @@ use crate::clients::compositor::{Compositor, Visibility, Workspace, WorkspaceUpd
|
|||
use crate::config::CommonConfig;
|
||||
use crate::image::new_icon_button;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::{send_async, try_send};
|
||||
use crate::{glib_recv, send_async, spawn, try_send};
|
||||
use color_eyre::{Report, Result};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Button, IconTheme};
|
||||
use serde::Deserialize;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tracing::trace;
|
||||
|
||||
|
@ -205,7 +204,7 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
// since it fires for every workspace subscriber
|
||||
let mut has_initialized = false;
|
||||
|
||||
context.widget_rx.attach(None, move |event| {
|
||||
glib_recv!(context.subscribe(), event => {
|
||||
match event {
|
||||
WorkspaceUpdate::Init(workspaces) => {
|
||||
if !has_initialized {
|
||||
|
@ -350,8 +349,6 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
}
|
||||
WorkspaceUpdate::Update(_) => {}
|
||||
};
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
44
src/popup.rs
44
src/popup.rs
|
@ -1,8 +1,10 @@
|
|||
use glib::Propagation;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use gtk::gdk::Monitor;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{ApplicationWindow, Orientation};
|
||||
use gtk_layer_shell::LayerShell;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::config::BarPosition;
|
||||
|
@ -37,52 +39,38 @@ impl Popup {
|
|||
.application(module_info.app)
|
||||
.build();
|
||||
|
||||
gtk_layer_shell::init_for_window(&win);
|
||||
gtk_layer_shell::set_monitor(&win, module_info.monitor);
|
||||
gtk_layer_shell::set_layer(&win, gtk_layer_shell::Layer::Overlay);
|
||||
gtk_layer_shell::set_namespace(&win, env!("CARGO_PKG_NAME"));
|
||||
win.init_layer_shell();
|
||||
win.set_monitor(module_info.monitor);
|
||||
win.set_layer(gtk_layer_shell::Layer::Overlay);
|
||||
win.set_namespace(env!("CARGO_PKG_NAME"));
|
||||
|
||||
gtk_layer_shell::set_margin(
|
||||
&win,
|
||||
win.set_layer_shell_margin(
|
||||
gtk_layer_shell::Edge::Top,
|
||||
if pos == BarPosition::Top { gap } else { 0 },
|
||||
);
|
||||
gtk_layer_shell::set_margin(
|
||||
&win,
|
||||
win.set_layer_shell_margin(
|
||||
gtk_layer_shell::Edge::Bottom,
|
||||
if pos == BarPosition::Bottom { gap } else { 0 },
|
||||
);
|
||||
gtk_layer_shell::set_margin(
|
||||
&win,
|
||||
win.set_layer_shell_margin(
|
||||
gtk_layer_shell::Edge::Left,
|
||||
if pos == BarPosition::Left { gap } else { 0 },
|
||||
);
|
||||
gtk_layer_shell::set_margin(
|
||||
&win,
|
||||
win.set_layer_shell_margin(
|
||||
gtk_layer_shell::Edge::Right,
|
||||
if pos == BarPosition::Right { gap } else { 0 },
|
||||
);
|
||||
|
||||
gtk_layer_shell::set_anchor(
|
||||
&win,
|
||||
win.set_anchor(
|
||||
gtk_layer_shell::Edge::Top,
|
||||
pos == BarPosition::Top || orientation == Orientation::Vertical,
|
||||
);
|
||||
gtk_layer_shell::set_anchor(
|
||||
&win,
|
||||
gtk_layer_shell::Edge::Bottom,
|
||||
pos == BarPosition::Bottom,
|
||||
);
|
||||
gtk_layer_shell::set_anchor(
|
||||
&win,
|
||||
win.set_anchor(gtk_layer_shell::Edge::Bottom, pos == BarPosition::Bottom);
|
||||
win.set_anchor(
|
||||
gtk_layer_shell::Edge::Left,
|
||||
pos == BarPosition::Left || orientation == Orientation::Horizontal,
|
||||
);
|
||||
gtk_layer_shell::set_anchor(
|
||||
&win,
|
||||
gtk_layer_shell::Edge::Right,
|
||||
pos == BarPosition::Right,
|
||||
);
|
||||
win.set_anchor(gtk_layer_shell::Edge::Right, pos == BarPosition::Right);
|
||||
|
||||
win.connect_leave_notify_event(move |win, ev| {
|
||||
const THRESHOLD: f64 = 3.0;
|
||||
|
@ -111,7 +99,7 @@ impl Popup {
|
|||
win.hide();
|
||||
}
|
||||
|
||||
Inhibit(false)
|
||||
Propagation::Proceed
|
||||
});
|
||||
|
||||
Self {
|
||||
|
@ -229,6 +217,6 @@ impl Popup {
|
|||
gtk_layer_shell::Edge::Top
|
||||
};
|
||||
|
||||
gtk_layer_shell::set_margin(&self.window, edge, offset as i32);
|
||||
self.window.set_layer_shell_margin(edge, offset as i32);
|
||||
}
|
||||
}
|
||||
|
|
34
src/style.rs
34
src/style.rs
|
@ -1,6 +1,5 @@
|
|||
use crate::send;
|
||||
use crate::{glib_recv_mpsc, spawn, try_send};
|
||||
use color_eyre::{Help, Report};
|
||||
use glib::Continue;
|
||||
use gtk::ffi::GTK_STYLE_PROVIDER_PRIORITY_USER;
|
||||
use gtk::prelude::CssProviderExt;
|
||||
use gtk::{gdk, gio, CssProvider, StyleContext};
|
||||
|
@ -8,7 +7,7 @@ use notify::event::ModifyKind;
|
|||
use notify::{recommended_watcher, Event, EventKind, RecursiveMode, Result, Watcher};
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::time::sleep;
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
|
@ -36,7 +35,7 @@ pub fn load_css(style_path: PathBuf) {
|
|||
GTK_STYLE_PROVIDER_PRIORITY_USER as u32,
|
||||
);
|
||||
|
||||
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||
let (tx, mut rx) = mpsc::channel(8);
|
||||
|
||||
spawn(async move {
|
||||
let style_path2 = style_path.clone();
|
||||
|
@ -49,7 +48,7 @@ pub fn load_css(style_path: PathBuf) {
|
|||
.map(|p| p == &style_path2)
|
||||
.unwrap_or_default()
|
||||
{
|
||||
send!(tx, style_path2.clone());
|
||||
try_send!(tx, style_path2.clone());
|
||||
}
|
||||
}
|
||||
Err(e) => error!("Error occurred when watching stylesheet: {:?}", e),
|
||||
|
@ -70,19 +69,14 @@ pub fn load_css(style_path: PathBuf) {
|
|||
}
|
||||
});
|
||||
|
||||
{
|
||||
rx.attach(None, move |path| {
|
||||
info!("Reloading CSS");
|
||||
if let Err(err) = provider
|
||||
.load_from_file(&gio::File::for_path(path)) {
|
||||
error!("{:?}", Report::new(err)
|
||||
.wrap_err("Failed to load CSS")
|
||||
.suggestion("Check the CSS file for errors")
|
||||
.suggestion("GTK CSS uses a subset of the full CSS spec and many properties are not available. Ensure you are not using any unsupported property.")
|
||||
);
|
||||
}
|
||||
|
||||
Continue(true)
|
||||
});
|
||||
}
|
||||
glib_recv_mpsc!(rx, path => {
|
||||
info!("Reloading CSS");
|
||||
if let Err(err) = provider.load_from_file(&gio::File::for_path(path)) {
|
||||
error!("{:?}", Report::new(err)
|
||||
.wrap_err("Failed to load CSS")
|
||||
.suggestion("Check the CSS file for errors")
|
||||
.suggestion("GTK CSS uses a subset of the full CSS spec and many properties are not available. Ensure you are not using any unsupported property.")
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue