1pub extern crate x11;
49
50use euclid::default::{Point2D, Size2D};
51use std::{
52 ffi::CString,
53 fmt, mem,
54 os::raw::{c_char, c_int, c_uint},
55 ptr::{self, NonNull},
56 sync::{Arc, Weak},
57};
58use x11::xlib::{self, XID};
59
60pub use x11::xlib::{Atom, KeySym};
61
62pub mod color;
63pub use color::*;
64pub mod context;
65pub use context::*;
66pub mod drawable;
67pub use drawable::*;
68pub mod error;
69pub use error::*;
70pub mod event;
71pub use event::*;
72pub mod font;
73pub use font::*;
74pub mod image;
75pub use image::*;
76pub mod pixmap;
77pub use pixmap::*;
78mod screen;
79pub use screen::*;
80pub mod text;
81pub use text::*;
82pub mod window;
83pub use window::*;
84
85#[inline]
87pub(crate) unsafe fn to_cstring(s: &str) -> Result<*mut c_char, FlutterbugError> {
88 Ok(CString::new(s)?.into_raw())
89}
90
91#[inline]
93pub(crate) fn cstring_buffer(len: usize) -> CString {
94 let mut buffer: Vec<u8> = Vec::with_capacity(len + 1);
95 buffer.extend([b' '].iter().cycle().take(len));
96 unsafe { CString::from_vec_unchecked(buffer) }
97}
98
99pub trait HasXID {
101 fn xid(&self) -> XID;
103}
104
105impl HasXID for XID {
106 #[inline]
107 fn xid(&self) -> XID {
108 *self
109 }
110}
111
112pub struct Display {
117 raw: Arc<NonNull<xlib::Display>>,
118}
119
120impl PartialEq for Display {
121 #[inline]
122 fn eq(&self, other: &Self) -> bool {
123 self.raw.as_ptr() == other.raw.as_ptr()
125 }
126}
127
128impl Eq for Display {}
129
130impl fmt::Debug for Display {
132 #[inline]
133 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134 write!(f, "X11 Display Object")
135 }
136}
137
138impl Drop for Display {
139 fn drop(&mut self) {
140 unsafe { xlib::XCloseDisplay(self.raw.as_ptr()) };
141 }
142}
143
144impl Display {
145 #[inline]
149 pub fn new() -> Result<Self, FlutterbugError> {
150 let display_ptr = unsafe { xlib::XOpenDisplay(ptr::null()) };
151 match NonNull::new(display_ptr) {
152 Some(dpy) => Ok(Self::from_raw(Arc::new(dpy))),
153 None => Err(FlutterbugError::UnableToOpenDisplay),
154 }
155 }
156
157 #[inline]
161 pub(crate) fn from_raw(raw: Arc<NonNull<xlib::Display>>) -> Self {
162 Self { raw }
163 }
164}
165
166pub struct DisplayReference {
170 reference: Weak<NonNull<xlib::Display>>,
171}
172
173impl fmt::Debug for DisplayReference {
175 #[inline]
176 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177 write!(f, "X11 Display Reference")
178 }
179}
180
181impl PartialEq for DisplayReference {
182 fn eq(&self, other: &Self) -> bool {
183 self.reference.ptr_eq(&other.reference)
184 }
185}
186
187impl Clone for DisplayReference {
188 #[inline]
189 fn clone(&self) -> Self {
190 Self {
191 reference: self.reference.clone(),
192 }
193 }
194}
195
196impl DisplayReference {
197 #[inline]
198 pub(crate) fn from_ref(reference: Weak<NonNull<xlib::Display>>) -> Self {
199 Self { reference }
200 }
201}
202
203pub trait GenericDisplay: fmt::Debug {
209 fn reference(&self) -> DisplayReference;
211
212 fn raw(&self) -> Result<NonNull<xlib::Display>, FlutterbugError>;
214
215 #[inline]
217 fn default_screen(&self) -> Result<Screen, FlutterbugError> {
218 Ok(Screen::new(unsafe {
219 xlib::XDefaultScreen(self.raw()?.as_mut())
220 }))
221 }
222
223 #[inline]
225 fn visual(&self, screen: Screen) -> Result<*mut xlib::Visual, FlutterbugError> {
226 Ok(unsafe { xlib::XDefaultVisual(self.raw()?.as_mut(), screen.value()) })
227 }
228
229 #[inline]
231 fn default_visual(&self) -> Result<*mut xlib::Visual, FlutterbugError> {
232 self.visual(self.default_screen()?)
233 }
234
235 #[inline]
237 fn black_pixel(&self, screen: Screen) -> Result<Color, FlutterbugError> {
238 Ok(Color::PixelID(unsafe {
239 xlib::XBlackPixel(self.raw()?.as_mut(), screen.value())
240 }))
241 }
242
243 #[inline]
245 fn default_black_pixel(&self) -> Result<Color, FlutterbugError> {
246 self.black_pixel(self.default_screen()?)
247 }
248
249 #[inline]
251 fn white_pixel(&self, screen: Screen) -> Result<Color, FlutterbugError> {
252 Ok(Color::PixelID(unsafe {
253 xlib::XWhitePixel(self.raw()?.as_mut(), screen.value())
254 }))
255 }
256
257 #[inline]
259 fn default_white_pixel(&self) -> Result<Color, FlutterbugError> {
260 self.white_pixel(self.default_screen()?)
261 }
262
263 #[inline]
265 fn colormap(&self, screen: Screen) -> Result<ColorMap, FlutterbugError> {
266 let cmp = unsafe { xlib::XDefaultColormap(self.raw()?.as_mut(), screen.value()) };
267 Ok(ColorMap::from_raw(cmp, self.reference(), true)?)
268 }
269
270 #[inline]
272 fn default_colormap(&self) -> Result<ColorMap, FlutterbugError> {
273 self.colormap(self.default_screen()?)
274 }
275
276 #[inline]
278 fn gc(&self, screen: Screen) -> Result<GraphicsContext, FlutterbugError> {
279 let gc = unsafe { xlib::XDefaultGC(self.raw()?.as_mut(), screen.value()) };
280 let gc = NonNull::new(gc).ok_or_else(|| FlutterbugError::GCWasNull)?;
281 Ok(GraphicsContext::from_raw(Arc::new(gc), self.reference(), true))
282 }
283
284 #[inline]
286 fn default_gc(&self) -> Result<GraphicsContext, FlutterbugError> {
287 self.gc(self.default_screen()?)
288 }
289
290 fn create_simple_window(
292 &self,
293 parent: Option<&Window>,
294 origin: Point2D<i32>,
295 size: Size2D<u32>,
296 border_width: u32,
297 border_color: Color,
298 background_color: Color,
299 ) -> Result<Window, FlutterbugError> {
300 macro_rules! test_color {
301 ($cname: ident) => {
302 if $cname != self.default_black_pixel()? && $cname != self.default_white_pixel()? {
303 return Err(FlutterbugError::Msg(format!(
304 "{} must be either black or white",
305 &stringify!($cname)
306 )));
307 }
308 };
309 }
310
311 test_color!(border_color);
312 test_color!(background_color);
313
314 let win = unsafe {
315 xlib::XCreateSimpleWindow(
316 self.raw()?.as_mut(),
317 match parent {
318 Some(p) => p.window(),
319 None => xlib::XRootWindow(self.raw()?.as_mut(), self.default_screen()?.value()),
320 },
321 origin.x as c_int,
322 origin.y as c_int,
323 size.width as c_uint,
324 size.height as c_uint,
325 border_width as c_uint,
326 border_color.pixel_id(),
327 background_color.pixel_id(),
328 )
329 };
330
331 let gc = unsafe { xlib::XCreateGC(self.raw()?.as_mut(), win, 0, ptr::null_mut()) };
333 let gc = NonNull::new(gc).ok_or_else(|| FlutterbugError::GCWasNull)?;
334 let gc = GraphicsContext::from_raw(Arc::new(gc), self.reference(), false);
335
336 Ok(Window::from_raw(win, self.reference(), gc))
337 }
338 fn create_context(&self) -> Result<Context, FlutterbugError> {
340 Ok(Context::from_dpy(self.reference()))
341 }
342 fn internal_atom(
344 &self,
345 name: &str,
346 create_if_exists: bool,
347 ) -> Result<xlib::Atom, FlutterbugError> {
348 let txt = unsafe { to_cstring(name) }?;
349 let val = Ok(unsafe {
350 xlib::XInternAtom(
351 self.raw()?.as_mut(),
352 txt,
353 if create_if_exists { 1 } else { 0 },
354 )
355 });
356 let _ = unsafe { CString::from_raw(txt) };
357 val
358 }
359 fn input_method(&self) -> Result<InputMethod, FlutterbugError> {
361 unsafe { libc::setlocale(libc::LC_ALL, (&[0]).as_ptr()) };
363 unsafe { xlib::XSetLocaleModifiers((&[0]).as_ptr()) };
364
365 #[inline]
366 fn open_im(mut dpy: NonNull<xlib::Display>) -> xlib::XIM {
367 unsafe {
368 xlib::XOpenIM(
369 dpy.as_mut(),
370 ptr::null_mut(),
371 ptr::null_mut(),
372 ptr::null_mut(),
373 )
374 }
375 }
376
377 let xim = NonNull::new(open_im(self.raw()?));
378 Ok(InputMethod::from_raw(
379 self.reference(),
380 match xim {
381 Some(x) => x,
382 None => {
383 let txt = unsafe { to_cstring("@im=none") }?;
385 unsafe { xlib::XSetLocaleModifiers(txt) };
386 let _ = unsafe { CString::from_raw(txt) };
387
388 NonNull::new(open_im(self.raw()?))
389 .ok_or_else(|| FlutterbugError::InputMethodNull)?
390 }
391 },
392 ))
393 }
394 #[inline]
396 fn create_image(
397 &self,
398 bounds: Size2D<u32>,
399 depth: u32,
400 data: Vec<c_char>,
401 ) -> Result<Image, FlutterbugError> {
402 let mut boxed = data.into_boxed_slice();
403 let ptr = boxed.as_mut_ptr();
404 let raw = self.raw()?;
405 let img = unsafe {
406 xlib::XCreateImage(
407 raw.as_ptr(),
408 self.default_visual()?,
409 depth as c_uint,
410 xlib::ZPixmap,
411 0,
412 ptr,
413 bounds.width,
414 bounds.height,
415 32,
416 0,
417 )
418 };
419 let img = NonNull::new(img).ok_or_else(|| FlutterbugError::ImageWasNull)?;
420
421 mem::forget(boxed);
423
424 Ok(Image::from_raw(Arc::new(img)))
425 }
426
427 fn sync(&self, s: bool) -> Result<(), FlutterbugError> {
428 unsafe { xlib::XSync(self.raw()?.as_mut(), if s { 1 } else { 0 }) };
429 Ok(())
430 }
431
432 fn depth(&self, screen: Screen) -> Result<i32, FlutterbugError> {
434 Ok(unsafe { xlib::XDefaultDepth(self.raw()?.as_mut(), screen.value()) })
435 }
436
437 fn default_depth(&self) -> Result<i32, FlutterbugError> {
439 self.depth(self.default_screen()?)
440 }
441}
442
443impl GenericDisplay for Display {
444 #[inline]
445 fn reference(&self) -> DisplayReference {
446 DisplayReference::from_ref(Arc::downgrade(&self.raw))
447 }
448 #[inline]
449 fn raw(&self) -> Result<NonNull<xlib::Display>, FlutterbugError> {
450 Ok(*self.raw)
451 }
452}
453
454impl GenericDisplay for DisplayReference {
456 #[inline]
457 fn reference(&self) -> DisplayReference {
458 self.clone()
459 }
460 #[inline]
461 fn raw(&self) -> Result<NonNull<xlib::Display>, FlutterbugError> {
462 Ok(*self
463 .reference
464 .upgrade()
465 .ok_or_else(|| FlutterbugError::PointerWasDropped(DroppableObject::Display))?)
466 }
467}
468
469pub mod prelude {
471 pub use super::{
472 DerivesAnEvent, DerivesEvent, Drawable, GenericDisplay, GenericGraphicsContext,
473 GenericImage, GenericInputContext, HasXID,
474 };
475}