浏览代码

feat: add is_focused APIs, closes #6472 (#6530)

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Amr Bashir 2 年之前
父节点
当前提交
000104bc3b

+ 5 - 0
.changes/is_focused-api.md

@@ -0,0 +1,5 @@
+---
+'@tauri-apps/api': 'minor:feat'
+---
+
+Add `WebviewWindow.is_focused` and `WebviewWindow.getFocusedWindow` getters.

+ 6 - 0
.changes/is_focused-runtime.md

@@ -0,0 +1,6 @@
+---
+'tauri-runtime': 'minor:feat'
+'tauri-runtime-wry': 'minor:feat'
+---
+
+Add `Window::is_focused` getter.

+ 5 - 0
.changes/is_focused-tauri.md

@@ -0,0 +1,5 @@
+---
+'tauri': 'minor:feat'
+---
+
+Add `Window::is_focused` and `Manager::get_focused_window` getters.

+ 6 - 0
core/tauri-runtime-wry/src/lib.rs

@@ -1072,6 +1072,7 @@ pub enum WindowMessage {
   IsFullscreen(Sender<bool>),
   IsMinimized(Sender<bool>),
   IsMaximized(Sender<bool>),
+  IsFocused(Sender<bool>),
   IsDecorated(Sender<bool>),
   IsResizable(Sender<bool>),
   IsMaximizable(Sender<bool>),
@@ -1308,6 +1309,10 @@ impl<T: UserEvent> Dispatch<T> for WryDispatcher<T> {
     window_getter!(self, WindowMessage::IsMaximized)
   }
 
+  fn is_focused(&self) -> Result<bool> {
+    window_getter!(self, WindowMessage::IsFocused)
+  }
+
   /// Gets the window’s current decoration state.
   fn is_decorated(&self) -> Result<bool> {
     window_getter!(self, WindowMessage::IsDecorated)
@@ -2467,6 +2472,7 @@ fn handle_user_message<T: UserEvent>(
             WindowMessage::IsFullscreen(tx) => tx.send(window.fullscreen().is_some()).unwrap(),
             WindowMessage::IsMinimized(tx) => tx.send(window.is_minimized()).unwrap(),
             WindowMessage::IsMaximized(tx) => tx.send(window.is_maximized()).unwrap(),
+            WindowMessage::IsFocused(tx) => tx.send(window.is_focused()).unwrap(),
             WindowMessage::IsDecorated(tx) => tx.send(window.is_decorated()).unwrap(),
             WindowMessage::IsResizable(tx) => tx.send(window.is_resizable()).unwrap(),
             WindowMessage::IsMaximizable(tx) => tx.send(window.is_maximizable()).unwrap(),

+ 3 - 0
core/tauri-runtime/src/lib.rs

@@ -576,6 +576,9 @@ pub trait Dispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'static
   /// Gets the window's current maximized state.
   fn is_maximized(&self) -> Result<bool>;
 
+  /// Gets the window's current focus state.
+  fn is_focused(&self) -> Result<bool>;
+
   /// Gets the window’s current decoration state.
   fn is_decorated(&self) -> Result<bool>;
 

文件差异内容过多而无法显示
+ 0 - 0
core/tauri/scripts/bundle.global.js


+ 2 - 0
core/tauri/src/endpoints/window.rs

@@ -65,6 +65,7 @@ pub enum WindowManagerCmd {
   IsFullscreen,
   IsMinimized,
   IsMaximized,
+  IsFocused,
   IsDecorated,
   IsResizable,
   IsMaximizable,
@@ -263,6 +264,7 @@ impl Cmd {
       WindowManagerCmd::IsFullscreen => return Ok(window.is_fullscreen()?.into()),
       WindowManagerCmd::IsMinimized => return Ok(window.is_minimized()?.into()),
       WindowManagerCmd::IsMaximized => return Ok(window.is_maximized()?.into()),
+      WindowManagerCmd::IsFocused => return Ok(window.is_focused()?.into()),
       WindowManagerCmd::IsDecorated => return Ok(window.is_decorated()?.into()),
       WindowManagerCmd::IsResizable => return Ok(window.is_resizable()?.into()),
       WindowManagerCmd::IsMaximizable => return Ok(window.is_maximizable()?.into()),

+ 4 - 0
core/tauri/src/lib.rs

@@ -651,6 +651,10 @@ pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
   fn get_window(&self, label: &str) -> Option<Window<R>> {
     self.manager().get_window(label)
   }
+  /// Fetch the focused window. Returns `None` if there is not any focused window.
+  fn get_focused_window(&self) -> Option<Window<R>> {
+    self.manager().get_focused_window()
+  }
 
   /// Fetch all managed windows.
   fn windows(&self) -> HashMap<String, Window<R>> {

+ 8 - 0
core/tauri/src/manager.rs

@@ -1180,6 +1180,14 @@ impl<R: Runtime> WindowManager<R> {
     self.windows_lock().get(label).cloned()
   }
 
+  pub fn get_focused_window(&self) -> Option<Window<R>> {
+    self
+      .windows_lock()
+      .iter()
+      .find(|w| w.1.is_focused().unwrap_or(false))
+      .map(|w| w.1.clone())
+  }
+
   pub fn windows(&self) -> HashMap<String, Window<R>> {
     self.windows_lock().clone()
   }

+ 4 - 0
core/tauri/src/test/mock_runtime.rs

@@ -395,6 +395,10 @@ impl<T: UserEvent> Dispatch<T> for MockDispatcher {
     Ok(false)
   }
 
+  fn is_focused(&self) -> Result<bool> {
+    Ok(false)
+  }
+
   fn is_decorated(&self) -> Result<bool> {
     Ok(false)
   }

+ 5 - 0
core/tauri/src/window.rs

@@ -1042,6 +1042,11 @@ impl<R: Runtime> Window<R> {
     self.window.dispatcher.is_maximized().map_err(Into::into)
   }
 
+  /// Gets the window's current focus state.
+  pub fn is_focused(&self) -> crate::Result<bool> {
+    self.window.dispatcher.is_focused().map_err(Into::into)
+  }
+
   /// Gets the window’s current decoration state.
   pub fn is_decorated(&self) -> crate::Result<bool> {
     self.window.dispatcher.is_decorated().map_err(Into::into)

文件差异内容过多而无法显示
+ 0 - 0
tooling/api/docs/js-api.json


+ 48 - 0
tooling/api/src/window.ts

@@ -636,6 +636,33 @@ class WindowManager extends WebviewWindowHandle {
     })
   }
 
+  /**
+   * Gets the window's current focus state.
+   * @example
+   * ```typescript
+   * import { appWindow } from '@tauri-apps/api/window';
+   * const focused = await appWindow.isFocused();
+   * ```
+   *
+   * @returns Whether the window is focused or not.
+   *
+   * @since 1.4
+   * */
+  async isFocused(): Promise<boolean> {
+    return invokeTauriCommand({
+      __tauriModule: 'Window',
+      message: {
+        cmd: 'manage',
+        data: {
+          label: this.label,
+          cmd: {
+            type: 'isFocused'
+          }
+        }
+      }
+    })
+  }
+
   /**
    * Gets the window's current decorated state.
    * @example
@@ -2228,6 +2255,27 @@ class WebviewWindow extends WindowManager {
     }
     return null
   }
+
+  /**
+   *  Gets the focused window.
+   * @example
+   * ```typescript
+   * import { WebviewWindow } from '@tauri-apps/api/window';
+   * const focusedWindow = WebviewWindow.getFocusedWindow();
+   * ```
+   *
+   * @returns The WebviewWindow instance to communicate with the webview or `undefined` if there is not any focused window.
+   *
+   * @since 1.4
+   */
+  static async getFocusedWindow(): Promise<WebviewWindow | null> {
+    for (const w of getAll()) {
+      if (await w.isFocused()) {
+        return w
+      }
+    }
+    return null
+  }
 }
 
 /** The WebviewWindow for the current window. */

部分文件因为文件数量过多而无法显示