use crate::base::{self, BaseError, BaseEvent, GeEvent, Raw, Reply, WiredIn, WiredOut, Xid};
use crate::ext;
use crate::ffi::base::*;
use crate::ffi::ext::*;
use crate::lat1_str::{Lat1Str, Lat1String, Lat1StrF};
use crate::xproto;
use crate::xfixes;
use crate::render;
use crate::shape;
use crate::xproto::PropEl;
use bitflags::bitflags;
use libc::{self, iovec};
use std::convert::TryInto;
use std::hash::{Hash, Hasher};
use std::os::unix::io::RawFd;
pub const XNAME: &str = "DAMAGE";
pub const MAJOR_VERSION: u32 = 1;
pub const MINOR_VERSION: u32 = 1;
pub const VERSION_STRING: &str = "1.1";
pub(crate) static mut FFI_EXT: xcb_extension_t = xcb_extension_t {
name: "DAMAGE\0".as_ptr() as *const _,
global_id: 0,
};
pub fn prefetch_extension_data(conn: &base::Connection) {
unsafe {
xcb_prefetch_extension_data(conn.get_raw_conn(), &mut FFI_EXT as *mut _);
}
}
pub fn get_extension_data(conn: &base::Connection) -> std::option::Option<ext::ExtensionData> {
unsafe {
let reply = xcb_get_extension_data(conn.get_raw_conn(), &mut FFI_EXT as *mut _);
assert!(!reply.is_null(), "Could not fetch Damage extension data");
let reply = xproto::QueryExtensionReply::from_raw(reply);
if !reply.present() {
std::mem::forget(reply);
return None;
}
let res = ext::ExtensionData{
ext: ext::Extension::Damage,
major_opcode: reply.major_opcode(),
first_event: reply.first_event(),
first_error: reply.first_error(),
};
std::mem::forget(reply);
Some(res)
}
}
pub struct BadDamageError {
raw: *mut xcb_generic_error_t,
}
impl base::Raw<xcb_generic_error_t> for BadDamageError {
unsafe fn from_raw(raw: *mut xcb_generic_error_t) -> Self { BadDamageError { raw } }
fn as_raw(&self) -> *mut xcb_generic_error_t {
self.raw
}
}
impl base::BaseError for BadDamageError {
const EXTENSION: std::option::Option<ext::Extension> = Some(ext::Extension::Damage);
const NUMBER: u32 = 0;
}
impl BadDamageError {
fn wire_ptr(&self) -> *const u8 { self.raw as *const u8 }
fn wire_len(&self) -> usize { 32 }
pub fn response_type(&self) -> u8 {
unsafe {
let offset = 0usize;
let ptr = self.wire_ptr().add(offset) as *const u8;
base::value_from_ptr(ptr)
}
}
pub fn error_code(&self) -> u8 {
unsafe {
let offset = 1usize;
let ptr = self.wire_ptr().add(offset) as *const u8;
base::value_from_ptr(ptr)
}
}
pub fn sequence(&self) -> u16 {
unsafe {
let offset = 2usize;
let ptr = self.wire_ptr().add(offset) as *const u16;
base::value_from_ptr(ptr)
}
}
}
impl std::fmt::Debug for BadDamageError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BadDamageError")
.field("response_type", &self.response_type())
.field("error_code", &self.error_code())
.field("sequence", &self.sequence())
.finish()
}
}
impl Drop for BadDamageError {
fn drop(&mut self) {
unsafe { libc::free(self.raw as *mut _); }
}
}
unsafe impl Send for BadDamageError {}
unsafe impl Sync for BadDamageError {}
#[derive(Debug)]
pub enum Error {
BadDamage(BadDamageError),
}
impl base::ResolveWireError for Error {
unsafe fn resolve_wire_error(first_error: u8, raw: *mut xcb_generic_error_t) -> Self {
debug_assert!(!raw.is_null());
let error_code = (*raw).error_code;
match error_code - first_error {
0 => Error::BadDamage(BadDamageError::from_raw(raw)),
_ => unreachable!(
"Could not resolve damage Error with error_code {} and first_error {}",
error_code, first_error
),
}
}
}
pub struct NotifyEvent {
raw: *mut xcb_generic_event_t,
}
impl base::Raw<xcb_generic_event_t> for NotifyEvent {
unsafe fn from_raw(raw: *mut xcb_generic_event_t) -> Self { NotifyEvent { raw } }
fn as_raw(&self) -> *mut xcb_generic_event_t {
self.raw
}
}
impl base::BaseEvent for NotifyEvent {
const EXTENSION: std::option::Option<ext::Extension> = Some(ext::Extension::Damage);
const NUMBER: u32 = 0;
}
impl NotifyEvent {
pub fn new(event_base: u8,
level: ReportLevel,
drawable: xproto::Drawable,
damage: Damage,
timestamp: xproto::Timestamp,
area: xproto::Rectangle,
geometry: xproto::Rectangle,
) -> NotifyEvent {
unsafe {
let ptr = libc::malloc(32) as *mut u8;
let wire_buf = std::slice::from_raw_parts_mut(ptr, 32);
let mut wire_off = 0usize;
let response_type = event_base;
let sequence = 0u16;
wire_off += response_type.serialize(&mut wire_buf[wire_off ..]);
wire_off += (std::mem::transmute::<_, u32>(level) as u8).serialize(&mut wire_buf[wire_off ..]);
wire_off += sequence.serialize(&mut wire_buf[wire_off ..]);
wire_off += drawable.serialize(&mut wire_buf[wire_off ..]);
wire_off += damage.serialize(&mut wire_buf[wire_off ..]);
wire_off += timestamp.serialize(&mut wire_buf[wire_off ..]);
wire_off += area.serialize(&mut wire_buf[wire_off ..]);
geometry.serialize(&mut wire_buf[wire_off ..]);
NotifyEvent::from_raw(ptr as *mut xcb_generic_event_t)
}
}
fn wire_ptr(&self) -> *const u8 { self.raw as *const u8 }
pub fn response_type(&self) -> u8 {
unsafe {
let offset = 0usize;
let ptr = self.wire_ptr().add(offset) as *const u8;
base::value_from_ptr(ptr)
}
}
pub fn level(&self) -> ReportLevel {
unsafe {
let offset = 1usize;
let ptr = self.wire_ptr().add(offset) as *const u8;
let val = base::value_from_ptr(ptr) as u32;
std::mem::transmute::<u32, ReportLevel>(val)
}
}
pub fn sequence(&self) -> u16 {
unsafe {
let offset = 2usize;
let ptr = self.wire_ptr().add(offset) as *const u16;
base::value_from_ptr(ptr)
}
}
fn drawable(&self) -> xproto::Drawable {
unsafe {
let offset = 4usize;
let res_id = *(self.wire_ptr().add(offset) as *const u32);
xproto::Drawable::Unknown(res_id)
}
}
pub fn damage(&self) -> Damage {
unsafe {
let offset = 8usize;
let ptr = self.wire_ptr().add(offset) as *const Damage;
base::value_from_ptr(ptr)
}
}
pub fn timestamp(&self) -> xproto::Timestamp {
unsafe {
let offset = 12usize;
let ptr = self.wire_ptr().add(offset) as *const xproto::Timestamp;
base::value_from_ptr(ptr)
}
}
pub fn area(&self) -> xproto::Rectangle {
unsafe {
let offset = 16usize;
let ptr = self.wire_ptr().add(offset) as *const xproto::Rectangle;
base::value_from_ptr(ptr)
}
}
pub fn geometry(&self) -> xproto::Rectangle {
unsafe {
let offset = 24usize;
let ptr = self.wire_ptr().add(offset) as *const xproto::Rectangle;
base::value_from_ptr(ptr)
}
}
}
impl std::fmt::Debug for NotifyEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NotifyEvent")
.field("response_type", &self.response_type())
.field("level", &self.level())
.field("sequence", &self.sequence())
.field("drawable", &self.drawable())
.field("damage", &self.damage())
.field("timestamp", &self.timestamp())
.field("area", &self.area())
.field("geometry", &self.geometry())
.finish()
}
}
impl base::WiredOut for NotifyEvent {
fn wire_len(&self) -> usize {
32usize
}
fn serialize(&self, wire_buf: &mut[u8]) -> usize {
debug_assert!(wire_buf.len() >= self.wire_len());
let raw_slice = unsafe { std::slice::from_raw_parts(self.raw as *const u8, self.wire_len()) };
wire_buf[0 .. self.wire_len()].copy_from_slice(raw_slice);
self.wire_len()
}
}
impl base::WiredIn for NotifyEvent {
type Params = ();
unsafe fn compute_wire_len(_ptr: *const u8, _params: ()) -> usize {
32
}
unsafe fn unserialize(ptr: *const u8, _params: (), offset: &mut usize) -> Self {
let sz = Self::compute_wire_len(ptr, ());
*offset += sz;
let raw = libc::malloc(sz) as *mut xcb_generic_event_t;
std::ptr::copy(ptr as *const xcb_generic_event_t, raw, sz);
NotifyEvent { raw }
}
}
impl Drop for NotifyEvent {
fn drop(&mut self) {
unsafe { libc::free(self.raw as *mut _); }
}
}
unsafe impl Send for NotifyEvent {}
unsafe impl Sync for NotifyEvent {}
#[derive(Debug)]
pub enum Event {
Notify(NotifyEvent),
}
impl Event {
pub fn as_raw(&self) -> *mut xcb_generic_event_t {
match self {
Self::Notify(e) => e.as_raw(),
}
}
}
impl base::ResolveWireEvent for Event {
unsafe fn resolve_wire_event(first_event: u8, raw: *mut xcb_generic_event_t) -> std::option::Option<Self> {
debug_assert!(!raw.is_null());
let response_type = (*raw).response_type & 0x7F;
debug_assert!(response_type != 0, "This is not an event but an error!");
debug_assert!(response_type != XCB_GE_GENERIC, "This is a GE_GENERIC event!");
match response_type - first_event {
0 => Some(Event::Notify(NotifyEvent::from_raw(raw))),
_ => None,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C)]
pub struct Damage {
res_id: u32,
}
impl base::Xid for Damage {
fn none() -> Self { Damage { res_id: 0 } }
fn resource_id(&self) -> u32 { self.res_id }
}
impl base::XidNew for Damage {
unsafe fn new(res_id: u32) -> Self { Damage { res_id } }
}
#[test]
fn test_sizeof_damage() {
assert_eq!(std::mem::size_of::<Damage>(), 4);
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u32)]
pub enum ReportLevel {
RawRectangles = 0,
DeltaRectangles = 1,
BoundingBox = 2,
NonEmpty = 3,
}
pub(crate) fn request_name(opcode: u16) -> std::option::Option<&'static str> {
match opcode {
0 => Some("damage::QueryVersion"),
1 => Some("damage::Create"),
2 => Some("damage::Destroy"),
3 => Some("damage::Subtract"),
4 => Some("damage::Add"),
_ => None,
}
}
pub struct QueryVersionReply {
raw: *const u8,
}
impl QueryVersionReply {
fn wire_ptr(&self) -> *const u8 {
self.raw
}
fn wire_len(&self) -> usize {
(32 + self.length() * 4) as _
}
pub fn response_type(&self) -> u8 {
unsafe {
let offset = 0usize;
let ptr = self.wire_ptr().add(offset) as *const u8;
base::value_from_ptr(ptr)
}
}
pub fn sequence(&self) -> u16 {
unsafe {
let offset = 2usize;
let ptr = self.wire_ptr().add(offset) as *const u16;
base::value_from_ptr(ptr)
}
}
pub fn length(&self) -> u32 {
unsafe {
let offset = 4usize;
let ptr = self.wire_ptr().add(offset) as *const u32;
base::value_from_ptr(ptr)
}
}
pub fn major_version(&self) -> u32 {
unsafe {
let offset = 8usize;
let ptr = self.wire_ptr().add(offset) as *const u32;
base::value_from_ptr(ptr)
}
}
pub fn minor_version(&self) -> u32 {
unsafe {
let offset = 12usize;
let ptr = self.wire_ptr().add(offset) as *const u32;
base::value_from_ptr(ptr)
}
}
}
impl base::Reply for QueryVersionReply {
unsafe fn from_raw(raw: *const u8) -> Self {
Self { raw }
}
unsafe fn into_raw(self) -> *const u8 {
let raw = self.raw;
std::mem::forget(self);
raw
}
}
impl std::fmt::Debug for QueryVersionReply {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("QueryVersionReply")
.field("response_type", &self.response_type())
.field("pad", &1)
.field("sequence", &self.sequence())
.field("length", &self.length())
.field("major_version", &self.major_version())
.field("minor_version", &self.minor_version())
.field("pad", &16)
.finish()
}
}
impl Drop for QueryVersionReply {
fn drop(&mut self) {
unsafe { libc::free(self.raw as *mut _); }
}
}
unsafe impl std::marker::Send for QueryVersionReply {}
unsafe impl std::marker::Sync for QueryVersionReply {}
#[derive(Debug)]
pub struct QueryVersionCookie {
seq: u64,
}
#[derive(Debug)]
pub struct QueryVersionCookieUnchecked {
seq: u64,
}
impl base::Cookie for QueryVersionCookie {
unsafe fn from_sequence(seq: u64) -> Self {
QueryVersionCookie { seq }
}
fn sequence(&self) -> u64 {
self.seq
}
}
unsafe impl base::CookieChecked for QueryVersionCookie {
}
unsafe impl base::CookieWithReplyChecked for QueryVersionCookie {
type Reply = QueryVersionReply;
}
impl base::Cookie for QueryVersionCookieUnchecked {
unsafe fn from_sequence(seq: u64) -> Self {
QueryVersionCookieUnchecked { seq }
}
fn sequence(&self) -> u64 {
self.seq
}
}
unsafe impl base::CookieWithReplyUnchecked for QueryVersionCookieUnchecked {
type Reply = QueryVersionReply;
}
#[derive(Clone, Debug)]
pub struct QueryVersion {
pub client_major_version: u32,
pub client_minor_version: u32,
}
unsafe impl base::RawRequest for QueryVersion {
fn raw_request(&self, c: &base::Connection, checked: bool) -> u64 { unsafe {
let mut protocol_request = xcb_protocol_request_t {
count: 2,
ext: (&mut FFI_EXT) as *mut _,
opcode: 0,
isvoid: 0,
};
let mut sections: [iovec; 4] = [iovec {
iov_base: std::ptr::null_mut(),
iov_len: 0,
}; 4];
let buf0: &mut [u8] = &mut [0; 12];
self.client_major_version.serialize(&mut buf0[4 .. ]);
self.client_minor_version.serialize(&mut buf0[8 .. ]);
sections[2].iov_base = buf0.as_mut_ptr() as *mut _;
sections[2].iov_len = 12;
sections[3].iov_len = base::align_pad(sections[2].iov_len, 4);
let flags = if checked { base::RequestFlags::CHECKED } else { base::RequestFlags::NONE };
xcb_send_request64(
c.get_raw_conn(),
flags.bits() as _,
sections.as_mut_ptr().add(2),
&mut protocol_request as *mut _,
)
}
}}
impl base::Request for QueryVersion {
type Cookie = QueryVersionCookie;
const IS_VOID: bool = false;
}
impl base::RequestWithReply for QueryVersion {
type Reply = QueryVersionReply;
type Cookie = QueryVersionCookie;
type CookieUnchecked = QueryVersionCookieUnchecked;
}
#[derive(Clone, Debug)]
pub struct Create {
pub damage: Damage,
pub drawable: xproto::Drawable,
pub level: ReportLevel,
}
unsafe impl base::RawRequest for Create {
fn raw_request(&self, c: &base::Connection, checked: bool) -> u64 { unsafe {
let mut protocol_request = xcb_protocol_request_t {
count: 2,
ext: (&mut FFI_EXT) as *mut _,
opcode: 1,
isvoid: 1,
};
let mut sections: [iovec; 4] = [iovec {
iov_base: std::ptr::null_mut(),
iov_len: 0,
}; 4];
let buf0: &mut [u8] = &mut [0; 16];
self.damage.serialize(&mut buf0[4 .. ]);
self.drawable.serialize(&mut buf0[8 .. ]);
(std::mem::transmute::<_, u32>(self.level) as u8).serialize(&mut buf0[12 .. ]);
sections[2].iov_base = buf0.as_mut_ptr() as *mut _;
sections[2].iov_len = 16;
sections[3].iov_len = base::align_pad(sections[2].iov_len, 4);
let flags = if checked { base::RequestFlags::CHECKED } else { base::RequestFlags::NONE };
xcb_send_request64(
c.get_raw_conn(),
flags.bits() as _,
sections.as_mut_ptr().add(2),
&mut protocol_request as *mut _,
)
}
}}
impl base::Request for Create {
type Cookie = base::VoidCookie;
const IS_VOID: bool = true;
}
impl base::RequestWithoutReply for Create {
}
#[derive(Clone, Debug)]
pub struct Destroy {
pub damage: Damage,
}
unsafe impl base::RawRequest for Destroy {
fn raw_request(&self, c: &base::Connection, checked: bool) -> u64 { unsafe {
let mut protocol_request = xcb_protocol_request_t {
count: 2,
ext: (&mut FFI_EXT) as *mut _,
opcode: 2,
isvoid: 1,
};
let mut sections: [iovec; 4] = [iovec {
iov_base: std::ptr::null_mut(),
iov_len: 0,
}; 4];
let buf0: &mut [u8] = &mut [0; 8];
self.damage.serialize(&mut buf0[4 .. ]);
sections[2].iov_base = buf0.as_mut_ptr() as *mut _;
sections[2].iov_len = 8;
sections[3].iov_len = base::align_pad(sections[2].iov_len, 4);
let flags = if checked { base::RequestFlags::CHECKED } else { base::RequestFlags::NONE };
xcb_send_request64(
c.get_raw_conn(),
flags.bits() as _,
sections.as_mut_ptr().add(2),
&mut protocol_request as *mut _,
)
}
}}
impl base::Request for Destroy {
type Cookie = base::VoidCookie;
const IS_VOID: bool = true;
}
impl base::RequestWithoutReply for Destroy {
}
#[derive(Clone, Debug)]
pub struct Subtract {
pub damage: Damage,
pub repair: xfixes::Region,
pub parts: xfixes::Region,
}
unsafe impl base::RawRequest for Subtract {
fn raw_request(&self, c: &base::Connection, checked: bool) -> u64 { unsafe {
let mut protocol_request = xcb_protocol_request_t {
count: 2,
ext: (&mut FFI_EXT) as *mut _,
opcode: 3,
isvoid: 1,
};
let mut sections: [iovec; 4] = [iovec {
iov_base: std::ptr::null_mut(),
iov_len: 0,
}; 4];
let buf0: &mut [u8] = &mut [0; 16];
self.damage.serialize(&mut buf0[4 .. ]);
self.repair.serialize(&mut buf0[8 .. ]);
self.parts.serialize(&mut buf0[12 .. ]);
sections[2].iov_base = buf0.as_mut_ptr() as *mut _;
sections[2].iov_len = 16;
sections[3].iov_len = base::align_pad(sections[2].iov_len, 4);
let flags = if checked { base::RequestFlags::CHECKED } else { base::RequestFlags::NONE };
xcb_send_request64(
c.get_raw_conn(),
flags.bits() as _,
sections.as_mut_ptr().add(2),
&mut protocol_request as *mut _,
)
}
}}
impl base::Request for Subtract {
type Cookie = base::VoidCookie;
const IS_VOID: bool = true;
}
impl base::RequestWithoutReply for Subtract {
}
#[derive(Clone, Debug)]
pub struct Add {
pub drawable: xproto::Drawable,
pub region: xfixes::Region,
}
unsafe impl base::RawRequest for Add {
fn raw_request(&self, c: &base::Connection, checked: bool) -> u64 { unsafe {
let mut protocol_request = xcb_protocol_request_t {
count: 2,
ext: (&mut FFI_EXT) as *mut _,
opcode: 4,
isvoid: 1,
};
let mut sections: [iovec; 4] = [iovec {
iov_base: std::ptr::null_mut(),
iov_len: 0,
}; 4];
let buf0: &mut [u8] = &mut [0; 12];
self.drawable.serialize(&mut buf0[4 .. ]);
self.region.serialize(&mut buf0[8 .. ]);
sections[2].iov_base = buf0.as_mut_ptr() as *mut _;
sections[2].iov_len = 12;
sections[3].iov_len = base::align_pad(sections[2].iov_len, 4);
let flags = if checked { base::RequestFlags::CHECKED } else { base::RequestFlags::NONE };
xcb_send_request64(
c.get_raw_conn(),
flags.bits() as _,
sections.as_mut_ptr().add(2),
&mut protocol_request as *mut _,
)
}
}}
impl base::Request for Add {
type Cookie = base::VoidCookie;
const IS_VOID: bool = true;
}
impl base::RequestWithoutReply for Add {
}