use crate::{
auth_info::AuthInfo,
auto::{
xproto::{Colormap, Screen, Setup, SetupRequest, Visualid, Visualtype, Window},
AsByteSequence,
},
event::Event,
util::cycled_zeroes,
xid::XidGenerator,
Request, XID,
};
use alloc::{boxed::Box, collections::VecDeque};
use core::{fmt, iter, marker::PhantomData, mem, num::NonZeroU32, ptr::NonNull};
use cty::{c_int, c_void};
use hashbrown::HashMap;
use tinyvec::TinyVec;
#[cfg(feature = "std")]
use std::borrow::Cow;
mod connection;
pub use connection::*;
#[cfg(feature = "std")]
pub mod name;
mod functions;
mod input;
mod output;
pub use functions::*;
pub struct Display<Conn> {
pub(crate) connection: Conn,
pub(crate) setup: Setup,
xid: XidGenerator,
default_screen: usize,
pub(crate) event_queue: VecDeque<Event>,
pub(crate) pending_requests: VecDeque<input::PendingRequest>,
pub(crate) pending_replies: HashMap<u16, Box<[u8]>>,
request_number: u64,
pub(crate) wm_protocols_atom: Option<NonZeroU32>,
context: HashMap<(XID, ContextID), NonNull<c_void>>,
}
pub type ContextID = c_int;
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Default, Eq, Hash)]
#[repr(transparent)]
pub struct RequestCookie<R: Request> {
sequence: u16,
_phantom: PhantomData<Option<R::Reply>>,
}
impl<R: Request> RequestCookie<R> {
#[inline]
pub(crate) fn from_sequence(sequence: u64) -> Self {
Self {
sequence: sequence as u16, _phantom: PhantomData,
}
}
}
#[derive(Default, Debug)]
pub(crate) struct PendingRequestFlags {
pub discard_reply: bool,
pub checked: bool,
}
impl<Conn: fmt::Debug> fmt::Debug for Display<Conn> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Display")
.field("connection", &self.connection)
.field("setup", &self.setup)
.field("xid", &self.xid)
.field("default_screen", &self.default_screen)
.field("event_queue", &self.event_queue)
.field("pending_requests", &self.pending_requests)
.field("pending_replies", &self.pending_replies)
.field("request_number", &self.request_number)
.finish()
}
}
#[inline]
const fn endian_byte() -> u8 {
#[cfg(not(target_endian = "little"))]
{
const BE_SIGNIFIER: u8 = b'B';
BE_SIGNIFIER
}
#[cfg(target_endian = "little")]
{
const LE_SIGNIFIER: u8 = b'l';
LE_SIGNIFIER
}
}
impl<Conn: Connection> Display<Conn> {
#[inline]
fn decode_reply<R: Request>(reply: Box<[u8]>) -> crate::Result<R::Reply> {
Ok(R::Reply::from_bytes(&reply)
.ok_or(crate::BreadError::BadObjectRead(None))?
.0)
}
#[inline]
pub fn send_request<R: Request>(&mut self, req: R) -> crate::Result<RequestCookie<R>> {
self.send_request_internal(req)
}
#[inline]
pub fn resolve_request<R: Request>(
&mut self,
token: RequestCookie<R>,
) -> crate::Result<R::Reply>
where
R::Reply: Default,
{
if mem::size_of::<R::Reply>() == 0 {
log::debug!("Immediately resolving for reply of size 0");
return Ok(Default::default());
}
loop {
log::trace!("Current replies: {:?}", &self.pending_replies);
match self.pending_replies.remove(&token.sequence) {
Some(reply) => break Self::decode_reply::<R>(reply),
None => self.wait()?,
}
}
}
#[cfg(feature = "async")]
#[inline]
pub async fn send_request_async<R: Request>(
&mut self,
req: R,
) -> crate::Result<RequestCookie<R>> {
self.send_request_internal_async(req).await
}
#[cfg(feature = "async")]
#[inline]
pub async fn resolve_request_async<R: Request>(
&mut self,
token: RequestCookie<R>,
) -> crate::Result<R::Reply>
where
R::Reply: Default,
{
if mem::size_of::<R::Reply>() == 0 {
return Ok(Default::default());
}
loop {
match self.pending_replies.remove(&token.sequence) {
Some(reply) => {
break Self::decode_reply::<R>(reply);
}
None => self.wait_async().await?,
}
}
}
#[inline]
fn from_connection_internal(connection: Conn) -> Self {
Self {
connection,
setup: Default::default(),
xid: Default::default(),
default_screen: 0,
event_queue: VecDeque::new(),
pending_requests: VecDeque::new(),
pending_replies: HashMap::new(),
request_number: 1,
wm_protocols_atom: None,
context: HashMap::new(),
}
}
#[inline]
pub fn from_connection(connection: Conn, auth: Option<AuthInfo>) -> crate::Result<Self> {
let mut d = Self::from_connection_internal(connection);
d.init(auth.unwrap_or_default())?;
Ok(d)
}
#[cfg(feature = "async")]
#[inline]
pub async fn from_connection_async(
connection: Conn,
auth: Option<AuthInfo>,
) -> crate::Result<Self> {
let mut d = Self::from_connection_internal(connection);
d.init_async(auth.unwrap_or(Default::default())).await?;
Ok(d)
}
#[inline]
fn create_setup(auth: AuthInfo) -> SetupRequest {
let AuthInfo { name, data } = auth;
SetupRequest {
byte_order: endian_byte(),
protocol_major_version: 11,
protocol_minor_version: 0,
authorization_protocol_name: name,
authorization_protocol_data: data,
}
}
#[inline]
fn init(&mut self, auth: AuthInfo) -> crate::Result {
let setup = Self::create_setup(auth);
let mut bytes: TinyVec<[u8; 32]> = cycled_zeroes(32);
let len = setup.as_bytes(&mut bytes);
bytes.truncate(len);
self.connection.send_packet(&bytes[0..len])?;
let mut bytes: TinyVec<[u8; 32]> = cycled_zeroes(8);
self.connection.read_packet(&mut bytes)?;
match bytes[0] {
0 | 2 => return Err(crate::BreadError::FailedToConnect),
_ => (),
}
let length_bytes: [u8; 2] = [bytes[6], bytes[7]];
let length = (u16::from_ne_bytes(length_bytes) as usize) * 4;
bytes.extend(iter::once(0).cycle().take(length));
self.connection.read_packet(&mut bytes[8..])?;
let (setup, _) =
Setup::from_bytes(&bytes).ok_or(crate::BreadError::BadObjectRead(Some("Setup")))?;
self.setup = setup;
self.xid = XidGenerator::new(self.setup.resource_id_base, self.setup.resource_id_mask);
log::debug!("resource_id_base is {:#032b}", self.setup.resource_id_base);
log::debug!("resource_id_mask is {:#032b}", self.setup.resource_id_mask);
log::debug!(
"resource_id inc. is {:#032b}",
self.setup.resource_id_mask & self.setup.resource_id_mask.wrapping_neg()
);
Ok(())
}
#[cfg(feature = "async")]
#[inline]
async fn init_async(&mut self, auth: AuthInfo) -> crate::Result {
let setup = Self::create_setup(auth);
let mut bytes: TinyVec<[u8; 32]> = cycled_zeroes(32);
let len = setup.as_bytes(&mut bytes);
bytes.truncate(len);
self.connection.send_packet_async(&bytes[0..len]).await?;
let mut bytes: TinyVec<[u8; 32]> = cycled_zeroes(8);
self.connection.read_packet_async(&mut bytes).await?;
match bytes[0] {
0 | 2 => return Err(crate::BreadError::FailedToConnect),
_ => (),
}
let length_bytes: [u8; 2] = [bytes[6], bytes[7]];
let length = (u16::from_ne_bytes(length_bytes) as usize) * 4;
bytes.extend(iter::once(0).cycle().take(length));
self.connection.read_packet_async(&mut bytes[8..]).await?;
let (setup, _) = Setup::from_bytes(&bytes)
.ok_or_else(|| crate::BreadError::BadObjectRead(Some("Setup")))?;
self.setup = setup;
self.xid = XidGenerator::new(self.setup.resource_id_base, self.setup.resource_id_mask);
log::debug!("resource_id_base is {:#032b}", self.setup.resource_id_base);
log::debug!("resource_id_mask is {:#032b}", self.setup.resource_id_mask);
log::debug!(
"resource_id inc. is {:#032b}",
self.setup.resource_id_mask & self.setup.resource_id_mask.wrapping_neg()
);
Ok(())
}
#[inline]
pub fn setup(&self) -> &Setup {
&self.setup
}
#[inline]
pub fn default_root(&self) -> Window {
self.default_screen().root
}
#[inline]
pub fn default_screen(&self) -> &Screen {
&self.setup.roots[self.default_screen]
}
#[inline]
pub fn default_white_pixel(&self) -> u32 {
self.default_screen().white_pixel
}
#[inline]
pub fn default_black_pixel(&self) -> u32 {
self.default_screen().black_pixel
}
#[inline]
pub fn default_visual_id(&self) -> Visualid {
self.default_screen().root_visual
}
#[inline]
pub fn default_visual(&self) -> &Visualtype {
self.visual_id_to_visual(self.default_visual_id()).unwrap()
}
#[inline]
pub fn default_colormap(&self) -> Colormap {
self.default_screen().default_colormap
}
#[inline]
pub fn visual_id_to_visual(&self, id: Visualid) -> Option<&Visualtype> {
self.setup
.roots
.iter()
.flat_map(|s| s.allowed_depths.iter())
.flat_map(|d| d.visuals.iter())
.find(|v| v.visual_id == id)
}
#[inline]
pub fn generate_xid(&mut self) -> crate::Result<XID> {
Ok(self.xid.next().unwrap())
}
#[inline]
pub fn wait_for_event(&mut self) -> crate::Result<Event> {
log::debug!("Beginning event wait...");
loop {
match self.event_queue.pop_front() {
Some(event) => break Ok(event),
None => self.wait()?,
}
}
}
#[cfg(feature = "async")]
#[inline]
pub async fn wait_for_event_async(&mut self) -> crate::Result<Event> {
loop {
match self.event_queue.pop_front() {
Some(event) => break Ok(event),
None => self.wait_async().await?,
}
}
}
#[inline]
pub fn check_if_event<F: FnMut(&Event) -> bool>(&self, predicate: F) -> bool {
self.event_queue.iter().any(predicate)
}
#[inline]
pub fn save_context(&mut self, xid: XID, context: ContextID, data: NonNull<c_void>) {
self.context.insert((xid, context), data);
}
#[inline]
pub fn find_context(&mut self, xid: XID, context: ContextID) -> Option<NonNull<c_void>> {
self.context.get(&(xid, context)).copied()
}
#[inline]
pub fn delete_context(&mut self, xid: XID, context: ContextID) {
self.context.remove(&(xid, context));
}
}
#[cfg(feature = "std")]
pub type DisplayConnection = Display<name::NameConnection>;
#[cfg(feature = "std")]
impl DisplayConnection {
#[inline]
pub fn create(name: Option<Cow<'_, str>>, auth_info: Option<AuthInfo>) -> crate::Result<Self> {
let connection = name::NameConnection::connect_internal(name)?;
Self::from_connection(connection, auth_info)
}
#[cfg(feature = "async")]
#[inline]
pub async fn create_async(
name: Option<Cow<'_, str>>,
auth_info: Option<AuthInfo>,
) -> crate::Result<Self> {
let connection = name::NameConnection::connect_internal_async(name).await?;
Self::from_connection_async(connection, auth_info).await
}
}