diff options
author | Martin Robinson <mrobinson@igalia.com> | 2025-01-28 15:57:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-28 14:57:57 +0000 |
commit | 9dbc942beeab1ce9d771706ee3c6d09c6b7aa227 (patch) | |
tree | 5bfcf6d16cf29286e2796d953bebec9a937b20f3 /ports/servoshell/desktop/app.rs | |
parent | a1cf0cbf86b93c863bc2b7693a382668d0f38e7c (diff) | |
download | servo-9dbc942beeab1ce9d771706ee3c6d09c6b7aa227.tar.gz servo-9dbc942beeab1ce9d771706ee3c6d09c6b7aa227.zip |
libservo: Port desktop servoshell to use the new `WebView` API (#35183)
This removes all uses of `EmbedderEvent` in the desktop servoshell to
use the new `WebView` API -- filling it out when necessary.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Delan Azabani <dazabani@igalia.com>
Diffstat (limited to 'ports/servoshell/desktop/app.rs')
-rw-r--r-- | ports/servoshell/desktop/app.rs | 173 |
1 files changed, 97 insertions, 76 deletions
diff --git a/ports/servoshell/desktop/app.rs b/ports/servoshell/desktop/app.rs index 73b0b00acdb..c9b30ab669e 100644 --- a/ports/servoshell/desktop/app.rs +++ b/ports/servoshell/desktop/app.rs @@ -10,10 +10,10 @@ use std::rc::Rc; use std::time::Instant; use std::{env, fs}; -use log::{info, trace}; +use arboard::Clipboard; +use log::{info, trace, warn}; use raw_window_handle::HasDisplayHandle; -use servo::base::id::WebViewId; -use servo::compositing::windowing::{AnimationState, EmbedderEvent, WindowMethods}; +use servo::compositing::windowing::{AnimationState, WindowMethods}; use servo::compositing::CompositeTarget; use servo::config::opts::Opts; use servo::config::prefs::Preferences; @@ -22,6 +22,7 @@ use servo::servo_url::ServoUrl; use servo::webrender_traits::SurfmanRenderingContext; use servo::{EventLoopWaker, Servo}; use surfman::Connection; +use url::Url; use webxr::glwindow::GlWindowDiscovery; #[cfg(target_os = "windows")] use webxr::openxr::{AppInfo, OpenXrDiscovery}; @@ -31,22 +32,22 @@ use winit::event_loop::{ActiveEventLoop, ControlFlow}; use winit::window::WindowId; use super::events_loop::{EventsLoop, WakerEvent}; -use super::minibrowser::Minibrowser; +use super::minibrowser::{Minibrowser, MinibrowserEvent}; use super::webview::WebViewManager; use super::{headed_window, headless_window}; use crate::desktop::embedder::{EmbedderCallbacks, XrDiscovery}; use crate::desktop::tracing::trace_winit_event; use crate::desktop::window_trait::WindowPortsMethods; -use crate::parser::get_default_url; +use crate::parser::{get_default_url, location_bar_input_to_url}; use crate::prefs::ServoShellPreferences; pub struct App { opts: Opts, preferences: Preferences, servo_shell_preferences: ServoShellPreferences, + clipboard: Option<Clipboard>, servo: Option<Servo>, - webviews: Option<WebViewManager<dyn WindowPortsMethods>>, - event_queue: Vec<EmbedderEvent>, + webviews: Option<WebViewManager>, suspended: Cell<bool>, windows: HashMap<WindowId, Rc<dyn WindowPortsMethods>>, minibrowser: Option<Minibrowser>, @@ -91,7 +92,7 @@ impl App { opts, preferences, servo_shell_preferences, - event_queue: vec![], + clipboard: Clipboard::new().ok(), webviews: None, servo: None, suspended: Cell::new(false), @@ -164,7 +165,7 @@ impl App { minibrowser.update( window.winit_window().unwrap(), self.webviews.as_mut().unwrap(), - None, + self.servo.as_mut(), "init", ); window.set_toolbar_height(minibrowser.toolbar_height); @@ -173,7 +174,6 @@ impl App { self.windows.insert(window.id(), window); self.suspended.set(false); - self.event_queue.push(EmbedderEvent::Idle); let (_, window) = self.windows.iter().next().unwrap(); let xr_discovery = if pref!(dom_webxr_openxr_enabled) && !self.opts.headless { @@ -213,7 +213,7 @@ impl App { } else { CompositeTarget::Window }; - let mut servo = Servo::new( + let servo = Servo::new( self.opts.clone(), self.preferences.clone(), Rc::new(rendering_context), @@ -223,12 +223,11 @@ impl App { composite_target, ); - servo.handle_events(vec![EmbedderEvent::NewWebView( - self.initial_url.to_owned(), - WebViewId::new(), - )]); servo.setup_logging(); + let webview = servo.new_webview(self.initial_url.clone().into_url()); + self.webviews.as_mut().unwrap().add(webview); + self.servo = Some(servo); } @@ -236,61 +235,47 @@ impl App { self.windows.iter().any(|(_, window)| window.is_animating()) } - fn get_events(&mut self) -> Vec<EmbedderEvent> { - std::mem::take(&mut self.event_queue) - } - - /// Pumps events and messages between the embedder and Servo, where embedder events flow - /// towards Servo and embedder messages flow away from Servo, and also runs the compositor. + /// Spins the Servo event loop, and (for now) handles a few other tasks: + /// - Notifying Servo about incoming gamepad events + /// - Receiving updates from Servo + /// - Performing updates in the compositor, such as queued pinch zoom events /// - /// As the embedder, we push embedder events through our event queues, from the App queue and - /// Window queues to the WebViewManager queue, and from the WebViewManager queue to Servo. We - /// receive and collect embedder messages from the various Servo components, then take them out - /// of the Servo interface so that the WebViewManager can handle them. + /// In the future, these tasks may be decoupled. fn handle_events(&mut self) -> PumpResult { - let mut embedder_events = self.get_events(); let webviews = self.webviews.as_mut().unwrap(); - // Take any outstanding embedder events from the App and its Windows. - for window in self.windows.values() { - embedder_events.extend(window.get_events()); - } - - // Catch some keyboard events, and push the rest onto the WebViewManager event queue. - webviews.handle_window_events(embedder_events); - // If the Gamepad API is enabled, handle gamepad events from GilRs. // Checking for focused_webview_id should ensure we'll have a valid browsing context. if pref!(dom_gamepad_enabled) && webviews.focused_webview_id().is_some() { webviews.handle_gamepad_events(); } - // Take any new embedder messages from Servo itself. - let mut embedder_messages = self.servo.as_mut().unwrap().get_events(); + // Take any new embedder messages from Servo. + let servo = self.servo.as_mut().expect("Servo should be running."); + let mut embedder_messages: Vec<_> = servo.get_events().collect(); let mut need_resize = false; let mut need_present = false; let mut need_update = false; loop { // Consume and handle those embedder messages. - let servo_event_response = webviews.handle_servo_events(&self.opts, embedder_messages); + let servo_event_response = webviews.handle_servo_events( + servo, + &mut self.clipboard, + &self.opts, + embedder_messages, + ); need_present |= servo_event_response.need_present; need_update |= servo_event_response.need_update; - // Route embedder events from the WebViewManager to the relevant Servo components, - // receives and collects embedder messages from various Servo components, - // and runs the compositor. - need_resize |= self - .servo - .as_mut() - .unwrap() - .handle_events(webviews.get_events()); + // Runs the compositor, and receives and collects embedder messages from various Servo components. + need_resize |= servo.handle_events(vec![]); if webviews.shutdown_requested() { return PumpResult::Shutdown; } // Take any new embedder messages from Servo itself. - embedder_messages = self.servo.as_mut().unwrap().get_events(); - if embedder_messages.len() == 0 { + embedder_messages = servo.get_events().collect(); + if embedder_messages.is_empty() { break; } } @@ -333,7 +318,7 @@ impl App { minibrowser.update( window.winit_window().unwrap(), webviews, - self.servo.as_ref().unwrap().offscreen_framebuffer_id(), + self.servo.as_mut(), "update_location_in_toolbar", ); } @@ -351,7 +336,7 @@ impl App { minibrowser.update( window.winit_window().unwrap(), self.webviews.as_mut().unwrap(), - self.servo.as_ref().unwrap().offscreen_framebuffer_id(), + self.servo.as_mut(), "PumpResult::Present::Immediate", ); minibrowser.paint(window.winit_window().unwrap()); @@ -391,7 +376,6 @@ impl App { if self.servo.is_none() { return false; } - self.event_queue.push(EmbedderEvent::Idle); let mut exit = false; match self.handle_events() { @@ -421,6 +405,62 @@ impl App { } exit } + + /// Takes any events generated during `egui` updates and performs their actions. + fn handle_servoshell_ui_events(&mut self) { + let Some(webviews) = self.webviews.as_mut() else { + return; + }; + let Some(minibrowser) = self.minibrowser.as_ref() else { + return; + }; + let Some(servo) = self.servo.as_ref() else { + return; + }; + + for event in minibrowser.take_events() { + match event { + MinibrowserEvent::Go(location) => { + minibrowser.update_location_dirty(false); + let Some(url) = location_bar_input_to_url( + &location.clone(), + &self.servo_shell_preferences.searchpage, + ) else { + warn!("failed to parse location"); + break; + }; + if let Some(focused_webview) = webviews.focused_webview() { + focused_webview.servo_webview.load(url.into_url()); + } + }, + MinibrowserEvent::Back => { + if let Some(focused_webview) = webviews.focused_webview() { + focused_webview.servo_webview.go_back(1); + } + }, + MinibrowserEvent::Forward => { + if let Some(focused_webview) = webviews.focused_webview() { + focused_webview.servo_webview.go_forward(1); + } + }, + MinibrowserEvent::Reload => { + minibrowser.update_location_dirty(false); + if let Some(focused_webview) = webviews.focused_webview() { + focused_webview.servo_webview.reload(); + } + }, + MinibrowserEvent::NewWebView => { + minibrowser.update_location_dirty(false); + let webview = servo.new_webview(Url::parse("servo:newtab").unwrap()); + webviews.add(webview); + }, + MinibrowserEvent::CloseWebView(id) => { + minibrowser.update_location_dirty(false); + webviews.close_webview(servo, id); + }, + } + } + } } impl ApplicationHandler<WakerEvent> for App { @@ -463,7 +503,7 @@ impl ApplicationHandler<WakerEvent> for App { minibrowser.update( window.winit_window().unwrap(), self.webviews.as_mut().unwrap(), - self.servo.as_ref().unwrap().offscreen_framebuffer_id(), + self.servo.as_mut(), "RedrawRequested", ); minibrowser.paint(window.winit_window().unwrap()); @@ -505,7 +545,7 @@ impl ApplicationHandler<WakerEvent> for App { minibrowser.update( window.winit_window().unwrap(), self.webviews.as_mut().unwrap(), - self.servo.as_ref().unwrap().offscreen_framebuffer_id(), + self.servo.as_mut(), "Sync WebView size with Window Resize event", ); } @@ -522,11 +562,9 @@ impl ApplicationHandler<WakerEvent> for App { } } if !consumed { - if event == winit::event::WindowEvent::RedrawRequested { - self.event_queue.push(EmbedderEvent::Idle); + if let (Some(servo), Some(webviews)) = (self.servo.as_ref(), self.webviews.as_mut()) { + window.handle_winit_event(servo, &mut self.clipboard, webviews, event); } - - window.queue_embedder_events_for_winit_event(event); } let animating = self.is_animating(); @@ -538,16 +576,8 @@ impl ApplicationHandler<WakerEvent> for App { event_loop.set_control_flow(ControlFlow::Poll); } - // Consume and handle any events from the Minibrowser. - if let Some(ref minibrowser) = self.minibrowser { - let webviews = &mut self.webviews.as_mut().unwrap(); - let app_event_queue = &mut self.event_queue; - minibrowser.queue_embedder_events_for_minibrowser_events( - webviews, - app_event_queue, - &self.servo_shell_preferences, - ); - } + // Consume and handle any events from the servoshell UI. + self.handle_servoshell_ui_events(); self.handle_events_with_winit(event_loop, window); } @@ -567,7 +597,6 @@ impl ApplicationHandler<WakerEvent> for App { if self.servo.is_none() { return; } - self.event_queue.push(EmbedderEvent::Idle); let Some(window) = self.windows.values().next() else { return; @@ -584,15 +613,7 @@ impl ApplicationHandler<WakerEvent> for App { } // Consume and handle any events from the Minibrowser. - if let Some(ref minibrowser) = self.minibrowser { - let webviews = &mut self.webviews.as_mut().unwrap(); - let app_event_queue = &mut self.event_queue; - minibrowser.queue_embedder_events_for_minibrowser_events( - webviews, - app_event_queue, - &self.servo_shell_preferences, - ); - } + self.handle_servoshell_ui_events(); self.handle_events_with_winit(event_loop, window); } |