Browse Source

refactor(core): add window getters, physical & logical sizes/positions (#1723)

Lucas Fernandes Nogueira 4 years ago
parent
commit
6bfac866a7

+ 6 - 0
.changes/refactor-window-management.md

@@ -0,0 +1,6 @@
+---
+"api": patch
+"tauri": patch
+---
+
+The window management API was refactored: removed `setX`, `setY`, `setWidth`, `setHeight` APIs, renamed `resize` to `setSize` and the size and position APIs now allow defining both logical and physical values.

+ 6 - 0
.changes/window-getters.md

@@ -0,0 +1,6 @@
+---
+"api": patch
+"tauri": patch
+---
+
+Adds window getters.

File diff suppressed because it is too large
+ 0 - 0
core/tauri/scripts/bundle.js


+ 49 - 67
core/tauri/src/endpoints/window.rs

@@ -4,7 +4,12 @@
 
 #[cfg(window_create)]
 use crate::Manager;
-use crate::{api::config::WindowConfig, endpoints::InvokeResponse, Params, Window};
+use crate::{
+  api::config::WindowConfig,
+  endpoints::InvokeResponse,
+  runtime::window::dpi::{Position, Size},
+  Params, Window,
+};
 use serde::Deserialize;
 
 use crate::Icon;
@@ -28,17 +33,25 @@ impl From<IconDto> for Icon {
 
 /// The API descriptor.
 #[derive(Deserialize)]
-#[serde(tag = "cmd", rename_all = "camelCase")]
+#[serde(tag = "cmd", content = "data", rename_all = "camelCase")]
 pub enum Cmd {
   CreateWebview {
     options: WindowConfig,
   },
-  SetResizable {
-    resizable: bool,
-  },
-  SetTitle {
-    title: String,
-  },
+  // Getters
+  ScaleFactor,
+  InnerPosition,
+  OuterPosition,
+  InnerSize,
+  OuterSize,
+  IsFullscreen,
+  IsMaximized,
+  CurrentMonitor,
+  PrimaryMonitor,
+  AvailableMonitors,
+  // Setters
+  SetResizable(bool),
+  SetTitle(String),
   Maximize,
   Unmaximize,
   Minimize,
@@ -46,46 +59,14 @@ pub enum Cmd {
   Show,
   Hide,
   Close,
-  SetDecorations {
-    decorations: bool,
-  },
-  #[serde(rename_all = "camelCase")]
-  SetAlwaysOnTop {
-    always_on_top: bool,
-  },
-  SetWidth {
-    width: f64,
-  },
-  SetHeight {
-    height: f64,
-  },
-  Resize {
-    width: f64,
-    height: f64,
-  },
+  SetDecorations(bool),
   #[serde(rename_all = "camelCase")]
-  SetMinSize {
-    min_width: f64,
-    min_height: f64,
-  },
-  #[serde(rename_all = "camelCase")]
-  SetMaxSize {
-    max_width: f64,
-    max_height: f64,
-  },
-  SetX {
-    x: f64,
-  },
-  SetY {
-    y: f64,
-  },
-  SetPosition {
-    x: f64,
-    y: f64,
-  },
-  SetFullscreen {
-    fullscreen: bool,
-  },
+  SetAlwaysOnTop(bool),
+  SetSize(Size),
+  SetMinSize(Option<Size>),
+  SetMaxSize(Option<Size>),
+  SetPosition(Position),
+  SetFullscreen(bool),
   SetIcon {
     icon: IconDto,
   },
@@ -135,9 +116,20 @@ impl Cmd {
             }),
           )?;
         }
-
-        Self::SetResizable { resizable } => window.set_resizable(resizable)?,
-        Self::SetTitle { title } => window.set_title(&title)?,
+        // Getters
+        Self::ScaleFactor => return Ok(window.scale_factor()?.into()),
+        Self::InnerPosition => return Ok(window.inner_position()?.into()),
+        Self::OuterPosition => return Ok(window.outer_position()?.into()),
+        Self::InnerSize => return Ok(window.inner_size()?.into()),
+        Self::OuterSize => return Ok(window.outer_size()?.into()),
+        Self::IsFullscreen => return Ok(window.is_fullscreen()?.into()),
+        Self::IsMaximized => return Ok(window.is_maximized()?.into()),
+        Self::CurrentMonitor => return Ok(window.current_monitor()?.into()),
+        Self::PrimaryMonitor => return Ok(window.primary_monitor()?.into()),
+        Self::AvailableMonitors => return Ok(window.available_monitors()?.into()),
+        // Setters
+        Self::SetResizable(resizable) => window.set_resizable(resizable)?,
+        Self::SetTitle(title) => window.set_title(&title)?,
         Self::Maximize => window.maximize()?,
         Self::Unmaximize => window.unmaximize()?,
         Self::Minimize => window.minimize()?,
@@ -145,23 +137,13 @@ impl Cmd {
         Self::Show => window.show()?,
         Self::Hide => window.hide()?,
         Self::Close => window.close()?,
-        Self::SetDecorations { decorations } => window.set_decorations(decorations)?,
-        Self::SetAlwaysOnTop { always_on_top } => window.set_always_on_top(always_on_top)?,
-        Self::SetWidth { width } => window.set_width(width)?,
-        Self::SetHeight { height } => window.set_height(height)?,
-        Self::Resize { width, height } => window.resize(width, height)?,
-        Self::SetMinSize {
-          min_width,
-          min_height,
-        } => window.set_min_size(min_width, min_height)?,
-        Self::SetMaxSize {
-          max_width,
-          max_height,
-        } => window.set_max_size(max_width, max_height)?,
-        Self::SetX { x } => window.set_x(x)?,
-        Self::SetY { y } => window.set_y(y)?,
-        Self::SetPosition { x, y } => window.set_position(x, y)?,
-        Self::SetFullscreen { fullscreen } => window.set_fullscreen(fullscreen)?,
+        Self::SetDecorations(decorations) => window.set_decorations(decorations)?,
+        Self::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top)?,
+        Self::SetSize(size) => window.set_size(size)?,
+        Self::SetMinSize(size) => window.set_min_size(size)?,
+        Self::SetMaxSize(size) => window.set_max_size(size)?,
+        Self::SetPosition(position) => window.set_position(position)?,
+        Self::SetFullscreen(fullscreen) => window.set_fullscreen(fullscreen)?,
         Self::SetIcon { icon } => window.set_icon(icon.into())?,
         Self::StartDragging => window.start_dragging()?,
       }

+ 5 - 1
core/tauri/src/lib.rs

@@ -61,8 +61,12 @@ pub use {
   },
   self::runtime::app::{App, Builder},
   self::runtime::flavors::wry::Wry,
+  self::runtime::monitor::Monitor,
   self::runtime::webview::{WebviewAttributes, WindowBuilder},
-  self::runtime::window::export::Window,
+  self::runtime::window::export::{
+    dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size},
+    Window,
+  },
   self::state::{State, StateManager},
 };
 

+ 225 - 101
core/tauri/src/runtime/flavors/wry.rs

@@ -11,8 +11,11 @@ use crate::{
       FileDropEvent, FileDropHandler, RpcRequest, WebviewRpcHandler, WindowBuilder,
       WindowBuilderBase,
     },
-    window::{DetachedWindow, PendingWindow},
-    Dispatch, Params, Runtime,
+    window::{
+      dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
+      DetachedWindow, PendingWindow,
+    },
+    Dispatch, Monitor, Params, Runtime,
   },
   Icon,
 };
@@ -20,9 +23,14 @@ use crate::{
 use image::{GenericImageView, Pixel};
 use wry::{
   application::{
-    dpi::{LogicalPosition, LogicalSize, Size},
+    dpi::{
+      LogicalPosition as WryLogicalPosition, LogicalSize as WryLogicalSize,
+      PhysicalPosition as WryPhysicalPosition, PhysicalSize as WryPhysicalSize,
+      Position as WryPosition, Size as WrySize,
+    },
     event::{Event, WindowEvent},
     event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget},
+    monitor::MonitorHandle,
     window::{Fullscreen, Icon as WindowIcon, Window, WindowBuilder as WryWindowBuilder, WindowId},
   },
   webview::{
@@ -80,6 +88,89 @@ impl TryFrom<Icon> for WryIcon {
   }
 }
 
+impl From<MonitorHandle> for Monitor {
+  fn from(monitor: MonitorHandle) -> Monitor {
+    Self {
+      name: monitor.name(),
+      position: monitor.position().into(),
+      size: monitor.size().into(),
+      scale_factor: monitor.scale_factor(),
+    }
+  }
+}
+
+impl<T> From<WryPhysicalPosition<T>> for PhysicalPosition<T> {
+  fn from(position: WryPhysicalPosition<T>) -> Self {
+    Self {
+      x: position.x,
+      y: position.y,
+    }
+  }
+}
+
+impl<T> From<PhysicalPosition<T>> for WryPhysicalPosition<T> {
+  fn from(position: PhysicalPosition<T>) -> Self {
+    Self {
+      x: position.x,
+      y: position.y,
+    }
+  }
+}
+
+impl<T> From<LogicalPosition<T>> for WryLogicalPosition<T> {
+  fn from(position: LogicalPosition<T>) -> Self {
+    Self {
+      x: position.x,
+      y: position.y,
+    }
+  }
+}
+
+impl<T> From<WryPhysicalSize<T>> for PhysicalSize<T> {
+  fn from(size: WryPhysicalSize<T>) -> Self {
+    Self {
+      width: size.width,
+      height: size.height,
+    }
+  }
+}
+
+impl<T> From<PhysicalSize<T>> for WryPhysicalSize<T> {
+  fn from(size: PhysicalSize<T>) -> Self {
+    Self {
+      width: size.width,
+      height: size.height,
+    }
+  }
+}
+
+impl<T> From<LogicalSize<T>> for WryLogicalSize<T> {
+  fn from(size: LogicalSize<T>) -> Self {
+    Self {
+      width: size.width,
+      height: size.height,
+    }
+  }
+}
+
+impl From<Size> for WrySize {
+  fn from(size: Size) -> Self {
+    match size {
+      Size::Logical(s) => Self::Logical(s.into()),
+      Size::Physical(s) => Self::Physical(s.into()),
+    }
+  }
+}
+
+impl From<Position> for WryPosition {
+  fn from(position: Position) -> Self {
+    match position {
+      Position::Logical(s) => Self::Logical(s.into()),
+      Position::Physical(s) => Self::Physical(s.into()),
+    }
+  }
+}
+
 impl WindowBuilderBase for WryWindowBuilder {}
 impl WindowBuilder for WryWindowBuilder {
   fn new() -> Self {
@@ -112,19 +203,19 @@ impl WindowBuilder for WryWindowBuilder {
   }
 
   fn position(self, x: f64, y: f64) -> Self {
-    self.with_position(LogicalPosition::new(x, y))
+    self.with_position(WryLogicalPosition::new(x, y))
   }
 
   fn inner_size(self, width: f64, height: f64) -> Self {
-    self.with_inner_size(LogicalSize::new(width, height))
+    self.with_inner_size(WryLogicalSize::new(width, height))
   }
 
   fn min_inner_size(self, min_width: f64, min_height: f64) -> Self {
-    self.with_min_inner_size(Size::new(LogicalSize::new(min_width, min_height)))
+    self.with_min_inner_size(WryLogicalSize::new(min_width, min_height))
   }
 
   fn max_inner_size(self, max_width: f64, max_height: f64) -> Self {
-    self.with_max_inner_size(Size::new(LogicalSize::new(max_width, max_height)))
+    self.with_max_inner_size(WryLogicalSize::new(max_width, max_height))
   }
 
   fn resizable(self, resizable: bool) -> Self {
@@ -193,6 +284,18 @@ impl From<WryFileDropEvent> for FileDropEvent {
 
 #[derive(Debug, Clone)]
 enum WindowMessage {
+  // Getters
+  ScaleFactor(Sender<f64>),
+  InnerPosition(Sender<crate::Result<PhysicalPosition<i32>>>),
+  OuterPosition(Sender<crate::Result<PhysicalPosition<i32>>>),
+  InnerSize(Sender<PhysicalSize<u32>>),
+  OuterSize(Sender<PhysicalSize<u32>>),
+  IsFullscreen(Sender<bool>),
+  IsMaximized(Sender<bool>),
+  CurrentMonitor(Sender<Option<MonitorHandle>>),
+  PrimaryMonitor(Sender<Option<MonitorHandle>>),
+  AvailableMonitors(Sender<Vec<MonitorHandle>>),
+  // Setters
   SetResizable(bool),
   SetTitle(String),
   Maximize,
@@ -204,14 +307,10 @@ enum WindowMessage {
   Close,
   SetDecorations(bool),
   SetAlwaysOnTop(bool),
-  SetWidth(f64),
-  SetHeight(f64),
-  Resize { width: f64, height: f64 },
-  SetMinSize { min_width: f64, min_height: f64 },
-  SetMaxSize { max_width: f64, max_height: f64 },
-  SetX(f64),
-  SetY(f64),
-  SetPosition { x: f64, y: f64 },
+  SetSize(Size),
+  SetMinSize(Option<Size>),
+  SetMaxSize(Option<Size>),
+  SetPosition(Position),
   SetFullscreen(bool),
   SetIcon(WindowIcon),
   DragWindow,
@@ -237,6 +336,36 @@ pub struct WryDispatcher {
   task_tx: Sender<MainThreadTask>,
 }
 
+macro_rules! dispatcher_getter {
+  ($self: ident, $message: expr) => {{
+    let (tx, rx) = channel();
+    $self
+      .proxy
+      .send_event(Message::Window($self.window_id, $message(tx)))
+      .map_err(|_| crate::Error::FailedToSendMessage)?;
+    rx.recv().unwrap()
+  }};
+}
+
+macro_rules! window_result_getter {
+  ($window: ident, $tx: ident, $call: ident) => {
+    $tx
+      .send(
+        $window
+          .$call()
+          .map(Into::into)
+          .map_err(|_| crate::Error::FailedToSendMessage),
+      )
+      .unwrap()
+  };
+}
+
+macro_rules! window_getter {
+  ($window: ident, $tx: ident, $call: ident) => {
+    $tx.send($window.$call().into()).unwrap()
+  };
+}
+
 impl Dispatch for WryDispatcher {
   type Runtime = Wry;
   type WindowBuilder = WryWindowBuilder;
@@ -248,6 +377,53 @@ impl Dispatch for WryDispatcher {
       .map_err(|_| crate::Error::FailedToSendMessage)
   }
 
+  // GETTERS
+
+  fn scale_factor(&self) -> crate::Result<f64> {
+    Ok(dispatcher_getter!(self, WindowMessage::ScaleFactor))
+  }
+
+  fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
+    dispatcher_getter!(self, WindowMessage::InnerPosition)
+  }
+
+  fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
+    dispatcher_getter!(self, WindowMessage::OuterPosition)
+  }
+
+  fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
+    Ok(dispatcher_getter!(self, WindowMessage::InnerSize))
+  }
+
+  fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
+    Ok(dispatcher_getter!(self, WindowMessage::OuterSize))
+  }
+
+  fn is_fullscreen(&self) -> crate::Result<bool> {
+    Ok(dispatcher_getter!(self, WindowMessage::IsFullscreen))
+  }
+
+  fn is_maximized(&self) -> crate::Result<bool> {
+    Ok(dispatcher_getter!(self, WindowMessage::IsMaximized))
+  }
+
+  fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
+    Ok(dispatcher_getter!(self, WindowMessage::CurrentMonitor).map(Into::into))
+  }
+
+  fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
+    Ok(dispatcher_getter!(self, WindowMessage::PrimaryMonitor).map(Into::into))
+  }
+
+  fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
+    Ok(
+      dispatcher_getter!(self, WindowMessage::AvailableMonitors)
+        .into_iter()
+        .map(Into::into)
+        .collect(),
+    )
+  }
+
   fn create_window<M: Params<Runtime = Self::Runtime>>(
     &mut self,
     pending: PendingWindow<M>,
@@ -363,82 +539,42 @@ impl Dispatch for WryDispatcher {
       .map_err(|_| crate::Error::FailedToSendMessage)
   }
 
-  fn set_width(&self, width: f64) -> crate::Result<()> {
-    self
-      .proxy
-      .send_event(Message::Window(
-        self.window_id,
-        WindowMessage::SetWidth(width),
-      ))
-      .map_err(|_| crate::Error::FailedToSendMessage)
-  }
-
-  fn set_height(&self, height: f64) -> crate::Result<()> {
-    self
-      .proxy
-      .send_event(Message::Window(
-        self.window_id,
-        WindowMessage::SetHeight(height),
-      ))
-      .map_err(|_| crate::Error::FailedToSendMessage)
-  }
-
-  fn resize(&self, width: f64, height: f64) -> crate::Result<()> {
+  fn set_size(&self, size: Size) -> crate::Result<()> {
     self
       .proxy
       .send_event(Message::Window(
         self.window_id,
-        WindowMessage::Resize { width, height },
+        WindowMessage::SetSize(size),
       ))
       .map_err(|_| crate::Error::FailedToSendMessage)
   }
 
-  fn set_min_size(&self, min_width: f64, min_height: f64) -> crate::Result<()> {
+  fn set_min_size(&self, size: Option<Size>) -> crate::Result<()> {
     self
       .proxy
       .send_event(Message::Window(
         self.window_id,
-        WindowMessage::SetMinSize {
-          min_width,
-          min_height,
-        },
+        WindowMessage::SetMinSize(size),
       ))
       .map_err(|_| crate::Error::FailedToSendMessage)
   }
 
-  fn set_max_size(&self, max_width: f64, max_height: f64) -> crate::Result<()> {
+  fn set_max_size(&self, size: Option<Size>) -> crate::Result<()> {
     self
       .proxy
       .send_event(Message::Window(
         self.window_id,
-        WindowMessage::SetMaxSize {
-          max_width,
-          max_height,
-        },
+        WindowMessage::SetMaxSize(size),
       ))
       .map_err(|_| crate::Error::FailedToSendMessage)
   }
 
-  fn set_x(&self, x: f64) -> crate::Result<()> {
-    self
-      .proxy
-      .send_event(Message::Window(self.window_id, WindowMessage::SetX(x)))
-      .map_err(|_| crate::Error::FailedToSendMessage)
-  }
-
-  fn set_y(&self, y: f64) -> crate::Result<()> {
-    self
-      .proxy
-      .send_event(Message::Window(self.window_id, WindowMessage::SetY(y)))
-      .map_err(|_| crate::Error::FailedToSendMessage)
-  }
-
-  fn set_position(&self, x: f64, y: f64) -> crate::Result<()> {
+  fn set_position(&self, position: Position) -> crate::Result<()> {
     self
       .proxy
       .send_event(Message::Window(
         self.window_id,
-        WindowMessage::SetPosition { x, y },
+        WindowMessage::SetPosition(position),
       ))
       .map_err(|_| crate::Error::FailedToSendMessage)
   }
@@ -563,6 +699,24 @@ impl Runtime for Wry {
             if let Some(webview) = webviews.get_mut(&id) {
               let window = webview.window();
               match window_message {
+                // Getters
+                WindowMessage::ScaleFactor(tx) => window_getter!(window, tx, scale_factor),
+                WindowMessage::InnerPosition(tx) => {
+                  window_result_getter!(window, tx, inner_position)
+                }
+                WindowMessage::OuterPosition(tx) => {
+                  window_result_getter!(window, tx, outer_position)
+                }
+                WindowMessage::InnerSize(tx) => window_getter!(window, tx, inner_size),
+                WindowMessage::OuterSize(tx) => window_getter!(window, tx, outer_size),
+                WindowMessage::IsFullscreen(tx) => tx.send(window.fullscreen().is_some()).unwrap(),
+                WindowMessage::IsMaximized(tx) => window_getter!(window, tx, is_maximized),
+                WindowMessage::CurrentMonitor(tx) => window_getter!(window, tx, current_monitor),
+                WindowMessage::PrimaryMonitor(tx) => window_getter!(window, tx, primary_monitor),
+                WindowMessage::AvailableMonitors(tx) => {
+                  tx.send(window.available_monitors().collect()).unwrap()
+                }
+                // Setters
                 WindowMessage::SetResizable(resizable) => window.set_resizable(resizable),
                 WindowMessage::SetTitle(title) => window.set_title(&title),
                 WindowMessage::Maximize => window.set_maximized(true),
@@ -581,47 +735,17 @@ impl Runtime for Wry {
                 WindowMessage::SetAlwaysOnTop(always_on_top) => {
                   window.set_always_on_top(always_on_top)
                 }
-                WindowMessage::SetWidth(width) => {
-                  let mut size = window.inner_size().to_logical(window.scale_factor());
-                  size.width = width;
-                  window.set_inner_size(size);
-                }
-                WindowMessage::SetHeight(height) => {
-                  let mut size = window.inner_size().to_logical(window.scale_factor());
-                  size.height = height;
-                  window.set_inner_size(size);
-                }
-                WindowMessage::Resize { width, height } => {
-                  window.set_inner_size(LogicalSize::new(width, height));
-                }
-                WindowMessage::SetMinSize {
-                  min_width,
-                  min_height,
-                } => {
-                  window.set_min_inner_size(Some(LogicalSize::new(min_width, min_height)));
+                WindowMessage::SetSize(size) => {
+                  window.set_inner_size(WrySize::from(size));
                 }
-                WindowMessage::SetMaxSize {
-                  max_width,
-                  max_height,
-                } => {
-                  window.set_max_inner_size(Some(LogicalSize::new(max_width, max_height)));
+                WindowMessage::SetMinSize(size) => {
+                  window.set_min_inner_size(size.map(WrySize::from));
                 }
-                WindowMessage::SetX(x) => {
-                  if let Ok(outer_position) = window.outer_position() {
-                    let mut outer_position = outer_position.to_logical(window.scale_factor());
-                    outer_position.x = x;
-                    window.set_outer_position(outer_position);
-                  }
-                }
-                WindowMessage::SetY(y) => {
-                  if let Ok(outer_position) = window.outer_position() {
-                    let mut outer_position = outer_position.to_logical(window.scale_factor());
-                    outer_position.y = y;
-                    window.set_outer_position(outer_position);
-                  }
+                WindowMessage::SetMaxSize(size) => {
+                  window.set_max_inner_size(size.map(WrySize::from));
                 }
-                WindowMessage::SetPosition { x, y } => {
-                  window.set_outer_position(LogicalPosition::new(x, y))
+                WindowMessage::SetPosition(position) => {
+                  window.set_outer_position(WryPosition::from(position))
                 }
                 WindowMessage::SetFullscreen(fullscreen) => {
                   if fullscreen {

+ 51 - 16
core/tauri/src/runtime/mod.rs

@@ -12,10 +12,15 @@ use crate::{
 pub(crate) mod app;
 pub mod flavors;
 pub(crate) mod manager;
+/// Types useful for interacting with a user's monitors.
+pub mod monitor;
 pub mod tag;
 pub mod webview;
 pub mod window;
 
+use monitor::Monitor;
+use window::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
+
 /// The webview runtime interface.
 pub trait Runtime: Sized + 'static {
   /// The message dispatcher.
@@ -45,6 +50,48 @@ pub trait Dispatch: Clone + Send + Sized + 'static {
   /// Run a task on the main thread.
   fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()>;
 
+  // GETTERS
+
+  /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
+  fn scale_factor(&self) -> crate::Result<f64>;
+
+  /// Returns the position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop.
+  fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>>;
+
+  /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
+  fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>>;
+
+  /// Returns the physical size of the window's client area.
+  ///
+  /// The client area is the content of the window, excluding the title bar and borders.
+  fn inner_size(&self) -> crate::Result<PhysicalSize<u32>>;
+
+  /// Returns the physical size of the entire window.
+  ///
+  /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
+  fn outer_size(&self) -> crate::Result<PhysicalSize<u32>>;
+
+  /// Gets the window's current fullscreen state.
+  fn is_fullscreen(&self) -> crate::Result<bool>;
+
+  /// Gets the window's current maximized state.
+  fn is_maximized(&self) -> crate::Result<bool>;
+
+  /// Returns the monitor on which the window currently resides.
+  ///
+  /// Returns None if current monitor can't be detected.
+  fn current_monitor(&self) -> crate::Result<Option<Monitor>>;
+
+  /// Returns the primary monitor of the system.
+  ///
+  /// Returns None if it can't identify any monitor as a primary one.
+  fn primary_monitor(&self) -> crate::Result<Option<Monitor>>;
+
+  /// Returns the list of all the monitors available on the system.
+  fn available_monitors(&self) -> crate::Result<Vec<Monitor>>;
+
+  // SETTERS
+
   /// Create a new webview window.
   fn create_window<P: Params<Runtime = Self::Runtime>>(
     &mut self,
@@ -84,29 +131,17 @@ pub trait Dispatch: Clone + Send + Sized + 'static {
   /// Updates the window alwaysOnTop flag.
   fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()>;
 
-  /// Updates the window width.
-  fn set_width(&self, width: f64) -> crate::Result<()>;
-
-  /// Updates the window height.
-  fn set_height(&self, height: f64) -> crate::Result<()>;
-
   /// Resizes the window.
-  fn resize(&self, width: f64, height: f64) -> crate::Result<()>;
+  fn set_size(&self, size: Size) -> crate::Result<()>;
 
   /// Updates the window min size.
-  fn set_min_size(&self, min_width: f64, min_height: f64) -> crate::Result<()>;
+  fn set_min_size(&self, size: Option<Size>) -> crate::Result<()>;
 
   /// Updates the window max size.
-  fn set_max_size(&self, max_width: f64, max_height: f64) -> crate::Result<()>;
-
-  /// Updates the X position.
-  fn set_x(&self, x: f64) -> crate::Result<()>;
-
-  /// Updates the Y position.
-  fn set_y(&self, y: f64) -> crate::Result<()>;
+  fn set_max_size(&self, size: Option<Size>) -> crate::Result<()>;
 
   /// Updates the window position.
-  fn set_position(&self, x: f64, y: f64) -> crate::Result<()>;
+  fn set_position(&self, position: Position) -> crate::Result<()>;
 
   /// Updates the window fullscreen state.
   fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()>;

+ 39 - 0
core/tauri/src/runtime/monitor.rs

@@ -0,0 +1,39 @@
+// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+use super::window::dpi::{PhysicalPosition, PhysicalSize};
+use serde::Serialize;
+
+/// Monitor descriptor.
+#[derive(Debug, Clone, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Monitor {
+  pub(crate) name: Option<String>,
+  pub(crate) size: PhysicalSize<u32>,
+  pub(crate) position: PhysicalPosition<i32>,
+  pub(crate) scale_factor: f64,
+}
+
+impl Monitor {
+  /// Returns a human-readable name of the monitor.
+  /// Returns None if the monitor doesn't exist anymore.
+  pub fn name(&self) -> Option<&String> {
+    self.name.as_ref()
+  }
+
+  /// Returns the monitor's resolution.
+  pub fn size(&self) -> &PhysicalSize<u32> {
+    &self.size
+  }
+
+  /// Returns the top-left corner position of the monitor relative to the larger full screen area.
+  pub fn position(&self) -> &PhysicalPosition<i32> {
+    &self.position
+  }
+
+  /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
+  pub fn scale_factor(&self) -> f64 {
+    self.scale_factor
+  }
+}

+ 76 - 43
core/tauri/src/runtime/window.rs

@@ -11,7 +11,7 @@ use crate::{
   runtime::{
     tag::ToJsString,
     webview::{FileDropHandler, InvokePayload, WebviewAttributes, WebviewRpcHandler},
-    Dispatch, Runtime,
+    Dispatch, Monitor, Runtime,
   },
   sealed::{ManagerBase, RuntimeOrDispatch},
   Icon, Manager, Params, WindowBuilder,
@@ -20,6 +20,9 @@ use serde::Serialize;
 use serde_json::Value as JsonValue;
 use std::hash::{Hash, Hasher};
 
+/// UI scaling utilities.
+pub mod dpi;
+
 /// A webview window that has yet to be built.
 pub struct PendingWindow<M: Params> {
   /// The label that the window will be named.
@@ -113,10 +116,12 @@ impl<M: Params> PartialEq for DetachedWindow<M> {
 
 /// We want to export the runtime related window at the crate root, but not look like a re-export.
 pub(crate) mod export {
+  pub(crate) use super::dpi;
   use super::*;
   use crate::command::{CommandArg, CommandItem};
   use crate::runtime::{manager::WindowManager, tag::TagRef};
   use crate::{Invoke, InvokeError};
+  use dpi::{PhysicalPosition, PhysicalSize, Position, Size};
   use std::borrow::Borrow;
 
   /// A webview window managed by Tauri.
@@ -308,6 +313,68 @@ pub(crate) mod export {
       self.window.dispatcher.eval_script(js)
     }
 
+    // Getters
+
+    /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
+    pub fn scale_factor(&self) -> crate::Result<f64> {
+      self.window.dispatcher.scale_factor()
+    }
+
+    /// Returns the position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop.
+    pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
+      self.window.dispatcher.inner_position()
+    }
+
+    /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
+    pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
+      self.window.dispatcher.outer_position()
+    }
+
+    /// Returns the physical size of the window's client area.
+    ///
+    /// The client area is the content of the window, excluding the title bar and borders.
+    pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
+      self.window.dispatcher.inner_size()
+    }
+
+    /// Returns the physical size of the entire window.
+    ///
+    /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
+    pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
+      self.window.dispatcher.outer_size()
+    }
+
+    /// Gets the window's current fullscreen state.
+    pub fn is_fullscreen(&self) -> crate::Result<bool> {
+      self.window.dispatcher.is_fullscreen()
+    }
+
+    /// Gets the window's current maximized state.
+    pub fn is_maximized(&self) -> crate::Result<bool> {
+      self.window.dispatcher.is_maximized()
+    }
+
+    /// Returns the monitor on which the window currently resides.
+    ///
+    /// Returns None if current monitor can't be detected.
+    pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
+      self.window.dispatcher.current_monitor()
+    }
+
+    /// Returns the primary monitor of the system.
+    ///
+    /// Returns None if it can't identify any monitor as a primary one.
+    pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
+      self.window.dispatcher.primary_monitor()
+    }
+
+    /// Returns the list of all the monitors available on the system.
+    pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
+      self.window.dispatcher.available_monitors()
+    }
+
+    // Setters
+
     /// Determines if this window should be resizable.
     pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
       self.window.dispatcher.set_resizable(resizable)
@@ -365,58 +432,24 @@ pub(crate) mod export {
       self.window.dispatcher.set_always_on_top(always_on_top)
     }
 
-    /// Sets this window's width.
-    pub fn set_width(&self, width: impl Into<f64>) -> crate::Result<()> {
-      self.window.dispatcher.set_width(width.into())
-    }
-
-    /// Sets this window's height.
-    pub fn set_height(&self, height: impl Into<f64>) -> crate::Result<()> {
-      self.window.dispatcher.set_height(height.into())
-    }
-
     /// Resizes this window.
-    pub fn resize(&self, width: impl Into<f64>, height: impl Into<f64>) -> crate::Result<()> {
-      self.window.dispatcher.resize(width.into(), height.into())
+    pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
+      self.window.dispatcher.set_size(size.into())
     }
 
     /// Sets this window's minimum size.
-    pub fn set_min_size(
-      &self,
-      min_width: impl Into<f64>,
-      min_height: impl Into<f64>,
-    ) -> crate::Result<()> {
-      self
-        .window
-        .dispatcher
-        .set_min_size(min_width.into(), min_height.into())
+    pub fn set_min_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
+      self.window.dispatcher.set_min_size(size.map(|s| s.into()))
     }
 
     /// Sets this window's maximum size.
-    pub fn set_max_size(
-      &self,
-      max_width: impl Into<f64>,
-      max_height: impl Into<f64>,
-    ) -> crate::Result<()> {
-      self
-        .window
-        .dispatcher
-        .set_max_size(max_width.into(), max_height.into())
-    }
-
-    /// Sets this window's x position.
-    pub fn set_x(&self, x: impl Into<f64>) -> crate::Result<()> {
-      self.window.dispatcher.set_x(x.into())
-    }
-
-    /// Sets this window's y position.
-    pub fn set_y(&self, y: impl Into<f64>) -> crate::Result<()> {
-      self.window.dispatcher.set_y(y.into())
+    pub fn set_max_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
+      self.window.dispatcher.set_max_size(size.map(|s| s.into()))
     }
 
     /// Sets this window's position.
-    pub fn set_position(&self, x: impl Into<f64>, y: impl Into<f64>) -> crate::Result<()> {
-      self.window.dispatcher.set_position(x.into(), y.into())
+    pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
+      self.window.dispatcher.set_position(position.into())
     }
 
     /// Determines if this window should be fullscreen.

+ 168 - 0
core/tauri/src/runtime/window/dpi.rs

@@ -0,0 +1,168 @@
+// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+use serde::{Deserialize, Serialize};
+
+fn validate_scale_factor(scale_factor: f64) -> bool {
+  scale_factor.is_sign_positive() && scale_factor.is_normal()
+}
+
+/// A pixel definition. Must be created from a `f64` value.
+pub trait Pixel: Copy + Into<f64> {
+  /// Creates the pixel from the `f64` value.
+  fn from_f64(f: f64) -> Self;
+  /// Casts a pixel.
+  fn cast<P: Pixel>(self) -> P {
+    P::from_f64(self.into())
+  }
+}
+
+impl Pixel for u8 {
+  fn from_f64(f: f64) -> Self {
+    f.round() as u8
+  }
+}
+
+impl Pixel for u16 {
+  fn from_f64(f: f64) -> Self {
+    f.round() as u16
+  }
+}
+
+impl Pixel for u32 {
+  fn from_f64(f: f64) -> Self {
+    f.round() as u32
+  }
+}
+
+impl Pixel for i8 {
+  fn from_f64(f: f64) -> Self {
+    f.round() as i8
+  }
+}
+
+impl Pixel for i16 {
+  fn from_f64(f: f64) -> Self {
+    f.round() as i16
+  }
+}
+
+impl Pixel for i32 {
+  fn from_f64(f: f64) -> Self {
+    f.round() as i32
+  }
+}
+
+impl Pixel for f32 {
+  fn from_f64(f: f64) -> Self {
+    f as f32
+  }
+}
+
+impl Pixel for f64 {
+  #[allow(clippy::wrong_self_convention)]
+  fn from_f64(f: f64) -> Self {
+    f
+  }
+}
+
+/// A position represented in physical pixels.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PhysicalPosition<P> {
+  /// Vertical axis value.
+  pub x: P,
+  /// Horizontal axis value.
+  pub y: P,
+}
+
+impl<P: Pixel> PhysicalPosition<P> {
+  /// Converts the physical position to a logical one, using the scale factor.
+  #[inline]
+  pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalPosition<X> {
+    assert!(validate_scale_factor(scale_factor));
+    let x = self.x.into() / scale_factor;
+    let y = self.y.into() / scale_factor;
+    LogicalPosition { x, y }.cast()
+  }
+}
+
+/// A position represented in logical pixels.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LogicalPosition<P> {
+  /// Vertical axis value.
+  pub x: P,
+  /// Horizontal axis value.
+  pub y: P,
+}
+
+impl<T: Pixel> LogicalPosition<T> {
+  /// Casts the logical size to another pixel type.
+  #[inline]
+  pub fn cast<X: Pixel>(&self) -> LogicalPosition<X> {
+    LogicalPosition {
+      x: self.x.cast(),
+      y: self.y.cast(),
+    }
+  }
+}
+
+/// A position that's either physical or logical.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(tag = "type", content = "data")]
+pub enum Position {
+  /// Physical position.
+  Physical(PhysicalPosition<i32>),
+  /// Logical position.
+  Logical(LogicalPosition<f64>),
+}
+
+/// A size represented in physical pixels.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PhysicalSize<T> {
+  /// Width.
+  pub width: T,
+  /// Height.
+  pub height: T,
+}
+
+impl<T: Pixel> PhysicalSize<T> {
+  /// Converts the physical size to a logical one, applying the scale factor.
+  #[inline]
+  pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalSize<X> {
+    assert!(validate_scale_factor(scale_factor));
+    let width = self.width.into() / scale_factor;
+    let height = self.height.into() / scale_factor;
+    LogicalSize { width, height }.cast()
+  }
+}
+
+/// A size represented in logical pixels.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LogicalSize<T> {
+  /// Width.
+  pub width: T,
+  /// Height.
+  pub height: T,
+}
+
+impl<T: Pixel> LogicalSize<T> {
+  /// Casts the logical size to another pixel type.
+  #[inline]
+  pub fn cast<X: Pixel>(&self) -> LogicalSize<X> {
+    LogicalSize {
+      width: self.width.cast(),
+      height: self.height.cast(),
+    }
+  }
+}
+
+/// A size that's either physical or logical.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(tag = "type", content = "data")]
+pub enum Size {
+  /// Physical size.
+  Physical(PhysicalSize<u32>),
+  /// Logical size.
+  Logical(LogicalSize<f64>),
+}

File diff suppressed because it is too large
+ 0 - 0
examples/api/public/build/bundle.js


File diff suppressed because it is too large
+ 0 - 0
examples/api/public/build/bundle.js.map


+ 7 - 14
examples/api/src/components/Window.svelte

@@ -1,5 +1,5 @@
 <script>
-  import { appWindow, WebviewWindow } from "@tauri-apps/api/window";
+  import { appWindow, WebviewWindow, LogicalSize, LogicalPosition } from "@tauri-apps/api/window";
   import { open as openDialog } from "@tauri-apps/api/dialog";
   import { open } from "@tauri-apps/api/shell";
 
@@ -14,14 +14,10 @@
     hide,
     setDecorations,
     setAlwaysOnTop,
-    setWidth,
-    setHeight,
-    // resize,
+    setSize,
     setMinSize,
     setMaxSize,
-    setX,
-    setY,
-    // setPosition,
+    setPosition,
     setFullscreen,
     setIcon,
   } = appWindow;
@@ -79,17 +75,14 @@
 
   $: setResizable(resizable);
   $: maximized ? maximize() : unmaximize();
-  //$: setTransparent(transparent)
   $: setDecorations(decorations);
   $: setAlwaysOnTop(alwaysOnTop);
   $: setFullscreen(fullscreen);
 
-  $: setWidth(width);
-  $: setHeight(height);
-  $: minWidth && minHeight && setMinSize(minWidth, minHeight);
-  $: maxWidth && maxHeight && setMaxSize(maxWidth, maxHeight);
-  $: setX(x);
-  $: setY(y);
+  $: setSize(new LogicalSize(width, height));
+  $: minWidth && minHeight ? setMinSize(new LogicalSize(minWidth, minHeight)) : setMinSize(null);
+  $: maxWidth && maxHeight ? setMaxSize(new LogicalSize(maxWidth, maxHeight)) : setMaxSize(null);
+  $: setPosition(new LogicalPosition(x, y));
 </script>
 
 <div class="flex col">

+ 1 - 1
examples/api/yarn.lock

@@ -62,7 +62,7 @@
     estree-walker "^1.0.1"
     picomatch "^2.2.2"
 
-"@tauri-apps/api@link:../../tooling/api":
+"@tauri-apps/api@link:../../tooling/api/dist":
   version "0.0.0"
   uid ""
 

+ 259 - 95
tooling/api/src/window.ts

@@ -11,6 +11,76 @@ import { invokeTauriCommand } from './helpers/tauri'
 import { EventCallback, UnlistenFn, listen, once } from './event'
 import { emit } from './helpers/event'
 
+/** Allows you to retrieve information about a given monitor. */
+interface Monitor {
+  /** Human-readable name of the monitor */
+  name: string | null
+  /** The monitor's resolution. */
+  size: PhysicalSize
+  /** the Top-left corner position of the monitor relative to the larger full screen area. */
+  position: PhysicalPosition
+  /** The scale factor that can be used to map physical pixels to logical pixels. */
+  scaleFactor: number
+}
+
+/** A size represented in logical pixels. */
+class LogicalSize {
+  type = 'Logical'
+  width: number
+  height: number
+
+  constructor(width: number, height: number) {
+    this.width = width
+    this.height = height
+  }
+}
+
+/** A size represented in physical pixels. */
+class PhysicalSize {
+  type = 'Physical'
+  width: number
+  height: number
+
+  constructor(width: number, height: number) {
+    this.width = width
+    this.height = height
+  }
+
+  /** Converts the physical size to a logical one. */
+  toLogical(scaleFactor: number): LogicalSize {
+    return new LogicalSize(this.width / scaleFactor, this.height / scaleFactor)
+  }
+}
+
+/** A position represented in logical pixels. */
+class LogicalPosition {
+  type = 'Logical'
+  x: number
+  y: number
+
+  constructor(x: number, y: number) {
+    this.x = x
+    this.y = y
+  }
+}
+
+/** A position represented in physical pixels. */
+class PhysicalPosition {
+  type = 'Physical'
+  x: number
+  y: number
+
+  constructor(x: number, y: number) {
+    this.x = x
+    this.y = y
+  }
+
+  /** Converts the physical position to a logical one. */
+  toLogical(scaleFactor: number): LogicalPosition {
+    return new LogicalPosition(this.x / scaleFactor, this.y / scaleFactor)
+  }
+}
+
 /** @ignore */
 interface WindowDef {
   label: string
@@ -168,9 +238,11 @@ class WebviewWindow extends WebviewWindowHandle {
       __tauriModule: 'Window',
       message: {
         cmd: 'createWebview',
-        options: {
-          label,
-          ...options
+        data: {
+          options: {
+            label,
+            ...options
+          }
         }
       }
     })
@@ -196,6 +268,85 @@ class WebviewWindow extends WebviewWindowHandle {
  * Manage the current window object.
  */
 export class WindowManager {
+  // Getters
+  /** The scale factor that can be used to map physical pixels to logical pixels. */
+  async scaleFactor(): Promise<number> {
+    return invokeTauriCommand({
+      __tauriModule: 'Window',
+      message: {
+        cmd: 'scaleFactor'
+      }
+    })
+  }
+
+  /** The position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop. */
+  async innerPosition(): Promise<PhysicalPosition> {
+    return invokeTauriCommand({
+      __tauriModule: 'Window',
+      message: {
+        cmd: 'innerPosition'
+      }
+    })
+  }
+
+  /** The position of the top-left hand corner of the window relative to the top-left hand corner of the desktop. */
+  async outerPosition(): Promise<PhysicalPosition> {
+    return invokeTauriCommand({
+      __tauriModule: 'Window',
+      message: {
+        cmd: 'outerPosition'
+      }
+    })
+  }
+
+  /**
+   * The physical size of the window's client area.
+   * The client area is the content of the window, excluding the title bar and borders.
+   */
+  async innerSize(): Promise<PhysicalSize> {
+    return invokeTauriCommand({
+      __tauriModule: 'Window',
+      message: {
+        cmd: 'innerSize'
+      }
+    })
+  }
+
+  /**
+   * The physical size of the entire window.
+   * These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
+   */
+  async outerSize(): Promise<PhysicalSize> {
+    return invokeTauriCommand({
+      __tauriModule: 'Window',
+      message: {
+        cmd: 'outerSize'
+      }
+    })
+  }
+
+  /** Gets the window's current fullscreen state. */
+  async isFullscreen(): Promise<boolean> {
+    return invokeTauriCommand({
+      __tauriModule: 'Window',
+      message: {
+        cmd: 'isFullscreen'
+      }
+    })
+  }
+
+  /** Gets the window's current maximized state. */
+  async isMaximized(): Promise<boolean> {
+    return invokeTauriCommand({
+      __tauriModule: 'Window',
+      message: {
+        cmd: 'isMaximized'
+      }
+    })
+  }
+
+  // Setters
+
   /**
    * Updates the window resizable flag.
    *
@@ -207,7 +358,7 @@ export class WindowManager {
       __tauriModule: 'Window',
       message: {
         cmd: 'setResizable',
-        resizable
+        data: resizable
       }
     })
   }
@@ -223,7 +374,7 @@ export class WindowManager {
       __tauriModule: 'Window',
       message: {
         cmd: 'setTitle',
-        title
+        data: title
       }
     })
   }
@@ -337,7 +488,7 @@ export class WindowManager {
       __tauriModule: 'Window',
       message: {
         cmd: 'setDecorations',
-        decorations
+        data: decorations
       }
     })
   }
@@ -353,39 +504,7 @@ export class WindowManager {
       __tauriModule: 'Window',
       message: {
         cmd: 'setAlwaysOnTop',
-        alwaysOnTop
-      }
-    })
-  }
-
-  /**
-   * Sets the window width.
-   *
-   * @param width The new window width.
-   * @returns A promise indicating the success or failure of the operation.
-   */
-  async setWidth(width: number): Promise<void> {
-    return invokeTauriCommand({
-      __tauriModule: 'Window',
-      message: {
-        cmd: 'setWidth',
-        width
-      }
-    })
-  }
-
-  /**
-   * Sets the window height.
-   *
-   * @param height The new window height.
-   * @returns A promise indicating the success or failure of the operation.
-   */
-  async setHeight(height: number): Promise<void> {
-    return invokeTauriCommand({
-      __tauriModule: 'Window',
-      message: {
-        cmd: 'setHeight',
-        height
+        data: alwaysOnTop
       }
     })
   }
@@ -393,17 +512,21 @@ export class WindowManager {
   /**
    * Resizes the window.
    *
-   * @param width The new window width.
-   * @param height The new window height.
+   * @param size The logical or physical size.
    * @returns A promise indicating the success or failure of the operation.
    */
-  async resize(width: number, height: number): Promise<void> {
+  async setSize(size: LogicalSize | PhysicalSize): Promise<void> {
     return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
-        cmd: 'resize',
-        width,
-        height
+        cmd: 'setSize',
+        data: {
+          type: size.type,
+          data: {
+            width: size.width,
+            height: size.height
+          }
+        }
       }
     })
   }
@@ -411,17 +534,25 @@ export class WindowManager {
   /**
    * Sets the window min size.
    *
-   * @param minWidth The new window min width.
-   * @param minHeight The new window min height.
+   * @param size The logical or physical size.
    * @returns A promise indicating the success or failure of the operation.
    */
-  async setMinSize(minWidth: number, minHeight: number): Promise<void> {
+  async setMinSize(
+    size: LogicalSize | PhysicalSize | undefined
+  ): Promise<void> {
     return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setMinSize',
-        minWidth,
-        minHeight
+        data: size
+          ? {
+              type: size.type,
+              data: {
+                width: size.width,
+                height: size.height
+              }
+            }
+          : null
       }
     })
   }
@@ -429,49 +560,25 @@ export class WindowManager {
   /**
    * Sets the window max size.
    *
-   * @param maxWidth The new window max width.
-   * @param maxHeight The new window max height.
+   * @param size The logical or physical size.
    * @returns A promise indicating the success or failure of the operation.
    */
-  async setMaxSize(maxWidth: number, maxHeight: number): Promise<void> {
+  async setMaxSize(
+    size: LogicalSize | PhysicalSize | undefined
+  ): Promise<void> {
     return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setMaxSize',
-        maxWidth,
-        maxHeight
-      }
-    })
-  }
-
-  /**
-   * Sets the window x position.
-   *
-   * @param x The new window x position.
-   * @returns A promise indicating the success or failure of the operation.
-   */
-  async setX(x: number): Promise<void> {
-    return invokeTauriCommand({
-      __tauriModule: 'Window',
-      message: {
-        cmd: 'setX',
-        x
-      }
-    })
-  }
-
-  /**
-   * Sets the window y position.
-   *
-   * @param y The new window y position.
-   * @returns A promise indicating the success or failure of the operation.
-   */
-  async setY(y: number): Promise<void> {
-    return invokeTauriCommand({
-      __tauriModule: 'Window',
-      message: {
-        cmd: 'setY',
-        y
+        data: size
+          ? {
+              type: size.type,
+              data: {
+                width: size.width,
+                height: size.height
+              }
+            }
+          : null
       }
     })
   }
@@ -479,17 +586,23 @@ export class WindowManager {
   /**
    * Sets the window position.
    *
-   * @param x The new window x position.
-   * @param y The new window y position.
+   * @param position The new position, in logical or physical pixels.
    * @returns A promise indicating the success or failure of the operation.
    */
-  async setPosition(x: number, y: number): Promise<void> {
+  async setPosition(
+    position: LogicalPosition | PhysicalPosition
+  ): Promise<void> {
     return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setPosition',
-        x,
-        y
+        data: {
+          type: position.type,
+          data: {
+            x: position.x,
+            y: position.y
+          }
+        }
       }
     })
   }
@@ -505,7 +618,7 @@ export class WindowManager {
       __tauriModule: 'Window',
       message: {
         cmd: 'setFullscreen',
-        fullscreen
+        data: fullscreen
       }
     })
   }
@@ -521,7 +634,9 @@ export class WindowManager {
       __tauriModule: 'Window',
       message: {
         cmd: 'setIcon',
-        icon
+        data: {
+          icon
+        }
       }
     })
   }
@@ -582,4 +697,53 @@ export interface WindowOptions {
   alwaysOnTop?: boolean
 }
 
-export { WebviewWindow, getCurrent, getAll, appWindow }
+/**
+ * Returns the monitor on which the window currently resides.
+ * Returns `null` if current monitor can't be detected.
+ */
+async function currentMonitor(): Promise<Monitor | null> {
+  return invokeTauriCommand({
+    __tauriModule: 'Window',
+    message: {
+      cmd: 'currentMonitor'
+    }
+  })
+}
+
+/**
+ * Returns the primary monitor of the system.
+ * Returns `null` if it can't identify any monitor as a primary one.
+ */
+async function primaryMonitor(): Promise<Monitor | null> {
+  return invokeTauriCommand({
+    __tauriModule: 'Window',
+    message: {
+      cmd: 'primaryMonitor'
+    }
+  })
+}
+
+/** Returns the list of all the monitors available on the system. */
+async function availableMonitors(): Promise<Monitor[]> {
+  return invokeTauriCommand({
+    __tauriModule: 'Window',
+    message: {
+      cmd: 'availableMonitors'
+    }
+  })
+}
+
+export {
+  WebviewWindow,
+  getCurrent,
+  getAll,
+  appWindow,
+  Monitor,
+  LogicalSize,
+  PhysicalSize,
+  LogicalPosition,
+  PhysicalPosition,
+  currentMonitor,
+  primaryMonitor,
+  availableMonitors
+}

Some files were not shown because too many files changed in this diff