New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move tinyfiledialog call from script to embedder #23651
Changes from all commits
File filter...
Jump to…
Some generated files are not rendered by default. Learn more.
| @@ -18,15 +18,14 @@ use crate::dom::globalscope::GlobalScope; | ||
| use crate::dom::permissionstatus::PermissionStatus; | ||
| use crate::dom::promise::Promise; | ||
| use dom_struct::dom_struct; | ||
| use embedder_traits::{EmbedderMsg, PermissionRequest}; | ||
| use ipc_channel::ipc; | ||
| use js::conversions::ConversionResult; | ||
| use js::jsapi::{JSContext, JSObject}; | ||
| use js::jsval::{ObjectValue, UndefinedValue}; | ||
| use servo_config::pref; | ||
| use std::rc::Rc; | ||
| #[cfg(target_os = "linux")] | ||
| use tinyfiledialogs::{self, MessageBoxIcon, YesNo}; | ||
|
|
||
| #[cfg(target_os = "linux")] | ||
| const DIALOG_TITLE: &'static str = "Permission request dialog"; | ||
| const NONSECURE_DIALOG_MESSAGE: &'static str = "feature is only safe to use in secure context,\ | ||
| but servo can't guarantee\n that the current context is secure. Do you want to proceed and grant permission?"; | ||
| @@ -146,7 +145,6 @@ impl Permissions { | ||
| // (Revoke) Step 3. | ||
| let globalscope = self.global(); | ||
| globalscope | ||
| .as_window() | ||
| .permission_state_invocation_results() | ||
| .borrow_mut() | ||
| .remove(&root_desc.name.to_string()); | ||
| @@ -179,7 +177,6 @@ impl Permissions { | ||
| // (Revoke) Step 3. | ||
| let globalscope = self.global(); | ||
| globalscope | ||
| .as_window() | ||
| .permission_state_invocation_results() | ||
| .borrow_mut() | ||
| .remove(&root_desc.name.to_string()); | ||
| @@ -268,16 +265,11 @@ impl PermissionAlgorithm for Permissions { | ||
| PermissionState::Prompt => { | ||
| let perm_name = status.get_query(); | ||
|
|
||
| let globalscope = GlobalScope::current().expect("No current global object"); | ||
|
|
||
| // https://w3c.github.io/permissions/#request-permission-to-use (Step 3 - 4) | ||
| let state = prompt_user( | ||
| &format!("{} {} ?", REQUEST_DIALOG_MESSAGE, perm_name.clone()), | ||
| globalscope.is_headless(), | ||
| ); | ||
|
|
||
| let globalscope = GlobalScope::current().expect("No current global object"); | ||
| let prompt = format!("{} {} ?", REQUEST_DIALOG_MESSAGE, perm_name.clone()); | ||
jdm
Member
|
||
| let state = prompt_user_from_embedder(prompt, &globalscope); | ||
| globalscope | ||
| .as_window() | ||
| .permission_state_invocation_results() | ||
| .borrow_mut() | ||
| .insert(perm_name.to_string(), state); | ||
| @@ -300,7 +292,7 @@ pub fn get_descriptor_permission_state( | ||
| env_settings_obj: Option<&GlobalScope>, | ||
| ) -> PermissionState { | ||
| // Step 1. | ||
| let settings = match env_settings_obj { | ||
| let globalscope = match env_settings_obj { | ||
| Some(env_settings_obj) => DomRoot::from_ref(env_settings_obj), | ||
| None => GlobalScope::current().expect("No current global object"), | ||
| }; | ||
| @@ -316,22 +308,18 @@ pub fn get_descriptor_permission_state( | ||
| if pref!(dom.permissions.testing.allowed_in_nonsecure_contexts) { | ||
| PermissionState::Granted | ||
| } else { | ||
| settings | ||
| .as_window() | ||
| globalscope | ||
| .permission_state_invocation_results() | ||
| .borrow_mut() | ||
| .remove(&permission_name.to_string()); | ||
|
|
||
| prompt_user( | ||
| &format!("The {} {}", permission_name, NONSECURE_DIALOG_MESSAGE), | ||
| settings.is_headless(), | ||
| ) | ||
| let prompt = format!("The {} {}", permission_name, NONSECURE_DIALOG_MESSAGE); | ||
| prompt_user_from_embedder(prompt, &globalscope) | ||
| } | ||
| }; | ||
|
|
||
| // Step 3. | ||
| if let Some(prev_result) = settings | ||
| .as_window() | ||
| if let Some(prev_result) = globalscope | ||
| .permission_state_invocation_results() | ||
| .borrow() | ||
| .get(&permission_name.to_string()) | ||
| @@ -340,8 +328,7 @@ pub fn get_descriptor_permission_state( | ||
| } | ||
|
|
||
| // Store the invocation result | ||
| settings | ||
| .as_window() | ||
| globalscope | ||
| .permission_state_invocation_results() | ||
| .borrow_mut() | ||
| .insert(permission_name.to_string(), state); | ||
| @@ -350,28 +337,6 @@ pub fn get_descriptor_permission_state( | ||
| state | ||
| } | ||
|
|
||
| #[cfg(target_os = "linux")] | ||
| fn prompt_user(message: &str, headless: bool) -> PermissionState { | ||
| if headless { | ||
| return PermissionState::Denied; | ||
| } | ||
| match tinyfiledialogs::message_box_yes_no( | ||
| DIALOG_TITLE, | ||
| message, | ||
| MessageBoxIcon::Question, | ||
| YesNo::No, | ||
| ) { | ||
| YesNo::Yes => PermissionState::Granted, | ||
| YesNo::No => PermissionState::Denied, | ||
| } | ||
| } | ||
|
|
||
| #[cfg(not(target_os = "linux"))] | ||
| fn prompt_user(_message: &str, _headless: bool) -> PermissionState { | ||
| // TODO popup only supported on linux | ||
| PermissionState::Denied | ||
| } | ||
|
|
||
| // https://w3c.github.io/permissions/#allowed-in-non-secure-contexts | ||
| fn allowed_in_nonsecure_contexts(permission_name: &PermissionName) -> bool { | ||
| match *permission_name { | ||
| @@ -399,3 +364,21 @@ fn allowed_in_nonsecure_contexts(permission_name: &PermissionName) -> bool { | ||
| PermissionName::Persistent_storage => false, | ||
| } | ||
| } | ||
|
|
||
| fn prompt_user_from_embedder(prompt: String, gs: &GlobalScope) -> PermissionState { | ||
| let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!"); | ||
| gs.send_to_embedder(EmbedderMsg::PromptPermission( | ||
| prompt, | ||
| DIALOG_TITLE.to_string(), | ||
| sender, | ||
| )); | ||
|
|
||
| match receiver.recv() { | ||
| Ok(PermissionRequest::Granted) => PermissionState::Granted, | ||
| Ok(PermissionRequest::Denied) => PermissionState::Denied, | ||
| Err(e) => { | ||
| warn!("Failed to receive permission state from embedder ({}).", e); | ||
| PermissionState::Denied | ||
| }, | ||
| } | ||
| } | ||
| @@ -7,7 +7,7 @@ use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT}; | ||
| use euclid::{TypedPoint2D, TypedVector2D}; | ||
| use keyboard_types::{Key, KeyboardEvent, Modifiers, ShortcutMatcher}; | ||
| use servo::compositing::windowing::{WebRenderDebugOption, WindowEvent}; | ||
| use servo::embedder_traits::{EmbedderMsg, FilterPattern}; | ||
| use servo::embedder_traits::{EmbedderMsg, FilterPattern, PermissionRequest}; | ||
| use servo::msg::constellation_msg::TopLevelBrowsingContextId as BrowserId; | ||
| use servo::msg::constellation_msg::TraversalDirection; | ||
| use servo::net_traits::pub_domains::is_reg_domain; | ||
| @@ -23,7 +23,7 @@ use std::mem; | ||
| use std::rc::Rc; | ||
| use std::thread; | ||
| use std::time::Duration; | ||
| use tinyfiledialogs::{self, MessageBoxIcon}; | ||
| use tinyfiledialogs::{self, MessageBoxIcon, YesNo}; | ||
|
|
||
| pub struct Browser<Window: WindowPortsMethods + ?Sized> { | ||
| current_url: Option<ServoUrl>, | ||
| @@ -401,6 +401,10 @@ where | ||
| self.event_queue.push(WindowEvent::SendError(None, reason)); | ||
| }; | ||
| }, | ||
| EmbedderMsg::PromptPermission(message, dialog_title, sender) => { | ||
jdm
Member
|
||
| let permission_state = prompt_user(&message, &dialog_title); | ||
| let _ = sender.send(permission_state); | ||
| } | ||
| EmbedderMsg::ShowIME(_kind) => { | ||
| debug!("ShowIME received"); | ||
| }, | ||
| @@ -419,6 +423,28 @@ where | ||
| } | ||
| } | ||
|
|
||
| #[cfg(target_os = "linux")] | ||
| fn prompt_user(prompt: &str, dialog_title: &str) -> PermissionRequest { | ||
| if opts::get().headless { | ||
| return PermissionRequest::Denied; | ||
| } | ||
| match tinyfiledialogs::message_box_yes_no( | ||
| dialog_title, | ||
| prompt, | ||
| MessageBoxIcon::Question, | ||
| YesNo::No, | ||
| ) { | ||
| YesNo::Yes => PermissionRequest::Granted, | ||
| YesNo::No => PermissionRequest::Denied, | ||
| } | ||
| } | ||
|
|
||
| #[cfg(not(target_os = "linux"))] | ||
| fn prompt_user(_prompt: &str, _dialog_title: &str) -> PermissionRequest { | ||
| // TODO popup only supported on linux | ||
| PermissionRequest::Denied | ||
| } | ||
|
|
||
| #[cfg(target_os = "linux")] | ||
| fn platform_get_selected_devices(devices: Vec<String>) -> Option<String> { | ||
| let picker_name = "Choose a device"; | ||
I propose instead of sending two strings, we send an enum:
This gives embedders the information they require in order to display whatever native prompt interface would make sense on that platform and supports localization better in the future.