Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/native/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ font-embolden = ["blitz-paint/font-embolden"]
apple-font-embolden = ["blitz-paint/apple-font-embolden"]

# Other features
winit-event-handler = ["dep:slab"]
# No-op on wasm32 (blitz_net::Provider needs tokio's threaded runtime); launch_cfg
# falls back to the in-process DioxusNativeNetProvider there.
net = ["dep:tokio", "dep:blitz-net"]
Expand Down Expand Up @@ -111,6 +112,7 @@ tracing = { workspace = true, optional = true }
rustc-hash = { workspace = true }
futures-util = { workspace = true }
cfg-if = "1.0.4"
slab = { workspace = true, optional = true }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { workspace = true, features = ["rt-multi-thread"], optional = true }
Expand Down
12 changes: 12 additions & 0 deletions packages/native/src/dioxus_application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ use winit::platform::macos::ApplicationHandlerExtMacOS;
use crate::DioxusNativeWindowRenderer;
use crate::{BlitzShellEvent, DioxusDocument, WindowConfig, contexts::DioxusNativeDocument};

#[cfg(feature = "winit-event-handler")]
use crate::event_handlers::WindowEventHandlers;

/// Dioxus-native specific event type
pub enum DioxusNativeEvent {
/// A hotreload event, basically telling us to update our templates.
Expand All @@ -34,6 +37,8 @@ pub enum DioxusNativeEvent {
pub struct DioxusNativeApplication {
pending_window: Option<WindowConfig<DioxusNativeWindowRenderer>>,
inner: BlitzApplication<DioxusNativeWindowRenderer>,
#[cfg(feature = "winit-event-handler")]
event_handler: Rc<WindowEventHandlers>,
}

impl DioxusNativeApplication {
Expand All @@ -45,6 +50,8 @@ impl DioxusNativeApplication {
Self {
pending_window: Some(config),
inner: BlitzApplication::new(proxy, event_queue),
#[cfg(feature = "winit-event-handler")]
event_handler: Rc::new(WindowEventHandlers::default()),
}
}

Expand Down Expand Up @@ -147,6 +154,8 @@ impl ApplicationHandler for DioxusNativeApplication {
window_id,
));
provide_context(shared);
#[cfg(feature = "winit-event-handler")]
provide_context(self.event_handler.clone());
});

// Add shell provider
Expand Down Expand Up @@ -190,6 +199,9 @@ impl ApplicationHandler for DioxusNativeApplication {
window_id: WindowId,
event: WindowEvent,
) {
#[cfg(feature = "winit-event-handler")]
self.event_handler
.apply_event(window_id, &event, event_loop);
self.inner.window_event(event_loop, window_id, event);
}

Expand Down
63 changes: 63 additions & 0 deletions packages/native/src/event_handlers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use slab::Slab;
use std::cell::RefCell;
use std::rc::Rc;
use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::WindowId};

/// 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 WinitEventHandler(pub(crate) usize);

impl WinitEventHandler {
/// Unregister this event handler from the window
pub fn remove(&self) {
let handlers: Rc<WindowEventHandlers> = dioxus_core::consume_context();
handlers.remove(*self);
}
}

struct WinitWindowEventHandlerInner {
window_id: WindowId,

#[allow(clippy::type_complexity)]
handler: Box<dyn FnMut(&WindowEvent, &dyn ActiveEventLoop) + 'static>,
}

#[derive(Default)]
pub(crate) struct WindowEventHandlers {
handlers: RefCell<Slab<WinitWindowEventHandlerInner>>,
}

impl WindowEventHandlers {
pub(crate) fn add(
&self,
window_id: WindowId,
handler: impl FnMut(&WindowEvent, &dyn ActiveEventLoop) + 'static,
) -> WinitEventHandler {
WinitEventHandler(
self.handlers
.borrow_mut()
.insert(WinitWindowEventHandlerInner {
window_id,
handler: Box::new(handler),
}),
)
}

pub(crate) fn remove(&self, id: WinitEventHandler) {
self.handlers.borrow_mut().try_remove(id.0);
}

pub fn apply_event(
&self,
window_id: WindowId,
event: &WindowEvent,
target: &dyn ActiveEventLoop,
) {
for (_, handler) in self.handlers.borrow_mut().iter_mut() {
if handler.window_id != window_id {
continue;
}
(handler.handler)(event, target)
}
}
}
24 changes: 24 additions & 0 deletions packages/native/src/hooks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use crate::event_handlers::{WindowEventHandlers, WinitEventHandler};

use dioxus_core::{Runtime, consume_context, current_scope_id, use_hook_with_cleanup};
use std::rc::Rc;
use winit::{event::WindowEvent, event_loop::ActiveEventLoop};

/// Register an event handler that runs when a winit event is processed.
pub fn use_winit_event_handler(
mut handler: impl FnMut(&WindowEvent, &dyn ActiveEventLoop) + 'static,
) -> WinitEventHandler {
let runtime = Runtime::current();
let scope_id = current_scope_id();
let window_id = crate::use_window().id();

use_hook_with_cleanup(
move || {
let handlers: Rc<WindowEventHandlers> = consume_context();
handlers.add(window_id, move |event, target| {
runtime.in_scope(scope_id, || handler(event, target))
})
},
move |handler| handler.remove(),
)
}
9 changes: 9 additions & 0 deletions packages/native/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ mod config;
mod contexts;
mod dioxus_application;
mod dioxus_renderer;
#[cfg(feature = "winit-event-handler")]
mod event_handlers;
#[cfg(feature = "winit-event-handler")]
mod hooks;
mod link_handler;

#[cfg(feature = "prelude")]
Expand Down Expand Up @@ -55,6 +59,11 @@ pub use {

pub use blitz_dom::{FontContext, Widget, build_single_font_ctx};
pub use config::Config;
#[cfg(feature = "winit-event-handler")]
pub use event_handlers::WinitEventHandler;
#[cfg(feature = "winit-event-handler")]
pub use hooks::use_winit_event_handler;
pub use winit;
pub use winit::dpi::{LogicalSize, PhysicalSize};
pub use winit::window::WindowAttributes;

Expand Down