git.lucas.co / cce-browser
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 }