mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-08-16 22:31:03 +02:00
Merge pull request #1010 from JakeStanger/refactor/glib-deps
refactor: `recv_glib` dependency arrays
This commit is contained in:
commit
b27c601733
31 changed files with 539 additions and 517 deletions
107
src/channels.rs
107
src/channels.rs
|
@ -95,20 +95,29 @@ pub trait MpscReceiverExt<T> {
|
||||||
/// Spawns a `GLib` future on the local thread, and calls `rx.recv()`
|
/// Spawns a `GLib` future on the local thread, and calls `rx.recv()`
|
||||||
/// in a loop, passing the message to `f`.
|
/// in a loop, passing the message to `f`.
|
||||||
///
|
///
|
||||||
/// This allows use of `GObjects` and futures in the same context.
|
/// This allows use of `GObjects` and futures in the same context.#
|
||||||
fn recv_glib<F>(self, f: F)
|
///
|
||||||
|
/// `deps` is a single reference, or tuple of references of clonable objects,
|
||||||
|
/// to be consumed inside the closure.
|
||||||
|
/// This avoids needing to `element.clone()` everywhere.
|
||||||
|
fn recv_glib<D, Fn>(self, deps: D, f: Fn)
|
||||||
where
|
where
|
||||||
F: FnMut(T) + 'static;
|
D: Dependency,
|
||||||
|
D::Target: Clone + 'static,
|
||||||
|
Fn: FnMut(&D::Target, T) + 'static;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> MpscReceiverExt<T> for mpsc::Receiver<T> {
|
impl<T: 'static> MpscReceiverExt<T> for mpsc::Receiver<T> {
|
||||||
fn recv_glib<F>(mut self, mut f: F)
|
fn recv_glib<D, Fn>(mut self, deps: D, mut f: Fn)
|
||||||
where
|
where
|
||||||
F: FnMut(T) + 'static,
|
D: Dependency,
|
||||||
|
D::Target: Clone + 'static,
|
||||||
|
Fn: FnMut(&D::Target, T) + 'static,
|
||||||
{
|
{
|
||||||
|
let deps = deps.clone_content();
|
||||||
glib::spawn_future_local(async move {
|
glib::spawn_future_local(async move {
|
||||||
while let Some(val) = self.recv().await {
|
while let Some(val) = self.recv().await {
|
||||||
f(val);
|
f(&deps, val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -122,14 +131,22 @@ where
|
||||||
/// in a loop, passing the message to `f`.
|
/// in a loop, passing the message to `f`.
|
||||||
///
|
///
|
||||||
/// This allows use of `GObjects` and futures in the same context.
|
/// This allows use of `GObjects` and futures in the same context.
|
||||||
fn recv_glib<F>(self, f: F)
|
///
|
||||||
|
/// `deps` is a single reference, or tuple of references of clonable objects,
|
||||||
|
/// to be consumed inside the closure.
|
||||||
|
/// This avoids needing to `element.clone()` everywhere.
|
||||||
|
fn recv_glib<D, Fn>(self, deps: D, f: Fn)
|
||||||
where
|
where
|
||||||
F: FnMut(T) + 'static;
|
D: Dependency,
|
||||||
|
D::Target: Clone + 'static,
|
||||||
|
Fn: FnMut(&D::Target, T) + 'static;
|
||||||
|
|
||||||
/// Like [`BroadcastReceiverExt::recv_glib`], but the closure must return a [`Future`].
|
/// Like [`BroadcastReceiverExt::recv_glib`], but the closure must return a [`Future`].
|
||||||
fn recv_glib_async<Fn, F>(self, f: Fn)
|
fn recv_glib_async<D, Fn, F>(self, deps: D, f: Fn)
|
||||||
where
|
where
|
||||||
Fn: FnMut(T) -> F + 'static,
|
D: Dependency,
|
||||||
|
D::Target: Clone + 'static,
|
||||||
|
Fn: FnMut(&D::Target, T) -> F + 'static,
|
||||||
F: Future;
|
F: Future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,14 +154,17 @@ impl<T> BroadcastReceiverExt<T> for broadcast::Receiver<T>
|
||||||
where
|
where
|
||||||
T: Debug + Clone + 'static,
|
T: Debug + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn recv_glib<F>(mut self, mut f: F)
|
fn recv_glib<D, Fn>(mut self, deps: D, mut f: Fn)
|
||||||
where
|
where
|
||||||
F: FnMut(T) + 'static,
|
D: Dependency,
|
||||||
|
D::Target: Clone + 'static,
|
||||||
|
Fn: FnMut(&D::Target, T) + 'static,
|
||||||
{
|
{
|
||||||
|
let deps = deps.clone_content();
|
||||||
glib::spawn_future_local(async move {
|
glib::spawn_future_local(async move {
|
||||||
loop {
|
loop {
|
||||||
match self.recv().await {
|
match self.recv().await {
|
||||||
Ok(val) => f(val),
|
Ok(val) => f(&deps, val),
|
||||||
Err(broadcast::error::RecvError::Lagged(count)) => {
|
Err(broadcast::error::RecvError::Lagged(count)) => {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"Channel lagged behind by {count}, this may result in unexpected or broken behaviour"
|
"Channel lagged behind by {count}, this may result in unexpected or broken behaviour"
|
||||||
|
@ -159,16 +179,19 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv_glib_async<Fn, F>(mut self, mut f: Fn)
|
fn recv_glib_async<D, Fn, F>(mut self, deps: D, mut f: Fn)
|
||||||
where
|
where
|
||||||
Fn: FnMut(T) -> F + 'static,
|
D: Dependency,
|
||||||
|
D::Target: Clone + 'static,
|
||||||
|
Fn: FnMut(&D::Target, T) -> F + 'static,
|
||||||
F: Future,
|
F: Future,
|
||||||
{
|
{
|
||||||
|
let deps = deps.clone_content();
|
||||||
glib::spawn_future_local(async move {
|
glib::spawn_future_local(async move {
|
||||||
loop {
|
loop {
|
||||||
match self.recv().await {
|
match self.recv().await {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
f(val).await;
|
f(&deps, val).await;
|
||||||
}
|
}
|
||||||
Err(broadcast::error::RecvError::Lagged(count)) => {
|
Err(broadcast::error::RecvError::Lagged(count)) => {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
|
@ -184,3 +207,55 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `recv_glib` callback dependency
|
||||||
|
/// or dependency tuple.
|
||||||
|
pub trait Dependency: Clone {
|
||||||
|
type Target;
|
||||||
|
|
||||||
|
fn clone_content(&self) -> Self::Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dependency for () {
|
||||||
|
type Target = ();
|
||||||
|
|
||||||
|
fn clone_content(&self) -> Self::Target {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Dependency for &'a T
|
||||||
|
where
|
||||||
|
T: Clone + 'a,
|
||||||
|
{
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn clone_content(&self) -> T {
|
||||||
|
T::clone(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_dependency {
|
||||||
|
($($idx:tt $t:ident),+) => {
|
||||||
|
impl<'a, $($t),+> Dependency for ($(&'a $t),+)
|
||||||
|
where
|
||||||
|
$($t: Clone + 'a),+
|
||||||
|
{
|
||||||
|
type Target = ($($t),+);
|
||||||
|
|
||||||
|
fn clone_content(&self) -> Self::Target {
|
||||||
|
($(self.$idx.clone()),+)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_dependency!(0 T1, 1 T2);
|
||||||
|
impl_dependency!(0 T1, 1 T2, 2 T3);
|
||||||
|
impl_dependency!(0 T1, 1 T2, 2 T3, 3 T4);
|
||||||
|
impl_dependency!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5);
|
||||||
|
impl_dependency!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6);
|
||||||
|
impl_dependency!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7);
|
||||||
|
impl_dependency!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8);
|
||||||
|
impl_dependency!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9);
|
||||||
|
impl_dependency!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9, 9 T10);
|
||||||
|
impl_dependency!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9, 9 T10, 10 T11);
|
||||||
|
impl_dependency!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9, 9 T10, 10 T11, 11 T12);
|
||||||
|
|
|
@ -301,8 +301,7 @@ impl CommonConfig {
|
||||||
install_oneshot!(self.on_mouse_exit, connect_leave_notify_event);
|
install_oneshot!(self.on_mouse_exit, connect_leave_notify_event);
|
||||||
|
|
||||||
if let Some(tooltip) = self.tooltip {
|
if let Some(tooltip) = self.tooltip {
|
||||||
let container = container.clone();
|
dynamic_string(&tooltip, container, move |container, string| {
|
||||||
dynamic_string(&tooltip, move |string| {
|
|
||||||
container.set_tooltip_text(Some(&string));
|
container.set_tooltip_text(Some(&string));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -314,19 +313,15 @@ impl CommonConfig {
|
||||||
container.show_all();
|
container.show_all();
|
||||||
},
|
},
|
||||||
|show_if| {
|
|show_if| {
|
||||||
|
// need to keep clone here for the notify callback
|
||||||
let container = container.clone();
|
let container = container.clone();
|
||||||
|
|
||||||
{
|
show_if.subscribe((revealer, &container), |(revealer, container), success| {
|
||||||
let revealer = revealer.clone();
|
if success {
|
||||||
let container = container.clone();
|
container.show_all();
|
||||||
|
}
|
||||||
show_if.subscribe(move |success| {
|
revealer.set_reveal_child(success);
|
||||||
if success {
|
});
|
||||||
container.show_all();
|
|
||||||
}
|
|
||||||
revealer.set_reveal_child(success);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
revealer.connect_child_revealed_notify(move |revealer| {
|
revealer.connect_child_revealed_notify(move |revealer| {
|
||||||
if !revealer.reveals_child() {
|
if !revealer.reveals_child() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#[cfg(feature = "ipc")]
|
#[cfg(feature = "ipc")]
|
||||||
use crate::Ironbar;
|
use crate::Ironbar;
|
||||||
use crate::channels::{AsyncSenderExt, MpscReceiverExt};
|
use crate::channels::{AsyncSenderExt, Dependency, MpscReceiverExt};
|
||||||
use crate::script::Script;
|
use crate::script::Script;
|
||||||
use crate::spawn;
|
use crate::spawn;
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
|
@ -19,9 +19,11 @@ pub enum DynamicBool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicBool {
|
impl DynamicBool {
|
||||||
pub fn subscribe<F>(self, f: F)
|
pub fn subscribe<D, F>(self, deps: D, f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(bool) + 'static,
|
D: Dependency,
|
||||||
|
D::Target: Clone + 'static,
|
||||||
|
F: FnMut(&D::Target, bool) + 'static,
|
||||||
{
|
{
|
||||||
let value = match self {
|
let value = match self {
|
||||||
Self::Unknown(input) => {
|
Self::Unknown(input) => {
|
||||||
|
@ -43,7 +45,7 @@ impl DynamicBool {
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel(32);
|
let (tx, rx) = mpsc::channel(32);
|
||||||
|
|
||||||
rx.recv_glib(f);
|
rx.recv_glib(deps, f);
|
||||||
|
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
match value {
|
match value {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#[cfg(feature = "ipc")]
|
#[cfg(feature = "ipc")]
|
||||||
use crate::Ironbar;
|
use crate::Ironbar;
|
||||||
use crate::channels::{AsyncSenderExt, MpscReceiverExt};
|
use crate::channels::{AsyncSenderExt, Dependency, MpscReceiverExt};
|
||||||
use crate::script::{OutputStream, Script};
|
use crate::script::{OutputStream, Script};
|
||||||
use crate::{arc_mut, lock, spawn};
|
use crate::{arc_mut, lock, spawn};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
@ -26,9 +26,11 @@ enum DynamicStringSegment {
|
||||||
/// label.set_label_escaped(&string);
|
/// label.set_label_escaped(&string);
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
pub fn dynamic_string<F>(input: &str, f: F)
|
pub fn dynamic_string<D, F>(input: &str, deps: D, f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(String) + 'static,
|
D: Dependency,
|
||||||
|
D::Target: Clone + 'static,
|
||||||
|
F: FnMut(&D::Target, String) + 'static,
|
||||||
{
|
{
|
||||||
let (tokens, is_static) = parse_input(input);
|
let (tokens, is_static) = parse_input(input);
|
||||||
|
|
||||||
|
@ -89,7 +91,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rx.recv_glib(f);
|
rx.recv_glib(deps, f);
|
||||||
|
|
||||||
// initialize
|
// initialize
|
||||||
if is_static {
|
if is_static {
|
||||||
|
|
|
@ -65,8 +65,7 @@ impl Ipc {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let application = application.clone();
|
cmd_rx.recv_glib(application, move |application, command| {
|
||||||
cmd_rx.recv_glib(move |command| {
|
|
||||||
let res = Self::handle_command(command, &application, &ironbar);
|
let res = Self::handle_command(command, &application, &ironbar);
|
||||||
res_tx.send_spawn(res);
|
res_tx.send_spawn(res);
|
||||||
});
|
});
|
||||||
|
|
|
@ -81,23 +81,17 @@ impl Module<Label> for Bindmode {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
context.subscribe().recv_glib(&label, |label, mode| {
|
||||||
let label = label.clone();
|
trace!("mode: {:?}", mode);
|
||||||
|
label.set_use_markup(mode.pango_markup);
|
||||||
|
label.set_label_escaped(&mode.name);
|
||||||
|
|
||||||
let on_mode = move |mode: BindModeUpdate| {
|
if mode.name.is_empty() {
|
||||||
trace!("mode: {:?}", mode);
|
label.hide();
|
||||||
label.set_use_markup(mode.pango_markup);
|
} else {
|
||||||
label.set_label_escaped(&mode.name);
|
label.show();
|
||||||
|
}
|
||||||
if mode.name.is_empty() {
|
});
|
||||||
label.hide();
|
|
||||||
} else {
|
|
||||||
label.show();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
context.subscribe().recv_glib(on_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ModuleParts {
|
Ok(ModuleParts {
|
||||||
widget: label,
|
widget: label,
|
||||||
|
|
|
@ -192,7 +192,7 @@ impl Module<gtk::Box> for CairoModule {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
context.subscribe().recv_glib(move |_ev| {
|
context.subscribe().recv_glib((), move |(), _ev| {
|
||||||
let res = fs::read_to_string(&self.path)
|
let res = fs::read_to_string(&self.path)
|
||||||
.map(|s| s.replace("function draw", format!("function __draw_{id}").as_str()));
|
.map(|s| s.replace("function draw", format!("function __draw_{id}").as_str()));
|
||||||
|
|
||||||
|
|
|
@ -184,9 +184,9 @@ impl Module<Button> for ClipboardModule {
|
||||||
|
|
||||||
let mut items = HashMap::new();
|
let mut items = HashMap::new();
|
||||||
|
|
||||||
{
|
context
|
||||||
let hidden_option = hidden_option.clone();
|
.subscribe()
|
||||||
context.subscribe().recv_glib(move |event| {
|
.recv_glib(&hidden_option, move |hidden_option, event| {
|
||||||
match event {
|
match event {
|
||||||
ControllerEvent::Add(id, item) => {
|
ControllerEvent::Add(id, item) => {
|
||||||
debug!("Adding new value with ID {}", id);
|
debug!("Adding new value with ID {}", id);
|
||||||
|
@ -196,7 +196,7 @@ impl Module<Button> for ClipboardModule {
|
||||||
|
|
||||||
let button = match item.value.as_ref() {
|
let button = match item.value.as_ref() {
|
||||||
ClipboardValue::Text(value) => {
|
ClipboardValue::Text(value) => {
|
||||||
let button = RadioButton::from_widget(&hidden_option);
|
let button = RadioButton::from_widget(hidden_option);
|
||||||
|
|
||||||
let label = Label::new(Some(value));
|
let label = Label::new(Some(value));
|
||||||
button.add(&label);
|
button.add(&label);
|
||||||
|
@ -222,7 +222,7 @@ impl Module<Button> for ClipboardModule {
|
||||||
Ok(pixbuf) => {
|
Ok(pixbuf) => {
|
||||||
let image = Image::from_pixbuf(Some(&pixbuf));
|
let image = Image::from_pixbuf(Some(&pixbuf));
|
||||||
|
|
||||||
let button = RadioButton::from_widget(&hidden_option);
|
let button = RadioButton::from_widget(hidden_option);
|
||||||
button.set_image(Some(&image));
|
button.set_image(Some(&image));
|
||||||
button.set_always_show_image(true);
|
button.set_always_show_image(true);
|
||||||
button.style_context().add_class("image");
|
button.style_context().add_class("image");
|
||||||
|
@ -320,7 +320,6 @@ impl Module<Button> for ClipboardModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
container.show_all();
|
container.show_all();
|
||||||
hidden_option.hide();
|
hidden_option.hide();
|
||||||
|
|
|
@ -139,7 +139,7 @@ impl Module<Button> for ClockModule {
|
||||||
let locale = Locale::try_from(self.locale.as_str()).unwrap_or(Locale::POSIX);
|
let locale = Locale::try_from(self.locale.as_str()).unwrap_or(Locale::POSIX);
|
||||||
|
|
||||||
let rx = context.subscribe();
|
let rx = context.subscribe();
|
||||||
rx.recv_glib(move |date| {
|
rx.recv_glib((), move |(), date| {
|
||||||
let date_string = format!("{}", date.format_localized(&format, locale));
|
let date_string = format!("{}", date.format_localized(&format, locale));
|
||||||
label.set_label(&date_string);
|
label.set_label(&date_string);
|
||||||
});
|
});
|
||||||
|
@ -173,7 +173,7 @@ impl Module<Button> for ClockModule {
|
||||||
let format = self.format_popup;
|
let format = self.format_popup;
|
||||||
let locale = Locale::try_from(self.locale.as_str()).unwrap_or(Locale::POSIX);
|
let locale = Locale::try_from(self.locale.as_str()).unwrap_or(Locale::POSIX);
|
||||||
|
|
||||||
context.subscribe().recv_glib(move |date| {
|
context.subscribe().recv_glib((), move |(), date| {
|
||||||
let date_string = format!("{}", date.format_localized(&format, locale));
|
let date_string = format!("{}", date.format_localized(&format, locale));
|
||||||
clock.set_label(&date_string);
|
clock.set_label(&date_string);
|
||||||
});
|
});
|
||||||
|
|
|
@ -73,7 +73,7 @@ impl CustomWidget for ButtonWidget {
|
||||||
|
|
||||||
button.add(&label);
|
button.add(&label);
|
||||||
|
|
||||||
dynamic_string(&text, move |string| {
|
dynamic_string(&text, (), move |(), string| {
|
||||||
label.set_label_escaped(&string);
|
label.set_label_escaped(&string);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,19 +44,15 @@ impl CustomWidget for ImageWidget {
|
||||||
fn into_widget(self, context: CustomWidgetContext) -> Self::Widget {
|
fn into_widget(self, context: CustomWidgetContext) -> Self::Widget {
|
||||||
let gtk_image = build!(self, Self::Widget);
|
let gtk_image = build!(self, Self::Widget);
|
||||||
|
|
||||||
{
|
dynamic_string(&self.src, >k_image, move |gtk_image, src| {
|
||||||
let gtk_image = gtk_image.clone();
|
let gtk_image = gtk_image.clone();
|
||||||
|
let image_provider = context.image_provider.clone();
|
||||||
dynamic_string(&self.src, move |src| {
|
glib::spawn_future_local(async move {
|
||||||
let gtk_image = gtk_image.clone();
|
image_provider
|
||||||
let image_provider = context.image_provider.clone();
|
.load_into_image_silent(&src, self.size, false, >k_image)
|
||||||
glib::spawn_future_local(async move {
|
.await;
|
||||||
image_provider
|
|
||||||
.load_into_image_silent(&src, self.size, false, >k_image)
|
|
||||||
.await;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
gtk_image
|
gtk_image
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,12 +55,9 @@ impl CustomWidget for LabelWidget {
|
||||||
label.truncate(truncate);
|
label.truncate(truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
dynamic_string(&self.label, &label, move |label, string| {
|
||||||
let label = label.clone();
|
label.set_label_escaped(&string);
|
||||||
dynamic_string(&self.label, move |string| {
|
});
|
||||||
label.set_label_escaped(&string);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
label
|
label
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,14 +95,13 @@ impl CustomWidget for ProgressWidget {
|
||||||
.await;
|
.await;
|
||||||
});
|
});
|
||||||
|
|
||||||
rx.recv_glib(move |value| progress.set_fraction(value / self.max));
|
rx.recv_glib((), move |(), value| progress.set_fraction(value / self.max));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(text) = self.label {
|
if let Some(text) = self.label {
|
||||||
let progress = progress.clone();
|
|
||||||
progress.set_show_text(true);
|
progress.set_show_text(true);
|
||||||
|
|
||||||
dynamic_string(&text, move |string| {
|
dynamic_string(&text, &progress, move |progress, string| {
|
||||||
progress.set_text(Some(&string));
|
progress.set_text(Some(&string));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,7 +165,7 @@ impl CustomWidget for SliderWidget {
|
||||||
.await;
|
.await;
|
||||||
});
|
});
|
||||||
|
|
||||||
rx.recv_glib(move |value| scale.set_value(value));
|
rx.recv_glib((), move |(), value| scale.set_value(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
scale
|
scale
|
||||||
|
|
|
@ -154,7 +154,7 @@ impl Module<gtk::Box> for FocusedModule {
|
||||||
{
|
{
|
||||||
let image_provider = context.ironbar.image_provider();
|
let image_provider = context.ironbar.image_provider();
|
||||||
|
|
||||||
context.subscribe().recv_glib_async(move |data| {
|
context.subscribe().recv_glib_async((), move |(), data| {
|
||||||
let icon = icon.clone();
|
let icon = icon.clone();
|
||||||
let label = label.clone();
|
let label = label.clone();
|
||||||
let image_provider = image_provider.clone();
|
let image_provider = image_provider.clone();
|
||||||
|
|
|
@ -305,39 +305,43 @@ impl Module<gtk::Box> for KeyboardModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
let icons = self.icons;
|
let icons = self.icons;
|
||||||
let handle_event = move |ev: KeyboardUpdate| match ev {
|
context
|
||||||
KeyboardUpdate::Key(ev) => {
|
.subscribe()
|
||||||
let parts = match (ev.key, ev.state) {
|
.recv_glib((), move |(), ev: KeyboardUpdate| match ev {
|
||||||
(Key::Caps, true) if self.show_caps => Some((&caps, icons.caps_on.as_str())),
|
KeyboardUpdate::Key(ev) => {
|
||||||
(Key::Caps, false) if self.show_caps => Some((&caps, icons.caps_off.as_str())),
|
let parts = match (ev.key, ev.state) {
|
||||||
(Key::Num, true) if self.show_num => Some((&num, icons.num_on.as_str())),
|
(Key::Caps, true) if self.show_caps => {
|
||||||
(Key::Num, false) if self.show_num => Some((&num, icons.num_off.as_str())),
|
Some((&caps, icons.caps_on.as_str()))
|
||||||
(Key::Scroll, true) if self.show_scroll => {
|
}
|
||||||
Some((&scroll, icons.scroll_on.as_str()))
|
(Key::Caps, false) if self.show_caps => {
|
||||||
}
|
Some((&caps, icons.caps_off.as_str()))
|
||||||
(Key::Scroll, false) if self.show_scroll => {
|
}
|
||||||
Some((&scroll, icons.scroll_off.as_str()))
|
(Key::Num, true) if self.show_num => Some((&num, icons.num_on.as_str())),
|
||||||
}
|
(Key::Num, false) if self.show_num => Some((&num, icons.num_off.as_str())),
|
||||||
_ => None,
|
(Key::Scroll, true) if self.show_scroll => {
|
||||||
};
|
Some((&scroll, icons.scroll_on.as_str()))
|
||||||
|
}
|
||||||
|
(Key::Scroll, false) if self.show_scroll => {
|
||||||
|
Some((&scroll, icons.scroll_off.as_str()))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
if let Some((label, input)) = parts {
|
if let Some((label, input)) = parts {
|
||||||
label.set_label(Some(input));
|
label.set_label(Some(input));
|
||||||
|
|
||||||
if ev.state {
|
if ev.state {
|
||||||
label.add_class("enabled");
|
label.add_class("enabled");
|
||||||
} else {
|
} else {
|
||||||
label.remove_class("enabled");
|
label.remove_class("enabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
KeyboardUpdate::Layout(KeyboardLayoutUpdate(language)) => {
|
||||||
KeyboardUpdate::Layout(KeyboardLayoutUpdate(language)) => {
|
let text = icons.layout_map.get(&language).unwrap_or(&language);
|
||||||
let text = icons.layout_map.get(&language).unwrap_or(&language);
|
layout_button.set_label(text);
|
||||||
layout_button.set_label(text);
|
}
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
|
||||||
context.subscribe().recv_glib(handle_event);
|
|
||||||
Ok(ModuleParts::new(container, None))
|
Ok(ModuleParts::new(container, None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,7 @@ impl Module<Label> for LabelModule {
|
||||||
context: &WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
context: &WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||||
_rx: mpsc::Receiver<Self::ReceiveMessage>,
|
_rx: mpsc::Receiver<Self::ReceiveMessage>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let tx = context.tx.clone();
|
dynamic_string(&self.label, &context.tx, move |tx, string| {
|
||||||
dynamic_string(&self.label, move |string| {
|
|
||||||
tx.send_update_spawn(string);
|
tx.send_update_spawn(string);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -79,12 +78,9 @@ impl Module<Label> for LabelModule {
|
||||||
label.truncate(truncate);
|
label.truncate(truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
context.subscribe().recv_glib(&label, move |label, string| {
|
||||||
let label = label.clone();
|
label.set_label_escaped(&string)
|
||||||
context
|
});
|
||||||
.subscribe()
|
|
||||||
.recv_glib(move |string| label.set_label_escaped(&string));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ModuleParts {
|
Ok(ModuleParts {
|
||||||
widget: label,
|
widget: label,
|
||||||
|
|
|
@ -458,10 +458,6 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
let container = container.clone();
|
|
||||||
|
|
||||||
let controller_tx = context.controller_tx.clone();
|
|
||||||
|
|
||||||
let appearance_options = AppearanceOptions {
|
let appearance_options = AppearanceOptions {
|
||||||
show_names: self.show_names,
|
show_names: self.show_names,
|
||||||
show_icons: self.show_icons,
|
show_icons: self.show_icons,
|
||||||
|
@ -477,114 +473,114 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
|
|
||||||
let mut buttons = IndexMap::<String, ItemButton>::new();
|
let mut buttons = IndexMap::<String, ItemButton>::new();
|
||||||
|
|
||||||
let tx = context.tx.clone();
|
|
||||||
let rx = context.subscribe();
|
let rx = context.subscribe();
|
||||||
|
|
||||||
let handle_event = move |event: LauncherUpdate| {
|
rx.recv_glib(
|
||||||
// all widgets show by default
|
(&container, &context.controller_tx, &context.tx),
|
||||||
// so check if pagination should be shown
|
move |(container, controller_tx, tx), event: LauncherUpdate| {
|
||||||
// to ensure correct state on init.
|
// all widgets show by default
|
||||||
if buttons.len() <= page_size {
|
// so check if pagination should be shown
|
||||||
pagination.hide();
|
// to ensure correct state on init.
|
||||||
}
|
if buttons.len() <= page_size {
|
||||||
|
pagination.hide();
|
||||||
|
}
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
LauncherUpdate::AddItem(item) => {
|
LauncherUpdate::AddItem(item) => {
|
||||||
debug!("Adding item with id '{}' to the bar: {item:?}", item.app_id);
|
debug!("Adding item with id '{}' to the bar: {item:?}", item.app_id);
|
||||||
|
|
||||||
if let Some(button) = buttons.get(&item.app_id) {
|
if let Some(button) = buttons.get(&item.app_id) {
|
||||||
button.set_open(true);
|
button.set_open(true);
|
||||||
button.set_focused(item.open_state.is_focused());
|
button.set_focused(item.open_state.is_focused());
|
||||||
} else {
|
|
||||||
let button = ItemButton::new(
|
|
||||||
&item,
|
|
||||||
appearance_options,
|
|
||||||
image_provider.clone(),
|
|
||||||
bar_position,
|
|
||||||
&tx,
|
|
||||||
&controller_tx,
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.reversed {
|
|
||||||
container.pack_end(&*button.button, false, false, 0);
|
|
||||||
} else {
|
} else {
|
||||||
container.add(&*button.button);
|
let button = ItemButton::new(
|
||||||
}
|
&item,
|
||||||
|
appearance_options,
|
||||||
|
image_provider.clone(),
|
||||||
|
bar_position,
|
||||||
|
&tx,
|
||||||
|
&controller_tx,
|
||||||
|
);
|
||||||
|
|
||||||
if buttons.len() + 1 >= pagination.offset() + page_size {
|
if self.reversed {
|
||||||
button.button.set_visible(false);
|
container.pack_end(&*button.button, false, false, 0);
|
||||||
pagination.set_sensitive_fwd(true);
|
} else {
|
||||||
}
|
container.add(&*button.button);
|
||||||
|
|
||||||
if buttons.len() + 1 > page_size {
|
|
||||||
pagination.show_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
buttons.insert(item.app_id, button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LauncherUpdate::AddWindow(app_id, win) => {
|
|
||||||
if let Some(button) = buttons.get(&app_id) {
|
|
||||||
button.set_open(true);
|
|
||||||
button.set_focused(win.open_state.is_focused());
|
|
||||||
|
|
||||||
write_lock!(button.menu_state).num_windows += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LauncherUpdate::RemoveItem(app_id) => {
|
|
||||||
debug!("Removing item with id {}", app_id);
|
|
||||||
|
|
||||||
if let Some(button) = buttons.get(&app_id) {
|
|
||||||
if button.persistent {
|
|
||||||
button.set_open(false);
|
|
||||||
if button.show_names {
|
|
||||||
button.button.label.set_label(&app_id);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
container.remove(&button.button.button);
|
if buttons.len() + 1 >= pagination.offset() + page_size {
|
||||||
buttons.shift_remove(&app_id);
|
button.button.set_visible(false);
|
||||||
|
pagination.set_sensitive_fwd(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if buttons.len() + 1 > page_size {
|
||||||
|
pagination.show_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons.insert(item.app_id, button);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LauncherUpdate::AddWindow(app_id, win) => {
|
||||||
if buttons.len() < pagination.offset() + page_size {
|
|
||||||
pagination.set_sensitive_fwd(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if buttons.len() <= page_size {
|
|
||||||
pagination.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LauncherUpdate::RemoveWindow(app_id, win_id) => {
|
|
||||||
debug!("Removing window {win_id} with id {app_id}");
|
|
||||||
|
|
||||||
if let Some(button) = buttons.get(&app_id) {
|
|
||||||
button.set_focused(false);
|
|
||||||
|
|
||||||
let mut menu_state = write_lock!(button.menu_state);
|
|
||||||
menu_state.num_windows -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LauncherUpdate::Focus(app_id, focus) => {
|
|
||||||
debug!("Changing focus to {} on item with id {}", focus, app_id);
|
|
||||||
|
|
||||||
if let Some(button) = buttons.get(&app_id) {
|
|
||||||
button.set_focused(focus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LauncherUpdate::Title(app_id, _, name) => {
|
|
||||||
debug!("Updating title for item with id {}: {:?}", app_id, name);
|
|
||||||
|
|
||||||
if show_names {
|
|
||||||
if let Some(button) = buttons.get(&app_id) {
|
if let Some(button) = buttons.get(&app_id) {
|
||||||
button.button.label.set_label(&name);
|
button.set_open(true);
|
||||||
|
button.set_focused(win.open_state.is_focused());
|
||||||
|
|
||||||
|
write_lock!(button.menu_state).num_windows += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
LauncherUpdate::RemoveItem(app_id) => {
|
||||||
LauncherUpdate::Hover(_) => {}
|
debug!("Removing item with id {}", app_id);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
rx.recv_glib(handle_event);
|
if let Some(button) = buttons.get(&app_id) {
|
||||||
|
if button.persistent {
|
||||||
|
button.set_open(false);
|
||||||
|
if button.show_names {
|
||||||
|
button.button.label.set_label(&app_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
container.remove(&button.button.button);
|
||||||
|
buttons.shift_remove(&app_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if buttons.len() < pagination.offset() + page_size {
|
||||||
|
pagination.set_sensitive_fwd(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if buttons.len() <= page_size {
|
||||||
|
pagination.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LauncherUpdate::RemoveWindow(app_id, win_id) => {
|
||||||
|
debug!("Removing window {win_id} with id {app_id}");
|
||||||
|
|
||||||
|
if let Some(button) = buttons.get(&app_id) {
|
||||||
|
button.set_focused(false);
|
||||||
|
|
||||||
|
let mut menu_state = write_lock!(button.menu_state);
|
||||||
|
menu_state.num_windows -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LauncherUpdate::Focus(app_id, focus) => {
|
||||||
|
debug!("Changing focus to {} on item with id {}", focus, app_id);
|
||||||
|
|
||||||
|
if let Some(button) = buttons.get(&app_id) {
|
||||||
|
button.set_focused(focus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LauncherUpdate::Title(app_id, _, name) => {
|
||||||
|
debug!("Updating title for item with id {}: {:?}", app_id, name);
|
||||||
|
|
||||||
|
if show_names {
|
||||||
|
if let Some(button) = buttons.get(&app_id) {
|
||||||
|
button.button.label.set_label(&name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LauncherUpdate::Hover(_) => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let popup = self.into_popup(context, info).into_popup_parts(vec![]); // since item buttons are dynamic, they pass their geometry directly
|
let popup = self.into_popup(context, info).into_popup_parts(vec![]); // since item buttons are dynamic, they pass their geometry directly
|
||||||
|
@ -611,9 +607,9 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
|
|
||||||
let mut buttons = IndexMap::<String, IndexMap<usize, ImageTextButton>>::new();
|
let mut buttons = IndexMap::<String, IndexMap<usize, ImageTextButton>>::new();
|
||||||
|
|
||||||
{
|
context
|
||||||
let container = container.clone();
|
.subscribe()
|
||||||
context.subscribe().recv_glib(move |event| {
|
.recv_glib(&container, move |container, event| {
|
||||||
match event {
|
match event {
|
||||||
LauncherUpdate::AddItem(item) => {
|
LauncherUpdate::AddItem(item) => {
|
||||||
let app_id = item.app_id.clone();
|
let app_id = item.app_id.clone();
|
||||||
|
@ -703,7 +699,6 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Some(container)
|
Some(container)
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,17 +209,18 @@ impl Module<Button> for MenuModule {
|
||||||
center_section.add_class("main-center");
|
center_section.add_class("main-center");
|
||||||
end_section.add_class("main-end");
|
end_section.add_class("main-end");
|
||||||
|
|
||||||
let container2 = container.clone();
|
let truncate_mode = self.truncate;
|
||||||
{
|
|
||||||
let main_menu = main_menu.clone();
|
|
||||||
let container = container.clone();
|
|
||||||
let start_section = start_section.clone();
|
|
||||||
let center_section = center_section.clone();
|
|
||||||
let end_section = end_section.clone();
|
|
||||||
|
|
||||||
let truncate_mode = self.truncate;
|
context.subscribe().recv_glib(
|
||||||
|
(
|
||||||
context.subscribe().recv_glib(move |applications| {
|
&main_menu,
|
||||||
|
&container,
|
||||||
|
&start_section,
|
||||||
|
¢er_section,
|
||||||
|
&end_section,
|
||||||
|
),
|
||||||
|
move |(main_menu, container, start_section, center_section, end_section),
|
||||||
|
applications| {
|
||||||
for application in applications.iter() {
|
for application in applications.iter() {
|
||||||
let mut inserted = false;
|
let mut inserted = false;
|
||||||
|
|
||||||
|
@ -288,15 +289,14 @@ impl Module<Button> for MenuModule {
|
||||||
add_entries!(¢er_entries, ¢er_section);
|
add_entries!(¢er_entries, ¢er_section);
|
||||||
add_entries!(&end_entries, &end_section);
|
add_entries!(&end_entries, &end_section);
|
||||||
|
|
||||||
main_menu.add(&start_section);
|
main_menu.add(start_section);
|
||||||
main_menu.add(¢er_section);
|
main_menu.add(center_section);
|
||||||
main_menu.add(&end_section);
|
main_menu.add(end_section);
|
||||||
});
|
},
|
||||||
}
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
let container = container2;
|
let container = container.clone();
|
||||||
|
|
||||||
context.popup.window.connect_hide(move |_| {
|
context.popup.window.connect_hide(move |_| {
|
||||||
start_section.foreach(|child| {
|
start_section.foreach(|child| {
|
||||||
child.remove_class("open");
|
child.remove_class("open");
|
||||||
|
|
|
@ -388,8 +388,7 @@ impl ModuleFactory for BarModuleFactory {
|
||||||
) where
|
) where
|
||||||
TSend: Debug + Clone + Send + 'static,
|
TSend: Debug + Clone + Send + 'static,
|
||||||
{
|
{
|
||||||
let popup = self.popup.clone();
|
rx.recv_glib(&self.popup, move |popup, ev| match ev {
|
||||||
rx.recv_glib(move |ev| match ev {
|
|
||||||
ModuleUpdateEvent::Update(update) => {
|
ModuleUpdateEvent::Update(update) => {
|
||||||
tx.send_expect(update);
|
tx.send_expect(update);
|
||||||
}
|
}
|
||||||
|
@ -464,10 +463,9 @@ impl ModuleFactory for PopupModuleFactory {
|
||||||
) where
|
) where
|
||||||
TSend: Debug + Clone + Send + 'static,
|
TSend: Debug + Clone + Send + 'static,
|
||||||
{
|
{
|
||||||
let popup = self.popup.clone();
|
|
||||||
let button_id = self.button_id;
|
let button_id = self.button_id;
|
||||||
|
|
||||||
rx.recv_glib(move |ev| match ev {
|
rx.recv_glib(&self.popup, move |popup, ev| match ev {
|
||||||
ModuleUpdateEvent::Update(update) => {
|
ModuleUpdateEvent::Update(update) => {
|
||||||
tx.send_expect(update);
|
tx.send_expect(update);
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,47 +217,42 @@ impl Module<Button> for MusicModule {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
let rx = context.subscribe();
|
||||||
let button = button.clone();
|
|
||||||
|
|
||||||
let tx = context.tx.clone();
|
rx.recv_glib((&button, &context.tx), move |(button, tx), event| {
|
||||||
let rx = context.subscribe();
|
let ControllerEvent::Update(mut event) = event else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
rx.recv_glib(move |event| {
|
if let Some(event) = event.take() {
|
||||||
let ControllerEvent::Update(mut event) = event else {
|
label.set_label_escaped(&event.display_string);
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(event) = event.take() {
|
button.show();
|
||||||
label.set_label_escaped(&event.display_string);
|
|
||||||
|
|
||||||
button.show();
|
match event.status.state {
|
||||||
|
PlayerState::Playing if self.show_status_icon => {
|
||||||
match event.status.state {
|
icon_play.show();
|
||||||
PlayerState::Playing if self.show_status_icon => {
|
|
||||||
icon_play.show();
|
|
||||||
icon_pause.hide();
|
|
||||||
}
|
|
||||||
PlayerState::Paused if self.show_status_icon => {
|
|
||||||
icon_pause.show();
|
|
||||||
icon_play.hide();
|
|
||||||
}
|
|
||||||
PlayerState::Stopped => {
|
|
||||||
button.hide();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.show_status_icon {
|
|
||||||
icon_pause.hide();
|
icon_pause.hide();
|
||||||
|
}
|
||||||
|
PlayerState::Paused if self.show_status_icon => {
|
||||||
|
icon_pause.show();
|
||||||
icon_play.hide();
|
icon_play.hide();
|
||||||
}
|
}
|
||||||
} else {
|
PlayerState::Stopped => {
|
||||||
button.hide();
|
button.hide();
|
||||||
tx.send_spawn(ModuleUpdateEvent::ClosePopup);
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
if !self.show_status_icon {
|
||||||
|
icon_pause.hide();
|
||||||
|
icon_play.hide();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
button.hide();
|
||||||
|
tx.send_spawn(ModuleUpdateEvent::ClosePopup);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let popup = self
|
let popup = self
|
||||||
.into_popup(context, info)
|
.into_popup(context, info)
|
||||||
|
@ -403,121 +398,114 @@ impl Module<Button> for MusicModule {
|
||||||
|
|
||||||
container.show_all();
|
container.show_all();
|
||||||
|
|
||||||
{
|
let image_size = self.cover_image_size;
|
||||||
let image_size = self.cover_image_size;
|
|
||||||
|
|
||||||
let mut prev_cover = None;
|
let mut prev_cover = None;
|
||||||
context.subscribe().recv_glib(move |event| {
|
context.subscribe().recv_glib((), move |(), event| {
|
||||||
match event {
|
match event {
|
||||||
ControllerEvent::Update(Some(update)) => {
|
ControllerEvent::Update(Some(update)) => {
|
||||||
// only update art when album changes
|
// only update art when album changes
|
||||||
let new_cover = update.song.cover_path;
|
let new_cover = update.song.cover_path;
|
||||||
if prev_cover != new_cover {
|
if prev_cover != new_cover {
|
||||||
prev_cover.clone_from(&new_cover);
|
prev_cover.clone_from(&new_cover);
|
||||||
|
|
||||||
if let Some(cover_path) = new_cover {
|
if let Some(cover_path) = new_cover {
|
||||||
let image_provider = image_provider.clone();
|
let image_provider = image_provider.clone();
|
||||||
let album_image = album_image.clone();
|
let album_image = album_image.clone();
|
||||||
|
|
||||||
glib::spawn_future_local(async move {
|
glib::spawn_future_local(async move {
|
||||||
let success = match image_provider
|
let success = match image_provider
|
||||||
.load_into_image(
|
.load_into_image(&cover_path, image_size, false, &album_image)
|
||||||
&cover_path,
|
.await
|
||||||
image_size,
|
{
|
||||||
false,
|
Ok(true) => {
|
||||||
&album_image,
|
album_image.show();
|
||||||
)
|
true
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(true) => {
|
|
||||||
album_image.show();
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Ok(false) => {
|
|
||||||
warn!("failed to parse image: {}", cover_path);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
error!("failed to load image: {}", err);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if !success {
|
|
||||||
album_image.set_from_pixbuf(None);
|
|
||||||
album_image.hide();
|
|
||||||
}
|
}
|
||||||
});
|
Ok(false) => {
|
||||||
} else {
|
warn!("failed to parse image: {}", cover_path);
|
||||||
album_image.set_from_pixbuf(None);
|
false
|
||||||
album_image.hide();
|
}
|
||||||
}
|
Err(err) => {
|
||||||
}
|
error!("failed to load image: {}", err);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
update_popup_metadata_label(update.song.title, &title_label);
|
if !success {
|
||||||
update_popup_metadata_label(update.song.album, &album_label);
|
album_image.set_from_pixbuf(None);
|
||||||
update_popup_metadata_label(update.song.artist, &artist_label);
|
album_image.hide();
|
||||||
|
}
|
||||||
match update.status.state {
|
});
|
||||||
PlayerState::Stopped => {
|
|
||||||
btn_pause.hide();
|
|
||||||
btn_play.show();
|
|
||||||
btn_play.set_sensitive(false);
|
|
||||||
}
|
|
||||||
PlayerState::Playing => {
|
|
||||||
btn_play.set_sensitive(false);
|
|
||||||
btn_play.hide();
|
|
||||||
|
|
||||||
btn_pause.set_sensitive(true);
|
|
||||||
btn_pause.show();
|
|
||||||
}
|
|
||||||
PlayerState::Paused => {
|
|
||||||
btn_pause.set_sensitive(false);
|
|
||||||
btn_pause.hide();
|
|
||||||
|
|
||||||
btn_play.set_sensitive(true);
|
|
||||||
btn_play.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let enable_prev = update.status.playlist_position > 0;
|
|
||||||
|
|
||||||
let enable_next =
|
|
||||||
update.status.playlist_position < update.status.playlist_length;
|
|
||||||
|
|
||||||
btn_prev.set_sensitive(enable_prev);
|
|
||||||
btn_next.set_sensitive(enable_next);
|
|
||||||
|
|
||||||
if let Some(volume) = update.status.volume_percent {
|
|
||||||
volume_slider.set_value(f64::from(volume));
|
|
||||||
volume_box.show();
|
|
||||||
} else {
|
} else {
|
||||||
volume_box.hide();
|
album_image.set_from_pixbuf(None);
|
||||||
|
album_image.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ControllerEvent::UpdateProgress(progress_tick)
|
|
||||||
if !drag_lock.load(Ordering::Relaxed) =>
|
|
||||||
{
|
|
||||||
if let (Some(elapsed), Some(duration)) =
|
|
||||||
(progress_tick.elapsed, progress_tick.duration)
|
|
||||||
{
|
|
||||||
progress_label.set_label_escaped(&format!(
|
|
||||||
"{}/{}",
|
|
||||||
format_time(elapsed),
|
|
||||||
format_time(duration)
|
|
||||||
));
|
|
||||||
|
|
||||||
progress.set_value(elapsed.as_secs_f64());
|
update_popup_metadata_label(update.song.title, &title_label);
|
||||||
progress.set_range(0.0, duration.as_secs_f64());
|
update_popup_metadata_label(update.song.album, &album_label);
|
||||||
progress_box.show_all();
|
update_popup_metadata_label(update.song.artist, &artist_label);
|
||||||
} else {
|
|
||||||
progress_box.hide();
|
match update.status.state {
|
||||||
|
PlayerState::Stopped => {
|
||||||
|
btn_pause.hide();
|
||||||
|
btn_play.show();
|
||||||
|
btn_play.set_sensitive(false);
|
||||||
|
}
|
||||||
|
PlayerState::Playing => {
|
||||||
|
btn_play.set_sensitive(false);
|
||||||
|
btn_play.hide();
|
||||||
|
|
||||||
|
btn_pause.set_sensitive(true);
|
||||||
|
btn_pause.show();
|
||||||
|
}
|
||||||
|
PlayerState::Paused => {
|
||||||
|
btn_pause.set_sensitive(false);
|
||||||
|
btn_pause.hide();
|
||||||
|
|
||||||
|
btn_play.set_sensitive(true);
|
||||||
|
btn_play.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
|
let enable_prev = update.status.playlist_position > 0;
|
||||||
|
|
||||||
|
let enable_next =
|
||||||
|
update.status.playlist_position < update.status.playlist_length;
|
||||||
|
|
||||||
|
btn_prev.set_sensitive(enable_prev);
|
||||||
|
btn_next.set_sensitive(enable_next);
|
||||||
|
|
||||||
|
if let Some(volume) = update.status.volume_percent {
|
||||||
|
volume_slider.set_value(f64::from(volume));
|
||||||
|
volume_box.show();
|
||||||
|
} else {
|
||||||
|
volume_box.hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
ControllerEvent::UpdateProgress(progress_tick)
|
||||||
}
|
if !drag_lock.load(Ordering::Relaxed) =>
|
||||||
|
{
|
||||||
|
if let (Some(elapsed), Some(duration)) =
|
||||||
|
(progress_tick.elapsed, progress_tick.duration)
|
||||||
|
{
|
||||||
|
progress_label.set_label_escaped(&format!(
|
||||||
|
"{}/{}",
|
||||||
|
format_time(elapsed),
|
||||||
|
format_time(duration)
|
||||||
|
));
|
||||||
|
|
||||||
|
progress.set_value(elapsed.as_secs_f64());
|
||||||
|
progress.set_range(0.0, duration.as_secs_f64());
|
||||||
|
progress_box.show_all();
|
||||||
|
} else {
|
||||||
|
progress_box.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(container)
|
Some(container)
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ impl Module<GtkBox> for NetworkManagerModule {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
context.subscribe().recv_glib_async(move |state| {
|
context.subscribe().recv_glib_async((), move |(), state| {
|
||||||
let image_provider = image_provider.clone();
|
let image_provider = image_provider.clone();
|
||||||
let icon = icon.clone();
|
let icon = icon.clone();
|
||||||
|
|
||||||
|
|
|
@ -204,17 +204,13 @@ impl Module<Overlay> for NotificationsModule {
|
||||||
ctx.send_spawn(UiEvent::ToggleVisibility);
|
ctx.send_spawn(UiEvent::ToggleVisibility);
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
context.subscribe().recv_glib(&button, move |button, ev| {
|
||||||
let button = button.clone();
|
let icon = self.icons.icon(ev);
|
||||||
|
button.set_label(icon);
|
||||||
|
|
||||||
context.subscribe().recv_glib(move |ev| {
|
label.set_label(&ev.count.to_string());
|
||||||
let icon = self.icons.icon(ev);
|
label.set_visible(self.show_count && ev.count > 0);
|
||||||
button.set_label(icon);
|
});
|
||||||
|
|
||||||
label.set_label(&ev.count.to_string());
|
|
||||||
label.set_visible(self.show_count && ev.count > 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ModuleParts {
|
Ok(ModuleParts {
|
||||||
widget: overlay,
|
widget: overlay,
|
||||||
|
|
|
@ -110,12 +110,9 @@ impl Module<Label> for ScriptModule {
|
||||||
.justify(self.layout.justify.into())
|
.justify(self.layout.justify.into())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
{
|
context
|
||||||
let label = label.clone();
|
.subscribe()
|
||||||
context
|
.recv_glib(&label, |label, s| label.set_label_escaped(&s));
|
||||||
.subscribe()
|
|
||||||
.recv_glib(move |s| label.set_label_escaped(&s));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ModuleParts {
|
Ok(ModuleParts {
|
||||||
widget: label,
|
widget: label,
|
||||||
|
|
|
@ -303,7 +303,7 @@ impl Module<gtk::Box> for SysInfoModule {
|
||||||
labels.push(label);
|
labels.push(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.subscribe().recv_glib(move |data| {
|
context.subscribe().recv_glib((), move |(), data| {
|
||||||
let label = &labels[data.0];
|
let label = &labels[data.0];
|
||||||
label.set_label_escaped(&data.1);
|
label.set_label_escaped(&data.1);
|
||||||
});
|
});
|
||||||
|
|
|
@ -117,13 +117,13 @@ impl Module<gtk::Box> for TrayModule {
|
||||||
// Each widget is wrapped in an EventBox, copying what Waybar does here.
|
// Each widget is wrapped in an EventBox, copying what Waybar does here.
|
||||||
let container = gtk::Box::new(orientation, 10);
|
let container = gtk::Box::new(orientation, 10);
|
||||||
|
|
||||||
{
|
let mut menus = HashMap::new();
|
||||||
let container = container.clone();
|
let icon_theme = context.ironbar.image_provider().icon_theme();
|
||||||
let mut menus = HashMap::new();
|
|
||||||
let icon_theme = context.ironbar.image_provider().icon_theme();
|
|
||||||
|
|
||||||
// listen for UI updates
|
// listen for UI updates
|
||||||
context.subscribe().recv_glib(move |update| {
|
context
|
||||||
|
.subscribe()
|
||||||
|
.recv_glib(&container, move |container, update| {
|
||||||
on_update(
|
on_update(
|
||||||
update,
|
update,
|
||||||
&container,
|
&container,
|
||||||
|
@ -133,7 +133,6 @@ impl Module<gtk::Box> for TrayModule {
|
||||||
self.prefer_theme_icons,
|
self.prefer_theme_icons,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
Ok(ModuleParts {
|
Ok(ModuleParts {
|
||||||
widget: container,
|
widget: container,
|
||||||
|
|
|
@ -202,7 +202,7 @@ impl Module<Button> for UpowerModule {
|
||||||
|
|
||||||
let rx = context.subscribe();
|
let rx = context.subscribe();
|
||||||
let provider = context.ironbar.image_provider();
|
let provider = context.ironbar.image_provider();
|
||||||
rx.recv_glib_async(move |properties| {
|
rx.recv_glib_async((), move |(), properties| {
|
||||||
let state = properties.state;
|
let state = properties.state;
|
||||||
|
|
||||||
let is_charging =
|
let is_charging =
|
||||||
|
@ -258,7 +258,7 @@ impl Module<Button> for UpowerModule {
|
||||||
label.add_class("upower-details");
|
label.add_class("upower-details");
|
||||||
container.add(&label);
|
container.add(&label);
|
||||||
|
|
||||||
context.subscribe().recv_glib(move |properties| {
|
context.subscribe().recv_glib((), move |(), properties| {
|
||||||
let state = properties.state;
|
let state = properties.state;
|
||||||
let format = match state {
|
let format = match state {
|
||||||
BatteryState::Charging | BatteryState::PendingCharge => {
|
BatteryState::Charging | BatteryState::PendingCharge => {
|
||||||
|
|
|
@ -228,13 +228,11 @@ impl Module<Button> for VolumeModule {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
let rx = context.subscribe();
|
||||||
let rx = context.subscribe();
|
|
||||||
let icons = self.icons.clone();
|
|
||||||
|
|
||||||
let format = self.format.clone();
|
rx.recv_glib(
|
||||||
|
(&self.icons, &self.format),
|
||||||
rx.recv_glib(move |event| match event {
|
move |(icons, format), event| match event {
|
||||||
Event::AddSink(sink) | Event::UpdateSink(sink) if sink.active => {
|
Event::AddSink(sink) | Event::UpdateSink(sink) if sink.active => {
|
||||||
let label = format
|
let label = format
|
||||||
.replace(
|
.replace(
|
||||||
|
@ -251,8 +249,8 @@ impl Module<Button> for VolumeModule {
|
||||||
button_label.set_label_escaped(&label);
|
button_label.set_label_escaped(&label);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
});
|
},
|
||||||
}
|
);
|
||||||
|
|
||||||
let popup = self
|
let popup = self
|
||||||
.into_popup(context, info)
|
.into_popup(context, info)
|
||||||
|
@ -351,13 +349,11 @@ impl Module<Button> for VolumeModule {
|
||||||
container.show_all();
|
container.show_all();
|
||||||
|
|
||||||
let mut inputs = HashMap::new();
|
let mut inputs = HashMap::new();
|
||||||
|
let mut sinks = vec![];
|
||||||
|
|
||||||
{
|
context
|
||||||
let input_container = input_container.clone();
|
.subscribe()
|
||||||
|
.recv_glib(&input_container, move |input_container, event| {
|
||||||
let mut sinks = vec![];
|
|
||||||
|
|
||||||
context.subscribe().recv_glib(move |event| {
|
|
||||||
match event {
|
match event {
|
||||||
Event::AddSink(info) => {
|
Event::AddSink(info) => {
|
||||||
sink_selector.append(Some(&info.name), &info.description);
|
sink_selector.append(Some(&info.name), &info.description);
|
||||||
|
@ -477,7 +473,6 @@ impl Module<Button> for VolumeModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Some(container)
|
Some(container)
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,93 +317,95 @@ impl Module<gtk::Box> for WorkspacesModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
let name_map = self.name_map;
|
let name_map = self.name_map;
|
||||||
let handle_event = move |event: WorkspaceUpdate| match event {
|
context
|
||||||
WorkspaceUpdate::Init(workspaces) => {
|
.subscribe()
|
||||||
if has_initialized {
|
.recv_glib((), move |(), event| match event {
|
||||||
return;
|
WorkspaceUpdate::Init(workspaces) => {
|
||||||
}
|
if has_initialized {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
trace!("Creating workspace buttons");
|
trace!("Creating workspace buttons");
|
||||||
|
|
||||||
for workspace in workspaces
|
for workspace in workspaces
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|w| self.all_monitors || w.monitor == output_name)
|
.filter(|w| self.all_monitors || w.monitor == output_name)
|
||||||
.filter(|w| !self.hidden.contains(&w.name))
|
.filter(|w| !self.hidden.contains(&w.name))
|
||||||
{
|
{
|
||||||
add_workspace(workspace, &mut button_map);
|
add_workspace(workspace, &mut button_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
reorder!();
|
|
||||||
|
|
||||||
has_initialized = true;
|
|
||||||
}
|
|
||||||
WorkspaceUpdate::Add(workspace) => {
|
|
||||||
if !self.hidden.contains(&workspace.name)
|
|
||||||
&& (self.all_monitors || workspace.monitor == output_name)
|
|
||||||
{
|
|
||||||
add_workspace(workspace, &mut button_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
reorder!();
|
|
||||||
}
|
|
||||||
WorkspaceUpdate::Remove(id) => remove_workspace(id, &mut button_map),
|
|
||||||
WorkspaceUpdate::Move(workspace) => {
|
|
||||||
if self.all_monitors {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if workspace.monitor == output_name && !self.hidden.contains(&workspace.name) {
|
|
||||||
add_workspace(workspace, &mut button_map);
|
|
||||||
reorder!();
|
reorder!();
|
||||||
} else {
|
|
||||||
remove_workspace(workspace.id, &mut button_map);
|
has_initialized = true;
|
||||||
}
|
}
|
||||||
}
|
WorkspaceUpdate::Add(workspace) => {
|
||||||
WorkspaceUpdate::Focus { old, new } => {
|
if !self.hidden.contains(&workspace.name)
|
||||||
// Open states are calculated here rather than using the workspace visibility
|
&& (self.all_monitors || workspace.monitor == output_name)
|
||||||
// as that seems to come back wrong, at least on Hyprland.
|
{
|
||||||
// Likely a deeper issue that needs exploring.
|
add_workspace(workspace, &mut button_map);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(old) = old {
|
reorder!();
|
||||||
if let Some(button) = button_map.find_button_mut(&old) {
|
}
|
||||||
let open_state = if new.monitor == old.monitor {
|
WorkspaceUpdate::Remove(id) => remove_workspace(id, &mut button_map),
|
||||||
OpenState::Hidden
|
WorkspaceUpdate::Move(workspace) => {
|
||||||
} else {
|
if self.all_monitors {
|
||||||
OpenState::Visible
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
button.set_open_state(open_state);
|
if workspace.monitor == output_name
|
||||||
|
&& !self.hidden.contains(&workspace.name)
|
||||||
|
{
|
||||||
|
add_workspace(workspace, &mut button_map);
|
||||||
|
reorder!();
|
||||||
|
} else {
|
||||||
|
remove_workspace(workspace.id, &mut button_map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
WorkspaceUpdate::Focus { old, new } => {
|
||||||
|
// Open states are calculated here rather than using the workspace visibility
|
||||||
|
// as that seems to come back wrong, at least on Hyprland.
|
||||||
|
// Likely a deeper issue that needs exploring.
|
||||||
|
|
||||||
if let Some(button) = button_map.find_button_mut(&new) {
|
if let Some(old) = old {
|
||||||
button.set_open_state(OpenState::Focused);
|
if let Some(button) = button_map.find_button_mut(&old) {
|
||||||
}
|
let open_state = if new.monitor == old.monitor {
|
||||||
}
|
OpenState::Hidden
|
||||||
WorkspaceUpdate::Rename { id, name } => {
|
} else {
|
||||||
if let Some(button) = button_map
|
OpenState::Visible
|
||||||
.get(&Identifier::Id(id))
|
};
|
||||||
.or_else(|| button_map.get(&Identifier::Name(name.clone())))
|
|
||||||
.map(Button::button)
|
|
||||||
{
|
|
||||||
let display_name = name_map.get(&name).unwrap_or(&name);
|
|
||||||
|
|
||||||
button.set_label(display_name);
|
button.set_open_state(open_state);
|
||||||
button.set_widget_name(&name);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
WorkspaceUpdate::Urgent { id, urgent } => {
|
|
||||||
if let Some(button) = button_map
|
|
||||||
.get(&Identifier::Id(id))
|
|
||||||
.or_else(|| button_map.find_button_by_id(id))
|
|
||||||
{
|
|
||||||
button.set_urgent(urgent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WorkspaceUpdate::Unknown => warn!("received unknown type workspace event"),
|
|
||||||
};
|
|
||||||
|
|
||||||
context.subscribe().recv_glib(handle_event);
|
if let Some(button) = button_map.find_button_mut(&new) {
|
||||||
|
button.set_open_state(OpenState::Focused);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WorkspaceUpdate::Rename { id, name } => {
|
||||||
|
if let Some(button) = button_map
|
||||||
|
.get(&Identifier::Id(id))
|
||||||
|
.or_else(|| button_map.get(&Identifier::Name(name.clone())))
|
||||||
|
.map(Button::button)
|
||||||
|
{
|
||||||
|
let display_name = name_map.get(&name).unwrap_or(&name);
|
||||||
|
|
||||||
|
button.set_label(display_name);
|
||||||
|
button.set_widget_name(&name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WorkspaceUpdate::Urgent { id, urgent } => {
|
||||||
|
if let Some(button) = button_map
|
||||||
|
.get(&Identifier::Id(id))
|
||||||
|
.or_else(|| button_map.find_button_by_id(id))
|
||||||
|
{
|
||||||
|
button.set_urgent(urgent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WorkspaceUpdate::Unknown => warn!("received unknown type workspace event"),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ModuleParts {
|
Ok(ModuleParts {
|
||||||
|
|
24
src/popup.rs
24
src/popup.rs
|
@ -113,21 +113,15 @@ impl Popup {
|
||||||
let output_size = rc_mut!(output_size);
|
let output_size = rc_mut!(output_size);
|
||||||
|
|
||||||
// respond to resolution changes
|
// respond to resolution changes
|
||||||
{
|
let rx = ironbar.clients.borrow_mut().wayland().subscribe_outputs();
|
||||||
let output_size = output_size.clone();
|
let output_name = module_info.output_name.to_string();
|
||||||
let output_name = module_info.output_name.to_string();
|
rx.recv_glib(&output_size, move |output_size, event: OutputEvent| {
|
||||||
|
if event.event_type == OutputEventType::Update
|
||||||
let on_output_event = move |event: OutputEvent| {
|
&& event.output.name.unwrap_or_default() == output_name
|
||||||
if event.event_type == OutputEventType::Update
|
{
|
||||||
&& event.output.name.unwrap_or_default() == output_name
|
*output_size.borrow_mut() = event.output.logical_size.unwrap_or_default();
|
||||||
{
|
}
|
||||||
*output_size.borrow_mut() = event.output.logical_size.unwrap_or_default();
|
});
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let rx = ironbar.clients.borrow_mut().wayland().subscribe_outputs();
|
|
||||||
rx.recv_glib(on_output_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
window: win,
|
window: win,
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub fn load_css(style_path: PathBuf, application: Application) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rx.recv_glib(move |path| {
|
rx.recv_glib((), move |(), path| {
|
||||||
info!("Reloading CSS");
|
info!("Reloading CSS");
|
||||||
if let Err(err) = provider.load_from_file(&gio::File::for_path(path)) {
|
if let Err(err) = provider.load_from_file(&gio::File::for_path(path)) {
|
||||||
error!("{:?}", Report::new(err)
|
error!("{:?}", Report::new(err)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue