diff --git a/crates/gpui/examples/window.rs b/crates/gpui/examples/window.rs index 8feb811ea2b0d62f2358cdddd43f89c5eb99330d..c3aa34436296fd4d219b2683597f67389353524b 100644 --- a/crates/gpui/examples/window.rs +++ b/crates/gpui/examples/window.rs @@ -75,7 +75,7 @@ impl Render for WindowDemo { .bg(rgb(0xffffff)) .size_full() .justify_center() - .items_center() + .content_center() .gap_2() .child(button("Normal", move |_, cx| { cx.open_window( @@ -165,18 +165,32 @@ impl Render for WindowDemo { }) .detach(); })) + .child(button("Resize", |window, _| { + let content_size = window.bounds().size; + window.resize(size(content_size.height, content_size.width)); + })) } } fn main() { Application::new().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx); + cx.open_window( WindowOptions { window_bounds: Some(WindowBounds::Windowed(bounds)), ..Default::default() }, - |_, cx| cx.new(|_| WindowDemo {}), + |window, cx| { + cx.new(|cx| { + cx.observe_window_bounds(window, move |_, window, _| { + println!("Window bounds changed: {:?}", window.bounds()); + }) + .detach(); + + WindowDemo {} + }) + }, ) .unwrap(); }); diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 141c650f3b7b17edccb980d3480576e261fcc189..d6c62dae8b75222188c3c84a7aadc62c0ad30726 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -383,6 +383,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { fn is_maximized(&self) -> bool; fn window_bounds(&self) -> WindowBounds; fn content_size(&self) -> Size; + fn resize(&mut self, size: Size); fn scale_factor(&self) -> f32; fn appearance(&self) -> WindowAppearance; fn display(&self) -> Option>; diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index a51e7933b8581e1aa22adb62a9ba7865aa673d91..17dcee6b3a37107051be12ea220ee9253f5399fb 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -797,6 +797,25 @@ impl PlatformWindow for WaylandWindow { self.borrow().bounds.size } + fn resize(&mut self, size: Size) { + let state = self.borrow(); + let state_ptr = self.0.clone(); + let dp_size = size.to_device_pixels(self.scale_factor()); + + state.xdg_surface.set_window_geometry( + state.bounds.origin.x.0 as i32, + state.bounds.origin.y.0 as i32, + dp_size.width.0, + dp_size.height.0, + ); + + state + .globals + .executor + .spawn(async move { state_ptr.resize(size) }) + .detach(); + } + fn scale_factor(&self) -> f32 { self.borrow().scale } diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index 0917d8bea47b933114e3d31ca03a8ad0ef11f257..57cba302efcf46ed2153b63e878a260cf310f261 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -1143,6 +1143,30 @@ impl PlatformWindow for X11Window { .map(|size| size.div(state.scale_factor)) } + fn resize(&mut self, size: Size) { + let state = self.0.state.borrow(); + let size = size.to_device_pixels(state.scale_factor); + let width = size.width.0 as u32; + let height = size.height.0 as u32; + + check_reply( + || { + format!( + "X11 ConfigureWindow failed. width: {}, height: {}", + width, height + ) + }, + self.0.xcb.configure_window( + self.0.x_window, + &xproto::ConfigureWindowAux::new() + .width(width) + .height(height), + ), + ) + .log_err(); + self.flush().log_err(); + } + fn scale_factor(&self) -> f32 { self.0.state.borrow().scale_factor } diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 8973677668a3f483da39f1dceef0a08b1f27db43..6394acc27df51eb6136b6c5058d15e0831cc06dc 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -805,6 +805,21 @@ impl PlatformWindow for MacWindow { self.0.as_ref().lock().content_size() } + fn resize(&mut self, size: Size) { + let this = self.0.lock(); + let window = this.native_window; + this.executor + .spawn(async move { + unsafe { + window.setContentSize_(NSSize { + width: size.width.0 as f64, + height: size.height.0 as f64, + }); + } + }) + .detach(); + } + fn scale_factor(&self) -> f32 { self.0.as_ref().lock().scale_factor() } diff --git a/crates/gpui/src/platform/test/window.rs b/crates/gpui/src/platform/test/window.rs index d950919ea7f84f54d8ced04931df9441a069e5aa..42ea7d8af467976cceca14510506ae463963de38 100644 --- a/crates/gpui/src/platform/test/window.rs +++ b/crates/gpui/src/platform/test/window.rs @@ -126,6 +126,11 @@ impl PlatformWindow for TestWindow { self.bounds().size } + fn resize(&mut self, size: Size) { + let mut lock = self.0.lock(); + lock.bounds.size = size; + } + fn scale_factor(&self) -> f32 { 2.0 } diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 7b99a445cf67da9c4c9e8312d2f59bdce6657613..65980a284c8ac8fcfb6f42f572855f3b0540a93c 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -520,6 +520,32 @@ impl PlatformWindow for WindowsWindow { self.0.state.borrow().content_size() } + fn resize(&mut self, size: Size) { + let hwnd = self.0.hwnd; + let bounds = + crate::bounds(self.bounds().origin, size).to_device_pixels(self.scale_factor()); + let rect = calculate_window_rect(bounds, self.0.state.borrow().border_offset); + + self.0 + .executor + .spawn(async move { + unsafe { + SetWindowPos( + hwnd, + None, + bounds.origin.x.0, + bounds.origin.y.0, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOMOVE, + ) + .context("unable to set window content size") + .log_err(); + } + }) + .detach(); + } + fn scale_factor(&self) -> f32 { self.0.state.borrow().scale_factor } diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 85e0edfe87344568ce74d21b7e05996058612d9c..4ee941d0634eddaf9ab333051f921971cb788dea 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -1320,6 +1320,11 @@ impl Window { self.platform_window.bounds() } + /// Set the content size of the window. + pub fn resize(&mut self, size: Size) { + self.platform_window.resize(size); + } + /// Returns whether or not the window is currently fullscreen pub fn is_fullscreen(&self) -> bool { self.platform_window.is_fullscreen()