refactor: allow changing the menu event sender (#35)

* refactor: allow changing the menu event sender

* readme

* fix docs warning

* readme
This commit is contained in:
Amr Bashir 2023-01-03 04:07:07 +02:00 committed by GitHub
parent 1e87714759
commit f871c68e81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 63 additions and 23 deletions

View file

@ -0,0 +1,5 @@
---
"muda": "patch"
---
Add `MenuEvent::set_event_handler` to set a handler for new menu events.

View file

@ -0,0 +1,5 @@
---
"muda": "minor"
---
**Breaking change** Remove `menu_event_receiver` function, use `MenuEvent::receiver` instead.

View file

@ -52,10 +52,10 @@ menu.show_context_menu_for_nsview(nsview, x, y);
```
## Processing menu events
You can use [`menu_event_receiver`](https://docs.rs/muda/latest/muda/fn.menu_event_receiver.html) to get a reference to the [`MenuEventReceiver`](https://docs.rs/muda/latest/muda/type.MenuEventReceiver.html)
You can use `MenuEvent::receiver` to get a reference to the `MenuEventReceiver`
which you can use to listen to events when a menu item is activated
```rs
if let Ok(event) = menu_event_receiver().try_recv() {
if let Ok(event) = MenuEvent::receiver().try_recv() {
match event.id {
_ if event.id == save_item.id() => {
println!("Save menu item activated");

View file

@ -5,7 +5,7 @@
#![allow(unused)]
use muda::{
accelerator::{Accelerator, Code, Modifiers},
menu_event_receiver, AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuItem,
AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuEvent, MenuItem,
PredefinedMenuItem, Submenu,
};
#[cfg(target_os = "macos")]
@ -144,7 +144,7 @@ fn main() {
window_m.set_windows_menu_for_nsapp();
}
let menu_channel = menu_event_receiver();
let menu_channel = MenuEvent::receiver();
let mut x = 0_f64;
let mut y = 0_f64;

View file

@ -5,7 +5,7 @@
#![allow(unused)]
use muda::{
accelerator::{Accelerator, Code, Modifiers},
menu_event_receiver, AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuItem,
AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuEvent, MenuItem,
PredefinedMenuItem, Submenu,
};
#[cfg(target_os = "macos")]
@ -136,7 +136,7 @@ fn main() {
window_m.set_windows_menu_for_nsapp();
}
let menu_channel = menu_event_receiver();
let menu_channel = MenuEvent::receiver();
let mut x = 0_f64;
let mut y = 0_f64;

View file

@ -79,13 +79,13 @@
//! ```
//! # Processing menu events
//!
//! You can use [`menu_event_receiver`] to get a reference to the [`MenuEventReceiver`]
//! You can use [`MenuEvent::receiver`] to get a reference to the [`MenuEventReceiver`]
//! which you can use to listen to events when a menu item is activated
//! ```no_run
//! # use muda::menu_event_receiver;
//! # use muda::MenuEvent;
//! #
//! # let save_item: muda::MenuItem = unsafe { std::mem::zeroed() };
//! if let Ok(event) = menu_event_receiver().try_recv() {
//! if let Ok(event) = MenuEvent::receiver().try_recv() {
//! match event.id {
//! id if id == save_item.id() => {
//! println!("Save menu item activated");
@ -103,7 +103,7 @@
//! See [`Menu::init_for_hwnd`] for more details
use crossbeam_channel::{unbounded, Receiver, Sender};
use once_cell::sync::Lazy;
use once_cell::sync::{Lazy, OnceCell};
pub mod accelerator;
mod check_menu_item;
@ -192,7 +192,7 @@ pub trait ContextMenu {
fn show_context_menu_for_hwnd(&self, hwnd: isize, x: f64, y: f64);
/// Attach the menu subclass handler to the given hwnd
/// so you can recieve events from that window using [menu_event_receiver]
/// so you can recieve events from that window using [MenuEvent::receiver]
///
/// This can be used along with [`ContextMenu::hpopupmenu`] when implementing a tray icon menu.
#[cfg(target_os = "windows")]
@ -231,11 +231,41 @@ pub struct MenuEvent {
/// A reciever that could be used to listen to menu events.
pub type MenuEventReceiver = Receiver<MenuEvent>;
type MenuEventHandler = Box<dyn Fn(MenuEvent) + Send + Sync + 'static>;
static MENU_CHANNEL: Lazy<(Sender<MenuEvent>, MenuEventReceiver)> = Lazy::new(unbounded);
static MENU_EVENT_HANDLER: OnceCell<Option<MenuEventHandler>> = OnceCell::new();
/// Gets a reference to the event channel's [MenuEventReceiver]
impl MenuEvent {
/// Gets a reference to the event channel's [`MenuEventReceiver`]
/// which can be used to listen for menu events.
pub fn menu_event_receiver<'a>() -> &'a MenuEventReceiver {
///
/// ## Note
///
/// This will not receive any events if [`MenuEvent::set_event_handler`] has been called with a `Some` value.
pub fn receiver<'a>() -> &'a MenuEventReceiver {
&MENU_CHANNEL.1
}
/// Set a handler to be called for new events. Useful for implementing custom event sender.
///
/// ## Note
///
/// Calling this function with a `Some` value,
/// will not send new events to the channel associated with [`MenuEvent::receiver`]
pub fn set_event_handler<F: Fn(MenuEvent) + Send + Sync + 'static>(f: Option<F>) {
if let Some(f) = f {
let _ = MENU_EVENT_HANDLER.set(Some(Box::new(f)));
} else {
let _ = MENU_EVENT_HANDLER.set(None);
}
}
pub(crate) fn send(event: MenuEvent) {
if let Some(handler) = MENU_EVENT_HANDLER.get_or_init(|| None) {
handler(event);
} else {
let _ = MENU_CHANNEL.0.send(event);
}
}
}

View file

@ -12,7 +12,7 @@ use crate::{
icon::Icon,
predefined::PredfinedMenuItemType,
util::{AddOp, Counter},
MenuItemType,
MenuEvent, MenuItemType,
};
use accelerator::{from_gtk_mnemonic, parse_accelerator, register_accelerator, to_gtk_mnemonic};
use gtk::{prelude::*, Orientation};
@ -826,7 +826,7 @@ impl MenuItem {
let id = self_.id;
item.connect_activate(move |_| {
let _ = crate::MENU_CHANNEL.0.send(crate::MenuEvent { id });
MenuEvent::send(crate::MenuEvent { id });
});
if add_to_cache {
@ -1069,7 +1069,7 @@ impl CheckMenuItem {
is_syncing_checked_state_c.store(false, Ordering::Release);
let _ = crate::MENU_CHANNEL.0.send(crate::MenuEvent { id });
MenuEvent::send(crate::MenuEvent { id });
}
});
@ -1188,7 +1188,7 @@ impl IconMenuItem {
let id = self_.id;
item.connect_activate(move |_| {
let _ = crate::MENU_CHANNEL.0.send(crate::MenuEvent { id });
MenuEvent::send(crate::MenuEvent { id });
});
if add_to_cache {

View file

@ -26,7 +26,7 @@ use crate::{
icon::Icon,
predefined::PredfinedMenuItemType,
util::{AddOp, Counter},
MenuItemExt, MenuItemType,
MenuEvent, MenuItemExt, MenuItemType,
};
static COUNTER: Counter = Counter::new();
@ -952,7 +952,7 @@ extern "C" fn fire_menu_item_click(this: &Object, _: Sel, _item: id) {
(*item).set_checked(!(*item).is_checked());
}
let _ = crate::MENU_CHANNEL.0.send(crate::MenuEvent { id });
MenuEvent::send(crate::MenuEvent { id });
}
}

View file

@ -13,7 +13,7 @@ use crate::{
icon::Icon,
predefined::PredfinedMenuItemType,
util::{AddOp, Counter},
MenuItemType,
MenuEvent, MenuItemType,
};
use std::{cell::RefCell, fmt::Debug, rc::Rc};
use util::{decode_wide, encode_wide, Accel};
@ -1144,7 +1144,7 @@ website: {} {}
}
if dispatch {
let _ = crate::MENU_CHANNEL.0.send(crate::MenuEvent { id });
MenuEvent::send(crate::MenuEvent { id });
}
}
}