use super::{DisplayReference, FlutterbugError, GenericDisplay, HasXID};
use std::{
fmt, mem,
os::raw::{c_char, c_ulong, c_ushort},
};
use x11::xlib;
#[derive(Debug, Copy, Clone)]
pub enum Color {
Rgb {
r: c_ushort,
g: c_ushort,
b: c_ushort,
},
Monochrome(c_ushort),
PixelID(c_ulong),
}
impl PartialEq for Color {
fn eq(&self, other: &Self) -> bool {
match *self {
Color::Rgb { r, g, b } => match *other {
Color::Rgb {
r: r1,
g: g1,
b: b1,
} => r == r1 && g == g1 && b == b1,
_ => false,
},
Color::Monochrome(m) => match *other {
Color::Monochrome(m1) => m == m1,
_ => false,
},
Color::PixelID(i) => match *other {
Color::PixelID(i1) => i == i1,
_ => false,
},
}
}
}
impl Eq for Color {}
impl Color {
#[inline]
pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
Self::Rgb {
r: r as c_ushort * 256,
g: g as c_ushort * 256,
b: b as c_ushort * 256,
}
}
#[inline]
pub fn from_pixel_id(id: c_ulong) -> Self {
Self::PixelID(id)
}
#[inline]
pub fn pixel_id(&self) -> c_ulong {
match *self {
Color::PixelID(p) => p,
_ => panic!("Color was not of the PixelID variant: {:?}", self),
}
}
}
pub struct ColorMap {
internal: xlib::Colormap,
dpy: DisplayReference,
black_pixel: c_ulong,
white_pixel: c_ulong,
is_default: bool,
}
impl fmt::Debug for ColorMap {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "X11 Colormap")
}
}
impl HasXID for ColorMap {
#[inline]
fn xid(&self) -> xlib::XID {
self.internal
}
}
impl ColorMap {
#[inline]
pub(crate) fn from_raw(
internal: xlib::Colormap,
dpy: DisplayReference,
is_default: bool,
) -> Result<Self, FlutterbugError> {
Ok(Self {
internal,
dpy: dpy.clone(),
black_pixel: dpy.default_black_pixel()?.pixel_id(),
white_pixel: dpy.default_white_pixel()?.pixel_id(),
is_default,
})
}
pub fn color(&self, clr: Color) -> Result<Color, FlutterbugError> {
const DO_ALL_COLORS: c_char = xlib::DoRed | xlib::DoGreen | xlib::DoBlue;
let tuple: (c_ushort, c_ushort, c_ushort) = match clr {
Color::PixelID(_p) => {
return Ok(clr);
}
Color::Monochrome(m) => (m, m, m),
Color::Rgb { r, g, b } => (r, g, b),
};
let (r, g, b) = tuple;
if (r == 0) && (g == 0) && (b == 0) {
return Ok(Color::PixelID(self.black_pixel));
} else if (r == std::u16::MAX) && (g == std::u16::MAX) && (b == std::u16::MAX) {
return Ok(Color::PixelID(self.white_pixel));
}
let mut xcolor = xlib::XColor {
red: r,
green: g,
blue: b,
flags: DO_ALL_COLORS,
..unsafe { mem::zeroed() }
};
unsafe { xlib::XAllocColor(self.dpy.raw()?.as_mut(), self.internal, &mut xcolor) };
Ok(Color::PixelID(xcolor.pixel))
}
}
impl Drop for ColorMap {
fn drop(&mut self) {
if let Ok(mut d) = self.dpy.raw() {
if !self.is_default {
unsafe { xlib::XFreeColormap(d.as_mut(), self.internal) };
}
}
}
}