mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Implement ResizeObserver
(#2859)
Co-authored-by: Liam Murphy <43807659+Liamolucko@users.noreply.github.com>
This commit is contained in:
parent
7ce86c3d2a
commit
9a9c9b15ba
|
@ -67,7 +67,7 @@ And please only add new entries to the top of this list, right below the `# Unre
|
||||||
- On Web, fix pen treated as mouse input.
|
- On Web, fix pen treated as mouse input.
|
||||||
- On Web, send mouse position on button release as well.
|
- On Web, send mouse position on button release as well.
|
||||||
- On Web, fix touch input not gaining or loosing focus.
|
- On Web, fix touch input not gaining or loosing focus.
|
||||||
- **Breaking:** On Web, dropped support for Safari versions below 13.
|
- **Breaking:** On Web, dropped support for Safari versions below 13.1.
|
||||||
- On Web, prevent clicks on the canvas to select text.
|
- On Web, prevent clicks on the canvas to select text.
|
||||||
- On Web, `EventLoopProxy` now implements `Send`.
|
- On Web, `EventLoopProxy` now implements `Send`.
|
||||||
- On Web, `Window` now implements `Send` and `Sync`.
|
- On Web, `Window` now implements `Send` and `Sync`.
|
||||||
|
@ -79,6 +79,8 @@ And please only add new entries to the top of this list, right below the `# Unre
|
||||||
- On Web, fix scale factor resize suggestion always overwriting the canvas size.
|
- On Web, fix scale factor resize suggestion always overwriting the canvas size.
|
||||||
- On macOS, fix crash when dropping `Window`.
|
- On macOS, fix crash when dropping `Window`.
|
||||||
- On Web, use `Window.requestIdleCallback()` for `ControlFlow::Poll` when available.
|
- On Web, use `Window.requestIdleCallback()` for `ControlFlow::Poll` when available.
|
||||||
|
- **Breaking:** On Web, the canvas size is not controlled by Winit anymore and external changes to
|
||||||
|
the canvas size will be reported through `WindowEvent::Resized`.
|
||||||
|
|
||||||
# 0.28.6
|
# 0.28.6
|
||||||
|
|
||||||
|
|
|
@ -129,12 +129,13 @@ redox_syscall = "0.3"
|
||||||
|
|
||||||
[target.'cfg(target_family = "wasm")'.dependencies.web_sys]
|
[target.'cfg(target_family = "wasm")'.dependencies.web_sys]
|
||||||
package = "web-sys"
|
package = "web-sys"
|
||||||
version = "0.3"
|
version = "0.3.64"
|
||||||
features = [
|
features = [
|
||||||
'console',
|
'console',
|
||||||
'CssStyleDeclaration',
|
'CssStyleDeclaration',
|
||||||
'Document',
|
'Document',
|
||||||
'DomRect',
|
'DomRect',
|
||||||
|
'DomRectReadOnly',
|
||||||
'Element',
|
'Element',
|
||||||
'Event',
|
'Event',
|
||||||
'EventTarget',
|
'EventTarget',
|
||||||
|
@ -145,6 +146,11 @@ features = [
|
||||||
'MediaQueryList',
|
'MediaQueryList',
|
||||||
'Node',
|
'Node',
|
||||||
'PointerEvent',
|
'PointerEvent',
|
||||||
|
'ResizeObserver',
|
||||||
|
'ResizeObserverBoxOptions',
|
||||||
|
'ResizeObserverEntry',
|
||||||
|
'ResizeObserverOptions',
|
||||||
|
'ResizeObserverSize',
|
||||||
'Window',
|
'Window',
|
||||||
'WheelEvent'
|
'WheelEvent'
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#![allow(clippy::disallowed_methods, clippy::single_match)]
|
#![allow(clippy::disallowed_methods, clippy::single_match)]
|
||||||
|
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{Event, WindowEvent},
|
event::{ElementState, Event, KeyEvent, WindowEvent},
|
||||||
event_loop::EventLoop,
|
event_loop::EventLoop,
|
||||||
window::WindowBuilder,
|
keyboard::KeyCode,
|
||||||
|
window::{Fullscreen, WindowBuilder},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
@ -31,6 +32,25 @@ pub fn main() {
|
||||||
Event::MainEventsCleared => {
|
Event::MainEventsCleared => {
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event:
|
||||||
|
WindowEvent::KeyboardInput {
|
||||||
|
event:
|
||||||
|
KeyEvent {
|
||||||
|
physical_key: KeyCode::KeyF,
|
||||||
|
state: ElementState::Released,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
},
|
||||||
|
} if window_id == window.id() => {
|
||||||
|
if window.fullscreen().is_some() {
|
||||||
|
window.set_fullscreen(None);
|
||||||
|
} else {
|
||||||
|
window.set_fullscreen(Some(Fullscreen::Borderless(None)));
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
mod proxy;
|
mod proxy;
|
||||||
mod runner;
|
pub(crate) mod runner;
|
||||||
mod state;
|
mod state;
|
||||||
mod window_target;
|
mod window_target;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use super::{super::ScaleChangeArgs, backend, state::State};
|
use super::{backend, state::State};
|
||||||
|
use crate::dpi::PhysicalSize;
|
||||||
use crate::event::{Event, StartCause};
|
use crate::event::{Event, StartCause};
|
||||||
use crate::event_loop::ControlFlow;
|
use crate::event_loop::ControlFlow;
|
||||||
use crate::window::WindowId;
|
use crate::window::WindowId;
|
||||||
|
@ -25,13 +26,12 @@ impl<T> Clone for Shared<T> {
|
||||||
|
|
||||||
pub struct Execution<T: 'static> {
|
pub struct Execution<T: 'static> {
|
||||||
runner: RefCell<RunnerEnum<T>>,
|
runner: RefCell<RunnerEnum<T>>,
|
||||||
events: RefCell<VecDeque<Event<'static, T>>>,
|
events: RefCell<VecDeque<EventWrapper<T>>>,
|
||||||
id: RefCell<u32>,
|
id: RefCell<u32>,
|
||||||
window: web_sys::Window,
|
window: web_sys::Window,
|
||||||
all_canvases: RefCell<Vec<(WindowId, Weak<RefCell<backend::Canvas>>)>>,
|
all_canvases: RefCell<Vec<(WindowId, Weak<RefCell<backend::Canvas>>)>>,
|
||||||
redraw_pending: RefCell<HashSet<WindowId>>,
|
redraw_pending: RefCell<HashSet<WindowId>>,
|
||||||
destroy_pending: RefCell<VecDeque<WindowId>>,
|
destroy_pending: RefCell<VecDeque<WindowId>>,
|
||||||
scale_change_detector: RefCell<Option<backend::ScaleChangeDetector>>,
|
|
||||||
unload_event_handle: RefCell<Option<backend::UnloadEventHandle>>,
|
unload_event_handle: RefCell<Option<backend::UnloadEventHandle>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,10 +86,31 @@ impl<T: 'static> Runner<T> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_single_event(&mut self, event: Event<'_, T>, control: &mut ControlFlow) {
|
fn handle_single_event(
|
||||||
|
&mut self,
|
||||||
|
runner: &Shared<T>,
|
||||||
|
event: impl Into<EventWrapper<T>>,
|
||||||
|
control: &mut ControlFlow,
|
||||||
|
) {
|
||||||
let is_closed = matches!(*control, ControlFlow::ExitWithCode(_));
|
let is_closed = matches!(*control, ControlFlow::ExitWithCode(_));
|
||||||
|
|
||||||
(self.event_handler)(event, control);
|
match event.into() {
|
||||||
|
EventWrapper::Event(event) => (self.event_handler)(event, control),
|
||||||
|
EventWrapper::ScaleChange {
|
||||||
|
canvas,
|
||||||
|
size,
|
||||||
|
scale,
|
||||||
|
} => {
|
||||||
|
if let Some(canvas) = canvas.upgrade() {
|
||||||
|
canvas.borrow().handle_scale_change(
|
||||||
|
runner,
|
||||||
|
|event| (self.event_handler)(event, control),
|
||||||
|
size,
|
||||||
|
scale,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maintain closed state, even if the callback changes it
|
// Maintain closed state, even if the callback changes it
|
||||||
if is_closed {
|
if is_closed {
|
||||||
|
@ -109,7 +130,6 @@ impl<T: 'static> Shared<T> {
|
||||||
all_canvases: RefCell::new(Vec::new()),
|
all_canvases: RefCell::new(Vec::new()),
|
||||||
redraw_pending: RefCell::new(HashSet::new()),
|
redraw_pending: RefCell::new(HashSet::new()),
|
||||||
destroy_pending: RefCell::new(VecDeque::new()),
|
destroy_pending: RefCell::new(VecDeque::new()),
|
||||||
scale_change_detector: RefCell::new(None),
|
|
||||||
unload_event_handle: RefCell::new(None),
|
unload_event_handle: RefCell::new(None),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -147,16 +167,6 @@ impl<T: 'static> Shared<T> {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_on_scale_change<F>(&self, handler: F)
|
|
||||||
where
|
|
||||||
F: 'static + FnMut(ScaleChangeArgs),
|
|
||||||
{
|
|
||||||
*self.0.scale_change_detector.borrow_mut() = Some(backend::ScaleChangeDetector::new(
|
|
||||||
self.window().clone(),
|
|
||||||
handler,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a strictly increasing ID
|
// Generate a strictly increasing ID
|
||||||
// This is used to differentiate windows when handling events
|
// This is used to differentiate windows when handling events
|
||||||
pub fn generate_id(&self) -> u32 {
|
pub fn generate_id(&self) -> u32 {
|
||||||
|
@ -168,7 +178,7 @@ impl<T: 'static> Shared<T> {
|
||||||
|
|
||||||
pub fn request_redraw(&self, id: WindowId) {
|
pub fn request_redraw(&self, id: WindowId) {
|
||||||
self.0.redraw_pending.borrow_mut().insert(id);
|
self.0.redraw_pending.borrow_mut().insert(id);
|
||||||
self.send_events(iter::empty());
|
self.send_events::<EventWrapper<T>>(iter::empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&self) {
|
pub fn init(&self) {
|
||||||
|
@ -196,14 +206,17 @@ impl<T: 'static> Shared<T> {
|
||||||
// Add an event to the event loop runner, from the user or an event handler
|
// Add an event to the event loop runner, from the user or an event handler
|
||||||
//
|
//
|
||||||
// It will determine if the event should be immediately sent to the user or buffered for later
|
// It will determine if the event should be immediately sent to the user or buffered for later
|
||||||
pub fn send_event(&self, event: Event<'static, T>) {
|
pub(crate) fn send_event<E: Into<EventWrapper<T>>>(&self, event: E) {
|
||||||
self.send_events(iter::once(event));
|
self.send_events(iter::once(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a series of events to the event loop runner
|
// Add a series of events to the event loop runner
|
||||||
//
|
//
|
||||||
// It will determine if the event should be immediately sent to the user or buffered for later
|
// It will determine if the event should be immediately sent to the user or buffered for later
|
||||||
pub fn send_events(&self, events: impl IntoIterator<Item = Event<'static, T>>) {
|
pub(crate) fn send_events<E: Into<EventWrapper<T>>>(
|
||||||
|
&self,
|
||||||
|
events: impl IntoIterator<Item = E>,
|
||||||
|
) {
|
||||||
// If the event loop is closed, it should discard any new events
|
// If the event loop is closed, it should discard any new events
|
||||||
if self.is_closed() {
|
if self.is_closed() {
|
||||||
return;
|
return;
|
||||||
|
@ -232,7 +245,10 @@ impl<T: 'static> Shared<T> {
|
||||||
}
|
}
|
||||||
if !process_immediately {
|
if !process_immediately {
|
||||||
// Queue these events to look at later
|
// Queue these events to look at later
|
||||||
self.0.events.borrow_mut().extend(events);
|
self.0
|
||||||
|
.events
|
||||||
|
.borrow_mut()
|
||||||
|
.extend(events.into_iter().map(Into::into));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// At this point, we know this is a fresh set of events
|
// At this point, we know this is a fresh set of events
|
||||||
|
@ -250,13 +266,13 @@ impl<T: 'static> Shared<T> {
|
||||||
// Take the start event, then the events provided to this function, and run an iteration of
|
// Take the start event, then the events provided to this function, and run an iteration of
|
||||||
// the event loop
|
// the event loop
|
||||||
let start_event = Event::NewEvents(start_cause);
|
let start_event = Event::NewEvents(start_cause);
|
||||||
let events = iter::once(start_event).chain(events);
|
let events =
|
||||||
|
iter::once(EventWrapper::from(start_event)).chain(events.into_iter().map(Into::into));
|
||||||
self.run_until_cleared(events);
|
self.run_until_cleared(events);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the destroy-pending windows. This should only be called from
|
// Process the destroy-pending windows. This should only be called from
|
||||||
// `run_until_cleared` and `handle_scale_changed`, somewhere between emitting
|
// `run_until_cleared`, somewhere between emitting `NewEvents` and `MainEventsCleared`.
|
||||||
// `NewEvents` and `MainEventsCleared`.
|
|
||||||
fn process_destroy_pending_windows(&self, control: &mut ControlFlow) {
|
fn process_destroy_pending_windows(&self, control: &mut ControlFlow) {
|
||||||
while let Some(id) = self.0.destroy_pending.borrow_mut().pop_front() {
|
while let Some(id) = self.0.destroy_pending.borrow_mut().pop_front() {
|
||||||
self.0
|
self.0
|
||||||
|
@ -278,10 +294,10 @@ impl<T: 'static> Shared<T> {
|
||||||
// cleared
|
// cleared
|
||||||
//
|
//
|
||||||
// This will also process any events that have been queued or that are queued during processing
|
// This will also process any events that have been queued or that are queued during processing
|
||||||
fn run_until_cleared(&self, events: impl Iterator<Item = Event<'static, T>>) {
|
fn run_until_cleared<E: Into<EventWrapper<T>>>(&self, events: impl Iterator<Item = E>) {
|
||||||
let mut control = self.current_control_flow();
|
let mut control = self.current_control_flow();
|
||||||
for event in events {
|
for event in events {
|
||||||
self.handle_event(event, &mut control);
|
self.handle_event(event.into(), &mut control);
|
||||||
}
|
}
|
||||||
self.process_destroy_pending_windows(&mut control);
|
self.process_destroy_pending_windows(&mut control);
|
||||||
self.handle_event(Event::MainEventsCleared, &mut control);
|
self.handle_event(Event::MainEventsCleared, &mut control);
|
||||||
|
@ -301,85 +317,6 @@ impl<T: 'static> Shared<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_scale_changed(&self, old_scale: f64, new_scale: f64) {
|
|
||||||
// If there aren't any windows, then there is nothing to do here.
|
|
||||||
if self.0.all_canvases.borrow().is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let start_cause = match (self.0.runner.borrow().maybe_runner())
|
|
||||||
.unwrap_or_else(|| unreachable!("`scale_changed` should not happen without a runner"))
|
|
||||||
.maybe_start_cause()
|
|
||||||
{
|
|
||||||
Some(c) => c,
|
|
||||||
// If we're in the exit state, don't do event processing
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
let mut control = self.current_control_flow();
|
|
||||||
|
|
||||||
// Handle the start event and all other events in the queue.
|
|
||||||
self.handle_event(Event::NewEvents(start_cause), &mut control);
|
|
||||||
|
|
||||||
// It is possible for windows to be dropped before this point. We don't
|
|
||||||
// want to send `ScaleFactorChanged` for destroyed windows, so we process
|
|
||||||
// the destroy-pending windows here.
|
|
||||||
self.process_destroy_pending_windows(&mut control);
|
|
||||||
|
|
||||||
// Now handle the `ScaleFactorChanged` events.
|
|
||||||
for &(id, ref canvas) in &*self.0.all_canvases.borrow() {
|
|
||||||
let rc = match canvas.upgrade() {
|
|
||||||
Some(rc) => rc,
|
|
||||||
// This shouldn't happen, but just in case...
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
let canvas = rc.borrow();
|
|
||||||
// First, we send the `ScaleFactorChanged` event:
|
|
||||||
let current_size = canvas.size().get();
|
|
||||||
let logical_size = current_size.to_logical::<f64>(old_scale);
|
|
||||||
let mut new_size = logical_size.to_physical(new_scale);
|
|
||||||
self.handle_single_event_sync(
|
|
||||||
Event::WindowEvent {
|
|
||||||
window_id: id,
|
|
||||||
event: crate::event::WindowEvent::ScaleFactorChanged {
|
|
||||||
scale_factor: new_scale,
|
|
||||||
new_inner_size: &mut new_size,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&mut control,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Then we resize the canvas to the new size and send a `Resized` event:
|
|
||||||
if current_size != new_size {
|
|
||||||
backend::set_canvas_size(&canvas, crate::dpi::Size::Physical(new_size));
|
|
||||||
self.handle_single_event_sync(
|
|
||||||
Event::WindowEvent {
|
|
||||||
window_id: id,
|
|
||||||
event: crate::event::WindowEvent::Resized(new_size),
|
|
||||||
},
|
|
||||||
&mut control,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the destroy-pending windows again.
|
|
||||||
self.process_destroy_pending_windows(&mut control);
|
|
||||||
self.handle_event(Event::MainEventsCleared, &mut control);
|
|
||||||
|
|
||||||
// Discard all the pending redraw as we shall just redraw all windows.
|
|
||||||
self.0.redraw_pending.borrow_mut().clear();
|
|
||||||
for &(window_id, _) in &*self.0.all_canvases.borrow() {
|
|
||||||
self.handle_event(Event::RedrawRequested(window_id), &mut control);
|
|
||||||
}
|
|
||||||
self.handle_event(Event::RedrawEventsCleared, &mut control);
|
|
||||||
|
|
||||||
self.apply_control_flow(control);
|
|
||||||
// If the event loop is closed, it has been closed this iteration and now the closing
|
|
||||||
// event should be emitted
|
|
||||||
if self.is_closed() {
|
|
||||||
self.handle_loop_destroyed(&mut control);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_unload(&self) {
|
fn handle_unload(&self) {
|
||||||
self.apply_control_flow(ControlFlow::Exit);
|
self.apply_control_flow(ControlFlow::Exit);
|
||||||
let mut control = self.current_control_flow();
|
let mut control = self.current_control_flow();
|
||||||
|
@ -388,35 +325,20 @@ impl<T: 'static> Shared<T> {
|
||||||
self.handle_event(Event::LoopDestroyed, &mut control);
|
self.handle_event(Event::LoopDestroyed, &mut control);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle_single_event_sync takes in an event and handles it synchronously.
|
|
||||||
//
|
|
||||||
// It should only ever be called from `scale_changed`.
|
|
||||||
fn handle_single_event_sync(&self, event: Event<'_, T>, control: &mut ControlFlow) {
|
|
||||||
if self.is_closed() {
|
|
||||||
*control = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
match *self.0.runner.borrow_mut() {
|
|
||||||
RunnerEnum::Running(ref mut runner) => {
|
|
||||||
runner.handle_single_event(event, control);
|
|
||||||
}
|
|
||||||
_ => panic!("Cannot handle event synchronously without a runner"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle_event takes in events and either queues them or applies a callback
|
// handle_event takes in events and either queues them or applies a callback
|
||||||
//
|
//
|
||||||
// It should only ever be called from `run_until_cleared` and `scale_changed`.
|
// It should only ever be called from `run_until_cleared`.
|
||||||
fn handle_event(&self, event: Event<'static, T>, control: &mut ControlFlow) {
|
fn handle_event(&self, event: impl Into<EventWrapper<T>>, control: &mut ControlFlow) {
|
||||||
if self.is_closed() {
|
if self.is_closed() {
|
||||||
*control = ControlFlow::Exit;
|
*control = ControlFlow::Exit;
|
||||||
}
|
}
|
||||||
match *self.0.runner.borrow_mut() {
|
match *self.0.runner.borrow_mut() {
|
||||||
RunnerEnum::Running(ref mut runner) => {
|
RunnerEnum::Running(ref mut runner) => {
|
||||||
runner.handle_single_event(event, control);
|
runner.handle_single_event(self, event, control);
|
||||||
}
|
}
|
||||||
// If an event is being handled without a runner somehow, add it to the event queue so
|
// If an event is being handled without a runner somehow, add it to the event queue so
|
||||||
// it will eventually be processed
|
// it will eventually be processed
|
||||||
RunnerEnum::Pending => self.0.events.borrow_mut().push_back(event),
|
RunnerEnum::Pending => self.0.events.borrow_mut().push_back(event.into()),
|
||||||
// If the Runner has been destroyed, there is nothing to do.
|
// If the Runner has been destroyed, there is nothing to do.
|
||||||
RunnerEnum::Destroyed => return,
|
RunnerEnum::Destroyed => return,
|
||||||
}
|
}
|
||||||
|
@ -482,7 +404,6 @@ impl<T: 'static> Shared<T> {
|
||||||
fn handle_loop_destroyed(&self, control: &mut ControlFlow) {
|
fn handle_loop_destroyed(&self, control: &mut ControlFlow) {
|
||||||
self.handle_event(Event::LoopDestroyed, control);
|
self.handle_event(Event::LoopDestroyed, control);
|
||||||
let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut());
|
let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut());
|
||||||
*self.0.scale_change_detector.borrow_mut() = None;
|
|
||||||
*self.0.unload_event_handle.borrow_mut() = None;
|
*self.0.unload_event_handle.borrow_mut() = None;
|
||||||
// Dropping the `Runner` drops the event handler closure, which will in
|
// Dropping the `Runner` drops the event handler closure, which will in
|
||||||
// turn drop all `Window`s moved into the closure.
|
// turn drop all `Window`s moved into the closure.
|
||||||
|
@ -530,3 +451,18 @@ impl<T: 'static> Shared<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) enum EventWrapper<T: 'static> {
|
||||||
|
Event(Event<'static, T>),
|
||||||
|
ScaleChange {
|
||||||
|
canvas: Weak<RefCell<backend::Canvas>>,
|
||||||
|
size: PhysicalSize<u32>,
|
||||||
|
scale: f64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Event<'static, T>> for EventWrapper<T> {
|
||||||
|
fn from(value: Event<'static, T>) -> Self {
|
||||||
|
Self::Event(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use raw_window_handle::{RawDisplayHandle, WebDisplayHandle};
|
use raw_window_handle::{RawDisplayHandle, WebDisplayHandle};
|
||||||
|
|
||||||
|
use super::runner::EventWrapper;
|
||||||
use super::{
|
use super::{
|
||||||
super::{monitor::MonitorHandle, KeyEventExtra},
|
super::{monitor::MonitorHandle, KeyEventExtra},
|
||||||
backend,
|
backend,
|
||||||
|
@ -16,7 +17,6 @@ use super::{
|
||||||
runner,
|
runner,
|
||||||
window::WindowId,
|
window::WindowId,
|
||||||
};
|
};
|
||||||
use crate::dpi::Size;
|
|
||||||
use crate::event::{
|
use crate::event::{
|
||||||
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase,
|
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase,
|
||||||
WindowEvent,
|
WindowEvent,
|
||||||
|
@ -71,10 +71,6 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
|
|
||||||
pub fn run(&self, event_handler: Box<runner::EventHandler<T>>) {
|
pub fn run(&self, event_handler: Box<runner::EventHandler<T>>) {
|
||||||
self.runner.set_listener(event_handler);
|
self.runner.set_listener(event_handler);
|
||||||
let runner = self.runner.clone();
|
|
||||||
self.runner.set_on_scale_change(move |arg| {
|
|
||||||
runner.handle_scale_changed(arg.old_scale, arg.new_scale)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_id(&self) -> WindowId {
|
pub fn generate_id(&self) -> WindowId {
|
||||||
|
@ -595,35 +591,6 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
prevent_default,
|
prevent_default,
|
||||||
);
|
);
|
||||||
|
|
||||||
// The size to restore to after exiting fullscreen.
|
|
||||||
let mut intended_size = canvas.size().get();
|
|
||||||
|
|
||||||
canvas.on_fullscreen_change({
|
|
||||||
let window = self.runner.window().clone();
|
|
||||||
let runner = self.runner.clone();
|
|
||||||
|
|
||||||
move || {
|
|
||||||
let canvas = canvas_clone.borrow();
|
|
||||||
|
|
||||||
// If the canvas is marked as fullscreen, it is moving *into* fullscreen
|
|
||||||
// If it is not, it is moving *out of* fullscreen
|
|
||||||
let new_size = if backend::is_fullscreen(&window, canvas.raw()) {
|
|
||||||
intended_size = canvas.size().get();
|
|
||||||
|
|
||||||
backend::window_size(&window).to_physical(backend::scale_factor(&window))
|
|
||||||
} else {
|
|
||||||
intended_size
|
|
||||||
};
|
|
||||||
|
|
||||||
backend::set_canvas_size(&canvas, Size::Physical(new_size));
|
|
||||||
runner.send_event(Event::WindowEvent {
|
|
||||||
window_id: RootWindowId(id),
|
|
||||||
event: WindowEvent::Resized(new_size),
|
|
||||||
});
|
|
||||||
runner.request_redraw(RootWindowId(id));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let runner = self.runner.clone();
|
let runner = self.runner.clone();
|
||||||
canvas.on_touch_cancel(move |device_id, location, force| {
|
canvas.on_touch_cancel(move |device_id, location, force| {
|
||||||
runner.send_event(Event::WindowEvent {
|
runner.send_event(Event::WindowEvent {
|
||||||
|
@ -650,6 +617,37 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
event: WindowEvent::ThemeChanged(theme),
|
event: WindowEvent::ThemeChanged(theme),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
canvas.on_resize_scale(
|
||||||
|
{
|
||||||
|
let runner = self.runner.clone();
|
||||||
|
let canvas = canvas_clone.clone();
|
||||||
|
|
||||||
|
move |size, scale| {
|
||||||
|
runner.send_event(EventWrapper::ScaleChange {
|
||||||
|
canvas: Rc::downgrade(&canvas),
|
||||||
|
size,
|
||||||
|
scale,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
let runner = self.runner.clone();
|
||||||
|
|
||||||
|
move |new_size| {
|
||||||
|
let canvas = RefCell::borrow(&canvas_clone);
|
||||||
|
canvas.set_current_size(new_size);
|
||||||
|
if canvas.old_size() != new_size {
|
||||||
|
canvas.set_old_size(new_size);
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: RootWindowId(id),
|
||||||
|
event: WindowEvent::Resized(new_size),
|
||||||
|
});
|
||||||
|
runner.request_redraw(RootWindowId(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn available_monitors(&self) -> VecDequeIter<MonitorHandle> {
|
pub fn available_monitors(&self) -> VecDequeIter<MonitorHandle> {
|
||||||
|
|
|
@ -39,9 +39,3 @@ pub use self::window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId
|
||||||
pub(crate) use self::keyboard::KeyEventExtra;
|
pub(crate) use self::keyboard::KeyEventExtra;
|
||||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||||
pub(self) use crate::platform_impl::Fullscreen;
|
pub(self) use crate::platform_impl::Fullscreen;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub(crate) struct ScaleChangeArgs {
|
|
||||||
old_scale: f64,
|
|
||||||
new_scale: f64,
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
|
use super::super::WindowId;
|
||||||
use super::event_handle::EventListenerHandle;
|
use super::event_handle::EventListenerHandle;
|
||||||
use super::media_query_handle::MediaQueryListHandle;
|
use super::media_query_handle::MediaQueryListHandle;
|
||||||
use super::pointer::PointerHandler;
|
use super::pointer::PointerHandler;
|
||||||
use super::{event, ButtonsState};
|
use super::{event, ButtonsState, ResizeScaleHandle};
|
||||||
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
|
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
|
||||||
use crate::error::OsError as RootOE;
|
use crate::error::OsError as RootOE;
|
||||||
use crate::event::{Force, MouseButton, MouseScrollDelta};
|
use crate::event::{Force, MouseButton, MouseScrollDelta};
|
||||||
use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState};
|
use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState};
|
||||||
use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes};
|
use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes};
|
||||||
use crate::window::WindowAttributes;
|
use crate::window::{WindowAttributes, WindowId as RootWindowId};
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -22,6 +23,7 @@ use web_sys::{Event, FocusEvent, HtmlCanvasElement, KeyboardEvent, WheelEvent};
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct Canvas {
|
pub struct Canvas {
|
||||||
common: Common,
|
common: Common,
|
||||||
|
id: WindowId,
|
||||||
on_touch_start: Option<EventListenerHandle<dyn FnMut(Event)>>,
|
on_touch_start: Option<EventListenerHandle<dyn FnMut(Event)>>,
|
||||||
on_touch_end: Option<EventListenerHandle<dyn FnMut(Event)>>,
|
on_touch_end: Option<EventListenerHandle<dyn FnMut(Event)>>,
|
||||||
on_focus: Option<EventListenerHandle<dyn FnMut(FocusEvent)>>,
|
on_focus: Option<EventListenerHandle<dyn FnMut(FocusEvent)>>,
|
||||||
|
@ -29,21 +31,23 @@ pub struct Canvas {
|
||||||
on_keyboard_release: Option<EventListenerHandle<dyn FnMut(KeyboardEvent)>>,
|
on_keyboard_release: Option<EventListenerHandle<dyn FnMut(KeyboardEvent)>>,
|
||||||
on_keyboard_press: Option<EventListenerHandle<dyn FnMut(KeyboardEvent)>>,
|
on_keyboard_press: Option<EventListenerHandle<dyn FnMut(KeyboardEvent)>>,
|
||||||
on_mouse_wheel: Option<EventListenerHandle<dyn FnMut(WheelEvent)>>,
|
on_mouse_wheel: Option<EventListenerHandle<dyn FnMut(WheelEvent)>>,
|
||||||
on_fullscreen_change: Option<EventListenerHandle<dyn FnMut(Event)>>,
|
|
||||||
on_dark_mode: Option<MediaQueryListHandle>,
|
on_dark_mode: Option<MediaQueryListHandle>,
|
||||||
pointer_handler: PointerHandler,
|
pointer_handler: PointerHandler,
|
||||||
|
on_resize_scale: Option<ResizeScaleHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Common {
|
pub struct Common {
|
||||||
pub window: web_sys::Window,
|
pub window: web_sys::Window,
|
||||||
/// Note: resizing the HTMLCanvasElement should go through `backend::set_canvas_size` to ensure the DPI factor is maintained.
|
/// Note: resizing the HTMLCanvasElement should go through `backend::set_canvas_size` to ensure the DPI factor is maintained.
|
||||||
pub raw: HtmlCanvasElement,
|
pub raw: HtmlCanvasElement,
|
||||||
size: Rc<Cell<PhysicalSize<u32>>>,
|
old_size: Rc<Cell<PhysicalSize<u32>>>,
|
||||||
|
current_size: Rc<Cell<PhysicalSize<u32>>>,
|
||||||
wants_fullscreen: Rc<RefCell<bool>>,
|
wants_fullscreen: Rc<RefCell<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Canvas {
|
impl Canvas {
|
||||||
pub fn create(
|
pub fn create(
|
||||||
|
id: WindowId,
|
||||||
window: web_sys::Window,
|
window: web_sys::Window,
|
||||||
attr: &WindowAttributes,
|
attr: &WindowAttributes,
|
||||||
platform_attr: PlatformSpecificWindowBuilderAttributes,
|
platform_attr: PlatformSpecificWindowBuilderAttributes,
|
||||||
|
@ -73,24 +77,20 @@ impl Canvas {
|
||||||
.map_err(|_| os_error!(OsError("Failed to set a tabindex".to_owned())))?;
|
.map_err(|_| os_error!(OsError("Failed to set a tabindex".to_owned())))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = attr
|
if let Some(size) = attr.inner_size {
|
||||||
.inner_size
|
let size = size.to_logical(super::scale_factor(&window));
|
||||||
.unwrap_or(
|
super::set_canvas_size(&window, &canvas, size);
|
||||||
LogicalSize {
|
|
||||||
width: 1024.0,
|
|
||||||
height: 768.0,
|
|
||||||
}
|
}
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
.to_physical(super::scale_factor(&window));
|
|
||||||
|
|
||||||
let canvas = Canvas {
|
Ok(Canvas {
|
||||||
common: Common {
|
common: Common {
|
||||||
window,
|
window,
|
||||||
raw: canvas,
|
raw: canvas,
|
||||||
size: Rc::new(Cell::new(size)),
|
old_size: Rc::default(),
|
||||||
|
current_size: Rc::default(),
|
||||||
wants_fullscreen: Rc::new(RefCell::new(false)),
|
wants_fullscreen: Rc::new(RefCell::new(false)),
|
||||||
},
|
},
|
||||||
|
id,
|
||||||
on_touch_start: None,
|
on_touch_start: None,
|
||||||
on_touch_end: None,
|
on_touch_end: None,
|
||||||
on_blur: None,
|
on_blur: None,
|
||||||
|
@ -98,14 +98,10 @@ impl Canvas {
|
||||||
on_keyboard_release: None,
|
on_keyboard_release: None,
|
||||||
on_keyboard_press: None,
|
on_keyboard_press: None,
|
||||||
on_mouse_wheel: None,
|
on_mouse_wheel: None,
|
||||||
on_fullscreen_change: None,
|
|
||||||
on_dark_mode: None,
|
on_dark_mode: None,
|
||||||
pointer_handler: PointerHandler::new(),
|
pointer_handler: PointerHandler::new(),
|
||||||
};
|
on_resize_scale: None,
|
||||||
|
})
|
||||||
super::set_canvas_size(&canvas, size.into());
|
|
||||||
|
|
||||||
Ok(canvas)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cursor_lock(&self, lock: bool) -> Result<(), RootOE> {
|
pub fn set_cursor_lock(&self, lock: bool) -> Result<(), RootOE> {
|
||||||
|
@ -138,12 +134,24 @@ impl Canvas {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window(&self) -> &web_sys::Window {
|
pub fn old_size(&self) -> PhysicalSize<u32> {
|
||||||
&self.common.window
|
self.common.old_size.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> &Rc<Cell<PhysicalSize<u32>>> {
|
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
||||||
&self.common.size
|
self.common.current_size.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_old_size(&self, size: PhysicalSize<u32>) {
|
||||||
|
self.common.old_size.set(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_current_size(&self, size: PhysicalSize<u32>) {
|
||||||
|
self.common.current_size.set(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window(&self) -> &web_sys::Window {
|
||||||
|
&self.common.window
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw(&self) -> &HtmlCanvasElement {
|
pub fn raw(&self) -> &HtmlCanvasElement {
|
||||||
|
@ -329,16 +337,6 @@ impl Canvas {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_fullscreen_change<F>(&mut self, mut handler: F)
|
|
||||||
where
|
|
||||||
F: 'static + FnMut(),
|
|
||||||
{
|
|
||||||
self.on_fullscreen_change = Some(
|
|
||||||
self.common
|
|
||||||
.add_event("fullscreenchange", move |_: Event| handler()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn on_dark_mode<F>(&mut self, mut handler: F)
|
pub fn on_dark_mode<F>(&mut self, mut handler: F)
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(bool),
|
F: 'static + FnMut(bool),
|
||||||
|
@ -350,6 +348,19 @@ impl Canvas {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn on_resize_scale<S, R>(&mut self, scale_handler: S, size_handler: R)
|
||||||
|
where
|
||||||
|
S: 'static + FnMut(PhysicalSize<u32>, f64),
|
||||||
|
R: 'static + FnMut(PhysicalSize<u32>),
|
||||||
|
{
|
||||||
|
self.on_resize_scale = Some(ResizeScaleHandle::new(
|
||||||
|
self.window().clone(),
|
||||||
|
self.raw().clone(),
|
||||||
|
scale_handler,
|
||||||
|
size_handler,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn request_fullscreen(&self) {
|
pub fn request_fullscreen(&self) {
|
||||||
self.common.request_fullscreen()
|
self.common.request_fullscreen()
|
||||||
}
|
}
|
||||||
|
@ -358,15 +369,54 @@ impl Canvas {
|
||||||
self.common.is_fullscreen()
|
self.common.is_fullscreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn handle_scale_change<T: 'static>(
|
||||||
|
&self,
|
||||||
|
runner: &super::super::event_loop::runner::Shared<T>,
|
||||||
|
event_handler: impl FnOnce(crate::event::Event<'_, T>),
|
||||||
|
current_size: PhysicalSize<u32>,
|
||||||
|
scale: f64,
|
||||||
|
) {
|
||||||
|
// First, we send the `ScaleFactorChanged` event:
|
||||||
|
self.set_current_size(current_size);
|
||||||
|
let mut new_size = current_size;
|
||||||
|
event_handler(crate::event::Event::WindowEvent {
|
||||||
|
window_id: RootWindowId(self.id),
|
||||||
|
event: crate::event::WindowEvent::ScaleFactorChanged {
|
||||||
|
scale_factor: scale,
|
||||||
|
new_inner_size: &mut new_size,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if current_size != new_size {
|
||||||
|
// Then we resize the canvas to the new size, a new
|
||||||
|
// `Resized` event will be sent by the `ResizeObserver`:
|
||||||
|
let new_size = new_size.to_logical(scale);
|
||||||
|
super::set_canvas_size(self.window(), self.raw(), new_size);
|
||||||
|
|
||||||
|
// Set the size might not trigger the event because the calculation is inaccurate.
|
||||||
|
self.on_resize_scale
|
||||||
|
.as_ref()
|
||||||
|
.expect("expected Window to still be active")
|
||||||
|
.notify_resize();
|
||||||
|
} else if self.old_size() != new_size {
|
||||||
|
// Then we at least send a resized event.
|
||||||
|
self.set_old_size(new_size);
|
||||||
|
runner.send_event(crate::event::Event::WindowEvent {
|
||||||
|
window_id: RootWindowId(self.id),
|
||||||
|
event: crate::event::WindowEvent::Resized(new_size),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_listeners(&mut self) {
|
pub fn remove_listeners(&mut self) {
|
||||||
self.on_focus = None;
|
self.on_focus = None;
|
||||||
self.on_blur = None;
|
self.on_blur = None;
|
||||||
self.on_keyboard_release = None;
|
self.on_keyboard_release = None;
|
||||||
self.on_keyboard_press = None;
|
self.on_keyboard_press = None;
|
||||||
self.on_mouse_wheel = None;
|
self.on_mouse_wheel = None;
|
||||||
self.on_fullscreen_change = None;
|
|
||||||
self.on_dark_mode = None;
|
self.on_dark_mode = None;
|
||||||
self.pointer_handler.remove_listeners()
|
self.pointer_handler.remove_listeners();
|
||||||
|
self.on_resize_scale = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,19 +3,19 @@ mod event;
|
||||||
mod event_handle;
|
mod event_handle;
|
||||||
mod media_query_handle;
|
mod media_query_handle;
|
||||||
mod pointer;
|
mod pointer;
|
||||||
mod scaling;
|
mod resize_scaling;
|
||||||
mod timeout;
|
mod timeout;
|
||||||
|
|
||||||
pub use self::canvas::Canvas;
|
pub use self::canvas::Canvas;
|
||||||
pub use self::event::ButtonsState;
|
pub use self::event::ButtonsState;
|
||||||
pub use self::scaling::ScaleChangeDetector;
|
pub use self::resize_scaling::ResizeScaleHandle;
|
||||||
pub use self::timeout::{IdleCallback, Timeout};
|
pub use self::timeout::{IdleCallback, Timeout};
|
||||||
|
|
||||||
use crate::dpi::{LogicalSize, Size};
|
use crate::dpi::LogicalSize;
|
||||||
use crate::platform::web::WindowExtWebSys;
|
use crate::platform::web::WindowExtWebSys;
|
||||||
use crate::window::Window;
|
use crate::window::Window;
|
||||||
use wasm_bindgen::closure::Closure;
|
use wasm_bindgen::closure::Closure;
|
||||||
use web_sys::{Element, HtmlCanvasElement};
|
use web_sys::{CssStyleDeclaration, Element, HtmlCanvasElement};
|
||||||
|
|
||||||
pub fn throw(msg: &str) {
|
pub fn throw(msg: &str) {
|
||||||
wasm_bindgen::throw_str(msg);
|
wasm_bindgen::throw_str(msg);
|
||||||
|
@ -52,38 +52,52 @@ impl WindowExtWebSys for Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_size(window: &web_sys::Window) -> LogicalSize<f64> {
|
|
||||||
let width = window
|
|
||||||
.inner_width()
|
|
||||||
.expect("Failed to get width")
|
|
||||||
.as_f64()
|
|
||||||
.expect("Failed to get width as f64");
|
|
||||||
let height = window
|
|
||||||
.inner_height()
|
|
||||||
.expect("Failed to get height")
|
|
||||||
.as_f64()
|
|
||||||
.expect("Failed to get height as f64");
|
|
||||||
|
|
||||||
LogicalSize { width, height }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scale_factor(window: &web_sys::Window) -> f64 {
|
pub fn scale_factor(window: &web_sys::Window) -> f64 {
|
||||||
window.device_pixel_ratio()
|
window.device_pixel_ratio()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_canvas_size(canvas: &Canvas, new_size: Size) {
|
pub fn set_canvas_size(
|
||||||
let scale_factor = scale_factor(canvas.window());
|
window: &web_sys::Window,
|
||||||
|
raw: &HtmlCanvasElement,
|
||||||
|
mut new_size: LogicalSize<f64>,
|
||||||
|
) {
|
||||||
|
let document = window.document().expect("Failed to obtain document");
|
||||||
|
|
||||||
let physical_size = new_size.to_physical(scale_factor);
|
let style = window
|
||||||
canvas.size().set(physical_size);
|
.get_computed_style(raw)
|
||||||
|
.expect("Failed to obtain computed style")
|
||||||
|
// this can't fail: we aren't using a pseudo-element
|
||||||
|
.expect("Invalid pseudo-element");
|
||||||
|
|
||||||
let logical_size = new_size.to_logical::<f64>(scale_factor);
|
if !document.contains(Some(raw)) || style.get_property_value("display").unwrap() == "none" {
|
||||||
set_canvas_style_property(canvas.raw(), "width", &format!("{}px", logical_size.width));
|
return;
|
||||||
set_canvas_style_property(
|
}
|
||||||
canvas.raw(),
|
|
||||||
"height",
|
if style.get_property_value("box-sizing").unwrap() == "border-box" {
|
||||||
&format!("{}px", logical_size.height),
|
new_size.width += style_size_property(&style, "border-left-width")
|
||||||
);
|
+ style_size_property(&style, "border-right-width")
|
||||||
|
+ style_size_property(&style, "padding-left")
|
||||||
|
+ style_size_property(&style, "padding-right");
|
||||||
|
new_size.height += style_size_property(&style, "border-top-width")
|
||||||
|
+ style_size_property(&style, "border-bottom-width")
|
||||||
|
+ style_size_property(&style, "padding-top")
|
||||||
|
+ style_size_property(&style, "padding-bottom");
|
||||||
|
}
|
||||||
|
|
||||||
|
set_canvas_style_property(raw, "width", &format!("{}px", new_size.width));
|
||||||
|
set_canvas_style_property(raw, "height", &format!("{}px", new_size.height));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function will panic if the element is not inserted in the DOM
|
||||||
|
/// or is not a CSS property that represents a size in pixel.
|
||||||
|
pub fn style_size_property(style: &CssStyleDeclaration, property: &str) -> f64 {
|
||||||
|
let prop = style
|
||||||
|
.get_property_value(property)
|
||||||
|
.expect("Found invalid property");
|
||||||
|
prop.strip_suffix("px")
|
||||||
|
.expect("Element was not inserted into the DOM or is not a size in pixel")
|
||||||
|
.parse()
|
||||||
|
.expect("CSS property is not a size in pixel")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_canvas_style_property(raw: &HtmlCanvasElement, property: &str, value: &str) {
|
pub fn set_canvas_style_property(raw: &HtmlCanvasElement, property: &str, value: &str) {
|
||||||
|
|
321
src/platform_impl/web/web_sys/resize_scaling.rs
Normal file
321
src/platform_impl/web/web_sys/resize_scaling.rs
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
use js_sys::{Array, Object};
|
||||||
|
use once_cell::unsync::Lazy;
|
||||||
|
use wasm_bindgen::prelude::{wasm_bindgen, Closure};
|
||||||
|
use wasm_bindgen::{JsCast, JsValue};
|
||||||
|
use web_sys::{
|
||||||
|
HtmlCanvasElement, MediaQueryList, ResizeObserver, ResizeObserverBoxOptions,
|
||||||
|
ResizeObserverEntry, ResizeObserverOptions, ResizeObserverSize, Window,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::dpi::{LogicalSize, PhysicalSize};
|
||||||
|
|
||||||
|
use super::super::backend;
|
||||||
|
use super::media_query_handle::MediaQueryListHandle;
|
||||||
|
|
||||||
|
use std::cell::{Cell, RefCell};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct ResizeScaleHandle(Rc<RefCell<ResizeScaleInternal>>);
|
||||||
|
|
||||||
|
impl ResizeScaleHandle {
|
||||||
|
pub(crate) fn new<S, R>(
|
||||||
|
window: Window,
|
||||||
|
canvas: HtmlCanvasElement,
|
||||||
|
scale_handler: S,
|
||||||
|
resize_handler: R,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
S: 'static + FnMut(PhysicalSize<u32>, f64),
|
||||||
|
R: 'static + FnMut(PhysicalSize<u32>),
|
||||||
|
{
|
||||||
|
Self(ResizeScaleInternal::new(
|
||||||
|
window,
|
||||||
|
canvas,
|
||||||
|
scale_handler,
|
||||||
|
resize_handler,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn notify_resize(&self) {
|
||||||
|
self.0.borrow_mut().notify()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is a helper type to help manage the `MediaQueryList` used for detecting
|
||||||
|
/// changes of the `devicePixelRatio`.
|
||||||
|
struct ResizeScaleInternal {
|
||||||
|
window: Window,
|
||||||
|
canvas: HtmlCanvasElement,
|
||||||
|
mql: MediaQueryListHandle,
|
||||||
|
observer: ResizeObserver,
|
||||||
|
_observer_closure: Closure<dyn FnMut(Array, ResizeObserver)>,
|
||||||
|
scale_handler: Box<dyn FnMut(PhysicalSize<u32>, f64)>,
|
||||||
|
resize_handler: Box<dyn FnMut(PhysicalSize<u32>)>,
|
||||||
|
notify_scale: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResizeScaleInternal {
|
||||||
|
fn new<S, R>(
|
||||||
|
window: Window,
|
||||||
|
canvas: HtmlCanvasElement,
|
||||||
|
scale_handler: S,
|
||||||
|
resize_handler: R,
|
||||||
|
) -> Rc<RefCell<Self>>
|
||||||
|
where
|
||||||
|
S: 'static + FnMut(PhysicalSize<u32>, f64),
|
||||||
|
R: 'static + FnMut(PhysicalSize<u32>),
|
||||||
|
{
|
||||||
|
Rc::<RefCell<ResizeScaleInternal>>::new_cyclic(|weak_self| {
|
||||||
|
let mql = Self::create_mql(&window, {
|
||||||
|
let weak_self = weak_self.clone();
|
||||||
|
move |mql| {
|
||||||
|
if let Some(rc_self) = weak_self.upgrade() {
|
||||||
|
Self::handle_scale(rc_self, mql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let weak_self = weak_self.clone();
|
||||||
|
let observer_closure = Closure::new(move |entries: Array, _| {
|
||||||
|
if let Some(rc_self) = weak_self.upgrade() {
|
||||||
|
let mut this = rc_self.borrow_mut();
|
||||||
|
|
||||||
|
let size = Self::process_entry(&this.window, &this.canvas, entries);
|
||||||
|
|
||||||
|
if this.notify_scale.replace(false) {
|
||||||
|
let scale = backend::scale_factor(&this.window);
|
||||||
|
(this.scale_handler)(size, scale)
|
||||||
|
} else {
|
||||||
|
(this.resize_handler)(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let observer = Self::create_observer(&canvas, observer_closure.as_ref());
|
||||||
|
|
||||||
|
RefCell::new(Self {
|
||||||
|
window,
|
||||||
|
canvas,
|
||||||
|
mql,
|
||||||
|
observer,
|
||||||
|
_observer_closure: observer_closure,
|
||||||
|
scale_handler: Box::new(scale_handler),
|
||||||
|
resize_handler: Box::new(resize_handler),
|
||||||
|
notify_scale: Cell::new(false),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_mql<F>(window: &Window, closure: F) -> MediaQueryListHandle
|
||||||
|
where
|
||||||
|
F: 'static + FnMut(&MediaQueryList),
|
||||||
|
{
|
||||||
|
let current_scale = super::scale_factor(window);
|
||||||
|
// TODO: Remove `-webkit-device-pixel-ratio`. Requires Safari v16.
|
||||||
|
let media_query = format!(
|
||||||
|
"(resolution: {current_scale}dppx),
|
||||||
|
(-webkit-device-pixel-ratio: {current_scale})",
|
||||||
|
);
|
||||||
|
let mql = MediaQueryListHandle::new(window, &media_query, closure);
|
||||||
|
assert!(
|
||||||
|
mql.mql().matches(),
|
||||||
|
"created media query doesn't match, {current_scale} != {}",
|
||||||
|
super::scale_factor(window)
|
||||||
|
);
|
||||||
|
mql
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_observer(canvas: &HtmlCanvasElement, closure: &JsValue) -> ResizeObserver {
|
||||||
|
let observer = ResizeObserver::new(closure.as_ref().unchecked_ref())
|
||||||
|
.expect("Failed to create `ResizeObserver`");
|
||||||
|
|
||||||
|
// Safari doesn't support `devicePixelContentBoxSize`
|
||||||
|
if has_device_pixel_support() {
|
||||||
|
observer.observe_with_options(
|
||||||
|
canvas,
|
||||||
|
ResizeObserverOptions::new().box_(ResizeObserverBoxOptions::DevicePixelContentBox),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
observer.observe(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
observer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn notify(&mut self) {
|
||||||
|
let style = self
|
||||||
|
.window
|
||||||
|
.get_computed_style(&self.canvas)
|
||||||
|
.expect("Failed to obtain computed style")
|
||||||
|
// this can't fail: we aren't using a pseudo-element
|
||||||
|
.expect("Invalid pseudo-element");
|
||||||
|
|
||||||
|
let document = self.window.document().expect("Failed to obtain document");
|
||||||
|
|
||||||
|
if !document.contains(Some(&self.canvas))
|
||||||
|
|| style.get_property_value("display").unwrap() == "none"
|
||||||
|
{
|
||||||
|
let size = PhysicalSize::new(0, 0);
|
||||||
|
|
||||||
|
if self.notify_scale.replace(false) {
|
||||||
|
let scale = backend::scale_factor(&self.window);
|
||||||
|
(self.scale_handler)(size, scale)
|
||||||
|
} else {
|
||||||
|
(self.resize_handler)(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safari doesn't support `devicePixelContentBoxSize`
|
||||||
|
if has_device_pixel_support() {
|
||||||
|
self.observer.unobserve(&self.canvas);
|
||||||
|
self.observer.observe(&self.canvas);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut size = LogicalSize::new(
|
||||||
|
backend::style_size_property(&style, "width"),
|
||||||
|
backend::style_size_property(&style, "height"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if style.get_property_value("box-sizing").unwrap() == "border-box" {
|
||||||
|
size.width -= backend::style_size_property(&style, "border-left-width")
|
||||||
|
+ backend::style_size_property(&style, "border-right-width")
|
||||||
|
+ backend::style_size_property(&style, "padding-left")
|
||||||
|
+ backend::style_size_property(&style, "padding-right");
|
||||||
|
size.height -= backend::style_size_property(&style, "border-top-width")
|
||||||
|
+ backend::style_size_property(&style, "border-bottom-width")
|
||||||
|
+ backend::style_size_property(&style, "padding-top")
|
||||||
|
+ backend::style_size_property(&style, "padding-bottom");
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = size.to_physical(backend::scale_factor(&self.window));
|
||||||
|
|
||||||
|
if self.notify_scale.replace(false) {
|
||||||
|
let scale = backend::scale_factor(&self.window);
|
||||||
|
(self.scale_handler)(size, scale)
|
||||||
|
} else {
|
||||||
|
(self.resize_handler)(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scale(this: Rc<RefCell<Self>>, mql: &MediaQueryList) {
|
||||||
|
let weak_self = Rc::downgrade(&this);
|
||||||
|
let mut this = this.borrow_mut();
|
||||||
|
let scale = super::scale_factor(&this.window);
|
||||||
|
|
||||||
|
// TODO: confirm/reproduce this problem, see:
|
||||||
|
// <https://github.com/rust-windowing/winit/issues/2597>.
|
||||||
|
// This should never happen, but if it does then apparently the scale factor didn't change.
|
||||||
|
if mql.matches() {
|
||||||
|
warn!(
|
||||||
|
"media query tracking scale factor was triggered without a change:\n\
|
||||||
|
Media Query: {}\n\
|
||||||
|
Current Scale: {scale}",
|
||||||
|
mql.media(),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_mql = Self::create_mql(&this.window, move |mql| {
|
||||||
|
if let Some(rc_self) = weak_self.upgrade() {
|
||||||
|
Self::handle_scale(rc_self, mql);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.mql = new_mql;
|
||||||
|
|
||||||
|
this.notify_scale.set(true);
|
||||||
|
this.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_entry(
|
||||||
|
window: &Window,
|
||||||
|
canvas: &HtmlCanvasElement,
|
||||||
|
entries: Array,
|
||||||
|
) -> PhysicalSize<u32> {
|
||||||
|
let entry: ResizeObserverEntry = entries.get(0).unchecked_into();
|
||||||
|
|
||||||
|
// Safari doesn't support `devicePixelContentBoxSize`
|
||||||
|
if !has_device_pixel_support() {
|
||||||
|
let rect = entry.content_rect();
|
||||||
|
|
||||||
|
return LogicalSize::new(rect.width(), rect.height())
|
||||||
|
.to_physical(backend::scale_factor(window));
|
||||||
|
}
|
||||||
|
|
||||||
|
let entry: ResizeObserverSize = entry
|
||||||
|
.device_pixel_content_box_size()
|
||||||
|
.get(0)
|
||||||
|
.unchecked_into();
|
||||||
|
|
||||||
|
let style = window
|
||||||
|
.get_computed_style(canvas)
|
||||||
|
.expect("Failed to get computed style of canvas")
|
||||||
|
// this can only be empty if we provided an invalid `pseudoElt`
|
||||||
|
.expect("`getComputedStyle` can not be empty");
|
||||||
|
|
||||||
|
let writing_mode = style
|
||||||
|
.get_property_value("writing-mode")
|
||||||
|
.expect("`wirting-mode` is a valid CSS property");
|
||||||
|
|
||||||
|
// means the canvas is not inserted into the DOM
|
||||||
|
if writing_mode.is_empty() {
|
||||||
|
debug_assert_eq!(entry.inline_size(), 0.);
|
||||||
|
debug_assert_eq!(entry.block_size(), 0.);
|
||||||
|
|
||||||
|
return PhysicalSize::new(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let horizontal = match writing_mode.as_str() {
|
||||||
|
_ if writing_mode.starts_with("horizontal") => true,
|
||||||
|
_ if writing_mode.starts_with("vertical") | writing_mode.starts_with("sideways") => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
// deprecated values
|
||||||
|
"lr" | "lr-tb" | "rl" => true,
|
||||||
|
"tb" | "tb-lr" | "tb-rl" => false,
|
||||||
|
_ => {
|
||||||
|
warn!("unrecognized `writing-mode`, assuming horizontal");
|
||||||
|
true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if horizontal {
|
||||||
|
PhysicalSize::new(entry.inline_size() as u32, entry.block_size() as u32)
|
||||||
|
} else {
|
||||||
|
PhysicalSize::new(entry.block_size() as u32, entry.inline_size() as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ResizeScaleInternal {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.observer.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove when Safari supports `devicePixelContentBoxSize`.
|
||||||
|
// See <https://bugs.webkit.org/show_bug.cgi?id=219005>.
|
||||||
|
pub fn has_device_pixel_support() -> bool {
|
||||||
|
thread_local! {
|
||||||
|
static DEVICE_PIXEL_SUPPORT: Lazy<bool> = Lazy::new(|| {
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
type ResizeObserverEntryExt;
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_class = ResizeObserverEntry, static_method_of = ResizeObserverEntryExt, getter)]
|
||||||
|
fn prototype() -> Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prototype = ResizeObserverEntryExt::prototype();
|
||||||
|
let descriptor = Object::get_own_property_descriptor(
|
||||||
|
&prototype,
|
||||||
|
&JsValue::from_str("devicePixelContentBoxSize"),
|
||||||
|
);
|
||||||
|
!descriptor.is_undefined()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVICE_PIXEL_SUPPORT.with(|support| **support)
|
||||||
|
}
|
|
@ -1,102 +0,0 @@
|
||||||
use web_sys::MediaQueryList;
|
|
||||||
|
|
||||||
use super::super::ScaleChangeArgs;
|
|
||||||
use super::media_query_handle::MediaQueryListHandle;
|
|
||||||
|
|
||||||
use std::{cell::RefCell, rc::Rc};
|
|
||||||
|
|
||||||
pub struct ScaleChangeDetector(Rc<RefCell<ScaleChangeDetectorInternal>>);
|
|
||||||
|
|
||||||
impl ScaleChangeDetector {
|
|
||||||
pub(crate) fn new<F>(window: web_sys::Window, handler: F) -> Self
|
|
||||||
where
|
|
||||||
F: 'static + FnMut(ScaleChangeArgs),
|
|
||||||
{
|
|
||||||
Self(ScaleChangeDetectorInternal::new(window, handler))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This is a helper type to help manage the `MediaQueryList` used for detecting
|
|
||||||
/// changes of the `devicePixelRatio`.
|
|
||||||
struct ScaleChangeDetectorInternal {
|
|
||||||
window: web_sys::Window,
|
|
||||||
callback: Box<dyn FnMut(ScaleChangeArgs)>,
|
|
||||||
mql: MediaQueryListHandle,
|
|
||||||
last_scale: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ScaleChangeDetectorInternal {
|
|
||||||
fn new<F>(window: web_sys::Window, handler: F) -> Rc<RefCell<Self>>
|
|
||||||
where
|
|
||||||
F: 'static + FnMut(ScaleChangeArgs),
|
|
||||||
{
|
|
||||||
let current_scale = super::scale_factor(&window);
|
|
||||||
Rc::new_cyclic(|weak_self| {
|
|
||||||
let weak_self = weak_self.clone();
|
|
||||||
let mql = Self::create_mql(&window, move |mql| {
|
|
||||||
if let Some(rc_self) = weak_self.upgrade() {
|
|
||||||
Self::handler(rc_self, mql);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
RefCell::new(Self {
|
|
||||||
window,
|
|
||||||
callback: Box::new(handler),
|
|
||||||
mql,
|
|
||||||
last_scale: current_scale,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_mql<F>(window: &web_sys::Window, closure: F) -> MediaQueryListHandle
|
|
||||||
where
|
|
||||||
F: 'static + FnMut(&MediaQueryList),
|
|
||||||
{
|
|
||||||
let current_scale = super::scale_factor(window);
|
|
||||||
// TODO: Remove `-webkit-device-pixel-ratio`. Requires Safari v16.
|
|
||||||
let media_query = format!(
|
|
||||||
"(resolution: {current_scale}dppx),
|
|
||||||
(-webkit-device-pixel-ratio: {current_scale})",
|
|
||||||
);
|
|
||||||
let mql = MediaQueryListHandle::new(window, &media_query, closure);
|
|
||||||
assert!(
|
|
||||||
mql.mql().matches(),
|
|
||||||
"created media query doesn't match, {current_scale} != {}",
|
|
||||||
super::scale_factor(window)
|
|
||||||
);
|
|
||||||
mql
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handler(this: Rc<RefCell<Self>>, mql: &MediaQueryList) {
|
|
||||||
let weak_self = Rc::downgrade(&this);
|
|
||||||
let mut this = this.borrow_mut();
|
|
||||||
let old_scale = this.last_scale;
|
|
||||||
let new_scale = super::scale_factor(&this.window);
|
|
||||||
|
|
||||||
// TODO: confirm/reproduce this problem, see:
|
|
||||||
// <https://github.com/rust-windowing/winit/issues/2597>.
|
|
||||||
// This should never happen, but if it does then apparently the scale factor didn't change.
|
|
||||||
if mql.matches() {
|
|
||||||
warn!(
|
|
||||||
"media query tracking scale factor was triggered without a change:\n\
|
|
||||||
Media Query: {}\n\
|
|
||||||
Current Scale: {new_scale}",
|
|
||||||
mql.media(),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
(this.callback)(ScaleChangeArgs {
|
|
||||||
old_scale,
|
|
||||||
new_scale,
|
|
||||||
});
|
|
||||||
|
|
||||||
let new_mql = Self::create_mql(&this.window, move |mql| {
|
|
||||||
if let Some(rc_self) = weak_self.upgrade() {
|
|
||||||
Self::handler(rc_self, mql);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.mql = new_mql;
|
|
||||||
this.last_scale = new_scale;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
|
use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
|
||||||
use crate::event;
|
|
||||||
use crate::icon::Icon;
|
use crate::icon::Icon;
|
||||||
use crate::window::{
|
use crate::window::{
|
||||||
CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme, UserAttentionType,
|
CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme, UserAttentionType,
|
||||||
|
@ -31,7 +30,6 @@ pub struct Inner {
|
||||||
canvas: Rc<RefCell<backend::Canvas>>,
|
canvas: Rc<RefCell<backend::Canvas>>,
|
||||||
previous_pointer: RefCell<&'static str>,
|
previous_pointer: RefCell<&'static str>,
|
||||||
register_redraw_request: Box<dyn Fn()>,
|
register_redraw_request: Box<dyn Fn()>,
|
||||||
resize_notify_fn: Box<dyn Fn(PhysicalSize<u32>)>,
|
|
||||||
destroy_fn: Option<Box<dyn FnOnce()>>,
|
destroy_fn: Option<Box<dyn FnOnce()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +46,7 @@ impl Window {
|
||||||
let prevent_default = platform_attr.prevent_default;
|
let prevent_default = platform_attr.prevent_default;
|
||||||
|
|
||||||
let window = target.runner.window();
|
let window = target.runner.window();
|
||||||
let canvas = backend::Canvas::create(window.clone(), &attr, platform_attr)?;
|
let canvas = backend::Canvas::create(id, window.clone(), &attr, platform_attr)?;
|
||||||
let canvas = Rc::new(RefCell::new(canvas));
|
let canvas = Rc::new(RefCell::new(canvas));
|
||||||
|
|
||||||
let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));
|
let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));
|
||||||
|
@ -56,14 +54,6 @@ impl Window {
|
||||||
let has_focus = Arc::new(AtomicBool::new(false));
|
let has_focus = Arc::new(AtomicBool::new(false));
|
||||||
target.register(&canvas, id, prevent_default, has_focus.clone());
|
target.register(&canvas, id, prevent_default, has_focus.clone());
|
||||||
|
|
||||||
let runner = target.runner.clone();
|
|
||||||
let resize_notify_fn = Box::new(move |new_size| {
|
|
||||||
runner.send_event(event::Event::WindowEvent {
|
|
||||||
window_id: RootWI(id),
|
|
||||||
event: event::WindowEvent::Resized(new_size),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let runner = target.runner.clone();
|
let runner = target.runner.clone();
|
||||||
let destroy_fn = Box::new(move || runner.notify_destroy_window(RootWI(id)));
|
let destroy_fn = Box::new(move || runner.notify_destroy_window(RootWI(id)));
|
||||||
|
|
||||||
|
@ -75,7 +65,6 @@ impl Window {
|
||||||
canvas,
|
canvas,
|
||||||
previous_pointer: RefCell::new("auto"),
|
previous_pointer: RefCell::new("auto"),
|
||||||
register_redraw_request,
|
register_redraw_request,
|
||||||
resize_notify_fn,
|
|
||||||
destroy_fn: Some(destroy_fn),
|
destroy_fn: Some(destroy_fn),
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
@ -149,7 +138,7 @@ impl Window {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
||||||
self.inner.queue(|inner| inner.inner_size())
|
self.inner.queue(|inner| inner.canvas.borrow().inner_size())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -161,12 +150,9 @@ impl Window {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_inner_size(&self, size: Size) {
|
pub fn set_inner_size(&self, size: Size) {
|
||||||
self.inner.dispatch(move |inner| {
|
self.inner.dispatch(move |inner| {
|
||||||
let old_size = inner.inner_size();
|
let size = size.to_logical(inner.scale_factor());
|
||||||
backend::set_canvas_size(&inner.canvas.borrow(), size);
|
let canvas = inner.canvas.borrow();
|
||||||
let new_size = inner.inner_size();
|
backend::set_canvas_size(canvas.window(), canvas.raw(), size);
|
||||||
if old_size != new_size {
|
|
||||||
(inner.resize_notify_fn)(new_size);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,11 +428,6 @@ impl Inner {
|
||||||
pub fn scale_factor(&self) -> f64 {
|
pub fn scale_factor(&self) -> f64 {
|
||||||
super::backend::scale_factor(&self.window)
|
super::backend::scale_factor(&self.window)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
|
||||||
self.canvas.borrow().size().get()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
|
Loading…
Reference in a new issue