diff --git a/.changes/linux-content-fixed-overlay.md b/.changes/linux-content-fixed-overlay.md new file mode 100644 index 000000000..a7d6329f4 --- /dev/null +++ b/.changes/linux-content-fixed-overlay.md @@ -0,0 +1,5 @@ +--- +"tao": minor +--- + +On Linux, add a full-window `gtk::Fixed` overlay layer to each window (alongside the default vertical `gtk::Box`), exposed via `WindowExtUnix::content_fixed()`. A runtime can build positioned child webviews into this `gtk::Fixed` so they overlay the window and honor their bounds, instead of stacking beside the default box (GTK divides a vertical box among its children, which breaks multi-webview positioning — tauri-apps/tauri#10420). The default box stays the overlay's main child, so single-webview windows are unchanged. diff --git a/src/platform/unix.rs b/src/platform/unix.rs index c96fb9361..524806b72 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -82,6 +82,10 @@ pub trait WindowExtUnix { /// Returns `None` if the default vertical `gtk::Box` creation was disabled by [`WindowBuilderExtUnix::with_default_vbox`]. fn default_vbox(&self) -> Option<>k::Box>; + /// Returns the full-window `gtk::Fixed` overlay layer that hosts positioned + /// child webviews. `None` when the default `gtk::Box` creation is disabled. + fn content_fixed(&self) -> Option<>k::Fixed>; + /// Whether to show the window icon in the taskbar or not. fn set_skip_taskbar(&self, skip: bool) -> Result<(), ExternalError>; @@ -97,6 +101,10 @@ impl WindowExtUnix for Window { self.window.default_vbox.as_ref() } + fn content_fixed(&self) -> Option<>k::Fixed> { + self.window.content_fixed.as_ref() + } + fn set_skip_taskbar(&self, skip: bool) -> Result<(), ExternalError> { self.window.set_skip_taskbar(skip) } diff --git a/src/platform_impl/linux/window.rs b/src/platform_impl/linux/window.rs index fca4c308c..b319fe4f4 100644 --- a/src/platform_impl/linux/window.rs +++ b/src/platform_impl/linux/window.rs @@ -49,6 +49,10 @@ pub struct Window { /// Gtk application window. pub(crate) window: gtk::ApplicationWindow, pub(crate) default_vbox: Option, + /// Full-window `gtk::Fixed` overlay layer for positioned child webviews, so a + /// runtime can place them over the window instead of stacking them beside the + /// default box. `None` when the default `gtk::Box` creation is disabled. + pub(crate) content_fixed: Option, /// Window requests sender pub(crate) window_requests_tx: glib::Sender<(WindowId, WindowRequest)>, scale_factor: Rc, @@ -152,12 +156,25 @@ impl Window { } } - let default_vbox = if pl_attribs.default_vbox { + let (default_vbox, content_fixed) = if pl_attribs.default_vbox { let box_ = gtk::Box::new(gtk::Orientation::Vertical, 0); - window.add(&box_); - Some(box_) + // Wrap the content in a `gtk::Overlay` so positioned child webviews can be + // placed over the window rather than stacking beside the default box — GTK + // divides a vertical box among its children, which breaks multi-webview + // positioning (tauri-apps/tauri#10420). The default box stays the overlay's + // main child, so single-webview windows are unchanged; a pass-through + // `gtk::Fixed` overlay layer hosts positioned child webviews. + let overlay = gtk::Overlay::new(); + window.add(&overlay); + overlay.add(&box_); + let fixed = gtk::Fixed::new(); + fixed.set_halign(gtk::Align::Fill); + fixed.set_valign(gtk::Align::Fill); + overlay.add_overlay(&fixed); + overlay.set_overlay_pass_through(&fixed, true); + (Some(box_), Some(fixed)) } else { - None + (None, None) }; // Rest attributes @@ -262,6 +279,7 @@ impl Window { window_id, window, default_vbox, + content_fixed, window_requests_tx, draw_tx, scale_factor, @@ -405,6 +423,7 @@ impl Window { window_id, window, default_vbox: None, + content_fixed: None, window_requests_tx, draw_tx, scale_factor,