Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): add an option for preventing window overflow #9687

Open
wants to merge 67 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
d9e2626
Add an option for preventing window overflow
Legend-Master May 7, 2024
02ddb4f
Fix shadow counted as part of the width
Legend-Master May 7, 2024
6a3b1c4
Enable prevent overflow by default
Legend-Master May 7, 2024
9a8c4ab
Fix crashing when margin is bigger than screen
Legend-Master May 7, 2024
ae1d90d
Merge branch 'dev' of https://github.com/tauri-apps/tauri into preven…
Legend-Master May 7, 2024
01a8e7a
Config file support
Legend-Master May 7, 2024
5aa3eda
Add to ts type
Legend-Master May 7, 2024
b4f61c0
Add mac implementation
Legend-Master May 8, 2024
3451755
Should be let some
Legend-Master May 8, 2024
d5c2352
Apply suggestions from code review
Legend-Master May 8, 2024
097a5ed
Merge branch 'dev' into prevent-window-overflow
Legend-Master May 8, 2024
a5a028a
Merge branch 'dev' into prevent-window-overflow
Legend-Master May 10, 2024
e8026f7
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master May 14, 2024
2100bda
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master May 14, 2024
a9283cb
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master May 25, 2024
b92a7e7
checked_sub -> saturating_sub
Legend-Master May 25, 2024
b548734
Merge branch 'dev' into prevent-window-overflow
Legend-Master Jul 1, 2024
7c519f2
Revert license header
Legend-Master Jul 1, 2024
d7fd244
Merge branch 'dev' into prevent-window-overflow
Legend-Master Aug 8, 2024
ec6e483
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master Aug 28, 2024
aab7893
Migrate windows 0.58
Legend-Master Aug 28, 2024
b7c5e23
Generate schema
Legend-Master Aug 28, 2024
2bbb42a
Merge branch 'dev' into prevent-window-overflow
Legend-Master Nov 5, 2024
03ed8c5
Fix merge conflict
Legend-Master Nov 5, 2024
ef94548
Try casting to objc2_app_kit::NSScreen
Legend-Master Nov 5, 2024
de09f3a
Add NSScreen feature
Legend-Master Nov 5, 2024
7656966
Use cast instead of as
Legend-Master Nov 5, 2024
1b4d7b0
fmt
Legend-Master Nov 5, 2024
5083149
Deref first
Legend-Master Nov 5, 2024
fe638b1
Wrong unsafe block
Legend-Master Nov 5, 2024
b6661bb
Add change file
Legend-Master Nov 5, 2024
13b4a1d
Add serde alias
Legend-Master Nov 5, 2024
c7714fb
More docs
Legend-Master Nov 5, 2024
aeeaae8
Disable prevent_overflow by default
Legend-Master Nov 5, 2024
ab7a48f
Remove unused default impl
Legend-Master Nov 5, 2024
86ef220
Merge branch 'dev' into prevent-window-overflow
Legend-Master Nov 5, 2024
e880df2
Missing pub
Legend-Master Nov 5, 2024
e59669f
Fix mock_runtime on ios
Legend-Master Nov 5, 2024
dde6abc
Merge branch 'dev' into prevent-window-overflow
Legend-Master Nov 6, 2024
07255da
Match PreventOverflowMargin's description
Legend-Master Nov 6, 2024
035e6bc
Merge branch 'dev' into prevent-window-overflow
Legend-Master Nov 7, 2024
52b9c7a
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master Nov 7, 2024
4c944ee
Merge branch 'dev' into prevent-window-overflow
Legend-Master Nov 10, 2024
d492e9c
Typo
Legend-Master Nov 12, 2024
16f4895
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master Nov 12, 2024
d887510
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master Nov 13, 2024
7e84cb1
Apply suggestions from code review
Legend-Master Nov 13, 2024
a5a8b81
Move get_work_area_size to seperate files
Legend-Master Nov 13, 2024
ade88e8
Unused imports
Legend-Master Nov 13, 2024
a7bd0d2
Add prevent_overflow to WebviewWindowBuilder
Legend-Master Nov 13, 2024
deddb12
Fix mac compile
Legend-Master Nov 13, 2024
edf6132
MonitorExt is only for desktop
Legend-Master Nov 13, 2024
657b479
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master Nov 13, 2024
a01d5c9
Rename to work_area
Legend-Master Nov 15, 2024
8bfd36e
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master Nov 15, 2024
4e6cded
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master Dec 9, 2024
cadb7a7
Use workarea for linux
Legend-Master Dec 9, 2024
984cc79
Missing `()`
Legend-Master Dec 9, 2024
9726b8c
Convert size
Legend-Master Dec 9, 2024
ab75756
Import MonitorExt
Legend-Master Dec 9, 2024
dc0eb0a
as u32
Legend-Master Dec 9, 2024
87941e9
Re-build API js
Legend-Master Dec 9, 2024
5bd115a
Fix wrong docs for work_area
Legend-Master Dec 9, 2024
5f30b49
Remove linux platform specific note
Legend-Master Dec 9, 2024
d5c2e8c
Remove left over linux platform specific note
Legend-Master Dec 10, 2024
8e1ca44
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master Dec 11, 2024
bdb8d2e
Merge remote-tracking branch 'upstream/dev' into prevent-window-overflow
Legend-Master Dec 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changes/prevent-window-overflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"tauri": "patch:feat"
"tauri-utils": "patch:feat"
"tauri-runtime": "patch:feat"
"tauri-runtime-wry": "patch:feat"
"@tauri-apps/api": "patch:feat"
---

Add `preventOverflow` config option to prevent the window from overflowing the monitor size on creation
51 changes: 51 additions & 0 deletions crates/tauri-cli/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,17 @@
],
"format": "double"
},
"preventOverflow": {
"description": "Whether or not to prevent the window from overflowing the workarea\n\n ## Platform-specific\n\n - **Linux:** Prevent overflowing the monitor instead of workarea\n - **iOS / Android:** Unsupported.",
"anyOf": [
{
"$ref": "#/definitions/PreventOverflowConfig"
},
{
"type": "null"
}
]
},
"resizable": {
"description": "Whether the window is resizable or not. When resizable is set to false, native window's maximize button is automatically disabled.",
"default": true,
Expand Down Expand Up @@ -539,6 +550,46 @@
}
]
},
"PreventOverflowConfig": {
"description": "Prevent overflow with a margin",
"anyOf": [
{
"description": "Enable prevent overflow or not",
"type": "boolean"
},
{
"description": "Enable prevent overflow with a margin\n so that the window's size + this margin won't overflow the workarea",
"allOf": [
{
"$ref": "#/definitions/PreventOverflowMargin"
}
]
}
]
},
"PreventOverflowMargin": {
"description": "Enable prevent overflow with a margin\n so that the window's size + this margin won't overflow the workarea",
"type": "object",
"required": [
"height",
"width"
],
"properties": {
"width": {
"description": "Horizontal margin in physical unit",
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"height": {
"description": "Vertical margin in physical unit",
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
},
"Theme": {
"description": "System theme.",
"oneOf": [
Expand Down
51 changes: 51 additions & 0 deletions crates/tauri-cli/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,17 @@
],
"format": "double"
},
"preventOverflow": {
"description": "Whether or not to prevent window overflow",
"anyOf": [
{
"$ref": "#/definitions/PreventOverflowMarginConfig"
},
{
"type": "null"
}
]
},
"resizable": {
"description": "Whether the window is resizable or not. When resizable is set to false, native window's maximize button is automatically disabled.",
"default": true,
Expand Down Expand Up @@ -488,6 +499,46 @@
}
]
},
"PreventOverflowMarginConfig": {
"description": "Prevent overflow with a margin",
"anyOf": [
{
"description": "Enable prevent overflow or not",
"type": "boolean"
},
{
"description": "Enable prevent overflow with a margin",
"allOf": [
{
"$ref": "#/definitions/PreventOverflowMargin"
}
]
}
]
},
"PreventOverflowMargin": {
"description": "Enable prevent overflow with a margin",
"type": "object",
"required": [
"height",
"width"
],
"properties": {
"width": {
"description": "Horizontal margin in physical unit",
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"height": {
"description": "Vertical margin in physical unit",
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
},
"Theme": {
"description": "System theme.",
"oneOf": [
Expand Down
51 changes: 51 additions & 0 deletions crates/tauri-cli/tauri.config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,17 @@
],
"format": "double"
},
"preventOverflow": {
"description": "Whether or not to prevent window overflow",
"anyOf": [
{
"$ref": "#/definitions/PreventOverflowMarginConfig"
},
{
"type": "null"
}
]
},
"resizable": {
"description": "Whether the window is resizable or not. When resizable is set to false, native window's maximize button is automatically disabled.",
"default": true,
Expand Down Expand Up @@ -488,6 +499,46 @@
}
]
},
"PreventOverflowMarginConfig": {
"description": "Prevent overflow with a margin",
"anyOf": [
{
"description": "Enable prevent overflow or not",
"type": "boolean"
},
{
"description": "Enable prevent overflow with a margin",
"allOf": [
{
"$ref": "#/definitions/PreventOverflowMargin"
}
]
}
]
},
"PreventOverflowMargin": {
"description": "Enable prevent overflow with a margin",
"type": "object",
"required": [
"height",
"width"
],
"properties": {
"width": {
"description": "Horizontal margin in physical unit",
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"height": {
"description": "Vertical margin in physical unit",
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
},
"Theme": {
"description": "System theme.",
"oneOf": [
Expand Down
1 change: 1 addition & 0 deletions crates/tauri-runtime-wry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ objc2-app-kit = { version = "0.2.2", features = [
"NSResponder",
"NSView",
"NSWindow",
"NSScreen",
"NSGraphics",
] }

Expand Down
108 changes: 88 additions & 20 deletions crates/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
)]

use http::Request;
#[cfg(desktop)]
use monitor::MonitorExt;
use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle};

use tauri_runtime::{
Expand Down Expand Up @@ -66,7 +68,7 @@ use tao::{
#[cfg(target_os = "macos")]
use tauri_utils::TitleBarStyle;
use tauri_utils::{
config::{Color, WindowConfig},
config::{Color, PreventOverflowConfig, WindowConfig},
Theme,
};
use url::Url;
Expand Down Expand Up @@ -123,6 +125,7 @@ use std::{
pub type WebviewId = u32;
type IpcHandler = dyn Fn(Request<String>) + 'static;

mod monitor;
#[cfg(any(
windows,
target_os = "linux",
Expand Down Expand Up @@ -728,14 +731,17 @@ impl From<ProgressBarState> for ProgressBarStateWrapper {
pub struct WindowBuilderWrapper {
inner: TaoWindowBuilder,
center: bool,
prevent_overflow: Option<Size>,
#[cfg(target_os = "macos")]
tabbing_identifier: Option<String>,
}

impl std::fmt::Debug for WindowBuilderWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = f.debug_struct("WindowBuilderWrapper");
s.field("inner", &self.inner).field("center", &self.center);
s.field("inner", &self.inner)
.field("center", &self.center)
.field("prevent_overflow", &self.prevent_overflow);
#[cfg(target_os = "macos")]
{
s.field("tabbing_identifier", &self.tabbing_identifier);
Expand Down Expand Up @@ -861,6 +867,15 @@ impl WindowBuilder for WindowBuilderWrapper {
if let Some(window_classname) = &config.window_classname {
window = window.window_classname(window_classname);
}

if let Some(prevent_overflow) = &config.prevent_overflow {
window = match prevent_overflow {
PreventOverflowConfig::Enable(true) => window.prevent_overflow(),
PreventOverflowConfig::Margin(margin) => window
.prevent_overflow_with_margin(TaoPhysicalSize::new(margin.width, margin.height).into()),
_ => window,
};
}
}

window
Expand Down Expand Up @@ -907,6 +922,33 @@ impl WindowBuilder for WindowBuilderWrapper {
self
}

/// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size) on creation
///
/// ## Platform-specific
///
/// - **Linux:** Prevent overflowing the monitor instead of workarea
/// - **iOS / Android:** Unsupported.
#[must_use]
fn prevent_overflow(mut self) -> Self {
self
.prevent_overflow
.replace(PhysicalSize::new(0, 0).into());
self
}

/// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size)
/// on creation with a margin
///
/// ## Platform-specific
///
/// - **Linux:** Prevent overflowing the monitor instead of workarea
Legend-Master marked this conversation as resolved.
Show resolved Hide resolved
/// - **iOS / Android:** Unsupported.
#[must_use]
fn prevent_overflow_with_margin(mut self, margin: Size) -> Self {
self.prevent_overflow.replace(margin);
self
}

fn resizable(mut self, resizable: bool) -> Self {
self.inner = self.inner.with_resizable(resizable);
self
Expand Down Expand Up @@ -3906,7 +3948,7 @@ fn create_window<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
}

#[cfg(desktop)]
if window_builder.center {
if window_builder.prevent_overflow.is_some() || window_builder.center {
let monitor = if let Some(window_position) = &window_builder.inner.window.position {
event_loop.available_monitors().find(|m| {
Legend-Master marked this conversation as resolved.
Show resolved Hide resolved
let monitor_pos = m.position();
Expand All @@ -3923,39 +3965,65 @@ fn create_window<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
} else {
event_loop.primary_monitor()
};

if let Some(monitor) = monitor {
let scale_factor = monitor.scale_factor();
let desired_size = window_builder
.inner
.window
.inner_size
.unwrap_or_else(|| TaoPhysicalSize::new(800, 600).into());
let scale_factor = monitor.scale_factor();
#[allow(unused_mut)]
let mut window_size = window_builder
let mut inner_size = window_builder
.inner
.window
.inner_size_constraints
.clamp(desired_size, scale_factor)
.to_physical::<u32>(scale_factor);
let mut window_size = inner_size;
#[allow(unused_mut)]
// Left and right window shadow counts as part of the window on Windows
// We need to include it when calculating positions, but not size
let mut shadow_width = 0;
Legend-Master marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(windows)]
{
if window_builder.inner.window.decorations {
use windows::Win32::UI::WindowsAndMessaging::{AdjustWindowRect, WS_OVERLAPPEDWINDOW};
let mut rect = windows::Win32::Foundation::RECT::default();
let result = unsafe { AdjustWindowRect(&mut rect, WS_OVERLAPPEDWINDOW, false) };
if result.is_ok() {
window_size.width += (rect.right - rect.left) as u32;
// rect.bottom is made out of shadow, and we don't care about it
window_size.height += -rect.top as u32;
if window_builder.inner.window.decorations {
use windows::Win32::UI::WindowsAndMessaging::{AdjustWindowRect, WS_OVERLAPPEDWINDOW};
let mut rect = windows::Win32::Foundation::RECT::default();
let result = unsafe { AdjustWindowRect(&mut rect, WS_OVERLAPPEDWINDOW, false) };
if result.is_ok() {
shadow_width = (rect.right - rect.left) as u32;
// rect.bottom is made out of shadow, and we don't care about it
window_size.height += -rect.top as u32;
}
}

if let Some(margin) = window_builder.prevent_overflow {
let size = monitor.get_work_area_size();
let margin = margin.to_physical::<u32>(scale_factor);
let constraint = PhysicalSize::new(size.width - margin.width, size.height - margin.height);
if window_size.width > constraint.width || window_size.height > constraint.height {
if window_size.width > constraint.width {
inner_size.width = inner_size
.width
.saturating_sub(window_size.width - constraint.width);
window_size.width = constraint.width;
}
if window_size.height > constraint.height {
inner_size.height = inner_size
.height
.saturating_sub(window_size.height - constraint.height);
window_size.height = constraint.height;
}
window_builder.inner.window.inner_size = Some(inner_size.into());
}
}
let position = window::calculate_window_center_position(window_size, monitor);
let logical_position = position.to_logical::<f64>(scale_factor);
window_builder = window_builder.position(logical_position.x, logical_position.y);

if window_builder.center {
window_size.width += shadow_width;
let position = window::calculate_window_center_position(window_size, monitor);
let logical_position = position.to_logical::<f64>(scale_factor);
window_builder = window_builder.position(logical_position.x, logical_position.y);
}
}
}
};

let window = window_builder.inner.build(event_loop).unwrap();

Expand Down
Loading
Loading