use super::{
bigreq, input, output, Connection, Display, DisplayBase, PendingItem, RequestInfo, StaticSetup,
EXT_KEY_SIZE,
};
use crate::{auth_info::AuthInfo, event::Event, log_trace, XidGenerator, XID};
use alloc::{borrow::Cow, collections::VecDeque};
use core::num::NonZeroU32;
use hashbrown::HashMap;
#[cfg(feature = "std")]
use super::name::NameConnection;
#[cfg(feature = "async")]
use super::{
common::{SendBuffer, WaitBuffer, WaitBufferReturn},
name::AsyncNameConnection,
AsyncConnection, AsyncDisplay, PollOr, RequestWorkaround,
};
#[cfg(feature = "async")]
use alloc::{vec, vec::Vec};
#[cfg(feature = "async")]
use core::{
mem,
task::{Context, Poll},
};
#[derive(Debug)]
pub struct BasicDisplay<Conn> {
pub(crate) connection: Option<Conn>,
pub(crate) setup: StaticSetup,
pub(crate) bigreq_enabled: bool,
pub(crate) max_request_len: usize,
pub(crate) xid: XidGenerator,
pub(crate) default_screen: usize,
pub(crate) event_queue: VecDeque<Event>,
pub(crate) pending_items: HashMap<u16, PendingItem>,
pub(crate) special_event_queues: HashMap<XID, VecDeque<Event>>,
pub(crate) request_number: u64,
pub(crate) wm_protocols_atom: Option<NonZeroU32>,
pub(crate) checked: bool,
pub(crate) extensions: HashMap<[u8; EXT_KEY_SIZE], u8>,
#[cfg(feature = "async")]
wait_buffer: Option<WaitBuffer>,
#[cfg(feature = "async")]
send_buffer: SendBuffer,
#[cfg(feature = "async")]
workarounders: Vec<u16>,
}
impl<Conn> BasicDisplay<Conn> {
#[inline]
fn from_connection_internal(connection: Conn, default_screen: usize) -> Self {
Self {
connection: Some(connection),
setup: Default::default(),
xid: Default::default(),
default_screen,
event_queue: VecDeque::with_capacity(8),
bigreq_enabled: false,
max_request_len: 0,
special_event_queues: HashMap::with_capacity(1),
pending_items: HashMap::with_capacity(4),
request_number: 1,
wm_protocols_atom: None,
checked: cfg!(debug_assertions),
extensions: HashMap::with_capacity(8),
#[cfg(feature = "async")]
wait_buffer: None,
#[cfg(feature = "async")]
send_buffer: Default::default(),
#[cfg(feature = "async")]
workarounders: vec![],
}
}
#[inline]
pub fn connection(&self) -> &Conn {
self.connection.as_ref().expect("Poisoned!")
}
#[inline]
pub fn connection_mut(&mut self) -> &mut Conn {
self.connection.as_mut().expect("Poisoned!")
}
}
impl<Conn: Connection> BasicDisplay<Conn> {
#[cfg_attr(feature = "std", doc = "")]
#[cfg_attr(feature = "std", doc = "# Example")]
#[cfg_attr(feature = "std", doc = "")]
#[cfg_attr(feature = "std", doc = "```rust,no_run")]
#[cfg_attr(feature = "std", doc = "use breadx::display::BasicDisplay;")]
#[cfg_attr(feature = "std", doc = "use std::net::TcpStream;")]
#[cfg_attr(feature = "std", doc = "")]
#[cfg_attr(feature = "std", doc = "# fn main() -> breadx::Result {")]
#[cfg_attr(
feature = "std",
doc = "let server = TcpStream::connect(\"127.0.0.1:60000\")?;"
)]
#[cfg_attr(
feature = "std",
doc = "let conn = BasicDisplay::from_connection(server, 0, None)?;"
)]
#[cfg_attr(feature = "std", doc = "# Ok(())")]
#[cfg_attr(feature = "std", doc = "# }")]
#[cfg_attr(feature = "std", doc = "```")]
#[inline]
pub fn from_connection(
connection: Conn,
default_screen: usize,
auth_info: Option<AuthInfo>,
) -> crate::Result<Self> {
let mut this = Self::from_connection_internal(connection, default_screen);
let mut conn = this.connection.take().unwrap();
let (setup, xid) = conn.establish(auth_info)?;
this.connection = Some(conn);
this.max_request_len = (setup.maximum_request_length as usize).saturating_mul(4);
if let Some(max_request_len) = bigreq::try_bigreq(&mut this)? {
this.bigreq_enabled = true;
this.max_request_len = (max_request_len as usize).saturating_mul(4);
}
this.setup = setup;
this.xid = xid;
Ok(this)
}
}
#[cfg(feature = "async")]
impl<Conn: AsyncConnection + Unpin> BasicDisplay<Conn> {
#[inline]
pub async fn from_connection_async(
connection: Conn,
default_screen: usize,
auth_info: Option<AuthInfo>,
) -> crate::Result<Self> {
let mut this = Self::from_connection_internal(connection, default_screen);
let (setup, xid) = this
.connection
.as_mut()
.unwrap()
.establish_async(auth_info)
.await?;
this.max_request_len = (setup.maximum_request_length as usize).saturating_mul(4);
if let Some(max_request_len) = bigreq::try_bigreq_async(&mut this).await? {
this.bigreq_enabled = true;
this.max_request_len = (max_request_len as usize).saturating_mul(4);
}
this.setup = setup;
this.xid = xid;
Ok(this)
}
}
impl<Conn> DisplayBase for BasicDisplay<Conn> {
#[inline]
fn setup(&self) -> &StaticSetup {
&self.setup
}
#[inline]
fn default_screen_index(&self) -> usize {
self.default_screen
}
#[inline]
fn next_request_number(&mut self) -> u64 {
let rn = self.request_number;
self.request_number = self.request_number.wrapping_add(1);
rn
}
#[inline]
fn has_pending_event(&self) -> bool {
!self.event_queue.is_empty()
}
#[inline]
fn push_event(&mut self, event: Event) {
self.event_queue.push_back(event)
}
#[inline]
fn pop_event(&mut self) -> Option<Event> {
self.event_queue.pop_front()
}
#[inline]
fn generate_xid(&mut self) -> Option<XID> {
self.xid.next_xid()
}
#[inline]
fn add_pending_item(&mut self, req_id: u16, item: PendingItem) {
log_trace!("Adding pending item for {}: {:?}", req_id, &item);
#[cfg(feature = "async")]
{
if let PendingItem::Request(ref pereq) = item {
if matches!(pereq.flags.workaround, RequestWorkaround::GlxFbconfigBug) {
self.workarounders.push(req_id);
}
}
}
self.pending_items.insert(req_id, item);
}
#[inline]
fn get_pending_item(&mut self, req_id: u16) -> Option<PendingItem> {
self.pending_items.get(&req_id).cloned()
}
#[inline]
fn take_pending_item(&mut self, req_id: u16) -> Option<PendingItem> {
log_trace!("Removing pending item for {}", req_id);
#[cfg(feature = "async")]
self.workarounders.retain(|&r| r != req_id);
self.pending_items.remove(&req_id)
}
#[inline]
fn create_special_event_queue(&mut self, xid: XID) {
self.special_event_queues.insert(xid, VecDeque::new());
}
#[inline]
fn push_special_event(&mut self, xid: XID, event: Event) -> Result<(), Event> {
match self.special_event_queues.get_mut(&xid) {
Some(queue) => {
queue.push_back(event);
Ok(())
}
None => Err(event),
}
}
#[inline]
fn pop_special_event(&mut self, xid: XID) -> Option<Event> {
self.special_event_queues
.get_mut(&xid)
.and_then(VecDeque::pop_front)
}
#[inline]
fn delete_special_event_queue(&mut self, xid: XID) {
self.special_event_queues.remove(&xid);
}
#[inline]
fn checked(&self) -> bool {
self.checked
}
#[inline]
fn set_checked(&mut self, checked: bool) {
self.checked = checked;
}
#[inline]
fn bigreq_enabled(&self) -> bool {
self.bigreq_enabled
}
#[inline]
fn max_request_len(&self) -> usize {
self.max_request_len
}
#[inline]
fn get_extension_opcode(&mut self, key: &[u8; EXT_KEY_SIZE]) -> Option<u8> {
self.extensions.get(key).copied()
}
#[inline]
fn set_extension_opcode(&mut self, key: [u8; EXT_KEY_SIZE], opcode: u8) {
self.extensions.insert(key, opcode);
}
#[inline]
fn wm_protocols_atom(&self) -> Option<NonZeroU32> {
self.wm_protocols_atom
}
#[inline]
fn set_wm_protocols_atom(&mut self, a: NonZeroU32) {
self.wm_protocols_atom = Some(a);
}
}
impl<Connect: Connection> Display for BasicDisplay<Connect> {
#[inline]
fn wait(&mut self) -> crate::Result {
let mut conn = self.connection.take().expect("Poisoned!");
let res = input::wait(self, &mut conn);
self.connection = Some(conn);
res
}
#[inline]
fn send_request_raw(&mut self, request_info: RequestInfo) -> crate::Result<u16> {
let mut conn = self.connection.take().expect("Poisoned!");
let res = output::send_request(self, &mut conn, request_info);
self.connection = Some(conn);
res
}
}
#[cfg(feature = "async")]
impl<Connect: AsyncConnection + Unpin> AsyncDisplay for BasicDisplay<Connect> {
#[inline]
fn poll_wait(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result> {
let mut conn = self.connection.take().expect("Poisoned!");
let workarounders = &self.workarounders;
let res = self
.wait_buffer
.get_or_insert_with(WaitBuffer::default)
.poll_wait(&mut conn, move |seq| workarounders.contains(&seq), cx);
self.connection = Some(conn);
let (bytes, fds) = match res {
Poll::Ready(res) => {
self.wait_buffer.take();
match res {
Ok(WaitBufferReturn { data, fds }) => (data, fds),
Err(e) => return Poll::Ready(Err(e)),
}
}
Poll::Pending => return Poll::Pending,
};
Poll::Ready(input::process_bytes(self, bytes, fds))
}
#[inline]
fn begin_send_request_raw(
&mut self,
req: RequestInfo,
_cx: &mut Context<'_>,
) -> PollOr<(), RequestInfo> {
self.send_buffer.fill_hole(req);
PollOr::Ready(())
}
#[inline]
fn poll_send_request_raw(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<u16>> {
let mut send_buffer = mem::replace(&mut self.send_buffer, SendBuffer::OccupiedHole);
let mut conn = self.connection.take().expect("Poisoned!");
let res = send_buffer.poll_send_request(self, &mut conn, cx);
self.send_buffer = send_buffer;
self.connection = Some(conn);
if res.is_ready() {
self.send_buffer.dig_hole();
}
match res {
Poll::Ready(Ok(pr)) => Poll::Ready(Ok(output::finish_request(self, pr))),
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
Poll::Pending => Poll::Pending,
}
}
}
#[cfg(feature = "std")]
pub type DisplayConnection = BasicDisplay<NameConnection>;
#[cfg(all(feature = "std", feature = "async"))]
pub type AsyncDisplayConnection = BasicDisplay<AsyncNameConnection>;
#[cfg(feature = "std")]
impl DisplayConnection {
#[inline]
pub fn create(name: Option<Cow<'_, str>>, auth_info: Option<AuthInfo>) -> crate::Result<Self> {
let (connection, screen) = NameConnection::connect_internal(name)?;
Self::from_connection(connection, screen, auth_info)
}
}
#[cfg(all(feature = "std", feature = "async"))]
impl AsyncDisplayConnection {
#[inline]
pub async fn create_async(
name: Option<Cow<'_, str>>,
auth_info: Option<AuthInfo>,
) -> crate::Result<Self> {
let (connection, screen) = AsyncNameConnection::connect_internal_async(name).await?;
Self::from_connection_async(connection, screen, auth_info).await
}
}