Repository: servo/servo
File: ports/servoshell/running_app_state.rs (Rust)

Code before:
        let experimental_preferences_enabled =
            Cell::new(servoshell_preferences.experimental_preferences_enabled);

        Self {
            windows: Default::default(),
            focused_window: Default::default(),
            gamepad_support: RefCell::new(gamepad_support),
            webdriver_senders: RefCell::default(),
            webdriver_embedder_controls: Default::default(),
            pending_webdriver_events: Default::default(),
            webdriver_receiver,
            servoshell_preferences,
            servo,
            achieved_stable_image: Default::default(),
            exit_scheduled: Default::default(),
            experimental_preferences_enabled,
        }
    }

    pub(crate) fn open_window(
        self: &Rc<Self>,
        platform_window: Rc<dyn PlatformWindow>,
        initial_url: Url,
    ) -> Rc<ServoShellWindow> {
        let window = Rc::new(ServoShellWindow::new(platform_window));
        self.focus_window(window.clone());
        window.create_and_activate_toplevel_webview(self.clone(), initial_url);
        self.windows
            .borrow_mut()
            .insert(window.id(), window.clone());
        window
    }

    pub(crate) fn windows<'a>(
        &'a self,
    ) -> Ref<'a, HashMap<ServoShellWindowId, Rc<ServoShellWindow>>> {
        self.windows.borrow()
    }

    pub(crate) fn focused_window(&self) -> Option<Rc<ServoShellWindow>> {
        self.focused_window.borrow().clone()
    }

    pub(crate) fn focus_window(&self, window: Rc<ServoShellWindow>) {
        window.focus();
        *self.focused_window.borrow_mut() = Some(window);
    }

    #[cfg_attr(any(target_os = "android", target_env = "ohos"), expect(dead_code))]
    pub(crate) fn window(&self, id: ServoShellWindowId) -> Option<Rc<ServoShellWindow>> {
        self.windows.borrow().get(&id).cloned()

Review comment (suggestion):
I think it should be up to the window manager to decide which windows get focus in servoshell. You're right though that we also aren't listening to signals that a window has been focused. We should add `RunningAppState::handle_focus`:

```rust
    pub(crate) fn handle_focused(&self, window: Rc<ServoShellWindow>) {
        *self.focused_window.borrow_mut() = Some(window);
    }
```

This is the same as `focus()`, but doesn't trigger a system focus request.

And then we handle `WindowEvent::Focused`:

```diff
diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs
index f0ff1e212a8..5f60be38a7d 100644
--- a/ports/servoshell/desktop/headed_window.rs
+++ b/ports/servoshell/desktop/headed_window.rs
@@ -629,6 +629,7 @@ impl PlatformWindow for Window {
         // Handle the event
         let mut consumed = false;
         match event {
+            WindowEvent::Focused(true) => running_app_state.handle_focused(window),
             WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
                 // Intercept any ScaleFactorChanged events away from EguiGlow::on_window_event, so
                 // we can use our own logic for calculating the scale factor and set egui’s
```

Code after:
        let experimental_preferences_enabled =
            Cell::new(servoshell_preferences.experimental_preferences_enabled);

        Self {
            windows: Default::default(),
            focused_window: Default::default(),
            gamepad_support: RefCell::new(gamepad_support),
            webdriver_senders: RefCell::default(),
            webdriver_embedder_controls: Default::default(),
            pending_webdriver_events: Default::default(),
            webdriver_receiver,
            servoshell_preferences,
            servo,
            achieved_stable_image: Default::default(),
            exit_scheduled: Default::default(),
            experimental_preferences_enabled,
        }
    }

    pub(crate) fn open_window(
        self: &Rc<Self>,
        platform_window: Rc<dyn PlatformWindow>,
        initial_url: Url,
    ) -> Rc<ServoShellWindow> {
        let has_winit_window = platform_window.has_winit_window();
        let window = Rc::new(ServoShellWindow::new(platform_window));

        // For [`HeadedWindow`], it is up to the `winit::event::WindowEvent::Focused`.
        // Otherwise, newly created windows are automatically focused.
        if !has_winit_window {
            self.focus_window(window.clone());
        }
        window.create_and_activate_toplevel_webview(self.clone(), initial_url);
        self.windows
            .borrow_mut()
            .insert(window.id(), window.clone());
        window
    }

    pub(crate) fn windows<'a>(
        &'a self,
    ) -> Ref<'a, HashMap<ServoShellWindowId, Rc<ServoShellWindow>>> {
        self.windows.borrow()
    }

    pub(crate) fn focused_window(&self) -> Option<Rc<ServoShellWindow>> {
        self.focused_window.borrow().clone()
    }

    pub(crate) fn focus_window(&self, window: Rc<ServoShellWindow>) {
        window.focus();