Initial internal support for multiple webviews (#31417)

* Add multiple concurrent top-level browsing contexts

Co-authored-by: Delan Azabani <dazabani@igalia.com>

* Rename variables and comments

There are some variable and comments still use browser as names.
This commit renames them to webview.

* Update log message from web view to webview

* Revert offscreen_framebuffer_id rename

* Rename all web view to webview

* Cargo fmt

* Fix viewport/event/clear coordinates when multiview is disabled

* Only deprecate things when multiview is enabled

* Update WebViewManger with shown and invisible sets

Replace visible_webviews and native_window_is_visible with shown_webviews
and invisible_webviews. Add 4 more methods to set them accordingly. The
behavior of is_effectively_visible will return true if the wbview is in
shown_webviews set but not in invisible_webviews.

* Update variant behaviors

* Rename WebViewVisibilityChanged to MarkWebViewInvisible

* Fix unit test by marking id 3 visible again

* Update MarkWebViewInvisible and add UnmarkWebViewInvisible

* Update format and doc comments

* Clean up doc comments

* Address style and naming changes

* Rename UpdateWebView to UpdateFrameTreeForWebView

* constellation: send frame tree unconditionally over focus and feature

* Clarify shown and invisible sets in constellation WebViewManager

* Eliminate forward_to_constellation!()

* Actually remove the unused macro

* Don’t gate compositor changes on multiview feature flag

* Update todo in mouse event dispatch

* Pass all visible webview ids in a single ReadyToPresent message

* Fix compile and lint errors

* servoshell: fix gap between minibrowser toolbar and webview

* Fix failure in /_mozilla/mozilla/window_resizeTo.html

* Fix compile warnings

* Remove stray dbg!()

* Remove confusing “effectively visible” logic (see #31815, #31816)

* Allow embedder to show/hide/raise webviews without ipc

* Update root pipeline only when painting order actually changes

* Stop gating old focus and SetFrameTree behaviour behind Cargo feature

* Use webview_id and WebViewId in webview-related code

* Improve logging of webview-related embedder events

* Allow webview Show and Raise events to optionally hide all others

* Don’t do anything in response to WebViewPaintingOrder

* Remove WebViewPaintingOrder, since its payload is unreliable

* On MoveResizeWebView, only update root pipeline if rect changed

* Rename IOCompositor methods for clarity

* compositor: add event tracing; log webview ops even without ipc

* Add temporary debug logging

* Add more temporary debug logging

* Remove temporary logging in compositor

* Remove temporary debug logging

* Add temporary debug logging, but defer I/O until panic

* Capture a backtrace with each crash log entry

* Proper error handling without panicking in WebViewManager

* Clean up imports in constellation

---------

Co-authored-by: Delan Azabani <dazabani@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Ngo Iok Ui (Wu Yu Wei) 2024-04-03 20:06:28 +09:00 committed by GitHub
parent 18b37e676b
commit 66878fb834
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 1142 additions and 434 deletions

View file

@ -435,7 +435,7 @@ impl ServoGlue {
pub fn resize(&mut self, coordinates: Coordinates) -> Result<(), &'static str> {
info!("resize");
*self.callbacks.coordinates.borrow_mut() = coordinates;
self.process_event(EmbedderEvent::Resize)
self.process_event(EmbedderEvent::WindowResize)
}
/// Start scrolling.
@ -818,7 +818,7 @@ impl ServoGlue {
EmbedderMsg::Panic(reason, backtrace) => {
self.callbacks.host_callbacks.on_panic(reason, backtrace);
},
EmbedderMsg::ReadyToPresent => {
EmbedderMsg::ReadyToPresent(_webview_ids) => {
need_present = true;
},
EmbedderMsg::Status(..) |

View file

@ -124,17 +124,15 @@ impl App {
if let Some(mut minibrowser) = app.minibrowser() {
// Servo is not yet initialised, so there is no `servo_framebuffer_id`.
minibrowser.update(window.winit_window().unwrap(), None, "init");
minibrowser.update(
window.winit_window().unwrap(),
&mut app.webviews.borrow_mut(),
None,
"init",
);
window.set_toolbar_height(minibrowser.toolbar_height);
}
// Whether or not to recomposite during the next RedrawRequested event.
// Normally this is true, including for RedrawRequested events that come from the platform
// (e.g. X11 without picom or similar) when an offscreen or obscured window becomes visible.
// If we are calling request_redraw in response to the compositor having painted to this
// frame, set this to false, so we can avoid an unnecessary recomposite.
let mut need_recomposite = true;
let t_start = Instant::now();
let mut t = t_start;
let ev_waker = events_loop.create_event_loop_waker();
@ -208,22 +206,17 @@ impl App {
// WARNING: do not defer painting or presenting to some later tick of the event
// loop or servoshell may become unresponsive! (servo#30312)
if need_recomposite {
trace!("need_recomposite");
app.servo.as_mut().unwrap().recomposite();
}
if let Some(mut minibrowser) = app.minibrowser() {
minibrowser.update(
window.winit_window().unwrap(),
&mut app.webviews.borrow_mut(),
app.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"RedrawRequested",
);
minibrowser.paint(window.winit_window().unwrap());
}
app.servo.as_mut().unwrap().present();
// By default, the next RedrawRequested event will need to recomposite.
need_recomposite = true;
app.servo.as_mut().unwrap().present();
}
// Handle the event
@ -303,6 +296,7 @@ impl App {
// redraw, doing so would delay the location update by two frames.
minibrowser.update(
window.winit_window().unwrap(),
webviews,
app.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"update_location_in_toolbar",
);
@ -314,13 +308,13 @@ impl App {
// The window was resized.
trace!("PumpResult::Present::Immediate");
// Resizes are unusual in that we need to repaint synchronously.
// TODO(servo#30049) can we replace this with the simpler Servo::recomposite?
app.servo.as_mut().unwrap().repaint_synchronously();
// If we had resized any of the viewports in response to this, we would need to
// call Servo::repaint_synchronously. At the moment we dont, so there wont be
// any paint scheduled, and calling it would hang the compositor forever.
if let Some(mut minibrowser) = app.minibrowser() {
minibrowser.update(
window.winit_window().unwrap(),
&mut app.webviews.borrow_mut(),
app.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"PumpResult::Present::Immediate",
);
@ -339,10 +333,6 @@ impl App {
} else {
app.servo.as_mut().unwrap().present();
}
// We dont need the compositor to paint to this frame during the redraw event.
// TODO(servo#30331) broken on macOS?
// need_recomposite = false;
},
Present::None => {},
}

View file

@ -8,7 +8,6 @@ use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc;
use euclid::num::Zero;
use euclid::{Angle, Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector2D, Vector3D};
use log::{debug, info, trace};
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
@ -309,8 +308,11 @@ impl WindowPortsMethods for Window {
}
fn set_inner_size(&self, size: DeviceIntSize) {
let toolbar_height = self.toolbar_height() * self.hidpi_factor();
let toolbar_height = toolbar_height.get().ceil() as i32;
let total_size = PhysicalSize::new(size.width, size.height + toolbar_height);
self.winit_window
.set_inner_size::<PhysicalSize<i32>>(PhysicalSize::new(size.width, size.height))
.set_inner_size::<PhysicalSize<i32>>(total_size)
}
fn set_position(&self, point: DeviceIntPoint) {
@ -399,9 +401,7 @@ impl WindowPortsMethods for Window {
}
},
winit::event::WindowEvent::CursorMoved { position, .. } => {
let toolbar_height = self.toolbar_height.get() * self.hidpi_factor();
let mut position = winit_position_to_euclid_point(position).to_f32();
position -= Size2D::from_lengths(Length::zero(), toolbar_height);
let position = winit_position_to_euclid_point(position);
self.mouse_pos.set(position.to_i32());
self.event_queue
.borrow_mut()
@ -476,7 +476,9 @@ impl WindowPortsMethods for Window {
.resize(physical_size.to_i32())
.expect("Failed to resize");
self.inner_size.set(new_size);
self.event_queue.borrow_mut().push(EmbedderEvent::Resize);
self.event_queue
.borrow_mut()
.push(EmbedderEvent::WindowResize);
}
},
_ => {},
@ -510,6 +512,10 @@ impl WindowPortsMethods for Window {
Some(&self.winit_window)
}
fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel> {
self.toolbar_height.get()
}
fn set_toolbar_height(&self, height: Length<f32, DeviceIndependentPixel>) {
self.toolbar_height.set(height);
}
@ -520,13 +526,8 @@ impl WindowMethods for Window {
let window_size = winit_size_to_euclid_size(self.winit_window.outer_size()).to_i32();
let window_origin = self.winit_window.outer_position().unwrap_or_default();
let window_origin = winit_position_to_euclid_point(window_origin).to_i32();
let inner_size = winit_size_to_euclid_size(self.winit_window.inner_size()).to_f32();
// Subtract the minibrowser toolbar height if any
let toolbar_height = self.toolbar_height.get() * self.hidpi_factor();
let viewport_size = inner_size - Size2D::from_lengths(Length::zero(), toolbar_height);
let viewport_origin = DeviceIntPoint::zero(); // bottom left
let viewport_size = winit_size_to_euclid_size(self.winit_window.inner_size()).to_f32();
let viewport = DeviceIntRect::from_origin_and_size(viewport_origin, viewport_size.to_i32());
let screen = self.screen_size.to_i32();

View file

@ -8,6 +8,7 @@ use std::cell::Cell;
use std::rc::Rc;
use std::sync::RwLock;
use euclid::num::Zero;
use euclid::{Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D};
use log::warn;
use servo::compositing::windowing::{
@ -93,7 +94,7 @@ impl WindowPortsMethods for Window {
Ok(()) => {
self.inner_size.set(new_size);
if let Ok(ref mut queue) = self.event_queue.write() {
queue.push(EmbedderEvent::Resize);
queue.push(EmbedderEvent::WindowResize);
}
},
Err(error) => warn!("Could not resize window: {error:?}"),
@ -148,6 +149,10 @@ impl WindowPortsMethods for Window {
None
}
fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel> {
Length::zero()
}
fn set_toolbar_height(&self, _height: Length<f32, DeviceIndependentPixel>) {
unimplemented!("headless Window only")
}

View file

@ -7,10 +7,13 @@ use std::num::NonZeroU32;
use std::sync::Arc;
use std::time::Instant;
use egui::{CentralPanel, Color32, Frame, Key, Modifiers, PaintCallback, Spinner, TopBottomPanel};
use egui::{
CentralPanel, Color32, Frame, Key, Modifiers, PaintCallback, Pos2, Spinner, TopBottomPanel,
Vec2,
};
use egui_glow::CallbackFn;
use egui_winit::EventResponse;
use euclid::{Length, Point2D, Scale};
use euclid::{Box2D, Length, Point2D, Scale, Size2D};
use gleam::gl;
use glow::NativeFramebuffer;
use log::{trace, warn};
@ -19,6 +22,7 @@ use servo::msg::constellation_msg::TraversalDirection;
use servo::rendering_context::RenderingContext;
use servo::servo_geometry::DeviceIndependentPixel;
use servo::servo_url::ServoUrl;
use servo::style_traits::DevicePixel;
use crate::egui_glue::EguiGlow;
use crate::events_loop::EventsLoop;
@ -124,6 +128,7 @@ impl Minibrowser {
pub fn update(
&mut self,
window: &winit::window::Window,
webviews: &mut WebViewManager<dyn WindowPortsMethods>,
servo_framebuffer_id: Option<gl::GLuint>,
reason: &'static str,
) {
@ -203,9 +208,32 @@ impl Minibrowser {
// point, but the Context is correct and the TopBottomPanel is wrong.
*toolbar_height = Length::new(ctx.available_rect().min.y);
let scale =
Scale::<_, DeviceIndependentPixel, DevicePixel>::new(ctx.pixels_per_point());
let Some(focused_webview_id) = webviews.focused_webview_id() else {
return;
};
let Some(webview) = webviews.get_mut(focused_webview_id) else {
return;
};
let mut embedder_events = vec![];
CentralPanel::default()
.frame(Frame::none())
.show(ctx, |ui| {
let Pos2 { x, y } = ui.cursor().min;
let Vec2 {
x: width,
y: height,
} = ui.available_size();
let rect = Box2D::from_origin_and_size(
Point2D::new(x, y),
Size2D::new(width, height),
) * scale;
if rect != webview.rect {
webview.rect = rect;
embedder_events
.push(EmbedderEvent::MoveResizeWebView(focused_webview_id, rect));
}
let min = ui.cursor().min;
let size = ui.available_size();
let rect = egui::Rect::from_min_size(min, size);
@ -255,6 +283,10 @@ impl Minibrowser {
});
});
if !embedder_events.is_empty() {
webviews.handle_window_events(embedder_events);
}
*last_update = now;
});
}

View file

@ -81,7 +81,7 @@ mod from_winit {
Self::Suspended => target!("Suspended"),
Self::Resumed => target!("Resumed"),
Self::MainEventsCleared => target!("MainEventsCleared"),
Self::RedrawRequested(_) => target!("RedrawRequested"),
Self::RedrawRequested(..) => target!("RedrawRequested"),
Self::RedrawEventsCleared => target!("RedrawEventsCleared"),
Self::LoopDestroyed => target!("LoopDestroyed"),
}
@ -96,18 +96,18 @@ mod from_winit {
};
}
match self {
Self::Resized(_) => target_variant!("Resized"),
Self::Moved(_) => target_variant!("Moved"),
Self::Resized(..) => target_variant!("Resized"),
Self::Moved(..) => target_variant!("Moved"),
Self::CloseRequested => target_variant!("CloseRequested"),
Self::Destroyed => target_variant!("Destroyed"),
Self::DroppedFile(_) => target_variant!("DroppedFile"),
Self::HoveredFile(_) => target_variant!("HoveredFile"),
Self::DroppedFile(..) => target_variant!("DroppedFile"),
Self::HoveredFile(..) => target_variant!("HoveredFile"),
Self::HoveredFileCancelled => target_variant!("HoveredFileCancelled"),
Self::ReceivedCharacter(_) => target_variant!("ReceivedCharacter"),
Self::Focused(_) => target_variant!("Focused"),
Self::ReceivedCharacter(..) => target_variant!("ReceivedCharacter"),
Self::Focused(..) => target_variant!("Focused"),
Self::KeyboardInput { .. } => target_variant!("KeyboardInput"),
Self::ModifiersChanged(_) => target_variant!("ModifiersChanged"),
Self::Ime(_) => target_variant!("Ime"),
Self::ModifiersChanged(..) => target_variant!("ModifiersChanged"),
Self::Ime(..) => target_variant!("Ime"),
Self::CursorMoved { .. } => target_variant!("CursorMoved"),
Self::CursorEntered { .. } => target_variant!("CursorEntered"),
Self::CursorLeft { .. } => target_variant!("CursorLeft"),
@ -118,10 +118,10 @@ mod from_winit {
Self::TouchpadRotate { .. } => target_variant!("TouchpadRotate"),
Self::TouchpadPressure { .. } => target_variant!("TouchpadPressure"),
Self::AxisMotion { .. } => target_variant!("AxisMotion"),
Self::Touch(_) => target_variant!("Touch"),
Self::Touch(..) => target_variant!("Touch"),
Self::ScaleFactorChanged { .. } => target_variant!("ScaleFactorChanged"),
Self::ThemeChanged(_) => target_variant!("ThemeChanged"),
Self::Occluded(_) => target_variant!("Occluded"),
Self::ThemeChanged(..) => target_variant!("ThemeChanged"),
Self::Occluded(..) => target_variant!("Occluded"),
}
}
}
@ -139,41 +139,41 @@ mod from_servo {
impl LogTarget for servo::embedder_traits::EmbedderMsg {
fn log_target(&self) -> &'static str {
match self {
Self::Status(_) => target!("Status"),
Self::ChangePageTitle(_) => target!("ChangePageTitle"),
Self::MoveTo(_) => target!("MoveTo"),
Self::ResizeTo(_) => target!("ResizeTo"),
Self::Prompt(_, _) => target!("Prompt"),
Self::ShowContextMenu(_, _, _) => target!("ShowContextMenu"),
Self::AllowNavigationRequest(_, _) => target!("AllowNavigationRequest"),
Self::AllowOpeningWebView(_) => target!("AllowOpeningWebView"),
Self::WebViewOpened(_) => target!("WebViewOpened"),
Self::WebViewClosed(_) => target!("WebViewClosed"),
Self::WebViewFocused(_) => target!("WebViewFocused"),
Self::Status(..) => target!("Status"),
Self::ChangePageTitle(..) => target!("ChangePageTitle"),
Self::MoveTo(..) => target!("MoveTo"),
Self::ResizeTo(..) => target!("ResizeTo"),
Self::Prompt(..) => target!("Prompt"),
Self::ShowContextMenu(..) => target!("ShowContextMenu"),
Self::AllowNavigationRequest(..) => target!("AllowNavigationRequest"),
Self::AllowOpeningWebView(..) => target!("AllowOpeningWebView"),
Self::WebViewOpened(..) => target!("WebViewOpened"),
Self::WebViewClosed(..) => target!("WebViewClosed"),
Self::WebViewFocused(..) => target!("WebViewFocused"),
Self::WebViewBlurred => target!("WebViewBlurred"),
Self::AllowUnload(_) => target!("AllowUnload"),
Self::Keyboard(_) => target!("Keyboard"),
Self::GetClipboardContents(_) => target!("GetClipboardContents"),
Self::SetClipboardContents(_) => target!("SetClipboardContents"),
Self::SetCursor(_) => target!("SetCursor"),
Self::NewFavicon(_) => target!("NewFavicon"),
Self::AllowUnload(..) => target!("AllowUnload"),
Self::Keyboard(..) => target!("Keyboard"),
Self::GetClipboardContents(..) => target!("GetClipboardContents"),
Self::SetClipboardContents(..) => target!("SetClipboardContents"),
Self::SetCursor(..) => target!("SetCursor"),
Self::NewFavicon(..) => target!("NewFavicon"),
Self::HeadParsed => target!("HeadParsed"),
Self::HistoryChanged(_, _) => target!("HistoryChanged"),
Self::SetFullscreenState(_) => target!("SetFullscreenState"),
Self::HistoryChanged(..) => target!("HistoryChanged"),
Self::SetFullscreenState(..) => target!("SetFullscreenState"),
Self::LoadStart => target!("LoadStart"),
Self::LoadComplete => target!("LoadComplete"),
Self::Panic(_, _) => target!("Panic"),
Self::GetSelectedBluetoothDevice(_, _) => target!("GetSelectedBluetoothDevice"),
Self::SelectFiles(_, _, _) => target!("SelectFiles"),
Self::PromptPermission(_, _) => target!("PromptPermission"),
Self::ShowIME(_, _, _, _) => target!("ShowIME"),
Self::Panic(..) => target!("Panic"),
Self::GetSelectedBluetoothDevice(..) => target!("GetSelectedBluetoothDevice"),
Self::SelectFiles(..) => target!("SelectFiles"),
Self::PromptPermission(..) => target!("PromptPermission"),
Self::ShowIME(..) => target!("ShowIME"),
Self::HideIME => target!("HideIME"),
Self::Shutdown => target!("Shutdown"),
Self::ReportProfile(_) => target!("ReportProfile"),
Self::MediaSessionEvent(_) => target!("MediaSessionEvent"),
Self::OnDevtoolsStarted(_, _) => target!("OnDevtoolsStarted"),
Self::ReadyToPresent => target!("ReadyToPresent"),
Self::EventDelivered(_) => target!("EventDelivered"),
Self::ReportProfile(..) => target!("ReportProfile"),
Self::MediaSessionEvent(..) => target!("MediaSessionEvent"),
Self::OnDevtoolsStarted(..) => target!("OnDevtoolsStarted"),
Self::ReadyToPresent(..) => target!("ReadyToPresent"),
Self::EventDelivered(..) => target!("EventDelivered"),
}
}
}
@ -193,36 +193,41 @@ mod to_servo {
match self {
Self::Idle => target!("Idle"),
Self::Refresh => target!("Refresh"),
Self::Resize => target!("Resize"),
Self::AllowNavigationResponse(_, _) => target!("AllowNavigationResponse"),
Self::LoadUrl(_, _) => target!("LoadUrl"),
Self::MouseWindowEventClass(_) => target!("MouseWindowEventClass"),
Self::MouseWindowMoveEventClass(_) => target!("MouseWindowMoveEventClass"),
Self::Touch(_, _, _) => target!("Touch"),
Self::Wheel(_, _) => target!("Wheel"),
Self::Scroll(_, _, _) => target!("Scroll"),
Self::Zoom(_) => target!("Zoom"),
Self::PinchZoom(_) => target!("PinchZoom"),
Self::WindowResize => target!("WindowResize"),
Self::AllowNavigationResponse(..) => target!("AllowNavigationResponse"),
Self::LoadUrl(..) => target!("LoadUrl"),
Self::MouseWindowEventClass(..) => target!("MouseWindowEventClass"),
Self::MouseWindowMoveEventClass(..) => target!("MouseWindowMoveEventClass"),
Self::Touch(..) => target!("Touch"),
Self::Wheel(..) => target!("Wheel"),
Self::Scroll(..) => target!("Scroll"),
Self::Zoom(..) => target!("Zoom"),
Self::PinchZoom(..) => target!("PinchZoom"),
Self::ResetZoom => target!("ResetZoom"),
Self::Navigation(_, _) => target!("Navigation"),
Self::Navigation(..) => target!("Navigation"),
Self::Quit => target!("Quit"),
Self::ExitFullScreen(_) => target!("ExitFullScreen"),
Self::Keyboard(_) => target!("Keyboard"),
Self::Reload(_) => target!("Reload"),
Self::NewWebView(_, _) => target!("NewWebView"),
Self::CloseWebView(_) => target!("CloseWebView"),
Self::SendError(_, _) => target!("SendError"),
Self::FocusWebView(_) => target!("FocusWebView"),
Self::ToggleWebRenderDebug(_) => target!("ToggleWebRenderDebug"),
Self::ExitFullScreen(..) => target!("ExitFullScreen"),
Self::Keyboard(..) => target!("Keyboard"),
Self::Reload(..) => target!("Reload"),
Self::NewWebView(..) => target!("NewWebView"),
Self::CloseWebView(..) => target!("CloseWebView"),
Self::SendError(..) => target!("SendError"),
Self::MoveResizeWebView(..) => target!("MoveResizeWebView"),
Self::ShowWebView(..) => target!("ShowWebView"),
Self::HideWebView(..) => target!("HideWebView"),
Self::RaiseWebViewToTop(..) => target!("RaiseWebViewToTop"),
Self::FocusWebView(..) => target!("FocusWebView"),
Self::BlurWebView => target!("BlurWebView"),
Self::ToggleWebRenderDebug(..) => target!("ToggleWebRenderDebug"),
Self::CaptureWebRender => target!("CaptureWebRender"),
Self::ClearCache => target!("ClearCache"),
Self::ToggleSamplingProfiler(_, _) => target!("ToggleSamplingProfiler"),
Self::MediaSessionAction(_) => target!("MediaSessionAction"),
Self::SetWebViewThrottled(_, _) => target!("SetWebViewThrottled"),
Self::ToggleSamplingProfiler(..) => target!("ToggleSamplingProfiler"),
Self::MediaSessionAction(..) => target!("MediaSessionAction"),
Self::SetWebViewThrottled(..) => target!("SetWebViewThrottled"),
Self::IMEDismissed => target!("IMEDismissed"),
Self::InvalidateNativeSurface => target!("InvalidateNativeSurface"),
Self::ReplaceNativeSurface(_, _) => target!("ReplaceNativeSurface"),
Self::Gamepad(_) => target!("Gamepad"),
Self::ReplaceNativeSurface(..) => target!("ReplaceNativeSurface"),
Self::Gamepad(..) => target!("Gamepad"),
}
}
}

View file

@ -26,6 +26,7 @@ use servo::script_traits::{
};
use servo::servo_config::opts;
use servo::servo_url::ServoUrl;
use servo::webrender_api::units::DeviceRect;
use servo::webrender_api::ScrollLocation;
use tinyfiledialogs::{self, MessageBoxIcon, OkCancel, YesNo};
@ -60,7 +61,9 @@ pub struct WebViewManager<Window: WindowPortsMethods + ?Sized> {
}
#[derive(Debug)]
pub struct WebView {}
pub struct WebView {
pub rect: DeviceRect,
}
pub struct ServoEventResponse {
pub need_present: bool,
@ -111,6 +114,14 @@ where
self.focused_webview_id
}
pub fn get_mut(&mut self, webview_id: WebViewId) -> Option<&mut WebView> {
self.webviews.get_mut(&webview_id)
}
pub fn focused_webview_id(&self) -> Option<WebViewId> {
self.focused_webview_id.clone()
}
pub fn current_url_string(&self) -> Option<&str> {
self.current_url_string.as_deref()
}
@ -453,6 +464,20 @@ where
self.window.set_position(point);
},
EmbedderMsg::ResizeTo(size) => {
if let Some(webview_id) = webview_id {
let new_rect = self.get_mut(webview_id).and_then(|webview| {
if webview.rect.size() != size.to_f32() {
webview.rect.set_size(size.to_f32());
Some(webview.rect)
} else {
None
}
});
if let Some(new_rect) = new_rect {
self.event_queue
.push(EmbedderEvent::MoveResizeWebView(webview_id, new_rect));
}
}
self.window.set_inner_size(size);
},
EmbedderMsg::Prompt(definition, origin) => {
@ -555,10 +580,22 @@ where
};
},
EmbedderMsg::WebViewOpened(new_webview_id) => {
self.webviews.insert(new_webview_id, WebView {});
let scale = self.window.hidpi_factor().get();
let toolbar = self.window.toolbar_height().get();
// Adjust for our toolbar height.
// TODO: Adjust for egui window decorations if we end up using those
let mut rect = self.window.get_coordinates().get_viewport().to_f32();
rect.min.y += toolbar * scale;
self.webviews.insert(new_webview_id, WebView { rect });
self.creation_order.push(new_webview_id);
self.event_queue
.push(EmbedderEvent::FocusWebView(new_webview_id));
self.event_queue
.push(EmbedderEvent::MoveResizeWebView(new_webview_id, rect));
self.event_queue
.push(EmbedderEvent::RaiseWebViewToTop(new_webview_id, true));
},
EmbedderMsg::WebViewClosed(webview_id) => {
self.webviews.retain(|&id, _| id != webview_id);
@ -573,6 +610,10 @@ where
},
EmbedderMsg::WebViewFocused(webview_id) => {
self.focused_webview_id = Some(webview_id);
// Show the most recently created webview and hide all others.
// TODO: Stop doing this once we have full multiple webviews support
self.event_queue
.push(EmbedderEvent::ShowWebView(webview_id, true));
},
EmbedderMsg::WebViewBlurred => {
self.focused_webview_id = None;
@ -681,15 +722,18 @@ where
EmbedderMsg::ShowContextMenu(sender, ..) => {
let _ = sender.send(ContextMenuResult::Ignored);
},
EmbedderMsg::ReadyToPresent => {
EmbedderMsg::ReadyToPresent(_webview_ids) => {
need_present = true;
},
EmbedderMsg::EventDelivered(event) => {
if let (Some(webview_id), CompositorEventVariant::MouseButtonEvent) =
(webview_id, event)
{
// TODO Focus webview and/or raise to top if needed.
trace!("{}: Got a mouse button event", webview_id);
self.event_queue
.push(EmbedderEvent::RaiseWebViewToTop(webview_id, true));
self.event_queue
.push(EmbedderEvent::FocusWebView(webview_id));
}
},
}

View file

@ -47,5 +47,6 @@ pub trait WindowPortsMethods: WindowMethods {
events_loop: &winit::event_loop::EventLoopWindowTarget<WakerEvent>,
) -> Box<dyn webxr::glwindow::GlWindow>;
fn winit_window(&self) -> Option<&winit::window::Window>;
fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel>;
fn set_toolbar_height(&self, height: Length<f32, DeviceIndependentPixel>);
}