Skip to content
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

Initial effort to use IPC calls to control verso #207

Merged
merged 5 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = ["verso", "versoview_messages"]
[workspace.dependencies]
ipc-channel = "0.19"
serde = { version = "1.0", features = ["derive"] }
url = { version = "2.5.2", features = ["serde"] }

[package]
name = "versoview"
Expand Down Expand Up @@ -104,7 +105,7 @@ webxr-api = { git = "https://github.com/servo/webxr" }
cargo-packager-resource-resolver = { version = "0.1.1", features = [
"auto-detect-format",
], optional = true }
url = "2.5.2"
url = { workspace = true }
headers = "0.3"
versoview_messages = { path = "./versoview_messages" }

Expand Down
14 changes: 13 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use servo_config::opts::{default_opts, set_options, Opts};
pub struct CliArgs {
/// URL to load initially.
pub url: Option<url::Url>,
/// URL to load initially.
pub ipc_channel_name: Option<String>,
Legend-Master marked this conversation as resolved.
Show resolved Hide resolved
}

/// Configuration of Verso instance.
Expand All @@ -33,6 +35,12 @@ fn parse_cli_args() -> Result<CliArgs, getopts::Fail> {

let mut opts = getopts::Options::new();
opts.optopt("", "url", "URL to load on start", "URL");
opts.optopt(
"",
"ipc-channel",
"IPC channel name to communicate and control verso",
"",
);

let matches: getopts::Matches = opts.parse(&args[1..])?;
let url = matches
Expand All @@ -49,8 +57,12 @@ fn parse_cli_args() -> Result<CliArgs, getopts::Fail> {
None
}
});
let ipc_channel_name = matches.opt_str("ipc-channel");

Ok(CliArgs { url })
Ok(CliArgs {
url,
ipc_channel_name,
})
}

impl Config {
Expand Down
22 changes: 17 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use versoview::config::Config;
use versoview::verso::EventLoopProxyMessage;
use versoview::{Result, Verso};
use winit::application::ApplicationHandler;
use winit::event_loop::{self, DeviceEvents};
use winit::event_loop::{EventLoop, EventLoopProxy};

struct App {
verso: Option<Verso>,
proxy: EventLoopProxy<()>,
proxy: EventLoopProxy<EventLoopProxyMessage>,
}

impl ApplicationHandler for App {
impl ApplicationHandler<EventLoopProxyMessage> for App {
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
let config = Config::new(resources_dir_path().unwrap());
self.verso = Some(Verso::new(event_loop, self.proxy.clone(), config));
Expand All @@ -30,15 +31,26 @@ impl ApplicationHandler for App {
}
}

fn user_event(&mut self, event_loop: &event_loop::ActiveEventLoop, _: ()) {
fn user_event(
&mut self,
event_loop: &event_loop::ActiveEventLoop,
event: EventLoopProxyMessage,
) {
if let Some(v) = self.verso.as_mut() {
v.handle_servo_messages(event_loop);
match event {
EventLoopProxyMessage::Wake => {
v.handle_servo_messages(event_loop);
}
EventLoopProxyMessage::WebviewControllerMessage(message) => {
v.handle_incoming_webview_message(message);
}
}
}
}
}

fn main() -> Result<()> {
let event_loop = EventLoop::new()?;
let event_loop = EventLoop::<EventLoopProxyMessage>::with_user_event().build()?;
event_loop.listen_device_events(DeviceEvents::Never);
let proxy = event_loop.create_proxy();
let mut app = App { verso: None, proxy };
Expand Down
58 changes: 54 additions & 4 deletions src/verso.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ use profile;
use script::{self, JSEngineSetup};
use script_traits::WindowSizeData;
use servo_config::{opts, pref};
use servo_url::ServoUrl;
use style;
use versoview_messages::ControllerMessage;
use webgpu;
use webrender::{create_webrender_instance, ShaderPrecacheFlags, WebRenderOptions};
use webrender_api::*;
Expand Down Expand Up @@ -75,10 +77,33 @@ impl Verso {
/// - Canvas: Enabled
/// - Constellation: Enabled
/// - Image Cache: Enabled
pub fn new(evl: &ActiveEventLoop, proxy: EventLoopProxy<()>, config: Config) -> Self {
pub fn new(
evl: &ActiveEventLoop,
proxy: EventLoopProxy<EventLoopProxyMessage>,
config: Config,
) -> Self {
if let Some(ipc_channel_name) = &config.args.ipc_channel_name {
let sender =
IpcSender::<IpcSender<ControllerMessage>>::connect(ipc_channel_name.to_string())
.unwrap();
let (controller_sender, receiver) = ipc::channel::<ControllerMessage>().unwrap();
sender.send(controller_sender).unwrap();
let proxy_clone = proxy.clone();
std::thread::spawn(move || {
while let Ok(message) = receiver.recv() {
if let Err(e) = proxy_clone
.send_event(EventLoopProxyMessage::WebviewControllerMessage(message))
{
log::error!("Failed to send controller message to Verso: {e}");
}
}
});
wusyong marked this conversation as resolved.
Show resolved Hide resolved
};

// Initialize configurations and Verso window
let protocols = config.create_protocols();
let initial_url = config.args.url.clone();

config.init();
// Reserving a namespace to create TopLevelBrowsingContextId.
PipelineNamespace::install(PipelineNamespaceId(0));
Expand Down Expand Up @@ -494,6 +519,23 @@ impl Verso {
}
}

/// Handle message came from webview controller.
pub fn handle_incoming_webview_message(&self, message: ControllerMessage) {
match message {
ControllerMessage::NavigateTo(to_url) => {
if let Some(webview_id) = self.windows.values().next().and_then(|(window, _)| {
window.webview.as_ref().map(|webview| webview.webview_id)
}) {
send_to_constellation(
&self.constellation_sender,
ConstellationMsg::LoadUrl(webview_id, ServoUrl::from_url(to_url)),
);
}
}
_ => {}
}
}

/// Return true if one of the Verso windows is animating.
pub fn is_animating(&self) -> bool {
self.compositor
Expand All @@ -516,17 +558,25 @@ impl Verso {
}
}

/// Message send to the event loop
pub enum EventLoopProxyMessage {
/// Wake
Wake,
/// Message coming from the webview controller
WebviewControllerMessage(ControllerMessage),
}

#[derive(Debug, Clone)]
struct Waker(pub EventLoopProxy<()>);
struct Waker(pub EventLoopProxy<EventLoopProxyMessage>);

impl EventLoopWaker for Waker {
fn clone_box(&self) -> Box<dyn EventLoopWaker> {
Box::new(self.clone())
}

fn wake(&self) {
if let Err(e) = self.0.send_event(()) {
log::error!("Servo failed to send wake up event to Verso: {}", e);
if let Err(e) = self.0.send_event(EventLoopProxyMessage::Wake) {
log::error!("Servo failed to send wake up event to Verso: {e}");
}
}
}
Expand Down
1 change: 1 addition & 0 deletions verso/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ edition = "2021"
[dependencies]
ipc-channel = { workspace = true }
serde = { workspace = true }
url = { workspace = true }
versoview_messages = { path = "../versoview_messages" }
15 changes: 15 additions & 0 deletions verso/examples/simple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use std::{path::PathBuf, thread::sleep, time::Duration};

fn main() {
let controller = verso::VersoviewController::new(
PathBuf::from("target/debug/versoview"),
url::Url::parse("https://example.com").unwrap(),
);
sleep(Duration::from_secs(10));
dbg!(controller
.navigate(url::Url::parse("https://docs.rs").unwrap())
.unwrap());
loop {
sleep(Duration::from_secs(10));
}
}
26 changes: 26 additions & 0 deletions verso/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,27 @@
use std::{path::Path, process::Command};
use versoview_messages::ControllerMessage;

use ipc_channel::ipc::{IpcOneShotServer, IpcSender};

pub struct VersoviewController(IpcSender<ControllerMessage>);

impl VersoviewController {
/// Create a new verso instance and get the controller to it
pub fn new(verso_path: impl AsRef<Path>, initial_url: url::Url) -> Self {
let path = verso_path.as_ref();
let (server, server_name) =
IpcOneShotServer::<IpcSender<ControllerMessage>>::new().unwrap();
Command::new(path)
.arg(format!("--ipc-channel={server_name}"))
.arg(format!("--url={initial_url}"))
.spawn()
.unwrap();
let (_, sender) = server.accept().unwrap();
Self(sender)
}

/// Navigate to url
pub fn navigate(&self, url: url::Url) -> Result<(), Box<ipc_channel::ErrorKind>> {
self.0.send(ControllerMessage::NavigateTo(url))
}
}
1 change: 1 addition & 0 deletions versoview_messages/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ edition = "2021"
[dependencies]
ipc-channel = { workspace = true }
serde = { workspace = true }
url = { workspace = true }
6 changes: 6 additions & 0 deletions versoview_messages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum ControllerMessage {
NavigateTo(url::Url),
}