use super::{DroppableObject, FlutterbugError};
use euclid::default::Point2D;
use std::{
fmt,
os::raw::c_ulong,
ptr::NonNull,
sync::{Arc, Weak},
};
use x11::xlib;
pub struct Image {
inner: Arc<NonNull<xlib::XImage>>,
}
impl fmt::Debug for Image {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ptr = self.inner.as_ptr();
let width = unsafe { (*ptr).width };
let height = unsafe { (*ptr).height };
write!(f, "{}x{} X11 Image", width, height)
}
}
impl Drop for Image {
fn drop(&mut self) {
unsafe { xlib::XDestroyImage(self.inner.as_ptr()) };
}
}
impl Image {
#[inline]
pub(crate) fn from_raw(inner: Arc<NonNull<xlib::XImage>>) -> Self {
Self { inner }
}
}
pub struct ImageReference {
inner: Weak<NonNull<xlib::XImage>>,
}
impl fmt::Debug for ImageReference {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "X11 Image Reference")
}
}
impl Clone for ImageReference {
fn clone(&self) -> Self {
Self::from_raw(self.inner.clone())
}
}
impl ImageReference {
#[inline]
pub(crate) fn from_raw(inner: Weak<NonNull<xlib::XImage>>) -> Self {
Self { inner }
}
}
pub trait GenericImage: fmt::Debug {
fn raw(&self) -> Result<NonNull<xlib::XImage>, FlutterbugError>;
fn reference(&self) -> ImageReference;
fn width(&self) -> Result<u32, FlutterbugError> {
let ptr = self.raw()?.as_ptr();
Ok(unsafe { (*ptr).width } as u32)
}
fn height(&self) -> Result<u32, FlutterbugError> {
let ptr = self.raw()?.as_ptr();
Ok(unsafe { (*ptr).height } as u32)
}
fn put_pixel(&self, loc: Point2D<i32>, r: u8, g: u8, b: u8) -> Result<(), FlutterbugError> {
let pixel = (65536 * (b as c_ulong)) + (256 * (g as c_ulong)) + (r as c_ulong);
unsafe { xlib::XPutPixel(self.raw()?.as_mut(), loc.x, loc.y, pixel) };
Ok(())
}
}
impl GenericImage for Image {
#[inline]
fn raw(&self) -> Result<NonNull<xlib::XImage>, FlutterbugError> {
Ok(*self.inner)
}
#[inline]
fn reference(&self) -> ImageReference {
ImageReference::from_raw(Arc::downgrade(&self.inner))
}
}
impl GenericImage for ImageReference {
#[inline]
fn raw(&self) -> Result<NonNull<xlib::XImage>, FlutterbugError> {
Ok(*self
.inner
.upgrade()
.ok_or_else(|| FlutterbugError::PointerWasDropped(DroppableObject::Image))?)
}
#[inline]
fn reference(&self) -> ImageReference {
self.clone()
}
}