#![allow(clippy::too_many_arguments)]
#[allow(unused_imports)]
use std::borrow::Cow;
use std::convert::TryFrom;
#[allow(unused_imports)]
use std::convert::TryInto;
use std::io::IoSlice;
#[allow(unused_imports)]
use crate::utils::{RawFdContainer, pretty_print_bitmask, pretty_print_enum};
#[allow(unused_imports)]
use crate::x11_utils::{Request, RequestHeader, Serialize, TryParse, TryParseFd, TryIntoUSize};
use crate::connection::{BufWithFds, PiecewiseBuf, RequestConnection};
#[allow(unused_imports)]
use crate::connection::Connection as X11Connection;
#[allow(unused_imports)]
use crate::cookie::{Cookie, CookieWithFds, VoidCookie};
use crate::errors::{ConnectionError, ParseError};
#[allow(unused_imports)]
use crate::errors::ReplyOrIdError;
use super::xfixes;
use super::xproto;
pub const X11_EXTENSION_NAME: &str = "DAMAGE";
pub const X11_XML_VERSION: (u32, u32) = (1, 1);
fn major_opcode<Conn: RequestConnection + ?Sized>(conn: &Conn) -> Result<u8, ConnectionError> {
let info = conn.extension_information(X11_EXTENSION_NAME)?;
let info = info.ok_or(ConnectionError::UnsupportedExtension)?;
Ok(info.major_opcode)
}
pub type Damage = u32;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct ReportLevel(u8);
impl ReportLevel {
pub const RAW_RECTANGLES: Self = Self(0);
pub const DELTA_RECTANGLES: Self = Self(1);
pub const BOUNDING_BOX: Self = Self(2);
pub const NON_EMPTY: Self = Self(3);
}
impl From<ReportLevel> for u8 {
#[inline]
fn from(input: ReportLevel) -> Self {
input.0
}
}
impl From<ReportLevel> for Option<u8> {
#[inline]
fn from(input: ReportLevel) -> Self {
Some(input.0)
}
}
impl From<ReportLevel> for u16 {
#[inline]
fn from(input: ReportLevel) -> Self {
u16::from(input.0)
}
}
impl From<ReportLevel> for Option<u16> {
#[inline]
fn from(input: ReportLevel) -> Self {
Some(u16::from(input.0))
}
}
impl From<ReportLevel> for u32 {
#[inline]
fn from(input: ReportLevel) -> Self {
u32::from(input.0)
}
}
impl From<ReportLevel> for Option<u32> {
#[inline]
fn from(input: ReportLevel) -> Self {
Some(u32::from(input.0))
}
}
impl From<u8> for ReportLevel {
#[inline]
fn from(value: u8) -> Self {
Self(value)
}
}
impl std::fmt::Debug for ReportLevel {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let variants = [
(Self::RAW_RECTANGLES.0.into(), "RAW_RECTANGLES", "RawRectangles"),
(Self::DELTA_RECTANGLES.0.into(), "DELTA_RECTANGLES", "DeltaRectangles"),
(Self::BOUNDING_BOX.0.into(), "BOUNDING_BOX", "BoundingBox"),
(Self::NON_EMPTY.0.into(), "NON_EMPTY", "NonEmpty"),
];
pretty_print_enum(fmt, self.0.into(), &variants)
}
}
pub const BAD_DAMAGE_ERROR: u8 = 0;
pub const QUERY_VERSION_REQUEST: u8 = 0;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QueryVersionRequest {
pub client_major_version: u32,
pub client_minor_version: u32,
}
impl QueryVersionRequest {
fn serialize(self, major_opcode: u8) -> BufWithFds<PiecewiseBuf<'static>> {
let length_so_far = 0;
let client_major_version_bytes = self.client_major_version.serialize();
let client_minor_version_bytes = self.client_minor_version.serialize();
let mut request0 = vec![
major_opcode,
QUERY_VERSION_REQUEST,
0,
0,
client_major_version_bytes[0],
client_major_version_bytes[1],
client_major_version_bytes[2],
client_major_version_bytes[3],
client_minor_version_bytes[0],
client_minor_version_bytes[1],
client_minor_version_bytes[2],
client_minor_version_bytes[3],
];
let length_so_far = length_so_far + request0.len();
assert_eq!(length_so_far % 4, 0);
let length = u16::try_from(length_so_far / 4).unwrap_or(0);
request0[2..4].copy_from_slice(&length.to_ne_bytes());
(vec![request0.into()], vec![])
}
pub fn send<Conn>(self, conn: &Conn) -> Result<Cookie<'_, Conn, QueryVersionReply>, ConnectionError>
where
Conn: RequestConnection + ?Sized,
{
let (bytes, fds) = self.serialize(major_opcode(conn)?);
let slices = bytes.iter().map(|b| IoSlice::new(&*b)).collect::<Vec<_>>();
conn.send_request_with_reply(&slices, fds)
}
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
if header.minor_opcode != QUERY_VERSION_REQUEST {
return Err(ParseError::InvalidValue);
}
let (client_major_version, remaining) = u32::try_parse(value)?;
let (client_minor_version, remaining) = u32::try_parse(remaining)?;
let _ = remaining;
Ok(QueryVersionRequest {
client_major_version,
client_minor_version,
})
}
}
impl Request for QueryVersionRequest {
type Reply = QueryVersionReply;
}
pub fn query_version<Conn>(conn: &Conn, client_major_version: u32, client_minor_version: u32) -> Result<Cookie<'_, Conn, QueryVersionReply>, ConnectionError>
where
Conn: RequestConnection + ?Sized,
{
let request0 = QueryVersionRequest {
client_major_version,
client_minor_version,
};
request0.send(conn)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QueryVersionReply {
pub sequence: u16,
pub length: u32,
pub major_version: u32,
pub minor_version: u32,
}
impl TryParse for QueryVersionReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::InsufficientData)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
let (length, remaining) = u32::try_parse(remaining)?;
let (major_version, remaining) = u32::try_parse(remaining)?;
let (minor_version, remaining) = u32::try_parse(remaining)?;
let remaining = remaining.get(16..).ok_or(ParseError::InsufficientData)?;
if response_type != 1 {
return Err(ParseError::InvalidValue);
}
let result = QueryVersionReply { sequence, length, major_version, minor_version };
let _ = remaining;
let remaining = initial_value.get(32 + length as usize * 4..)
.ok_or(ParseError::InsufficientData)?;
Ok((result, remaining))
}
}
pub const CREATE_REQUEST: u8 = 1;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CreateRequest {
pub damage: Damage,
pub drawable: xproto::Drawable,
pub level: ReportLevel,
}
impl CreateRequest {
fn serialize(self, major_opcode: u8) -> BufWithFds<PiecewiseBuf<'static>> {
let length_so_far = 0;
let damage_bytes = self.damage.serialize();
let drawable_bytes = self.drawable.serialize();
let level_bytes = u8::from(self.level).serialize();
let mut request0 = vec![
major_opcode,
CREATE_REQUEST,
0,
0,
damage_bytes[0],
damage_bytes[1],
damage_bytes[2],
damage_bytes[3],
drawable_bytes[0],
drawable_bytes[1],
drawable_bytes[2],
drawable_bytes[3],
level_bytes[0],
0,
0,
0,
];
let length_so_far = length_so_far + request0.len();
assert_eq!(length_so_far % 4, 0);
let length = u16::try_from(length_so_far / 4).unwrap_or(0);
request0[2..4].copy_from_slice(&length.to_ne_bytes());
(vec![request0.into()], vec![])
}
pub fn send<Conn>(self, conn: &Conn) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Conn: RequestConnection + ?Sized,
{
let (bytes, fds) = self.serialize(major_opcode(conn)?);
let slices = bytes.iter().map(|b| IoSlice::new(&*b)).collect::<Vec<_>>();
conn.send_request_without_reply(&slices, fds)
}
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
if header.minor_opcode != CREATE_REQUEST {
return Err(ParseError::InvalidValue);
}
let (damage, remaining) = Damage::try_parse(value)?;
let (drawable, remaining) = xproto::Drawable::try_parse(remaining)?;
let (level, remaining) = u8::try_parse(remaining)?;
let level = level.into();
let remaining = remaining.get(3..).ok_or(ParseError::InsufficientData)?;
let _ = remaining;
Ok(CreateRequest {
damage,
drawable,
level,
})
}
}
impl Request for CreateRequest {
type Reply = ();
}
pub fn create<Conn>(conn: &Conn, damage: Damage, drawable: xproto::Drawable, level: ReportLevel) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Conn: RequestConnection + ?Sized,
{
let request0 = CreateRequest {
damage,
drawable,
level,
};
request0.send(conn)
}
pub const DESTROY_REQUEST: u8 = 2;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DestroyRequest {
pub damage: Damage,
}
impl DestroyRequest {
fn serialize(self, major_opcode: u8) -> BufWithFds<PiecewiseBuf<'static>> {
let length_so_far = 0;
let damage_bytes = self.damage.serialize();
let mut request0 = vec![
major_opcode,
DESTROY_REQUEST,
0,
0,
damage_bytes[0],
damage_bytes[1],
damage_bytes[2],
damage_bytes[3],
];
let length_so_far = length_so_far + request0.len();
assert_eq!(length_so_far % 4, 0);
let length = u16::try_from(length_so_far / 4).unwrap_or(0);
request0[2..4].copy_from_slice(&length.to_ne_bytes());
(vec![request0.into()], vec![])
}
pub fn send<Conn>(self, conn: &Conn) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Conn: RequestConnection + ?Sized,
{
let (bytes, fds) = self.serialize(major_opcode(conn)?);
let slices = bytes.iter().map(|b| IoSlice::new(&*b)).collect::<Vec<_>>();
conn.send_request_without_reply(&slices, fds)
}
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
if header.minor_opcode != DESTROY_REQUEST {
return Err(ParseError::InvalidValue);
}
let (damage, remaining) = Damage::try_parse(value)?;
let _ = remaining;
Ok(DestroyRequest {
damage,
})
}
}
impl Request for DestroyRequest {
type Reply = ();
}
pub fn destroy<Conn>(conn: &Conn, damage: Damage) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Conn: RequestConnection + ?Sized,
{
let request0 = DestroyRequest {
damage,
};
request0.send(conn)
}
pub const SUBTRACT_REQUEST: u8 = 3;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SubtractRequest {
pub damage: Damage,
pub repair: xfixes::Region,
pub parts: xfixes::Region,
}
impl SubtractRequest {
fn serialize(self, major_opcode: u8) -> BufWithFds<PiecewiseBuf<'static>> {
let length_so_far = 0;
let damage_bytes = self.damage.serialize();
let repair_bytes = self.repair.serialize();
let parts_bytes = self.parts.serialize();
let mut request0 = vec![
major_opcode,
SUBTRACT_REQUEST,
0,
0,
damage_bytes[0],
damage_bytes[1],
damage_bytes[2],
damage_bytes[3],
repair_bytes[0],
repair_bytes[1],
repair_bytes[2],
repair_bytes[3],
parts_bytes[0],
parts_bytes[1],
parts_bytes[2],
parts_bytes[3],
];
let length_so_far = length_so_far + request0.len();
assert_eq!(length_so_far % 4, 0);
let length = u16::try_from(length_so_far / 4).unwrap_or(0);
request0[2..4].copy_from_slice(&length.to_ne_bytes());
(vec![request0.into()], vec![])
}
pub fn send<Conn>(self, conn: &Conn) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Conn: RequestConnection + ?Sized,
{
let (bytes, fds) = self.serialize(major_opcode(conn)?);
let slices = bytes.iter().map(|b| IoSlice::new(&*b)).collect::<Vec<_>>();
conn.send_request_without_reply(&slices, fds)
}
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
if header.minor_opcode != SUBTRACT_REQUEST {
return Err(ParseError::InvalidValue);
}
let (damage, remaining) = Damage::try_parse(value)?;
let (repair, remaining) = xfixes::Region::try_parse(remaining)?;
let (parts, remaining) = xfixes::Region::try_parse(remaining)?;
let _ = remaining;
Ok(SubtractRequest {
damage,
repair,
parts,
})
}
}
impl Request for SubtractRequest {
type Reply = ();
}
pub fn subtract<Conn, A, B>(conn: &Conn, damage: Damage, repair: A, parts: B) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Conn: RequestConnection + ?Sized,
A: Into<xfixes::Region>,
B: Into<xfixes::Region>,
{
let repair: xfixes::Region = repair.into();
let parts: xfixes::Region = parts.into();
let request0 = SubtractRequest {
damage,
repair,
parts,
};
request0.send(conn)
}
pub const ADD_REQUEST: u8 = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AddRequest {
pub drawable: xproto::Drawable,
pub region: xfixes::Region,
}
impl AddRequest {
fn serialize(self, major_opcode: u8) -> BufWithFds<PiecewiseBuf<'static>> {
let length_so_far = 0;
let drawable_bytes = self.drawable.serialize();
let region_bytes = self.region.serialize();
let mut request0 = vec![
major_opcode,
ADD_REQUEST,
0,
0,
drawable_bytes[0],
drawable_bytes[1],
drawable_bytes[2],
drawable_bytes[3],
region_bytes[0],
region_bytes[1],
region_bytes[2],
region_bytes[3],
];
let length_so_far = length_so_far + request0.len();
assert_eq!(length_so_far % 4, 0);
let length = u16::try_from(length_so_far / 4).unwrap_or(0);
request0[2..4].copy_from_slice(&length.to_ne_bytes());
(vec![request0.into()], vec![])
}
pub fn send<Conn>(self, conn: &Conn) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Conn: RequestConnection + ?Sized,
{
let (bytes, fds) = self.serialize(major_opcode(conn)?);
let slices = bytes.iter().map(|b| IoSlice::new(&*b)).collect::<Vec<_>>();
conn.send_request_without_reply(&slices, fds)
}
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
if header.minor_opcode != ADD_REQUEST {
return Err(ParseError::InvalidValue);
}
let (drawable, remaining) = xproto::Drawable::try_parse(value)?;
let (region, remaining) = xfixes::Region::try_parse(remaining)?;
let _ = remaining;
Ok(AddRequest {
drawable,
region,
})
}
}
impl Request for AddRequest {
type Reply = ();
}
pub fn add<Conn>(conn: &Conn, drawable: xproto::Drawable, region: xfixes::Region) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Conn: RequestConnection + ?Sized,
{
let request0 = AddRequest {
drawable,
region,
};
request0.send(conn)
}
pub const NOTIFY_EVENT: u8 = 0;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NotifyEvent {
pub response_type: u8,
pub level: ReportLevel,
pub sequence: u16,
pub drawable: xproto::Drawable,
pub damage: Damage,
pub timestamp: xproto::Timestamp,
pub area: xproto::Rectangle,
pub geometry: xproto::Rectangle,
}
impl TryParse for NotifyEvent {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
let (response_type, remaining) = u8::try_parse(remaining)?;
let (level, remaining) = u8::try_parse(remaining)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
let (drawable, remaining) = xproto::Drawable::try_parse(remaining)?;
let (damage, remaining) = Damage::try_parse(remaining)?;
let (timestamp, remaining) = xproto::Timestamp::try_parse(remaining)?;
let (area, remaining) = xproto::Rectangle::try_parse(remaining)?;
let (geometry, remaining) = xproto::Rectangle::try_parse(remaining)?;
let level = level.into();
let result = NotifyEvent { response_type, level, sequence, drawable, damage, timestamp, area, geometry };
let _ = remaining;
let remaining = initial_value.get(32..)
.ok_or(ParseError::InsufficientData)?;
Ok((result, remaining))
}
}
impl From<&NotifyEvent> for [u8; 32] {
fn from(input: &NotifyEvent) -> Self {
let response_type_bytes = input.response_type.serialize();
let level_bytes = u8::from(input.level).serialize();
let sequence_bytes = input.sequence.serialize();
let drawable_bytes = input.drawable.serialize();
let damage_bytes = input.damage.serialize();
let timestamp_bytes = input.timestamp.serialize();
let area_bytes = input.area.serialize();
let geometry_bytes = input.geometry.serialize();
[
response_type_bytes[0],
level_bytes[0],
sequence_bytes[0],
sequence_bytes[1],
drawable_bytes[0],
drawable_bytes[1],
drawable_bytes[2],
drawable_bytes[3],
damage_bytes[0],
damage_bytes[1],
damage_bytes[2],
damage_bytes[3],
timestamp_bytes[0],
timestamp_bytes[1],
timestamp_bytes[2],
timestamp_bytes[3],
area_bytes[0],
area_bytes[1],
area_bytes[2],
area_bytes[3],
area_bytes[4],
area_bytes[5],
area_bytes[6],
area_bytes[7],
geometry_bytes[0],
geometry_bytes[1],
geometry_bytes[2],
geometry_bytes[3],
geometry_bytes[4],
geometry_bytes[5],
geometry_bytes[6],
geometry_bytes[7],
]
}
}
impl From<NotifyEvent> for [u8; 32] {
fn from(input: NotifyEvent) -> Self {
Self::from(&input)
}
}
pub trait ConnectionExt: RequestConnection {
fn damage_query_version(&self, client_major_version: u32, client_minor_version: u32) -> Result<Cookie<'_, Self, QueryVersionReply>, ConnectionError>
{
query_version(self, client_major_version, client_minor_version)
}
fn damage_create(&self, damage: Damage, drawable: xproto::Drawable, level: ReportLevel) -> Result<VoidCookie<'_, Self>, ConnectionError>
{
create(self, damage, drawable, level)
}
fn damage_destroy(&self, damage: Damage) -> Result<VoidCookie<'_, Self>, ConnectionError>
{
destroy(self, damage)
}
fn damage_subtract<A, B>(&self, damage: Damage, repair: A, parts: B) -> Result<VoidCookie<'_, Self>, ConnectionError>
where
A: Into<xfixes::Region>,
B: Into<xfixes::Region>,
{
subtract(self, damage, repair, parts)
}
fn damage_add(&self, drawable: xproto::Drawable, region: xfixes::Region) -> Result<VoidCookie<'_, Self>, ConnectionError>
{
add(self, drawable, region)
}
}
impl<C: RequestConnection + ?Sized> ConnectionExt for C {}
#[derive(Debug)]
pub struct DamageWrapper<'c, C: RequestConnection>(&'c C, Damage);
impl<'c, C: RequestConnection> DamageWrapper<'c, C>
{
pub fn for_damage(conn: &'c C, id: Damage) -> Self {
DamageWrapper(conn, id)
}
pub fn damage(&self) -> Damage {
self.1
}
pub fn into_damage(self) -> Damage {
let id = self.1;
std::mem::forget(self);
id
}
}
impl<'c, C: X11Connection> DamageWrapper<'c, C>
{
pub fn create_and_get_cookie(conn: &'c C, drawable: xproto::Drawable, level: ReportLevel) -> Result<(Self, VoidCookie<'c, C>), ReplyOrIdError>
{
let damage = conn.generate_id()?;
let cookie = create(conn, damage, drawable, level)?;
Ok((Self::for_damage(conn, damage), cookie))
}
pub fn create(conn: &'c C, drawable: xproto::Drawable, level: ReportLevel) -> Result<Self, ReplyOrIdError>
{
Ok(Self::create_and_get_cookie(conn, drawable, level)?.0)
}
}
impl<C: RequestConnection> From<&DamageWrapper<'_, C>> for Damage {
fn from(from: &DamageWrapper<'_, C>) -> Self {
from.1
}
}
impl<C: RequestConnection> Drop for DamageWrapper<'_, C> {
fn drop(&mut self) {
let _ = destroy(self.0, self.1);
}
}