web browser (Servo)
git clone https://git.lucas.co/cce-browser.git
fix: a forwarded open focuses the browser window
Single-instance made link clicks look broken: the tab opened instantly,
but in a window parked wherever the browser last was — off-camera and
unfocused — where a fresh launch used to be focused and panned to by the
compositor. On OpenExternal the app now sends focus-window over the
control socket (focus pans the camera and raises). xdg-activation is not
the route: the compositor deliberately answers it with an attention
notification, not focus.
Co-Authored-By: Claude Fable 5 <[email protected]>
CLAUDE.md | 9 +++++++--
src/main.rs | 10 ++++++++++
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 639acdf..ee7c849 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -74,8 +74,13 @@ with `parse_startup_arg` — it *is* a launch argument, so the URL bar's
domain-guess parsing stays wrong for it — and a forwarded relative file path is
canonicalized on the *sending* side, whose cwd it is relative to. Beyond
tidiness this guards the profile dir: two engines must not share the plaintext
-cookie jar. There is deliberately no `--new-window` yet; raising the existing
-window on forward is also still open.
+cookie jar. There is deliberately no `--new-window` yet. On every forwarded
+open the app asks the compositor to `focus-window cce-browser` over the
+control socket — focus pans the camera to the window, which is what makes a
+forwarded link *visible*; without it the tab opens in a window parked
+off-camera and the click looks inert (that shipped for half a day). The
+compositor's xdg-activation is not the route: it deliberately answers with an
+attention notification, not focus.
The other half of click-to-tab latency is inside WebKit: creating a webview
and spawning its WebProcess is ~200ms, so the WPE host keeps a hidden **spare
diff --git a/src/main.rs b/src/main.rs
index ef2a3a1..384e1e8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1034,6 +1034,16 @@ impl Application for BrowserApp {
}
None => self.new_tab(),
}
+ // Bring the window to the user: focus + camera pan + raise
+ // over the control socket. A fresh launch used to get this
+ // from the compositor for free; without it the tab opens in
+ // a window parked somewhere off-camera and the click looks
+ // like it did nothing. (xdg-activation is not the route: the
+ // compositor deliberately answers it with an attention
+ // notification, not focus.)
+ std::thread::spawn(|| {
+ let _ = cce_ui::ipc::send_command("cce", "focus-window cce-browser");
+ });
*needs_rebuild = true;
}
}