mirror of
https://github.com/servo/servo.git
synced 2025-10-01 00:59:15 +01:00
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:
commit
f6762d54e2
32 changed files with 413 additions and 375 deletions
|
@ -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> {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue