1 | //! Utilities to access X11 specific config properties. |
2 | |
3 | use std::mem; |
4 | |
5 | use once_cell::sync::Lazy; |
6 | use x11_dl::xlib::{Display, XVisualInfo, Xlib}; |
7 | #[cfg (egl_backend)] |
8 | use x11_dl::xlib::{VisualIDMask, XID}; |
9 | use x11_dl::xrender::Xrender; |
10 | |
11 | /// The XLIB handle. |
12 | pub(crate) static XLIB: Lazy<Option<Xlib>> = Lazy::new(|| Xlib::open().ok()); |
13 | |
14 | /// The XRENDER handle. |
15 | static XRENDER: Lazy<Option<Xrender>> = Lazy::new(|| Xrender::open().ok()); |
16 | |
17 | /// The GlConfig extension trait to get X11 specific properties from a config. |
18 | pub trait X11GlConfigExt { |
19 | /// The `X11VisualInfo` that must be used to inititalize the Xlib window. |
20 | fn x11_visual(&self) -> Option<X11VisualInfo>; |
21 | } |
22 | |
23 | /// The X11 visual info. |
24 | /// |
25 | /// This must be used when building X11 window, so it'll be compatible with the |
26 | /// underlying Api. |
27 | #[derive (Debug)] |
28 | pub struct X11VisualInfo { |
29 | raw: *const XVisualInfo, |
30 | transparency: bool, |
31 | } |
32 | |
33 | impl X11VisualInfo { |
34 | #[cfg (egl_backend)] |
35 | pub(crate) unsafe fn from_xid(display: *mut Display, xid: XID) -> Option<Self> { |
36 | let xlib = XLIB.as_ref().unwrap(); |
37 | |
38 | if xid == 0 { |
39 | return None; |
40 | } |
41 | |
42 | let raw = unsafe { |
43 | let mut raw: XVisualInfo = std::mem::zeroed(); |
44 | raw.visualid = xid; |
45 | |
46 | let mut num_visuals = 0; |
47 | (xlib.XGetVisualInfo)(display, VisualIDMask, &mut raw, &mut num_visuals) |
48 | }; |
49 | |
50 | if raw.is_null() { |
51 | return None; |
52 | } |
53 | |
54 | let transparency = Self::has_non_zero_alpha(display, raw); |
55 | |
56 | Some(Self { raw, transparency }) |
57 | } |
58 | |
59 | #[cfg (glx_backend)] |
60 | pub(crate) unsafe fn from_raw(display: *mut Display, raw: *const XVisualInfo) -> Self { |
61 | let transparency = Self::has_non_zero_alpha(display, raw); |
62 | Self { raw, transparency } |
63 | } |
64 | |
65 | /// Returns `true` if the visual has non-zero alpha mask. |
66 | pub fn supports_transparency(&self) -> bool { |
67 | self.transparency |
68 | } |
69 | |
70 | /// Get XID of for this visual. |
71 | pub fn visual_id(&self) -> std::ffi::c_ulong { |
72 | unsafe { (*self.raw).visualid } |
73 | } |
74 | |
75 | /// Convert the visual to the raw pointer. |
76 | /// |
77 | /// You must clear it with `XFree` after the use. |
78 | pub fn into_raw(self) -> *const std::ffi::c_void { |
79 | let raw = self.raw as *const _; |
80 | mem::forget(self); |
81 | raw |
82 | } |
83 | |
84 | pub(crate) fn has_non_zero_alpha(display: *mut Display, raw: *const XVisualInfo) -> bool { |
85 | let xrender = XRENDER.as_ref().unwrap(); |
86 | unsafe { |
87 | let visual_format = (xrender.XRenderFindVisualFormat)(display, (*raw).visual); |
88 | |
89 | (!visual_format.is_null()) |
90 | .then(|| (*visual_format).direct.alphaMask != 0) |
91 | .unwrap_or(false) |
92 | } |
93 | } |
94 | } |
95 | |
96 | impl Drop for X11VisualInfo { |
97 | fn drop(&mut self) { |
98 | unsafe { |
99 | (XLIB.as_ref().unwrap().XFree)(self.raw as *mut _); |
100 | } |
101 | } |
102 | } |
103 | |