diff --git a/Cargo.lock b/Cargo.lock index 889295a4ac8..2411ae37055 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,6 +182,7 @@ dependencies = [ "bluetooth_traits 0.0.1", "compositing 0.0.1", "device 0.0.1 (git+https://github.com/servo/devices)", + "embedder_traits 0.0.1", "ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "servo_config 0.0.1", @@ -419,6 +420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "compositing" version = "0.0.1" dependencies = [ + "embedder_traits 0.0.1", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "gleam 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -772,7 +774,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "embedder_traits" version = "0.0.1" dependencies = [ + "ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "msg 0.0.1", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "servo_url 0.0.1", + "style_traits 0.0.1", + "webrender_api 0.57.2 (git+https://github.com/servo/webrender)", ] [[package]] @@ -1847,7 +1856,6 @@ version = "0.0.1" dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "brotli 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "compositing 0.0.1", "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "devtools_traits 0.0.1", "embedder_traits 0.0.1", @@ -2593,6 +2601,7 @@ dependencies = [ "canvas_traits 0.0.1", "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "devtools_traits 0.0.1", + "embedder_traits 0.0.1", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/bluetooth/Cargo.toml b/components/bluetooth/Cargo.toml index bc172342977..114772a7f99 100644 --- a/components/bluetooth/Cargo.toml +++ b/components/bluetooth/Cargo.toml @@ -14,8 +14,12 @@ bitflags = "1.0" bluetooth_traits = {path = "../bluetooth_traits"} compositing = {path = "../compositing"} device = {git = "https://github.com/servo/devices", features = ["bluetooth-test"]} +embedder_traits = {path = "../embedder_traits"} ipc-channel = "0.10" log = "0.4" servo_config = {path = "../config"} servo_rand = {path = "../rand"} uuid = {version = "0.6", features = ["v4"]} + +[dev-dependencies] +embedder_traits = { path = "../embedder_traits", features = ["tests"]} diff --git a/components/bluetooth/lib.rs b/components/bluetooth/lib.rs index 3df295b56e9..cc9693c69d6 100644 --- a/components/bluetooth/lib.rs +++ b/components/bluetooth/lib.rs @@ -5,8 +5,8 @@ #[macro_use] extern crate bitflags; extern crate bluetooth_traits; -extern crate compositing; extern crate device; +extern crate embedder_traits; extern crate ipc_channel; #[macro_use] extern crate log; @@ -21,9 +21,9 @@ use bluetooth_traits::{BluetoothDeviceMsg, BluetoothRequest, BluetoothResponse, use bluetooth_traits::{BluetoothError, BluetoothResponseResult, BluetoothResult}; use bluetooth_traits::blocklist::{uuid_is_blocklisted, Blocklist}; use bluetooth_traits::scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence, RequestDeviceoptions}; -use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy}; use device::bluetooth::{BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic}; use device::bluetooth::{BluetoothGATTDescriptor, BluetoothGATTService}; +use embedder_traits::{EmbedderMsg, EmbedderProxy}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use servo_config::opts; use servo_config::prefs::PREFS; @@ -382,7 +382,7 @@ impl BluetoothManager { } let (ipc_sender, ipc_receiver) = ipc::channel().expect("Failed to create IPC channel!"); - let msg = EmbedderMsg::GetSelectedBluetoothDevice(dialog_rows, ipc_sender); + let msg = (None, EmbedderMsg::GetSelectedBluetoothDevice(dialog_rows, ipc_sender)); self.embedder_proxy.send(msg); match ipc_receiver.recv() { diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml index 7715effd551..7dbd1e28688 100644 --- a/components/compositing/Cargo.toml +++ b/components/compositing/Cargo.toml @@ -14,6 +14,7 @@ path = "lib.rs" default = [] [dependencies] +embedder_traits = {path = "../embedder_traits"} euclid = "0.17" gfx_traits = {path = "../gfx_traits"} gleam = {version = "0.5", optional = true} @@ -36,3 +37,6 @@ webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} [build-dependencies] toml = "0.4.5" + +[dev-dependencies] +embedder_traits = { path = "../embedder_traits", features = ["tests"]} diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index 2e8dc7a66d6..76b3172b5dd 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -6,68 +6,21 @@ use SendableFrameTree; use compositor::CompositingReason; +use embedder_traits::EventLoopWaker; use gfx_traits::Epoch; use ipc_channel::ipc::IpcSender; -use msg::constellation_msg::{InputMethodType, Key, KeyModifiers, KeyState, PipelineId, TopLevelBrowsingContextId}; -use net_traits::filemanager_thread::FilterPattern; +use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId}; use net_traits::image::base::Image; use profile_traits::mem; use profile_traits::time; -use script_traits::{AnimationState, ConstellationMsg, EventResult, LoadData}; -use servo_url::ServoUrl; +use script_traits::{AnimationState, ConstellationMsg, EventResult}; use std::fmt::{Debug, Error, Formatter}; use std::sync::mpsc::{Receiver, Sender}; -use style_traits::cursor::CursorKind; use style_traits::viewport::ViewportConstraints; use webrender; use webrender_api::{self, DeviceIntPoint, DeviceUintSize}; -/// Used to wake up the event loop, provided by the servo port/embedder. -pub trait EventLoopWaker : 'static + Send { - fn clone(&self) -> Box; - fn wake(&self); -} - -/// Sends messages to the embedder. -pub struct EmbedderProxy { - pub sender: Sender, - pub event_loop_waker: Box, -} - -impl EmbedderProxy { - pub fn send(&self, msg: EmbedderMsg) { - // Send a message and kick the OS event loop awake. - if let Err(err) = self.sender.send(msg) { - warn!("Failed to send response ({}).", err); - } - self.event_loop_waker.wake(); - } -} - -impl Clone for EmbedderProxy { - fn clone(&self) -> EmbedderProxy { - EmbedderProxy { - sender: self.sender.clone(), - event_loop_waker: self.event_loop_waker.clone(), - } - } -} - -/// The port that the embedder receives messages on. -pub struct EmbedderReceiver { - pub receiver: Receiver -} - -impl EmbedderReceiver { - pub fn try_recv_embedder_msg(&mut self) -> Option { - self.receiver.try_recv().ok() - } - pub fn recv_embedder_msg(&mut self) -> EmbedderMsg { - self.receiver.recv().unwrap() - } -} - /// Sends messages to the compositor. pub struct CompositorProxy { pub sender: Sender, @@ -113,47 +66,6 @@ impl CompositorProxy { } } -pub enum EmbedderMsg { - /// A status message to be displayed by the browser chrome. - Status(TopLevelBrowsingContextId, Option), - /// Alerts the embedder that the current page has changed its title. - ChangePageTitle(TopLevelBrowsingContextId, Option), - /// Move the window to a point - MoveTo(TopLevelBrowsingContextId, DeviceIntPoint), - /// Resize the window to size - ResizeTo(TopLevelBrowsingContextId, DeviceUintSize), - /// Wether or not to follow a link - AllowNavigation(TopLevelBrowsingContextId, ServoUrl, IpcSender), - /// Sends an unconsumed key event back to the embedder. - KeyEvent(Option, Option, Key, KeyState, KeyModifiers), - /// Changes the cursor. - SetCursor(CursorKind), - /// A favicon was detected - NewFavicon(TopLevelBrowsingContextId, ServoUrl), - /// tag finished parsing - HeadParsed(TopLevelBrowsingContextId), - /// The history state has changed. - HistoryChanged(TopLevelBrowsingContextId, Vec, usize), - /// Enter or exit fullscreen - SetFullscreenState(TopLevelBrowsingContextId, bool), - /// The load of a page has begun - LoadStart(TopLevelBrowsingContextId), - /// The load of a page has completed - LoadComplete(TopLevelBrowsingContextId), - /// A pipeline panicked. First string is the reason, second one is the backtrace. - Panic(TopLevelBrowsingContextId, String, Option), - /// Open dialog to select bluetooth device. - GetSelectedBluetoothDevice(Vec, IpcSender>), - /// Open file dialog to select files. Set boolean flag to true allows to select multiple files. - SelectFiles(Vec, bool, IpcSender>>), - /// Request to present an IME to the user when an editable element is focused. - ShowIME(TopLevelBrowsingContextId, InputMethodType), - /// Request to hide the IME when the editable element is blurred. - HideIME(TopLevelBrowsingContextId), - /// Servo has shut down - Shutdown, -} - /// Messages from the painting thread and the constellation thread to the compositor thread. pub enum Msg { /// Requests that the compositor shut down. @@ -233,32 +145,6 @@ impl Debug for Msg { } } -impl Debug for EmbedderMsg { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - match *self { - EmbedderMsg::Status(..) => write!(f, "Status"), - EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"), - EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"), - EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"), - EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"), - EmbedderMsg::KeyEvent(..) => write!(f, "KeyEvent"), - EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"), - EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"), - EmbedderMsg::HeadParsed(..) => write!(f, "HeadParsed"), - EmbedderMsg::HistoryChanged(..) => write!(f, "HistoryChanged"), - EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"), - EmbedderMsg::LoadStart(..) => write!(f, "LoadStart"), - EmbedderMsg::LoadComplete(..) => write!(f, "LoadComplete"), - EmbedderMsg::Panic(..) => write!(f, "Panic"), - EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"), - EmbedderMsg::SelectFiles(..) => write!(f, "SelectFiles"), - EmbedderMsg::ShowIME(..) => write!(f, "ShowIME"), - EmbedderMsg::HideIME(..) => write!(f, "HideIME"), - EmbedderMsg::Shutdown => write!(f, "Shutdown"), - } - } -} - /// Data used to construct a compositor. pub struct InitialCompositorState { /// A channel to the compositor. diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index f19230ebcdd..59c7600fcfd 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -4,6 +4,7 @@ #![deny(unsafe_code)] +extern crate embedder_traits; extern crate euclid; extern crate gfx_traits; #[cfg(feature = "gleam")] diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 11143e5eaa9..b81b1e3ebc7 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -4,7 +4,7 @@ //! Abstract windowing methods. The concrete implementations of these can be found in `platform/`. -use compositor_thread::EventLoopWaker; +use embedder_traits::EventLoopWaker; use euclid::TypedScale; #[cfg(feature = "gleam")] use gleam::gl; @@ -78,6 +78,8 @@ pub enum WindowEvent { NewBrowser(ServoUrl, IpcSender), /// Close a top level browsing context CloseBrowser(TopLevelBrowsingContextId), + /// Panic a top level browsing context. + SendError(Option, String), /// Make a top level browsing context visible, hiding the previous /// visible one. SelectBrowser(TopLevelBrowsingContextId), @@ -106,6 +108,7 @@ impl Debug for WindowEvent { WindowEvent::Quit => write!(f, "Quit"), WindowEvent::Reload(..) => write!(f, "Reload"), WindowEvent::NewBrowser(..) => write!(f, "NewBrowser"), + WindowEvent::SendError(..) => write!(f, "SendError"), WindowEvent::CloseBrowser(..) => write!(f, "CloseBrowser"), WindowEvent::SelectBrowser(..) => write!(f, "SelectBrowser"), WindowEvent::ToggleWebRenderDebug(..) => write!(f, "ToggleWebRenderDebug"), diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 970073cafbf..2da318fef7d 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -98,10 +98,11 @@ use canvas_traits::canvas::CanvasId; use canvas_traits::canvas::CanvasMsg; use clipboard::{ClipboardContext, ClipboardProvider}; use compositing::SendableFrameTree; -use compositing::compositor_thread::{CompositorProxy, EmbedderMsg, EmbedderProxy}; +use compositing::compositor_thread::CompositorProxy; use compositing::compositor_thread::Msg as ToCompositorMsg; use debugger; use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg}; +use embedder_traits::{EmbedderMsg, EmbedderProxy}; use euclid::{Size2D, TypedSize2D, TypedScale}; use event_loop::EventLoop; use gfx::font_cache_thread::FontCacheThread; @@ -969,6 +970,15 @@ impl Constellation FromCompositorMsg::CloseBrowser(top_level_browsing_context_id) => { self.handle_close_top_level_browsing_context(top_level_browsing_context_id); } + // Panic a top level browsing context. + FromCompositorMsg::SendError(top_level_browsing_context_id, error) => { + debug!("constellation got SendError message"); + if let Some(id) = top_level_browsing_context_id { + self.handle_panic(id, error, None); + } else { + warn!("constellation got a SendError message without top level id"); + } + } // Send frame tree to WebRender. Make it visible. FromCompositorMsg::SelectBrowser(top_level_browsing_context_id) => { self.send_frame_tree(top_level_browsing_context_id); @@ -1014,12 +1024,10 @@ impl Constellation Some(ctx) => ctx, }; - let source_is_top_level_pipeline = self.browsing_contexts - .get(&BrowsingContextId::from(source_top_ctx_id)) - .map(|ctx| ctx.pipeline_id == source_pipeline_id) - .unwrap_or(false); - match content { + FromScriptMsg::ForwardToEmbedder(embedder_msg) => { + self.embedder_proxy.send((Some(source_top_ctx_id), embedder_msg)); + } FromScriptMsg::PipelineExited => { self.handle_pipeline_exited(source_pipeline_id); } @@ -1119,34 +1127,12 @@ impl Constellation warn!("Error replying to remove iframe ({})", e); } } - FromScriptMsg::NewFavicon(url) => { - if source_is_top_level_pipeline { - self.embedder_proxy.send(EmbedderMsg::NewFavicon(source_top_ctx_id, url)); - } - } - FromScriptMsg::HeadParsed => { - if source_is_top_level_pipeline { - self.embedder_proxy.send(EmbedderMsg::HeadParsed(source_top_ctx_id)); - } - } FromScriptMsg::CreateCanvasPaintThread(size, sender) => { self.handle_create_canvas_paint_thread_msg(&size, sender) } - FromScriptMsg::NodeStatus(message) => { - self.embedder_proxy.send(EmbedderMsg::Status(source_top_ctx_id, message)); - } FromScriptMsg::SetDocumentState(state) => { self.document_states.insert(source_pipeline_id, state); } - FromScriptMsg::Alert(message, sender) => { - self.handle_alert(source_top_ctx_id, message, sender); - } - FromScriptMsg::MoveTo(point) => { - self.embedder_proxy.send(EmbedderMsg::MoveTo(source_top_ctx_id, point)); - } - FromScriptMsg::ResizeTo(size) => { - self.embedder_proxy.send(EmbedderMsg::ResizeTo(source_top_ctx_id, size)); - } FromScriptMsg::GetClientWindow(send) => { self.compositor_proxy.send(ToCompositorMsg::GetClientWindow(send)); } @@ -1162,15 +1148,6 @@ impl Constellation FromScriptMsg::LogEntry(thread_name, entry) => { self.handle_log_entry(Some(source_top_ctx_id), thread_name, entry); } - FromScriptMsg::SetTitle(title) => { - if source_is_top_level_pipeline { - self.embedder_proxy.send(EmbedderMsg::ChangePageTitle(source_top_ctx_id, title)) - } - } - FromScriptMsg::SendKeyEvent(ch, key, key_state, key_modifiers) => { - let event = EmbedderMsg::KeyEvent(Some(source_top_ctx_id), ch, key, key_state, key_modifiers); - self.embedder_proxy.send(event); - } FromScriptMsg::TouchEventProcessed(result) => { self.compositor_proxy.send(ToCompositorMsg::TouchEventProcessed(result)) } @@ -1208,15 +1185,6 @@ impl Constellation FromScriptMsg::BroadcastStorageEvent(storage, url, key, old_value, new_value) => { self.handle_broadcast_storage_event(source_pipeline_id, storage, url, key, old_value, new_value); } - FromScriptMsg::SetFullscreenState(state) => { - self.embedder_proxy.send(EmbedderMsg::SetFullscreenState(source_top_ctx_id, state)); - } - FromScriptMsg::ShowIME(kind) => { - self.embedder_proxy.send(EmbedderMsg::ShowIME(source_top_ctx_id, kind)); - } - FromScriptMsg::HideIME => { - self.embedder_proxy.send(EmbedderMsg::HideIME(source_top_ctx_id)); - } } } @@ -1413,7 +1381,7 @@ impl Constellation let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); - self.embedder_proxy.send(EmbedderMsg::Panic(top_level_browsing_context_id, reason, backtrace)); + self.embedder_proxy.send((Some(top_level_browsing_context_id), EmbedderMsg::Panic(reason, backtrace))); let (window_size, pipeline_id) = { let browsing_context = self.browsing_contexts.get(&browsing_context_id); @@ -1695,7 +1663,7 @@ impl Constellation } fn handle_set_cursor_msg(&mut self, cursor: CursorKind) { - self.embedder_proxy.send(EmbedderMsg::SetCursor(cursor)) + self.embedder_proxy.send((None, EmbedderMsg::SetCursor(cursor))) } fn handle_change_running_animations_state(&mut self, @@ -1727,23 +1695,6 @@ impl Constellation } } - fn handle_alert(&mut self, - top_level_browsing_context_id: TopLevelBrowsingContextId, - _message: String, - sender: IpcSender) { - // FIXME: forward alert event to embedder - // https://github.com/servo/servo/issues/19992 - let result = sender.send(true); - if let Err(e) = result { - let ctx_id = BrowsingContextId::from(top_level_browsing_context_id); - let pipeline_id = match self.browsing_contexts.get(&ctx_id) { - Some(ctx) => ctx.pipeline_id, - None => return warn!("Alert sent for unknown browsing context."), - }; - self.handle_send_error(pipeline_id, e); - } - } - fn handle_load_url_msg(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId, source_id: PipelineId, load_data: LoadData, replace: bool) { self.load_url(top_level_browsing_context_id, source_id, load_data, replace); @@ -1753,7 +1704,7 @@ impl Constellation load_data: LoadData, replace: bool) -> Option { // Allow the embedder to handle the url itself let (chan, port) = ipc::channel().expect("Failed to create IPC channel!"); - let msg = EmbedderMsg::AllowNavigation(top_level_browsing_context_id, load_data.url.clone(), chan); + let msg = (Some(top_level_browsing_context_id), EmbedderMsg::AllowNavigation(load_data.url.clone(), chan)); self.embedder_proxy.send(msg); if let Ok(false) = port.recv() { return None; @@ -1861,7 +1812,7 @@ impl Constellation pipeline_id: PipelineId) { if self.pipelines.get(&pipeline_id).and_then(|p| p.parent_info).is_none() { // Notify embedder top level document started loading. - self.embedder_proxy.send(EmbedderMsg::LoadStart(top_level_browsing_context_id)); + self.embedder_proxy.send((Some(top_level_browsing_context_id), EmbedderMsg::LoadStart)); } } @@ -1895,7 +1846,7 @@ impl Constellation if !current_top_level_pipeline_will_be_replaced { // Notify embedder and compositor top level document finished loading. self.compositor_proxy.send(ToCompositorMsg::LoadComplete(top_level_browsing_context_id)); - self.embedder_proxy.send(EmbedderMsg::LoadComplete(top_level_browsing_context_id)); + self.embedder_proxy.send((Some(top_level_browsing_context_id), EmbedderMsg::LoadComplete)); } } self.handle_subframe_loaded(pipeline_id); @@ -2148,7 +2099,7 @@ impl Constellation } }, None => { - let event = EmbedderMsg::KeyEvent(None, ch, key, state, mods); + let event = (None, EmbedderMsg::KeyEvent(ch, key, state, mods)); self.embedder_proxy.clone().send(event); } } @@ -2321,7 +2272,7 @@ impl Constellation }, WebDriverCommandMsg::SetWindowSize(top_level_browsing_context_id, size, reply) => { self.webdriver.resize_channel = Some(reply); - self.embedder_proxy.send(EmbedderMsg::ResizeTo(top_level_browsing_context_id, size)); + self.embedder_proxy.send((Some(top_level_browsing_context_id), EmbedderMsg::ResizeTo(size))); }, WebDriverCommandMsg::LoadUrl(top_level_browsing_context_id, load_data, reply) => { self.load_url_for_webdriver(top_level_browsing_context_id, load_data, reply, false); @@ -2451,8 +2402,8 @@ impl Constellation entries.extend(session_history.future.iter().rev() .scan(current_load_data.clone(), &resolve_load_data_future)); - - let msg = EmbedderMsg::HistoryChanged(top_level_browsing_context_id, entries, current_index); + let urls = entries.iter().map(|entry| entry.url.clone()).collect(); + let msg = (Some(top_level_browsing_context_id), EmbedderMsg::HistoryChanged(urls, current_index)); self.embedder_proxy.send(msg); } diff --git a/components/constellation/lib.rs b/components/constellation/lib.rs index 5ae86080300..1fd6662d405 100644 --- a/components/constellation/lib.rs +++ b/components/constellation/lib.rs @@ -14,7 +14,7 @@ extern crate clipboard; extern crate compositing; extern crate debugger; extern crate devtools_traits; -#[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] +#[cfg(not(target_os = "ios"))] extern crate embedder_traits; extern crate euclid; #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] diff --git a/components/embedder_traits/Cargo.toml b/components/embedder_traits/Cargo.toml index 9146893b13d..eb8bc420db6 100644 --- a/components/embedder_traits/Cargo.toml +++ b/components/embedder_traits/Cargo.toml @@ -13,4 +13,11 @@ path = "lib.rs" tests = [] [dependencies] +ipc-channel = "0.10" lazy_static = "1" +log = "0.4" +msg = {path = "../msg"} +serde = "1.0" +servo_url = {path = "../url"} +style_traits = {path = "../style_traits"} +webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} diff --git a/components/embedder_traits/lib.rs b/components/embedder_traits/lib.rs index aa8a3c0e111..9122a76f0ef 100644 --- a/components/embedder_traits/lib.rs +++ b/components/embedder_traits/lib.rs @@ -2,6 +2,149 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#[macro_use] extern crate lazy_static; +extern crate ipc_channel; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; +extern crate msg; +#[macro_use] +extern crate serde; +extern crate servo_url; +extern crate style_traits; +extern crate webrender_api; pub mod resources; + +use ipc_channel::ipc::IpcSender; +use msg::constellation_msg::{InputMethodType, Key, KeyModifiers, KeyState, TopLevelBrowsingContextId}; +use servo_url::ServoUrl; +use std::fmt::{Debug, Error, Formatter}; +use std::sync::mpsc::{Receiver, Sender}; +use style_traits::cursor::CursorKind; +use webrender_api::{DeviceIntPoint, DeviceUintSize}; + + +/// Used to wake up the event loop, provided by the servo port/embedder. +pub trait EventLoopWaker : 'static + Send { + fn clone(&self) -> Box; + fn wake(&self); +} + +/// Sends messages to the embedder. +pub struct EmbedderProxy { + pub sender: Sender<(Option, EmbedderMsg)>, + pub event_loop_waker: Box, +} + +impl EmbedderProxy { + pub fn send(&self, msg: (Option, EmbedderMsg)) { + // Send a message and kick the OS event loop awake. + if let Err(err) = self.sender.send(msg) { + warn!("Failed to send response ({}).", err); + } + self.event_loop_waker.wake(); + } +} + +impl Clone for EmbedderProxy { + fn clone(&self) -> EmbedderProxy { + EmbedderProxy { + sender: self.sender.clone(), + event_loop_waker: self.event_loop_waker.clone(), + } + } +} + +/// The port that the embedder receives messages on. +pub struct EmbedderReceiver { + pub receiver: Receiver<(Option, EmbedderMsg)> +} + +impl EmbedderReceiver { + pub fn try_recv_embedder_msg(&mut self) -> Option<(Option, EmbedderMsg)> { + self.receiver.try_recv().ok() + } + pub fn recv_embedder_msg(&mut self) -> (Option, EmbedderMsg) { + self.receiver.recv().unwrap() + } +} + +#[derive(Deserialize, Serialize)] +pub enum EmbedderMsg { + /// A status message to be displayed by the browser chrome. + Status(Option), + /// Alerts the embedder that the current page has changed its title. + ChangePageTitle(Option), + /// Move the window to a point + MoveTo(DeviceIntPoint), + /// Resize the window to size + ResizeTo(DeviceUintSize), + // Show an alert message. + Alert(String, IpcSender<()>), + /// Wether or not to follow a link + AllowNavigation(ServoUrl, IpcSender), + /// Wether or not to unload a document + AllowUnload(IpcSender), + /// Sends an unconsumed key event back to the embedder. + KeyEvent(Option, Key, KeyState, KeyModifiers), + /// Changes the cursor. + SetCursor(CursorKind), + /// A favicon was detected + NewFavicon(ServoUrl), + /// tag finished parsing + HeadParsed, + /// The history state has changed. + HistoryChanged(Vec, usize), + /// Enter or exit fullscreen + SetFullscreenState(bool), + /// The load of a page has begun + LoadStart, + /// The load of a page has completed + LoadComplete, + /// A pipeline panicked. First string is the reason, second one is the backtrace. + Panic(String, Option), + /// Open dialog to select bluetooth device. + GetSelectedBluetoothDevice(Vec, IpcSender>), + /// Open file dialog to select files. Set boolean flag to true allows to select multiple files. + SelectFiles(Vec, bool, IpcSender>>), + /// Request to present an IME to the user when an editable element is focused. + ShowIME(InputMethodType), + /// Request to hide the IME when the editable element is blurred. + HideIME, + /// Servo has shut down + Shutdown, +} + +impl Debug for EmbedderMsg { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + match *self { + EmbedderMsg::Status(..) => write!(f, "Status"), + EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"), + EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"), + EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"), + EmbedderMsg::Alert(..) => write!(f, "Alert"), + EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"), + EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"), + EmbedderMsg::KeyEvent(..) => write!(f, "KeyEvent"), + EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"), + EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"), + EmbedderMsg::HeadParsed => write!(f, "HeadParsed"), + EmbedderMsg::HistoryChanged(..) => write!(f, "HistoryChanged"), + EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"), + EmbedderMsg::LoadStart => write!(f, "LoadStart"), + EmbedderMsg::LoadComplete => write!(f, "LoadComplete"), + EmbedderMsg::Panic(..) => write!(f, "Panic"), + EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"), + EmbedderMsg::SelectFiles(..) => write!(f, "SelectFiles"), + EmbedderMsg::ShowIME(..) => write!(f, "ShowIME"), + EmbedderMsg::HideIME => write!(f, "HideIME"), + EmbedderMsg::Shutdown => write!(f, "Shutdown"), + } + } +} + +/// Filter for file selection; +/// the `String` content is expected to be extension (e.g, "doc", without the prefixing ".") +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct FilterPattern(pub String); diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml index 9ef3654f902..43c8b22c4c0 100644 --- a/components/net/Cargo.toml +++ b/components/net/Cargo.toml @@ -16,7 +16,6 @@ doctest = false base64 = "0.6" brotli = "1.0.6" cookie = "0.10" -compositing = {path = "../compositing"} devtools_traits = {path = "../devtools_traits"} embedder_traits = { path = "../embedder_traits" } flate2 = "1" diff --git a/components/net/filemanager_thread.rs b/components/net/filemanager_thread.rs index 6926412d104..3dda46a979d 100644 --- a/components/net/filemanager_thread.rs +++ b/components/net/filemanager_thread.rs @@ -2,11 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy}; +use embedder_traits::{EmbedderMsg, EmbedderProxy, FilterPattern}; use ipc_channel::ipc::{self, IpcSender}; use mime_guess::guess_mime_type_opt; use net_traits::blob_url_store::{BlobBuf, BlobURLStoreError}; -use net_traits::filemanager_thread::{FileManagerResult, FileManagerThreadMsg, FileOrigin, FilterPattern}; +use net_traits::filemanager_thread::{FileManagerResult, FileManagerThreadMsg, FileOrigin}; use net_traits::filemanager_thread::{FileManagerThreadError, ReadFileProgress, RelativePos, SelectedFile}; use servo_config::prefs::PREFS; use std::collections::HashMap; @@ -220,7 +220,7 @@ impl FileManagerStore { multiple_files: bool, embedder_proxy: EmbedderProxy) -> Option> { let (ipc_sender, ipc_receiver) = ipc::channel().expect("Failed to create IPC channel!"); - let msg = EmbedderMsg::SelectFiles(patterns, multiple_files, ipc_sender); + let msg = (None, EmbedderMsg::SelectFiles(patterns, multiple_files, ipc_sender)); embedder_proxy.send(msg); match ipc_receiver.recv() { diff --git a/components/net/lib.rs b/components/net/lib.rs index a8d802ae49f..cdeb7d54595 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -6,7 +6,6 @@ extern crate base64; extern crate brotli; -extern crate compositing; extern crate cookie as cookie_rs; extern crate devtools_traits; extern crate embedder_traits; diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index d00c0323f38..ffcdccebfe9 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -3,12 +3,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //! A thread that takes a URL and streams back the binary data. -use compositing::compositor_thread::EmbedderProxy; use connector::{create_http_connector, create_ssl_client}; use cookie; use cookie_rs; use cookie_storage::CookieStorage; use devtools_traits::DevtoolsControlMsg; +use embedder_traits::EmbedderProxy; use embedder_traits::resources::{self, Resource}; use fetch::cors_cache::CorsCache; use fetch::methods::{CancellationListener, FetchContext, fetch}; diff --git a/components/net/tests/filemanager_thread.rs b/components/net/tests/filemanager_thread.rs index d71c9f30187..8612bdae672 100644 --- a/components/net/tests/filemanager_thread.rs +++ b/components/net/tests/filemanager_thread.rs @@ -3,10 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use create_embedder_proxy; +use embedder_traits::FilterPattern; use ipc_channel::ipc; use net::filemanager_thread::FileManager; use net_traits::blob_url_store::BlobURLStoreError; -use net_traits::filemanager_thread::{FilterPattern, FileManagerThreadMsg, FileManagerThreadError, ReadFileProgress}; +use net_traits::filemanager_thread::{FileManagerThreadMsg, FileManagerThreadError, ReadFileProgress}; use servo_config::prefs::{PrefValue, PREFS}; use std::fs::File; use std::io::Read; diff --git a/components/net/tests/main.rs b/components/net/tests/main.rs index a644a6a2fd4..1a7d5c462a5 100644 --- a/components/net/tests/main.rs +++ b/components/net/tests/main.rs @@ -4,7 +4,6 @@ #![cfg(test)] -extern crate compositing; extern crate cookie as cookie_rs; extern crate devtools_traits; extern crate embedder_traits; @@ -35,8 +34,8 @@ mod mime_classifier; mod resource_thread; mod subresource_integrity; -use compositing::compositor_thread::{EmbedderProxy, EventLoopWaker}; use devtools_traits::DevtoolsControlMsg; +use embedder_traits::{EmbedderProxy, EventLoopWaker}; use embedder_traits::resources::{self, Resource}; use hyper::server::{Handler, Listening, Server}; use net::connector::create_ssl_client; diff --git a/components/net_traits/filemanager_thread.rs b/components/net_traits/filemanager_thread.rs index a9cb76bf98a..fa0ac23d8f5 100644 --- a/components/net_traits/filemanager_thread.rs +++ b/components/net_traits/filemanager_thread.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use blob_url_store::{BlobBuf, BlobURLStoreError}; +use embedder_traits::FilterPattern; use ipc_channel::ipc::IpcSender; use num_traits::ToPrimitive; use std::cmp::{max, min}; @@ -110,11 +111,6 @@ pub struct SelectedFile { pub type_string: String, } -/// Filter for file selection; -/// the `String` content is expected to be extension (e.g, "doc", without the prefixing ".") -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct FilterPattern(pub String); - #[derive(Deserialize, Serialize)] pub enum FileManagerThreadMsg { /// Select a single file. Last field is pre-selected file path for testing diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 3b6b92246f1..dc9eae886bb 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -10,8 +10,10 @@ use dom::attr::Attr; use dom::beforeunloadevent::BeforeUnloadEvent; use dom::bindings::callback::ExceptionHandling; use dom::bindings::cell::DomRefCell; +use dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEventBinding::BeforeUnloadEventMethods; use dom::bindings::codegen::Bindings::DocumentBinding; use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState, ElementCreationOptions}; +use dom::bindings::codegen::Bindings::EventBinding::EventBinding::EventMethods; use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementBinding::HTMLIFrameElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter; @@ -88,13 +90,14 @@ use dom::webglcontextevent::WebGLContextEvent; use dom::window::{ReflowReason, Window}; use dom::windowproxy::WindowProxy; use dom_struct::dom_struct; +use embedder_traits::EmbedderMsg; use encoding_rs::{Encoding, UTF_8}; use euclid::Point2D; use fetch::FetchCanceller; use html5ever::{LocalName, Namespace, QualName}; use hyper::header::{Header, SetCookie}; use hyper_serde::Serde; -use ipc_channel::ipc::IpcSender; +use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::{JSContext, JSObject, JSRuntime}; use js::jsapi::JS_GetRuntime; use metrics::{InteractiveFlag, InteractiveMetrics, InteractiveWindow, ProfilerMetadataFactory, ProgressiveWebMetric}; @@ -107,7 +110,7 @@ use net_traits::pub_domains::is_pub_domain; use net_traits::request::RequestInit; use net_traits::response::HttpsState; use num_traits::ToPrimitive; -use profile_traits::ipc; +use profile_traits::ipc as profile_ipc; use profile_traits::time::{TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType}; use ref_slice::ref_slice; use script_layout_interface::message::{Msg, NodesFromPointQueryType, QueryMsg, ReflowGoal}; @@ -855,7 +858,7 @@ impl Document { // Notify the embedder to hide the input method. if elem.input_method_type().is_some() { - self.send_to_constellation(ScriptMsg::HideIME); + self.send_to_embedder(EmbedderMsg::HideIME); } } @@ -869,12 +872,12 @@ impl Document { // Update the focus state for all elements in the focus chain. // https://html.spec.whatwg.org/multipage/#focus-chain if focus_type == FocusType::Element { - self.send_to_constellation(ScriptMsg::Focus); + self.window().send_to_constellation(ScriptMsg::Focus); } // Notify the embedder to display an input method. if let Some(kind) = elem.input_method_type() { - self.send_to_constellation(ScriptMsg::ShowIME(kind)); + self.send_to_embedder(EmbedderMsg::ShowIME(kind)); } } } @@ -882,14 +885,22 @@ impl Document { /// Handles any updates when the document's title has changed. pub fn title_changed(&self) { if self.browsing_context().is_some() { - self.send_title_to_constellation(); + self.send_title_to_embedder(); } } /// Sends this document's title to the constellation. - pub fn send_title_to_constellation(&self) { - let title = Some(String::from(self.Title())); - self.send_to_constellation(ScriptMsg::SetTitle(title)); + pub fn send_title_to_embedder(&self) { + let window = self.window(); + if window.is_top_level() { + let title = Some(String::from(self.Title())); + self.send_to_embedder(EmbedderMsg::ChangePageTitle(title)); + } + } + + fn send_to_embedder(&self, msg: EmbedderMsg) { + let window = self.window(); + window.send_to_embedder(msg); } pub fn dirty_all_nodes(&self) { @@ -1352,8 +1363,8 @@ impl Document { } if cancel_state == EventDefault::Allowed { - let msg = ScriptMsg::SendKeyEvent(ch, key, state, modifiers); - self.send_to_constellation(msg); + let msg = EmbedderMsg::KeyEvent(ch, key, state, modifiers); + self.send_to_embedder(msg); // This behavior is unspecced // We are supposed to dispatch synthetic click activation for Space and/or Return, @@ -1488,7 +1499,7 @@ impl Document { // repeated rAF. let event = ScriptMsg::ChangeRunningAnimationsState(AnimationState::AnimationCallbacksPresent); - self.send_to_constellation(event); + self.window().send_to_constellation(event); } ident @@ -1559,7 +1570,7 @@ impl Document { ); } let event = ScriptMsg::ChangeRunningAnimationsState(AnimationState::NoAnimationCallbacksPresent); - self.send_to_constellation(event); + self.window().send_to_constellation(event); } // Update the counter of spurious animation frames. @@ -1656,7 +1667,15 @@ impl Document { // Step 7 self.salvageable.set(!has_listeners); let mut can_unload = true; - // TODO: Step 8 send a message to embedder to prompt user. + // TODO: Step 8, also check sandboxing modals flag. + let default_prevented = event.DefaultPrevented(); + let return_value_not_empty = !event.downcast::().unwrap().ReturnValue().is_empty(); + if default_prevented || return_value_not_empty { + let (chan, port) = ipc::channel().expect("Failed to create IPC channel!"); + let msg = EmbedderMsg::AllowUnload(chan); + self.send_to_embedder(msg); + can_unload = port.recv().unwrap(); + } // Step 9 if !recursive_flag { for iframe in self.iter_iframes() { @@ -2009,7 +2028,7 @@ impl Document { } pub fn notify_constellation_load(&self) { - self.send_to_constellation(ScriptMsg::LoadComplete); + self.window().send_to_constellation(ScriptMsg::LoadComplete); } pub fn set_current_parser(&self, script: Option<&ServoParser>) { @@ -2167,11 +2186,6 @@ impl Document { registry.lookup_definition(local_name, is) } - fn send_to_constellation(&self, msg: ScriptMsg) { - let global_scope = self.window.upcast::(); - global_scope.script_to_constellation_chan().send(msg).unwrap(); - } - pub fn increment_throw_on_dynamic_markup_insertion_counter(&self) { let counter = self.throw_on_dynamic_markup_insertion_counter.get(); self.throw_on_dynamic_markup_insertion_counter.set(counter + 1); @@ -2787,8 +2801,8 @@ impl Document { let window = self.window(); // Step 6 if !error { - let event = ScriptMsg::SetFullscreenState(true); - self.send_to_constellation(event); + let event = EmbedderMsg::SetFullscreenState(true); + self.send_to_embedder(event); } let pipeline_id = self.window().pipeline_id(); @@ -2822,8 +2836,8 @@ impl Document { let window = self.window(); // Step 8 - let event = ScriptMsg::SetFullscreenState(false); - self.send_to_constellation(event); + let event = EmbedderMsg::SetFullscreenState(true); + self.send_to_embedder(event); // Step 9 let trusted_element = Trusted::new(element.r()); @@ -3634,7 +3648,7 @@ impl DocumentMethods for Document { } let url = self.url(); - let (tx, rx) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); + let (tx, rx) = profile_ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); let _ = self.window .upcast::() .resource_threads() diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index c3ac339e33c..7d921d57ce8 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -12,13 +12,12 @@ use dom::bindings::str::DOMString; use dom::document::Document; use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; use dom::eventtarget::EventTarget; -use dom::globalscope::GlobalScope; use dom::htmlelement::HTMLElement; use dom::node::{Node, document_from_node, window_from_node}; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; +use embedder_traits::EmbedderMsg; use html5ever::{LocalName, Prefix}; -use script_traits::ScriptMsg; use servo_url::ServoUrl; use style::attr::AttrValue; use time; @@ -151,8 +150,10 @@ impl VirtualMethods for HTMLBodyElement { let window = window_from_node(self); let document = window.Document(); document.set_reflow_timeout(time::precise_time_ns() + INITIAL_REFLOW_DELAY); - let event = ScriptMsg::HeadParsed; - window.upcast::().script_to_constellation_chan().send(event).unwrap(); + if window.is_top_level() { + let msg = EmbedderMsg::HeadParsed; + window.send_to_embedder(msg); + } } fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue { diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index ab7d55d5b9a..f2d83fa4d54 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -38,12 +38,13 @@ use dom::validation::Validatable; use dom::validitystate::ValidationFlags; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; +use embedder_traits::FilterPattern; use html5ever::{LocalName, Prefix}; use mime_guess; use msg::constellation_msg::InputMethodType; use net_traits::{CoreResourceMsg, IpcSend}; use net_traits::blob_url_store::get_blob_origin; -use net_traits::filemanager_thread::{FileManagerThreadMsg, FilterPattern}; +use net_traits::filemanager_thread::FileManagerThreadMsg; use profile_traits::ipc; use script_layout_interface::rpc::TextIndexResponse; use script_traits::ScriptToConstellationChan; diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index f3f82cb5ce1..f55a795ba0d 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -16,15 +16,14 @@ use dom::document::Document; use dom::domtokenlist::DOMTokenList; use dom::element::{AttributeMutation, Element, ElementCreator}; use dom::element::{cors_setting_for_element, reflect_cross_origin_attribute, set_cross_origin_attribute}; -use dom::globalscope::GlobalScope; use dom::htmlelement::HTMLElement; use dom::node::{Node, UnbindContext, document_from_node, window_from_node}; use dom::stylesheet::StyleSheet as DOMStyleSheet; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; +use embedder_traits::EmbedderMsg; use html5ever::{LocalName, Prefix}; use net_traits::ReferrerPolicy; -use script_traits::ScriptMsg; use servo_arc::Arc; use std::borrow::ToOwned; use std::cell::Cell; @@ -306,8 +305,12 @@ impl HTMLLinkElement { let document = document_from_node(self); match document.base_url().join(href) { Ok(url) => { - let event = ScriptMsg::NewFavicon(url.clone()); - document.window().upcast::().script_to_constellation_chan().send(event).unwrap(); + let window = document.window(); + if window.is_top_level() { + let msg = EmbedderMsg::NewFavicon(url.clone()); + window.send_to_embedder(msg); + } + } Err(e) => debug!("Parsing url {} failed: {}", href, e) } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index dcd9c2e0756..3a24a1ac95d 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -48,6 +48,7 @@ use dom::windowproxy::WindowProxy; use dom::worklet::Worklet; use dom::workletglobalscope::WorkletGlobalScopeType; use dom_struct::dom_struct; +use embedder_traits::EmbedderMsg; use euclid::{Point2D, Vector2D, Rect, Size2D, TypedPoint2D, TypedScale, TypedSize2D}; use fetch; use ipc_channel::ipc::IpcSender; @@ -114,8 +115,6 @@ use task_source::performance_timeline::PerformanceTimelineTaskSource; use task_source::user_interaction::UserInteractionTaskSource; use time; use timers::{IsInterval, TimerCallback}; -#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] -use tinyfiledialogs::{self, MessageBoxIcon}; use url::Position; use webdriver_handlers::jsval_to_webdriver; use webrender_api::{ExternalScrollId, DeviceIntPoint, DeviceUintSize, DocumentId}; @@ -444,18 +443,6 @@ impl Window { } } -#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] -fn display_alert_dialog(message: &str) { - if !opts::get().headless { - tinyfiledialogs::message_box_ok("Alert!", message, MessageBoxIcon::Warning); - } -} - -#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] -fn display_alert_dialog(_message: &str) { - // tinyfiledialogs not supported on Android -} - // https://html.spec.whatwg.org/multipage/#atob pub fn base64_btoa(input: DOMString) -> Fallible { // "The btoa() method must throw an InvalidCharacterError exception if @@ -541,14 +528,10 @@ impl WindowMethods for Window { stdout.flush().unwrap(); stderr.flush().unwrap(); } - let (sender, receiver) = ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap(); - self.send_to_constellation(ScriptMsg::Alert(s.to_string(), sender)); - - let should_display_alert_dialog = receiver.recv().unwrap(); - if should_display_alert_dialog { - display_alert_dialog(&s); - } + let msg = EmbedderMsg::Alert(s.to_string(), sender); + self.send_to_embedder(msg); + receiver.recv().unwrap(); } // https://html.spec.whatwg.org/multipage/#dom-window-closed @@ -937,7 +920,7 @@ impl WindowMethods for Window { //TODO determine if this operation is allowed let dpr = self.device_pixel_ratio(); let size = TypedSize2D::new(width, height).to_f32() * dpr; - self.send_to_constellation(ScriptMsg::ResizeTo(size.to_u32())); + self.send_to_embedder(EmbedderMsg::ResizeTo(size.to_u32())); } // https://drafts.csswg.org/cssom-view/#dom-window-resizeby @@ -953,7 +936,8 @@ impl WindowMethods for Window { //TODO determine if this operation is allowed let dpr = self.device_pixel_ratio(); let point = TypedPoint2D::new(x, y).to_f32() * dpr; - self.send_to_constellation(ScriptMsg::MoveTo(point.to_i32())); + let msg = EmbedderMsg::MoveTo(point.to_i32()); + self.send_to_embedder(msg); } // https://drafts.csswg.org/cssom-view/#dom-window-moveby @@ -1742,7 +1726,11 @@ impl Window { self.navigation_start_precise.set(time::precise_time_ns()); } - fn send_to_constellation(&self, msg: ScriptMsg) { + pub fn send_to_embedder(&self, msg: EmbedderMsg) { + self.send_to_constellation(ScriptMsg::ForwardToEmbedder(msg)); + } + + pub fn send_to_constellation(&self, msg: ScriptMsg) { self.upcast::() .script_to_constellation_chan() .send(msg) diff --git a/components/script/lib.rs b/components/script/lib.rs index bee088aa5e0..cf020ab9ac6 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -93,7 +93,7 @@ extern crate style; extern crate style_traits; extern crate swapper; extern crate time; -#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] +#[cfg(target_os = "linux")] extern crate tinyfiledialogs; extern crate unicode_segmentation; extern crate url; diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 613918f6a76..a28bdfbb5bf 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -62,6 +62,7 @@ use dom::windowproxy::WindowProxy; use dom::worker::TrustedWorkerAddress; use dom::worklet::WorkletThreadPool; use dom::workletglobalscope::WorkletGlobalScopeInit; +use embedder_traits::EmbedderMsg; use euclid::{Point2D, Vector2D, Rect}; use fetch::FetchCanceller; use hyper::header::{ContentType, HttpDate, Headers, LastModified}; @@ -1822,7 +1823,7 @@ impl ScriptThread { Some(document) => document, None => return warn!("Message sent to closed pipeline {}.", pipeline_id), }; - document.send_title_to_constellation(); + document.send_title_to_embedder(); } /// Handles a request to exit a pipeline and shut down layout. @@ -2282,6 +2283,7 @@ impl ScriptThread { Some(document) => document, None => return warn!("Message sent to closed pipeline {}.", pipeline_id), }; + let window = document.window(); // Get the previous target temporarily let prev_mouse_over_target = self.topmost_mouse_over_target.get(); @@ -2310,9 +2312,8 @@ impl ScriptThread { let url = document.url(); url.join(&value).map(|url| url.to_string()).ok() }); - - let event = ScriptMsg::NodeStatus(status); - self.script_sender.send((pipeline_id, event)).unwrap(); + let event = EmbedderMsg::Status(status); + window.send_to_embedder(event); state_already_changed = true; } @@ -2325,8 +2326,8 @@ impl ScriptThread { .inclusive_ancestors() .filter_map(DomRoot::downcast::) .next() { - let event = ScriptMsg::NodeStatus(None); - self.script_sender.send((pipeline_id, event)).unwrap(); + let event = EmbedderMsg::Status(None); + window.send_to_embedder(event); } } } diff --git a/components/script_traits/Cargo.toml b/components/script_traits/Cargo.toml index 2d3c47c14b7..a5ae8cf0d7e 100644 --- a/components/script_traits/Cargo.toml +++ b/components/script_traits/Cargo.toml @@ -14,6 +14,7 @@ bluetooth_traits = {path = "../bluetooth_traits"} canvas_traits = {path = "../canvas_traits"} cookie = "0.10" devtools_traits = {path = "../devtools_traits"} +embedder_traits = {path = "../embedder_traits"} euclid = "0.17" gfx_traits = {path = "../gfx_traits"} hyper = "0.10" @@ -34,3 +35,6 @@ time = "0.1.12" url = "1.2" webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webvr_traits = {path = "../webvr_traits"} + +[dev-dependencies] +embedder_traits = { path = "../embedder_traits", features = ["tests"]} diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 9ecda6625d6..6075cc6fc43 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -13,6 +13,7 @@ extern crate bluetooth_traits; extern crate canvas_traits; extern crate cookie as cookie_rs; extern crate devtools_traits; +extern crate embedder_traits; extern crate euclid; extern crate gfx_traits; extern crate hyper; @@ -702,6 +703,8 @@ pub enum ConstellationMsg { NewBrowser(ServoUrl, IpcSender), /// Close a top level browsing context. CloseBrowser(TopLevelBrowsingContextId), + /// Panic a top level browsing context. + SendError(Option, String), /// Make browser visible. SelectBrowser(TopLevelBrowsingContextId), /// Forward an event to the script task of the given pipeline. @@ -730,6 +733,7 @@ impl fmt::Debug for ConstellationMsg { WebVREvents(..) => "WebVREvents", NewBrowser(..) => "NewBrowser", CloseBrowser(..) => "CloseBrowser", + SendError(..) => "SendError", SelectBrowser(..) => "SelectBrowser", ForwardEvent(..) => "ForwardEvent", SetCursor(..) => "SetCursor", diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index ad437b09d8d..c9cb879f1c2 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -12,11 +12,11 @@ use WorkerGlobalScopeInit; use WorkerScriptLoadOrigin; use canvas_traits::canvas::{CanvasMsg, CanvasId}; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; +use embedder_traits::EmbedderMsg; use euclid::{Size2D, TypedSize2D}; use gfx_traits::Epoch; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, TraversalDirection}; -use msg::constellation_msg::{InputMethodType, Key, KeyModifiers, KeyState}; use net_traits::CoreResourceMsg; use net_traits::request::RequestInit; use net_traits::storage_thread::StorageType; @@ -83,6 +83,8 @@ pub enum LogEntry { /// Messages from the script to the constellation. #[derive(Deserialize, Serialize)] pub enum ScriptMsg { + /// Forward a message to the embedder. + ForwardToEmbedder(EmbedderMsg), /// Requests are sent to constellation and fetches are checked manually /// for cross-origin loads InitiateNavigateRequest(RequestInit, /* cancellation_chan */ IpcReceiver<()>), @@ -104,8 +106,6 @@ pub enum ScriptMsg { GetParentInfo(PipelineId, IpcSender>), /// Get the nth child browsing context ID for a given browsing context, sorted in tree order. GetChildBrowsingContextId(BrowsingContextId, usize, IpcSender>), - /// tag finished parsing - HeadParsed, /// All pending loads are complete, and the `load` event for this pipeline /// has been dispatched. LoadComplete, @@ -124,10 +124,6 @@ pub enum ScriptMsg { ReplaceHistoryState(HistoryStateId, ServoUrl), /// Gets the length of the joint session history from the constellation. JointSessionHistoryLength(IpcSender), - /// Favicon detected - NewFavicon(ServoUrl), - /// Status message to be displayed in the chrome, eg. a link URL on mouseover. - NodeStatus(Option), /// Notification that this iframe should be removed. /// Returns a list of pipelines which were closed. RemoveIFrame(BrowsingContextId, IpcSender>), @@ -147,17 +143,6 @@ pub enum ScriptMsg { SetDocumentState(DocumentState), /// Update the pipeline Url, which can change after redirections. SetFinalUrl(ServoUrl), - /// Check if an alert dialog box should be presented - Alert(String, IpcSender), - /// Set title of current page - /// - SetTitle(Option), - /// Send a key event - SendKeyEvent(Option, Key, KeyState, KeyModifiers), - /// Move the window to a point - MoveTo(DeviceIntPoint), - /// Resize the window to size - ResizeTo(DeviceUintSize), /// Script has handled a touch event, and either prevented or allowed default actions. TouchEventProcessed(EventResult), /// A log entry, with the top-level browsing context id and thread name @@ -171,18 +156,12 @@ pub enum ScriptMsg { ForwardDOMMessage(DOMMessage, ServoUrl), /// Store the data required to activate a service worker for the given scope RegisterServiceWorker(ScopeThings, ServoUrl), - /// Enter or exit fullscreen - SetFullscreenState(bool), /// Get Window Informations size and position GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>), /// Get the screen size (pixel) GetScreenSize(IpcSender<(DeviceUintSize)>), /// Get the available screen size (pixel) GetScreenAvailSize(IpcSender<(DeviceUintSize)>), - /// Request to present an IME to the user when an editable element is focused. - ShowIME(InputMethodType), - /// Request to hide the IME when the editable element is blurred. - HideIME, /// Requests that the compositor shut down. Exit, } @@ -191,6 +170,7 @@ impl fmt::Debug for ScriptMsg { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { use self::ScriptMsg::*; let variant = match *self { + ForwardToEmbedder(..) => "ForwardToEmbedder", InitiateNavigateRequest(..) => "InitiateNavigateRequest", BroadcastStorageEvent(..) => "BroadcastStorageEvent", ChangeRunningAnimationsState(..) => "ChangeRunningAnimationsState", @@ -200,7 +180,6 @@ impl fmt::Debug for ScriptMsg { GetBrowsingContextId(..) => "GetBrowsingContextId", GetParentInfo(..) => "GetParentInfo", GetChildBrowsingContextId(..) => "GetChildBrowsingContextId", - HeadParsed => "HeadParsed", LoadComplete => "LoadComplete", LoadUrl(..) => "LoadUrl", AbortLoadUrl => "AbortLoadUrl", @@ -209,8 +188,6 @@ impl fmt::Debug for ScriptMsg { PushHistoryState(..) => "PushHistoryState", ReplaceHistoryState(..) => "ReplaceHistoryState", JointSessionHistoryLength(..) => "JointSessionHistoryLength", - NewFavicon(..) => "NewFavicon", - NodeStatus(..) => "NodeStatus", RemoveIFrame(..) => "RemoveIFrame", SetVisible(..) => "SetVisible", VisibilityChangeComplete(..) => "VisibilityChangeComplete", @@ -220,23 +197,15 @@ impl fmt::Debug for ScriptMsg { ActivateDocument => "ActivateDocument", SetDocumentState(..) => "SetDocumentState", SetFinalUrl(..) => "SetFinalUrl", - Alert(..) => "Alert", - SetTitle(..) => "SetTitle", - SendKeyEvent(..) => "SendKeyEvent", - MoveTo(..) => "MoveTo", - ResizeTo(..) => "ResizeTo", TouchEventProcessed(..) => "TouchEventProcessed", LogEntry(..) => "LogEntry", DiscardDocument => "DiscardDocument", PipelineExited => "PipelineExited", ForwardDOMMessage(..) => "ForwardDOMMessage", RegisterServiceWorker(..) => "RegisterServiceWorker", - SetFullscreenState(..) => "SetFullscreenState", GetClientWindow(..) => "GetClientWindow", GetScreenSize(..) => "GetScreenSize", GetScreenAvailSize(..) => "GetScreenAvailSize", - ShowIME(..) => "ShowIME", - HideIME => "HideIME", Exit => "Exit", }; write!(formatter, "ScriptMsg::{}", variant) diff --git a/components/servo/lib.rs b/components/servo/lib.rs index bc06dc84ca7..10074241878 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -73,13 +73,13 @@ use bluetooth_traits::BluetoothRequest; use canvas::gl_context::GLContextFactory; use canvas::webgl_thread::WebGLThreads; use compositing::{IOCompositor, ShutdownState, RenderNotifier}; -use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver, InitialCompositorState}; -use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy, EmbedderReceiver}; +use compositing::compositor_thread::{CompositorProxy, CompositorReceiver, InitialCompositorState}; use compositing::windowing::{WindowEvent, WindowMethods}; use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent}; use constellation::{FromCompositorLogger, FromScriptLogger}; #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] use constellation::content_process_sandbox_profile; +use embedder_traits::{EmbedderMsg, EmbedderProxy, EmbedderReceiver, EventLoopWaker}; use env_logger::Builder as EnvLoggerBuilder; use euclid::Length; #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] @@ -124,7 +124,7 @@ pub struct Servo { compositor: IOCompositor, constellation_chan: Sender, embedder_receiver: EmbedderReceiver, - embedder_events: Vec, + embedder_events: Vec<(Option, EmbedderMsg)>, } impl Servo where Window: WindowMethods + 'static { @@ -346,11 +346,18 @@ impl Servo where Window: WindowMethods + 'static { warn!("Sending CloseBrowser message to constellation failed ({}).", e); } } + + WindowEvent::SendError(ctx, e) => { + let msg = ConstellationMsg::SendError(ctx, e); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending CloseBrowser message to constellation failed ({}).", e); + } + } } } fn receive_messages(&mut self) { - while let Some(msg) = self.embedder_receiver.try_recv_embedder_msg() { + while let Some((top_level_browsing_context, msg)) = self.embedder_receiver.try_recv_embedder_msg() { match (msg, self.compositor.shutdown_state) { (_, ShutdownState::FinishedShuttingDown) => { error!("embedder shouldn't be handling messages after compositor has shut down"); @@ -358,22 +365,22 @@ impl Servo where Window: WindowMethods + 'static { (_, ShutdownState::ShuttingDown) => {}, - (EmbedderMsg::KeyEvent(top_level_browsing_context, ch, key, state, modified), + (EmbedderMsg::KeyEvent(ch, key, state, modified), ShutdownState::NotShuttingDown) => { if state == KeyState::Pressed { - let msg = EmbedderMsg::KeyEvent(top_level_browsing_context, ch, key, state, modified); - self.embedder_events.push(msg); + let event = (top_level_browsing_context, EmbedderMsg::KeyEvent(ch, key, state, modified)); + self.embedder_events.push(event); } }, (msg, ShutdownState::NotShuttingDown) => { - self.embedder_events.push(msg); + self.embedder_events.push((top_level_browsing_context, msg)); }, } } } - pub fn get_events(&mut self) -> Vec { + pub fn get_events(&mut self) -> Vec<(Option, EmbedderMsg)> { ::std::mem::replace(&mut self.embedder_events, Vec::new()) } @@ -387,7 +394,7 @@ impl Servo where Window: WindowMethods + 'static { if self.compositor.shutdown_state != ShutdownState::FinishedShuttingDown { self.compositor.perform_updates(); } else { - self.embedder_events.push(EmbedderMsg::Shutdown); + self.embedder_events.push((None, EmbedderMsg::Shutdown)); } } @@ -417,7 +424,7 @@ impl Servo where Window: WindowMethods + 'static { } } -fn create_embedder_channel(event_loop_waker: Box) +fn create_embedder_channel(event_loop_waker: Box) -> (EmbedderProxy, EmbedderReceiver) { let (sender, receiver) = channel(); (EmbedderProxy { @@ -429,7 +436,7 @@ fn create_embedder_channel(event_loop_waker: Box) +fn create_compositor_channel(event_loop_waker: Box) -> (CompositorProxy, CompositorReceiver) { let (sender, receiver) = channel(); (CompositorProxy { diff --git a/ports/servo/browser.rs b/ports/servo/browser.rs index 6d83c59153d..7ecefcc730f 100644 --- a/ports/servo/browser.rs +++ b/ports/servo/browser.rs @@ -5,12 +5,10 @@ use euclid::{TypedPoint2D, TypedVector2D}; use glutin_app::keyutils::{CMD_OR_CONTROL, CMD_OR_ALT}; use glutin_app::window::{Window, LINE_HEIGHT}; -use servo::compositing::compositor_thread::EmbedderMsg; use servo::compositing::windowing::{WebRenderDebugOption, WindowEvent}; -use servo::ipc_channel::ipc::IpcSender; +use servo::embedder_traits::{EmbedderMsg, FilterPattern}; use servo::msg::constellation_msg::{Key, TopLevelBrowsingContextId as BrowserId}; use servo::msg::constellation_msg::{KeyModifiers, KeyState, TraversalDirection}; -use servo::net_traits::filemanager_thread::FilterPattern; use servo::net_traits::pub_domains::is_reg_domain; use servo::script_traits::TouchEventType; use servo::servo_config::opts; @@ -21,7 +19,8 @@ use std::mem; use std::rc::Rc; #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] use std::thread; -use tinyfiledialogs; +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] +use tinyfiledialogs::{self, MessageBoxIcon}; pub struct Browser { current_url: Option, @@ -100,7 +99,7 @@ impl Browser { String::from("") }; let title = "URL or search query"; - if let Some(input) = tinyfiledialogs::input_box(title, title, &url) { + if let Some(input) = get_url_input(title, &url) { if let Some(url) = sanitize_url(&input) { self.event_queue.push(WindowEvent::LoadUrl(id, url)); } @@ -233,13 +232,13 @@ impl Browser { self.event_queue.push(event); } - pub fn handle_servo_events(&mut self, events: Vec) { - for event in events { - match event { - EmbedderMsg::Status(_browser_id, status) => { + pub fn handle_servo_events(&mut self, events: Vec<(Option, EmbedderMsg)>) { + for (browser_id, msg) in events { + match msg { + EmbedderMsg::Status(status) => { self.status = status; }, - EmbedderMsg::ChangePageTitle(_browser_id, title) => { + EmbedderMsg::ChangePageTitle(title) => { self.title = title; let fallback_title: String = if let Some(ref current_url) = self.current_url { @@ -254,59 +253,82 @@ impl Browser { let title = format!("{} - Servo", title); self.window.set_title(&title); } - EmbedderMsg::MoveTo(_browser_id, point) => { + EmbedderMsg::MoveTo(point) => { self.window.set_position(point); } - EmbedderMsg::ResizeTo(_browser_id, size) => { + EmbedderMsg::ResizeTo(size) => { self.window.set_inner_size(size); } - EmbedderMsg::AllowNavigation(_browser_id, _url, response_chan) => { + EmbedderMsg::Alert(message, sender) => { + display_alert_dialog(message.to_owned()); + if let Err(e) = sender.send(()) { + let reason = format!("Failed to send Alert response: {}", e); + self.event_queue.push(WindowEvent::SendError(browser_id, reason)); + } + } + EmbedderMsg::AllowUnload(sender) => { + // Always allow unload for now. + if let Err(e) = sender.send(true) { + let reason = format!("Failed to send AllowUnload response: {}", e); + self.event_queue.push(WindowEvent::SendError(browser_id, reason)); + } + } + EmbedderMsg::AllowNavigation(_url, response_chan) => { if let Err(e) = response_chan.send(true) { warn!("Failed to send allow_navigation() response: {}", e); }; } - EmbedderMsg::KeyEvent(browser_id, ch, key, state, modified) => { + EmbedderMsg::KeyEvent(ch, key, state, modified) => { self.handle_key_from_servo(browser_id, ch, key, state, modified); } EmbedderMsg::SetCursor(cursor) => { self.window.set_cursor(cursor); } - EmbedderMsg::NewFavicon(_browser_id, url) => { + EmbedderMsg::NewFavicon(url) => { self.favicon = Some(url); } - EmbedderMsg::HeadParsed(_browser_id, ) => { + EmbedderMsg::HeadParsed => { self.loading_state = Some(LoadingState::Loading); } - EmbedderMsg::HistoryChanged(_browser_id, entries, current) => { - self.current_url = Some(entries[current].url.clone()); + EmbedderMsg::HistoryChanged(urls, current) => { + self.current_url = Some(urls[current].clone()); } - EmbedderMsg::SetFullscreenState(_browser_id, state) => { + EmbedderMsg::SetFullscreenState(state) => { self.window.set_fullscreen(state); } - EmbedderMsg::LoadStart(_browser_id) => { + EmbedderMsg::LoadStart => { self.loading_state = Some(LoadingState::Connecting); } - EmbedderMsg::LoadComplete(_browser_id) => { + EmbedderMsg::LoadComplete => { self.loading_state = Some(LoadingState::Loaded); } EmbedderMsg::Shutdown => { self.shutdown_requested = true; }, - EmbedderMsg::Panic(_browser_id, _reason, _backtrace) => { + EmbedderMsg::Panic(_reason, _backtrace) => { }, EmbedderMsg::GetSelectedBluetoothDevice(devices, sender) => { - platform_get_selected_devices(devices, sender); + let selected = platform_get_selected_devices(devices); + if let Err(e) = sender.send(selected) { + let reason = format!("Failed to send GetSelectedBluetoothDevice response: {}", e); + self.event_queue.push(WindowEvent::SendError(None, reason)); + }; }, EmbedderMsg::SelectFiles(patterns, multiple_files, sender) => { - if opts::get().headless { - let _ = sender.send(None); - } - platform_get_selected_files(patterns, multiple_files, sender); + let res = match (opts::get().headless, + platform_get_selected_files(patterns, multiple_files)) { + (true, _) | (false, None) => sender.send(None), + (false, Some(files)) => sender.send(Some(files)) + }; + if let Err(e) = res { + let reason = format!("Failed to send SelectFiles response: {}", e); + self.event_queue.push(WindowEvent::SendError(None, reason)); + }; } - EmbedderMsg::ShowIME(_browser_id, _kind) => { + EmbedderMsg::ShowIME(_kind) => { debug!("ShowIME received"); } - EmbedderMsg::HideIME(_browser_id) => { + EmbedderMsg::HideIME => { debug!("HideIME received"); } } @@ -315,8 +337,33 @@ impl Browser { } +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] +fn display_alert_dialog(message: String) { + if !opts::get().headless { + let _ = thread::Builder::new().name("display alert dialog".to_owned()).spawn(move || { + tinyfiledialogs::message_box_ok("Alert!", &message, MessageBoxIcon::Warning); + }).unwrap().join().expect("Thread spawning failed"); + } +} + +#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] +fn display_alert_dialog(_message: String) { + // tinyfiledialogs not supported on Android +} + +#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] +fn get_url_input(_title: &str, _url: &str) -> Option { + // tinyfiledialogs not supported on Android + None +} + +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] +fn get_url_input(title: &str, url: &str) -> Option { + tinyfiledialogs::input_box(title, title, url) +} + #[cfg(target_os = "linux")] -fn platform_get_selected_devices(devices: Vec, sender: IpcSender>) { +fn platform_get_selected_devices(devices: Vec) -> Option { let picker_name = "Choose a device"; thread::Builder::new().name(picker_name.to_owned()).spawn(move || { @@ -328,58 +375,54 @@ fn platform_get_selected_devices(devices: Vec, sender: IpcSender { // The device string format will be "Address|Name". We need the first part of it. - let address = device.split("|").next().map(|s| s.to_string()); - let _ = sender.send(address); + device.split("|").next().map(|s| s.to_string()) }, None => { - let _ = sender.send(None); + None } } - }).expect("Thread spawning failed"); + }).unwrap().join().expect("Thread spawning failed") } #[cfg(not(target_os = "linux"))] -fn platform_get_selected_devices(devices: Vec, sender: IpcSender>) { +fn platform_get_selected_devices(devices: Vec) -> Option { for device in devices { if let Some(address) = device.split("|").next().map(|s| s.to_string()) { - let _ = sender.send(Some(address)); + return Some(address) } } - let _ = sender.send(None); + None } #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] fn platform_get_selected_files(patterns: Vec, - multiple_files: bool, - sender: IpcSender>>) { + multiple_files: bool) + -> Option> { let picker_name = if multiple_files { "Pick files" } else { "Pick a file" }; - thread::Builder::new().name(picker_name.to_owned()).spawn(move || { - let mut filter = vec![]; + let mut filters = vec![]; for p in patterns { let s = "*.".to_string() + &p.0; - filter.push(s) + filters.push(s) } - - let filter_ref = &(filter.iter().map(|s| s.as_str()).collect::>()[..]); - let filter_opt = if filter.len() > 0 { Some((filter_ref, "")) } else { None }; + let filter_ref = &(filters.iter().map(|s| s.as_str()).collect::>()[..]); + let filter_opt = if filters.len() > 0 { Some((filter_ref, "")) } else { None }; if multiple_files { - let files = tinyfiledialogs::open_file_dialog_multi(picker_name, "", filter_opt); - let _ = sender.send(files); + tinyfiledialogs::open_file_dialog_multi(picker_name, "", filter_opt) } else { let file = tinyfiledialogs::open_file_dialog(picker_name, "", filter_opt); - let _ = sender.send(file.map(|x| vec![x])); + file.map(|x| vec![x]) } - }).expect("Thread spawning failed"); + }).unwrap().join().expect("Thread spawning failed") } #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] fn platform_get_selected_files(_patterns: Vec, - _multiple_files: bool, - sender: IpcSender>>) { + _multiple_files: bool) + -> Option> { warn!("File picker not implemented"); - let _ = sender.send(None); + None } fn sanitize_url(request: &str) -> Option { diff --git a/ports/servo/glutin_app/window.rs b/ports/servo/glutin_app/window.rs index d14e49673b5..d7cca306fc8 100644 --- a/ports/servo/glutin_app/window.rs +++ b/ports/servo/glutin_app/window.rs @@ -11,9 +11,9 @@ use gleam::gl; use glutin::{Api, ContextBuilder, GlContext, GlRequest, GlWindow}; #[cfg(any(target_os = "linux", target_os = "macos"))] use osmesa_sys; -use servo::compositing::compositor_thread::EventLoopWaker; use servo::compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent}; use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods}; +use servo::embedder_traits::EventLoopWaker; use servo::msg::constellation_msg::{Key, KeyState}; use servo::script_traits::TouchEventType; use servo::servo_config::opts; diff --git a/ports/servo/main.rs b/ports/servo/main.rs index 31d249183af..b0db7926eb1 100644 --- a/ports/servo/main.rs +++ b/ports/servo/main.rs @@ -34,6 +34,7 @@ extern crate servo; #[cfg(all(feature = "unstable", not(target_os = "android")))] #[macro_use] extern crate sig; +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] extern crate tinyfiledialogs; extern crate winit; #[cfg(target_os = "windows")] extern crate winapi;