diff --git a/examples/servo/Cargo.lock b/examples/servo/Cargo.lock index 970390eb39..702a0b32d7 100644 --- a/examples/servo/Cargo.lock +++ b/examples/servo/Cargo.lock @@ -8242,6 +8242,7 @@ dependencies = [ "i-slint-backend-qt", "i-slint-backend-selector", "i-slint-backend-winit", + "i-slint-common", "i-slint-core", "i-slint-core-macros", "i-slint-renderer-femtovg", diff --git a/examples/servo/src/adapter.rs b/examples/servo/src/adapter.rs index 7af7a1a8f7..46d8d5c9d6 100644 --- a/examples/servo/src/adapter.rs +++ b/examples/servo/src/adapter.rs @@ -23,7 +23,6 @@ pub fn upgrade_adapter(weak_ref: &Weak) -> Rc, /// Channel sender to wake the event loop waker_sender: Sender<()>, /// Channel receiver for event loop wake signals @@ -33,7 +32,6 @@ pub struct SlintServoAdapter { } pub struct SlintServoAdapterInner { - scale_factor: f32, webview: Option, rendering_adapter: Option>>, #[cfg(not(target_os = "android"))] @@ -44,20 +42,17 @@ pub struct SlintServoAdapterInner { impl SlintServoAdapter { pub fn new( - app: slint::Weak, waker_sender: Sender<()>, waker_receiver: Receiver<()>, #[cfg(not(target_os = "android"))] device: wgpu::Device, #[cfg(not(target_os = "android"))] queue: wgpu::Queue, ) -> Self { Self { - app, waker_sender, waker_receiver, servo: RefCell::new(None), inner: RefCell::new(SlintServoAdapterInner { webview: None, - scale_factor: 1.0, rendering_adapter: None, #[cfg(not(target_os = "android"))] device: device, @@ -75,10 +70,6 @@ impl SlintServoAdapter { self.inner.borrow_mut() } - pub fn app(&self) -> MyApp { - self.app.upgrade().expect("Failed to upgrade MyApp") - } - pub fn waker_sender(&self) -> Sender<()> { self.waker_sender.clone() } @@ -87,10 +78,6 @@ impl SlintServoAdapter { self.waker_receiver.clone() } - pub fn scale_factor(&self) -> f32 { - self.inner().scale_factor - } - #[cfg(not(target_os = "android"))] pub fn wgpu_device(&self) -> wgpu::Device { self.inner().device.clone() @@ -109,30 +96,23 @@ impl SlintServoAdapter { &self, servo: Servo, webview: WebView, - scale_factor: f32, rendering_adapter: Rc>, ) { *self.servo.borrow_mut() = Some(servo); let mut inner = self.inner_mut(); inner.webview = Some(webview); - inner.scale_factor = scale_factor; inner.rendering_adapter = Some(rendering_adapter); } /// Captures the current Servo framebuffer and updates the Slint UI with the rendered content. /// This bridges the rendering output from Servo to the Slint display surface. - pub fn update_web_content_with_latest_frame(&self) { + pub fn update_web_content_with_latest_frame(&self, app: &MyApp) { let inner = self.inner(); let rendering_adapter = inner.rendering_adapter.as_ref().unwrap(); // Convert framebuffer to Slint image format let slint_image = rendering_adapter.current_framebuffer_as_image(); - let app = self - .app - .upgrade() - .expect("Application reference is no longer valid - UI may have been destroyed"); - app.global::().set_web_content(slint_image); app.window().request_redraw(); } diff --git a/examples/servo/src/delegate.rs b/examples/servo/src/delegate.rs index d0b96b8def..465a252230 100644 --- a/examples/servo/src/delegate.rs +++ b/examples/servo/src/delegate.rs @@ -5,15 +5,16 @@ use std::rc::Rc; use servo::{WebView, WebViewDelegate}; -use crate::adapter::SlintServoAdapter; +use crate::{MyApp, adapter::SlintServoAdapter}; pub struct AppDelegate { pub state: Rc, + pub app: slint::Weak, } impl AppDelegate { - pub fn new(state: Rc) -> Self { - Self { state } + pub fn new(state: Rc, app: slint::Weak) -> Self { + Self { state, app } } } @@ -22,6 +23,8 @@ impl WebViewDelegate for AppDelegate { /// Triggers painting and updates the Slint UI with the new frame. fn notify_new_frame_ready(&self, webview: WebView) { webview.paint(); - self.state.update_web_content_with_latest_frame(); + if let Some(app) = self.app.upgrade() { + self.state.update_web_content_with_latest_frame(&app); + } } } diff --git a/examples/servo/src/lib.rs b/examples/servo/src/lib.rs index 091d9c197b..4265586719 100644 --- a/examples/servo/src/lib.rs +++ b/examples/servo/src/lib.rs @@ -62,10 +62,14 @@ pub fn main() { let url = "https://slint.dev"; #[cfg(not(target_os = "android"))] - let _adapter = init_servo(app.clone_strong(), url.into(), device, queue); - - #[cfg(target_os = "android")] - let _adapter = init_servo(app.clone_strong(), url.into()); + let _adapter = init_servo( + app.clone_strong(), + url.into(), + #[cfg(not(target_os = "android"))] + device, + #[cfg(not(target_os = "android"))] + queue, + ); app.run().expect("Application failed to run - check for runtime errors"); } diff --git a/examples/servo/src/on_events.rs b/examples/servo/src/on_events.rs index ecd1689f43..b12f92f492 100644 --- a/examples/servo/src/on_events.rs +++ b/examples/servo/src/on_events.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use url::Url; use winit::dpi::PhysicalSize; -use euclid::{Box2D, Point2D, Size2D}; +use euclid::{Box2D, Point2D, Scale, Size2D}; use i_slint_core::items::{ColorScheme, PointerEvent, PointerEventKind}; use slint::{ComponentHandle, platform::PointerEventButton}; @@ -18,24 +18,21 @@ use servo::{ }; use crate::{ - WebviewLogic, + MyApp, WebviewLogic, adapter::{SlintServoAdapter, upgrade_adapter}, }; -pub fn on_app_callbacks(adapter: Rc) { - on_url(adapter.clone()); - on_theme(adapter.clone()); - on_resize(adapter.clone()); - on_scroll(adapter.clone()); - on_buttons(adapter.clone()); - on_pointer(adapter.clone()); +pub fn on_app_callbacks(app: &MyApp, adapter: Rc) { + on_url(app, adapter.clone()); + on_theme(app, adapter.clone()); + on_resize(app, adapter.clone()); + on_scroll(app, adapter.clone()); + on_buttons(app, adapter.clone()); + on_pointer(app, adapter.clone()); } -fn on_url(adapter: Rc) { - let app = adapter.app(); - +fn on_url(app: &MyApp, adapter: Rc) { let adapter_weak = Rc::downgrade(&adapter); - app.global::().on_loadUrl(move |url| { let adapter = upgrade_adapter(&adapter_weak); let webview = adapter.webview(); @@ -44,11 +41,8 @@ fn on_url(adapter: Rc) { }); } -fn on_theme(adapter: Rc) { - let app = adapter.app(); - +fn on_theme(app: &MyApp, adapter: Rc) { let adapter_weak = Rc::downgrade(&adapter); - app.global::().on_theme(move |color_scheme| { let theme = if color_scheme == ColorScheme::Dark { Theme::Dark } else { Theme::Light }; @@ -56,24 +50,29 @@ fn on_theme(adapter: Rc) { let webview = adapter.webview(); - // Theme not updating its the issue with servo itself until mouse move over it + // Theme not updating until mouse move over it // https://github.com/servo/servo/issues/40268 webview.notify_theme_change(theme); }); } -fn on_resize(adapter: Rc) { - let app = adapter.app(); - +// This will always called when slint window show first time and when resize so set scale factor here +fn on_resize(app: &MyApp, adapter: Rc) { let adapter_weak = Rc::downgrade(&adapter); + let app_weak = app.as_weak(); app.global::().on_resize(move |width, height| { let adapter = upgrade_adapter(&adapter_weak); let webview = adapter.webview(); - let scale_factor = adapter.scale_factor(); + let scale_factor = + app_weak.upgrade().expect("Failed to upgrade app").window().scale_factor(); - let size = Size2D::new(width, height) * scale_factor; + let scale = Scale::new(scale_factor); + + webview.set_hidpi_scale_factor(scale); + + let size = Size2D::new(width, height); let physical_size = PhysicalSize::new(size.width as u32, size.height as u32); @@ -84,18 +83,14 @@ fn on_resize(adapter: Rc) { }); } -fn on_scroll(adapter: Rc) { - let app = adapter.app(); - +fn on_scroll(app: &MyApp, adapter: Rc) { let adapter_weak = Rc::downgrade(&adapter); app.global::().on_scroll(move |initial_x, initial_y, delta_x, delta_y| { let adapter = upgrade_adapter(&adapter_weak); let webview = adapter.webview(); - let scale_factor = adapter.scale_factor(); - - let point = DevicePoint::new(initial_x * scale_factor, initial_y * scale_factor); + let point = DevicePoint::new(initial_x, initial_y); let moved_by = DeviceVector2D::new(delta_x, delta_y); @@ -106,9 +101,7 @@ fn on_scroll(adapter: Rc) { }); } -fn on_buttons(adapter: Rc) { - let app = adapter.app(); - +fn on_buttons(app: &MyApp, adapter: Rc) { let adapter_weak = Rc::downgrade(&adapter); app.on_back(move || { let adapter = upgrade_adapter(&adapter_weak); @@ -137,18 +130,14 @@ fn on_buttons(adapter: Rc) { }); } -fn on_pointer(adapter: Rc) { - let app = adapter.app(); - +fn on_pointer(app: &MyApp, adapter: Rc) { let adapter_weak = Rc::downgrade(&adapter); app.global::().on_pointer(move |pointer_event, x, y| { let adapter = upgrade_adapter(&adapter_weak); let webview = adapter.webview(); - let scale_factor = adapter.scale_factor(); - - let point = DevicePoint::new(x * scale_factor, y * scale_factor); + let point = DevicePoint::new(x, y); let input_event = convert_slint_pointer_event_to_servo_input_event(&pointer_event, point.into()); @@ -166,7 +155,7 @@ fn convert_slint_pointer_event_to_servo_input_event( if pointer_event.is_touch { handle_touch_events(pointer_event, point) } else { - _handle_mouse_events(pointer_event, point) + handle_mouse_events(pointer_event, point) } } @@ -180,8 +169,8 @@ fn handle_touch_events(pointer_event: &PointerEvent, point: WebViewPoint) -> Inp InputEvent::Touch(touch_event) } -fn _handle_mouse_events(pointer_event: &PointerEvent, point: WebViewPoint) -> InputEvent { - let button = _get_mouse_button(pointer_event); +fn handle_mouse_events(pointer_event: &PointerEvent, point: WebViewPoint) -> InputEvent { + let button = get_mouse_button(pointer_event); match pointer_event.kind { PointerEventKind::Down => { let mouse_event = MouseButtonEvent::new(MouseButtonAction::Down, button, point); @@ -195,7 +184,7 @@ fn _handle_mouse_events(pointer_event: &PointerEvent, point: WebViewPoint) -> In } } -fn _get_mouse_button(point_event: &PointerEvent) -> MouseButton { +fn get_mouse_button(point_event: &PointerEvent) -> MouseButton { match point_event.button { PointerEventButton::Left => MouseButton::Left, PointerEventButton::Right => MouseButton::Right, diff --git a/examples/servo/src/servo_util.rs b/examples/servo/src/servo_util.rs index 0d174ace73..8ae14ec63d 100644 --- a/examples/servo/src/servo_util.rs +++ b/examples/servo/src/servo_util.rs @@ -7,7 +7,7 @@ use smol::channel; use url::Url; use winit::dpi::PhysicalSize; -use euclid::{Scale, Size2D}; +use euclid::Size2D; use i_slint_core::items::ColorScheme; use slint::{ComponentHandle, SharedString}; @@ -29,78 +29,58 @@ pub fn init_servo( #[cfg(not(target_os = "android"))] device: slint::wgpu_27::wgpu::Device, #[cfg(not(target_os = "android"))] queue: slint::wgpu_27::wgpu::Queue, ) -> Rc { - let app_weak = app.as_weak(); let (waker_sender, waker_receiver) = channel::unbounded::<()>(); - #[cfg(not(target_os = "android"))] let adapter = Rc::new(SlintServoAdapter::new( - app_weak, waker_sender.clone(), waker_receiver.clone(), + #[cfg(not(target_os = "android"))] device, + #[cfg(not(target_os = "android"))] queue, )); - #[cfg(target_os = "android")] - let adapter = Rc::new(SlintServoAdapter::new( - app_weak, - waker_sender.clone(), - waker_receiver.clone(), - )); - let state_weak = Rc::downgrade(&adapter); - slint::spawn_local({ - async move { + let state = upgrade_adapter(&state_weak); - let state = upgrade_adapter(&state_weak); + let (rendering_adapter, physical_size) = init_rendering_adpater(&app, state.clone()); - let (rendering_adapter, physical_size, scale_factor) = - init_rendering_adpater(state.clone()); + let servo = init_servo_builder(state.clone(), rendering_adapter.clone()); - let servo = init_servo_builder(state.clone(), rendering_adapter.clone()); - - init_webview(scale_factor, physical_size, initial_url, state, servo, rendering_adapter); - } - }) - .unwrap(); + init_webview(&app, physical_size, initial_url, state, servo, rendering_adapter); spin_servo_event_loop(adapter.clone()); - on_app_callbacks(adapter.clone()); + on_app_callbacks(&app, adapter.clone()); adapter - } fn init_rendering_adpater( - state: Rc, -) -> (Rc>, PhysicalSize, f32) { - let app = state.app(); - - let scale_factor = app.window().scale_factor() as f32; - + app: &MyApp, + adapter: Rc, +) -> (Rc>, PhysicalSize) { let width = app.global::().get_viewport_width(); let height = app.global::().get_viewport_height(); - let size: Size2D = Size2D::new(width, height) * scale_factor; - + let size: Size2D = Size2D::new(width, height); let physical_size = PhysicalSize::new(size.width as u32, size.height as u32); #[cfg(not(target_os = "android"))] - let rendering_adapter = { - let wgpu_device = state.wgpu_device(); - let wgpu_queue = state.wgpu_queue(); - crate::rendering_context::try_create_gpu_context(wgpu_device, wgpu_queue, physical_size) - .unwrap() - }; + let rendering_adapter = crate::rendering_context::try_create_gpu_context( + adapter.wgpu_device(), + adapter.wgpu_queue(), + physical_size, + ) + .unwrap(); #[cfg(target_os = "android")] let rendering_adapter = crate::rendering_context::create_software_context(physical_size); let rendering_adapter_rc = Rc::new(rendering_adapter); - (rendering_adapter_rc, physical_size, scale_factor) + (rendering_adapter_rc, physical_size) } fn init_servo_builder( @@ -117,29 +97,21 @@ fn init_servo_builder( } fn init_webview( - scale_factor: f32, + app: &MyApp, physical_size: PhysicalSize, initial_url: SharedString, adapter: Rc, servo: Servo, rendering_adapter: Rc>, ) { - let scale = Scale::new(scale_factor); - - let app = adapter.app(); - app.global::().set_current_url(initial_url.clone()); let url = Url::parse(&initial_url).expect("Failed to parse url"); - let delegate = Rc::new(AppDelegate::new(adapter.clone())); + let delegate = Rc::new(AppDelegate::new(adapter.clone(), app.as_weak())); - let webview = WebViewBuilder::new(&servo) - .url(url) - .size(physical_size) - .delegate(delegate) - .hidpi_scale_factor(scale) - .build(); + let webview = + WebViewBuilder::new(&servo).url(url).size(physical_size).delegate(delegate).build(); webview.show(true); @@ -149,7 +121,7 @@ fn init_webview( webview.notify_theme_change(theme); - adapter.set_inner(servo, webview, scale_factor, rendering_adapter); + adapter.set_inner(servo, webview, rendering_adapter); } fn spin_servo_event_loop(state: Rc) { diff --git a/examples/servo/ui/webview.slint b/examples/servo/ui/webview.slint index 43db43de01..8ac7ae6f84 100644 --- a/examples/servo/ui/webview.slint +++ b/examples/servo/ui/webview.slint @@ -7,9 +7,9 @@ export global WebviewLogic { callback loadUrl(url: string); callback theme(scheme: ColorScheme); - callback resize(width: length, height: length); - callback pointer(event: PointerEvent, x: length, y: length); - callback scroll(initital_x: length, initital_y: length, delta_x: length, delta_y: length); + callback resize(width: physical-length, height: physical-length); + callback pointer(event: PointerEvent, x: physical-length, y: physical-length); + callback scroll(initital_x: physical-length, initital_y: physical-length, delta_x: length, delta_y: length); in property web_content; in-out property current_url;