Skip to content

Commit

Permalink
feat: add cursor_position getter (#9297)
Browse files Browse the repository at this point in the history
* feat: add `cursor_position` getter

closes #9250

* js api

* Update mod.rs

* fix build on iOS and android

* use existing wrapper

* fmt

* adjust wording

* update docs

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
  • Loading branch information
amrbashir and lucasfernog committed Apr 29, 2024
1 parent 5a213a4 commit 477bb8c
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changes/cursor_position.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'tauri': 'patch:feat'
---

Add `App/AppHandle/Window/Webview/WebviewWindow::cursor_position` getter to get the current cursor position.
5 changes: 5 additions & 0 deletions .changes/cursor_position_js.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tauri-apps/api': 'patch:feat'
---

Add `cursorPosition` function in `window` module to get the current cursor position.
22 changes: 22 additions & 0 deletions core/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2162,6 +2162,17 @@ impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
.collect()
}

fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
self
.context
.main_thread
.window_target
.cursor_position()
.map(PhysicalPositionWrapper)
.map(Into::into)
.map_err(|_| Error::FailedToGetCursorPosition)
}

#[cfg(target_os = "macos")]
fn show(&self) -> tauri_runtime::Result<()> {
send_user_message(
Expand Down Expand Up @@ -2409,6 +2420,17 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
.collect()
}

fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
self
.context
.main_thread
.window_target
.cursor_position()
.map(PhysicalPositionWrapper)
.map(Into::into)
.map_err(|_| Error::FailedToGetCursorPosition)
}

#[cfg(target_os = "macos")]
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
self
Expand Down
7 changes: 7 additions & 0 deletions core/tauri-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ pub enum Error {
/// Failed to get monitor on window operation.
#[error("failed to get monitor")]
FailedToGetMonitor,
/// Failed to get cursor position.
#[error("failed to get cursor position")]
FailedToGetCursorPosition,
#[error("Invalid header name: {0}")]
InvalidHeaderName(#[from] InvalidHeaderName),
#[error("Invalid header value: {0}")]
Expand Down Expand Up @@ -293,6 +296,8 @@ pub trait RuntimeHandle<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'st
fn primary_monitor(&self) -> Option<Monitor>;
fn available_monitors(&self) -> Vec<Monitor>;

fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;

/// Shows the application, but does not automatically focus it.
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
Expand Down Expand Up @@ -373,6 +378,8 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
fn primary_monitor(&self) -> Option<Monitor>;
fn available_monitors(&self) -> Vec<Monitor>;

fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;

/// Sets the activation policy for the application.
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
Expand Down
1 change: 1 addition & 0 deletions core/tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
("current_monitor", true),
("primary_monitor", true),
("available_monitors", true),
("cursor_position", true),
("theme", true),
// setters
("center", false),
Expand Down
2 changes: 2 additions & 0 deletions core/tauri/permissions/window/autogenerated/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
|`deny-create`|Denies the create command without any pre-configured scope.|
|`allow-current-monitor`|Enables the current_monitor command without any pre-configured scope.|
|`deny-current-monitor`|Denies the current_monitor command without any pre-configured scope.|
|`allow-cursor-position`|Enables the cursor_position command without any pre-configured scope.|
|`deny-cursor-position`|Denies the cursor_position command without any pre-configured scope.|
|`allow-destroy`|Enables the destroy command without any pre-configured scope.|
|`deny-destroy`|Denies the destroy command without any pre-configured scope.|
|`allow-hide`|Enables the hide command without any pre-configured scope.|
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/scripts/bundle.global.js

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions core/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,23 @@ macro_rules! shared_app_impl {
_ => unreachable!(),
})
}

/// Get the cursor position relative to the top-left hand corner of the desktop.
///
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
/// If the user uses a desktop with multiple monitors,
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
/// or the top-left of the leftmost monitor on X11.
///
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
Ok(match self.runtime() {
RuntimeOrDispatch::Runtime(h) => h.cursor_position()?,
RuntimeOrDispatch::RuntimeHandle(h) => h.cursor_position()?,
_ => unreachable!(),
})
}

/// Returns the default window icon.
pub fn default_window_icon(&self) -> Option<&Image<'_>> {
self.manager.window.default_icon.as_ref()
Expand Down
8 changes: 8 additions & 0 deletions core/tauri/src/test/mock_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ impl<T: UserEvent> RuntimeHandle<T> for MockRuntimeHandle {
{
todo!()
}

fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
Ok(PhysicalPosition::new(0.0, 0.0))
}
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -1152,4 +1156,8 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {

callback(RunEvent::Exit);
}

fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
Ok(PhysicalPosition::new(0.0, 0.0))
}
}
12 changes: 12 additions & 0 deletions core/tauri/src/webview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,18 @@ impl<R: Runtime> Webview<R> {
self.webview.dispatcher.print().map_err(Into::into)
}

/// Get the cursor position relative to the top-left hand corner of the desktop.
///
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
/// If the user uses a desktop with multiple monitors,
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
/// or the top-left of the leftmost monitor on X11.
///
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
self.app_handle.cursor_position()
}

/// Closes this webview.
pub fn close(&self) -> crate::Result<()> {
self.webview.dispatcher.close()?;
Expand Down
16 changes: 16 additions & 0 deletions core/tauri/src/webview/webview_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,22 @@ impl<R: Runtime> WebviewWindow<R> {
}
}

/// Desktop window getters.
#[cfg(desktop)]
impl<R: Runtime> WebviewWindow<R> {
/// Get the cursor position relative to the top-left hand corner of the desktop.
///
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
/// If the user uses a desktop with multiple monitors,
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
/// or the top-left of the leftmost monitor on X11.
///
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
self.webview.cursor_position()
}
}

/// Desktop window setters and actions.
#[cfg(desktop)]
impl<R: Runtime> WebviewWindow<R> {
Expand Down
16 changes: 16 additions & 0 deletions core/tauri/src/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,22 @@ impl<R: Runtime> Window<R> {
}
}

/// Desktop window getters.
#[cfg(desktop)]
impl<R: Runtime> Window<R> {
/// Get the cursor position relative to the top-left hand corner of the desktop.
///
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
/// If the user uses a desktop with multiple monitors,
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
/// or the top-left of the leftmost monitor on X11.
///
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
self.app_handle.cursor_position()
}
}

/// Desktop window setters and actions.
#[cfg(desktop)]
impl<R: Runtime> Window<R> {
Expand Down
2 changes: 2 additions & 0 deletions core/tauri/src/window/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ mod desktop_commands {
getter!(current_monitor, Option<Monitor>);
getter!(primary_monitor, Option<Monitor>);
getter!(available_monitors, Vec<Monitor>);
getter!(cursor_position, PhysicalPosition<f64>);
getter!(theme, Theme);

setter!(center);
Expand Down Expand Up @@ -222,6 +223,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
desktop_commands::current_monitor,
desktop_commands::primary_monitor,
desktop_commands::available_monitors,
desktop_commands::cursor_position,
desktop_commands::theme,
// setters
desktop_commands::center,
Expand Down
19 changes: 18 additions & 1 deletion tooling/api/src/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2256,6 +2256,22 @@ async function availableMonitors(): Promise<Monitor[]> {
)
}

/**
* Get the cursor position relative to the top-left hand corner of the desktop.
*
* Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
* If the user uses a desktop with multiple monitors,
* the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
* or the top-left of the leftmost monitor on X11.
*
* The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
*/
async function cursorPosition(): Promise<PhysicalPosition> {
return invoke<PhysicalPosition>('plugin:window|cursor_position').then(
mapPhysicalPosition
)
}

export {
Window,
CloseRequestedEvent,
Expand All @@ -2270,7 +2286,8 @@ export {
EffectState,
currentMonitor,
primaryMonitor,
availableMonitors
availableMonitors,
cursorPosition
}

export type {
Expand Down

0 comments on commit 477bb8c

Please sign in to comment.