instant_display/
lib.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0 OR Zlib
2
3//! A simple type that allows you to get a display handle if you don't need a window.
4//! 
5//! This is useful for crates like [`glutin`], where a display handle can be feasibly used
6//! without an involved window handle.
7//! 
8//! [`glutin`]: https://crates.io/crates/glutin
9
10#![forbid(future_incompatible, rust_2018_idioms)]
11
12use raw_window_handle::{self as rwh, HasRawDisplayHandle, RawDisplayHandle};
13use std::fmt;
14
15/// The whole point.
16pub struct Display {
17    /// This type is a private field to prevent construction.
18    _private: (),
19
20    #[cfg(all(
21        unix,
22        not(any(target_vendor = "apple", target_os = "android", target_os = "redox"))
23    ))]
24    global_display: (&'static GlobalDisplay, usize),
25}
26
27impl Display {
28    /// Create a new `Display`.
29    pub fn new() -> Result<Self, Error> {
30        cfg_if::cfg_if! {
31            if #[cfg(all(unix, not(any(target_vendor = "apple", target_os = "android", target_os = "redox"))))] {
32                let (display, screen) = get_display().as_ref().map_err(Error)?;
33                Ok(Self {
34                    _private: (),
35                    global_display: (display, *screen),
36                })
37            } else {
38                Ok(Self {
39                    _private: ()
40                })
41            }
42        }
43    }
44
45    fn raw_handle(&self) -> RawDisplayHandle {
46        cfg_if::cfg_if! {
47            if #[cfg(windows)] {
48                RawDisplayHandle::Windows(rwh::WindowsDisplayHandle::empty())
49            } else if #[cfg(target_os = "macos")] {
50                RawDisplayHandle::AppKit(rwh::AppKitDisplayHandle::empty())
51            } else if #[cfg(target_vendor = "apple")] {
52                RawDisplayHandle::UiKit(rwh::UiKitDisplayHandle::empty())
53            } else if #[cfg(target_os = "redox")] {
54                RawDisplayHandle::Orbital(rwh::OrbitalDisplayHandle::empty())
55            } else if #[cfg(target_os = "android")] {
56                RawDisplayHandle::Android(rwh::AndroidDisplayHandle::empty())
57            } else if #[cfg(target_family = "wasm")] {
58                RawDisplayHandle::Web(rwh::WebDisplayHandle::empty())
59            } else if #[cfg(target_os = "haiku")] {
60                RawDisplayHandle::Haiku(rwh::HaikuDisplayHandle::empty())
61            } else if #[cfg(unix)] {
62                let mut handle = rwh::XcbDisplayHandle::empty();
63                handle.connection = self.global_display.0.get_raw_xcb_connection();
64                handle.screen = self.global_display.1 as _;
65                RawDisplayHandle::Xcb(handle)
66            } else {
67                compile_error!("Unsupported platform");
68            }
69        }
70    }
71}
72
73unsafe impl HasRawDisplayHandle for Display {
74    fn raw_display_handle(&self) -> RawDisplayHandle {
75        self.raw_handle()
76    }
77}
78
79impl rwh::HasDisplayHandle for Display {
80    fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
81        unsafe { Ok(rwh::DisplayHandle::borrow_raw(self.raw_handle())) }
82    }
83}
84
85/// The inner error type.
86#[derive(Debug)]
87pub struct Error(ErrorImpl);
88
89impl fmt::Display for Error {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        fmt::Display::fmt(self.0, f)
92    }
93}
94
95impl std::error::Error for Error {}
96
97#[cfg(all(
98    unix,
99    not(any(target_vendor = "apple", target_os = "android", target_os = "redox"))
100))]
101mod global_display {
102    pub(crate) use x11rb::xcb_ffi::XCBConnection as GlobalDisplay;
103
104    use once_cell::sync::OnceCell;
105    use x11rb::errors::ConnectError;
106
107    pub(crate) type ErrorImpl = &'static ConnectError;
108    type GlobalResult = Result<(GlobalDisplay, usize), ConnectError>;
109
110    #[inline]
111    pub(crate) fn get_display() -> &'static GlobalResult {
112        static GLOBAL_DISPLAY: OnceCell<GlobalResult> = OnceCell::new();
113        GLOBAL_DISPLAY.get_or_init(|| GlobalDisplay::connect(None))
114    }
115}
116
117#[cfg(all(
118    unix,
119    not(any(target_vendor = "apple", target_os = "android", target_os = "redox"))
120))]
121use global_display::*;
122
123#[cfg(not(all(
124    unix,
125    not(any(target_vendor = "apple", target_os = "android", target_os = "redox"))
126)))]
127type ErrorImpl = std::convert::Infallible;
128
129#[cfg(test)]
130mod tests {
131    #[test]
132    fn smoke() {
133        super::Display::new().unwrap();
134    }
135}