web browser (Servo)
git clone https://git.lucas.co/cce-browser.git
src/bin/open.rs (2.3K)
1 //! `cce-browser-open` — the launch-latency half of single-instance.
2 //!
3 //! The desktop entry's `Exec` points here, not at `cce-browser`: forwarding a
4 //! link through the full browser binary costs ~20ms of dynamic-library loading
5 //! (libWPEWebKit and friends) before `main()` runs, all on the click-to-tab
6 //! path. This bin exists to link nothing, forward in a few ms, and only
7 //! `exec` the real browser when no instance answers.
8 //!
9 //! It takes the client half of the socket protocol from `cce_core::ipc`
10 //! (the GUI-free half of the toolkit, which has no native libraries): the
11 //! path convention and the one-line forward with its ack wait. `src/instance.rs`
12 //! (same crate, on `cce_ui::ipc::instance`, the same module) is the server side.
13 //! Both must agree on the `open <arg>` / `new-tab` lines. Until 2026-10-07 this
14 //! file copied both halves, to stay clear of cce-ui's native link flags.
15
16 use std::os::unix::process::CommandExt;
17
18 /// One forwarding attempt; false on any failure. A stuck instance does not
19 /// hang the click: `forward` bounds its wait for the ack.
20 fn try_forward(arg: Option<&str>) -> bool {
21 let command = match arg {
22 Some(a) => {
23 // A relative file path is resolved against *this* process's cwd —
24 // the instance's differs, so it must travel absolute.
25 let p = std::path::Path::new(a);
26 let abs = if p.exists() {
27 std::fs::canonicalize(p)
28 .ok()
29 .and_then(|c| c.to_str().map(String::from))
30 } else {
31 None
32 };
33 format!("open {}", abs.as_deref().unwrap_or(a))
34 }
35 None => "new-tab".to_string(),
36 };
37 cce_core::ipc::instance::forward("cce-browser", &command).is_some()
38 }
39
40 fn main() {
41 let args: Vec<String> = std::env::args().skip(1).collect();
42 if try_forward(args.first().map(String::as_str)) {
43 return;
44 }
45 // No instance answered: become one. PATH resolution matches the desktop
46 // entry convention (~/.local/bin first); the browser runs its own
47 // forward_or_claim, which settles any launch race from here on.
48 let err = std::process::Command::new("cce-browser").args(&args).exec();
49 eprintln!("cce-browser-open: could not exec cce-browser: {err}");
50 std::process::exit(1);
51 }