On Web, add Window::(set_)prevent_default() (#3307)

This commit is contained in:
daxpedda 2023-12-25 09:37:35 +01:00 committed by GitHub
parent 28a811bbba
commit 843d7904d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 84 additions and 60 deletions

View file

@ -23,6 +23,7 @@ Unreleased` header.
- **Breaking:** On Web, return `RawWindowHandle::WebCanvas` instead of `RawWindowHandle::Web`.
- **Breaking:** On Web, macOS and iOS, return `HandleError::Unavailable` when a window handle is not available.
- **Breaking:** Bump MSRV from `1.65` to `1.70`.
- On Web, add the ability to toggle calling `Event.preventDefault()` on `Window`.
# 0.29.6

View file

@ -42,6 +42,21 @@ pub trait WindowExtWebSys {
/// Only returns the canvas if called from inside the window context (the
/// main thread).
fn canvas(&self) -> Option<HtmlCanvasElement>;
/// Returns [`true`] if calling `event.preventDefault()` is enabled.
///
/// See [`Window::set_prevent_default()`] for more details.
fn prevent_default(&self) -> bool;
/// Sets whether `event.preventDefault()` should be called on events on the
/// canvas that have side effects.
///
/// For example, by default using the mouse wheel would cause the page to scroll, enabling this
/// would prevent that.
///
/// Some events are impossible to prevent. E.g. Firefox allows to access the native browser
/// context menu with Shift+Rightclick.
fn set_prevent_default(&self, prevent_default: bool);
}
impl WindowExtWebSys for Window {
@ -49,6 +64,14 @@ impl WindowExtWebSys for Window {
fn canvas(&self) -> Option<HtmlCanvasElement> {
self.window.canvas()
}
fn prevent_default(&self) -> bool {
self.window.prevent_default()
}
fn set_prevent_default(&self, prevent_default: bool) {
self.window.set_prevent_default(prevent_default)
}
}
pub trait WindowBuilderExtWebSys {
@ -60,14 +83,10 @@ pub trait WindowBuilderExtWebSys {
/// [`None`] by default.
fn with_canvas(self, canvas: Option<HtmlCanvasElement>) -> Self;
/// Whether `event.preventDefault()` should be called on events on the
/// Sets whether `event.preventDefault()` should be called on events on the
/// canvas that have side effects.
///
/// For example, by default using the mouse wheel would cause the page to scroll, enabling this
/// would prevent that.
///
/// Some events are impossible to prevent. E.g. Firefox allows to access the native browser
/// context menu with Shift+Rightclick.
/// See [`Window::set_prevent_default()`] for more details.
///
/// Enabled by default.
fn with_prevent_default(self, prevent_default: bool) -> Self;

View file

@ -75,18 +75,13 @@ impl<T> EventLoopWindowTarget<T> {
WindowId(self.runner.generate_id())
}
pub fn register(
&self,
canvas: &Rc<RefCell<backend::Canvas>>,
id: WindowId,
prevent_default: bool,
) {
pub fn register(&self, canvas: &Rc<RefCell<backend::Canvas>>, id: WindowId) {
let canvas_clone = canvas.clone();
let mut canvas = canvas.borrow_mut();
#[cfg(any(feature = "rwh_04", feature = "rwh_05"))]
canvas.set_attribute("data-raw-handle", &id.0.to_string());
canvas.on_touch_start(prevent_default);
canvas.on_touch_start();
let runner = self.runner.clone();
let has_focus = canvas.has_focus.clone();
@ -157,7 +152,6 @@ impl<T> EventLoopWindowTarget<T> {
.chain(modifiers_changed),
);
},
prevent_default,
);
let runner = self.runner.clone();
@ -194,7 +188,6 @@ impl<T> EventLoopWindowTarget<T> {
.chain(modifiers_changed),
)
},
prevent_default,
);
let has_focus = canvas.has_focus.clone();
@ -374,7 +367,6 @@ impl<T> EventLoopWindowTarget<T> {
]));
}
},
prevent_default,
);
canvas.on_mouse_press(
@ -456,7 +448,6 @@ impl<T> EventLoopWindowTarget<T> {
)))
}
},
prevent_default,
);
canvas.on_mouse_release(
@ -547,30 +538,27 @@ impl<T> EventLoopWindowTarget<T> {
let runner = self.runner.clone();
let modifiers = self.modifiers.clone();
canvas.on_mouse_wheel(
move |pointer_id, delta, active_modifiers| {
let modifiers_changed = (has_focus.get() && modifiers.get() != active_modifiers)
.then(|| {
modifiers.set(active_modifiers);
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::ModifiersChanged(active_modifiers.into()),
}
});
runner.send_events(modifiers_changed.into_iter().chain(iter::once(
canvas.on_mouse_wheel(move |pointer_id, delta, active_modifiers| {
let modifiers_changed =
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
modifiers.set(active_modifiers);
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::MouseWheel {
device_id: RootDeviceId(DeviceId(pointer_id)),
delta,
phase: TouchPhase::Moved,
},
event: WindowEvent::ModifiersChanged(active_modifiers.into()),
}
});
runner.send_events(modifiers_changed.into_iter().chain(iter::once(
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::MouseWheel {
device_id: RootDeviceId(DeviceId(pointer_id)),
delta,
phase: TouchPhase::Moved,
},
)));
},
prevent_default,
);
},
)));
});
let runner = self.runner.clone();
canvas.on_touch_cancel(move |device_id, location, force| {
@ -649,7 +637,7 @@ impl<T> EventLoopWindowTarget<T> {
let runner = self.runner.clone();
canvas.on_animation_frame(move || runner.request_redraw(RootWindowId(id)));
canvas.on_context_menu(prevent_default);
canvas.on_context_menu();
}
pub fn available_monitors(&self) -> VecDequeIter<MonitorHandle> {

View file

@ -30,6 +30,7 @@ pub struct Canvas {
common: Common,
id: WindowId,
pub has_focus: Rc<Cell<bool>>,
pub prevent_default: Rc<Cell<bool>>,
pub is_intersecting: Option<bool>,
on_touch_start: Option<EventListenerHandle<dyn FnMut(Event)>>,
on_focus: Option<EventListenerHandle<dyn FnMut(FocusEvent)>>,
@ -141,6 +142,7 @@ impl Canvas {
common,
id,
has_focus: Rc::new(Cell::new(false)),
prevent_default: Rc::new(Cell::new(platform_attr.prevent_default)),
is_intersecting: None,
on_touch_start: None,
on_blur: None,
@ -231,9 +233,10 @@ impl Canvas {
&self.common.style
}
pub fn on_touch_start(&mut self, prevent_default: bool) {
pub fn on_touch_start(&mut self) {
let prevent_default = Rc::clone(&self.prevent_default);
self.on_touch_start = Some(self.common.add_event("touchstart", move |event: Event| {
if prevent_default {
if prevent_default.get() {
event.prevent_default();
}
}));
@ -257,13 +260,14 @@ impl Canvas {
}));
}
pub fn on_keyboard_release<F>(&mut self, mut handler: F, prevent_default: bool)
pub fn on_keyboard_release<F>(&mut self, mut handler: F)
where
F: 'static + FnMut(PhysicalKey, Key, Option<SmolStr>, KeyLocation, bool, ModifiersState),
{
let prevent_default = Rc::clone(&self.prevent_default);
self.on_keyboard_release =
Some(self.common.add_event("keyup", move |event: KeyboardEvent| {
if prevent_default {
if prevent_default.get() {
event.prevent_default();
}
let key = event::key(&event);
@ -279,14 +283,15 @@ impl Canvas {
}));
}
pub fn on_keyboard_press<F>(&mut self, mut handler: F, prevent_default: bool)
pub fn on_keyboard_press<F>(&mut self, mut handler: F)
where
F: 'static + FnMut(PhysicalKey, Key, Option<SmolStr>, KeyLocation, bool, ModifiersState),
{
let prevent_default = Rc::clone(&self.prevent_default);
self.on_keyboard_press = Some(self.common.add_event(
"keydown",
move |event: KeyboardEvent| {
if prevent_default {
if prevent_default.get() {
event.prevent_default();
}
let key = event::key(&event);
@ -340,7 +345,6 @@ impl Canvas {
modifier_handler: MOD,
mouse_handler: M,
touch_handler: T,
prevent_default: bool,
) where
MOD: 'static + FnMut(ModifiersState),
M: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, MouseButton),
@ -351,7 +355,7 @@ impl Canvas {
modifier_handler,
mouse_handler,
touch_handler,
prevent_default,
Rc::clone(&self.prevent_default),
)
}
@ -361,7 +365,6 @@ impl Canvas {
mouse_handler: M,
touch_handler: T,
button_handler: B,
prevent_default: bool,
) where
MOD: 'static + FnMut(ModifiersState),
M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator<Item = PhysicalPosition<f64>>),
@ -375,7 +378,7 @@ impl Canvas {
mouse_handler,
touch_handler,
button_handler,
prevent_default,
Rc::clone(&self.prevent_default),
)
}
@ -386,13 +389,14 @@ impl Canvas {
self.pointer_handler.on_touch_cancel(&self.common, handler)
}
pub fn on_mouse_wheel<F>(&mut self, mut handler: F, prevent_default: bool)
pub fn on_mouse_wheel<F>(&mut self, mut handler: F)
where
F: 'static + FnMut(i32, MouseScrollDelta, ModifiersState),
{
let window = self.common.window.clone();
let prevent_default = Rc::clone(&self.prevent_default);
self.on_mouse_wheel = Some(self.common.add_event("wheel", move |event: WheelEvent| {
if prevent_default {
if prevent_default.get() {
event.prevent_default();
}
@ -443,11 +447,12 @@ impl Canvas {
self.animation_frame_handler.on_animation_frame(f)
}
pub(crate) fn on_context_menu(&mut self, prevent_default: bool) {
pub(crate) fn on_context_menu(&mut self) {
let prevent_default = Rc::clone(&self.prevent_default);
self.on_context_menu = Some(self.common.add_event(
"contextmenu",
move |event: PointerEvent| {
if prevent_default {
if prevent_default.get() {
event.prevent_default();
}
},

View file

@ -1,3 +1,6 @@
use std::cell::Cell;
use std::rc::Rc;
use super::canvas::Common;
use super::event;
use super::event_handle::EventListenerHandle;
@ -110,7 +113,7 @@ impl PointerHandler {
mut modifier_handler: MOD,
mut mouse_handler: M,
mut touch_handler: T,
prevent_default: bool,
prevent_default: Rc<Cell<bool>>,
) where
MOD: 'static + FnMut(ModifiersState),
M: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, MouseButton),
@ -121,7 +124,7 @@ impl PointerHandler {
self.on_pointer_press = Some(canvas_common.add_event(
"pointerdown",
move |event: PointerEvent| {
if prevent_default {
if prevent_default.get() {
// prevent text selection
event.prevent_default();
// but still focus element
@ -165,7 +168,7 @@ impl PointerHandler {
mut mouse_handler: M,
mut touch_handler: T,
mut button_handler: B,
prevent_default: bool,
prevent_default: Rc<Cell<bool>>,
) where
MOD: 'static + FnMut(ModifiersState),
M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator<Item = PhysicalPosition<f64>>),
@ -197,7 +200,7 @@ impl PointerHandler {
"expect pointer type of a chorded button event to be a mouse"
);
if prevent_default {
if prevent_default.get() {
// prevent text selection
event.prevent_default();
// but still focus element

View file

@ -36,8 +36,6 @@ impl Window {
) -> Result<Self, RootOE> {
let id = target.generate_id();
let prevent_default = platform_attr.prevent_default;
let window = target.runner.window();
let document = target.runner.document();
let canvas =
@ -45,7 +43,7 @@ impl Window {
let canvas = Rc::new(RefCell::new(canvas));
let cursor = CursorState::new(canvas.borrow().style().clone());
target.register(&canvas, id, prevent_default);
target.register(&canvas, id);
let runner = target.runner.clone();
let destroy_fn = Box::new(move || runner.notify_destroy_window(RootWI(id)));
@ -84,6 +82,16 @@ impl Window {
.map(|inner| inner.canvas.borrow().raw().clone())
}
pub(crate) fn prevent_default(&self) -> bool {
self.inner
.queue(|inner| inner.canvas.borrow().prevent_default.get())
}
pub(crate) fn set_prevent_default(&self, prevent_default: bool) {
self.inner
.dispatch(move |inner| inner.canvas.borrow().prevent_default.set(prevent_default))
}
#[cfg(feature = "rwh_06")]
#[inline]
pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {