Skip to content

Commit 3efbc67

Browse files
feat: implement raw_window_handle on Linux (#4469)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
1 parent 82eb6e7 commit 3efbc67

File tree

9 files changed

+61
-68
lines changed

9 files changed

+61
-68
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"tauri": "patch"
3+
"tauri-runtime": "patch"
4+
"tauri-runtime-wry": "patch"
5+
---
6+
7+
Implement `raw_window_handle::HasRawWindowHandle` on Linux.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"tauri-runtime": minor
3+
"tauri-runtime-wry": minor
4+
---
5+
6+
Removed the `hwnd` and `ns_window` functions from `Dispatch` in favor of `raw_window_handle`.

core/tauri-runtime-wry/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ tauri-runtime = { version = "0.9.0", path = "../tauri-runtime" }
1818
tauri-utils = { version = "1.0.0", path = "../tauri-utils" }
1919
uuid = { version = "1", features = [ "v4" ] }
2020
rand = "0.8"
21+
raw-window-handle = "0.4.3"
2122

2223
[target."cfg(windows)".dependencies]
2324
webview2-com = "0.16.0"

core/tauri-runtime-wry/src/lib.rs

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
//! The [`wry`] Tauri [`Runtime`].
66
7+
use raw_window_handle::HasRawWindowHandle;
78
use tauri_runtime::{
89
http::{
910
Request as HttpRequest, RequestParts as HttpRequestParts, Response as HttpResponse,
@@ -976,18 +977,6 @@ impl From<FileDropEventWrapper> for FileDropEvent {
976977
}
977978
}
978979

979-
#[cfg(target_os = "macos")]
980-
pub struct NSWindow(*mut std::ffi::c_void);
981-
#[cfg(target_os = "macos")]
982-
#[allow(clippy::non_send_fields_in_send_ty)]
983-
unsafe impl Send for NSWindow {}
984-
985-
#[cfg(windows)]
986-
pub struct Hwnd(HWND);
987-
#[cfg(windows)]
988-
#[allow(clippy::non_send_fields_in_send_ty)]
989-
unsafe impl Send for Hwnd {}
990-
991980
#[cfg(any(
992981
target_os = "linux",
993982
target_os = "dragonfly",
@@ -1006,6 +995,9 @@ pub struct GtkWindow(gtk::ApplicationWindow);
1006995
#[allow(clippy::non_send_fields_in_send_ty)]
1007996
unsafe impl Send for GtkWindow {}
1008997

998+
pub struct RawWindowHandle(raw_window_handle::RawWindowHandle);
999+
unsafe impl Send for RawWindowHandle {}
1000+
10091001
pub enum WindowMessage {
10101002
WithWebview(Box<dyn FnOnce(Webview) + Send>),
10111003
// Devtools
@@ -1030,10 +1022,6 @@ pub enum WindowMessage {
10301022
CurrentMonitor(Sender<Option<MonitorHandle>>),
10311023
PrimaryMonitor(Sender<Option<MonitorHandle>>),
10321024
AvailableMonitors(Sender<Vec<MonitorHandle>>),
1033-
#[cfg(target_os = "macos")]
1034-
NSWindow(Sender<NSWindow>),
1035-
#[cfg(windows)]
1036-
Hwnd(Sender<Hwnd>),
10371025
#[cfg(any(
10381026
target_os = "linux",
10391027
target_os = "dragonfly",
@@ -1042,6 +1030,7 @@ pub enum WindowMessage {
10421030
target_os = "openbsd"
10431031
))]
10441032
GtkWindow(Sender<GtkWindow>),
1033+
RawWindowHandle(Sender<RawWindowHandle>),
10451034
Theme(Sender<Theme>),
10461035
// Setters
10471036
Center(Sender<Result<()>>),
@@ -1285,16 +1274,6 @@ impl<T: UserEvent> Dispatch<T> for WryDispatcher<T> {
12851274
)
12861275
}
12871276

1288-
#[cfg(target_os = "macos")]
1289-
fn ns_window(&self) -> Result<*mut std::ffi::c_void> {
1290-
window_getter!(self, WindowMessage::NSWindow).map(|w| w.0)
1291-
}
1292-
1293-
#[cfg(windows)]
1294-
fn hwnd(&self) -> Result<HWND> {
1295-
window_getter!(self, WindowMessage::Hwnd).map(|w| w.0)
1296-
}
1297-
12981277
fn theme(&self) -> Result<Theme> {
12991278
window_getter!(self, WindowMessage::Theme)
13001279
}
@@ -1311,6 +1290,10 @@ impl<T: UserEvent> Dispatch<T> for WryDispatcher<T> {
13111290
window_getter!(self, WindowMessage::GtkWindow).map(|w| w.0)
13121291
}
13131292

1293+
fn raw_window_handle(&self) -> Result<raw_window_handle::RawWindowHandle> {
1294+
window_getter!(self, WindowMessage::RawWindowHandle).map(|w| w.0)
1295+
}
1296+
13141297
// Setters
13151298

13161299
fn center(&self) -> Result<()> {
@@ -2330,10 +2313,6 @@ fn handle_user_message<T: UserEvent>(
23302313
WindowMessage::AvailableMonitors(tx) => {
23312314
tx.send(window.available_monitors().collect()).unwrap()
23322315
}
2333-
#[cfg(target_os = "macos")]
2334-
WindowMessage::NSWindow(tx) => tx.send(NSWindow(window.ns_window())).unwrap(),
2335-
#[cfg(windows)]
2336-
WindowMessage::Hwnd(tx) => tx.send(Hwnd(HWND(window.hwnd() as _))).unwrap(),
23372316
#[cfg(any(
23382317
target_os = "linux",
23392318
target_os = "dragonfly",
@@ -2344,6 +2323,9 @@ fn handle_user_message<T: UserEvent>(
23442323
WindowMessage::GtkWindow(tx) => {
23452324
tx.send(GtkWindow(window.gtk_window().clone())).unwrap()
23462325
}
2326+
WindowMessage::RawWindowHandle(tx) => tx
2327+
.send(RawWindowHandle(window.raw_window_handle()))
2328+
.unwrap(),
23472329
WindowMessage::Theme(tx) => {
23482330
#[cfg(any(windows, target_os = "macos"))]
23492331
tx.send(map_theme(&window.theme())).unwrap();

core/tauri-runtime/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ uuid = { version = "1", features = [ "v4" ] }
3131
http = "0.2.4"
3232
http-range = "0.1.4"
3333
infer = "0.7"
34+
raw-window-handle = "0.4.3"
3435

3536
[target."cfg(windows)".dependencies]
3637
webview2-com = "0.16.0"

core/tauri-runtime/src/lib.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ use std::{fmt::Debug, sync::mpsc::Sender};
1111
use tauri_utils::Theme;
1212
use uuid::Uuid;
1313

14-
#[cfg(windows)]
15-
use windows::Win32::Foundation::HWND;
16-
1714
pub mod http;
1815
/// Create window and system tray menus.
1916
pub mod menu;
@@ -433,14 +430,6 @@ pub trait Dispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'static
433430
/// Returns the list of all the monitors available on the system.
434431
fn available_monitors(&self) -> Result<Vec<Monitor>>;
435432

436-
/// Returns the native handle that is used by this window.
437-
#[cfg(windows)]
438-
fn hwnd(&self) -> Result<HWND>;
439-
440-
/// Returns the native handle that is used by this window.
441-
#[cfg(target_os = "macos")]
442-
fn ns_window(&self) -> Result<*mut std::ffi::c_void>;
443-
444433
/// Returns the `ApplicationWindow` from gtk crate that is used by this window.
445434
#[cfg(any(
446435
target_os = "linux",
@@ -451,6 +440,8 @@ pub trait Dispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'static
451440
))]
452441
fn gtk_window(&self) -> Result<gtk::ApplicationWindow>;
453442

443+
fn raw_window_handle(&self) -> Result<raw_window_handle::RawWindowHandle>;
444+
454445
/// Returns the current window theme.
455446
fn theme(&self) -> Result<Theme>;
456447

core/tauri/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ pub enum Error {
128128
#[cfg(feature = "icon-png")]
129129
#[error("failed to decode PNG: {0}")]
130130
PngDecode(#[from] png::DecodingError),
131+
/// The Window's raw handle is invalid for the platform.
132+
#[error("Unexpected `raw_window_handle` for the current platform")]
133+
InvalidWindowHandle,
131134
}
132135

133136
pub(crate) fn into_anyhow<T: std::fmt::Display>(err: T) -> anyhow::Error {

core/tauri/src/test/mock_runtime.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -355,20 +355,10 @@ impl<T: UserEvent> Dispatch<T> for MockDispatcher {
355355
Ok(Vec::new())
356356
}
357357

358-
#[cfg(windows)]
359-
fn hwnd(&self) -> Result<HWND> {
360-
unimplemented!()
361-
}
362-
363358
fn theme(&self) -> Result<Theme> {
364359
Ok(Theme::Light)
365360
}
366361

367-
#[cfg(target_os = "macos")]
368-
fn ns_window(&self) -> Result<*mut std::ffi::c_void> {
369-
unimplemented!()
370-
}
371-
372362
#[cfg(any(
373363
target_os = "linux",
374364
target_os = "dragonfly",
@@ -380,6 +370,10 @@ impl<T: UserEvent> Dispatch<T> for MockDispatcher {
380370
unimplemented!()
381371
}
382372

373+
fn raw_window_handle(&self) -> Result<raw_window_handle::RawWindowHandle> {
374+
unimplemented!()
375+
}
376+
383377
fn center(&self) -> Result<()> {
384378
Ok(())
385379
}

core/tauri/src/window.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -489,23 +489,9 @@ pub struct Window<R: Runtime> {
489489
pub(crate) app_handle: AppHandle<R>,
490490
}
491491

492-
#[cfg(any(windows, target_os = "macos"))]
493-
#[cfg_attr(doc_cfg, doc(cfg(any(windows, target_os = "macos"))))]
494492
unsafe impl<R: Runtime> raw_window_handle::HasRawWindowHandle for Window<R> {
495-
#[cfg(windows)]
496-
fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
497-
let mut handle = raw_window_handle::Win32Handle::empty();
498-
handle.hwnd = self.hwnd().expect("failed to get window `hwnd`").0 as *mut _;
499-
raw_window_handle::RawWindowHandle::Win32(handle)
500-
}
501-
502-
#[cfg(target_os = "macos")]
503493
fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
504-
let mut handle = raw_window_handle::AppKitHandle::empty();
505-
handle.ns_window = self
506-
.ns_window()
507-
.expect("failed to get window's `ns_window`");
508-
raw_window_handle::RawWindowHandle::AppKit(handle)
494+
self.window.dispatcher.raw_window_handle().unwrap()
509495
}
510496
}
511497

@@ -855,13 +841,35 @@ impl<R: Runtime> Window<R> {
855841
/// Returns the native handle that is used by this window.
856842
#[cfg(target_os = "macos")]
857843
pub fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void> {
858-
self.window.dispatcher.ns_window().map_err(Into::into)
844+
self
845+
.window
846+
.dispatcher
847+
.raw_window_handle()
848+
.map_err(Into::into)
849+
.and_then(|handle| {
850+
if let raw_window_handle::RawWindowHandle::AppKit(h) = handle {
851+
Ok(h.ns_window)
852+
} else {
853+
Err(crate::Error::InvalidWindowHandle)
854+
}
855+
})
859856
}
860857

861858
/// Returns the native handle that is used by this window.
862859
#[cfg(windows)]
863860
pub fn hwnd(&self) -> crate::Result<HWND> {
864-
self.window.dispatcher.hwnd().map_err(Into::into)
861+
self
862+
.window
863+
.dispatcher
864+
.raw_window_handle()
865+
.map_err(Into::into)
866+
.and_then(|handle| {
867+
if let raw_window_handle::RawWindowHandle::Win32(h) = handle {
868+
Ok(HWND(h.hwnd as _))
869+
} else {
870+
Err(crate::Error::InvalidWindowHandle)
871+
}
872+
})
865873
}
866874

867875
/// Returns the `ApplicatonWindow` from gtk crate that is used by this window.

0 commit comments

Comments
 (0)