mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-11-24 12:14:05 +03:00
fix(core): multiwebview mode fixes for auto resize, reparent and add_child (#8999)
* refactor(core): simplify multiwebview impl, fix autoresize * add_child on main thread * fix reparent * revert some changes * add change files
This commit is contained in:
parent
de38c31163
commit
222a96b74b
5
.changes/fix-add-child-deadlock.md
Normal file
5
.changes/fix-add-child-deadlock.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:bug
|
||||
---
|
||||
|
||||
Fixes `Window::add_child` deadlock.
|
5
.changes/fix-reparent.md
Normal file
5
.changes/fix-reparent.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:bug
|
||||
---
|
||||
|
||||
Fixes `Webview::reparent` not updating the webview parent window reference.
|
5
.changes/multiwebview-bounds-fixes.md
Normal file
5
.changes/multiwebview-bounds-fixes.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-runtime-wry": patch:bug
|
||||
---
|
||||
|
||||
Fixes auto resize and positioning when using the multiwebview mode.
|
@ -2829,10 +2829,10 @@ fn handle_user_message<T: UserEvent>(
|
||||
bounds.height = size.height;
|
||||
|
||||
if let Some(b) = &webview.bounds {
|
||||
let window_size = window.inner_size();
|
||||
let window_size = window.inner_size().to_logical::<f32>(window.scale_factor());
|
||||
let mut bounds = b.lock().unwrap();
|
||||
bounds.width_rate = size.width as f32 / window_size.width as f32;
|
||||
bounds.height_rate = size.height as f32 / window_size.height as f32;
|
||||
bounds.width_rate = size.width as f32 / window_size.width;
|
||||
bounds.height_rate = size.height as f32 / window_size.height;
|
||||
}
|
||||
|
||||
webview.set_bounds(bounds);
|
||||
@ -2844,10 +2844,11 @@ fn handle_user_message<T: UserEvent>(
|
||||
bounds.y = position.y;
|
||||
|
||||
if let Some(b) = &webview.bounds {
|
||||
let window_size = window.inner_size();
|
||||
let window_size = window.inner_size().to_logical::<f32>(window.scale_factor());
|
||||
let mut bounds = b.lock().unwrap();
|
||||
bounds.width_rate = position.x as f32 / window_size.width as f32;
|
||||
bounds.height_rate = position.y as f32 / window_size.height as f32;
|
||||
|
||||
bounds.x_rate = position.x as f32 / window_size.width;
|
||||
bounds.y_rate = position.y as f32 / window_size.height;
|
||||
}
|
||||
|
||||
webview.set_bounds(bounds);
|
||||
@ -2913,7 +2914,6 @@ fn handle_user_message<T: UserEvent>(
|
||||
f(webview.handle())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(debug_assertions, feature = "devtools"))]
|
||||
WebviewMessage::OpenDevTools => {
|
||||
webview.open_devtools();
|
||||
@ -2940,6 +2940,7 @@ fn handle_user_message<T: UserEvent>(
|
||||
Ok(webview) => {
|
||||
windows.0.borrow_mut().get_mut(&window_id).map(|w| {
|
||||
w.webviews.push(webview);
|
||||
w.has_children.store(true, Ordering::Relaxed);
|
||||
w
|
||||
});
|
||||
}
|
||||
@ -3181,20 +3182,21 @@ fn handle_event_loop<T: UserEvent>(
|
||||
}
|
||||
}
|
||||
TaoWindowEvent::Resized(size) => {
|
||||
if let Some(webviews) = windows
|
||||
if let Some((Some(window), webviews)) = windows
|
||||
.0
|
||||
.borrow()
|
||||
.get(&window_id)
|
||||
.map(|w| w.webviews.clone())
|
||||
.map(|w| (w.inner.clone(), w.webviews.clone()))
|
||||
{
|
||||
let size = size.to_logical::<f32>(window.scale_factor());
|
||||
for webview in webviews {
|
||||
if let Some(bounds) = &webview.bounds {
|
||||
let b = bounds.lock().unwrap();
|
||||
webview.set_bounds(wry::Rect {
|
||||
x: (size.width as f32 * b.x_rate) as i32,
|
||||
y: (size.height as f32 * b.y_rate) as i32,
|
||||
width: (size.width as f32 * b.width_rate) as u32,
|
||||
height: (size.height as f32 * b.height_rate) as u32,
|
||||
x: (size.width * b.x_rate) as i32,
|
||||
y: (size.height * b.y_rate) as i32,
|
||||
width: (size.width * b.width_rate) as u32,
|
||||
height: (size.height * b.height_rate) as u32,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -3594,7 +3596,8 @@ fn create_webview<T: UserEvent>(
|
||||
|
||||
if let Some(navigation_handler) = pending.navigation_handler {
|
||||
webview_builder = webview_builder.with_navigation_handler(move |url| {
|
||||
Url::parse(&url)
|
||||
url
|
||||
.parse()
|
||||
.map(|url| navigation_handler(&url))
|
||||
.unwrap_or(true)
|
||||
});
|
||||
@ -3610,14 +3613,14 @@ fn create_webview<T: UserEvent>(
|
||||
height: size.height,
|
||||
});
|
||||
|
||||
let window_size = window.inner_size();
|
||||
let window_size = window.inner_size().to_logical::<f32>(window.scale_factor());
|
||||
|
||||
if webview_attributes.auto_resize {
|
||||
Some(WebviewBounds {
|
||||
x_rate: (position.x as f32) / window_size.width as f32,
|
||||
y_rate: (position.y as f32) / window_size.height as f32,
|
||||
width_rate: (size.width as f32) / window_size.width as f32,
|
||||
height_rate: (size.height as f32) / window_size.height as f32,
|
||||
x_rate: (position.x as f32) / window_size.width,
|
||||
y_rate: (position.y as f32) / window_size.height,
|
||||
width_rate: (size.width as f32) / window_size.width,
|
||||
height_rate: (size.height as f32) / window_size.height,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@ -3647,7 +3650,7 @@ fn create_webview<T: UserEvent>(
|
||||
|
||||
if let Some(page_load_handler) = pending.on_page_load_handler {
|
||||
webview_builder = webview_builder.with_on_page_load_handler(move |event, url| {
|
||||
let _ = Url::parse(&url).map(|url| {
|
||||
let _ = url.parse().map(|url| {
|
||||
page_load_handler(
|
||||
url,
|
||||
match event {
|
||||
|
@ -47,7 +47,7 @@ serde = { version = "1.0", features = [ "derive", "rc" ] }
|
||||
tokio = { version = "1", features = [ "rt", "rt-multi-thread", "sync", "fs", "io-util" ] }
|
||||
futures-util = "0.3"
|
||||
uuid = { version = "1", features = [ "v4" ], optional = true }
|
||||
url = { version = "2.4" }
|
||||
url = "2"
|
||||
anyhow = "1.0"
|
||||
thiserror = "1.0"
|
||||
tauri-runtime = { version = "2.0.0-beta.5", path = "../tauri-runtime" }
|
||||
|
@ -40,6 +40,9 @@ pub enum Error {
|
||||
/// Webview label must be unique.
|
||||
#[error("a webview with label `{0}` already exists")]
|
||||
WebviewLabelAlreadyExists(String),
|
||||
/// Cannot use the webview reparent function on webview windows.
|
||||
#[error("cannot reparent when using a WebviewWindow")]
|
||||
CannotReparentWebviewWindow,
|
||||
/// Embedded asset not found.
|
||||
#[error("asset not found: {0}")]
|
||||
AssetNotFound(String),
|
||||
|
@ -804,7 +804,7 @@ pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
|
||||
/// Fetch a single webview window from the manager.
|
||||
fn get_webview_window(&self, label: &str) -> Option<WebviewWindow<R>> {
|
||||
self.manager().get_webview(label).and_then(|webview| {
|
||||
if webview.window().is_webview_window {
|
||||
if webview.window().is_webview_window() {
|
||||
Some(WebviewWindow { webview })
|
||||
} else {
|
||||
None
|
||||
@ -819,7 +819,7 @@ pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
|
||||
.webviews()
|
||||
.into_iter()
|
||||
.filter_map(|(label, webview)| {
|
||||
if webview.window().is_webview_window {
|
||||
if webview.window().is_webview_window() {
|
||||
Some((label, WebviewWindow { webview }))
|
||||
} else {
|
||||
None
|
||||
|
@ -79,7 +79,7 @@ impl<R: Runtime> WindowManager<R> {
|
||||
&self,
|
||||
app_handle: AppHandle<R>,
|
||||
window: DetachedWindow<EventLoopMessage, R>,
|
||||
multiwebview: bool,
|
||||
is_webview_window: bool,
|
||||
#[cfg(desktop)] menu: Option<crate::window::WindowMenu<R>>,
|
||||
) -> Window<R> {
|
||||
let window = Window::new(
|
||||
@ -88,7 +88,7 @@ impl<R: Runtime> WindowManager<R> {
|
||||
app_handle,
|
||||
#[cfg(desktop)]
|
||||
menu,
|
||||
multiwebview,
|
||||
is_webview_window,
|
||||
);
|
||||
|
||||
let window_ = window.clone();
|
||||
@ -197,7 +197,7 @@ fn on_window_event<R: Runtime>(window: &Window<R>, event: &WindowEvent) -> crate
|
||||
WindowEvent::FileDrop(event) => match event {
|
||||
FileDropEvent::Hovered { paths, position } => {
|
||||
let payload = FileDropPayload { paths, position };
|
||||
if window.is_webview_window {
|
||||
if window.is_webview_window() {
|
||||
window.emit_to(
|
||||
EventTarget::labeled(window.label()),
|
||||
DROP_HOVER_EVENT,
|
||||
@ -218,14 +218,14 @@ fn on_window_event<R: Runtime>(window: &Window<R>, event: &WindowEvent) -> crate
|
||||
}
|
||||
let payload = FileDropPayload { paths, position };
|
||||
|
||||
if window.is_webview_window {
|
||||
if window.is_webview_window() {
|
||||
window.emit_to(EventTarget::labeled(window.label()), DROP_EVENT, payload)?
|
||||
} else {
|
||||
window.emit_to_window(DROP_EVENT, payload)?
|
||||
}
|
||||
}
|
||||
FileDropEvent::Cancelled => {
|
||||
if window.is_webview_window {
|
||||
if window.is_webview_window() {
|
||||
window.emit_to(
|
||||
EventTarget::labeled(window.label()),
|
||||
DROP_CANCELLED_EVENT,
|
||||
|
@ -894,7 +894,7 @@ impl<R: Runtime> Webview<R> {
|
||||
/// Closes this webview.
|
||||
pub fn close(&self) -> crate::Result<()> {
|
||||
let window = self.window();
|
||||
if window.is_webview_window {
|
||||
if window.is_webview_window() {
|
||||
window.close()
|
||||
} else {
|
||||
self.webview.dispatcher.close()?;
|
||||
@ -906,7 +906,7 @@ impl<R: Runtime> Webview<R> {
|
||||
/// Resizes this webview.
|
||||
pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
|
||||
let window = self.window();
|
||||
if window.is_webview_window {
|
||||
if window.is_webview_window() {
|
||||
window.set_size(size.into())
|
||||
} else {
|
||||
self
|
||||
@ -920,7 +920,7 @@ impl<R: Runtime> Webview<R> {
|
||||
/// Sets this webviews's position.
|
||||
pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
|
||||
let window = self.window();
|
||||
if window.is_webview_window {
|
||||
if window.is_webview_window() {
|
||||
window.set_position(position.into())
|
||||
} else {
|
||||
self
|
||||
@ -939,10 +939,13 @@ impl<R: Runtime> Webview<R> {
|
||||
/// Move the webview to the given window.
|
||||
pub fn reparent(&self, window: &Window<R>) -> crate::Result<()> {
|
||||
let current_window = self.window();
|
||||
if !current_window.is_webview_window {
|
||||
if current_window.is_webview_window() || window.is_webview_window() {
|
||||
Err(crate::Error::CannotReparentWebviewWindow)
|
||||
} else {
|
||||
self.webview.dispatcher.reparent(window.window.id)?;
|
||||
*self.window_label.lock().unwrap() = window.label().to_string();
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the webview position.
|
||||
@ -951,7 +954,7 @@ impl<R: Runtime> Webview<R> {
|
||||
/// - For webview window, returns the inner position of the window.
|
||||
pub fn position(&self) -> crate::Result<PhysicalPosition<i32>> {
|
||||
let window = self.window();
|
||||
if window.is_webview_window {
|
||||
if window.is_webview_window() {
|
||||
window.inner_position()
|
||||
} else {
|
||||
self.webview.dispatcher.position().map_err(Into::into)
|
||||
@ -961,7 +964,7 @@ impl<R: Runtime> Webview<R> {
|
||||
/// Returns the physical size of the webviews's client area.
|
||||
pub fn size(&self) -> crate::Result<PhysicalSize<u32>> {
|
||||
let window = self.window();
|
||||
if window.is_webview_window {
|
||||
if window.is_webview_window() {
|
||||
window.inner_size()
|
||||
} else {
|
||||
self.webview.dispatcher.size().map_err(Into::into)
|
||||
|
@ -880,7 +880,7 @@ impl<'de, R: Runtime> CommandArg<'de, R> for WebviewWindow<R> {
|
||||
/// Grabs the [`Window`] from the [`CommandItem`]. This will never fail.
|
||||
fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
|
||||
let webview = command.message.webview();
|
||||
if webview.window().is_webview_window {
|
||||
if webview.window().is_webview_window() {
|
||||
Ok(Self { webview })
|
||||
} else {
|
||||
Err(InvokeError::from_anyhow(anyhow::anyhow!(
|
||||
|
@ -866,7 +866,7 @@ pub struct Window<R: Runtime> {
|
||||
#[cfg(desktop)]
|
||||
pub(crate) menu: Arc<std::sync::Mutex<Option<WindowMenu<R>>>>,
|
||||
/// Whether this window is a Webview window (hosts only a single webview) or a container for multiple webviews
|
||||
pub(crate) is_webview_window: bool,
|
||||
is_webview_window: bool,
|
||||
}
|
||||
|
||||
impl<R: Runtime> std::fmt::Debug for Window<R> {
|
||||
@ -981,7 +981,17 @@ impl<R: Runtime> Window<R> {
|
||||
position: P,
|
||||
size: S,
|
||||
) -> crate::Result<Webview<R>> {
|
||||
webview_builder.build(self.clone(), position.into(), size.into())
|
||||
use std::sync::mpsc::channel;
|
||||
|
||||
let (tx, rx) = channel();
|
||||
let position = position.into();
|
||||
let size = size.into();
|
||||
let window_ = self.clone();
|
||||
self.run_on_main_thread(move || {
|
||||
let res = webview_builder.build(window_, position, size);
|
||||
tx.send(res.map_err(Into::into)).unwrap();
|
||||
})?;
|
||||
rx.recv().unwrap()
|
||||
}
|
||||
|
||||
/// List of webviews associated with this window.
|
||||
@ -996,6 +1006,10 @@ impl<R: Runtime> Window<R> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn is_webview_window(&self) -> bool {
|
||||
self.is_webview_window
|
||||
}
|
||||
|
||||
/// Runs the given closure on the main thread.
|
||||
pub fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()> {
|
||||
self
|
||||
|
Loading…
Reference in New Issue
Block a user