@@ -12,6 +12,7 @@ use crate::{
1212#[ cfg( desktop) ]
1313mod desktop_commands {
1414 use serde:: Deserialize ;
15+ use tauri_runtime:: ResizeDirection ;
1516 use tauri_utils:: ProgressBarState ;
1617
1718 use super :: * ;
@@ -155,6 +156,7 @@ mod desktop_commands {
155156 setter ! ( set_cursor_position, Position ) ;
156157 setter ! ( set_ignore_cursor_events, bool ) ;
157158 setter ! ( start_dragging) ;
159+ setter ! ( start_resize_dragging, ResizeDirection ) ;
158160 setter ! ( set_progress_bar, ProgressBarState ) ;
159161 setter ! ( print) ;
160162
@@ -211,6 +213,107 @@ mod desktop_commands {
211213 }
212214 Ok ( ( ) )
213215 }
216+
217+ #[ derive( Debug ) ]
218+ enum HitTestResult {
219+ Client ,
220+ Left ,
221+ Right ,
222+ Top ,
223+ Bottom ,
224+ TopLeft ,
225+ TopRight ,
226+ BottomLeft ,
227+ BottomRight ,
228+ NoWhere ,
229+ }
230+
231+ impl HitTestResult {
232+ fn drag_resize_window < R : Runtime > ( & self , window : & Window < R > ) {
233+ let _ = window. start_resize_dragging ( match self {
234+ HitTestResult :: Left => ResizeDirection :: West ,
235+ HitTestResult :: Right => ResizeDirection :: East ,
236+ HitTestResult :: Top => ResizeDirection :: North ,
237+ HitTestResult :: Bottom => ResizeDirection :: South ,
238+ HitTestResult :: TopLeft => ResizeDirection :: NorthWest ,
239+ HitTestResult :: TopRight => ResizeDirection :: NorthEast ,
240+ HitTestResult :: BottomLeft => ResizeDirection :: SouthWest ,
241+ HitTestResult :: BottomRight => ResizeDirection :: SouthEast ,
242+ _ => unreachable ! ( ) ,
243+ } ) ;
244+ }
245+
246+ fn change_cursor < R : Runtime > ( & self , window : & Window < R > ) {
247+ let _ = window. set_cursor_icon ( match self {
248+ HitTestResult :: Left => CursorIcon :: WResize ,
249+ HitTestResult :: Right => CursorIcon :: EResize ,
250+ HitTestResult :: Top => CursorIcon :: NResize ,
251+ HitTestResult :: Bottom => CursorIcon :: SResize ,
252+ HitTestResult :: TopLeft => CursorIcon :: NwResize ,
253+ HitTestResult :: TopRight => CursorIcon :: NeResize ,
254+ HitTestResult :: BottomLeft => CursorIcon :: SwResize ,
255+ HitTestResult :: BottomRight => CursorIcon :: SeResize ,
256+ _ => CursorIcon :: Default ,
257+ } ) ;
258+ }
259+ }
260+
261+ fn hit_test ( window_size : PhysicalSize < u32 > , x : i32 , y : i32 , scale : f64 ) -> HitTestResult {
262+ const BORDERLESS_RESIZE_INSET : f64 = 5.0 ;
263+
264+ const CLIENT : isize = 0b0000 ;
265+ const LEFT : isize = 0b0001 ;
266+ const RIGHT : isize = 0b0010 ;
267+ const TOP : isize = 0b0100 ;
268+ const BOTTOM : isize = 0b1000 ;
269+ const TOPLEFT : isize = TOP | LEFT ;
270+ const TOPRIGHT : isize = TOP | RIGHT ;
271+ const BOTTOMLEFT : isize = BOTTOM | LEFT ;
272+ const BOTTOMRIGHT : isize = BOTTOM | RIGHT ;
273+
274+ let top = 0 ;
275+ let left = 0 ;
276+ let bottom = top + window_size. height as i32 ;
277+ let right = left + window_size. width as i32 ;
278+
279+ let inset = ( BORDERLESS_RESIZE_INSET * scale) as i32 ;
280+
281+ #[ rustfmt:: skip]
282+ let result =
283+ ( LEFT * ( if x < ( left + inset) { 1 } else { 0 } ) )
284+ | ( RIGHT * ( if x >= ( right - inset) { 1 } else { 0 } ) )
285+ | ( TOP * ( if y < ( top + inset) { 1 } else { 0 } ) )
286+ | ( BOTTOM * ( if y >= ( bottom - inset) { 1 } else { 0 } ) ) ;
287+
288+ match result {
289+ CLIENT => HitTestResult :: Client ,
290+ LEFT => HitTestResult :: Left ,
291+ RIGHT => HitTestResult :: Right ,
292+ TOP => HitTestResult :: Top ,
293+ BOTTOM => HitTestResult :: Bottom ,
294+ TOPLEFT => HitTestResult :: TopLeft ,
295+ TOPRIGHT => HitTestResult :: TopRight ,
296+ BOTTOMLEFT => HitTestResult :: BottomLeft ,
297+ BOTTOMRIGHT => HitTestResult :: BottomRight ,
298+ _ => HitTestResult :: NoWhere ,
299+ }
300+ }
301+
302+ #[ command( root = "crate" ) ]
303+ pub async fn on_mousemove < R : Runtime > ( window : Window < R > , x : i32 , y : i32 ) -> crate :: Result < ( ) > {
304+ hit_test ( window. inner_size ( ) ?, x, y, window. scale_factor ( ) ?) . change_cursor ( & window) ;
305+ Ok ( ( ) )
306+ }
307+
308+ #[ command( root = "crate" ) ]
309+ pub async fn on_mousedown < R : Runtime > ( window : Window < R > , x : i32 , y : i32 ) -> crate :: Result < ( ) > {
310+ let res = hit_test ( window. inner_size ( ) ?, x, y, window. scale_factor ( ) ?) ;
311+ match res {
312+ HitTestResult :: Client | HitTestResult :: NoWhere => { }
313+ _ => res. drag_resize_window ( & window) ,
314+ } ;
315+ Ok ( ( ) )
316+ }
214317}
215318
216319/// Initializes the plugin.
@@ -239,6 +342,21 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
239342 . into_string ( ) ,
240343 ) ;
241344
345+ #[ derive( Template ) ]
346+ #[ default_template( "./scripts/undecorated-resizing.js" ) ]
347+ struct UndecoratedResizingJavascript < ' a > {
348+ os_name : & ' a str ,
349+ }
350+
351+ init_script. push_str (
352+ & UndecoratedResizingJavascript {
353+ os_name : std:: env:: consts:: OS ,
354+ }
355+ . render_default ( & Default :: default ( ) )
356+ . unwrap ( )
357+ . into_string ( ) ,
358+ ) ;
359+
242360 #[ cfg( any( debug_assertions, feature = "devtools" ) ) ]
243361 {
244362 #[ derive( Template ) ]
@@ -320,13 +438,16 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
320438 desktop_commands:: set_cursor_position,
321439 desktop_commands:: set_ignore_cursor_events,
322440 desktop_commands:: start_dragging,
441+ desktop_commands:: start_resize_dragging,
323442 desktop_commands:: set_progress_bar,
324443 desktop_commands:: print,
325444 desktop_commands:: set_icon,
326445 desktop_commands:: toggle_maximize,
327446 desktop_commands:: internal_toggle_maximize,
328447 #[ cfg( any( debug_assertions, feature = "devtools" ) ) ]
329448 desktop_commands:: internal_toggle_devtools,
449+ desktop_commands:: on_mousemove,
450+ desktop_commands:: on_mousedown,
330451 ] ) ;
331452 handler ( invoke)
332453 }
0 commit comments