Add raw window handle implementations to GPUI (#7101)

Mikayla Maki created

This is in preparation for experiments with wgpu. This should have no
external effect.

Release Notes:

- N/A

Change summary

Cargo.lock                              |  9 +++++++
crates/gpui/Cargo.toml                  |  1 
crates/gpui/src/platform.rs             |  9 ++++---
crates/gpui/src/platform/mac/window.rs  | 30 ++++++++++++++++++++++++++
crates/gpui/src/platform/test/window.rs | 17 +++++++++++++++
5 files changed, 60 insertions(+), 6 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -3129,6 +3129,7 @@ dependencies = [
  "png",
  "postage",
  "rand 0.8.5",
+ "raw-window-handle 0.6.0",
  "refineable",
  "resvg",
  "schemars",
@@ -4495,7 +4496,7 @@ dependencies = [
  "jni-sys",
  "ndk-sys",
  "num_enum",
- "raw-window-handle",
+ "raw-window-handle 0.5.2",
  "thiserror",
 ]
 
@@ -5953,6 +5954,12 @@ version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
 
+[[package]]
+name = "raw-window-handle"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544"
+
 [[package]]
 name = "rawpointer"
 version = "0.2.1"

crates/gpui/Cargo.toml 🔗

@@ -58,6 +58,7 @@ slotmap = "1.0.6"
 schemars.workspace = true
 bitflags = "2.4.0"
 anyhow.workspace = true
+raw-window-handle = "0.6.0"
 
 [dev-dependencies]
 backtrace = "0.3"

crates/gpui/src/platform.rs 🔗

@@ -8,13 +8,14 @@ mod test;
 use crate::{
     Action, AnyWindowHandle, AsyncWindowContext, BackgroundExecutor, Bounds, DevicePixels, Font,
     FontId, FontMetrics, FontRun, ForegroundExecutor, GlobalPixels, GlyphId, Keymap, LineLayout,
-    Pixels, PlatformInput, Point, RenderGlyphParams, RenderImageParams, RenderSvgParams, Result,
-    Scene, SharedString, Size, Task, TaskLabel, WindowContext,
+    Pixels, PlatformInput, Point, RenderGlyphParams, RenderImageParams, RenderSvgParams, Scene,
+    SharedString, Size, Task, TaskLabel, WindowContext,
 };
-use anyhow::anyhow;
+use anyhow::{anyhow, Result};
 use async_task::Runnable;
 use futures::channel::oneshot;
 use parking::Unparker;
+use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
 use seahash::SeaHasher;
 use serde::{Deserialize, Serialize};
 use std::borrow::Cow;
@@ -138,7 +139,7 @@ impl Debug for DisplayId {
 
 unsafe impl Send for DisplayId {}
 
-pub(crate) trait PlatformWindow {
+pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
     fn bounds(&self) -> WindowBounds;
     fn content_size(&self) -> Size<Pixels>;
     fn scale_factor(&self) -> f32;

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

@@ -32,6 +32,10 @@ use objc::{
     sel, sel_impl,
 };
 use parking_lot::Mutex;
+use raw_window_handle::{
+    AppKitDisplayHandle, AppKitWindowHandle, DisplayHandle, HasDisplayHandle, HasWindowHandle,
+    RawWindowHandle, WindowHandle,
+};
 use smallvec::SmallVec;
 use std::{
     any::Any,
@@ -41,7 +45,7 @@ use std::{
     ops::Range,
     os::raw::c_char,
     path::PathBuf,
-    ptr,
+    ptr::{self, NonNull},
     rc::Rc,
     sync::{Arc, Weak},
     time::Duration,
@@ -316,6 +320,7 @@ struct MacWindowState {
     handle: AnyWindowHandle,
     executor: ForegroundExecutor,
     native_window: id,
+    native_view: NonNull<id>,
     renderer: MetalRenderer,
     kind: WindowKind,
     request_frame_callback: Option<Box<dyn FnMut()>>,
@@ -523,6 +528,7 @@ impl MacWindow {
                 handle,
                 executor,
                 native_window,
+                native_view: NonNull::new_unchecked(native_view as *mut _),
                 renderer: MetalRenderer::new(true),
                 kind: options.kind,
                 request_frame_callback: None,
@@ -1011,6 +1017,28 @@ impl PlatformWindow for MacWindow {
     }
 }
 
+impl HasWindowHandle for MacWindow {
+    fn window_handle(
+        &self,
+    ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::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()),
+            )))
+        }
+    }
+}
+
+impl HasDisplayHandle for MacWindow {
+    fn display_handle(
+        &self,
+    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
+        // SAFETY: This is a no-op on macOS
+        unsafe { Ok(DisplayHandle::borrow_raw(AppKitDisplayHandle::new().into())) }
+    }
+}
+
 fn get_scale_factor(native_window: id) -> f32 {
     let factor = unsafe {
         let screen: id = msg_send![native_window, screen];

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

@@ -5,6 +5,7 @@ use crate::{
 };
 use collections::HashMap;
 use parking_lot::Mutex;
+use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
 use std::{
     rc::{Rc, Weak},
     sync::{self, Arc},
@@ -29,6 +30,22 @@ pub(crate) struct TestWindowState {
 #[derive(Clone)]
 pub(crate) struct TestWindow(pub(crate) Arc<Mutex<TestWindowState>>);
 
+impl HasWindowHandle for TestWindow {
+    fn window_handle(
+        &self,
+    ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
+        unimplemented!("Test Windows are not backed by a real platform window")
+    }
+}
+
+impl HasDisplayHandle for TestWindow {
+    fn display_handle(
+        &self,
+    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
+        unimplemented!("Test Windows are not backed by a real platform window")
+    }
+}
+
 impl TestWindow {
     pub fn new(
         options: WindowOptions,