1#![forbid(future_incompatible, rust_2018_idioms)]
11
12use raw_window_handle::{self as rwh, HasRawDisplayHandle, RawDisplayHandle};
13use std::fmt;
14
15pub struct Display {
17 _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 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#[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}