Procházet zdrojové kódy

feat: implement `raw_window_handle` on Linux (#4469)

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Amr Bashir před 3 roky
rodič
revize
3efbc67f74

+ 7 - 0
.changes/linux-raw-window-handle.md

@@ -0,0 +1,7 @@
+---
+"tauri": "patch"
+"tauri-runtime": "patch"
+"tauri-runtime-wry": "patch"
+---
+
+Implement `raw_window_handle::HasRawWindowHandle` on Linux.

+ 6 - 0
.changes/runtime-remove-hwnd-ns_window.md

@@ -0,0 +1,6 @@
+---
+"tauri-runtime": minor
+"tauri-runtime-wry": minor
+---
+
+Removed the `hwnd` and `ns_window` functions from `Dispatch` in favor of `raw_window_handle`.

+ 1 - 0
core/tauri-runtime-wry/Cargo.toml

@@ -18,6 +18,7 @@ tauri-runtime = { version = "0.9.0", path = "../tauri-runtime" }
 tauri-utils = { version = "1.0.0", path = "../tauri-utils" }
 uuid = { version = "1", features = [ "v4" ] }
 rand = "0.8"
+raw-window-handle = "0.4.3"
 
 [target."cfg(windows)".dependencies]
 webview2-com = "0.16.0"

+ 12 - 30
core/tauri-runtime-wry/src/lib.rs

@@ -4,6 +4,7 @@
 
 //! The [`wry`] Tauri [`Runtime`].
 
+use raw_window_handle::HasRawWindowHandle;
 use tauri_runtime::{
   http::{
     Request as HttpRequest, RequestParts as HttpRequestParts, Response as HttpResponse,
@@ -976,18 +977,6 @@ impl From<FileDropEventWrapper> for FileDropEvent {
   }
 }
 
-#[cfg(target_os = "macos")]
-pub struct NSWindow(*mut std::ffi::c_void);
-#[cfg(target_os = "macos")]
-#[allow(clippy::non_send_fields_in_send_ty)]
-unsafe impl Send for NSWindow {}
-
-#[cfg(windows)]
-pub struct Hwnd(HWND);
-#[cfg(windows)]
-#[allow(clippy::non_send_fields_in_send_ty)]
-unsafe impl Send for Hwnd {}
-
 #[cfg(any(
   target_os = "linux",
   target_os = "dragonfly",
@@ -1006,6 +995,9 @@ pub struct GtkWindow(gtk::ApplicationWindow);
 #[allow(clippy::non_send_fields_in_send_ty)]
 unsafe impl Send for GtkWindow {}
 
+pub struct RawWindowHandle(raw_window_handle::RawWindowHandle);
+unsafe impl Send for RawWindowHandle {}
+
 pub enum WindowMessage {
   WithWebview(Box<dyn FnOnce(Webview) + Send>),
   // Devtools
@@ -1030,10 +1022,6 @@ pub enum WindowMessage {
   CurrentMonitor(Sender<Option<MonitorHandle>>),
   PrimaryMonitor(Sender<Option<MonitorHandle>>),
   AvailableMonitors(Sender<Vec<MonitorHandle>>),
-  #[cfg(target_os = "macos")]
-  NSWindow(Sender<NSWindow>),
-  #[cfg(windows)]
-  Hwnd(Sender<Hwnd>),
   #[cfg(any(
     target_os = "linux",
     target_os = "dragonfly",
@@ -1042,6 +1030,7 @@ pub enum WindowMessage {
     target_os = "openbsd"
   ))]
   GtkWindow(Sender<GtkWindow>),
+  RawWindowHandle(Sender<RawWindowHandle>),
   Theme(Sender<Theme>),
   // Setters
   Center(Sender<Result<()>>),
@@ -1285,16 +1274,6 @@ impl<T: UserEvent> Dispatch<T> for WryDispatcher<T> {
     )
   }
 
-  #[cfg(target_os = "macos")]
-  fn ns_window(&self) -> Result<*mut std::ffi::c_void> {
-    window_getter!(self, WindowMessage::NSWindow).map(|w| w.0)
-  }
-
-  #[cfg(windows)]
-  fn hwnd(&self) -> Result<HWND> {
-    window_getter!(self, WindowMessage::Hwnd).map(|w| w.0)
-  }
-
   fn theme(&self) -> Result<Theme> {
     window_getter!(self, WindowMessage::Theme)
   }
@@ -1311,6 +1290,10 @@ impl<T: UserEvent> Dispatch<T> for WryDispatcher<T> {
     window_getter!(self, WindowMessage::GtkWindow).map(|w| w.0)
   }
 
+  fn raw_window_handle(&self) -> Result<raw_window_handle::RawWindowHandle> {
+    window_getter!(self, WindowMessage::RawWindowHandle).map(|w| w.0)
+  }
+
   // Setters
 
   fn center(&self) -> Result<()> {
@@ -2330,10 +2313,6 @@ fn handle_user_message<T: UserEvent>(
             WindowMessage::AvailableMonitors(tx) => {
               tx.send(window.available_monitors().collect()).unwrap()
             }
-            #[cfg(target_os = "macos")]
-            WindowMessage::NSWindow(tx) => tx.send(NSWindow(window.ns_window())).unwrap(),
-            #[cfg(windows)]
-            WindowMessage::Hwnd(tx) => tx.send(Hwnd(HWND(window.hwnd() as _))).unwrap(),
             #[cfg(any(
               target_os = "linux",
               target_os = "dragonfly",
@@ -2344,6 +2323,9 @@ fn handle_user_message<T: UserEvent>(
             WindowMessage::GtkWindow(tx) => {
               tx.send(GtkWindow(window.gtk_window().clone())).unwrap()
             }
+            WindowMessage::RawWindowHandle(tx) => tx
+              .send(RawWindowHandle(window.raw_window_handle()))
+              .unwrap(),
             WindowMessage::Theme(tx) => {
               #[cfg(any(windows, target_os = "macos"))]
               tx.send(map_theme(&window.theme())).unwrap();

+ 1 - 0
core/tauri-runtime/Cargo.toml

@@ -31,6 +31,7 @@ uuid = { version = "1", features = [ "v4" ] }
 http = "0.2.4"
 http-range = "0.1.4"
 infer = "0.7"
+raw-window-handle = "0.4.3"
 
 [target."cfg(windows)".dependencies]
 webview2-com = "0.16.0"

+ 2 - 11
core/tauri-runtime/src/lib.rs

@@ -11,9 +11,6 @@ use std::{fmt::Debug, sync::mpsc::Sender};
 use tauri_utils::Theme;
 use uuid::Uuid;
 
-#[cfg(windows)]
-use windows::Win32::Foundation::HWND;
-
 pub mod http;
 /// Create window and system tray menus.
 pub mod menu;
@@ -433,14 +430,6 @@ pub trait Dispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'static
   /// Returns the list of all the monitors available on the system.
   fn available_monitors(&self) -> Result<Vec<Monitor>>;
 
-  /// Returns the native handle that is used by this window.
-  #[cfg(windows)]
-  fn hwnd(&self) -> Result<HWND>;
-
-  /// Returns the native handle that is used by this window.
-  #[cfg(target_os = "macos")]
-  fn ns_window(&self) -> Result<*mut std::ffi::c_void>;
-
   /// Returns the `ApplicationWindow` from gtk crate that is used by this window.
   #[cfg(any(
     target_os = "linux",
@@ -451,6 +440,8 @@ pub trait Dispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'static
   ))]
   fn gtk_window(&self) -> Result<gtk::ApplicationWindow>;
 
+  fn raw_window_handle(&self) -> Result<raw_window_handle::RawWindowHandle>;
+
   /// Returns the current window theme.
   fn theme(&self) -> Result<Theme>;
 

+ 3 - 0
core/tauri/src/error.rs

@@ -128,6 +128,9 @@ pub enum Error {
   #[cfg(feature = "icon-png")]
   #[error("failed to decode PNG: {0}")]
   PngDecode(#[from] png::DecodingError),
+  /// The Window's raw handle is invalid for the platform.
+  #[error("Unexpected `raw_window_handle` for the current platform")]
+  InvalidWindowHandle,
 }
 
 pub(crate) fn into_anyhow<T: std::fmt::Display>(err: T) -> anyhow::Error {

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

@@ -355,20 +355,10 @@ impl<T: UserEvent> Dispatch<T> for MockDispatcher {
     Ok(Vec::new())
   }
 
-  #[cfg(windows)]
-  fn hwnd(&self) -> Result<HWND> {
-    unimplemented!()
-  }
-
   fn theme(&self) -> Result<Theme> {
     Ok(Theme::Light)
   }
 
-  #[cfg(target_os = "macos")]
-  fn ns_window(&self) -> Result<*mut std::ffi::c_void> {
-    unimplemented!()
-  }
-
   #[cfg(any(
     target_os = "linux",
     target_os = "dragonfly",
@@ -380,6 +370,10 @@ impl<T: UserEvent> Dispatch<T> for MockDispatcher {
     unimplemented!()
   }
 
+  fn raw_window_handle(&self) -> Result<raw_window_handle::RawWindowHandle> {
+    unimplemented!()
+  }
+
   fn center(&self) -> Result<()> {
     Ok(())
   }

+ 25 - 17
core/tauri/src/window.rs

@@ -489,23 +489,9 @@ pub struct Window<R: Runtime> {
   pub(crate) app_handle: AppHandle<R>,
 }
 
-#[cfg(any(windows, target_os = "macos"))]
-#[cfg_attr(doc_cfg, doc(cfg(any(windows, target_os = "macos"))))]
 unsafe impl<R: Runtime> raw_window_handle::HasRawWindowHandle for Window<R> {
-  #[cfg(windows)]
-  fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
-    let mut handle = raw_window_handle::Win32Handle::empty();
-    handle.hwnd = self.hwnd().expect("failed to get window `hwnd`").0 as *mut _;
-    raw_window_handle::RawWindowHandle::Win32(handle)
-  }
-
-  #[cfg(target_os = "macos")]
   fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
-    let mut handle = raw_window_handle::AppKitHandle::empty();
-    handle.ns_window = self
-      .ns_window()
-      .expect("failed to get window's `ns_window`");
-    raw_window_handle::RawWindowHandle::AppKit(handle)
+    self.window.dispatcher.raw_window_handle().unwrap()
   }
 }
 
@@ -855,13 +841,35 @@ impl<R: Runtime> Window<R> {
   /// Returns the native handle that is used by this window.
   #[cfg(target_os = "macos")]
   pub fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void> {
-    self.window.dispatcher.ns_window().map_err(Into::into)
+    self
+      .window
+      .dispatcher
+      .raw_window_handle()
+      .map_err(Into::into)
+      .and_then(|handle| {
+        if let raw_window_handle::RawWindowHandle::AppKit(h) = handle {
+          Ok(h.ns_window)
+        } else {
+          Err(crate::Error::InvalidWindowHandle)
+        }
+      })
   }
 
   /// Returns the native handle that is used by this window.
   #[cfg(windows)]
   pub fn hwnd(&self) -> crate::Result<HWND> {
-    self.window.dispatcher.hwnd().map_err(Into::into)
+    self
+      .window
+      .dispatcher
+      .raw_window_handle()
+      .map_err(Into::into)
+      .and_then(|handle| {
+        if let raw_window_handle::RawWindowHandle::Win32(h) = handle {
+          Ok(HWND(h.hwnd as _))
+        } else {
+          Err(crate::Error::InvalidWindowHandle)
+        }
+      })
   }
 
   /// Returns the `ApplicatonWindow` from gtk crate that is used by this window.