Auto merge of #28236 - pecastro:winit_0_24_surfman, r=jdm

Winit 0.24.0 and surfman

<!-- Please describe your changes on the following line: -->
I've updated Servo to Winit 0.24.0 based on the previous work in #26394.
I've basically rebased master onto his jdm/winit branch which had the bulk of the work and I brute forced it till it built correcting things here and there as I could.
The build reports a few warnings:

```
00:04:59 Mar 03 10:20:06 warning: use of deprecated field `winit::event::KeyboardInput::modifiers`: Deprecated in favor of WindowEvent::ModifiersChanged
00:04:59 Mar 03 10:20:06    --> ports/winit/headed_window.rs:753:12
00:04:59 Mar 03 10:20:06     |
00:04:59 Mar 03 10:20:06 753 |         if input.modifiers.shift() {
00:04:59 Mar 03 10:20:06     |            ^^^^^^^^^^^^^^^
00:04:59 Mar 03 10:20:06     |
00:04:59 Mar 03 10:20:06     = note: `#[warn(deprecated)]` on by default
00:04:59 Mar 03 10:20:06
00:04:59 Mar 03 10:20:06 warning: use of deprecated field `winit::event::KeyboardInput::modifiers`: Deprecated in favor of WindowEvent::ModifiersChanged
00:04:59 Mar 03 10:20:06    --> ports/winit/keyutils.rs:263:34
00:04:59 Mar 03 10:20:06     |
00:04:59 Mar 03 10:20:06 263 |         modifiers: get_modifiers(input.modifiers),
00:04:59 Mar 03 10:20:06     |                                  ^^^^^^^^^^^^^^^
00:04:59 Mar 03 10:20:06
00:07:06 Mar 03 10:22:13 warning: 2 warnings emitted
00:07:06 Mar 03 10:22:13
00:07:06 Mar 03 10:22:13    Completed servo v0.0.1 bin "servo" in 132.7s
00:07:06 Mar 03 10:22:13     Finished dev [unoptimized + debuginfo] target(s) in 6m 59s
00:07:08 Mar 03 10:22:15 [Warning] Could not generate notification!
00:07:08 Mar 03 10:22:15 Build Completed in 0:07:01
```

And there are a few commits namely b27e09e009 which I'm not entirely sure of.
I've intentionally left the surfman patch in Cargo.toml so someone else can validate this branch.
Unit tests and smoke test run successfully.
Servo runs but I'm not familiar enough with it to validate how well it does. The window opens and content loads though.

My Rust foo is not great and I could use some help fixing those warnings.

Regards,

PECastro

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [x ] `./mach build -d` does not report any errors
A few warnings ...
- [x ] `./mach test-tidy` does not report any errors
A few duplicate version statements but no errors.
- [x] These changes fix #26394
- [x] There are tests for these changes
-  [ ] These changes do not require tests because

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
bors-servo 2021-03-14 19:26:04 -04:00 committed by GitHub
commit 68e200a581
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 714 additions and 559 deletions

599
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,8 @@ opt-level = 3
# This is here to dedupe winapi since mio 0.6 is still using winapi 0.2. # This is here to dedupe winapi since mio 0.6 is still using winapi 0.2.
mio = { git = "https://github.com/servo/mio.git", branch = "servo-mio-0.6.22" } mio = { git = "https://github.com/servo/mio.git", branch = "servo-mio-0.6.22" }
# Work around bug in winit 0.24 crashing servo headless in macOS
winit = { git = "https://github.com/rust-windowing/winit.git", rev = "4192d04a53202c199f94d1b7d883a34c9ad09272" }
[patch."https://github.com/jrmuizel/raqote"] [patch."https://github.com/jrmuizel/raqote"]
raqote = { git = "https://github.com/jdm/raqote", branch = "fkup" } raqote = { git = "https://github.com/jdm/raqote", branch = "fkup" }

View file

@ -40,8 +40,8 @@ sparkle = "0.1.25"
style = { path = "../style" } style = { path = "../style" }
style_traits = { path = "../style_traits" } style_traits = { path = "../style_traits" }
# NOTE: the sm-angle feature only enables angle on windows, not other platforms! # NOTE: the sm-angle feature only enables angle on windows, not other platforms!
surfman = { version = "0.3", features = ["sm-angle","sm-angle-default"] } surfman = { version = "0.4", features = ["sm-angle","sm-angle-default"] }
surfman-chains = "0.5" surfman-chains = "0.6"
surfman-chains-api = "0.2" surfman-chains-api = "0.2"
time = { version = "0.1.0", optional = true } time = { version = "0.1.0", optional = true }
webrender = { git = "https://github.com/servo/webrender" } webrender = { git = "https://github.com/servo/webrender" }

View file

@ -835,7 +835,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
} }
} }
pub fn on_resize_window_event(&mut self) { pub fn on_resize_window_event(&mut self) -> bool {
debug!("compositor resize requested"); debug!("compositor resize requested");
let old_coords = self.embedder_coordinates; let old_coords = self.embedder_coordinates;
@ -847,11 +847,12 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
} }
if self.embedder_coordinates.viewport == old_coords.viewport { if self.embedder_coordinates.viewport == old_coords.viewport {
return; return false;
} }
self.send_window_size(WindowSizeType::Resize); self.send_window_size(WindowSizeType::Resize);
self.composite_if_necessary(CompositingReason::Resize); self.composite_if_necessary(CompositingReason::Resize);
return true;
} }
pub fn on_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) { pub fn on_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) {

View file

@ -78,7 +78,7 @@ servo_url = { path = "../url" }
sparkle = "0.1" sparkle = "0.1"
style = { path = "../style", features = ["servo"] } style = { path = "../style", features = ["servo"] }
style_traits = { path = "../style_traits", features = ["servo"] } style_traits = { path = "../style_traits", features = ["servo"] }
surfman = "0.3" surfman = "0.4"
webdriver_server = { path = "../webdriver_server", optional = true } webdriver_server = { path = "../webdriver_server", optional = true }
webgpu = { path = "../webgpu" } webgpu = { path = "../webgpu" }
webrender = { git = "https://github.com/servo/webrender" } webrender = { git = "https://github.com/servo/webrender" }

View file

@ -549,7 +549,7 @@ where
} }
} }
fn handle_window_event(&mut self, event: WindowEvent) { fn handle_window_event(&mut self, event: WindowEvent) -> bool {
match event { match event {
WindowEvent::Idle => {}, WindowEvent::Idle => {},
@ -558,7 +558,7 @@ where
}, },
WindowEvent::Resize => { WindowEvent::Resize => {
self.compositor.on_resize_window_event(); return self.compositor.on_resize_window_event();
}, },
WindowEvent::AllowNavigationResponse(pipeline_id, allowed) => { WindowEvent::AllowNavigationResponse(pipeline_id, allowed) => {
@ -745,6 +745,7 @@ where
} }
}, },
} }
return false;
} }
fn receive_messages(&mut self) { fn receive_messages(&mut self) {
@ -776,18 +777,20 @@ where
::std::mem::replace(&mut self.embedder_events, Vec::new()) ::std::mem::replace(&mut self.embedder_events, Vec::new())
} }
pub fn handle_events(&mut self, events: Vec<WindowEvent>) { pub fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool {
if self.compositor.receive_messages() { if self.compositor.receive_messages() {
self.receive_messages(); self.receive_messages();
} }
let mut need_resize = false;
for event in events { for event in events {
self.handle_window_event(event); need_resize |= self.handle_window_event(event);
} }
if self.compositor.shutdown_state != ShutdownState::FinishedShuttingDown { if self.compositor.shutdown_state != ShutdownState::FinishedShuttingDown {
self.compositor.perform_updates(); self.compositor.perform_updates();
} else { } else {
self.embedder_events.push((None, EmbedderMsg::Shutdown)); self.embedder_events.push((None, EmbedderMsg::Shutdown));
} }
need_resize
} }
pub fn repaint_synchronously(&mut self) { pub fn repaint_synchronously(&mut self) {

View file

@ -12,6 +12,6 @@ path = "lib.rs"
[dependencies] [dependencies]
euclid = "0.20" euclid = "0.20"
surfman = "0.3" surfman = "0.4"
surfman-chains = "0.5" surfman-chains = "0.6"

View file

@ -29,8 +29,8 @@ libservo = { path = "../../components/servo" }
log = "0.4" log = "0.4"
servo-media = { git = "https://github.com/servo/media" } servo-media = { git = "https://github.com/servo/media" }
sparkle = "0.1" sparkle = "0.1"
surfman = "0.3" surfman = "0.4"
surfman-chains = "0.5" surfman-chains = "0.6"
surfman-chains-api = "0.2" surfman-chains-api = "0.2"
webxr = { git = "https://github.com/servo/webxr", features = ["glwindow"] } webxr = { git = "https://github.com/servo/webxr", features = ["glwindow"] }

View file

@ -249,7 +249,9 @@ impl ServoThread {
ServoWebSrcMsg::GetSwapChain(sender) => self.send_swap_chain(sender), ServoWebSrcMsg::GetSwapChain(sender) => self.send_swap_chain(sender),
ServoWebSrcMsg::SetSwapChain(swap_chain) => self.swap_chain = Some(swap_chain.0), ServoWebSrcMsg::SetSwapChain(swap_chain) => self.swap_chain = Some(swap_chain.0),
ServoWebSrcMsg::Resize(size) => self.resize(size), ServoWebSrcMsg::Resize(size) => self.resize(size),
ServoWebSrcMsg::Heartbeat => self.servo.handle_events(vec![]), ServoWebSrcMsg::Heartbeat => {
self.servo.handle_events(vec![]);
},
ServoWebSrcMsg::Stop => break, ServoWebSrcMsg::Stop => break,
} }
} }

View file

@ -12,7 +12,7 @@ ipc-channel = "0.14"
libservo = { path = "../../../components/servo" } libservo = { path = "../../../components/servo" }
log = "0.4" log = "0.4"
servo-media = { git = "https://github.com/servo/media" } servo-media = { git = "https://github.com/servo/media" }
surfman = { version = "0.3", features = ["sm-angle-default"] } surfman = { version = "0.4", features = ["sm-angle-default"] }
webxr = { git = "https://github.com/servo/webxr"} webxr = { git = "https://github.com/servo/webxr"}
webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] } webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }

View file

@ -18,7 +18,7 @@ env_logger = "0.8"
lazy_static = "1" lazy_static = "1"
log = "0.4" log = "0.4"
simpleservo = { path = "../api" } simpleservo = { path = "../api" }
surfman = "0.3" surfman = "0.4"
keyboard-types = "0.5" keyboard-types = "0.5"
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]

View file

@ -57,10 +57,10 @@ libservo = { path = "../../components/servo" }
log = "0.4" log = "0.4"
servo-media = { git = "https://github.com/servo/media" } servo-media = { git = "https://github.com/servo/media" }
shellwords = "1.0.0" shellwords = "1.0.0"
surfman = { version = "0.3", features = ["sm-winit", "sm-x11"] } surfman = { version = "0.4", features = ["sm-winit", "sm-x11"] }
tinyfiledialogs = "3.0" tinyfiledialogs = "3.0"
webxr = { git = "https://github.com/servo/webxr", features = ["ipc", "glwindow", "headless"] } webxr = { git = "https://github.com/servo/webxr", features = ["ipc", "glwindow", "headless"] }
winit = "0.19" winit = "0.24"
[target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies]
image = "0.23" image = "0.23"

View file

@ -6,9 +6,11 @@
use crate::browser::Browser; use crate::browser::Browser;
use crate::embedder::EmbedderCallbacks; use crate::embedder::EmbedderCallbacks;
use crate::events_loop::EventsLoop; use crate::events_loop::{EventsLoop, ServoEvent};
use crate::window_trait::WindowPortsMethods; use crate::window_trait::WindowPortsMethods;
use crate::{headed_window, headless_window}; use crate::{headed_window, headless_window};
use winit::window::WindowId;
use winit::event_loop::EventLoopWindowTarget;
use servo::compositing::windowing::WindowEvent; use servo::compositing::windowing::WindowEvent;
use servo::config::opts::{self, parse_url_or_filename}; use servo::config::opts::{self, parse_url_or_filename};
use servo::servo_config::pref; use servo::servo_config::pref;
@ -20,15 +22,13 @@ use std::env;
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
use webxr::glwindow::GlWindowDiscovery; use webxr::glwindow::GlWindowDiscovery;
use winit::WindowId;
thread_local! { thread_local! {
pub static WINDOWS: RefCell<HashMap<WindowId, Rc<dyn WindowPortsMethods>>> = RefCell::new(HashMap::new()); pub static WINDOWS: RefCell<HashMap<WindowId, Rc<dyn WindowPortsMethods>>> = RefCell::new(HashMap::new());
} }
pub struct App { pub struct App {
events_loop: Rc<RefCell<EventsLoop>>, servo: Option<Servo<dyn WindowPortsMethods>>,
servo: RefCell<Servo<dyn WindowPortsMethods>>,
browser: RefCell<Browser<dyn WindowPortsMethods>>, browser: RefCell<Browser<dyn WindowPortsMethods>>,
event_queue: RefCell<Vec<WindowEvent>>, event_queue: RefCell<Vec<WindowEvent>>,
suspended: Cell<bool>, suspended: Cell<bool>,
@ -48,17 +48,41 @@ impl App {
} else { } else {
Rc::new(headed_window::Window::new( Rc::new(headed_window::Window::new(
opts::get().initial_window_size, opts::get().initial_window_size,
events_loop.clone(), &events_loop,
no_native_titlebar, no_native_titlebar,
device_pixels_per_px, device_pixels_per_px,
)) ))
}; };
let xr_discovery = if pref!(dom.webxr.glwindow.enabled) { // Handle browser state.
let window = window.clone(); let browser = Browser::new(window.clone());
let mut app = App {
event_queue: RefCell::new(vec![]),
browser: RefCell::new(browser),
servo: None,
suspended: Cell::new(false),
};
let ev_waker = events_loop.create_event_loop_waker();
events_loop.run_forever(move |e, w, control_flow| {
if let winit::event::Event::NewEvents(winit::event::StartCause::Init) = e {
let surfman = window.webrender_surfman(); let surfman = window.webrender_surfman();
let events_loop = events_loop.clone();
let factory = Box::new(move || Ok(window.new_glwindow(&*events_loop.borrow()))); let xr_discovery = if pref!(dom.webxr.glwindow.enabled) && ! opts::get().headless {
let window = window.clone();
// This should be safe because run_forever does, in fact,
// run forever. The event loop window target doesn't get
// moved, and does outlast this closure, and we won't
// ever try to make use of it once shutdown begins and
// it stops being valid.
let w = unsafe {
std::mem::transmute::<
&EventLoopWindowTarget<ServoEvent>,
&'static EventLoopWindowTarget<ServoEvent>
>(w.unwrap())
};
let factory = Box::new(move || Ok(window.new_glwindow(w)));
Some(GlWindowDiscovery::new( Some(GlWindowDiscovery::new(
surfman.connection(), surfman.connection(),
surfman.adapter(), surfman.adapter(),
@ -69,28 +93,51 @@ impl App {
None None
}; };
let window = window.clone();
// Implements embedder methods, used by libservo and constellation. // Implements embedder methods, used by libservo and constellation.
let embedder = Box::new(EmbedderCallbacks::new(events_loop.clone(), xr_discovery)); let embedder = Box::new(EmbedderCallbacks::new(
ev_waker.clone(),
xr_discovery,
));
// Handle browser state. let mut servo = Servo::new(embedder, window.clone(), user_agent.clone());
let browser = Browser::new(window.clone());
let mut servo = Servo::new(embedder, window.clone(), user_agent);
let browser_id = BrowserId::new(); let browser_id = BrowserId::new();
servo.handle_events(vec![WindowEvent::NewBrowser(get_default_url(), browser_id)]); servo.handle_events(vec![WindowEvent::NewBrowser(get_default_url(), browser_id)]);
servo.setup_logging(); servo.setup_logging();
register_window(window); register_window(window.clone());
app.servo = Some(servo);
}
let app = App { // If self.servo is None here, it means that we're in the process of shutting down,
event_queue: RefCell::new(vec![]), // let's ignore events.
events_loop, if app.servo.is_none() {
browser: RefCell::new(browser), return;
servo: RefCell::new(servo), }
suspended: Cell::new(false),
};
app.run_loop(); // Handle the event
app.winit_event_to_servo_event(e);
let animating = WINDOWS.with(|windows| {
windows
.borrow()
.iter()
.any(|(_, window)| window.is_animating())
});
// Block until the window gets an event
if !animating || app.suspended.get() {
*control_flow = winit::event_loop::ControlFlow::Wait;
} else {
*control_flow = winit::event_loop::ControlFlow::Poll;
}
let stop = app.handle_events();
if stop {
*control_flow = winit::event_loop::ControlFlow::Exit;
app.servo.take().unwrap().deinit();
}
});
} }
fn get_events(&self) -> Vec<WindowEvent> { fn get_events(&self) -> Vec<WindowEvent> {
@ -98,87 +145,50 @@ impl App {
} }
// This function decides whether the event should be handled during `run_forever`. // This function decides whether the event should be handled during `run_forever`.
fn winit_event_to_servo_event(&self, event: winit::Event) -> winit::ControlFlow { fn winit_event_to_servo_event(&self, event: winit::event::Event<ServoEvent>) {
match event { match event {
// App level events // App level events
winit::Event::Suspended(suspended) => { winit::event::Event::Suspended => {
self.suspended.set(suspended); self.suspended.set(true);
if !suspended {
self.event_queue.borrow_mut().push(WindowEvent::Idle);
}
}, },
winit::Event::Awakened => { winit::event::Event::Resumed => {
self.suspended.set(false);
self.event_queue.borrow_mut().push(WindowEvent::Idle);
},
winit::event::Event::UserEvent(_) => {
self.event_queue.borrow_mut().push(WindowEvent::Idle);
},
winit::event::Event::DeviceEvent { .. } => {},
winit::event::Event::RedrawRequested(_) => {
self.event_queue.borrow_mut().push(WindowEvent::Idle); self.event_queue.borrow_mut().push(WindowEvent::Idle);
}, },
winit::Event::DeviceEvent { .. } => {},
// Window level events // Window level events
winit::Event::WindowEvent { winit::event::Event::WindowEvent {
window_id, event, .. window_id, event, ..
} => { } => {
return WINDOWS.with(|windows| { return WINDOWS.with(|windows| {
match windows.borrow().get(&window_id) { match windows.borrow().get(&window_id) {
None => { None => {
warn!("Got an event from unknown window"); warn!("Got an event from unknown window");
winit::ControlFlow::Break
}, },
Some(window) => { Some(window) => {
// Resize events need to be handled during run_forever
let cont = if let winit::WindowEvent::Resized(_) = event {
winit::ControlFlow::Continue
} else {
winit::ControlFlow::Break
};
window.winit_event_to_servo_event(event); window.winit_event_to_servo_event(event);
return cont;
}, },
} }
}); });
}, },
}
winit::ControlFlow::Break
}
fn run_loop(self) { winit::event::Event::LoopDestroyed |
loop { winit::event::Event::NewEvents(..) |
let animating = WINDOWS.with(|windows| { winit::event::Event::MainEventsCleared |
windows winit::event::Event::RedrawEventsCleared => {},
.borrow()
.iter()
.any(|(_, window)| window.is_animating())
});
if !animating || self.suspended.get() {
// If there's no animations running then we block on the window event loop.
self.events_loop.borrow_mut().run_forever(|e| {
let cont = self.winit_event_to_servo_event(e);
if cont == winit::ControlFlow::Continue {
// Note we need to be careful to make sure that any events
// that are handled during run_forever aren't re-entrant,
// since we are handling them while holding onto a mutable borrow
// of the events loop
self.handle_events();
}
cont
});
}
// Grab any other events that may have happened
self.events_loop.borrow_mut().poll_events(|e| {
self.winit_event_to_servo_event(e);
});
// If animations are running, we block on compositing
// (self.handle_events() ends up calling swap_buffers)
let stop = self.handle_events();
if stop {
break;
} }
} }
self.servo.into_inner().deinit() fn handle_events(&mut self) -> bool {
}
fn handle_events(&self) -> bool {
let mut browser = self.browser.borrow_mut(); let mut browser = self.browser.borrow_mut();
let mut servo = self.servo.borrow_mut();
// FIXME: // FIXME:
// As of now, we support only one browser (self.browser) // As of now, we support only one browser (self.browser)
@ -194,30 +204,24 @@ impl App {
} }
}); });
// FIXME: this could be handled by Servo. We don't need
// a repaint_synchronously function exposed.
let need_resize = app_events.iter().any(|e| match *e {
WindowEvent::Resize => true,
_ => false,
});
browser.handle_window_events(app_events); browser.handle_window_events(app_events);
let mut servo_events = servo.get_events(); let mut servo_events = self.servo.as_mut().unwrap().get_events();
let mut need_resize = false;
loop { loop {
browser.handle_servo_events(servo_events); browser.handle_servo_events(servo_events);
servo.handle_events(browser.get_events()); need_resize |= self.servo.as_mut().unwrap().handle_events(browser.get_events());
if browser.shutdown_requested() { if browser.shutdown_requested() {
return true; return true;
} }
servo_events = servo.get_events(); servo_events = self.servo.as_mut().unwrap().get_events();
if servo_events.is_empty() { if servo_events.is_empty() {
break; break;
} }
} }
if need_resize { if need_resize {
servo.repaint_synchronously(); self.servo.as_mut().unwrap().repaint_synchronously();
} }
false false
} }

View file

@ -4,26 +4,23 @@
//! Implements the global methods required by Servo (not window/gl/compositor related). //! Implements the global methods required by Servo (not window/gl/compositor related).
use crate::events_loop::EventsLoop;
use servo::compositing::windowing::EmbedderMethods; use servo::compositing::windowing::EmbedderMethods;
use servo::embedder_traits::{EmbedderProxy, EventLoopWaker}; use servo::embedder_traits::{EmbedderProxy, EventLoopWaker};
use servo::servo_config::pref; use servo::servo_config::pref;
use std::cell::RefCell;
use std::rc::Rc;
use webxr::glwindow::GlWindowDiscovery; use webxr::glwindow::GlWindowDiscovery;
pub struct EmbedderCallbacks { pub struct EmbedderCallbacks {
events_loop: Rc<RefCell<EventsLoop>>, event_loop_waker: Box<dyn EventLoopWaker>,
xr_discovery: Option<GlWindowDiscovery>, xr_discovery: Option<GlWindowDiscovery>,
} }
impl EmbedderCallbacks { impl EmbedderCallbacks {
pub fn new( pub fn new(
events_loop: Rc<RefCell<EventsLoop>>, event_loop_waker: Box<dyn EventLoopWaker>,
xr_discovery: Option<GlWindowDiscovery>, xr_discovery: Option<GlWindowDiscovery>,
) -> EmbedderCallbacks { ) -> EmbedderCallbacks {
EmbedderCallbacks { EmbedderCallbacks {
events_loop, event_loop_waker,
xr_discovery, xr_discovery,
} }
} }
@ -31,7 +28,7 @@ impl EmbedderCallbacks {
impl EmbedderMethods for EmbedderCallbacks { impl EmbedderMethods for EmbedderCallbacks {
fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker> { fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker> {
self.events_loop.borrow().create_event_loop_waker() self.event_loop_waker.clone()
} }
fn register_webxr( fn register_webxr(

View file

@ -5,16 +5,19 @@
//! An event loop implementation that works in headless mode. //! An event loop implementation that works in headless mode.
use servo::embedder_traits::EventLoopWaker; use servo::embedder_traits::EventLoopWaker;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::{Arc, Condvar, Mutex}; use std::sync::{Arc, Condvar, Mutex};
use std::time; use std::time;
use winit; use winit;
#[derive(Debug)]
pub enum ServoEvent {
Awakened,
}
#[allow(dead_code)] #[allow(dead_code)]
enum EventLoop { enum EventLoop {
/// A real Winit windowing event loop. /// A real Winit windowing event loop.
Winit(Option<winit::EventsLoop>), Winit(Option<winit::event_loop::EventLoop<ServoEvent>>),
/// A fake event loop which contains a signalling flag used to ensure /// A fake event loop which contains a signalling flag used to ensure
/// that pending events get processed in a timely fashion, and a condition /// that pending events get processed in a timely fashion, and a condition
/// variable to allow waiting on that flag changing state. /// variable to allow waiting on that flag changing state.
@ -26,20 +29,17 @@ pub struct EventsLoop(EventLoop);
impl EventsLoop { impl EventsLoop {
// Ideally, we could use the winit event loop in both modes, // Ideally, we could use the winit event loop in both modes,
// but on Linux, the event loop requires a X11 server. // but on Linux, the event loop requires a X11 server.
#[cfg(not(target_os = "linux"))] #[cfg(not(any(target_os = "linux", target_os = "macos")))]
pub fn new(_headless: bool) -> Rc<RefCell<EventsLoop>> { pub fn new(_headless: bool) -> EventsLoop {
Rc::new(RefCell::new(EventsLoop(EventLoop::Winit(Some( EventsLoop(EventLoop::Winit(Some(winit::event_loop::EventLoop::with_user_event())))
winit::EventsLoop::new(),
)))))
} }
#[cfg(target_os = "linux")] #[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn new(headless: bool) -> Rc<RefCell<EventsLoop>> { pub fn new(headless: bool) -> EventsLoop {
let events_loop = if headless { EventsLoop(if headless {
EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new()))) EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
} else { } else {
EventLoop::Winit(Some(winit::EventsLoop::new())) EventLoop::Winit(Some(winit::event_loop::EventLoop::with_user_event()))
}; })
Rc::new(RefCell::new(EventsLoop(events_loop)))
} }
} }
@ -55,7 +55,7 @@ impl EventsLoop {
EventLoop::Headless(ref data) => Box::new(HeadlessEventLoopWaker(data.clone())), EventLoop::Headless(ref data) => Box::new(HeadlessEventLoopWaker(data.clone())),
} }
} }
pub fn as_winit(&self) -> &winit::EventsLoop { pub fn as_winit(&self) -> &winit::event_loop::EventLoop<ServoEvent> {
match self.0 { match self.0 {
EventLoop::Winit(Some(ref event_loop)) => event_loop, EventLoop::Winit(Some(ref event_loop)) => event_loop,
EventLoop::Winit(None) | EventLoop::Headless(..) => { EventLoop::Winit(None) | EventLoop::Headless(..) => {
@ -64,49 +64,45 @@ impl EventsLoop {
} }
} }
pub fn poll_events<F>(&mut self, callback: F) pub fn run_forever<F: 'static>(self, mut callback: F)
where where F: FnMut(
F: FnMut(winit::Event), winit::event::Event<ServoEvent>,
{ Option<&winit::event_loop::EventLoopWindowTarget<ServoEvent>>,
&mut winit::event_loop::ControlFlow
) {
match self.0 { match self.0 {
EventLoop::Winit(Some(ref mut events_loop)) => events_loop.poll_events(callback), EventLoop::Winit(events_loop) => {
EventLoop::Winit(None) => (),
EventLoop::Headless(ref data) => {
// This is subtle - the use of the event loop in App::run_loop
// optionally calls run_forever, then always calls poll_events.
// If our signalling flag is true before we call run_forever,
// we don't want to reset it before poll_events is called or
// we'll end up sleeping even though there are events waiting
// to be handled. We compromise by only resetting the flag here
// in poll_events, so that both poll_events and run_forever can
// check it first and avoid sleeping unnecessarily.
self.sleep(&data.0, &data.1);
*data.0.lock().unwrap() = false;
},
}
}
pub fn run_forever<F>(&mut self, mut callback: F)
where
F: FnMut(winit::Event) -> winit::ControlFlow,
{
match self.0 {
EventLoop::Winit(ref mut events_loop) => {
let events_loop = events_loop let events_loop = events_loop
.as_mut()
.expect("Can't run an unavailable event loop."); .expect("Can't run an unavailable event loop.");
events_loop.run_forever(callback); events_loop.run(move |e, window_target, ref mut control_flow| {
}, callback(e, Some(window_target), control_flow)
});
}
EventLoop::Headless(ref data) => { EventLoop::Headless(ref data) => {
let &(ref flag, ref condvar) = &**data; let &(ref flag, ref condvar) = &**data;
while !*flag.lock().unwrap() { let mut event = winit::event::Event::NewEvents(winit::event::StartCause::Init);
loop {
self.sleep(flag, condvar); self.sleep(flag, condvar);
if callback(winit::Event::Awakened) == winit::ControlFlow::Break { let mut control_flow = winit::event_loop::ControlFlow::Poll;
callback(
event,
None,
&mut control_flow
);
event = winit::event::Event::<ServoEvent>::UserEvent(ServoEvent::Awakened);
if control_flow != winit::event_loop::ControlFlow::Poll {
*flag.lock().unwrap() = false;
}
if control_flow == winit::event_loop::ControlFlow::Exit {
break; break;
} }
} }
}, },
} }
} }
fn sleep(&self, lock: &Mutex<bool>, condvar: &Condvar) { fn sleep(&self, lock: &Mutex<bool>, condvar: &Condvar) {
// To avoid sleeping when we should be processing events, do two things: // To avoid sleeping when we should be processing events, do two things:
// * before sleeping, check whether our signalling flag has been set // * before sleeping, check whether our signalling flag has been set
@ -123,18 +119,18 @@ impl EventsLoop {
} }
struct HeadedEventLoopWaker { struct HeadedEventLoopWaker {
proxy: Arc<winit::EventsLoopProxy>, proxy: Arc<Mutex<winit::event_loop::EventLoopProxy<ServoEvent>>>,
} }
impl HeadedEventLoopWaker { impl HeadedEventLoopWaker {
fn new(events_loop: &winit::EventsLoop) -> HeadedEventLoopWaker { fn new(events_loop: &winit::event_loop::EventLoop<ServoEvent>) -> HeadedEventLoopWaker {
let proxy = Arc::new(events_loop.create_proxy()); let proxy = Arc::new(Mutex::new(events_loop.create_proxy()));
HeadedEventLoopWaker { proxy } HeadedEventLoopWaker { proxy }
} }
} }
impl EventLoopWaker for HeadedEventLoopWaker { impl EventLoopWaker for HeadedEventLoopWaker {
fn wake(&self) { fn wake(&self) {
// kick the OS event loop awake. // Kick the OS event loop awake.
if let Err(err) = self.proxy.wakeup() { if let Err(err) = self.proxy.lock().unwrap().send_event(ServoEvent::Awakened) {
warn!("Failed to wake up event loop ({}).", err); warn!("Failed to wake up event loop ({}).", err);
} }
} }

View file

@ -4,10 +4,18 @@
//! A winit window implementation. //! A winit window implementation.
use crate::events_loop::EventsLoop; use crate::events_loop::{EventsLoop, ServoEvent};
use crate::keyutils::keyboard_event_from_winit; use crate::keyutils::keyboard_event_from_winit;
use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT}; use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT};
use euclid::{Angle, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector2D, Vector3D}; use euclid::{
Angle, Point2D, Rotation3D, Scale, Size2D, UnknownUnit,
Vector2D, Vector3D,
};
#[cfg(target_os = "macos")]
use winit::platform::macos::{ActivationPolicy, WindowBuilderExtMacOS};
#[cfg(any(target_os = "linux", target_os = "windows"))]
use winit::window::Icon;
use winit::event::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
use image; use image;
use keyboard_types::{Key, KeyState, KeyboardEvent}; use keyboard_types::{Key, KeyState, KeyboardEvent};
@ -39,17 +47,11 @@ use surfman::GLVersion;
use surfman::SurfaceType; use surfman::SurfaceType;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use winapi; use winapi;
use winit::dpi::{LogicalPosition, LogicalSize, PhysicalSize}; use winit::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
#[cfg(target_os = "macos")] use winit::event::ModifiersState;
use winit::os::macos::{ActivationPolicy, WindowBuilderExt};
#[cfg(any(target_os = "linux", target_os = "windows"))]
use winit::Icon;
use winit::{
ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode,
};
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
fn builder_with_platform_options(mut builder: winit::WindowBuilder) -> winit::WindowBuilder { fn builder_with_platform_options(mut builder: winit::window::WindowBuilder) -> winit::window::WindowBuilder {
if opts::get().output_file.is_some() { if opts::get().output_file.is_some() {
// Prevent the window from showing in Dock.app, stealing focus, // Prevent the window from showing in Dock.app, stealing focus,
// when generating an output file. // when generating an output file.
@ -59,18 +61,18 @@ fn builder_with_platform_options(mut builder: winit::WindowBuilder) -> winit::Wi
} }
#[cfg(not(target_os = "macos"))] #[cfg(not(target_os = "macos"))]
fn builder_with_platform_options(builder: winit::WindowBuilder) -> winit::WindowBuilder { fn builder_with_platform_options(builder: winit::window::WindowBuilder) -> winit::window::WindowBuilder {
builder builder
} }
pub struct Window { pub struct Window {
winit_window: winit::Window, winit_window: winit::window::Window,
webrender_surfman: WebrenderSurfman, webrender_surfman: WebrenderSurfman,
screen_size: Size2D<u32, DeviceIndependentPixel>, screen_size: Size2D<u32, DeviceIndependentPixel>,
inner_size: Cell<Size2D<u32, DeviceIndependentPixel>>, inner_size: Cell<Size2D<u32, DeviceIndependentPixel>>,
mouse_down_button: Cell<Option<winit::MouseButton>>, mouse_down_button: Cell<Option<winit::event::MouseButton>>,
mouse_down_point: Cell<Point2D<i32, DevicePixel>>, mouse_down_point: Cell<Point2D<i32, DevicePixel>>,
primary_monitor: winit::MonitorId, primary_monitor: winit::monitor::MonitorHandle,
event_queue: RefCell<Vec<WindowEvent>>, event_queue: RefCell<Vec<WindowEvent>>,
mouse_pos: Cell<Point2D<i32, DevicePixel>>, mouse_pos: Cell<Point2D<i32, DevicePixel>>,
last_pressed: Cell<Option<(KeyboardEvent, Option<VirtualKeyCode>)>>, last_pressed: Cell<Option<(KeyboardEvent, Option<VirtualKeyCode>)>>,
@ -81,6 +83,7 @@ pub struct Window {
fullscreen: Cell<bool>, fullscreen: Cell<bool>,
device_pixels_per_px: Option<f32>, device_pixels_per_px: Option<f32>,
xr_window_poses: RefCell<Vec<Rc<XRWindowPose>>>, xr_window_poses: RefCell<Vec<Rc<XRWindowPose>>>,
modifiers_state: Cell<ModifiersState>,
} }
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
@ -98,7 +101,7 @@ fn window_creation_scale_factor() -> Scale<f32, DeviceIndependentPixel, DevicePi
impl Window { impl Window {
pub fn new( pub fn new(
win_size: Size2D<u32, DeviceIndependentPixel>, win_size: Size2D<u32, DeviceIndependentPixel>,
events_loop: Rc<RefCell<EventsLoop>>, events_loop: &EventsLoop,
no_native_titlebar: bool, no_native_titlebar: bool,
device_pixels_per_px: Option<f32>, device_pixels_per_px: Option<f32>,
) -> Window { ) -> Window {
@ -114,19 +117,16 @@ impl Window {
let width = win_size.to_untyped().width; let width = win_size.to_untyped().width;
let height = win_size.to_untyped().height; let height = win_size.to_untyped().height;
let mut window_builder = winit::WindowBuilder::new() let mut window_builder = winit::window::WindowBuilder::new()
.with_title("Servo".to_string()) .with_title("Servo".to_string())
.with_decorations(!no_native_titlebar) .with_decorations(!no_native_titlebar)
.with_transparency(no_native_titlebar) .with_transparent(no_native_titlebar)
.with_dimensions(LogicalSize::new(width as f64, height as f64)) .with_inner_size(PhysicalSize::new(width as f64, height as f64))
.with_visibility(visible) .with_visible(visible);
.with_multitouch();
window_builder = builder_with_platform_options(window_builder); window_builder = builder_with_platform_options(window_builder);
let winit_window = window_builder let winit_window = window_builder.build(events_loop.as_winit()).expect("Failed to create window.");
.build(events_loop.borrow().as_winit())
.expect("Failed to create window.");
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
{ {
@ -134,21 +134,16 @@ impl Window {
winit_window.set_window_icon(Some(load_icon(icon_bytes))); winit_window.set_window_icon(Some(load_icon(icon_bytes)));
} }
let primary_monitor = events_loop.borrow().as_winit().get_primary_monitor(); let primary_monitor = events_loop.as_winit().available_monitors().nth(0).expect("No monitor detected");
let PhysicalSize { let PhysicalSize {
width: screen_width, width: screen_width,
height: screen_height, height: screen_height,
} = primary_monitor.get_dimensions(); } = primary_monitor.clone().size();
let screen_size = Size2D::new(screen_width as u32, screen_height as u32); let screen_size = Size2D::new(screen_width as u32, screen_height as u32);
// TODO(ajeffrey): can this fail? let PhysicalSize { width, height } = winit_window.inner_size();
let LogicalSize { width, height } = winit_window
.get_inner_size()
.expect("Failed to get window inner size.");
let inner_size = Size2D::new(width as u32, height as u32); let inner_size = Size2D::new(width as u32, height as u32);
winit_window.show();
// Initialize surfman // Initialize surfman
let connection = let connection =
Connection::from_winit_window(&winit_window).expect("Failed to create connection"); Connection::from_winit_window(&winit_window).expect("Failed to create connection");
@ -179,6 +174,7 @@ impl Window {
screen_size, screen_size,
device_pixels_per_px, device_pixels_per_px,
xr_window_poses: RefCell::new(vec![]), xr_window_poses: RefCell::new(vec![]),
modifiers_state: Cell::new(ModifiersState::empty()),
} }
} }
@ -227,7 +223,7 @@ impl Window {
} }
fn handle_keyboard_input(&self, input: KeyboardInput) { fn handle_keyboard_input(&self, input: KeyboardInput) {
let mut event = keyboard_event_from_winit(input); let mut event = keyboard_event_from_winit(input, self.modifiers_state.get());
trace!("handling {:?}", event); trace!("handling {:?}", event);
if event.state == KeyState::Down && event.key == Key::Unidentified { if event.state == KeyState::Down && event.key == Key::Unidentified {
// If pressed and probably printable, we expect a ReceivedCharacter event. // If pressed and probably printable, we expect a ReceivedCharacter event.
@ -247,7 +243,7 @@ impl Window {
self.last_pressed.set(None); self.last_pressed.set(None);
let xr_poses = self.xr_window_poses.borrow(); let xr_poses = self.xr_window_poses.borrow();
for xr_window_pose in &*xr_poses { for xr_window_pose in &*xr_poses {
xr_window_pose.handle_xr_rotation(&input); xr_window_pose.handle_xr_rotation(&input, self.modifiers_state.get());
} }
self.event_queue self.event_queue
.borrow_mut() .borrow_mut()
@ -258,17 +254,17 @@ impl Window {
/// Helper function to handle a click /// Helper function to handle a click
fn handle_mouse( fn handle_mouse(
&self, &self,
button: winit::MouseButton, button: winit::event::MouseButton,
action: winit::ElementState, action: winit::event::ElementState,
coords: Point2D<i32, DevicePixel>, coords: Point2D<i32, DevicePixel>,
) { ) {
use servo::script_traits::MouseButton; use servo::script_traits::MouseButton;
let max_pixel_dist = 10.0 * self.servo_hidpi_factor().get(); let max_pixel_dist = 10.0 * self.servo_hidpi_factor().get();
let mouse_button = match &button { let mouse_button = match &button {
winit::MouseButton::Left => MouseButton::Left, winit::event::MouseButton::Left => MouseButton::Left,
winit::MouseButton::Right => MouseButton::Right, winit::event::MouseButton::Right => MouseButton::Right,
winit::MouseButton::Middle => MouseButton::Middle, winit::event::MouseButton::Middle => MouseButton::Middle,
_ => MouseButton::Left, _ => MouseButton::Left,
}; };
let event = match action { let event = match action {
@ -305,7 +301,7 @@ impl Window {
} }
fn device_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> { fn device_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
Scale::new(self.winit_window.get_hidpi_factor() as f32) Scale::new(self.winit_window.scale_factor() as f32)
} }
fn servo_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> { fn servo_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
@ -332,8 +328,7 @@ impl WindowPortsMethods for Window {
let dpr = self.servo_hidpi_factor(); let dpr = self.servo_hidpi_factor();
let size = self let size = self
.winit_window .winit_window
.get_inner_size() .inner_size();
.expect("Failed to get window inner size.");
size.height as f32 * dpr.get() size.height as f32 * dpr.get()
} }
@ -342,24 +337,23 @@ impl WindowPortsMethods for Window {
} }
fn set_inner_size(&self, size: DeviceIntSize) { fn set_inner_size(&self, size: DeviceIntSize) {
let size = size.to_f32() / self.device_hidpi_factor();
self.winit_window self.winit_window
.set_inner_size(LogicalSize::new(size.width.into(), size.height.into())) .set_inner_size::<PhysicalSize<i32>>(PhysicalSize::new(size.width.into(), size.height.into()))
} }
fn set_position(&self, point: DeviceIntPoint) { fn set_position(&self, point: DeviceIntPoint) {
let point = point.to_f32() / self.device_hidpi_factor();
self.winit_window self.winit_window
.set_position(LogicalPosition::new(point.x.into(), point.y.into())) .set_outer_position::<PhysicalPosition<i32>>(PhysicalPosition::new(point.x.into(), point.y.into()))
} }
fn set_fullscreen(&self, state: bool) { fn set_fullscreen(&self, state: bool) {
if self.fullscreen.get() != state { if self.fullscreen.get() != state {
self.winit_window.set_fullscreen(if state { self.winit_window
Some(self.primary_monitor.clone()) .set_fullscreen(
} else { if state {
None Some(winit::window::Fullscreen::Borderless(Some(self.primary_monitor.clone())))
}); } else { None }
);
} }
self.fullscreen.set(state); self.fullscreen.set(state);
} }
@ -369,68 +363,68 @@ impl WindowPortsMethods for Window {
} }
fn set_cursor(&self, cursor: Cursor) { fn set_cursor(&self, cursor: Cursor) {
use winit::MouseCursor; use winit::window::CursorIcon;
let winit_cursor = match cursor { let winit_cursor = match cursor {
Cursor::Default => MouseCursor::Default, Cursor::Default => CursorIcon::Default,
Cursor::Pointer => MouseCursor::Hand, Cursor::Pointer => CursorIcon::Hand,
Cursor::ContextMenu => MouseCursor::ContextMenu, Cursor::ContextMenu => CursorIcon::ContextMenu,
Cursor::Help => MouseCursor::Help, Cursor::Help => CursorIcon::Help,
Cursor::Progress => MouseCursor::Progress, Cursor::Progress => CursorIcon::Progress,
Cursor::Wait => MouseCursor::Wait, Cursor::Wait => CursorIcon::Wait,
Cursor::Cell => MouseCursor::Cell, Cursor::Cell => CursorIcon::Cell,
Cursor::Crosshair => MouseCursor::Crosshair, Cursor::Crosshair => CursorIcon::Crosshair,
Cursor::Text => MouseCursor::Text, Cursor::Text => CursorIcon::Text,
Cursor::VerticalText => MouseCursor::VerticalText, Cursor::VerticalText => CursorIcon::VerticalText,
Cursor::Alias => MouseCursor::Alias, Cursor::Alias => CursorIcon::Alias,
Cursor::Copy => MouseCursor::Copy, Cursor::Copy => CursorIcon::Copy,
Cursor::Move => MouseCursor::Move, Cursor::Move => CursorIcon::Move,
Cursor::NoDrop => MouseCursor::NoDrop, Cursor::NoDrop => CursorIcon::NoDrop,
Cursor::NotAllowed => MouseCursor::NotAllowed, Cursor::NotAllowed => CursorIcon::NotAllowed,
Cursor::Grab => MouseCursor::Grab, Cursor::Grab => CursorIcon::Grab,
Cursor::Grabbing => MouseCursor::Grabbing, Cursor::Grabbing => CursorIcon::Grabbing,
Cursor::EResize => MouseCursor::EResize, Cursor::EResize => CursorIcon::EResize,
Cursor::NResize => MouseCursor::NResize, Cursor::NResize => CursorIcon::NResize,
Cursor::NeResize => MouseCursor::NeResize, Cursor::NeResize => CursorIcon::NeResize,
Cursor::NwResize => MouseCursor::NwResize, Cursor::NwResize => CursorIcon::NwResize,
Cursor::SResize => MouseCursor::SResize, Cursor::SResize => CursorIcon::SResize,
Cursor::SeResize => MouseCursor::SeResize, Cursor::SeResize => CursorIcon::SeResize,
Cursor::SwResize => MouseCursor::SwResize, Cursor::SwResize => CursorIcon::SwResize,
Cursor::WResize => MouseCursor::WResize, Cursor::WResize => CursorIcon::WResize,
Cursor::EwResize => MouseCursor::EwResize, Cursor::EwResize => CursorIcon::EwResize,
Cursor::NsResize => MouseCursor::NsResize, Cursor::NsResize => CursorIcon::NsResize,
Cursor::NeswResize => MouseCursor::NeswResize, Cursor::NeswResize => CursorIcon::NeswResize,
Cursor::NwseResize => MouseCursor::NwseResize, Cursor::NwseResize => CursorIcon::NwseResize,
Cursor::ColResize => MouseCursor::ColResize, Cursor::ColResize => CursorIcon::ColResize,
Cursor::RowResize => MouseCursor::RowResize, Cursor::RowResize => CursorIcon::RowResize,
Cursor::AllScroll => MouseCursor::AllScroll, Cursor::AllScroll => CursorIcon::AllScroll,
Cursor::ZoomIn => MouseCursor::ZoomIn, Cursor::ZoomIn => CursorIcon::ZoomIn,
Cursor::ZoomOut => MouseCursor::ZoomOut, Cursor::ZoomOut => CursorIcon::ZoomOut,
_ => MouseCursor::Default, _ => CursorIcon::Default,
}; };
self.winit_window.set_cursor(winit_cursor); self.winit_window.set_cursor_icon(winit_cursor);
} }
fn is_animating(&self) -> bool { fn is_animating(&self) -> bool {
self.animation_state.get() == AnimationState::Animating self.animation_state.get() == AnimationState::Animating
} }
fn id(&self) -> winit::WindowId { fn id(&self) -> winit::window::WindowId {
self.winit_window.id() self.winit_window.id()
} }
fn winit_event_to_servo_event(&self, event: winit::WindowEvent) { fn winit_event_to_servo_event(&self, event: winit::event::WindowEvent) {
match event { match event {
winit::WindowEvent::ReceivedCharacter(ch) => self.handle_received_character(ch), winit::event::WindowEvent::ReceivedCharacter(ch) => self.handle_received_character(ch),
winit::WindowEvent::KeyboardInput { input, .. } => self.handle_keyboard_input(input), winit::event::WindowEvent::KeyboardInput { input, .. } => self.handle_keyboard_input(input),
winit::WindowEvent::MouseInput { state, button, .. } => { winit::event::WindowEvent::ModifiersChanged(state) => self.modifiers_state.set(state),
winit::event::WindowEvent::MouseInput { state, button, .. } => {
if button == MouseButton::Left || button == MouseButton::Right { if button == MouseButton::Left || button == MouseButton::Right {
self.handle_mouse(button, state, self.mouse_pos.get()); self.handle_mouse(button, state, self.mouse_pos.get());
} }
}, },
winit::WindowEvent::CursorMoved { position, .. } => { winit::event::WindowEvent::CursorMoved { position, .. } => {
let pos = position.to_physical(self.device_hidpi_factor().get() as f64); let (x, y): (i32, i32) = position.into();
let (x, y): (i32, i32) = pos.into();
self.mouse_pos.set(Point2D::new(x, y)); self.mouse_pos.set(Point2D::new(x, y));
self.event_queue self.event_queue
.borrow_mut() .borrow_mut()
@ -438,15 +432,15 @@ impl WindowPortsMethods for Window {
x as f32, y as f32, x as f32, y as f32,
))); )));
}, },
winit::WindowEvent::MouseWheel { delta, phase, .. } => { winit::event::WindowEvent::MouseWheel { delta, phase, .. } => {
let (mut dx, mut dy, mode) = match delta { let (mut dx, mut dy, mode) = match delta {
MouseScrollDelta::LineDelta(dx, dy) => { MouseScrollDelta::LineDelta(dx, dy) => {
(dx as f64, (dy * LINE_HEIGHT) as f64, WheelMode::DeltaLine) (dx as f64, (dy * LINE_HEIGHT) as f64, WheelMode::DeltaLine)
}, },
MouseScrollDelta::PixelDelta(position) => { MouseScrollDelta::PixelDelta(position) => {
let position = let position: LogicalPosition<f64> =
position.to_physical(self.device_hidpi_factor().get() as f64); position.to_logical(self.device_hidpi_factor().get() as f64);
(position.x as f64, position.y as f64, WheelMode::DeltaPixel) (position.x, position.y, WheelMode::DeltaPixel)
}, },
}; };
@ -478,30 +472,24 @@ impl WindowPortsMethods for Window {
self.event_queue.borrow_mut().push(wheel_event); self.event_queue.borrow_mut().push(wheel_event);
self.event_queue.borrow_mut().push(scroll_event); self.event_queue.borrow_mut().push(scroll_event);
}, },
winit::WindowEvent::Touch(touch) => { winit::event::WindowEvent::Touch(touch) => {
use servo::script_traits::TouchId; use servo::script_traits::TouchId;
let phase = winit_phase_to_touch_event_type(touch.phase); let phase = winit_phase_to_touch_event_type(touch.phase);
let id = TouchId(touch.id as i32); let id = TouchId(touch.id as i32);
let position = touch let position = touch.location;
.location
.to_physical(self.device_hidpi_factor().get() as f64);
let point = Point2D::new(position.x as f32, position.y as f32); let point = Point2D::new(position.x as f32, position.y as f32);
self.event_queue self.event_queue
.borrow_mut() .borrow_mut()
.push(WindowEvent::Touch(phase, id, point)); .push(WindowEvent::Touch(phase, id, point));
}, },
winit::WindowEvent::Refresh => { winit::event::WindowEvent::CloseRequested => {
self.event_queue.borrow_mut().push(WindowEvent::Refresh);
},
winit::WindowEvent::CloseRequested => {
self.event_queue.borrow_mut().push(WindowEvent::Quit); self.event_queue.borrow_mut().push(WindowEvent::Quit);
}, },
winit::WindowEvent::Resized(size) => { winit::event::WindowEvent::Resized(physical_size) => {
let (width, height) = size.into(); let (width, height) = physical_size.into();
let new_size = Size2D::new(width, height); let new_size = Size2D::new(width, height);
if self.inner_size.get() != new_size { if self.inner_size.get() != new_size {
let physical_size = size.to_physical(self.device_hidpi_factor().get() as f64);
let physical_size = Size2D::new(physical_size.width, physical_size.height); let physical_size = Size2D::new(physical_size.width, physical_size.height);
self.webrender_surfman self.webrender_surfman
.resize(physical_size.to_i32()) .resize(physical_size.to_i32())
@ -514,21 +502,20 @@ impl WindowPortsMethods for Window {
} }
} }
fn new_glwindow(&self, events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow> { fn new_glwindow(
let size = self &self,
.winit_window event_loop: &winit::event_loop::EventLoopWindowTarget<ServoEvent>
.get_outer_size() ) -> Box<dyn webxr::glwindow::GlWindow> {
.expect("Failed to get window outer size"); let size = self.winit_window.outer_size();
let mut window_builder = winit::WindowBuilder::new() let mut window_builder = winit::window::WindowBuilder::new()
.with_title("Servo XR".to_string()) .with_title("Servo XR".to_string())
.with_dimensions(size) .with_inner_size(size)
.with_visibility(true); .with_visible(true);
window_builder = builder_with_platform_options(window_builder); window_builder = builder_with_platform_options(window_builder);
let winit_window = window_builder let winit_window = window_builder.build(event_loop)
.build(events_loop.as_winit())
.expect("Failed to create window."); .expect("Failed to create window.");
let pose = Rc::new(XRWindowPose { let pose = Rc::new(XRWindowPose {
@ -542,24 +529,23 @@ impl WindowPortsMethods for Window {
impl WindowMethods for Window { impl WindowMethods for Window {
fn get_coordinates(&self) -> EmbedderCoordinates { fn get_coordinates(&self) -> EmbedderCoordinates {
// TODO(ajeffrey): can this fail? // Needed to convince the type system that winit's physical pixels
let dpr = self.device_hidpi_factor(); // are actually device pixels.
let LogicalSize { width, height } = self let dpr: Scale<f32, DeviceIndependentPixel, DevicePixel> = Scale::new(1.0);
let PhysicalSize { width, height } = self
.winit_window .winit_window
.get_outer_size() .outer_size();
.expect("Failed to get window outer size."); let PhysicalPosition { x, y } = self
let LogicalPosition { x, y } = self
.winit_window .winit_window
.get_position() .outer_position()
.unwrap_or(LogicalPosition::new(0., 0.)); .unwrap_or(PhysicalPosition::new(0, 0));
let win_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32(); let win_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32();
let win_origin = (Point2D::new(x as f32, y as f32) * dpr).to_i32(); let win_origin = (Point2D::new(x as f32, y as f32) * dpr).to_i32();
let screen = (self.screen_size.to_f32() * dpr).to_i32(); let screen = (self.screen_size.to_f32() * dpr).to_i32();
let LogicalSize { width, height } = self let PhysicalSize { width, height } = self
.winit_window .winit_window
.get_inner_size() .inner_size();
.expect("Failed to get window inner size.");
let inner_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32(); let inner_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32();
let viewport = DeviceIntRect::new(Point2D::zero(), inner_size); let viewport = DeviceIntRect::new(Point2D::zero(), inner_size);
let framebuffer = DeviceIntSize::from_untyped(viewport.size.to_untyped()); let framebuffer = DeviceIntSize::from_untyped(viewport.size.to_untyped());
@ -684,7 +670,7 @@ fn load_icon(icon_bytes: &[u8]) -> Icon {
} }
struct XRWindow { struct XRWindow {
winit_window: winit::Window, winit_window: winit::window::Window,
pose: Rc<XRWindowPose>, pose: Rc<XRWindowPose>,
} }
@ -757,8 +743,8 @@ impl XRWindowPose {
self.xr_translation.set(vec); self.xr_translation.set(vec);
} }
fn handle_xr_rotation(&self, input: &KeyboardInput) { fn handle_xr_rotation(&self, input: &KeyboardInput, modifiers: ModifiersState) {
if input.state != winit::ElementState::Pressed { if input.state != winit::event::ElementState::Pressed {
return; return;
} }
let mut x = 0.0; let mut x = 0.0;
@ -770,7 +756,7 @@ impl XRWindowPose {
Some(VirtualKeyCode::Right) => y = -1.0, Some(VirtualKeyCode::Right) => y = -1.0,
_ => return, _ => return,
}; };
if input.modifiers.shift { if modifiers.shift() {
x = 10.0 * x; x = 10.0 * x;
y = 10.0 * y; y = 10.0 * y;
} }

View file

@ -4,7 +4,7 @@
//! A headless window implementation. //! A headless window implementation.
use crate::events_loop::EventsLoop; use crate::events_loop::ServoEvent;
use crate::window_trait::WindowPortsMethods; use crate::window_trait::WindowPortsMethods;
use euclid::{Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D}; use euclid::{Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D};
use servo::compositing::windowing::{AnimationState, WindowEvent}; use servo::compositing::windowing::{AnimationState, WindowEvent};
@ -71,8 +71,8 @@ impl WindowPortsMethods for Window {
false false
} }
fn id(&self) -> winit::WindowId { fn id(&self) -> winit::window::WindowId {
unsafe { winit::WindowId::dummy() } unsafe { winit::window::WindowId::dummy() }
} }
fn page_height(&self) -> f32 { fn page_height(&self) -> f32 {
@ -98,11 +98,14 @@ impl WindowPortsMethods for Window {
self.animation_state.get() == AnimationState::Animating self.animation_state.get() == AnimationState::Animating
} }
fn winit_event_to_servo_event(&self, _event: winit::WindowEvent) { fn winit_event_to_servo_event(&self, _event: winit::event::WindowEvent) {
// Not expecting any winit events. // Not expecting any winit events.
} }
fn new_glwindow(&self, _events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow> { fn new_glwindow(
&self,
_events_loop: &winit::event_loop::EventLoopWindowTarget<ServoEvent>
) -> Box<dyn webxr::glwindow::GlWindow> {
unimplemented!() unimplemented!()
} }
} }

View file

@ -2,8 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use winit::event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode};
use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers}; use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers};
use winit::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode};
// Some shortcuts use Cmd on Mac and Control on other systems. // Some shortcuts use Cmd on Mac and Control on other systems.
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
@ -18,7 +18,7 @@ pub const CMD_OR_ALT: Modifiers = Modifiers::META;
pub const CMD_OR_ALT: Modifiers = Modifiers::ALT; pub const CMD_OR_ALT: Modifiers = Modifiers::ALT;
fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key { fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key {
use winit::VirtualKeyCode::*; use winit::event::VirtualKeyCode::*;
// TODO: figure out how to map NavigateForward, NavigateBackward // TODO: figure out how to map NavigateForward, NavigateBackward
// TODO: map the remaining keys if possible // TODO: map the remaining keys if possible
let key = if let Some(key) = key { let key = if let Some(key) = key {
@ -127,7 +127,7 @@ fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key {
} }
fn get_servo_location_from_winit_key(key: Option<VirtualKeyCode>) -> Location { fn get_servo_location_from_winit_key(key: Option<VirtualKeyCode>) -> Location {
use winit::VirtualKeyCode::*; use winit::event::VirtualKeyCode::*;
// TODO: add more numpad keys // TODO: add more numpad keys
let key = if let Some(key) = key { let key = if let Some(key) = key {
key key
@ -243,14 +243,14 @@ fn get_servo_code_from_scancode(_scancode: u32) -> Code {
fn get_modifiers(mods: ModifiersState) -> Modifiers { fn get_modifiers(mods: ModifiersState) -> Modifiers {
let mut modifiers = Modifiers::empty(); let mut modifiers = Modifiers::empty();
modifiers.set(Modifiers::CONTROL, mods.ctrl); modifiers.set(Modifiers::CONTROL, mods.ctrl());
modifiers.set(Modifiers::SHIFT, mods.shift); modifiers.set(Modifiers::SHIFT, mods.shift());
modifiers.set(Modifiers::ALT, mods.alt); modifiers.set(Modifiers::ALT, mods.alt());
modifiers.set(Modifiers::META, mods.logo); modifiers.set(Modifiers::META, mods.logo());
modifiers modifiers
} }
pub fn keyboard_event_from_winit(input: KeyboardInput) -> KeyboardEvent { pub fn keyboard_event_from_winit(input: KeyboardInput, state: ModifiersState) -> KeyboardEvent {
info!("winit keyboard input: {:?}", input); info!("winit keyboard input: {:?}", input);
KeyboardEvent { KeyboardEvent {
state: match input.state { state: match input.state {
@ -260,7 +260,7 @@ pub fn keyboard_event_from_winit(input: KeyboardInput) -> KeyboardEvent {
key: get_servo_key_from_winit_key(input.virtual_keycode), key: get_servo_key_from_winit_key(input.virtual_keycode),
code: get_servo_code_from_scancode(input.scancode), code: get_servo_code_from_scancode(input.scancode),
location: get_servo_location_from_winit_key(input.virtual_keycode), location: get_servo_location_from_winit_key(input.virtual_keycode),
modifiers: get_modifiers(input.modifiers), modifiers: get_modifiers(state),
repeat: false, repeat: false,
is_composing: false, is_composing: false,
} }

View file

@ -5,7 +5,7 @@
//! Definition of Window. //! Definition of Window.
//! Implemented by headless and headed windows. //! Implemented by headless and headed windows.
use crate::events_loop::EventsLoop; use crate::events_loop::ServoEvent;
use servo::compositing::windowing::{WindowEvent, WindowMethods}; use servo::compositing::windowing::{WindowEvent, WindowMethods};
use servo::embedder_traits::Cursor; use servo::embedder_traits::Cursor;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize}; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
@ -16,16 +16,19 @@ pub const LINE_HEIGHT: f32 = 38.0;
pub trait WindowPortsMethods: WindowMethods { pub trait WindowPortsMethods: WindowMethods {
fn get_events(&self) -> Vec<WindowEvent>; fn get_events(&self) -> Vec<WindowEvent>;
fn id(&self) -> winit::WindowId; fn id(&self) -> winit::window::WindowId;
fn has_events(&self) -> bool; fn has_events(&self) -> bool;
fn page_height(&self) -> f32; fn page_height(&self) -> f32;
fn get_fullscreen(&self) -> bool; fn get_fullscreen(&self) -> bool;
fn winit_event_to_servo_event(&self, event: winit::WindowEvent); fn winit_event_to_servo_event(&self, event: winit::event::WindowEvent);
fn is_animating(&self) -> bool; fn is_animating(&self) -> bool;
fn set_title(&self, _title: &str) {} fn set_title(&self, _title: &str) {}
fn set_inner_size(&self, _size: DeviceIntSize) {} fn set_inner_size(&self, _size: DeviceIntSize) {}
fn set_position(&self, _point: DeviceIntPoint) {} fn set_position(&self, _point: DeviceIntPoint) {}
fn set_fullscreen(&self, _state: bool) {} fn set_fullscreen(&self, _state: bool) {}
fn set_cursor(&self, _cursor: Cursor) {} fn set_cursor(&self, _cursor: Cursor) {}
fn new_glwindow(&self, events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow>; fn new_glwindow(
&self,
events_loop: &winit::event_loop::EventLoopWindowTarget<ServoEvent>
) -> Box<dyn webxr::glwindow::GlWindow>;
} }

View file

@ -67,17 +67,18 @@ packages = [
# Lots of crates to update. # Lots of crates to update.
"smallvec", "smallvec",
# https://github.com/servo/servo/issues/24421
"proc-macro2",
"quote",
"unicode-xid",
# https://github.com/servo/servo/pull/25518 # https://github.com/servo/servo/pull/25518
"core-foundation", "core-foundation",
"core-foundation-sys", "core-foundation-sys",
"core-graphics", "core-graphics",
"lyon_geom", "lyon_geom",
# https://github.com/servo/servo/pull/28236
"dlib",
"nix",
"nom",
"strsim",
# Duplicated by webrender debugger via ws # Duplicated by webrender debugger via ws
"digest", "digest",
"generic-array", "generic-array",

View file

@ -1,2 +0,0 @@
[flexible-order.html]
expected: FAIL