Auto merge of #20707 - gterzian:embedder_handling_of_prompts_and_alerts_2, r=payl

Embedder handling of prompts and alerts

<!-- Please describe your changes on the following line: -->

Allow embedder to allow alerts and prompts, but via constellation forwarding messages from script.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [ ] `./mach build -d` does not report any errors
- [ ] `./mach build-geckolib` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes fix #19992  (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] 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. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20707)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-05-24 10:34:48 -04:00 committed by GitHub
commit f6762d54e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 413 additions and 375 deletions

View file

@ -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<ServoUrl>,
@ -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<EmbedderMsg>) {
for event in events {
match event {
EmbedderMsg::Status(_browser_id, status) => {
pub fn handle_servo_events(&mut self, events: Vec<(Option<BrowserId>, 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<String> {
// 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<String> {
tinyfiledialogs::input_box(title, title, url)
}
#[cfg(target_os = "linux")]
fn platform_get_selected_devices(devices: Vec<String>, sender: IpcSender<Option<String>>) {
fn platform_get_selected_devices(devices: Vec<String>) -> Option<String> {
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<String>, sender: IpcSender<Option<
match tinyfiledialogs::list_dialog("Choose a device", &["Id", "Name"], dialog_rows) {
Some(device) => {
// 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<String>, sender: IpcSender<Option<String>>) {
fn platform_get_selected_devices(devices: Vec<String>) -> Option<String> {
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<FilterPattern>,
multiple_files: bool,
sender: IpcSender<Option<Vec<String>>>) {
multiple_files: bool)
-> Option<Vec<String>> {
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::<Vec<&str>>()[..]);
let filter_opt = if filter.len() > 0 { Some((filter_ref, "")) } else { None };
let filter_ref = &(filters.iter().map(|s| s.as_str()).collect::<Vec<&str>>()[..]);
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<FilterPattern>,
_multiple_files: bool,
sender: IpcSender<Option<Vec<String>>>) {
_multiple_files: bool)
-> Option<Vec<String>> {
warn!("File picker not implemented");
let _ = sender.send(None);
None
}
fn sanitize_url(request: &str) -> Option<ServoUrl> {

View file

@ -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;

View file

@ -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;