From 8fddbb6d514de8fa0561bd6631ff8a3699911ddd Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Wed, 22 Nov 2023 10:45:12 -0300 Subject: [PATCH] feat: add WebView::bounds getter (#1091) * feat: add WebView::bounds getter * macos impl * windows impl * dummy android * fix build on ios * fix initial size on macOS, adjust bounds impl * fallback to controller.bounds on windows * use webview.allocated_size on linux when not a child * cleanup windows impl * fix wgpu example * cleanup linux impl --------- Co-authored-by: amrbashir --- .changes/webview-bounds.md | 5 +++++ examples/wgpu.rs | 8 ++++---- src/android/mod.rs | 9 +++++++++ src/lib.rs | 6 +++++- src/webkitgtk/mod.rs | 37 ++++++++++++++++++++++++++++++++++ src/webview2/mod.rs | 41 +++++++++++++++++++++++++++++++++----- src/wkwebview/mod.rs | 39 ++++++++++++++++++++++++++---------- 7 files changed, 124 insertions(+), 21 deletions(-) create mode 100644 .changes/webview-bounds.md diff --git a/.changes/webview-bounds.md b/.changes/webview-bounds.md new file mode 100644 index 000000000..f1dd83962 --- /dev/null +++ b/.changes/webview-bounds.md @@ -0,0 +1,5 @@ +--- +"wry": patch +--- + +Add `WebView::bounds` getter. diff --git a/examples/wgpu.rs b/examples/wgpu.rs index 1a8b8b8e5..87a266cd0 100644 --- a/examples/wgpu.rs +++ b/examples/wgpu.rs @@ -98,10 +98,10 @@ fn fs_main() -> @location(0) vec4 { let _webview = WebViewBuilder::new_as_child(&window) .with_bounds(Rect { - x: 0, - y: 0, - width: 1, - height: 1, + x: 100, + y: 100, + width: 200, + height: 200, }) .with_transparent(true) .with_html( diff --git a/src/android/mod.rs b/src/android/mod.rs index f3e1df7bc..98c9a32e5 100644 --- a/src/android/mod.rs +++ b/src/android/mod.rs @@ -335,6 +335,15 @@ impl InnerWebView { Ok(()) } + pub fn bounds(&self) -> crate::Rect { + crate::Rect { + x: 0, + y: 0, + width: 0, + height: 0, + } + } + pub fn set_bounds(&self, bounds: crate::Rect) { // Unsupported } diff --git a/src/lib.rs b/src/lib.rs index a0b71f9d3..f03443fb9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -224,7 +224,7 @@ pub use url::Url; pub use web_context::WebContext; /// A rectangular region. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Rect { /// x coordinate of top left corner pub x: i32, @@ -1320,6 +1320,10 @@ impl WebView { self.webview.clear_all_browsing_data() } + pub fn bounds(&self) -> Rect { + self.webview.bounds() + } + /// Set the webview bounds. /// /// This is only effective if the webview was created as a child. diff --git a/src/webkitgtk/mod.rs b/src/webkitgtk/mod.rs index c78a35cb7..db591c95b 100644 --- a/src/webkitgtk/mod.rs +++ b/src/webkitgtk/mod.rs @@ -600,6 +600,43 @@ impl InnerWebView { Ok(()) } + pub fn bounds(&self) -> Rect { + let mut bounds = Rect::default(); + + if let (Some(xlib), Some(display), Some(window_handle)) = + (&self.xlib, self.x11_display, self.x11_window) + { + unsafe { + let mut attributes = std::mem::MaybeUninit::new(x11_dl::xlib::XWindowAttributes { + ..std::mem::zeroed() + }) + .assume_init(); + let ok = (xlib.XGetWindowAttributes)(display as _, window_handle, &mut attributes); + + if ok != 0 { + bounds.x = attributes.x; + bounds.y = attributes.y; + bounds.width = attributes.width as u32; + bounds.height = attributes.height as u32; + } + } + } else if let Some(window) = &self.gtk_window { + let position = window.position(); + let size = window.size(); + + bounds.x = position.0; + bounds.y = position.1; + bounds.width = size.0 as u32; + bounds.height = size.1 as u32; + } else { + let (size, _) = self.webview.allocated_size(); + bounds.width = size.width() as u32; + bounds.height = size.height() as u32; + } + + bounds + } + pub fn set_bounds(&self, bounds: Rect) { if self.is_child { if let Some(window) = &self.gtk_window { diff --git a/src/webview2/mod.rs b/src/webview2/mod.rs index 3fd954d90..cdb53bd4a 100644 --- a/src/webview2/mod.rs +++ b/src/webview2/mod.rs @@ -19,7 +19,7 @@ use windows::{ Win32::{ Foundation::*, Globalization::{self, MAX_LOCALE_NAME}, - Graphics::Gdi::{RedrawWindow, HBRUSH, HRGN, RDW_INTERNALPAINT}, + Graphics::Gdi::{MapWindowPoints, RedrawWindow, HBRUSH, HRGN, RDW_INTERNALPAINT}, System::{ Com::{CoInitializeEx, IStream, COINIT_APARTMENTTHREADED}, LibraryLoader::GetModuleHandleW, @@ -28,10 +28,11 @@ use windows::{ UI::{ Shell::{DefSubclassProc, SHCreateMemStream, SetWindowSubclass}, 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_NOZORDER, - SW_HIDE, SW_SHOW, WINDOW_EX_STYLE, WNDCLASSEXW, WS_CHILD, WS_CLIPCHILDREN, WS_VISIBLE, + self as win32wm, CreateWindowExW, DefWindowProcW, DestroyWindow, GetClientRect, GetParent, + PostMessageW, RegisterClassExW, RegisterWindowMessageA, SetWindowPos, ShowWindow, + CS_HREDRAW, CS_VREDRAW, 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, }, }, }, @@ -1009,6 +1010,36 @@ impl InnerWebView { set_theme(&self.webview, theme); } + pub fn bounds(&self) -> Rect { + let mut bounds = Rect::default(); + + if self.is_child { + let mut rect = RECT::default(); + if unsafe { GetClientRect(self.hwnd, &mut rect) }.is_err() { + panic!("Unexpected GetClientRect failure") + } + + let position_point = &mut [POINT { + x: rect.left, + y: rect.top, + }]; + unsafe { MapWindowPoints(self.hwnd, GetParent(self.hwnd), position_point) }; + + bounds.x = position_point[0].x; + bounds.y = position_point[0].y; + bounds.width = (rect.right - rect.left) as u32; + bounds.height = (rect.bottom - rect.top) as u32; + } else { + let mut rect = RECT::default(); + if unsafe { self.controller.Bounds(&mut rect) }.is_ok() { + bounds.width = (rect.right - rect.left) as u32; + bounds.height = (rect.bottom - rect.top) as u32; + } + } + + bounds + } + pub fn set_bounds(&self, bounds: Rect) { if self.is_child { unsafe { diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index 4003f030c..cb41c7c6f 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -397,17 +397,19 @@ impl InnerWebView { #[cfg(target_os = "macos")] { 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 (w, h) = if is_child { + attributes.bounds.map(|b| (b.width, b.height)) + } else { + None + } + .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), @@ -1090,6 +1092,21 @@ r#"Object.defineProperty(window, 'ipc', { Ok(()) } + pub fn bounds(&self) -> Rect { + unsafe { + let parent: id = msg_send![self.webview, superview]; + let parent_frame: CGRect = msg_send![parent, frame]; + let webview_frame: CGRect = msg_send![self.webview, frame]; + + Rect { + x: webview_frame.origin.x as i32, + y: (parent_frame.size.height - webview_frame.origin.y - webview_frame.size.height) as i32, + width: webview_frame.size.width as u32, + height: webview_frame.size.height as u32, + } + } + } + pub fn set_bounds(&self, bounds: Rect) { if self.is_child { unsafe {