From 20505857a1cba905ac8871b09d00beeff5ada0a2 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Tue, 14 Nov 2023 02:20:16 +0200 Subject: [PATCH 1/5] refactor: combine position and size into bounds --- examples/multiwebview.rs | 66 ++++++++++++++++++++++++++++---------- examples/wgpu.rs | 10 ++++-- examples/winit.rs | 7 ++++- src/android/mod.rs | 8 ++--- src/lib.rs | 60 ++++++++++++++++++----------------- src/webkitgtk/mod.rs | 33 ++++++++++++------- src/webview2/mod.rs | 49 +++++++++++------------------ src/wkwebview/mod.rs | 68 +++++++++++++++++----------------------- 8 files changed, 164 insertions(+), 137 deletions(-) diff --git a/examples/multiwebview.rs b/examples/multiwebview.rs index 4c7ed6957..97f754858 100644 --- a/examples/multiwebview.rs +++ b/examples/multiwebview.rs @@ -8,7 +8,7 @@ use winit::{ event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, }; -use wry::WebViewBuilder; +use wry::{Rect, WebViewBuilder}; fn main() -> wry::Result<()> { #[cfg(any( @@ -43,23 +43,39 @@ fn main() -> wry::Result<()> { let size = window.inner_size().to_logical::(window.scale_factor()); let webview = WebViewBuilder::new_as_child(&window) - .with_position((0, 0)) - .with_size((size.width / 2, size.height / 2)) + .with_bounds(Rect { + x: 0, + y: 0, + width: size.width / 2, + height: size.height / 2, + }) .with_url("https://tauri.app")? .build()?; let webview2 = WebViewBuilder::new_as_child(&window) - .with_position(((size.width / 2) as i32, 0)) - .with_size((size.width / 2, size.height / 2)) + .with_bounds(Rect { + x: (size.width / 2) as i32, + y: 0, + width: size.width / 2, + height: size.height / 2, + }) .with_url("https://github.com/tauri-apps/wry")? .build()?; let webview3 = WebViewBuilder::new_as_child(&window) - .with_position((0, (size.height / 2) as i32)) - .with_size((size.width / 2, size.height / 2)) + .with_bounds(Rect { + x: 0, + y: (size.height / 2) as i32, + width: size.width / 2, + height: size.height / 2, + }) .with_url("https://twitter.com/TauriApps")? .build()?; let webview4 = WebViewBuilder::new_as_child(&window) - .with_position(((size.width / 2) as i32, (size.height / 2) as i32)) - .with_size((size.width / 2, size.height / 2)) + .with_bounds(Rect { + x: (size.width / 2) as i32, + y: (size.height / 2) as i32, + width: size.width / 2, + height: size.height / 2, + }) .with_url("https://google.com")? .build()?; @@ -84,14 +100,30 @@ fn main() -> wry::Result<()> { .. } => { let size = size.to_logical::(window.scale_factor()); - webview.set_size((size.width / 2, size.height / 2)); - webview.set_position((0, 0)); - webview2.set_position(((size.width / 2) as i32, 0)); - webview2.set_size((size.width / 2, size.height / 2)); - webview3.set_position((0, (size.height / 2) as i32)); - webview3.set_size((size.width / 2, size.height / 2)); - webview4.set_position(((size.width / 2) as i32, (size.height / 2) as i32)); - webview4.set_size((size.width / 2, size.height / 2)); + webview.set_bounds(Rect { + x: 0, + y: 0, + width: size.width / 2, + height: size.height / 2, + }); + webview2.set_bounds(Rect { + x: (size.width / 2) as i32, + y: 0, + width: size.width / 2, + height: size.height / 2, + }); + webview3.set_bounds(Rect { + x: 0, + y: (size.height / 2) as i32, + width: size.width / 2, + height: size.height / 2, + }); + webview4.set_bounds(Rect { + x: (size.width / 2) as i32, + y: (size.height / 2) as i32, + width: size.width / 2, + height: size.height / 2, + }); } Event::WindowEvent { event: WindowEvent::CloseRequested, diff --git a/examples/wgpu.rs b/examples/wgpu.rs index 34a80cf69..1a8b8b8e5 100644 --- a/examples/wgpu.rs +++ b/examples/wgpu.rs @@ -4,7 +4,7 @@ use winit::{ event_loop::{ControlFlow, EventLoop}, window::Window, }; -use wry::WebViewBuilder; +use wry::{Rect, WebViewBuilder}; async fn run(event_loop: EventLoop<()>, window: Window) { let size = window.inner_size(); @@ -97,8 +97,12 @@ fn fs_main() -> @location(0) vec4 { surface.configure(&device, &config); let _webview = WebViewBuilder::new_as_child(&window) - .with_position((100, 100)) - .with_size((400, 400)) + .with_bounds(Rect { + x: 0, + y: 0, + width: 1, + height: 1, + }) .with_transparent(true) .with_html( r#" diff --git a/examples/winit.rs b/examples/winit.rs index 4ffa79304..841fd39b8 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -71,7 +71,12 @@ fn main() -> wry::Result<()> { event: WindowEvent::Resized(size), .. } => { - _webview.set_size(size.into()); + _webview.set_bounds(wry::Rect { + x: 0, + y: 0, + width: size.width, + height: size.height, + }); } Event::WindowEvent { event: WindowEvent::CloseRequested, diff --git a/src/android/mod.rs b/src/android/mod.rs index 5b3a947e4..f3e1df7bc 100644 --- a/src/android/mod.rs +++ b/src/android/mod.rs @@ -335,12 +335,8 @@ impl InnerWebView { Ok(()) } - pub fn set_position(&self, _position: (i32, i32)) { - // Unsupported. - } - - pub fn set_size(&self, _size: (u32, u32)) { - // Unsupported. + pub fn set_bounds(&self, bounds: crate::Rect) { + // Unsupported } pub fn set_visible(&self, _visible: bool) { diff --git a/src/lib.rs b/src/lib.rs index 2fa9b5256..ee02835a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -233,6 +233,19 @@ pub use proxy::{ProxyConfig, ProxyEndpoint}; pub use url::Url; pub use web_context::WebContext; +/// A rectangular region. +#[derive(Clone, Copy, Debug)] +pub struct Rect { + /// x coordinate of top left corner + pub x: i32, + /// y coordinate of top left corner + pub y: i32, + /// width + pub width: u32, + /// height + pub height: u32, +} + /// Resolves a custom protocol [`Request`] asynchronously. /// /// See [`WebViewBuilder::with_asynchronous_custom_protocol`] for more information. @@ -450,15 +463,9 @@ pub struct WebViewAttributes { /// - **macOS / Android / iOS:** Unsupported. pub focused: bool, - /// The webview postion. - /// This is effective if the webview was created by [`WebView::new_as_child`]. - /// If it's `None`, the position will be (0, 0). - pub position: Option<(i32, i32)>, - - /// The webview size. - /// This is effective if the webview was created by [`WebView::new_as_child`]. - /// If it's `None`, the size will be (0, 0). - pub size: Option<(u32, u32)>, + /// The webview bounds. Defaults to `x: 0, y: 0, width: 200, height: 200`. + /// This is only effective if the webview was created by [`WebView::new_as_child`] or [`WebViewBuilder::new_as_child`]. + pub bounds: Option, } impl Default for WebViewAttributes { @@ -493,8 +500,12 @@ impl Default for WebViewAttributes { on_page_load_handler: None, proxy_config: None, focused: true, - position: None, - size: None, + bounds: Some(Rect { + x: 0, + y: 0, + width: 200, + height: 200, + }), } } } @@ -951,15 +962,10 @@ impl<'a> WebViewBuilder<'a> { self } - /// Set the webview position relative to its parent if it was created as a child. - pub fn with_position(mut self, position: (i32, i32)) -> Self { - self.attrs.position = Some(position); - self - } - - /// Set the webview size if it was created as a child. - pub fn with_size(mut self, size: (u32, u32)) -> Self { - self.attrs.size = Some(size); + /// Specify the webview position relative to its parent if it will be created as a child. + /// Defaults to `x: 0, y: 0, width: 200, height: 200`. + pub fn with_bounds(mut self, bounds: Rect) -> Self { + self.attrs.bounds.replace(bounds); self } @@ -1354,15 +1360,11 @@ impl WebView { self.webview.clear_all_browsing_data() } - /// Set the webview position relative to its parent if it was created as a child. - pub fn set_position(&self, position: (i32, i32)) { - self.webview.set_position(position) - } - - /// Set the webview size if it was created as a child - /// or if ot was created directly in an X11 Window. - pub fn set_size(&self, size: (u32, u32)) { - self.webview.set_size(size) + /// Set the webview bounds. + /// + /// This is only effective if the webview was created as a child. + pub fn set_bounds(&self, bounds: Rect) { + self.webview.set_bounds(bounds) } /// Shows or hides the webview. diff --git a/src/webkitgtk/mod.rs b/src/webkitgtk/mod.rs index ba34662b4..c78a35cb7 100644 --- a/src/webkitgtk/mod.rs +++ b/src/webkitgtk/mod.rs @@ -34,8 +34,8 @@ use web_context::WebContextExt; pub use web_context::WebContextImpl; use crate::{ - proxy::ProxyConfig, web_context::WebContext, Error, PageLoadEvent, Result, WebViewAttributes, - RGBA, + proxy::ProxyConfig, web_context::WebContext, Error, PageLoadEvent, Rect, Result, + WebViewAttributes, RGBA, }; mod file_drop; @@ -115,10 +115,13 @@ impl InnerWebView { (xlib.XCreateSimpleWindow)( display as _, window_handle, - attributes.position.map(|p| p.0).unwrap_or(0), - attributes.position.map(|p| p.1).unwrap_or(0), - attributes.size.map(|s| s.0).unwrap_or(0), - attributes.size.map(|s| s.1).unwrap_or(0), + attributes.bounds.map(|p| p.x).unwrap_or(0), + attributes.bounds.map(|p| p.y).unwrap_or(0), + // it is unlikey that bounds are not set because + // we have a default for it, but anyways we need to have a fallback + // and we need to use 1 not 0 here otherwise xlib will crash + attributes.bounds.map(|s| s.width).unwrap_or(1), + attributes.bounds.map(|s| s.height).unwrap_or(1), 0, 0, 0, @@ -597,20 +600,26 @@ impl InnerWebView { Ok(()) } - pub fn set_position(&self, position: (i32, i32)) { + pub fn set_bounds(&self, bounds: Rect) { if self.is_child { if let Some(window) = &self.gtk_window { - window.move_(position.0, position.1); + window.move_(bounds.x, bounds.y); } } - } - pub fn set_size(&self, size: (u32, u32)) { if let Some(window) = &self.gtk_window { if self.is_child { - window.window().unwrap().resize(size.0 as _, size.1 as _); + window + .window() + .unwrap() + .resize(bounds.width as i32, bounds.height as i32); } - window.size_allocate(>k::Allocation::new(200, 200, size.0 as _, size.1 as _)); + window.size_allocate(>k::Allocation::new( + 0, + 0, + bounds.width as i32, + bounds.height as i32, + )); } } diff --git a/src/webview2/mod.rs b/src/webview2/mod.rs index 8524b063f..db32600f4 100644 --- a/src/webview2/mod.rs +++ b/src/webview2/mod.rs @@ -31,9 +31,8 @@ use windows::{ WindowsAndMessaging::{ self as win32wm, CreateWindowExW, DefWindowProcW, DestroyWindow, PostMessageW, RegisterClassExW, RegisterWindowMessageA, SetWindowPos, ShowWindow, CS_HREDRAW, CS_VREDRAW, - CW_USEDEFAULT, HCURSOR, HICON, HMENU, SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOMOVE, - SWP_NOSIZE, SWP_NOZORDER, SW_HIDE, SW_SHOW, WINDOW_EX_STYLE, WNDCLASSEXW, WS_CHILD, - WS_CLIPCHILDREN, WS_VISIBLE, + CW_USEDEFAULT, HCURSOR, HICON, HMENU, SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOZORDER, + SW_HIDE, SW_SHOW, WINDOW_EX_STYLE, WNDCLASSEXW, WS_CHILD, WS_CLIPCHILDREN, WS_VISIBLE, }, }, }, @@ -42,7 +41,7 @@ use windows::{ use self::file_drop::FileDropController; use super::Theme; use crate::{ - proxy::ProxyConfig, Error, MemoryUsageLevel, PageLoadEvent, RequestAsyncResponder, Result, + proxy::ProxyConfig, Error, MemoryUsageLevel, PageLoadEvent, Rect, RequestAsyncResponder, Result, WebContext, WebViewAttributes, RGBA, }; @@ -137,10 +136,16 @@ impl InnerWebView { PCWSTR::from_raw(class_name.as_ptr()), PCWSTR::null(), flags, - attributes.position.map(|a| a.0).unwrap_or(CW_USEDEFAULT), - attributes.position.map(|a| a.1).unwrap_or(CW_USEDEFAULT), - attributes.size.map(|a| a.0 as i32).unwrap_or(CW_USEDEFAULT), - attributes.size.map(|a| a.1 as i32).unwrap_or(CW_USEDEFAULT), + attributes.bounds.map(|a| a.x).unwrap_or(CW_USEDEFAULT), + attributes.bounds.map(|a| a.y).unwrap_or(CW_USEDEFAULT), + attributes + .bounds + .map(|a| a.width as i32) + .unwrap_or(CW_USEDEFAULT), + attributes + .bounds + .map(|a| a.height as i32) + .unwrap_or(CW_USEDEFAULT), HWND(parent), HMENU::default(), GetModuleHandleW(PCWSTR::null()).unwrap_or_default(), @@ -1005,33 +1010,17 @@ impl InnerWebView { set_theme(&self.webview, theme); } - pub fn set_position(&self, position: (i32, i32)) { + pub fn set_bounds(&self, bounds: Rect) { if self.is_child { unsafe { let _ = SetWindowPos( self.hwnd, HWND::default(), - position.0, - position.1, - 0, - 0, - SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER, - ); - } - } - } - - pub fn set_size(&self, size: (u32, u32)) { - if self.is_child { - unsafe { - let _ = SetWindowPos( - self.hwnd, - HWND::default(), - 0, - 0, - size.0 as _, - size.1 as _, - SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER, + bounds.x, + bounds.y, + bounds.width as i32, + bounds.height as i32, + SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOZORDER, ); } } diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index 254c99c57..f539713ac 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -394,24 +394,24 @@ impl InnerWebView { #[cfg(target_os = "macos")] { - let (x, y) = attributes.position.unwrap_or((0, 0)); + let (x, y) = attributes.bounds.map(|b| (b.x, b.y)).unwrap_or((0, 0)); + let (w, h) = attributes + .bounds + .map(|b| (b.width, b.height)) + .unwrap_or_else(|| { + if is_child { + let frame = NSView::frame(ns_view); + (frame.size.width as u32, frame.size.height as u32) + } else { + (0, 0) + } + }); + + let frame = CGRect { + origin: window_position(if is_child { ns_view } else { webview }, x, y, h as f64), + size: CGSize::new(w as f64, h as f64), + }; - let (w, h) = attributes.size.unwrap_or_else(|| { - if is_child { - let frame = NSView::frame(ns_view); - (frame.size.width as u32, frame.size.height as u32) - } else { - (0, 0) - } - }); - let frame: CGRect = CGRect::new( - &window_position( - if is_child { ns_view } else { webview }, - (x, y), - (w as f64, h as f64), - ), - &CGSize::new(w as f64, h as f64), - ); let _: () = msg_send![webview, initWithFrame:frame configuration:config]; if is_child { // fixed element @@ -1088,25 +1088,18 @@ r#"Object.defineProperty(window, 'ipc', { Ok(()) } - pub fn set_position(&self, position: (i32, i32)) { - if self.is_child { - unsafe { - let mut frame: CGRect = msg_send![self.webview, frame]; - frame.origin = window_position( - msg_send![self.webview, superview], - (position.0, position.1), - (frame.size.width, frame.size.height), - ); - let () = msg_send![self.webview, setFrame: frame]; - } - } - } - - pub fn set_size(&self, size: (u32, u32)) { + pub fn set_bounds(&self, bounds: Rect) { if self.is_child { unsafe { - let mut frame: CGRect = msg_send![self.webview, frame]; - frame.size = CGSize::new(size.0 as f64, size.1 as f64); + let frame = CGRect { + origin: window_position( + msg_send![self.webview, superview], + bounds.x, + bounds.y, + bounds.height, + ), + size: CGSize::new(bounds.width as f64, bounds.height as f64), + }; let () = msg_send![self.webview, setFrame: frame]; } } @@ -1261,10 +1254,7 @@ struct NSData(id); /// Converts from wry screen-coordinates to macOS screen-coordinates. /// wry: top-left is (0, 0) and y increasing downwards /// macOS: bottom-left is (0, 0) and y increasing upwards -unsafe fn window_position(view: id, position: (i32, i32), size: (f64, f64)) -> CGPoint { +unsafe fn window_position(view: id, x: i32, y: i32, height: f64) -> CGPoint { let frame: CGRect = msg_send![view, frame]; - CGPoint::new( - position.0 as f64, - frame.size.height - position.1 as f64 - size.1, - ) + CGPoint::new(x as f64, frame.size.height - y as f64 - height) } From cb3ab04e14a4e8b1f2c90d67e50aaa2cdc416a62 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Tue, 14 Nov 2023 02:24:41 +0200 Subject: [PATCH 2/5] update change file --- .changes/rwh.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/.changes/rwh.md b/.changes/rwh.md index 09d758265..d6a9e4e98 100644 --- a/.changes/rwh.md +++ b/.changes/rwh.md @@ -3,18 +3,20 @@ --- Refactor new method to take raw window handle instead. Following are APIs got affected: - - `application` module is removed, and `webivew` module is moved to root module. - - `WebViewBuilder::new`, `WebView::new` now take `RawWindowHandle` instead. - - Attributes `ipc_handler`, `file_drop_handler`, `document_change_handler` don't have window parameter anymore. - Users should use closure to capture the types they want to use. - - Position field in `FileDrop` event is now `Position` instead of `PhysicalPosition`. Users need to handle scale factor - depend on the situation they have. - - `Webview::inner_size` is removed. - - Add `WebViewBuilderExtUnix` trait to extend `WebViewBuilder` on Unix platforms. - - Add `new_gtk` functions to `WebViewBuilderExtUnix` and `WebviewExtUnix`. - - [raw-window-handle](https://docs.rs/raw-window-handle/latest/raw_window_handle/) crate is re-exported as `wry::raw_window_handle`. -This also means that we removed `tao` as a dependency completely which required some changes to the Android backend: - - We exposed the `android_setup` function that needs to be called once to setup necessary logic. - - Previously the `android_binding!` had internal call to `tao::android_binding` but now that `tao` has been removed, - the macro signature has changed and you now need to call `tao::android_binding` yourself, checkout the crate documentation for more information. +- `application` module is removed, and `webivew` module is moved to root module. +- `WebViewBuilder::new`, `WebView::new` now take `RawWindowHandle` instead. +- Add `WebViewBuilder::new_as_child`, `WebView::new_as_child` to crate a webview as a child inside a parent window. +- `Webview::inner_size` is removed. +- Add `WebViewBuilderExtUnix` trait to extend `WebViewBuilder` on Unix platforms. +- Add `new_gtk` functions to `WebViewBuilderExtUnix` and `WebviewExtUnix`. +- [raw-window-handle](https://docs.rs/raw-window-handle/latest/raw_window_handle/) crate is re-exported as `wry::raw_window_handle`. + +This also means that we removed `tao` as a dependency completely which required some changes to the public APIs and to the Android backend: + +- Webview attributes `ipc_handler`, `file_drop_handler`, `document_change_handler` don't take the `Window` as first parameter anymore. + Users should use closure to capture the types they want to use. +- Position field in `FileDrop` event is now a tuple of `(x, y)` physical position instead of `PhysicalPosition`. Users need to handle scale factor +- We exposed the `android_setup` function that needs to be called once to setup necessary logic. +- Previously the `android_binding!` had internal call to `tao::android_binding` but now that `tao` has been removed, + the macro signature has changed and you now need to call `tao::android_binding` yourself, checkout the crate documentation for more information. From f30b384d7b496aae0b1ea6878acb5b2016d00edf Mon Sep 17 00:00:00 2001 From: amrbashir Date: Tue, 14 Nov 2023 02:25:35 +0200 Subject: [PATCH 3/5] fix macOS build --- src/wkwebview/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index f539713ac..f31612679 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -45,6 +45,7 @@ use crate::{ wkwebview::proxy::{ nw_endpoint_t, nw_proxy_config_create_http_connect, nw_proxy_config_create_socksv5, }, + Rect, }; use crate::{ From d23b52c0804ca57a7e54c27a58e2b6a7fcdfa021 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Tue, 14 Nov 2023 02:34:53 +0200 Subject: [PATCH 4/5] again --- src/wkwebview/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index f31612679..e9f046bac 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -45,7 +45,6 @@ use crate::{ wkwebview::proxy::{ nw_endpoint_t, nw_proxy_config_create_http_connect, nw_proxy_config_create_socksv5, }, - Rect, }; use crate::{ @@ -56,7 +55,7 @@ use crate::{ }, navigation::{add_navigation_mathods, drop_navigation_methods, set_navigation_methods}, }, - Error, PageLoadEvent, RequestAsyncResponder, Result, WebContext, WebViewAttributes, RGBA, + Error, PageLoadEvent, Rect, RequestAsyncResponder, Result, WebContext, WebViewAttributes, RGBA, }; use http::{ From 8922c043677762d4b0ec4dbb889e51a8b20ddb80 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Tue, 14 Nov 2023 02:54:54 +0200 Subject: [PATCH 5/5] Update src/wkwebview/mod.rs --- src/wkwebview/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index e9f046bac..68c9a4496 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -1096,7 +1096,7 @@ r#"Object.defineProperty(window, 'ipc', { msg_send![self.webview, superview], bounds.x, bounds.y, - bounds.height, + bounds.height as f64, ), size: CGSize::new(bounds.width as f64, bounds.height as f64), };