1use as_raw_xcb_connection::xcb_connection_t;
23use std::os::raw::{c_char, c_int, c_uchar, c_ulong};
24
25#[cfg(feature = "dlopen")]
27include! {
28 concat!(env!("OUT_DIR"), "/libdir.rs")
29}
30
31pub(crate) enum Display {}
33
34#[repr(C)]
36#[derive(Clone, Copy)]
37pub(crate) struct XErrorEvent {
38 pub type_: c_int,
39 pub display: *mut Display,
40 pub resourceid: c_ulong,
41 pub serial: c_ulong,
42 pub error_code: c_uchar,
43 pub request_code: c_uchar,
44 pub minor_code: c_uchar,
45}
46
47type XOpenDisplay = unsafe extern "C" fn(display_name: *const c_char) -> *mut Display;
49type XCloseDisplay = unsafe extern "C" fn(display: *mut Display) -> c_int;
50type XGetXCBConnection = unsafe extern "C" fn(display: *mut Display) -> *mut xcb_connection_t;
51type XDefaultScreen = unsafe extern "C" fn(display: *mut Display) -> c_int;
52pub(crate) type XErrorHook =
53 Option<unsafe extern "C" fn(display: *mut Display, error_event: *mut XErrorEvent) -> c_int>;
54type XSetErrorHandler = unsafe extern "C" fn(handler: XErrorHook) -> XErrorHook;
55type XInitThreads = unsafe extern "C" fn() -> c_int;
56
57pub(crate) struct Xlib {
59 #[cfg(feature = "dlopen")]
61 _xlib_library: libloading::Library,
62
63 #[cfg(feature = "dlopen")]
65 _xlib_xcb_library: libloading::Library,
66
67 x_open_display: XOpenDisplay,
69
70 x_close_display: XCloseDisplay,
72
73 x_get_xcb_connection: XGetXCBConnection,
75
76 x_default_screen: XDefaultScreen,
78
79 x_set_error_handler: XSetErrorHandler,
81
82 x_init_threads: XInitThreads,
84}
85
86impl Xlib {
87 pub(crate) unsafe fn open_display(&self, display_name: *const c_char) -> *mut Display {
89 (self.x_open_display)(display_name)
90 }
91
92 pub(crate) unsafe fn close_display(&self, display: *mut Display) -> c_int {
94 (self.x_close_display)(display)
95 }
96
97 pub(crate) unsafe fn get_xcb_connection(&self, display: *mut Display) -> *mut xcb_connection_t {
99 (self.x_get_xcb_connection)(display)
100 }
101
102 pub(crate) unsafe fn default_screen(&self, display: *mut Display) -> c_int {
104 (self.x_default_screen)(display)
105 }
106
107 pub(crate) unsafe fn set_error_handler(&self, handler: XErrorHook) -> XErrorHook {
109 (self.x_set_error_handler)(handler)
110 }
111
112 pub(crate) unsafe fn init_threads(&self) -> c_int {
114 (self.x_init_threads)()
115 }
116
117 #[cfg_attr(coverage, no_coverage)]
119 #[cfg(not(feature = "dlopen"))]
120 pub(crate) fn load() -> Result<Self, std::io::Error> {
121 #[link(name = "X11", kind = "dylib")]
122 extern "C" {
123 fn XOpenDisplay(display_name: *const c_char) -> *mut Display;
124 fn XCloseDisplay(display: *mut Display) -> c_int;
125 fn XDefaultScreen(display: *mut Display) -> c_int;
126 fn XSetErrorHandler(handler: XErrorHook) -> XErrorHook;
127 fn XInitThreads() -> c_int;
128 }
129
130 #[link(name = "X11-xcb", kind = "dylib")]
131 extern "C" {
132 fn XGetXCBConnection(display: *mut Display) -> *mut xcb_connection_t;
133 }
134
135 Ok(Self {
136 x_open_display: XOpenDisplay,
137 x_close_display: XCloseDisplay,
138 x_get_xcb_connection: XGetXCBConnection,
139 x_default_screen: XDefaultScreen,
140 x_set_error_handler: XSetErrorHandler,
141 x_init_threads: XInitThreads,
142 })
143 }
144
145 #[cfg_attr(coverage, no_coverage)]
147 #[cfg(feature = "dlopen")]
148 pub(crate) fn load() -> Result<Self, libloading::Error> {
149 let xlib_library = unsafe { load_library(XLIB_LIBDIR, &["libX11.so.6", "libX11.so"]) }?;
150 let xlib_xcb_library =
151 unsafe { load_library(XLIB_XCB_LIBDIR, &["libX11-xcb.so.1", "libX11-xcb.so"]) }?;
152
153 let x_open_display = unsafe { xlib_library.get::<XOpenDisplay>(b"XOpenDisplay\0")? };
154
155 let x_close_display = unsafe { xlib_library.get::<XCloseDisplay>(b"XCloseDisplay\0")? };
156
157 let x_set_error_handler =
158 unsafe { xlib_library.get::<XSetErrorHandler>(b"XSetErrorHandler\0")? };
159
160 let x_default_screen = unsafe { xlib_library.get::<XDefaultScreen>(b"XDefaultScreen\0")? };
161
162 let x_get_xcb_connection =
163 unsafe { xlib_xcb_library.get::<XGetXCBConnection>(b"XGetXCBConnection\0")? };
164
165 let x_init_threads = unsafe { xlib_library.get::<XInitThreads>(b"XInitThreads\0")? };
166
167 Ok(Self {
168 x_open_display: *x_open_display,
169 x_close_display: *x_close_display,
170 x_get_xcb_connection: *x_get_xcb_connection,
171 x_default_screen: *x_default_screen,
172 x_set_error_handler: *x_set_error_handler,
173 x_init_threads: *x_init_threads,
174 _xlib_library: xlib_library,
175 _xlib_xcb_library: xlib_xcb_library,
176 })
177 }
178}
179
180#[cfg(feature = "dlopen")]
181#[cfg_attr(coverage, no_coverage)]
182unsafe fn load_library(
183 prefix: Option<&str>,
184 names: &[&str],
185) -> Result<libloading::Library, libloading::Error> {
186 use std::path::{Path, PathBuf};
187
188 debug_assert!(!names.is_empty());
189 let mut last_error = None;
190
191 for name in names {
192 let realpath = match prefix {
193 Some(prefix) => Path::new(prefix).join(name),
194 None => PathBuf::from(name),
195 };
196 match libloading::Library::new(realpath) {
197 Ok(lib) => return Ok(lib),
198 Err(err) => {
199 last_error = Some(err);
200 }
201 }
202 }
203
204 if prefix.is_some() {
205 if let Ok(lib) = load_library(None, names) {
206 return Ok(lib);
207 }
208 }
209
210 Err(last_error.unwrap())
211}