Skip to content

Commit da25f73

Browse files
authored
feat: add granular size constraints APIs (#10242)
1 parent 26f2e19 commit da25f73

File tree

16 files changed

+220
-12
lines changed

16 files changed

+220
-12
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@tauri-apps/api": patch:feat
3+
---
4+
5+
Add APIs to enable setting window size constraints separately:
6+
- Added `WindowSizeConstraints` interface in `window` and `webviewWindow` modules.
7+
- Added `Window.setSizeConstraints` and `WebviewWindow.setSizeConstraints`
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"tauri": patch:feat
3+
---
4+
5+
Add APIs to enable setting window size constraints separately:
6+
- Added `WindowBuilder::inner_size_constraints` and `WebviewWindowBuilder::inner_size_constraints` which can be used for setting granular constraints.
7+
- Added `WindowSizeConstraints` struct
8+
- Added `Window::set_size_constraints` and `WebviewWindow::set_size_constraints`
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"tauri-runtime": "patch"
3+
"tauri-runtime-wry": "patch"
4+
---
5+
6+
Add `inner_size_constraints` method on `WindowBuilder` trait and `set_size_constraints` method on `WindowDispatch` trait.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"tauri": "patch:bug"
3+
"@tauri-apps/api": "patch:bug"
4+
---
5+
6+
Apply `minWidth`, `minHieght`, `maxWidth` and `maxHeight` constraints separately, which fixes a long standing bug where these constraints were never applied unless width and height were constrained together.

core/tauri-runtime-wry/src/lib.rs

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use tauri_runtime::{
2020
webview::{DetachedWebview, DownloadEvent, PendingWebview, WebviewIpcHandler},
2121
window::{
2222
CursorIcon, DetachedWindow, DragDropEvent, PendingWindow, RawWindow, WebviewEvent,
23-
WindowBuilder, WindowBuilderBase, WindowEvent, WindowId,
23+
WindowBuilder, WindowBuilderBase, WindowEvent, WindowId, WindowSizeConstraints,
2424
},
2525
DeviceEventFilter, Error, EventLoopProxy, ExitRequestedEventAction, Icon, ProgressBarState,
2626
ProgressBarStatus, Result, RunEvent, Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType,
@@ -43,8 +43,8 @@ use wry::WebViewBuilderExtWindows;
4343
use tao::{
4444
dpi::{
4545
LogicalPosition as TaoLogicalPosition, LogicalSize as TaoLogicalSize,
46-
PhysicalPosition as TaoPhysicalPosition, PhysicalSize as TaoPhysicalSize,
47-
Position as TaoPosition, Size as TaoSize,
46+
LogicalUnit as ToaLogicalUnit, PhysicalPosition as TaoPhysicalPosition,
47+
PhysicalSize as TaoPhysicalSize, Position as TaoPosition, Size as TaoSize,
4848
},
4949
event::{Event, StartCause, WindowEvent as TaoWindowEvent},
5050
event_loop::{
@@ -774,12 +774,22 @@ impl WindowBuilder for WindowBuilderWrapper {
774774
.minimizable(config.minimizable)
775775
.shadow(config.shadow);
776776

777-
if let (Some(min_width), Some(min_height)) = (config.min_width, config.min_height) {
778-
window = window.min_inner_size(min_width, min_height);
777+
let mut constraints = WindowSizeConstraints::default();
778+
779+
if let Some(min_width) = config.min_width {
780+
constraints.min_width = Some(ToaLogicalUnit::new(min_width).into());
781+
}
782+
if let Some(min_height) = config.min_height {
783+
constraints.min_height = Some(ToaLogicalUnit::new(min_height).into());
784+
}
785+
if let Some(max_width) = config.max_width {
786+
constraints.max_width = Some(ToaLogicalUnit::new(max_width).into());
779787
}
780-
if let (Some(max_width), Some(max_height)) = (config.max_width, config.max_height) {
781-
window = window.max_inner_size(max_width, max_height);
788+
if let Some(max_height) = config.max_height {
789+
constraints.max_height = Some(ToaLogicalUnit::new(max_height).into());
782790
}
791+
window = window.inner_size_constraints(constraints);
792+
783793
if let (Some(x), Some(y)) = (config.x, config.y) {
784794
window = window.position(x, y);
785795
}
@@ -823,6 +833,16 @@ impl WindowBuilder for WindowBuilderWrapper {
823833
self
824834
}
825835

836+
fn inner_size_constraints(mut self, constraints: WindowSizeConstraints) -> Self {
837+
self.inner.window.inner_size_constraints = tao::window::WindowSizeConstraints {
838+
min_width: constraints.min_width,
839+
min_height: constraints.min_height,
840+
max_width: constraints.max_width,
841+
max_height: constraints.max_height,
842+
};
843+
self
844+
}
845+
826846
fn resizable(mut self, resizable: bool) -> Self {
827847
self.inner = self.inner.with_resizable(resizable);
828848
self
@@ -1144,6 +1164,7 @@ pub enum WindowMessage {
11441164
SetSize(Size),
11451165
SetMinSize(Option<Size>),
11461166
SetMaxSize(Option<Size>),
1167+
SetSizeConstraints(WindowSizeConstraints),
11471168
SetPosition(Position),
11481169
SetFullscreen(bool),
11491170
SetFocus,
@@ -1850,6 +1871,16 @@ impl<T: UserEvent> WindowDispatch<T> for WryWindowDispatcher<T> {
18501871
)
18511872
}
18521873

1874+
fn set_size_constraints(&self, constraints: WindowSizeConstraints) -> Result<()> {
1875+
send_user_message(
1876+
&self.context,
1877+
Message::Window(
1878+
self.window_id,
1879+
WindowMessage::SetSizeConstraints(constraints),
1880+
),
1881+
)
1882+
}
1883+
18531884
fn set_position(&self, position: Position) -> Result<()> {
18541885
send_user_message(
18551886
&self.context,
@@ -2831,6 +2862,14 @@ fn handle_user_message<T: UserEvent>(
28312862
WindowMessage::SetMaxSize(size) => {
28322863
window.set_max_inner_size(size.map(|s| SizeWrapper::from(s).0));
28332864
}
2865+
WindowMessage::SetSizeConstraints(constraints) => {
2866+
window.set_inner_size_constraints(tao::window::WindowSizeConstraints {
2867+
min_width: constraints.min_width,
2868+
min_height: constraints.min_height,
2869+
max_width: constraints.max_width,
2870+
max_height: constraints.max_height,
2871+
});
2872+
}
28342873
WindowMessage::SetPosition(position) => {
28352874
window.set_outer_position(PositionWrapper::from(position).0)
28362875
}

core/tauri-runtime/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ pub mod window;
2626

2727
use dpi::{PhysicalPosition, PhysicalSize, Position, Size};
2828
use monitor::Monitor;
29-
use window::{CursorIcon, DetachedWindow, PendingWindow, RawWindow, WebviewEvent, WindowEvent};
29+
use window::{
30+
CursorIcon, DetachedWindow, PendingWindow, RawWindow, WebviewEvent, WindowEvent,
31+
WindowSizeConstraints,
32+
};
3033
use window::{WindowBuilder, WindowId};
3134

3235
use http::{
@@ -735,6 +738,9 @@ pub trait WindowDispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 's
735738
/// Updates the window max inner size.
736739
fn set_max_size(&self, size: Option<Size>) -> Result<()>;
737740

741+
/// Sets this window's minimum inner width.
742+
fn set_size_constraints(&self, constraints: WindowSizeConstraints) -> Result<()>;
743+
738744
/// Updates the window position.
739745
fn set_position(&self, position: Position) -> Result<()>;
740746

core/tauri-runtime/src/window.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use crate::{
99
Icon, Runtime, UserEvent, WindowDispatch,
1010
};
1111

12-
use serde::{Deserialize, Deserializer};
12+
use dpi::PixelUnit;
13+
use serde::{Deserialize, Deserializer, Serialize};
1314
use tauri_utils::{config::WindowConfig, Theme};
1415
#[cfg(windows)]
1516
use windows::Win32::Foundation::HWND;
@@ -201,6 +202,28 @@ impl<'de> Deserialize<'de> for CursorIcon {
201202
}
202203
}
203204

205+
/// Window size constraints
206+
#[derive(Clone, Copy, PartialEq, Debug, Default, Serialize, Deserialize)]
207+
#[serde(rename_all = "camelCase")]
208+
pub struct WindowSizeConstraints {
209+
/// The minimum width a window can be, If this is `None`, the window will have no minimum width.
210+
///
211+
/// The default is `None`.
212+
pub min_width: Option<PixelUnit>,
213+
/// The minimum height a window can be, If this is `None`, the window will have no minimum height.
214+
///
215+
/// The default is `None`.
216+
pub min_height: Option<PixelUnit>,
217+
/// The maximum width a window can be, If this is `None`, the window will have no maximum width.
218+
///
219+
/// The default is `None`.
220+
pub max_width: Option<PixelUnit>,
221+
/// The maximum height a window can be, If this is `None`, the window will have no maximum height.
222+
///
223+
/// The default is `None`.
224+
pub max_height: Option<PixelUnit>,
225+
}
226+
204227
/// Do **NOT** implement this trait except for use in a custom [`Runtime`]
205228
///
206229
/// This trait is separate from [`WindowBuilder`] to prevent "accidental" implementation.
@@ -237,6 +260,10 @@ pub trait WindowBuilder: WindowBuilderBase {
237260
#[must_use]
238261
fn max_inner_size(self, max_width: f64, max_height: f64) -> Self;
239262

263+
/// Window inner size constraints.
264+
#[must_use]
265+
fn inner_size_constraints(self, constraints: WindowSizeConstraints) -> Self;
266+
240267
/// Whether the window is resizable or not.
241268
/// When resizable is set to false, native window's maximize button is automatically disabled.
242269
#[must_use]

core/tauri/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
9292
("set_content_protected", false),
9393
("set_size", false),
9494
("set_min_size", false),
95+
("set_size_constraints", false),
9596
("set_max_size", false),
9697
("set_position", false),
9798
("set_fullscreen", false),

core/tauri/permissions/window/autogenerated/reference.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,32 @@ Denies the set_size command without any pre-configured scope.
13901390
<tr>
13911391
<td>
13921392

1393+
`window:allow-set-size-constraints`
1394+
1395+
</td>
1396+
<td>
1397+
1398+
Enables the set_size_constraints command without any pre-configured scope.
1399+
1400+
</td>
1401+
</tr>
1402+
1403+
<tr>
1404+
<td>
1405+
1406+
`window:deny-set-size-constraints`
1407+
1408+
</td>
1409+
<td>
1410+
1411+
Denies the set_size_constraints command without any pre-configured scope.
1412+
1413+
</td>
1414+
</tr>
1415+
1416+
<tr>
1417+
<td>
1418+
13931419
`window:allow-set-skip-taskbar`
13941420

13951421
</td>

core/tauri/scripts/bundle.global.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)