Skip to content

Commit

Permalink
fix(core): fix undecorated window resizing, #8519 (#8537)
Browse files Browse the repository at this point in the history
* fix(core): fix undecorated window resizing, fixes #8519

* js api

* fix invoke call

* Update tauri-window-start-resize-dragging.md

* clippy
  • Loading branch information
amrbashir authored Jan 18, 2024
1 parent 9f8037c commit 7f033f6
Show file tree
Hide file tree
Showing 11 changed files with 237 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changes/api-start-resize-dragging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tauri-apps/api': 'patch:feat'
---

Add `Window.startResizeDragging`.
5 changes: 5 additions & 0 deletions .changes/tauri-undecorated-resizing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'tauri': 'patch:bug'
---

Fix undecorated window resizing on Windows and Linux.
7 changes: 7 additions & 0 deletions .changes/tauri-window-start-resize-dragging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'tauri': 'patch:feat'
'tauri-runtime': 'patch'
'tauri-runtime-wry': 'patch'
---

Add `Window::start_resize_dragging` and `ResizeDirection` enum.
20 changes: 20 additions & 0 deletions core/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,7 @@ pub enum WindowMessage {
SetIgnoreCursorEvents(bool),
SetProgressBar(ProgressBarState),
DragWindow,
ResizeDragWindow(tauri_runtime::ResizeDirection),
RequestRedraw,
}

Expand Down Expand Up @@ -1583,6 +1584,13 @@ impl<T: UserEvent> Dispatch<T> for WryDispatcher<T> {
)
}

fn start_resize_dragging(&self, direction: tauri_runtime::ResizeDirection) -> Result<()> {
send_user_message(
&self.context,
Message::Window(self.window_id, WindowMessage::ResizeDragWindow(direction)),
)
}

#[cfg(all(feature = "tracing", not(target_os = "android")))]
fn eval_script<S: Into<String>>(&self, script: S) -> Result<()> {
// use a channel so the EvaluateScript task uses the current span as parent
Expand Down Expand Up @@ -2423,6 +2431,18 @@ fn handle_user_message<T: UserEvent>(
WindowMessage::DragWindow => {
let _ = window.drag_window();
}
WindowMessage::ResizeDragWindow(direction) => {
let _ = window.drag_resize_window(match direction {
tauri_runtime::ResizeDirection::East => tao::window::ResizeDirection::East,
tauri_runtime::ResizeDirection::North => tao::window::ResizeDirection::North,
tauri_runtime::ResizeDirection::NorthEast => tao::window::ResizeDirection::NorthEast,
tauri_runtime::ResizeDirection::NorthWest => tao::window::ResizeDirection::NorthWest,
tauri_runtime::ResizeDirection::South => tao::window::ResizeDirection::South,
tauri_runtime::ResizeDirection::SouthEast => tao::window::ResizeDirection::SouthEast,
tauri_runtime::ResizeDirection::SouthWest => tao::window::ResizeDirection::SouthWest,
tauri_runtime::ResizeDirection::West => tao::window::ResizeDirection::West,
});
}
WindowMessage::RequestRedraw => {
window.request_redraw();
}
Expand Down
16 changes: 16 additions & 0 deletions core/tauri-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ impl Default for DeviceEventFilter {
}
}

/// Defines the orientation that a window resize will be performed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
pub enum ResizeDirection {
East,
North,
NorthEast,
NorthWest,
South,
SouthEast,
SouthWest,
West,
}

#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
Expand Down Expand Up @@ -590,6 +603,9 @@ pub trait Dispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'static
/// Starts dragging the window.
fn start_dragging(&self) -> Result<()>;

/// Starts resize-dragging the window.
fn start_resize_dragging(&self, direction: ResizeDirection) -> Result<()>;

/// Executes javascript on the window this [`Dispatch`] represents.
fn eval_script<S: Into<String>>(&self, script: S) -> Result<()>;

Expand Down
2 changes: 1 addition & 1 deletion core/tauri/scripts/bundle.global.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions core/tauri/src/test/mock_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,10 @@ impl<T: UserEvent> Dispatch<T> for MockDispatcher {
Ok(())
}

fn start_resize_dragging(&self, direction: tauri_runtime::ResizeDirection) -> Result<()> {
Ok(())
}

fn eval_script<S: Into<String>>(&self, script: S) -> Result<()> {
self
.last_evaluated_script
Expand Down
10 changes: 10 additions & 0 deletions core/tauri/src/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub(crate) mod plugin;

use http::HeaderMap;
pub use tauri_runtime::window::PageLoadEvent;
use tauri_runtime::ResizeDirection;
pub use tauri_utils::{config::Color, WindowEffect as Effect, WindowEffectState as EffectState};
use url::Url;

Expand Down Expand Up @@ -2256,6 +2257,15 @@ impl<R: Runtime> Window<R> {
self.window.dispatcher.start_dragging().map_err(Into::into)
}

/// Starts resize-dragging the window.
pub fn start_resize_dragging(&self, direction: ResizeDirection) -> crate::Result<()> {
self
.window
.dispatcher
.start_resize_dragging(direction)
.map_err(Into::into)
}

/// Sets the taskbar progress state.
///
/// ## Platform-specific
Expand Down
121 changes: 121 additions & 0 deletions core/tauri/src/window/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{
#[cfg(desktop)]
mod desktop_commands {
use serde::Deserialize;
use tauri_runtime::ResizeDirection;
use tauri_utils::ProgressBarState;

use super::*;
Expand Down Expand Up @@ -155,6 +156,7 @@ mod desktop_commands {
setter!(set_cursor_position, Position);
setter!(set_ignore_cursor_events, bool);
setter!(start_dragging);
setter!(start_resize_dragging, ResizeDirection);
setter!(set_progress_bar, ProgressBarState);
setter!(print);

Expand Down Expand Up @@ -211,6 +213,107 @@ mod desktop_commands {
}
Ok(())
}

#[derive(Debug)]
enum HitTestResult {
Client,
Left,
Right,
Top,
Bottom,
TopLeft,
TopRight,
BottomLeft,
BottomRight,
NoWhere,
}

impl HitTestResult {
fn drag_resize_window<R: Runtime>(&self, window: &Window<R>) {
let _ = window.start_resize_dragging(match self {
HitTestResult::Left => ResizeDirection::West,
HitTestResult::Right => ResizeDirection::East,
HitTestResult::Top => ResizeDirection::North,
HitTestResult::Bottom => ResizeDirection::South,
HitTestResult::TopLeft => ResizeDirection::NorthWest,
HitTestResult::TopRight => ResizeDirection::NorthEast,
HitTestResult::BottomLeft => ResizeDirection::SouthWest,
HitTestResult::BottomRight => ResizeDirection::SouthEast,
_ => unreachable!(),
});
}

fn change_cursor<R: Runtime>(&self, window: &Window<R>) {
let _ = window.set_cursor_icon(match self {
HitTestResult::Left => CursorIcon::WResize,
HitTestResult::Right => CursorIcon::EResize,
HitTestResult::Top => CursorIcon::NResize,
HitTestResult::Bottom => CursorIcon::SResize,
HitTestResult::TopLeft => CursorIcon::NwResize,
HitTestResult::TopRight => CursorIcon::NeResize,
HitTestResult::BottomLeft => CursorIcon::SwResize,
HitTestResult::BottomRight => CursorIcon::SeResize,
_ => CursorIcon::Default,
});
}
}

fn hit_test(window_size: PhysicalSize<u32>, x: i32, y: i32, scale: f64) -> HitTestResult {
const BORDERLESS_RESIZE_INSET: f64 = 5.0;

const CLIENT: isize = 0b0000;
const LEFT: isize = 0b0001;
const RIGHT: isize = 0b0010;
const TOP: isize = 0b0100;
const BOTTOM: isize = 0b1000;
const TOPLEFT: isize = TOP | LEFT;
const TOPRIGHT: isize = TOP | RIGHT;
const BOTTOMLEFT: isize = BOTTOM | LEFT;
const BOTTOMRIGHT: isize = BOTTOM | RIGHT;

let top = 0;
let left = 0;
let bottom = top + window_size.height as i32;
let right = left + window_size.width as i32;

let inset = (BORDERLESS_RESIZE_INSET * scale) as i32;

#[rustfmt::skip]
let result =
(LEFT * (if x < (left + inset) { 1 } else { 0 }))
| (RIGHT * (if x >= (right - inset) { 1 } else { 0 }))
| (TOP * (if y < (top + inset) { 1 } else { 0 }))
| (BOTTOM * (if y >= (bottom - inset) { 1 } else { 0 }));

match result {
CLIENT => HitTestResult::Client,
LEFT => HitTestResult::Left,
RIGHT => HitTestResult::Right,
TOP => HitTestResult::Top,
BOTTOM => HitTestResult::Bottom,
TOPLEFT => HitTestResult::TopLeft,
TOPRIGHT => HitTestResult::TopRight,
BOTTOMLEFT => HitTestResult::BottomLeft,
BOTTOMRIGHT => HitTestResult::BottomRight,
_ => HitTestResult::NoWhere,
}
}

#[command(root = "crate")]
pub async fn on_mousemove<R: Runtime>(window: Window<R>, x: i32, y: i32) -> crate::Result<()> {
hit_test(window.inner_size()?, x, y, window.scale_factor()?).change_cursor(&window);
Ok(())
}

#[command(root = "crate")]
pub async fn on_mousedown<R: Runtime>(window: Window<R>, x: i32, y: i32) -> crate::Result<()> {
let res = hit_test(window.inner_size()?, x, y, window.scale_factor()?);
match res {
HitTestResult::Client | HitTestResult::NoWhere => {}
_ => res.drag_resize_window(&window),
};
Ok(())
}
}

/// Initializes the plugin.
Expand Down Expand Up @@ -239,6 +342,21 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
.into_string(),
);

#[derive(Template)]
#[default_template("./scripts/undecorated-resizing.js")]
struct UndecoratedResizingJavascript<'a> {
os_name: &'a str,
}

init_script.push_str(
&UndecoratedResizingJavascript {
os_name: std::env::consts::OS,
}
.render_default(&Default::default())
.unwrap()
.into_string(),
);

#[cfg(any(debug_assertions, feature = "devtools"))]
{
#[derive(Template)]
Expand Down Expand Up @@ -320,13 +438,16 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
desktop_commands::set_cursor_position,
desktop_commands::set_ignore_cursor_events,
desktop_commands::start_dragging,
desktop_commands::start_resize_dragging,
desktop_commands::set_progress_bar,
desktop_commands::print,
desktop_commands::set_icon,
desktop_commands::toggle_maximize,
desktop_commands::internal_toggle_maximize,
#[cfg(any(debug_assertions, feature = "devtools"))]
desktop_commands::internal_toggle_devtools,
desktop_commands::on_mousemove,
desktop_commands::on_mousedown,
]);
handler(invoke)
}
Expand Down
21 changes: 21 additions & 0 deletions core/tauri/src/window/scripts/undecorated-resizing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

;(function () {
const osName = __TEMPLATE_os_name__
if (osName !== 'macos') {
document.addEventListener('mousemove', (e) => {
window.__TAURI_INTERNALS__.invoke('plugin:window|on_mousemove', {
x: e.clientX,
y: e.clientY
})
})
document.addEventListener('mousedown', (e) => {
window.__TAURI_INTERNALS__.invoke('plugin:window|on_mousedown', {
x: e.clientX,
y: e.clientY
})
})
}
})()
27 changes: 27 additions & 0 deletions tooling/api/src/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ export interface Monitor {
type Theme = 'light' | 'dark'
type TitleBarStyle = 'visible' | 'transparent' | 'overlay'

type ResizeDirection =
| 'East'
| 'North'
| 'NorthEast'
| 'NorthWest'
| 'South'
| 'SouthEast'
| 'SouthWest'
| 'West'

/**
* The payload for the `scaleChange` event.
*
Expand Down Expand Up @@ -1507,6 +1517,23 @@ class Window {
})
}

/**
* Starts resize-dragging the window.
* @example
* ```typescript
* import { getCurrent } from '@tauri-apps/api/window';
* await getCurrent().startResizeDragging();
* ```
*
* @return A promise indicating the success or failure of the operation.
*/
async startResizeDragging(direction: ResizeDirection): Promise<void> {
return invoke('plugin:window|start_resize_dragging', {
label: this.label,
value: direction
})
}

/**
* Sets the taskbar progress state.
*
Expand Down

0 comments on commit 7f033f6

Please sign in to comment.