pub extern crate x11;
use euclid::default::{Point2D, Size2D};
use std::{
ffi::CString,
fmt, mem,
os::raw::{c_char, c_int, c_uint},
ptr::{self, NonNull},
sync::{Arc, Weak},
};
use x11::xlib::{self, XID};
pub use x11::xlib::{Atom, KeySym};
pub mod color;
pub use color::*;
pub mod context;
pub use context::*;
pub mod drawable;
pub use drawable::*;
pub mod error;
pub use error::*;
pub mod event;
pub use event::*;
pub mod font;
pub use font::*;
pub mod image;
pub use image::*;
pub mod pixmap;
pub use pixmap::*;
mod screen;
pub use screen::*;
pub mod text;
pub use text::*;
pub mod window;
pub use window::*;
#[inline]
pub(crate) unsafe fn to_cstring(s: &str) -> Result<*mut c_char, FlutterbugError> {
Ok(CString::new(s)?.into_raw())
}
#[inline]
pub(crate) fn cstring_buffer(len: usize) -> CString {
let mut buffer: Vec<u8> = Vec::with_capacity(len + 1);
buffer.extend([b' '].iter().cycle().take(len));
unsafe { CString::from_vec_unchecked(buffer) }
}
pub trait HasXID {
fn xid(&self) -> XID;
}
impl HasXID for XID {
#[inline]
fn xid(&self) -> XID {
*self
}
}
pub struct Display {
raw: Arc<NonNull<xlib::Display>>,
}
impl PartialEq for Display {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.raw.as_ptr() == other.raw.as_ptr()
}
}
impl Eq for Display {}
impl fmt::Debug for Display {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "X11 Display Object")
}
}
impl Drop for Display {
fn drop(&mut self) {
unsafe { xlib::XCloseDisplay(self.raw.as_ptr()) };
}
}
impl Display {
#[inline]
pub fn new() -> Result<Self, FlutterbugError> {
let display_ptr = unsafe { xlib::XOpenDisplay(ptr::null()) };
match NonNull::new(display_ptr) {
Some(dpy) => Ok(Self::from_raw(Arc::new(dpy))),
None => Err(FlutterbugError::UnableToOpenDisplay),
}
}
#[inline]
pub(crate) fn from_raw(raw: Arc<NonNull<xlib::Display>>) -> Self {
Self { raw }
}
}
pub struct DisplayReference {
reference: Weak<NonNull<xlib::Display>>,
}
impl fmt::Debug for DisplayReference {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "X11 Display Reference")
}
}
impl PartialEq for DisplayReference {
fn eq(&self, other: &Self) -> bool {
self.reference.ptr_eq(&other.reference)
}
}
impl Clone for DisplayReference {
#[inline]
fn clone(&self) -> Self {
Self {
reference: self.reference.clone(),
}
}
}
impl DisplayReference {
#[inline]
pub(crate) fn from_ref(reference: Weak<NonNull<xlib::Display>>) -> Self {
Self { reference }
}
}
pub trait GenericDisplay: fmt::Debug {
fn reference(&self) -> DisplayReference;
fn raw(&self) -> Result<NonNull<xlib::Display>, FlutterbugError>;
#[inline]
fn default_screen(&self) -> Result<Screen, FlutterbugError> {
Ok(Screen::new(unsafe {
xlib::XDefaultScreen(self.raw()?.as_mut())
}))
}
#[inline]
fn visual(&self, screen: Screen) -> Result<*mut xlib::Visual, FlutterbugError> {
Ok(unsafe { xlib::XDefaultVisual(self.raw()?.as_mut(), screen.value()) })
}
#[inline]
fn default_visual(&self) -> Result<*mut xlib::Visual, FlutterbugError> {
self.visual(self.default_screen()?)
}
#[inline]
fn black_pixel(&self, screen: Screen) -> Result<Color, FlutterbugError> {
Ok(Color::PixelID(unsafe {
xlib::XBlackPixel(self.raw()?.as_mut(), screen.value())
}))
}
#[inline]
fn default_black_pixel(&self) -> Result<Color, FlutterbugError> {
self.black_pixel(self.default_screen()?)
}
#[inline]
fn white_pixel(&self, screen: Screen) -> Result<Color, FlutterbugError> {
Ok(Color::PixelID(unsafe {
xlib::XWhitePixel(self.raw()?.as_mut(), screen.value())
}))
}
#[inline]
fn default_white_pixel(&self) -> Result<Color, FlutterbugError> {
self.white_pixel(self.default_screen()?)
}
#[inline]
fn colormap(&self, screen: Screen) -> Result<ColorMap, FlutterbugError> {
let cmp = unsafe { xlib::XDefaultColormap(self.raw()?.as_mut(), screen.value()) };
Ok(ColorMap::from_raw(cmp, self.reference(), true)?)
}
#[inline]
fn default_colormap(&self) -> Result<ColorMap, FlutterbugError> {
self.colormap(self.default_screen()?)
}
#[inline]
fn gc(&self, screen: Screen) -> Result<GraphicsContext, FlutterbugError> {
let gc = unsafe { xlib::XDefaultGC(self.raw()?.as_mut(), screen.value()) };
let gc = NonNull::new(gc).ok_or_else(|| FlutterbugError::GCWasNull)?;
Ok(GraphicsContext::from_raw(Arc::new(gc), self.reference(), true))
}
#[inline]
fn default_gc(&self) -> Result<GraphicsContext, FlutterbugError> {
self.gc(self.default_screen()?)
}
fn create_simple_window(
&self,
parent: Option<&Window>,
origin: Point2D<i32>,
size: Size2D<u32>,
border_width: u32,
border_color: Color,
background_color: Color,
) -> Result<Window, FlutterbugError> {
macro_rules! test_color {
($cname: ident) => {
if $cname != self.default_black_pixel()? && $cname != self.default_white_pixel()? {
return Err(FlutterbugError::Msg(format!(
"{} must be either black or white",
&stringify!($cname)
)));
}
};
}
test_color!(border_color);
test_color!(background_color);
let win = unsafe {
xlib::XCreateSimpleWindow(
self.raw()?.as_mut(),
match parent {
Some(p) => p.window(),
None => xlib::XRootWindow(self.raw()?.as_mut(), self.default_screen()?.value()),
},
origin.x as c_int,
origin.y as c_int,
size.width as c_uint,
size.height as c_uint,
border_width as c_uint,
border_color.pixel_id(),
background_color.pixel_id(),
)
};
let gc = unsafe { xlib::XCreateGC(self.raw()?.as_mut(), win, 0, ptr::null_mut()) };
let gc = NonNull::new(gc).ok_or_else(|| FlutterbugError::GCWasNull)?;
let gc = GraphicsContext::from_raw(Arc::new(gc), self.reference(), false);
Ok(Window::from_raw(win, self.reference(), gc))
}
fn create_context(&self) -> Result<Context, FlutterbugError> {
Ok(Context::from_dpy(self.reference()))
}
fn internal_atom(
&self,
name: &str,
create_if_exists: bool,
) -> Result<xlib::Atom, FlutterbugError> {
let txt = unsafe { to_cstring(name) }?;
let val = Ok(unsafe {
xlib::XInternAtom(
self.raw()?.as_mut(),
txt,
if create_if_exists { 1 } else { 0 },
)
});
let _ = unsafe { CString::from_raw(txt) };
val
}
fn input_method(&self) -> Result<InputMethod, FlutterbugError> {
unsafe { libc::setlocale(libc::LC_ALL, (&[0]).as_ptr()) };
unsafe { xlib::XSetLocaleModifiers((&[0]).as_ptr()) };
#[inline]
fn open_im(mut dpy: NonNull<xlib::Display>) -> xlib::XIM {
unsafe {
xlib::XOpenIM(
dpy.as_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
)
}
}
let xim = NonNull::new(open_im(self.raw()?));
Ok(InputMethod::from_raw(
self.reference(),
match xim {
Some(x) => x,
None => {
let txt = unsafe { to_cstring("@im=none") }?;
unsafe { xlib::XSetLocaleModifiers(txt) };
let _ = unsafe { CString::from_raw(txt) };
NonNull::new(open_im(self.raw()?))
.ok_or_else(|| FlutterbugError::InputMethodNull)?
}
},
))
}
#[inline]
fn create_image(
&self,
bounds: Size2D<u32>,
depth: u32,
data: Vec<c_char>,
) -> Result<Image, FlutterbugError> {
let mut boxed = data.into_boxed_slice();
let ptr = boxed.as_mut_ptr();
let raw = self.raw()?;
let img = unsafe {
xlib::XCreateImage(
raw.as_ptr(),
self.default_visual()?,
depth as c_uint,
xlib::ZPixmap,
0,
ptr,
bounds.width,
bounds.height,
32,
0,
)
};
let img = NonNull::new(img).ok_or_else(|| FlutterbugError::ImageWasNull)?;
mem::forget(boxed);
Ok(Image::from_raw(Arc::new(img)))
}
fn sync(&self, s: bool) -> Result<(), FlutterbugError> {
unsafe { xlib::XSync(self.raw()?.as_mut(), if s { 1 } else { 0 }) };
Ok(())
}
fn depth(&self, screen: Screen) -> Result<i32, FlutterbugError> {
Ok(unsafe { xlib::XDefaultDepth(self.raw()?.as_mut(), screen.value()) })
}
fn default_depth(&self) -> Result<i32, FlutterbugError> {
self.depth(self.default_screen()?)
}
}
impl GenericDisplay for Display {
#[inline]
fn reference(&self) -> DisplayReference {
DisplayReference::from_ref(Arc::downgrade(&self.raw))
}
#[inline]
fn raw(&self) -> Result<NonNull<xlib::Display>, FlutterbugError> {
Ok(*self.raw)
}
}
impl GenericDisplay for DisplayReference {
#[inline]
fn reference(&self) -> DisplayReference {
self.clone()
}
#[inline]
fn raw(&self) -> Result<NonNull<xlib::Display>, FlutterbugError> {
Ok(*self
.reference
.upgrade()
.ok_or_else(|| FlutterbugError::PointerWasDropped(DroppableObject::Display))?)
}
}
pub mod prelude {
pub use super::{
DerivesAnEvent, DerivesEvent, Drawable, GenericDisplay, GenericGraphicsContext,
GenericImage, GenericInputContext, HasXID,
};
}