1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
//! This module contains all event related types.
//!
//! To understand how events work in _BrowserWindow_, here is a short summary.
//! The [`BrowserWindow`](../browser/struct.BrowserWindow.html) handle
//! contains a bunch of functions that return different event objects, and then
//! the event object can be used to register the callback at.
//!
//! Each event object has the
//! [`register`](trait.EventExt.html#tymethod.register) method to register a
//! closure to be executed on the occurence of the event.
//!
//! ```
//! use browser_window::{browser::*, prelude::*};
//!
//! fn example(bw: BrowserWindow) {
//! bw.on_message()
//! .register(|h: &BrowserWindowHandle, e: MessageEventArgs| {
//! // .. code here ...
//! });
//! }
//! ```
//!
//! There is also a
//! [`register_async`](trait.EventExt.html#tymethod.register_async)
//! method, which can be useful in async code:
//!
//! ```
//! use browser_window::{browser::*, prelude::*};
//!
//! fn async_example(bw: BrowserWindow) {
//! bw.on_message()
//! .register_async(|h: BrowserWindow, e: MessageEventArgs| async move {
//! // .. code here ...
//! });
//! }
//! ```
//!
//! Also, keep in mind that if the `register` or `register_async` methods are
//! not available, that means that event object does not implement `EventExt`,
//! which in turn means that the corresponding event is not supported for the
//! browser framework that has been selected.
//!
//! CEF supports all events, unless it is stated that it is not implemented yet.
//! The other browser frameworks only support a subset of what is supported for
//! CEF. The reason for this is that CEF is simply the most cross-platform
//! framework out there, so it gets the most care.
use std::{boxed::Box, future::Future, pin::Pin};
#[cfg(not(feature = "threadsafe"))]
pub type EventHandlerAsyncCallback<O, A> =
dyn FnMut(O, A) -> Pin<Box<dyn Future<Output = ()> + 'static>> + 'static;
#[cfg(not(feature = "threadsafe"))]
pub type EventHandlerSyncCallback<H, A> = dyn FnMut(&H, A) + 'static;
#[cfg(feature = "threadsafe")]
pub type EventHandlerAsyncCallback<O, A> =
dyn FnMut(O, A) -> Pin<Box<dyn Future<Output = ()> + 'static>> + Send + 'static;
#[cfg(feature = "threadsafe")]
pub type EventHandlerSyncCallback<H, A> = dyn FnMut(&H, A) + Send + 'static;
pub enum EventHandler<H, O, A> {
Sync(Box<EventHandlerSyncCallback<H, A>>),
Async(Box<EventHandlerAsyncCallback<O, A>>),
}
/// An `Event` can be registered to with a regular closure or an 'async
/// enclosure'. All events are implemented for CEF.
/// If an event is not implemented for another browser framework, it will simply
/// never be invoked. If an event _is_ supported by another browser framework,
/// it should say so in its documentation.
pub(crate) trait Event<H, O, A> {
fn register_handler(&mut self, handler: EventHandler<H, O, A>);
}
pub trait EventExt<H, O, A> {
/// Register a closure to be invoked for this event.
#[cfg(not(feature = "threadsafe"))]
fn register<X>(&mut self, handler: X)
where
X: FnMut(&H, A) + 'static;
/// Register a closure to be invoked for this event.
#[cfg(feature = "threadsafe")]
fn register<X>(&mut self, handler: X)
where
X: FnMut(&H, A) + Send + 'static;
/// Register an 'async closure' to be invoked for this event.
///
/// # Example
/// ```ignore
/// my_event.register_async(|args| async move {
/// // Do something ...
/// });
/// ```
#[cfg(not(feature = "threadsafe"))]
fn register_async<X, F>(&mut self, handler: X)
where
X: FnMut(O, A) -> F + 'static,
F: Future<Output = ()> + 'static;
/// Register an 'async closure' to be invoked for this event.
///
/// # Example
/// ```ignore
/// my_event.register_async(|args| async move {
/// // Do something ...
/// });
/// ```
#[cfg(feature = "threadsafe")]
fn register_async<X, F>(&mut self, handler: X)
where
X: FnMut(O, A) -> F + Send + 'static,
F: Future<Output = ()> + 'static;
}
impl<H, O, A, T> EventExt<H, O, A> for T
where
T: Event<H, O, A>,
{
#[cfg(not(feature = "threadsafe"))]
fn register<X>(&mut self, mut handler: X)
where
X: FnMut(&H, A) + 'static,
{
self.register_handler(EventHandler::Sync(Box::new(move |h, args| {
handler(h, args);
})));
}
#[cfg(feature = "threadsafe")]
fn register<X>(&mut self, mut handler: X)
where
X: FnMut(&H, A) + Send + 'static,
{
self.register_handler(EventHandler::Sync(Box::new(move |h, args| {
handler(h, args);
})));
}
#[cfg(not(feature = "threadsafe"))]
fn register_async<X, F>(&mut self, mut handler: X)
where
X: FnMut(O, A) -> F + 'static,
F: Future<Output = ()> + 'static,
{
self.register_handler(EventHandler::Async(Box::new(move |h, args| {
Box::pin(handler(h, args))
})));
}
#[cfg(feature = "threadsafe")]
fn register_async<X, F>(&mut self, mut handler: X)
where
X: FnMut(O, A) -> F + Send + 'static,
F: Future<Output = ()> + 'static,
{
self.register_handler(EventHandler::Async(Box::new(move |h, args| {
Box::pin(handler(h, args))
})));
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! decl_event {
($name:ident < $owner:ty >) => {
pub struct $name {
#[allow(dead_code)]
pub(crate) owner: crate::rc::Weak<$owner>,
}
impl $name {
#[allow(dead_code)]
pub(crate) fn new(owner: crate::rc::Weak<$owner>) -> Self { Self { owner } }
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! decl_browser_event {
($name:ident) => {
decl_event!($name<BrowserWindowOwner>);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! def_event {
( $name:ident<$handle_type:ty, $owner_type:ty, $arg_type:ty> (&mut $this:ident, $arg_name:ident) $body:block ) => {
impl crate::event::Event<$handle_type, $owner_type, $arg_type> for $name {
fn register_handler(&mut $this, $arg_name: crate::event::EventHandler<$handle_type, $owner_type, $arg_type>) $body
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! def_browser_event {
( $name:ident<$arg_type:ty> (&mut $this:ident, $arg_name:ident) $body:block ) => {
def_event!($name<BrowserWindowHandle, BrowserWindow, $arg_type> (&mut $this, $arg_name) $body);
}
}