diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index bb91f91abb..4652d4016b 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -703,6 +703,8 @@ pub trait PlatformWindow: HasWindowHandle + HasDisplayHandle { fn show_window_menu(&self, _position: Point) {} fn start_window_move(&self) {} fn start_window_resize(&self, _edge: ResizeEdge) {} + fn set_input_region(&self, _rects: &[Bounds]) {} + fn set_exclusive_zone(&self, _zone: Pixels) {} fn window_decorations(&self) -> Decorations { Decorations::Server } diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index ef538ae9cf..aa005bbcb8 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -1945,6 +1945,21 @@ impl Window { self.platform_window.request_decorations(decorations); } + /// Set the window's input region to the union of `rects`. Pointer events + /// outside the region pass through to whatever is below the window. + /// An empty slice resets the input region, so the window will receive all + /// pointer events again. (wayland only) + pub fn set_input_region(&self, rects: &[Bounds]) { + self.platform_window.set_input_region(rects); + } + + /// Controls how a surface interacts with surrounding screen space. + /// Positive values reserve space, 0 avoids reserved space, and -1 ignores + /// reserved space and may extend underneath other surfaces. (wayland only) + pub fn set_exclusive_zone(&self, zone: Pixels) { + self.platform_window.set_exclusive_zone(zone); + } + /// Start a window resize operation (Wayland) pub fn start_window_resize(&self, edge: ResizeEdge) { self.platform_window.start_window_resize(edge); diff --git a/crates/gpui_linux/src/linux/wayland/window.rs b/crates/gpui_linux/src/linux/wayland/window.rs index dbc71d77e3..e42342d239 100644 --- a/crates/gpui_linux/src/linux/wayland/window.rs +++ b/crates/gpui_linux/src/linux/wayland/window.rs @@ -286,6 +286,14 @@ impl WaylandSurfaceState { } } + fn set_exclusive_zone(&self, zone: i32) { + if let WaylandSurfaceState::LayerShell(WaylandLayerSurfaceState { layer_surface, .. }) = + self + { + layer_surface.set_exclusive_zone(zone); + } + } + fn destroy(&mut self) { match self { WaylandSurfaceState::Xdg(WaylandXdgSurfaceState { @@ -1471,6 +1479,40 @@ impl PlatformWindow for WaylandWindow { } } + fn set_input_region(&self, rects: &[Bounds]) { + let state = self.borrow(); + if rects.is_empty() { + state.surface.set_input_region(None); + } else { + let region = state + .globals + .compositor + .create_region(&state.globals.qh, ()); + rects + .iter() + .map(|rect| rect.map(|pixels| f32::from(pixels) as i32)) + .for_each(|rect| { + region.add( + rect.origin.x, + rect.origin.y, + rect.size.width, + rect.size.height, + ) + }); + state.surface.set_input_region(Some(®ion)); + region.destroy(); + } + state.surface.commit(); + } + + fn set_exclusive_zone(&self, zone: Pixels) { + let state = self.borrow(); + state + .surface_state + .set_exclusive_zone(f32::from(zone) as i32); + state.surface.commit(); + } + fn window_decorations(&self) -> Decorations { let state = self.borrow(); match state.decorations { diff --git a/crates/gpui_wgpu/src/wgpu_renderer.rs b/crates/gpui_wgpu/src/wgpu_renderer.rs index 05c5ad7c84..ff84c8fe01 100644 --- a/crates/gpui_wgpu/src/wgpu_renderer.rs +++ b/crates/gpui_wgpu/src/wgpu_renderer.rs @@ -1189,7 +1189,10 @@ impl WgpuRenderer { self.surface_config.height = clamped_height.max(1); let surface_config = self.surface_config.clone(); - let resources = self.resources_mut(); + // GPU resources may not exist yet, skip rather than panicking + let Some(resources) = self.resources.as_mut() else { + return; + }; // Wait for any in-flight GPU work to complete before destroying textures if let Err(e) = resources.device.poll(wgpu::PollType::Wait {