From 3efbc67f7469ce65a2d9ea4ff2b60b51d2a36aa5 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Sun, 26 Jun 2022 16:56:12 +0200 Subject: [PATCH] feat: implement `raw_window_handle` on Linux (#4469) Co-authored-by: Lucas Nogueira --- .changes/linux-raw-window-handle.md | 7 ++++ .changes/runtime-remove-hwnd-ns_window.md | 6 ++++ core/tauri-runtime-wry/Cargo.toml | 1 + core/tauri-runtime-wry/src/lib.rs | 42 +++++++---------------- core/tauri-runtime/Cargo.toml | 1 + core/tauri-runtime/src/lib.rs | 13 ++----- core/tauri/src/error.rs | 3 ++ core/tauri/src/test/mock_runtime.rs | 14 +++----- core/tauri/src/window.rs | 42 ++++++++++++++--------- 9 files changed, 61 insertions(+), 68 deletions(-) create mode 100644 .changes/linux-raw-window-handle.md create mode 100644 .changes/runtime-remove-hwnd-ns_window.md diff --git a/.changes/linux-raw-window-handle.md b/.changes/linux-raw-window-handle.md new file mode 100644 index 000000000..9ad0f49ef --- /dev/null +++ b/.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. diff --git a/.changes/runtime-remove-hwnd-ns_window.md b/.changes/runtime-remove-hwnd-ns_window.md new file mode 100644 index 000000000..954ba7827 --- /dev/null +++ b/.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`. diff --git a/core/tauri-runtime-wry/Cargo.toml b/core/tauri-runtime-wry/Cargo.toml index 51aecefc7..b61383938 100644 --- a/core/tauri-runtime-wry/Cargo.toml +++ b/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" diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index 452563b93..eb8886e22 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/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 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), // Devtools @@ -1030,10 +1022,6 @@ pub enum WindowMessage { CurrentMonitor(Sender>), PrimaryMonitor(Sender>), AvailableMonitors(Sender>), - #[cfg(target_os = "macos")] - NSWindow(Sender), - #[cfg(windows)] - Hwnd(Sender), #[cfg(any( target_os = "linux", target_os = "dragonfly", @@ -1042,6 +1030,7 @@ pub enum WindowMessage { target_os = "openbsd" ))] GtkWindow(Sender), + RawWindowHandle(Sender), Theme(Sender), // Setters Center(Sender>), @@ -1285,16 +1274,6 @@ impl Dispatch for WryDispatcher { ) } - #[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 { - window_getter!(self, WindowMessage::Hwnd).map(|w| w.0) - } - fn theme(&self) -> Result { window_getter!(self, WindowMessage::Theme) } @@ -1311,6 +1290,10 @@ impl Dispatch for WryDispatcher { window_getter!(self, WindowMessage::GtkWindow).map(|w| w.0) } + fn raw_window_handle(&self) -> Result { + window_getter!(self, WindowMessage::RawWindowHandle).map(|w| w.0) + } + // Setters fn center(&self) -> Result<()> { @@ -2330,10 +2313,6 @@ fn handle_user_message( 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( 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(); diff --git a/core/tauri-runtime/Cargo.toml b/core/tauri-runtime/Cargo.toml index 17dcf5185..ed5b175a9 100644 --- a/core/tauri-runtime/Cargo.toml +++ b/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" diff --git a/core/tauri-runtime/src/lib.rs b/core/tauri-runtime/src/lib.rs index b7538915d..ae98ec4a9 100644 --- a/core/tauri-runtime/src/lib.rs +++ b/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: Debug + Clone + Send + Sync + Sized + 'static /// Returns the list of all the monitors available on the system. fn available_monitors(&self) -> Result>; - /// Returns the native handle that is used by this window. - #[cfg(windows)] - fn hwnd(&self) -> Result; - - /// 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: Debug + Clone + Send + Sync + Sized + 'static ))] fn gtk_window(&self) -> Result; + fn raw_window_handle(&self) -> Result; + /// Returns the current window theme. fn theme(&self) -> Result; diff --git a/core/tauri/src/error.rs b/core/tauri/src/error.rs index 8a082c89e..cb03e74ad 100644 --- a/core/tauri/src/error.rs +++ b/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(err: T) -> anyhow::Error { diff --git a/core/tauri/src/test/mock_runtime.rs b/core/tauri/src/test/mock_runtime.rs index 207539655..f51f957a5 100644 --- a/core/tauri/src/test/mock_runtime.rs +++ b/core/tauri/src/test/mock_runtime.rs @@ -355,20 +355,10 @@ impl Dispatch for MockDispatcher { Ok(Vec::new()) } - #[cfg(windows)] - fn hwnd(&self) -> Result { - unimplemented!() - } - fn theme(&self) -> Result { 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 Dispatch for MockDispatcher { unimplemented!() } + fn raw_window_handle(&self) -> Result { + unimplemented!() + } + fn center(&self) -> Result<()> { Ok(()) } diff --git a/core/tauri/src/window.rs b/core/tauri/src/window.rs index dae3239a3..143ccc110 100644 --- a/core/tauri/src/window.rs +++ b/core/tauri/src/window.rs @@ -489,23 +489,9 @@ pub struct Window { pub(crate) app_handle: AppHandle, } -#[cfg(any(windows, target_os = "macos"))] -#[cfg_attr(doc_cfg, doc(cfg(any(windows, target_os = "macos"))))] unsafe impl raw_window_handle::HasRawWindowHandle for Window { - #[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 Window { /// 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 { - 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.