diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index e787f198d48..4bfe455ab5b 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -9,14 +9,12 @@ use euclid::TypedScale; use gleam::gl; use ipc_channel::ipc::IpcSender; use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection}; -use net_traits::net_error_list::NetError; -use script_traits::{LoadData, MouseButton, TouchEventType, TouchId}; +use script_traits::{MouseButton, TouchEventType, TouchId}; use servo_geometry::{DeviceIndependentPixel, DeviceUintLength}; use servo_url::ServoUrl; use std::fmt::{Debug, Error, Formatter}; use std::rc::Rc; use style_traits::DevicePixel; -use style_traits::cursor::CursorKind; use webrender_api::{DeviceIntPoint, DevicePoint, DeviceUintSize, DeviceUintRect, ScrollLocation}; #[derive(Clone)] @@ -123,64 +121,23 @@ pub enum AnimationState { pub trait WindowMethods { /// Presents the window to the screen (perhaps by page flipping). fn present(&self); - - /// Get the coordinates of the native window, the screen and the framebuffer. - fn get_coordinates(&self) -> EmbedderCoordinates; - /// Set the size inside of borders and head - fn set_inner_size(&self, ctx: TopLevelBrowsingContextId, size: DeviceUintSize); - /// Set the window position - fn set_position(&self, ctx: TopLevelBrowsingContextId, point: DeviceIntPoint); - /// Set fullscreen state - fn set_fullscreen_state(&self, ctx: TopLevelBrowsingContextId, state: bool); - - /// Sets the page title for the current page. - fn set_page_title(&self, ctx: TopLevelBrowsingContextId, title: Option); - /// Called when the browser chrome should display a status message. - fn status(&self, ctx: TopLevelBrowsingContextId, Option); - /// Called when the browser has started loading a frame. - fn load_start(&self, ctx: TopLevelBrowsingContextId); - /// Called when the browser is done loading a frame. - fn load_end(&self, ctx: TopLevelBrowsingContextId); - /// Called when the browser encounters an error while loading a URL - fn load_error(&self, ctx: TopLevelBrowsingContextId, code: NetError, url: String); - /// Wether or not to follow a link - fn allow_navigation(&self, ctx: TopLevelBrowsingContextId, url: ServoUrl, IpcSender); - /// Called when the tag has finished parsing - fn head_parsed(&self, ctx: TopLevelBrowsingContextId); - /// Called when the history state has changed. - fn history_changed(&self, ctx: TopLevelBrowsingContextId, Vec, usize); - - /// Returns a thread-safe object to wake up the window's event loop. - fn create_event_loop_waker(&self) -> Box; - /// Requests that the window system prepare a composite. Typically this will involve making /// some type of platform-specific graphics context current. Returns true if the composite may /// proceed and false if it should not. fn prepare_for_composite(&self, width: DeviceUintLength, height: DeviceUintLength) -> bool; - - /// Sets the cursor to be used in the window. - fn set_cursor(&self, cursor: CursorKind); - - /// Process a key event. - fn handle_key(&self, ctx: Option, ch: Option, key: Key, mods: KeyModifiers); - - /// Does this window support a clipboard - fn supports_clipboard(&self) -> bool; - - /// Add a favicon - fn set_favicon(&self, ctx: TopLevelBrowsingContextId, url: ServoUrl); - /// Return the GL function pointer trait. fn gl(&self) -> Rc; - + /// Returns a thread-safe object to wake up the window's event loop. + fn create_event_loop_waker(&self) -> Box; + /// Get the coordinates of the native window, the screen and the framebuffer. + fn get_coordinates(&self) -> EmbedderCoordinates; + /// Does this window support a clipboard + fn supports_clipboard(&self) -> bool; /// Set whether the application is currently animating. /// Typically, when animations are active, the window /// will want to avoid blocking on UI events, and just /// run the event loop at the vsync interval. - fn set_animation_state(&self, _state: AnimationState) {} - - /// Called when a pipeline panics. - fn handle_panic(&self, browser_id: TopLevelBrowsingContextId, reason: String, backtrace: Option); + fn set_animation_state(&self, _state: AnimationState); } #[derive(Clone, Copy, Debug)] diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 110660c79f4..a54d5dd52dd 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -86,7 +86,6 @@ use gaol::sandbox::{ChildSandbox, ChildSandboxMethods}; use gfx::font_cache_thread::FontCacheThread; use ipc_channel::ipc::{self, IpcSender}; use log::{Log, LogMetadata, LogRecord}; -use msg::constellation_msg::KeyState; use net::resource_thread::new_resource_threads; use net_traits::IpcSend; use profile::mem as profile_mem; @@ -124,7 +123,8 @@ pub use msg::constellation_msg::TopLevelBrowsingContextId as BrowserId; pub struct Servo { compositor: IOCompositor, constellation_chan: Sender, - embedder_receiver: EmbedderReceiver + embedder_receiver: EmbedderReceiver, + embedder_events: Vec, } impl Servo where Window: WindowMethods + 'static { @@ -255,6 +255,7 @@ impl Servo where Window: WindowMethods + 'static { compositor: compositor, constellation_chan: constellation_chan, embedder_receiver: embedder_receiver, + embedder_events: Vec::new(), } } @@ -371,83 +372,17 @@ impl Servo where Window: WindowMethods + 'static { (_, ShutdownState::ShuttingDown) => {}, - (EmbedderMsg::Status(top_level_browsing_context, message), ShutdownState::NotShuttingDown) => { - self.compositor.window.status(top_level_browsing_context, message); + (msg, ShutdownState::NotShuttingDown) => { + self.embedder_events.push(msg); }, - - (EmbedderMsg::ChangePageTitle(top_level_browsing_context, title), ShutdownState::NotShuttingDown) => { - self.compositor.window.set_page_title(top_level_browsing_context, title); - }, - - (EmbedderMsg::MoveTo(top_level_browsing_context, point), - ShutdownState::NotShuttingDown) => { - self.compositor.window.set_position(top_level_browsing_context, point); - }, - - (EmbedderMsg::ResizeTo(top_level_browsing_context, size), - ShutdownState::NotShuttingDown) => { - self.compositor.window.set_inner_size(top_level_browsing_context, size); - }, - - (EmbedderMsg::AllowNavigation(top_level_browsing_context, - url, - response_chan), - ShutdownState::NotShuttingDown) => { - self.compositor.window.allow_navigation(top_level_browsing_context, url, response_chan); - }, - - (EmbedderMsg::KeyEvent(top_level_browsing_context, - ch, - key, - state, - modified), - ShutdownState::NotShuttingDown) => { - if state == KeyState::Pressed { - self.compositor.window.handle_key(top_level_browsing_context, ch, key, modified); - } - }, - - (EmbedderMsg::SetCursor(cursor), ShutdownState::NotShuttingDown) => { - self.compositor.window.set_cursor(cursor) - }, - - (EmbedderMsg::NewFavicon(top_level_browsing_context, url), ShutdownState::NotShuttingDown) => { - self.compositor.window.set_favicon(top_level_browsing_context, url); - }, - - (EmbedderMsg::HeadParsed(top_level_browsing_context, ), ShutdownState::NotShuttingDown) => { - self.compositor.window.head_parsed(top_level_browsing_context, ); - }, - - (EmbedderMsg::HistoryChanged(top_level_browsing_context, entries, current), - ShutdownState::NotShuttingDown) => { - self.compositor.window.history_changed(top_level_browsing_context, entries, current); - }, - - (EmbedderMsg::SetFullscreenState(top_level_browsing_context, state), - ShutdownState::NotShuttingDown) => { - self.compositor.window.set_fullscreen_state(top_level_browsing_context, state); - }, - - (EmbedderMsg::LoadStart(top_level_browsing_context), ShutdownState::NotShuttingDown) => { - self.compositor.window.load_start(top_level_browsing_context); - }, - - (EmbedderMsg::LoadComplete(top_level_browsing_context), ShutdownState::NotShuttingDown) => { - // Inform the embedder that the load has finished. - // - // TODO(pcwalton): Specify which frame's load completed. - self.compositor.window.load_end(top_level_browsing_context); - }, - (EmbedderMsg::Panic(top_level_browsing_context, reason, backtrace), - ShutdownState::NotShuttingDown) => { - self.compositor.window.handle_panic(top_level_browsing_context, reason, backtrace); - }, - } } } + pub fn get_events(&mut self) -> Vec { + ::std::mem::replace(&mut self.embedder_events, Vec::new()) + } + pub fn handle_events(&mut self, events: Vec) -> bool { if self.compositor.receive_messages() { self.receive_messages(); diff --git a/ports/servo/glutin_app/window.rs b/ports/servo/glutin_app/window.rs index cf98c816829..7e49cc9d82e 100644 --- a/ports/servo/glutin_app/window.rs +++ b/ports/servo/glutin_app/window.rs @@ -4,7 +4,7 @@ //! A windowing implementation using glutin. -use compositing::compositor_thread::EventLoopWaker; +use compositing::compositor_thread::{EmbedderMsg, EventLoopWaker}; use compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent}; use compositing::windowing::{EmbedderCoordinates, WebRenderDebugOption, WindowMethods}; use euclid::{Length, TypedPoint2D, TypedVector2D, TypedScale, TypedSize2D}; @@ -15,7 +15,6 @@ use glutin; use glutin::{Api, GlContext, GlRequest}; use msg::constellation_msg::{self, Key, TopLevelBrowsingContextId as BrowserId}; use msg::constellation_msg::{KeyModifiers, KeyState, TraversalDirection}; -use net_traits::net_error_list::NetError; use net_traits::pub_domains::is_reg_domain; #[cfg(any(target_os = "linux", target_os = "macos"))] use osmesa_sys; @@ -582,6 +581,27 @@ impl Window { mem::replace(&mut *self.event_queue.borrow_mut(), Vec::new()) } + pub fn handle_servo_events(&self, events: Vec) { + for event in events { + match event { + EmbedderMsg::Status(top_level_browsing_context, message) => self.status(top_level_browsing_context, message), + EmbedderMsg::ChangePageTitle(top_level_browsing_context, title) => self.set_page_title(top_level_browsing_context, title), + EmbedderMsg::MoveTo(top_level_browsing_context, point) => self.set_position(top_level_browsing_context, point), + EmbedderMsg::ResizeTo(top_level_browsing_context, size) => self.set_inner_size(top_level_browsing_context, size), + EmbedderMsg::AllowNavigation(top_level_browsing_context, url, response_chan) => self.allow_navigation(top_level_browsing_context, url, response_chan), + EmbedderMsg::KeyEvent(top_level_browsing_context, ch, key, state, modified) => self.handle_key(top_level_browsing_context, ch, key, state, modified), + EmbedderMsg::SetCursor(cursor) => self.set_cursor(cursor), + EmbedderMsg::NewFavicon(top_level_browsing_context, url) => self.set_favicon(top_level_browsing_context, url), + EmbedderMsg::HeadParsed(top_level_browsing_context, ) => self.head_parsed(top_level_browsing_context, ), + EmbedderMsg::HistoryChanged(top_level_browsing_context, entries, current) => self.history_changed(top_level_browsing_context, entries, current), + EmbedderMsg::SetFullscreenState(top_level_browsing_context, state) => self.set_fullscreen_state(top_level_browsing_context, state), + EmbedderMsg::LoadStart(top_level_browsing_context) => self.load_start(top_level_browsing_context), + EmbedderMsg::LoadComplete(top_level_browsing_context) => self.load_end(top_level_browsing_context), + EmbedderMsg::Panic(top_level_browsing_context, reason, backtrace) => self.handle_panic(top_level_browsing_context, reason, backtrace), + } + } + } + fn is_animating(&self) -> bool { self.animation_state.get() == AnimationState::Animating && !self.suspended.get() } @@ -913,56 +933,6 @@ impl Window { let ppi = unsafe { gdi32::GetDeviceCaps(hdc, winapi::wingdi::LOGPIXELSY) }; TypedScale::new(ppi as f32 / 96.0) } -} - -impl WindowMethods for Window { - fn gl(&self) -> Rc { - self.gl.clone() - } - - fn get_coordinates(&self) -> EmbedderCoordinates { - let dpr = self.hidpi_factor(); - match self.kind { - WindowKind::Window(ref window, _) => { - // TODO(ajeffrey): can this fail? - let (width, height) = window.get_outer_size().expect("Failed to get window outer size."); - let (x, y) = window.get_position().unwrap_or((0, 0)); - let win_size = (TypedSize2D::new(width as f32, height as f32) * dpr).to_u32(); - let win_origin = (TypedPoint2D::new(x as f32, y as f32) * dpr).to_i32(); - let screen = (self.screen_size.to_f32() * dpr).to_u32(); - - let (width, height) = window.get_inner_size().expect("Failed to get window inner size."); - let inner_size = (TypedSize2D::new(width as f32, height as f32) * dpr).to_u32(); - - let viewport = DeviceUintRect::new(TypedPoint2D::zero(), inner_size); - - EmbedderCoordinates { - viewport: viewport, - framebuffer: inner_size, - window: (win_size, win_origin), - screen: screen, - // FIXME: Glutin doesn't have API for available size. Fallback to screen size - screen_avail: screen, - hidpi_factor: dpr, - } - }, - WindowKind::Headless(ref context) => { - let size = (TypedSize2D::new(context.width, context.height).to_f32() * dpr).to_u32(); - EmbedderCoordinates { - viewport: DeviceUintRect::new(TypedPoint2D::zero(), size), - framebuffer: size, - window: (size, TypedPoint2D::zero()), - screen: size, - screen_avail: size, - hidpi_factor: dpr, - } - } - } - } - - fn set_animation_state(&self, state: AnimationState) { - self.animation_state.set(state); - } fn set_inner_size(&self, _: BrowserId, size: DeviceUintSize) { match self.kind { @@ -996,53 +966,6 @@ impl WindowMethods for Window { self.fullscreen.set(state); } - fn present(&self) { - match self.kind { - WindowKind::Window(ref window, ..) => { - if let Err(err) = window.swap_buffers() { - warn!("Failed to swap window buffers ({}).", err); - } - } - WindowKind::Headless(..) => {} - } - } - - fn create_event_loop_waker(&self) -> Box { - struct GlutinEventLoopWaker { - proxy: Option>, - } - impl GlutinEventLoopWaker { - fn new(window: &Window) -> GlutinEventLoopWaker { - let proxy = match window.kind { - WindowKind::Window(_, ref events_loop) => { - Some(Arc::new(events_loop.borrow().create_proxy())) - }, - WindowKind::Headless(..) => { - None - } - }; - GlutinEventLoopWaker { proxy } - } - } - impl EventLoopWaker for GlutinEventLoopWaker { - fn wake(&self) { - // kick the OS event loop awake. - if let Some(ref proxy) = self.proxy { - if let Err(err) = proxy.wakeup() { - warn!("Failed to wake up event loop ({}).", err); - } - } - } - fn clone(&self) -> Box { - Box::new(GlutinEventLoopWaker { - proxy: self.proxy.clone(), - }) - } - } - - Box::new(GlutinEventLoopWaker::new(&self)) - } - fn set_page_title(&self, _: BrowserId, title: Option) { match self.kind { WindowKind::Window(ref window, ..) => { @@ -1084,9 +1007,6 @@ impl WindowMethods for Window { *self.current_url.borrow_mut() = Some(history[current].url.clone()); } - fn load_error(&self, _: BrowserId, _: NetError, _: String) { - } - fn head_parsed(&self, _: BrowserId) { } @@ -1143,12 +1063,11 @@ impl WindowMethods for Window { fn set_favicon(&self, _: BrowserId, _: ServoUrl) { } - fn prepare_for_composite(&self, _width: Length, _height: Length) -> bool { - true - } - /// Helper function to handle keyboard events. - fn handle_key(&self, _: Option, ch: Option, key: Key, mods: constellation_msg::KeyModifiers) { + fn handle_key(&self, _: Option, ch: Option, key: Key, state: KeyState, mods: constellation_msg::KeyModifiers) { + if state == KeyState::Pressed { + return; + } let browser_id = match self.browser_id.get() { Some(id) => id, None => { unreachable!("Can't get keys without a browser"); } @@ -1283,12 +1202,113 @@ impl WindowMethods for Window { }; } - fn supports_clipboard(&self) -> bool { + fn handle_panic(&self, _: BrowserId, _reason: String, _backtrace: Option) { + // Nothing to do here yet. The crash has already been reported on the console. + } +} + +impl WindowMethods for Window { + fn gl(&self) -> Rc { + self.gl.clone() + } + + fn get_coordinates(&self) -> EmbedderCoordinates { + let dpr = self.hidpi_factor(); + match self.kind { + WindowKind::Window(ref window, _) => { + // TODO(ajeffrey): can this fail? + let (width, height) = window.get_outer_size().expect("Failed to get window outer size."); + let (x, y) = window.get_position().unwrap_or((0, 0)); + let win_size = (TypedSize2D::new(width as f32, height as f32) * dpr).to_u32(); + let win_origin = (TypedPoint2D::new(x as f32, y as f32) * dpr).to_i32(); + let screen = (self.screen_size.to_f32() * dpr).to_u32(); + + let (width, height) = window.get_inner_size().expect("Failed to get window inner size."); + let inner_size = (TypedSize2D::new(width as f32, height as f32) * dpr).to_u32(); + + let viewport = DeviceUintRect::new(TypedPoint2D::zero(), inner_size); + + EmbedderCoordinates { + viewport: viewport, + framebuffer: inner_size, + window: (win_size, win_origin), + screen: screen, + // FIXME: Glutin doesn't have API for available size. Fallback to screen size + screen_avail: screen, + hidpi_factor: dpr, + } + }, + WindowKind::Headless(ref context) => { + let size = (TypedSize2D::new(context.width, context.height).to_f32() * dpr).to_u32(); + EmbedderCoordinates { + viewport: DeviceUintRect::new(TypedPoint2D::zero(), size), + framebuffer: size, + window: (size, TypedPoint2D::zero()), + screen: size, + screen_avail: size, + hidpi_factor: dpr, + } + } + } + } + + fn present(&self) { + match self.kind { + WindowKind::Window(ref window, ..) => { + if let Err(err) = window.swap_buffers() { + warn!("Failed to swap window buffers ({}).", err); + } + } + WindowKind::Headless(..) => {} + } + } + + fn create_event_loop_waker(&self) -> Box { + struct GlutinEventLoopWaker { + proxy: Option>, + } + impl GlutinEventLoopWaker { + fn new(window: &Window) -> GlutinEventLoopWaker { + let proxy = match window.kind { + WindowKind::Window(_, ref events_loop) => { + Some(Arc::new(events_loop.borrow().create_proxy())) + }, + WindowKind::Headless(..) => { + None + } + }; + GlutinEventLoopWaker { proxy } + } + } + impl EventLoopWaker for GlutinEventLoopWaker { + fn wake(&self) { + // kick the OS event loop awake. + if let Some(ref proxy) = self.proxy { + if let Err(err) = proxy.wakeup() { + warn!("Failed to wake up event loop ({}).", err); + } + } + } + fn clone(&self) -> Box { + Box::new(GlutinEventLoopWaker { + proxy: self.proxy.clone(), + }) + } + } + + Box::new(GlutinEventLoopWaker::new(&self)) + } + + fn set_animation_state(&self, state: AnimationState) { + self.animation_state.set(state); + } + + fn prepare_for_composite(&self, _width: Length, _height: Length) -> bool { true } - fn handle_panic(&self, _: BrowserId, _reason: String, _backtrace: Option) { - // Nothing to do here yet. The crash has already been reported on the console. + fn supports_clipboard(&self) -> bool { + true } } diff --git a/ports/servo/main.rs b/ports/servo/main.rs index 3c025675877..d440bf53bcf 100644 --- a/ports/servo/main.rs +++ b/ports/servo/main.rs @@ -184,15 +184,16 @@ fn main() { servo.setup_logging(); window.run(|| { - let events = window.get_events(); - let need_resize = events.iter().any(|e| match *e { + let win_events = window.get_events(); + let need_resize = win_events.iter().any(|e| match *e { WindowEvent::Resize => true, _ => false }); - let stop = !servo.handle_events(events); + let stop = !servo.handle_events(win_events); if need_resize { servo.repaint_synchronously(); } + window.handle_servo_events(servo.get_events()); stop });