mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Auto merge of #25242 - paulrouget:prompt, r=manishearth
Mechanism to allow Servo to prompt the user This blocks the embedder thread (compositor thread). Not ideal. I don't think it's too much work to only block script, I'll do that in a follow up bug. Fix #23376 @Manishearth we have a few new APIs. Hopefully this will cover your needs. A thing I haven't implemented yet is a way to ask the user to pick from a list. Let me know if it's something you'll need.
This commit is contained in:
commit
504437938a
22 changed files with 473 additions and 118 deletions
|
@ -13,6 +13,7 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
crossbeam-channel = "0.3"
|
||||
devtools_traits = {path = "../devtools_traits"}
|
||||
embedder_traits = {path = "../embedder_traits"}
|
||||
headers = "0.2"
|
||||
http = "0.1"
|
||||
hyper = "0.12"
|
||||
|
|
|
@ -39,7 +39,8 @@ use crossbeam_channel::{unbounded, Receiver, Sender};
|
|||
use devtools_traits::{ChromeToDevtoolsControlMsg, ConsoleMessage, DevtoolsControlMsg};
|
||||
use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo, LogLevel, NetworkEvent};
|
||||
use devtools_traits::{PageError, ScriptToDevtoolsControlMsg, WorkerId};
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use embedder_traits::{EmbedderMsg, EmbedderProxy, PromptDefinition, PromptOrigin, PromptResult};
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use std::borrow::ToOwned;
|
||||
use std::cell::RefCell;
|
||||
|
@ -135,13 +136,13 @@ struct ResponseStartUpdateMsg {
|
|||
}
|
||||
|
||||
/// Spin up a devtools server that listens for connections on the specified port.
|
||||
pub fn start_server(port: u16) -> Sender<DevtoolsControlMsg> {
|
||||
pub fn start_server(port: u16, embedder: EmbedderProxy) -> Sender<DevtoolsControlMsg> {
|
||||
let (sender, receiver) = unbounded();
|
||||
{
|
||||
let sender = sender.clone();
|
||||
thread::Builder::new()
|
||||
.name("Devtools".to_owned())
|
||||
.spawn(move || run_server(sender, receiver, port))
|
||||
.spawn(move || run_server(sender, receiver, port, embedder))
|
||||
.expect("Thread spawning failed");
|
||||
}
|
||||
sender
|
||||
|
@ -151,6 +152,7 @@ fn run_server(
|
|||
sender: Sender<DevtoolsControlMsg>,
|
||||
receiver: Receiver<DevtoolsControlMsg>,
|
||||
port: u16,
|
||||
embedder: EmbedderProxy,
|
||||
) {
|
||||
let listener = TcpListener::bind(&("0.0.0.0", port)).unwrap();
|
||||
|
||||
|
@ -553,7 +555,17 @@ fn run_server(
|
|||
.spawn(move || {
|
||||
// accept connections and process them, spawning a new thread for each one
|
||||
for stream in listener.incoming() {
|
||||
// connection succeeded
|
||||
// Prompt user for permission
|
||||
let (embedder_sender, receiver) =
|
||||
ipc::channel().expect("Failed to create IPC channel!");
|
||||
let message = "Accept incoming devtools connection?".to_owned();
|
||||
let prompt = PromptDefinition::YesNo(message, embedder_sender);
|
||||
let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Trusted);
|
||||
embedder.send((None, msg));
|
||||
if receiver.recv().unwrap() != PromptResult::Primary {
|
||||
continue;
|
||||
}
|
||||
// connection succeeded and accepted
|
||||
sender
|
||||
.send(DevtoolsControlMsg::FromChrome(
|
||||
ChromeToDevtoolsControlMsg::AddClient(stream.unwrap()),
|
||||
|
|
|
@ -106,6 +106,37 @@ impl EmbedderReceiver {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum PromptDefinition {
|
||||
/// Show a message.
|
||||
Alert(String, IpcSender<()>),
|
||||
/// Ask a Ok/Cancel question.
|
||||
OkCancel(String, IpcSender<PromptResult>),
|
||||
/// Ask a Yes/No question.
|
||||
YesNo(String, IpcSender<PromptResult>),
|
||||
/// Ask the user to enter text.
|
||||
Input(String, String, IpcSender<Option<String>>),
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Serialize)]
|
||||
pub enum PromptOrigin {
|
||||
/// Prompt is triggered from content (window.prompt/alert/confirm/…).
|
||||
/// Prompt message is unknown.
|
||||
Untrusted,
|
||||
/// Prompt is triggered from Servo (ask for permission, show error,…).
|
||||
Trusted,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Serialize)]
|
||||
pub enum PromptResult {
|
||||
/// Prompt was closed by clicking on the primary button (ok/yes)
|
||||
Primary,
|
||||
/// Prompt was closed by clicking on the secondary button (cancel/no)
|
||||
Secondary,
|
||||
/// Prompt was dismissed
|
||||
Dismissed,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum EmbedderMsg {
|
||||
/// A status message to be displayed by the browser chrome.
|
||||
|
@ -116,8 +147,8 @@ pub enum EmbedderMsg {
|
|||
MoveTo(DeviceIntPoint),
|
||||
/// Resize the window to size
|
||||
ResizeTo(DeviceIntSize),
|
||||
// Show an alert message.
|
||||
Alert(String, IpcSender<()>),
|
||||
/// Show dialog to user
|
||||
Prompt(PromptDefinition, PromptOrigin),
|
||||
/// Wether or not to allow a pipeline to load a url.
|
||||
AllowNavigationRequest(PipelineId, ServoUrl),
|
||||
/// Whether or not to allow script to open a new tab/browser
|
||||
|
@ -174,7 +205,7 @@ impl Debug for EmbedderMsg {
|
|||
EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
|
||||
EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"),
|
||||
EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"),
|
||||
EmbedderMsg::Alert(..) => write!(f, "Alert"),
|
||||
EmbedderMsg::Prompt(..) => write!(f, "Prompt"),
|
||||
EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
|
||||
EmbedderMsg::AllowNavigationRequest(..) => write!(f, "AllowNavigationRequest"),
|
||||
EmbedderMsg::Keyboard(..) => write!(f, "Keyboard"),
|
||||
|
|
|
@ -55,8 +55,8 @@
|
|||
// user prompts
|
||||
void alert(DOMString message);
|
||||
void alert();
|
||||
//boolean confirm(optional DOMString message = "");
|
||||
//DOMString? prompt(optional DOMString message = "", optional DOMString default = "");
|
||||
boolean confirm(optional DOMString message = "");
|
||||
DOMString? prompt(optional DOMString message = "", optional DOMString default = "");
|
||||
//void print();
|
||||
//any showModalDialog(DOMString url, optional any argument);
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ use crossbeam_channel::{unbounded, Sender, TryRecvError};
|
|||
use cssparser::{Parser, ParserInput, SourceLocation};
|
||||
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::{EmbedderMsg, EventLoopWaker};
|
||||
use embedder_traits::{EmbedderMsg, EventLoopWaker, PromptDefinition, PromptOrigin, PromptResult};
|
||||
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
|
||||
use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
|
||||
use ipc_channel::ipc::{channel, IpcSender};
|
||||
|
@ -620,11 +620,32 @@ impl WindowMethods for Window {
|
|||
}
|
||||
let (sender, receiver) =
|
||||
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
let msg = EmbedderMsg::Alert(s.to_string(), sender);
|
||||
let prompt = PromptDefinition::Alert(s.to_string(), sender);
|
||||
let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Untrusted);
|
||||
self.send_to_embedder(msg);
|
||||
receiver.recv().unwrap();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-confirm
|
||||
fn Confirm(&self, s: DOMString) -> bool {
|
||||
let (sender, receiver) =
|
||||
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
let prompt = PromptDefinition::OkCancel(s.to_string(), sender);
|
||||
let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Untrusted);
|
||||
self.send_to_embedder(msg);
|
||||
receiver.recv().unwrap() == PromptResult::Primary
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-prompt
|
||||
fn Prompt(&self, message: DOMString, default: DOMString) -> Option<DOMString> {
|
||||
let (sender, receiver) =
|
||||
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
let prompt = PromptDefinition::Input(message.to_string(), default.to_string(), sender);
|
||||
let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Untrusted);
|
||||
self.send_to_embedder(msg);
|
||||
receiver.recv().unwrap().map(|s| s.into())
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-window-stop
|
||||
fn Stop(&self) {
|
||||
// TODO: Cancel ongoing navigation.
|
||||
|
|
|
@ -356,8 +356,11 @@ where
|
|||
opts.profile_heartbeats,
|
||||
);
|
||||
let mem_profiler_chan = profile_mem::Profiler::create(opts.mem_profiler_period);
|
||||
|
||||
let debugger_chan = opts.debugger_port.map(|port| debugger::start_server(port));
|
||||
let devtools_chan = opts.devtools_port.map(|port| devtools::start_server(port));
|
||||
let devtools_chan = opts
|
||||
.devtools_port
|
||||
.map(|port| devtools::start_server(port, embedder_proxy.clone()));
|
||||
|
||||
let coordinates = window.get_coordinates();
|
||||
let device_pixel_ratio = coordinates.hidpi_factor.get();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue