use drmkit_core::{AtomicRequest, PropertyStore};
use crate::CursorError;
use crate::sprite::Rotation;
#[must_use]
pub fn plane_origin(pointer: (i32, i32), hotspot: (u32, u32)) -> (i32, i32) {
let back = |coordinate: i32, offset: u32| {
i32::try_from(offset).map_or(coordinate, |offset| coordinate.saturating_sub(offset))
};
(back(pointer.0, hotspot.0), back(pointer.1, hotspot.1))
}
#[must_use]
pub fn hardware_rotation(requested: Rotation, supported_mask: u64) -> u64 {
let want = requested.drm_mask();
if supported_mask & want != 0 {
want
} else {
Rotation::None.drm_mask()
}
}
#[derive(Debug, Clone, Copy)]
#[allow(
clippy::exhaustive_structs,
reason = "built by callers, with no default to fill a new field from"
)]
pub struct PlaneState {
pub plane_id: u32,
pub crtc_id: u32,
pub fb_id: u32,
pub width: u32,
pub height: u32,
pub pointer_x: i32,
pub pointer_y: i32,
pub hotspot: Option<(u32, u32)>,
pub rotation: Rotation,
pub rotation_mask: u64,
}
pub fn stage(
request: &mut AtomicRequest,
props: &PropertyStore,
placement: &PlaneState,
) -> Result<usize, CursorError> {
let (x, y) = plane_origin(
(placement.pointer_x, placement.pointer_y),
placement.hotspot.unwrap_or((0, 0)),
);
let mut written = 0;
let mut put = |name: &str, value: u64| -> Result<(), CursorError> {
let id = props
.property_id(placement.plane_id, name)
.map_err(|_| CursorError::MissingProperty)?;
request
.add_property(placement.plane_id, id, value)
.map_err(|_| CursorError::MissingProperty)?;
written += 1;
Ok(())
};
put("FB_ID", u64::from(placement.fb_id))?;
put("CRTC_ID", u64::from(placement.crtc_id))?;
put("CRTC_X", u64::from(x.cast_unsigned()))?;
put("CRTC_Y", u64::from(y.cast_unsigned()))?;
put("CRTC_W", u64::from(placement.width))?;
put("CRTC_H", u64::from(placement.height))?;
put("SRC_X", 0)?;
put("SRC_Y", 0)?;
put("SRC_W", u64::from(placement.width) << 16)?;
put("SRC_H", u64::from(placement.height) << 16)?;
if let Ok(id) = props.property_id(placement.plane_id, "rotation") {
let value = hardware_rotation(placement.rotation, placement.rotation_mask);
if request.add_property(placement.plane_id, id, value).is_err() {
return Err(CursorError::MissingProperty);
}
written += 1;
}
if let Some((hotspot_x, hotspot_y)) = placement.hotspot {
for (name, value) in [("HOTSPOT_X", hotspot_x), ("HOTSPOT_Y", hotspot_y)] {
if let Ok(id) = props.property_id(placement.plane_id, name) {
if request
.add_property(placement.plane_id, id, u64::from(value))
.is_err()
{
return Err(CursorError::MissingProperty);
}
written += 1;
}
}
}
Ok(written)
}