mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-26 06:00:21 +00:00
change to hook api
This commit is contained in:
parent
2772b86629
commit
cd17f515d4
5 changed files with 187 additions and 26 deletions
42
examples/window_focus.rs
Normal file
42
examples/window_focus.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use dioxus::prelude::*;
|
||||
use dioxus_desktop::tao::event::WindowEvent;
|
||||
use dioxus_desktop::use_wry_event_handler;
|
||||
use dioxus_desktop::wry::application::event::Event as WryEvent;
|
||||
|
||||
fn main() {
|
||||
dioxus_desktop::launch(app);
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let focused = use_state(cx, || false);
|
||||
|
||||
use_wry_event_handler(cx, {
|
||||
to_owned![focused];
|
||||
move |event, _| {
|
||||
if let WryEvent::WindowEvent {
|
||||
event: WindowEvent::Focused(new_focused),
|
||||
..
|
||||
} = event
|
||||
{
|
||||
focused.set(*new_focused);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
div{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
flex_direction: "column",
|
||||
align_items: "center",
|
||||
{
|
||||
if *focused.get() {
|
||||
"This window is focused!"
|
||||
} else {
|
||||
"This window is not focused!"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -32,6 +32,7 @@ tokio = { version = "1.16.1", features = [
|
|||
webbrowser = "0.8.0"
|
||||
infer = "0.11.0"
|
||||
dunce = "1.0.2"
|
||||
slab = "0.4"
|
||||
|
||||
interprocess = { version = "1.1.1", optional = true }
|
||||
futures-util = "0.3.25"
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use wry::application::event::Event;
|
||||
use wry::application::event_loop::EventLoopWindowTarget;
|
||||
use wry::application::window::Icon;
|
||||
use wry::{
|
||||
application::window::{Window, WindowBuilder},
|
||||
|
@ -10,18 +8,14 @@ use wry::{
|
|||
Result as WryResult,
|
||||
};
|
||||
|
||||
use crate::desktop_context::UserWindowEvent;
|
||||
|
||||
// pub(crate) type DynEventHandlerFn = dyn Fn(&mut EventLoop<()>, &mut WebView);
|
||||
|
||||
/// The configuration for the desktop application.
|
||||
pub struct Config {
|
||||
pub(crate) window: WindowBuilder,
|
||||
pub(crate) file_drop_handler: Option<DropHandler>,
|
||||
pub(crate) event_handler: Option<EventHandler>,
|
||||
pub(crate) protocols: Vec<WryProtocol>,
|
||||
pub(crate) pre_rendered: Option<String>,
|
||||
// pub(crate) event_handler: Option<Box<DynEventHandlerFn>>,
|
||||
pub(crate) disable_context_menu: bool,
|
||||
pub(crate) resource_dir: Option<PathBuf>,
|
||||
pub(crate) custom_head: Option<String>,
|
||||
|
@ -30,7 +24,6 @@ pub struct Config {
|
|||
}
|
||||
|
||||
type DropHandler = Box<dyn Fn(&Window, FileDropEvent) -> bool>;
|
||||
type EventHandler = Box<dyn Fn(&Event<UserWindowEvent>, &EventLoopWindowTarget<UserWindowEvent>)>;
|
||||
|
||||
pub(crate) type WryProtocol = (
|
||||
String,
|
||||
|
@ -48,7 +41,6 @@ impl Config {
|
|||
window,
|
||||
protocols: Vec::new(),
|
||||
file_drop_handler: None,
|
||||
event_handler: None,
|
||||
pre_rendered: None,
|
||||
disable_context_menu: !cfg!(debug_assertions),
|
||||
resource_dir: None,
|
||||
|
@ -84,16 +76,6 @@ impl Config {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set a custom wry event handler. This can be used to listen to window and webview events
|
||||
/// This only has an effect on the main window
|
||||
pub fn with_event_handler(
|
||||
mut self,
|
||||
handler: impl Fn(&Event<UserWindowEvent>, &EventLoopWindowTarget<UserWindowEvent>) + 'static,
|
||||
) -> Self {
|
||||
self.event_handler = Some(Box::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a file drop handler
|
||||
pub fn with_file_drop_handler(
|
||||
mut self,
|
||||
|
|
|
@ -10,6 +10,8 @@ use crate::WebviewHandler;
|
|||
use dioxus_core::ScopeState;
|
||||
use dioxus_core::VirtualDom;
|
||||
use serde_json::Value;
|
||||
use slab::Slab;
|
||||
use wry::application::event::Event;
|
||||
use wry::application::event_loop::EventLoopProxy;
|
||||
use wry::application::event_loop::EventLoopWindowTarget;
|
||||
#[cfg(target_os = "ios")]
|
||||
|
@ -57,6 +59,8 @@ pub struct DesktopContext {
|
|||
|
||||
pub(crate) event_loop: EventLoopWindowTarget<UserWindowEvent>,
|
||||
|
||||
pub(crate) event_handlers: WindowEventHandlers,
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
pub(crate) views: Rc<RefCell<Vec<*mut objc::runtime::Object>>>,
|
||||
}
|
||||
|
@ -76,6 +80,7 @@ impl DesktopContext {
|
|||
proxy: ProxyType,
|
||||
event_loop: EventLoopWindowTarget<UserWindowEvent>,
|
||||
webviews: WebviewQueue,
|
||||
event_handlers: WindowEventHandlers,
|
||||
) -> Self {
|
||||
Self {
|
||||
webview,
|
||||
|
@ -83,6 +88,7 @@ impl DesktopContext {
|
|||
event_loop,
|
||||
eval: tokio::sync::broadcast::channel(8).0,
|
||||
pending_windows: webviews,
|
||||
event_handlers,
|
||||
#[cfg(target_os = "ios")]
|
||||
views: Default::default(),
|
||||
}
|
||||
|
@ -102,6 +108,7 @@ impl DesktopContext {
|
|||
&self.proxy,
|
||||
dom,
|
||||
&self.pending_windows,
|
||||
&self.event_handlers,
|
||||
);
|
||||
|
||||
let id = window.webview.window().id();
|
||||
|
@ -216,6 +223,22 @@ impl DesktopContext {
|
|||
EvalResult::new(self.eval.clone())
|
||||
}
|
||||
|
||||
/// Create a wry event handler that listens for wry events.
|
||||
/// This event handler is scoped to the currently active window and will only recieve events that are either global or related to the current window.
|
||||
///
|
||||
/// The id this function returns can be used to remove the event handler with [`DesktopContext::remove_wry_event_handler`]
|
||||
pub fn create_wry_event_handler(
|
||||
&self,
|
||||
handler: impl FnMut(&Event<UserWindowEvent>, &EventLoopWindowTarget<UserWindowEvent>) + 'static,
|
||||
) -> WryEventHandlerId {
|
||||
self.event_handlers.add(self.id(), handler)
|
||||
}
|
||||
|
||||
/// Remove a wry event handler created with [`DesktopContext::create_wry_event_handler`]
|
||||
pub fn remove_wry_event_handler(&self, id: WryEventHandlerId) {
|
||||
self.event_handlers.remove(id)
|
||||
}
|
||||
|
||||
/// Push an objc view to the window
|
||||
#[cfg(target_os = "ios")]
|
||||
pub fn push_view(&self, view: objc_id::ShareId<objc::runtime::Object>) {
|
||||
|
@ -276,3 +299,112 @@ fn is_main_thread() -> bool {
|
|||
let result: BOOL = unsafe { msg_send![cls, isMainThread] };
|
||||
result != NO
|
||||
}
|
||||
|
||||
/// The unique identifier of a window event handler. This can be used to later remove the handler.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct WryEventHandlerId(usize);
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct WindowEventHandlers {
|
||||
handlers: Rc<RefCell<Slab<WryWindowEventHandlerInner>>>,
|
||||
}
|
||||
|
||||
impl WindowEventHandlers {
|
||||
pub(crate) fn add(
|
||||
&self,
|
||||
window_id: WindowId,
|
||||
handler: impl FnMut(&Event<UserWindowEvent>, &EventLoopWindowTarget<UserWindowEvent>) + 'static,
|
||||
) -> WryEventHandlerId {
|
||||
WryEventHandlerId(
|
||||
self.handlers
|
||||
.borrow_mut()
|
||||
.insert(WryWindowEventHandlerInner {
|
||||
window_id,
|
||||
handler: Box::new(handler),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn remove(&self, id: WryEventHandlerId) {
|
||||
self.handlers.borrow_mut().try_remove(id.0);
|
||||
}
|
||||
|
||||
pub(crate) fn apply_event(
|
||||
&self,
|
||||
event: &Event<UserWindowEvent>,
|
||||
target: &EventLoopWindowTarget<UserWindowEvent>,
|
||||
) {
|
||||
for (_, handler) in self.handlers.borrow_mut().iter_mut() {
|
||||
handler.apply_event(event, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WryWindowEventHandlerInner {
|
||||
window_id: WindowId,
|
||||
handler:
|
||||
Box<dyn FnMut(&Event<UserWindowEvent>, &EventLoopWindowTarget<UserWindowEvent>) + 'static>,
|
||||
}
|
||||
|
||||
impl WryWindowEventHandlerInner {
|
||||
fn apply_event(
|
||||
&mut self,
|
||||
event: &Event<UserWindowEvent>,
|
||||
target: &EventLoopWindowTarget<UserWindowEvent>,
|
||||
) {
|
||||
// if this event does not apply to the window this listener cares about, return
|
||||
match event {
|
||||
Event::WindowEvent { window_id, .. }
|
||||
| Event::MenuEvent {
|
||||
window_id: Some(window_id),
|
||||
..
|
||||
} => {
|
||||
if *window_id != self.window_id {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
(self.handler)(event, target)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a closure that executes any JavaScript in the WebView context.
|
||||
pub fn use_wry_event_handler(
|
||||
cx: &ScopeState,
|
||||
handler: impl FnMut(&Event<UserWindowEvent>, &EventLoopWindowTarget<UserWindowEvent>) + 'static,
|
||||
) -> &WryEventHandler {
|
||||
let desktop = use_window(cx);
|
||||
cx.use_hook(move || {
|
||||
let desktop = desktop.clone();
|
||||
|
||||
let id = desktop.create_wry_event_handler(handler);
|
||||
|
||||
WryEventHandler {
|
||||
handlers: desktop.event_handlers.clone(),
|
||||
id,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// A wry event handler that is scoped to the current component and window. The event handler will only receive events for the window it was created for and global events.
|
||||
///
|
||||
/// This will automatically be removed when the component is unmounted.
|
||||
pub struct WryEventHandler {
|
||||
handlers: WindowEventHandlers,
|
||||
/// The unique identifier of the event handler.
|
||||
pub id: WryEventHandlerId,
|
||||
}
|
||||
|
||||
impl WryEventHandler {
|
||||
/// Remove the event handler.
|
||||
pub fn remove(&self) {
|
||||
self.handlers.remove(self.id);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WryEventHandler {
|
||||
fn drop(&mut self) {
|
||||
self.handlers.remove(self.id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,10 @@ mod webview;
|
|||
mod hot_reload;
|
||||
|
||||
pub use cfg::Config;
|
||||
pub use desktop_context::{use_window, DesktopContext};
|
||||
use desktop_context::{EventData, UserWindowEvent, WebviewQueue};
|
||||
pub use desktop_context::{
|
||||
use_window, use_wry_event_handler, DesktopContext, WryEventHandler, WryEventHandlerId,
|
||||
};
|
||||
use desktop_context::{EventData, UserWindowEvent, WebviewQueue, WindowEventHandlers};
|
||||
use dioxus_core::*;
|
||||
use dioxus_html::HtmlEvent;
|
||||
pub use eval::{use_eval, EvalResult};
|
||||
|
@ -104,7 +106,7 @@ pub fn launch_cfg(root: Component, config_builder: Config) {
|
|||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, mut cfg: Config) {
|
||||
pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, cfg: Config) {
|
||||
let event_loop = EventLoop::<UserWindowEvent>::with_user_event();
|
||||
|
||||
let proxy = event_loop.create_proxy();
|
||||
|
@ -123,9 +125,10 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, mut cfg: Conf
|
|||
// Store them in a hashmap so we can remove them when they're closed
|
||||
let mut webviews = HashMap::<WindowId, WebviewHandler>::new();
|
||||
|
||||
let queue = WebviewQueue::default();
|
||||
// We use this to allow dynamically adding and removing window event handlers
|
||||
let event_handlers = WindowEventHandlers::default();
|
||||
|
||||
let event_handler = cfg.event_handler.take();
|
||||
let queue = WebviewQueue::default();
|
||||
|
||||
// By default, we'll create a new window when the app starts
|
||||
queue.borrow_mut().push(create_new_window(
|
||||
|
@ -134,14 +137,13 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, mut cfg: Conf
|
|||
&proxy,
|
||||
VirtualDom::new_with_props(root, props),
|
||||
&queue,
|
||||
&event_handlers,
|
||||
));
|
||||
|
||||
event_loop.run(move |window_event, event_loop, control_flow| {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
if let Some(handler) = &event_handler {
|
||||
handler(&window_event, event_loop);
|
||||
}
|
||||
event_handlers.apply_event(&window_event, event_loop);
|
||||
|
||||
match window_event {
|
||||
Event::WindowEvent {
|
||||
|
@ -246,6 +248,7 @@ fn create_new_window(
|
|||
proxy: &EventLoopProxy<UserWindowEvent>,
|
||||
dom: VirtualDom,
|
||||
queue: &WebviewQueue,
|
||||
event_handlers: &WindowEventHandlers,
|
||||
) -> WebviewHandler {
|
||||
let webview = webview::build(&mut cfg, event_loop, proxy.clone());
|
||||
|
||||
|
@ -254,6 +257,7 @@ fn create_new_window(
|
|||
proxy.clone(),
|
||||
event_loop.clone(),
|
||||
queue.clone(),
|
||||
event_handlers.clone(),
|
||||
));
|
||||
|
||||
let id = webview.window().id();
|
||||
|
|
Loading…
Reference in a new issue