I have a tray icon created with libappindicator3, containing a CheckMenuItem
which activates a system service.
Activating the system service can fail though, and when it fails to activate, I want the CheckMenuItem
to be unchecked, too. However, whenever I run set_active(status)
, it triggers the connect_active callback, which I don't want to (since that will try to stop the service).
Here's a simplified version of my code:
use gtk::prelude::*;
use appindicator3::prelude::*;
use appindicator3::{Indicator, IndicatorStatus, IndicatorCategory};
fn try_activate() -> bool {
false
}
fn main() {
gtk::init().unwrap();
let indicator = Indicator::builder("aaa")
.category(IndicatorCategory::ApplicationStatus)
.icon("computer-symbolic", "icon")
.status(IndicatorStatus::Active)
.build();
let m = gtk::Menu::new();
let mi_enabled = gtk::CheckMenuItem::with_label("Active");
m.append(&mi_enabled);
mi_enabled.connect_activate(|mi_enabled| {
if mi_enabled.is_active() {
println!("activating");
if try_activate() {
println!("activated successfully");
} else {
println!("failed to activate");
mi_enabled.set_active(false);
}
} else {
println!("deactivating");
println!("deactivated successfully");
}
});
indicator.set_menu(Some(&m));
indicator.set_secondary_activate_target(Some(&mi_enabled));
gtk::main();
}
This is the output when I try to activate it:
activating
failed to activate
deactivating
deactivated successfully
What I want is to fail to activate and set_active(false) without triggering "deactivating".
I think this can be solved with a global variable, which I can set when changing it programmatically, then check it in the signal handler. But that seems like the wrong way to go.
I managed to solve this by using block_signal
and unblock_signal
around the set_active
call. However, since I'm trying to reference the return of the function around the closure, I used a Rc<RefCell<>>
around it, which seems excessive, but I found no workaround for this.
Resulting code:
let handler_id: Rc<RefCell<Option<SignalHandlerId>>> = Rc::new(RefCell::new(None));
let h_id = mi_enabled.connect_activate(glib::clone!(@strong handler_id => move |mi_enabled| {
if mi_enabled.is_active() {
println!("activating");
if try_activate() {
println!("activated successfully");
} else {
println!("failed to activate");
mi_enabled.block_signal(&handler_id.as_ref().borrow_mut().as_mut().unwrap());
mi_enabled.set_active(false);
mi_enabled.unblock_signal(&handler_id.as_ref().borrow_mut().as_mut().unwrap());
}
} else {
println!("deactivating");
println!("deactivated successfully");
}
}));
handler_id.as_ref().borrow_mut().insert(h_id);