Update blade with transparency and exclusive fullscreen fixes (#10880)

Dzmitry Malyshau created

Release Notes:

- N/A

Picks up https://github.com/kvark/blade/pull/113 and a bunch of other
fixes.
Should prevent the exclusive full-screen on Vulkan - related to #9728
cc @kazatsuyu 

Note: this PR doesn't enable transparency, this is left to follow-up

Change summary

Cargo.lock                                       | 29 +++++-----
Cargo.toml                                       |  5 -
crates/gpui/Cargo.toml                           |  4 -
crates/gpui/src/platform/blade/blade_renderer.rs | 49 ++++++++---------
crates/gpui/src/platform/linux/wayland/window.rs | 36 +++++-------
crates/gpui/src/platform/linux/x11/window.rs     | 37 ++++--------
crates/gpui/src/platform/mac/window.rs           | 27 ++++-----
crates/gpui/src/platform/windows/window.rs       | 48 ++++++++---------
8 files changed, 105 insertions(+), 130 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -284,21 +284,21 @@ checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
 
 [[package]]
 name = "ash"
-version = "0.37.3+1.3.251"
+version = "0.38.0+1.3.281"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a"
+checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
 dependencies = [
- "libloading 0.7.4",
+ "libloading 0.8.0",
 ]
 
 [[package]]
 name = "ash-window"
-version = "0.12.0"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b912285a7c29f3a8f87ca6f55afc48768624e5e33ec17dbd2f2075903f5e35ab"
+checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82"
 dependencies = [
  "ash",
- "raw-window-handle 0.5.2",
+ "raw-window-handle 0.6.0",
  "raw-window-metal",
 ]
 
@@ -1479,7 +1479,7 @@ dependencies = [
 [[package]]
 name = "blade-graphics"
 version = "0.4.0"
-source = "git+https://github.com/kvark/blade?rev=810ec594358aafea29a4a3d8ab601d25292b2ce4#810ec594358aafea29a4a3d8ab601d25292b2ce4"
+source = "git+https://github.com/kvark/blade?rev=e82eec97691c3acdb43494484be60d661edfebf3#e82eec97691c3acdb43494484be60d661edfebf3"
 dependencies = [
  "ash",
  "ash-window",
@@ -1500,7 +1500,7 @@ dependencies = [
  "mint",
  "naga",
  "objc",
- "raw-window-handle 0.5.2",
+ "raw-window-handle 0.6.0",
  "slab",
  "wasm-bindgen",
  "web-sys",
@@ -1509,7 +1509,7 @@ dependencies = [
 [[package]]
 name = "blade-macros"
 version = "0.2.1"
-source = "git+https://github.com/kvark/blade?rev=810ec594358aafea29a4a3d8ab601d25292b2ce4#810ec594358aafea29a4a3d8ab601d25292b2ce4"
+source = "git+https://github.com/kvark/blade?rev=e82eec97691c3acdb43494484be60d661edfebf3#e82eec97691c3acdb43494484be60d661edfebf3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4486,9 +4486,9 @@ dependencies = [
 
 [[package]]
 name = "gpu-alloc-ash"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2424bc9be88170e1a56e57c25d3d0e2dfdd22e8f328e892786aeb4da1415732"
+checksum = "cbda7a18a29bc98c2e0de0435c347df935bf59489935d0cbd0b73f1679b6f79a"
 dependencies = [
  "ash",
  "gpu-alloc-types",
@@ -4555,7 +4555,6 @@ dependencies = [
  "postage",
  "profiling",
  "rand 0.8.5",
- "raw-window-handle 0.5.2",
  "raw-window-handle 0.6.0",
  "refineable",
  "resvg",
@@ -7726,14 +7725,14 @@ checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544"
 
 [[package]]
 name = "raw-window-metal"
-version = "0.3.2"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac4ea493258d54c24cb46aa9345d099e58e2ea3f30dd63667fc54fc892f18e76"
+checksum = "76e8caa82e31bb98fee12fa8f051c94a6aa36b07cddb03f0d4fc558988360ff1"
 dependencies = [
  "cocoa",
  "core-graphics",
  "objc",
- "raw-window-handle 0.5.2",
+ "raw-window-handle 0.6.0",
 ]
 
 [[package]]

Cargo.toml 🔗

@@ -249,9 +249,8 @@ async-recursion = "1.0.0"
 async-tar = "0.4.2"
 async-trait = "0.1"
 bitflags = "2.4.2"
-blade-graphics = { git = "https://github.com/kvark/blade", rev = "810ec594358aafea29a4a3d8ab601d25292b2ce4" }
-blade-macros = { git = "https://github.com/kvark/blade", rev = "810ec594358aafea29a4a3d8ab601d25292b2ce4" }
-blade-rwh = { package = "raw-window-handle", version = "0.5" }
+blade-graphics = { git = "https://github.com/kvark/blade", rev = "e82eec97691c3acdb43494484be60d661edfebf3" }
+blade-macros = { git = "https://github.com/kvark/blade", rev = "e82eec97691c3acdb43494484be60d661edfebf3" }
 cap-std = "3.0"
 chrono = { version = "0.4", features = ["serde"] }
 clap = { version = "4.4", features = ["derive"] }

crates/gpui/Cargo.toml 🔗

@@ -14,7 +14,7 @@ workspace = true
 default = []
 test-support = ["backtrace", "collections/test-support", "util/test-support"]
 runtime_shaders = []
-macos-blade = ["blade-graphics", "blade-macros", "blade-rwh", "bytemuck"]
+macos-blade = ["blade-graphics", "blade-macros", "bytemuck"]
 
 [lib]
 path = "src/gpui.rs"
@@ -26,7 +26,6 @@ async-task = "4.7"
 backtrace = { version = "0.3", optional = true }
 blade-graphics = { workspace = true, optional = true }
 blade-macros = { workspace = true, optional = true }
-blade-rwh = { workspace = true, optional = true }
 bytemuck = { version = "1", optional = true }
 collections.workspace = true
 ctor.workspace = true
@@ -95,7 +94,6 @@ flume = "0.11"
 #TODO: use these on all platforms
 blade-graphics.workspace = true
 blade-macros.workspace = true
-blade-rwh.workspace = true
 bytemuck = "1"
 cosmic-text = "0.11.2"
 copypasta = "0.10.1"

crates/gpui/src/platform/blade/blade_renderer.rs 🔗

@@ -12,7 +12,7 @@ use collections::HashMap;
 #[cfg(target_os = "macos")]
 use media::core_video::CVMetalTextureCache;
 #[cfg(target_os = "macos")]
-use std::ffi::c_void;
+use std::{ffi::c_void, ptr::NonNull};
 
 use blade_graphics as gpu;
 use std::{mem, sync::Arc};
@@ -25,35 +25,32 @@ pub type Renderer = BladeRenderer;
 #[cfg(target_os = "macos")]
 pub unsafe fn new_renderer(
     _context: self::Context,
-    native_window: *mut c_void,
+    _native_window: *mut c_void,
     native_view: *mut c_void,
     bounds: crate::Size<f32>,
 ) -> Renderer {
+    use raw_window_handle as rwh;
     struct RawWindow {
-        window: *mut c_void,
         view: *mut c_void,
     }
 
-    unsafe impl blade_rwh::HasRawWindowHandle for RawWindow {
-        fn raw_window_handle(&self) -> blade_rwh::RawWindowHandle {
-            let mut wh = blade_rwh::AppKitWindowHandle::empty();
-            wh.ns_window = self.window;
-            wh.ns_view = self.view;
-            wh.into()
+    impl rwh::HasWindowHandle for RawWindow {
+        fn window_handle(&self) -> Result<rwh::WindowHandle, rwh::HandleError> {
+            let view = NonNull::new(self.view).unwrap();
+            let handle = rwh::AppKitWindowHandle::new(view);
+            Ok(unsafe { rwh::WindowHandle::borrow_raw(handle.into()) })
         }
     }
-
-    unsafe impl blade_rwh::HasRawDisplayHandle for RawWindow {
-        fn raw_display_handle(&self) -> blade_rwh::RawDisplayHandle {
-            let dh = blade_rwh::AppKitDisplayHandle::empty();
-            dh.into()
+    impl rwh::HasDisplayHandle for RawWindow {
+        fn display_handle(&self) -> Result<rwh::DisplayHandle, rwh::HandleError> {
+            let handle = rwh::AppKitDisplayHandle::new();
+            Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) })
         }
     }
 
     let gpu = Arc::new(
         gpu::Context::init_windowed(
             &RawWindow {
-                window: native_window as *mut _,
                 view: native_view as *mut _,
             },
             gpu::ContextDesc {
@@ -184,7 +181,7 @@ struct BladePipelines {
 }
 
 impl BladePipelines {
-    fn new(gpu: &gpu::Context, surface_format: gpu::TextureFormat) -> Self {
+    fn new(gpu: &gpu::Context, surface_info: gpu::SurfaceInfo) -> Self {
         use gpu::ShaderData as _;
 
         let shader = gpu.create_shader(gpu::ShaderDesc {
@@ -216,7 +213,7 @@ impl BladePipelines {
                 depth_stencil: None,
                 fragment: shader.at("fs_quad"),
                 color_targets: &[gpu::ColorTargetState {
-                    format: surface_format,
+                    format: surface_info.format,
                     blend: Some(gpu::BlendState::ALPHA_BLENDING),
                     write_mask: gpu::ColorWrites::default(),
                 }],
@@ -233,7 +230,7 @@ impl BladePipelines {
                 depth_stencil: None,
                 fragment: shader.at("fs_shadow"),
                 color_targets: &[gpu::ColorTargetState {
-                    format: surface_format,
+                    format: surface_info.format,
                     blend: Some(gpu::BlendState::ALPHA_BLENDING),
                     write_mask: gpu::ColorWrites::default(),
                 }],
@@ -267,7 +264,7 @@ impl BladePipelines {
                 depth_stencil: None,
                 fragment: shader.at("fs_path"),
                 color_targets: &[gpu::ColorTargetState {
-                    format: surface_format,
+                    format: surface_info.format,
                     blend: Some(gpu::BlendState::ALPHA_BLENDING),
                     write_mask: gpu::ColorWrites::default(),
                 }],
@@ -284,7 +281,7 @@ impl BladePipelines {
                 depth_stencil: None,
                 fragment: shader.at("fs_underline"),
                 color_targets: &[gpu::ColorTargetState {
-                    format: surface_format,
+                    format: surface_info.format,
                     blend: Some(gpu::BlendState::ALPHA_BLENDING),
                     write_mask: gpu::ColorWrites::default(),
                 }],
@@ -301,7 +298,7 @@ impl BladePipelines {
                 depth_stencil: None,
                 fragment: shader.at("fs_mono_sprite"),
                 color_targets: &[gpu::ColorTargetState {
-                    format: surface_format,
+                    format: surface_info.format,
                     blend: Some(gpu::BlendState::ALPHA_BLENDING),
                     write_mask: gpu::ColorWrites::default(),
                 }],
@@ -318,7 +315,7 @@ impl BladePipelines {
                 depth_stencil: None,
                 fragment: shader.at("fs_poly_sprite"),
                 color_targets: &[gpu::ColorTargetState {
-                    format: surface_format,
+                    format: surface_info.format,
                     blend: Some(gpu::BlendState::ALPHA_BLENDING),
                     write_mask: gpu::ColorWrites::default(),
                 }],
@@ -335,7 +332,7 @@ impl BladePipelines {
                 depth_stencil: None,
                 fragment: shader.at("fs_surface"),
                 color_targets: &[gpu::ColorTargetState {
-                    format: surface_format,
+                    format: surface_info.format,
                     blend: Some(gpu::BlendState::ALPHA_BLENDING),
                     write_mask: gpu::ColorWrites::default(),
                 }],
@@ -367,16 +364,18 @@ impl BladeRenderer {
             //Note: this matches the original logic of the Metal backend,
             // but ultimaterly we need to switch to `Linear`.
             color_space: gpu::ColorSpace::Srgb,
+            allow_exclusive_full_screen: false,
+            transparent: false,
         }
     }
 
     pub fn new(gpu: Arc<gpu::Context>, size: gpu::Extent) -> Self {
-        let surface_format = gpu.resize(Self::make_surface_config(size));
+        let surface_info = gpu.resize(Self::make_surface_config(size));
         let command_encoder = gpu.create_command_encoder(gpu::CommandEncoderDesc {
             name: "main",
             buffer_count: 2,
         });
-        let pipelines = BladePipelines::new(&gpu, surface_format);
+        let pipelines = BladePipelines::new(&gpu, surface_info);
         let instance_belt = BladeBelt::new(BladeBeltDescriptor {
             memory: gpu::Memory::Shared,
             min_chunk_size: 0x1000,

crates/gpui/src/platform/linux/wayland/window.rs 🔗

@@ -2,16 +2,14 @@ use std::any::Any;
 use std::cell::{Ref, RefCell, RefMut};
 use std::ffi::c_void;
 use std::num::NonZeroU32;
+use std::ptr::NonNull;
 use std::rc::{Rc, Weak};
 use std::sync::Arc;
 
 use blade_graphics as gpu;
-use blade_rwh::{HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle};
 use collections::{HashMap, HashSet};
 use futures::channel::oneshot::Receiver;
-use raw_window_handle::{
-    DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, WindowHandle,
-};
+use raw_window_handle as rwh;
 use wayland_backend::client::ObjectId;
 use wayland_client::WEnum;
 use wayland_client::{protocol::wl_surface, Proxy};
@@ -49,19 +47,18 @@ struct RawWindow {
     display: *mut c_void,
 }
 
-unsafe impl HasRawWindowHandle for RawWindow {
-    fn raw_window_handle(&self) -> RawWindowHandle {
-        let mut wh = blade_rwh::WaylandWindowHandle::empty();
-        wh.surface = self.window;
-        wh.into()
+impl rwh::HasWindowHandle for RawWindow {
+    fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
+        let window = NonNull::new(self.window).unwrap();
+        let handle = rwh::WaylandWindowHandle::new(window);
+        Ok(unsafe { rwh::WindowHandle::borrow_raw(handle.into()) })
     }
 }
-
-unsafe impl HasRawDisplayHandle for RawWindow {
-    fn raw_display_handle(&self) -> RawDisplayHandle {
-        let mut dh = blade_rwh::WaylandDisplayHandle::empty();
-        dh.display = self.display;
-        dh.into()
+impl rwh::HasDisplayHandle for RawWindow {
+    fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
+        let display = NonNull::new(self.display).unwrap();
+        let handle = rwh::WaylandDisplayHandle::new(display);
+        Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) })
     }
 }
 
@@ -520,14 +517,13 @@ impl WaylandWindowStatePtr {
     }
 }
 
-impl HasWindowHandle for WaylandWindow {
-    fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
+impl rwh::HasWindowHandle for WaylandWindow {
+    fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
         unimplemented!()
     }
 }
-
-impl HasDisplayHandle for WaylandWindow {
-    fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
+impl rwh::HasDisplayHandle for WaylandWindow {
+    fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
         unimplemented!()
     }
 }

crates/gpui/src/platform/linux/x11/window.rs 🔗

@@ -77,8 +77,8 @@ pub struct Callbacks {
 }
 
 pub(crate) struct X11WindowState {
-    raw: RawWindow,
     atoms: XcbAtoms,
+    raw: RawWindow,
     bounds: Bounds<i32>,
     scale_factor: f32,
     renderer: BladeRenderer,
@@ -96,40 +96,29 @@ pub(crate) struct X11Window {
 }
 
 // todo(linux): Remove other RawWindowHandle implementation
-unsafe impl blade_rwh::HasRawWindowHandle for RawWindow {
-    fn raw_window_handle(&self) -> blade_rwh::RawWindowHandle {
-        let mut wh = blade_rwh::XcbWindowHandle::empty();
-        wh.window = self.window_id;
-        wh.visual_id = self.visual_id;
-        wh.into()
+impl rwh::HasWindowHandle for RawWindow {
+    fn window_handle(&self) -> Result<rwh::WindowHandle, rwh::HandleError> {
+        let non_zero = NonZeroU32::new(self.window_id).unwrap();
+        let handle = rwh::XcbWindowHandle::new(non_zero);
+        Ok(unsafe { rwh::WindowHandle::borrow_raw(handle.into()) })
     }
 }
-unsafe impl blade_rwh::HasRawDisplayHandle for RawWindow {
-    fn raw_display_handle(&self) -> blade_rwh::RawDisplayHandle {
-        let mut dh = blade_rwh::XcbDisplayHandle::empty();
-        dh.connection = self.connection;
-        dh.screen = self.screen_id as i32;
-        dh.into()
+impl rwh::HasDisplayHandle for RawWindow {
+    fn display_handle(&self) -> Result<rwh::DisplayHandle, rwh::HandleError> {
+        let non_zero = NonNull::new(self.connection).unwrap();
+        let handle = rwh::XcbDisplayHandle::new(Some(non_zero), self.screen_id as i32);
+        Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) })
     }
 }
 
 impl rwh::HasWindowHandle for X11Window {
     fn window_handle(&self) -> Result<rwh::WindowHandle, rwh::HandleError> {
-        Ok(unsafe {
-            let non_zero = NonZeroU32::new(self.state.borrow().raw.window_id).unwrap();
-            let handle = rwh::XcbWindowHandle::new(non_zero);
-            rwh::WindowHandle::borrow_raw(handle.into())
-        })
+        unimplemented!()
     }
 }
 impl rwh::HasDisplayHandle for X11Window {
     fn display_handle(&self) -> Result<rwh::DisplayHandle, rwh::HandleError> {
-        Ok(unsafe {
-            let this = self.state.borrow();
-            let non_zero = NonNull::new(this.raw.connection).unwrap();
-            let handle = rwh::XcbDisplayHandle::new(Some(non_zero), this.raw.screen_id as i32);
-            rwh::DisplayHandle::borrow_raw(handle.into())
-        })
+        unimplemented!()
     }
 }
 

crates/gpui/src/platform/mac/window.rs 🔗

@@ -31,10 +31,7 @@ use objc::{
     sel, sel_impl,
 };
 use parking_lot::Mutex;
-use raw_window_handle::{
-    AppKitDisplayHandle, AppKitWindowHandle, DisplayHandle, HasDisplayHandle, HasWindowHandle,
-    RawWindowHandle, WindowHandle,
-};
+use raw_window_handle as rwh;
 use smallvec::SmallVec;
 use std::{
     any::Any,
@@ -1141,25 +1138,25 @@ impl PlatformWindow for MacWindow {
     }
 }
 
-impl HasWindowHandle for MacWindow {
-    fn window_handle(
-        &self,
-    ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
+impl rwh::HasWindowHandle for MacWindow {
+    fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
         // SAFETY: The AppKitWindowHandle is a wrapper around a pointer to an NSView
         unsafe {
-            Ok(WindowHandle::borrow_raw(RawWindowHandle::AppKit(
-                AppKitWindowHandle::new(self.0.lock().native_view.cast()),
+            Ok(rwh::WindowHandle::borrow_raw(rwh::RawWindowHandle::AppKit(
+                rwh::AppKitWindowHandle::new(self.0.lock().native_view.cast()),
             )))
         }
     }
 }
 
-impl HasDisplayHandle for MacWindow {
-    fn display_handle(
-        &self,
-    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
+impl rwh::HasDisplayHandle for MacWindow {
+    fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
         // SAFETY: This is a no-op on macOS
-        unsafe { Ok(DisplayHandle::borrow_raw(AppKitDisplayHandle::new().into())) }
+        unsafe {
+            Ok(rwh::DisplayHandle::borrow_raw(
+                rwh::AppKitDisplayHandle::new().into(),
+            ))
+        }
     }
 }
 

crates/gpui/src/platform/windows/window.rs 🔗

@@ -3,7 +3,6 @@
 use std::{
     any::Any,
     cell::{Cell, RefCell},
-    ffi::c_void,
     iter::once,
     num::NonZeroIsize,
     path::PathBuf,
@@ -18,7 +17,7 @@ use anyhow::Context;
 use blade_graphics as gpu;
 use futures::channel::oneshot::{self, Receiver};
 use itertools::Itertools;
-use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
+use raw_window_handle as rwh;
 use smallvec::SmallVec;
 use std::result::Result;
 use windows::{
@@ -77,20 +76,24 @@ impl WindowsWindowInner {
         let scale_factor = Cell::new(monitor_dpi / USER_DEFAULT_SCREEN_DPI as f32);
         let input_handler = Cell::new(None);
         struct RawWindow {
-            hwnd: *mut c_void,
-        }
-        unsafe impl blade_rwh::HasRawWindowHandle for RawWindow {
-            fn raw_window_handle(&self) -> blade_rwh::RawWindowHandle {
-                let mut handle = blade_rwh::Win32WindowHandle::empty();
-                handle.hwnd = self.hwnd;
-                handle.into()
+            hwnd: isize,
+        }
+        impl rwh::HasWindowHandle for RawWindow {
+            fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
+                Ok(unsafe {
+                    let hwnd = NonZeroIsize::new_unchecked(self.hwnd);
+                    let handle = rwh::Win32WindowHandle::new(hwnd);
+                    rwh::WindowHandle::borrow_raw(handle.into())
+                })
             }
         }
-        unsafe impl blade_rwh::HasRawDisplayHandle for RawWindow {
-            fn raw_display_handle(&self) -> blade_rwh::RawDisplayHandle {
-                blade_rwh::WindowsDisplayHandle::empty().into()
+        impl rwh::HasDisplayHandle for RawWindow {
+            fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
+                let handle = rwh::WindowsDisplayHandle::new();
+                Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) })
             }
         }
+
         let raw = RawWindow { hwnd: hwnd.0 as _ };
         let gpu = Arc::new(
             unsafe {
@@ -1316,23 +1319,18 @@ impl WindowsWindow {
     }
 }
 
-impl HasWindowHandle for WindowsWindow {
-    fn window_handle(
-        &self,
-    ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
-        let raw = raw_window_handle::Win32WindowHandle::new(unsafe {
-            NonZeroIsize::new_unchecked(self.inner.hwnd.0)
-        })
-        .into();
-        Ok(unsafe { raw_window_handle::WindowHandle::borrow_raw(raw) })
+impl rwh::HasWindowHandle for WindowsWindow {
+    fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
+        let raw =
+            rwh::Win32WindowHandle::new(unsafe { NonZeroIsize::new_unchecked(self.inner.hwnd.0) })
+                .into();
+        Ok(unsafe { rwh::WindowHandle::borrow_raw(raw) })
     }
 }
 
 // todo(windows)
-impl HasDisplayHandle for WindowsWindow {
-    fn display_handle(
-        &self,
-    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
+impl rwh::HasDisplayHandle for WindowsWindow {
+    fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
         unimplemented!()
     }
 }