@ -8,6 +8,8 @@ use crate::Tray;
use serde_repr ::Deserialize_repr ;
use serde_repr ::Deserialize_repr ;
#[ cfg(feature = " tray-icon " ) ]
#[ cfg(feature = " tray-icon " ) ]
use tauri ::Manager ;
use tauri ::Manager ;
#[ cfg(feature = " tray-icon " ) ]
use tauri ::Monitor ;
use tauri ::{ PhysicalPosition , PhysicalSize , Result , Runtime , WebviewWindow , Window } ;
use tauri ::{ PhysicalPosition , PhysicalSize , Result , Runtime , WebviewWindow , Window } ;
/// Well known window positions.
/// Well known window positions.
@ -41,31 +43,129 @@ pub enum Position {
pub trait WindowExt {
pub trait WindowExt {
/// Moves the [`Window`] to the given [`Position`]
/// Moves the [`Window`] to the given [`Position`]
///
///
/// All positions are relative to the **current** screen.
/// All (non-tray) positions are relative to the **current** screen.
fn move_window ( & self , position : Position ) -> Result < ( ) > ;
fn move_window ( & self , position : Position ) -> Result < ( ) > ;
#[ cfg(feature = " tray-icon " ) ]
/// Moves the [`Window`] to the given [`Position`] while constraining Tray Positions to the dimensions of the screen.
///
/// All non-tray positions will not be constrained by this method.
///
/// This method allows you to position your Tray Windows without having them
/// cut off on the screen borders.
fn move_window_constrained ( & self , position : Position ) -> Result < ( ) > ;
}
}
impl < R : Runtime > WindowExt for WebviewWindow < R > {
impl < R : Runtime > WindowExt for WebviewWindow < R > {
fn move_window ( & self , pos : Position ) -> Result < ( ) > {
fn move_window ( & self , pos : Position ) -> Result < ( ) > {
self . as_ref ( ) . window ( ) . move_window ( pos )
self . as_ref ( ) . window ( ) . move_window ( pos )
}
}
#[ cfg(feature = " tray-icon " ) ]
fn move_window_constrained ( & self , position : Position ) -> Result < ( ) > {
self . as_ref ( ) . window ( ) . move_window_constrained ( position )
}
}
}
impl < R : Runtime > WindowExt for Window < R > {
impl < R : Runtime > WindowExt for Window < R > {
#[ cfg(feature = " tray-icon " ) ]
fn move_window_constrained ( & self , position : Position ) -> Result < ( ) > {
// Diverge to basic move_window, if the position is not a tray position
if ! matches! (
position ,
Position ::TrayLeft
| Position ::TrayBottomLeft
| Position ::TrayRight
| Position ::TrayBottomRight
| Position ::TrayCenter
| Position ::TrayBottomCenter
) {
return self . move_window ( position ) ;
}
let window_position = calculate_position ( self , position ) ? ;
let monitor = get_monitor_for_tray_icon ( self ) ? ;
if let Some ( monitor ) = monitor {
let monitor_size = monitor . size ( ) ;
let monitor_position = monitor . position ( ) ;
let window_size = self . outer_size ( ) ? ;
let right_border_monitor = monitor_position . x as f64 + monitor_size . width as f64 ;
let left_border_monitor = monitor_position . x as f64 ;
let right_border_window = window_position . x as f64 + window_size . width as f64 ;
let left_border_window = window_position . x as f64 ;
let constrained_x = if left_border_window < left_border_monitor {
left_border_monitor
} else if right_border_window > right_border_monitor {
right_border_monitor - window_size . width as f64
} else {
window_position . x as f64
} ;
let bottom_border_monitor = monitor_position . y as f64 + monitor_size . height as f64 ;
let top_border_monitor = monitor_position . y as f64 ;
let bottom_border_window = window_position . y as f64 + window_size . height as f64 ;
let top_border_window = window_position . y as f64 ;
let constrained_y = if top_border_window < top_border_monitor {
top_border_monitor
} else if bottom_border_window > bottom_border_monitor {
bottom_border_monitor - window_size . height as f64
} else {
window_position . y as f64
} ;
self . set_position ( PhysicalPosition ::new ( constrained_x , constrained_y ) ) ? ;
} else {
// Fallback on non constrained positioning
self . set_position ( window_position ) ? ;
}
Ok ( ( ) )
}
fn move_window ( & self , pos : Position ) -> Result < ( ) > {
fn move_window ( & self , pos : Position ) -> Result < ( ) > {
let position = calculate_position ( self , pos ) ? ;
self . set_position ( position )
}
}
#[ cfg(feature = " tray-icon " ) ]
/// Retrieve the monitor, where the tray icon is located on.
fn get_monitor_for_tray_icon < R : Runtime > ( window : & Window < R > ) -> Result < Option < Monitor > > {
let tray_position = window
. state ::< Tray > ( )
. 0
. lock ( )
. unwrap ( )
. map ( | ( pos , _ ) | pos )
. unwrap_or_default ( ) ;
window . monitor_from_point ( tray_position . x , tray_position . y )
}
/// Calculate the top-left position of the window based on the given
/// [`Position`].
fn calculate_position < R : Runtime > (
window : & Window < R > ,
pos : Position ,
) -> Result < PhysicalPosition < i32 > > {
use Position ::* ;
use Position ::* ;
let screen = self . current_monitor ( ) ? . unwrap ( ) ;
let screen = window . current_monitor ( ) ? . unwrap ( ) ;
// Only use the screen_position for the Tray independent positioning,
// because a tray event may not be called on the currently active monitor.
let screen_position = screen . position ( ) ;
let screen_position = screen . position ( ) ;
let screen_size = PhysicalSize ::< i32 > {
let screen_size = PhysicalSize ::< i32 > {
width : screen . size ( ) . width as i32 ,
width : screen . size ( ) . width as i32 ,
height : screen . size ( ) . height as i32 ,
height : screen . size ( ) . height as i32 ,
} ;
} ;
let window_size = PhysicalSize ::< i32 > {
let window_size = PhysicalSize ::< i32 > {
width : self . outer_size ( ) ? . width as i32 ,
width : window . outer_size ( ) ? . width as i32 ,
height : self . outer_size ( ) ? . height as i32 ,
height : window . outer_size ( ) ? . height as i32 ,
} ;
} ;
#[ cfg(feature = " tray-icon " ) ]
#[ cfg(feature = " tray-icon " ) ]
let ( tray_position , tray_size ) = self
let ( tray_position , tray_size ) = window
. state ::< Tray > ( )
. state ::< Tray > ( )
. 0
. 0
. lock ( )
. lock ( )
@ -114,9 +214,7 @@ impl<R: Runtime> WindowExt for Window<R> {
} ,
} ,
#[ cfg(feature = " tray-icon " ) ]
#[ cfg(feature = " tray-icon " ) ]
TrayLeft = > {
TrayLeft = > {
if let ( Some ( ( tray_x , tray_y ) ) , Some ( ( _ , _tray_height ) ) ) =
if let ( Some ( ( tray_x , tray_y ) ) , Some ( ( _ , _tray_height ) ) ) = ( tray_position , tray_size ) {
( tray_position , tray_size )
{
let y = tray_y - window_size . height ;
let y = tray_y - window_size . height ;
// Choose y value based on the target OS
// Choose y value based on the target OS
#[ cfg(target_os = " windows " ) ]
#[ cfg(target_os = " windows " ) ]
@ -164,8 +262,7 @@ impl<R: Runtime> WindowExt for Window<R> {
}
}
#[ cfg(feature = " tray-icon " ) ]
#[ cfg(feature = " tray-icon " ) ]
TrayBottomRight = > {
TrayBottomRight = > {
if let ( Some ( ( tray_x , tray_y ) ) , Some ( ( tray_width , _ ) ) ) = ( tray_position , tray_size )
if let ( Some ( ( tray_x , tray_y ) ) , Some ( ( tray_width , _ ) ) ) = ( tray_position , tray_size ) {
{
PhysicalPosition {
PhysicalPosition {
x : tray_x + tray_width ,
x : tray_x + tray_width ,
y : tray_y ,
y : tray_y ,
@ -195,8 +292,7 @@ impl<R: Runtime> WindowExt for Window<R> {
}
}
#[ cfg(feature = " tray-icon " ) ]
#[ cfg(feature = " tray-icon " ) ]
TrayBottomCenter = > {
TrayBottomCenter = > {
if let ( Some ( ( tray_x , tray_y ) ) , Some ( ( tray_width , _ ) ) ) = ( tray_position , tray_size )
if let ( Some ( ( tray_x , tray_y ) ) , Some ( ( tray_width , _ ) ) ) = ( tray_position , tray_size ) {
{
PhysicalPosition {
PhysicalPosition {
x : tray_x + ( tray_width / 2 ) - ( window_size . width / 2 ) ,
x : tray_x + ( tray_width / 2 ) - ( window_size . width / 2 ) ,
y : tray_y ,
y : tray_y ,
@ -207,6 +303,5 @@ impl<R: Runtime> WindowExt for Window<R> {
}
}
} ;
} ;
self . set_position ( tauri ::Position ::Physical ( physical_pos ) )
Ok ( physical_pos )
}
}
}