use super::PictureParameters;
use crate::{
auto::{
render::{
CreatePictureRequest, PictType, Pictformat, Pictforminfo, Pictscreen, Picture,
Pictvisual, QueryPictFormatsReply, QueryPictFormatsRequest, QueryVersionReply,
QueryVersionRequest,
},
xproto::{Drawable, Visualtype},
},
display::{Connection, Display, DisplayLike},
send_request, sr_request,
};
use alloc::vec::Vec;
#[cfg(feature = "async")]
use crate::display::AsyncConnection;
#[derive(Debug)]
pub struct RenderDisplay<Dpy> {
inner: Dpy,
formats: Vec<Pictforminfo>,
screens: Vec<Pictscreen>,
subpixels: Vec<u32>,
major_version: u32,
minor_version: u32,
}
impl<Dpy: DisplayLike> DisplayLike for RenderDisplay<Dpy> {
type Connection = Dpy::Connection;
#[inline]
fn display(&self) -> &Display<Dpy::Connection> {
self.inner.display()
}
#[inline]
fn display_mut(&mut self) -> &mut Display<Dpy::Connection> {
self.inner.display_mut()
}
}
impl<Dpy> RenderDisplay<Dpy> {
#[inline]
pub fn inner(&self) -> &Dpy {
&self.inner
}
#[inline]
pub fn inner_mut(&mut self) -> &mut Dpy {
&mut self.inner
}
#[inline]
pub fn into_inner(self) -> Dpy {
self.inner
}
#[inline]
fn fold_for_visformat<F: FnMut(&Pictvisual) -> bool>(&self, mut f: F) -> Option<Pictformat> {
self.screens
.iter()
.flat_map(|s| s.depths.iter())
.flat_map(|d| d.visuals.iter())
.find_map(|v| if f(v) { Some(v.format) } else { None })
}
#[inline]
pub fn find_visual_format(&self, visual: &Visualtype) -> Option<Pictformat> {
self.fold_for_visformat(|v| v.visual == visual.visual_id)
}
#[inline]
pub fn find_standard_format(&self, standard: StandardFormat) -> Option<Pictformat> {
const STANDARDS: &[fn(&Pictforminfo) -> bool] = &[
|p| {
p.ty == PictType::Direct
&& p.depth == 32
&& p.direct.red_shift == 16
&& p.direct.red_mask == 0xFF
&& p.direct.green_shift == 8
&& p.direct.green_mask == 0xFF
&& p.direct.blue_shift == 0
&& p.direct.blue_mask == 0xFF
&& p.direct.alpha_shift == 24
&& p.direct.alpha_mask == 0xFF
},
|p| {
p.ty == PictType::Direct
&& p.depth == 24
&& p.direct.red_shift == 16
&& p.direct.red_mask == 0xFF
&& p.direct.green_shift == 8
&& p.direct.green_mask == 0xFF
&& p.direct.blue_shift == 0
&& p.direct.blue_mask == 0xFF
&& p.direct.alpha_mask == 0
},
|p| {
p.ty == PictType::Direct
&& p.depth == 8
&& p.direct.red_mask == 0x00
&& p.direct.green_mask == 0x00
&& p.direct.blue_mask == 0x00
&& p.direct.alpha_shift == 0
&& p.direct.alpha_mask == 0xFF
},
|p| {
p.ty == PictType::Direct
&& p.depth == 4
&& p.direct.red_mask == 0x00
&& p.direct.green_mask == 0x00
&& p.direct.blue_mask == 0x00
&& p.direct.alpha_shift == 0
&& p.direct.alpha_mask == 0x0F
},
|p| {
p.ty == PictType::Direct
&& p.depth == 1
&& p.direct.red_mask == 0x00
&& p.direct.green_mask == 0x00
&& p.direct.blue_mask == 0x00
&& p.direct.alpha_shift == 0
&& p.direct.alpha_mask == 0x01
},
];
let standard_identifier = STANDARDS[standard as usize];
self.formats.iter().find_map(|p| {
if standard_identifier(p) {
Some(p.id)
} else {
None
}
})
}
#[inline]
fn create_picture_request(
pid: Picture,
drawable: Drawable,
format: Pictformat,
props: PictureParameters,
) -> CreatePictureRequest {
let mut cpr = CreatePictureRequest {
pid,
drawable,
format,
..Default::default()
};
let cp = props.convert_to_flags(&mut cpr);
cpr.value_mask = cp;
cpr
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(usize)]
pub enum StandardFormat {
Argb32 = 0,
Rgb24 = 1,
A8 = 2,
A4 = 3,
A1 = 4,
}
impl<Dpy: DisplayLike> RenderDisplay<Dpy>
where
Dpy::Connection: Connection,
{
#[inline]
pub fn new(
mut dpy: Dpy,
client_major_version: u32,
client_minor_version: u32,
) -> crate::Result<Self> {
let qvtok = send_request!(
dpy.display_mut(),
QueryVersionRequest {
client_major_version,
client_minor_version,
..Default::default()
}
)?;
let qpftok = send_request!(dpy.display_mut(), QueryPictFormatsRequest::default())?;
let QueryVersionReply {
major_version,
minor_version,
..
} = dpy.display_mut().resolve_request(qvtok)?;
let QueryPictFormatsReply {
formats,
screens,
subpixels,
..
} = dpy.display_mut().resolve_request(qpftok)?;
Ok(Self {
inner: dpy,
major_version,
minor_version,
formats,
screens,
subpixels,
})
}
#[inline]
pub fn create_picture<Target: Into<Drawable>>(
&mut self,
target: Target,
format: Pictformat,
properties: PictureParameters,
) -> crate::Result<Picture> {
let pic = Picture::const_from_xid(self.display_mut().generate_xid()?);
let cpr = Self::create_picture_request(pic, target.into(), format, properties);
sr_request!(self.display_mut(), cpr)?;
Ok(pic)
}
}
#[cfg(feature = "async")]
impl<Dpy: DisplayLike> RenderDisplay<Dpy>
where
Dpy::Connection: AsyncConnection + Send,
{
#[inline]
pub async fn new_async(
mut dpy: Dpy,
client_major_version: u32,
client_minor_version: u32,
) -> crate::Result<Self> {
let qvtok = send_request!(
dpy.display_mut(),
QueryVersionRequest {
client_major_version,
client_minor_version,
..Default::default()
},
async
)
.await?;
let qpftok =
send_request!(dpy.display_mut(), QueryPictFormatsRequest::default(), async).await?;
let QueryVersionReply {
major_version,
minor_version,
..
} = dpy.display_mut().resolve_request_async(qvtok).await?;
let QueryPictFormatsReply {
formats,
screens,
subpixels,
..
} = dpy.display_mut().resolve_request_async(qpftok).await?;
Ok(Self {
inner: dpy,
major_version,
minor_version,
formats,
screens,
subpixels,
})
}
#[inline]
pub async fn create_picture_async<Target: Into<Drawable>>(
&mut self,
target: Target,
format: Pictformat,
properties: PictureParameters,
) -> crate::Result<Picture> {
let pic = Picture::const_from_xid(self.display_mut().generate_xid()?);
let cpr = Self::create_picture_request(pic, target.into(), format, properties);
sr_request!(self.display_mut(), cpr, async).await?;
Ok(pic)
}
}