raw_window_handle/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![allow(clippy::new_without_default)]
4#![deny(unsafe_op_in_unsafe_fn)]
5
6//! Interoperability library for Rust Windowing applications.
7//!
8//! This library provides standard types for accessing a window's platform-specific raw window
9//! handle and platforms display handle. This does not provide any utilities for creating and
10//! managing windows; instead, it provides a common interface that window creation libraries (e.g.
11//! Winit, SDL) can use to easily talk with graphics libraries (e.g. gfx-hal).
12//!
13//! ## Safety guarantees
14//!
15//! Please see the docs of [`HasWindowHandle`] and [`HasDisplayHandle`].
16//!
17//! ## Platform handle initialization
18//!
19//! Each platform handle struct is purposefully non-exhaustive, so that additional fields may be
20//! added without breaking backwards compatibility. Each struct provides an `empty` method that may
21//! be used along with the struct update syntax to construct it. See each specific struct for
22//! examples.
23//!
24//! ## Display Handles
25//!
26//! Some windowing systems use a separate display handle for some operations. The display usually
27//! represents a connection to some display server, but it is not necessarily tied to a particular
28//! window. See [`RawDisplayHandle`] for more details.
29
30#[cfg(feature = "alloc")]
31extern crate alloc;
32
33#[cfg(feature = "std")]
34extern crate std;
35
36mod android;
37mod appkit;
38mod borrowed;
39mod haiku;
40mod ohos;
41mod redox;
42mod uikit;
43mod unix;
44mod web;
45mod windows;
46
47pub use android::{AndroidDisplayHandle, AndroidNdkWindowHandle};
48pub use appkit::{AppKitDisplayHandle, AppKitWindowHandle};
49pub use borrowed::{DisplayHandle, HasDisplayHandle, HasWindowHandle, WindowHandle};
50pub use haiku::{HaikuDisplayHandle, HaikuWindowHandle};
51pub use ohos::{OhosDisplayHandle, OhosNdkWindowHandle};
52pub use redox::{OrbitalDisplayHandle, OrbitalWindowHandle};
53pub use uikit::{UiKitDisplayHandle, UiKitWindowHandle};
54pub use unix::{
55    DrmDisplayHandle, DrmWindowHandle, GbmDisplayHandle, GbmWindowHandle, WaylandDisplayHandle,
56    WaylandWindowHandle, XcbDisplayHandle, XcbWindowHandle, XlibDisplayHandle, XlibWindowHandle,
57};
58pub use web::{
59    WebCanvasWindowHandle, WebDisplayHandle, WebOffscreenCanvasWindowHandle, WebWindowHandle,
60};
61pub use windows::{Win32WindowHandle, WinRtWindowHandle, WindowsDisplayHandle};
62
63use core::fmt;
64
65/// Window that wraps around a raw window handle.
66///
67/// # Safety
68///
69/// Users can safely assume that pointers and non-zero fields are valid, and it is up to the
70/// implementer of this trait to ensure that condition is upheld.
71///
72/// Despite that qualification, implementers should still make a best-effort attempt to fill in all
73/// available fields. If an implementation doesn't, and a downstream user needs the field, it should
74/// try to derive the field from other fields the implementer *does* provide via whatever methods the
75/// platform provides.
76///
77/// The exact handles returned by `raw_window_handle` must remain consistent between multiple calls
78/// to `raw_window_handle` as long as not indicated otherwise by platform specific events.
79#[deprecated = "Use `HasWindowHandle` instead"]
80pub unsafe trait HasRawWindowHandle {
81    fn raw_window_handle(&self) -> Result<RawWindowHandle, HandleError>;
82}
83
84#[allow(deprecated)]
85unsafe impl<T: HasWindowHandle + ?Sized> HasRawWindowHandle for T {
86    fn raw_window_handle(&self) -> Result<RawWindowHandle, HandleError> {
87        self.window_handle().map(Into::into)
88    }
89}
90
91/// A window handle for a particular windowing system.
92///
93/// Each variant contains a struct with fields specific to that windowing system
94/// (e.g. [`Win32WindowHandle`] will include a [HWND], [`WaylandWindowHandle`] uses [wl_surface],
95/// etc.)
96///
97/// [HWND]: https://learn.microsoft.com/en-us/windows/win32/winmsg/about-windows#window-handle
98/// [wl_surface]: https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_surface
99///
100/// # Variant Availability
101///
102/// Note that all variants are present on all targets (none are disabled behind
103/// `#[cfg]`s), but see the "Availability Hints" section on each variant for
104/// some hints on where this variant might be expected.
105///
106/// Note that these "Availability Hints" are not normative. That is to say, a
107/// [`HasWindowHandle`] implementor is completely allowed to return something
108/// unexpected. (For example, it's legal for someone to return a
109/// [`RawWindowHandle::Xlib`] on macOS, it would just be weird, and probably
110/// requires something like XQuartz be used).
111#[non_exhaustive]
112#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
113pub enum RawWindowHandle {
114    /// A raw window handle for UIKit (Apple's non-macOS windowing library).
115    ///
116    /// ## Availability Hints
117    /// This variant is likely to be used on iOS, tvOS, (in theory) watchOS, and
118    /// Mac Catalyst (`$arch-apple-ios-macabi` targets, which can notably use
119    /// UIKit *or* AppKit), as these are the targets that (currently) support
120    /// UIKit.
121    UiKit(UiKitWindowHandle),
122    /// A raw window handle for AppKit.
123    ///
124    /// ## Availability Hints
125    /// This variant is likely to be used on macOS, although Mac Catalyst
126    /// (`$arch-apple-ios-macabi` targets, which can notably use UIKit *or*
127    /// AppKit) can also use it despite being `target_os = "ios"`.
128    AppKit(AppKitWindowHandle),
129    /// A raw window handle for the Redox operating system.
130    ///
131    /// ## Availability Hints
132    /// This variant is used by the Orbital Windowing System in the Redox
133    /// operating system.
134    Orbital(OrbitalWindowHandle),
135    /// A raw window handle for the OpenHarmony OS NDK
136    ///
137    /// ## Availability Hints
138    /// This variant is used on OpenHarmony OS (`target_env = "ohos"`).
139    OhosNdk(OhosNdkWindowHandle),
140    /// A raw window handle for Xlib.
141    ///
142    /// ## Availability Hints
143    /// This variant is likely to show up anywhere someone manages to get X11
144    /// working that Xlib can be built for, which is to say, most (but not all)
145    /// Unix systems.
146    Xlib(XlibWindowHandle),
147    /// A raw window handle for Xcb.
148    ///
149    /// ## Availability Hints
150    /// This variant is likely to show up anywhere someone manages to get X11
151    /// working that XCB can be built for, which is to say, most (but not all)
152    /// Unix systems.
153    Xcb(XcbWindowHandle),
154    /// A raw window handle for Wayland.
155    ///
156    /// ## Availability Hints
157    /// This variant should be expected anywhere Wayland works, which is
158    /// currently some subset of unix systems.
159    Wayland(WaylandWindowHandle),
160    /// A raw window handle for the Linux Kernel Mode Set/Direct Rendering Manager
161    ///
162    /// ## Availability Hints
163    /// This variant is used on Linux when neither X nor Wayland are available
164    Drm(DrmWindowHandle),
165    /// A raw window handle for the Linux Generic Buffer Manager.
166    ///
167    /// ## Availability Hints
168    /// This variant is present regardless of windowing backend and likely to be used with
169    /// EGL_MESA_platform_gbm or EGL_KHR_platform_gbm.
170    Gbm(GbmWindowHandle),
171    /// A raw window handle for Win32.
172    ///
173    /// ## Availability Hints
174    /// This variant is used on Windows systems.
175    Win32(Win32WindowHandle),
176    /// A raw window handle for WinRT.
177    ///
178    /// ## Availability Hints
179    /// This variant is used on Windows systems.
180    WinRt(WinRtWindowHandle),
181    /// A raw window handle for the Web.
182    ///
183    /// ## Availability Hints
184    /// This variant is used on Wasm or asm.js targets when targeting the Web/HTML5.
185    Web(WebWindowHandle),
186    /// A raw window handle for a Web canvas registered via [`wasm-bindgen`].
187    ///
188    /// ## Availability Hints
189    /// This variant is used on Wasm or asm.js targets when targeting the Web/HTML5.
190    ///
191    /// [`wasm-bindgen`]: https://crates.io/crates/wasm-bindgen
192    WebCanvas(WebCanvasWindowHandle),
193    /// A raw window handle for a Web offscreen canvas registered via [`wasm-bindgen`].
194    ///
195    /// ## Availability Hints
196    /// This variant is used on Wasm or asm.js targets when targeting the Web/HTML5.
197    ///
198    /// [`wasm-bindgen`]: https://crates.io/crates/wasm-bindgen
199    WebOffscreenCanvas(WebOffscreenCanvasWindowHandle),
200    /// A raw window handle for Android NDK.
201    ///
202    /// ## Availability Hints
203    /// This variant is used on Android targets.
204    AndroidNdk(AndroidNdkWindowHandle),
205    /// A raw window handle for Haiku.
206    ///
207    /// ## Availability Hints
208    /// This variant is used on HaikuOS.
209    Haiku(HaikuWindowHandle),
210}
211
212/// Display that wraps around a raw display handle.
213///
214/// # Safety
215///
216/// Users can safely assume that pointers and non-zero fields are valid, and it is up to the
217/// implementer of this trait to ensure that condition is upheld.
218///
219/// Despite that qualification, implementers should still make a best-effort attempt to fill in all
220/// available fields. If an implementation doesn't, and a downstream user needs the field, it should
221/// try to derive the field from other fields the implementer *does* provide via whatever methods the
222/// platform provides.
223///
224/// The exact handles returned by `raw_display_handle` must remain consistent between multiple calls
225/// to `raw_display_handle` as long as not indicated otherwise by platform specific events.
226#[deprecated = "Use `HasDisplayHandle` instead"]
227pub unsafe trait HasRawDisplayHandle {
228    fn raw_display_handle(&self) -> Result<RawDisplayHandle, HandleError>;
229}
230
231#[allow(deprecated)]
232unsafe impl<T: HasDisplayHandle + ?Sized> HasRawDisplayHandle for T {
233    fn raw_display_handle(&self) -> Result<RawDisplayHandle, HandleError> {
234        self.display_handle().map(Into::into)
235    }
236}
237
238/// A display server handle for a particular windowing system.
239///
240/// The display usually represents a connection to some display server, but it is not necessarily
241/// tied to a particular window. Some APIs can use the display handle without ever creating a window
242/// handle (e.g. offscreen rendering, headless event handling).
243///
244/// Each variant contains a struct with fields specific to that windowing system
245/// (e.g. [`XlibDisplayHandle`] contains a [Display] connection to an X Server,
246/// [`WaylandDisplayHandle`] uses [wl_display] to connect to a compositor). Not all windowing
247/// systems have a separate display handle (or they haven't been implemented yet) and their variants
248/// contain empty structs.
249///
250/// [Display]: https://www.x.org/releases/current/doc/libX11/libX11/libX11.html#Display_Functions
251/// [wl_display]: https://wayland.freedesktop.org/docs/html/apb.html#Client-classwl__display
252///
253/// # Variant Availability
254///
255/// Note that all variants are present on all targets (none are disabled behind
256/// `#[cfg]`s), but see the "Availability Hints" section on each variant for
257/// some hints on where this variant might be expected.
258///
259/// Note that these "Availability Hints" are not normative. That is to say, a
260/// [`HasDisplayHandle`] implementor is completely allowed to return something
261/// unexpected. (For example, it's legal for someone to return a
262/// [`RawDisplayHandle::Xlib`] on macOS, it would just be weird, and probably
263/// requires something like XQuartz be used).
264#[non_exhaustive]
265#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
266pub enum RawDisplayHandle {
267    /// A raw display handle for UIKit (Apple's non-macOS windowing library).
268    ///
269    /// ## Availability Hints
270    /// This variant is likely to be used on iOS, tvOS, (in theory) watchOS, and
271    /// Mac Catalyst (`$arch-apple-ios-macabi` targets, which can notably use
272    /// UIKit *or* AppKit), as these are the targets that (currently) support
273    /// UIKit.
274    UiKit(UiKitDisplayHandle),
275    /// A raw display handle for AppKit.
276    ///
277    /// ## Availability Hints
278    /// This variant is likely to be used on macOS, although Mac Catalyst
279    /// (`$arch-apple-ios-macabi` targets, which can notably use UIKit *or*
280    /// AppKit) can also use it despite being `target_os = "ios"`.
281    AppKit(AppKitDisplayHandle),
282    /// A raw display handle for the Redox operating system.
283    ///
284    /// ## Availability Hints
285    /// This variant is used by the Orbital Windowing System in the Redox
286    /// operating system.
287    Orbital(OrbitalDisplayHandle),
288    /// A raw display handle for OpenHarmony OS NDK
289    ///
290    /// ## Availability Hints
291    /// This variant is used on OpenHarmony OS (`target_env = "ohos"`).
292    Ohos(OhosDisplayHandle),
293    /// A raw display handle for Xlib.
294    ///
295    /// ## Availability Hints
296    /// This variant is likely to show up anywhere someone manages to get X11
297    /// working that Xlib can be built for, which is to say, most (but not all)
298    /// Unix systems.
299    Xlib(XlibDisplayHandle),
300    /// A raw display handle for Xcb.
301    ///
302    /// ## Availability Hints
303    /// This variant is likely to show up anywhere someone manages to get X11
304    /// working that XCB can be built for, which is to say, most (but not all)
305    /// Unix systems.
306    Xcb(XcbDisplayHandle),
307    /// A raw display handle for Wayland.
308    ///
309    /// ## Availability Hints
310    /// This variant should be expected anywhere Wayland works, which is
311    /// currently some subset of unix systems.
312    Wayland(WaylandDisplayHandle),
313    /// A raw display handle for the Linux Kernel Mode Set/Direct Rendering Manager
314    ///
315    /// ## Availability Hints
316    /// This variant is used on Linux when neither X nor Wayland are available
317    Drm(DrmDisplayHandle),
318    /// A raw display handle for the Linux Generic Buffer Manager.
319    ///
320    /// ## Availability Hints
321    /// This variant is present regardless of windowing backend and likely to be used with
322    /// EGL_MESA_platform_gbm or EGL_KHR_platform_gbm.
323    Gbm(GbmDisplayHandle),
324    /// A raw display handle for Win32.
325    ///
326    /// ## Availability Hints
327    /// This variant is used on Windows systems.
328    Windows(WindowsDisplayHandle),
329    /// A raw display handle for the Web.
330    ///
331    /// ## Availability Hints
332    /// This variant is used on Wasm or asm.js targets when targeting the Web/HTML5.
333    Web(WebDisplayHandle),
334    /// A raw display handle for Android NDK.
335    ///
336    /// ## Availability Hints
337    /// This variant is used on Android targets.
338    Android(AndroidDisplayHandle),
339    /// A raw display handle for Haiku.
340    ///
341    /// ## Availability Hints
342    /// This variant is used on HaikuOS.
343    Haiku(HaikuDisplayHandle),
344}
345
346/// An error that can occur while fetching a display or window handle.
347#[derive(Debug, Clone)]
348#[non_exhaustive]
349pub enum HandleError {
350    /// The underlying handle cannot be represented using the types in this crate.
351    ///
352    /// This may be returned if the underlying window system does not support any of the
353    /// representative C window handles in this crate. For instance, if you were using a pure Rust
354    /// library to set up X11 (like [`x11rb`]), you would not be able to use any of the
355    /// [`RawWindowHandle`] variants, as they all represent C types.
356    ///
357    /// Another example would be a system that isn't supported by `raw-window-handle` yet,
358    /// like some game consoles.
359    ///
360    /// In the event that this error is returned, you should try to use the underlying window
361    /// system's native API to get the handle you need.
362    ///
363    /// [`x11rb`]: https://crates.io/crates/x11rb
364    NotSupported,
365
366    /// The underlying handle is not available.
367    ///
368    /// In some cases the underlying window handle may become temporarily unusable. For example, on
369    /// Android, the native window pointer can arbitrarily be replaced or removed by the system. In
370    /// this case, returning a window handle would be disingenuous, as it would not be usable. A
371    /// similar situation can occur on Wayland for the layer shell windows.
372    ///
373    /// In the event that this error is returned, you should wait until the handle becomes available
374    /// again.
375    Unavailable,
376}
377
378impl fmt::Display for HandleError {
379    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380        match self {
381            Self::NotSupported => write!(
382                f,
383                "the underlying handle cannot be represented using the types in this crate"
384            ),
385            Self::Unavailable => write!(f, "the underlying handle is not available"),
386        }
387    }
388}
389
390#[cfg(feature = "std")]
391impl std::error::Error for HandleError {}
392
393macro_rules! from_impl {
394    ($($to:ident, $enum:ident, $from:ty)*) => ($(
395        impl From<$from> for $to {
396            fn from(value: $from) -> Self {
397                $to::$enum(value)
398            }
399        }
400    )*)
401}
402
403from_impl!(RawDisplayHandle, UiKit, UiKitDisplayHandle);
404from_impl!(RawDisplayHandle, AppKit, AppKitDisplayHandle);
405from_impl!(RawDisplayHandle, Orbital, OrbitalDisplayHandle);
406from_impl!(RawDisplayHandle, Ohos, OhosDisplayHandle);
407from_impl!(RawDisplayHandle, Xlib, XlibDisplayHandle);
408from_impl!(RawDisplayHandle, Xcb, XcbDisplayHandle);
409from_impl!(RawDisplayHandle, Wayland, WaylandDisplayHandle);
410from_impl!(RawDisplayHandle, Drm, DrmDisplayHandle);
411from_impl!(RawDisplayHandle, Gbm, GbmDisplayHandle);
412from_impl!(RawDisplayHandle, Windows, WindowsDisplayHandle);
413from_impl!(RawDisplayHandle, Web, WebDisplayHandle);
414from_impl!(RawDisplayHandle, Android, AndroidDisplayHandle);
415from_impl!(RawDisplayHandle, Haiku, HaikuDisplayHandle);
416
417from_impl!(RawWindowHandle, UiKit, UiKitWindowHandle);
418from_impl!(RawWindowHandle, AppKit, AppKitWindowHandle);
419from_impl!(RawWindowHandle, Orbital, OrbitalWindowHandle);
420from_impl!(RawWindowHandle, OhosNdk, OhosNdkWindowHandle);
421from_impl!(RawWindowHandle, Xlib, XlibWindowHandle);
422from_impl!(RawWindowHandle, Xcb, XcbWindowHandle);
423from_impl!(RawWindowHandle, Wayland, WaylandWindowHandle);
424from_impl!(RawWindowHandle, Drm, DrmWindowHandle);
425from_impl!(RawWindowHandle, Gbm, GbmWindowHandle);
426from_impl!(RawWindowHandle, Win32, Win32WindowHandle);
427from_impl!(RawWindowHandle, WinRt, WinRtWindowHandle);
428from_impl!(RawWindowHandle, Web, WebWindowHandle);
429from_impl!(RawWindowHandle, WebCanvas, WebCanvasWindowHandle);
430from_impl!(
431    RawWindowHandle,
432    WebOffscreenCanvas,
433    WebOffscreenCanvasWindowHandle
434);
435from_impl!(RawWindowHandle, AndroidNdk, AndroidNdkWindowHandle);
436from_impl!(RawWindowHandle, Haiku, HaikuWindowHandle);
437
438#[cfg(test)]
439mod tests {
440    use core::panic::{RefUnwindSafe, UnwindSafe};
441    use static_assertions::{assert_impl_all, assert_not_impl_any};
442
443    use super::*;
444
445    #[test]
446    fn auto_traits() {
447        assert_impl_all!(RawDisplayHandle: UnwindSafe, RefUnwindSafe, Unpin);
448        assert_not_impl_any!(RawDisplayHandle: Send, Sync);
449        assert_impl_all!(DisplayHandle<'_>: UnwindSafe, RefUnwindSafe, Unpin);
450        assert_not_impl_any!(DisplayHandle<'_>: Send, Sync);
451        assert_impl_all!(RawWindowHandle: UnwindSafe, RefUnwindSafe, Unpin);
452        assert_not_impl_any!(RawWindowHandle: Send, Sync);
453        assert_impl_all!(WindowHandle<'_>: UnwindSafe, RefUnwindSafe, Unpin);
454        assert_not_impl_any!(WindowHandle<'_>: Send, Sync);
455        assert_impl_all!(HandleError: Send, Sync, UnwindSafe, RefUnwindSafe, Unpin);
456
457        // TODO: Unsure if some of these should not actually be Send + Sync
458        assert_impl_all!(UiKitDisplayHandle: Send, Sync);
459        assert_impl_all!(AppKitDisplayHandle: Send, Sync);
460        assert_impl_all!(OrbitalDisplayHandle: Send, Sync);
461        assert_impl_all!(OhosDisplayHandle: Send, Sync);
462        assert_not_impl_any!(XlibDisplayHandle: Send, Sync);
463        assert_not_impl_any!(XcbDisplayHandle: Send, Sync);
464        assert_not_impl_any!(WaylandDisplayHandle: Send, Sync);
465        assert_impl_all!(DrmDisplayHandle: Send, Sync);
466        assert_not_impl_any!(GbmDisplayHandle: Send, Sync);
467        assert_impl_all!(WindowsDisplayHandle: Send, Sync);
468        assert_impl_all!(WebDisplayHandle: Send, Sync);
469        assert_impl_all!(AndroidDisplayHandle: Send, Sync);
470        assert_impl_all!(HaikuDisplayHandle: Send, Sync);
471
472        // TODO: Unsure if some of these should not actually be Send + Sync
473        assert_not_impl_any!(UiKitWindowHandle: Send, Sync);
474        assert_not_impl_any!(AppKitWindowHandle: Send, Sync);
475        assert_not_impl_any!(OrbitalWindowHandle: Send, Sync);
476        assert_not_impl_any!(OhosNdkWindowHandle: Send, Sync);
477        assert_impl_all!(XlibWindowHandle: Send, Sync);
478        assert_impl_all!(XcbWindowHandle: Send, Sync);
479        assert_not_impl_any!(WaylandWindowHandle: Send, Sync);
480        assert_impl_all!(DrmWindowHandle: Send, Sync);
481        assert_not_impl_any!(GbmWindowHandle: Send, Sync);
482        assert_impl_all!(Win32WindowHandle: Send, Sync);
483        assert_not_impl_any!(WinRtWindowHandle: Send, Sync);
484        assert_impl_all!(WebWindowHandle: Send, Sync);
485        assert_not_impl_any!(WebCanvasWindowHandle: Send, Sync);
486        assert_not_impl_any!(WebOffscreenCanvasWindowHandle: Send, Sync);
487        assert_not_impl_any!(AndroidNdkWindowHandle: Send, Sync);
488        assert_not_impl_any!(HaikuWindowHandle: Send, Sync);
489    }
490
491    #[allow(deprecated, unused)]
492    fn assert_object_safe(
493        _: &dyn HasRawWindowHandle,
494        _: &dyn HasRawDisplayHandle,
495        _: &dyn HasWindowHandle,
496        _: &dyn HasDisplayHandle,
497    ) {
498    }
499}