1//! Utilities to access X11 specific config properties.
2
3use std::mem;
4
5use once_cell::sync::Lazy;
6use x11_dl::xlib::{Display, XVisualInfo, Xlib};
7#[cfg(egl_backend)]
8use x11_dl::xlib::{VisualIDMask, XID};
9use x11_dl::xrender::Xrender;
10
11/// The XLIB handle.
12pub(crate) static XLIB: Lazy<Option<Xlib>> = Lazy::new(|| Xlib::open().ok());
13
14/// The XRENDER handle.
15static XRENDER: Lazy<Option<Xrender>> = Lazy::new(|| Xrender::open().ok());
16
17/// The GlConfig extension trait to get X11 specific properties from a config.
18pub 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)]
28pub struct X11VisualInfo {
29 raw: *const XVisualInfo,
30 transparency: bool,
31}
32
33impl 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
96impl Drop for X11VisualInfo {
97 fn drop(&mut self) {
98 unsafe {
99 (XLIB.as_ref().unwrap().XFree)(self.raw as *mut _);
100 }
101 }
102}
103