use crate::{
auto::{
xproto::{Colormap, GetInputFocusRequest, Screen, Setup, Visualid, Visualtype, Window},
AsByteSequence,
},
error::BreadError,
event::Event,
util::expand_or_truncate_to_length,
Fd, Request, XID,
};
use alloc::{boxed::Box, vec::Vec};
use core::{fmt, iter, marker::PhantomData, mem, num::NonZeroU32};
use tinyvec::TinyVec;
#[cfg(feature = "async")]
use crate::xid::XidType;
#[cfg(feature = "async")]
use core::task::{Context, Poll};
mod basic;
pub(crate) mod bigreq;
mod cell;
mod connection;
pub mod traits;
pub use traits::{rgb, GcParameters, KeyboardMapping, WindowParameters};
pub use basic::*;
pub use cell::*;
pub use connection::*;
#[cfg(feature = "async")]
pub(crate) mod futures;
#[cfg(feature = "async")]
pub use futures::*;
#[cfg(feature = "sync-display")]
mod sync;
#[cfg(feature = "sync-display")]
pub use sync::*;
pub(crate) mod input;
pub(crate) mod output;
#[cfg(feature = "async")]
pub(crate) mod common;
#[cfg(feature = "std")]
pub mod name;
pub mod prelude {
pub use super::traits::*;
#[cfg(feature = "async")]
pub use super::{AsyncDisplay, AsyncDisplayExt};
pub use super::{Display, DisplayBase, DisplayExt};
}
pub type StaticSetup = Setup<'static, 'static, 'static, 'static, 'static>;
pub type StaticScreen = Screen<'static, 'static>;
pub(crate) const EXT_KEY_SIZE: usize = 24;
pub trait DisplayBase {
fn setup(&self) -> &StaticSetup;
fn default_screen_index(&self) -> usize;
fn next_request_number(&mut self) -> u64;
fn generate_xid(&mut self) -> Option<XID>;
fn add_pending_item(&mut self, req_id: u16, item: PendingItem);
fn get_pending_item(&mut self, req_id: u16) -> Option<PendingItem>;
fn take_pending_item(&mut self, req_id: u16) -> Option<PendingItem>;
fn has_pending_event(&self) -> bool;
fn push_event(&mut self, event: Event);
fn pop_event(&mut self) -> Option<Event>;
fn create_special_event_queue(&mut self, xid: XID);
fn push_special_event(&mut self, xid: XID, event: Event) -> Result<(), Event>;
fn pop_special_event(&mut self, xid: XID) -> Option<Event>;
fn delete_special_event_queue(&mut self, xid: XID);
fn checked(&self) -> bool;
fn set_checked(&mut self, checked: bool);
fn bigreq_enabled(&self) -> bool;
fn max_request_len(&self) -> usize;
fn get_extension_opcode(&mut self, key: &[u8; EXT_KEY_SIZE]) -> Option<u8>;
fn set_extension_opcode(&mut self, key: [u8; EXT_KEY_SIZE], opcode: u8);
fn wm_protocols_atom(&self) -> Option<NonZeroU32>;
fn set_wm_protocols_atom(&mut self, a: NonZeroU32);
#[inline]
fn add_pending_request(&mut self, req_id: u16, pereq: PendingRequest) {
self.add_pending_item(req_id, PendingItem::Request(pereq));
}
#[inline]
fn get_pending_request(&mut self, req_id: u16) -> Option<PendingRequest> {
self.get_pending_item(req_id).and_then(PendingItem::request)
}
#[inline]
fn take_pending_request(&mut self, req_id: u16) -> Option<PendingRequest> {
match self.take_pending_item(req_id) {
Some(PendingItem::Request(req)) => Some(req),
Some(other) => {
self.add_pending_item(req_id, other);
None
}
None => None,
}
}
#[inline]
fn add_pending_reply(&mut self, req_id: u16, perep: PendingReply) {
self.add_pending_item(req_id, PendingItem::Reply(perep));
}
#[inline]
fn take_pending_reply(&mut self, req_id: u16) -> Option<PendingReply> {
match self.take_pending_item(req_id) {
Some(PendingItem::Reply(repl)) => Some(repl),
Some(other) => {
self.add_pending_item(req_id, other);
None
}
None => None,
}
}
#[inline]
fn add_pending_error(&mut self, req_id: u16, err: BreadError) {
self.add_pending_item(req_id, PendingItem::Error(err));
}
#[inline]
fn check_for_pending_error(&mut self, req_id: u16) -> crate::Result {
match self.take_pending_item(req_id) {
Some(PendingItem::Error(err)) => Err(err),
Some(other) => {
self.add_pending_item(req_id, other);
Ok(())
}
_ => Ok(()),
}
}
#[inline]
fn screens(&self) -> &[StaticScreen] {
&self.setup().roots
}
#[inline]
fn default_screen(&self) -> &StaticScreen {
&self.setup().roots[self.default_screen_index()]
}
#[inline]
fn default_root(&self) -> Window {
self.default_screen().root
}
#[inline]
fn default_white_pixel(&self) -> u32 {
self.default_screen().white_pixel
}
#[inline]
fn default_black_pixel(&self) -> u32 {
self.default_screen().black_pixel
}
#[inline]
fn default_visual_id(&self) -> Visualid {
self.default_screen().root_visual
}
#[inline]
fn default_visual(&self) -> &Visualtype {
self.visual_id_to_visual(self.default_visual_id()).unwrap()
}
#[inline]
fn default_colormap(&self) -> Colormap {
self.default_screen().default_colormap
}
#[inline]
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]
fn get_scanline_pad(&self, depth: u8) -> usize {
self.setup()
.pixmap_formats
.iter()
.find(|f| f.depth == depth)
.map_or(self.setup().bitmap_format_scanline_pad, |f| f.scanline_pad) as _
}
#[inline]
fn depth_of_visual(&self, id: Visualid) -> Option<u8> {
self.setup()
.roots
.iter()
.flat_map(|s| s.allowed_depths.iter())
.find_map(|d| {
if d.visuals.iter().any(|v| v.visual_id == id) {
Some(d.depth)
} else {
None
}
})
}
}
impl<D: DisplayBase + ?Sized> DisplayBase for &mut D {
#[inline]
fn setup(&self) -> &StaticSetup {
(**self).setup()
}
#[inline]
fn default_screen_index(&self) -> usize {
(**self).default_screen_index()
}
#[inline]
fn next_request_number(&mut self) -> u64 {
(**self).next_request_number()
}
#[inline]
fn has_pending_event(&self) -> bool {
(**self).has_pending_event()
}
#[inline]
fn push_event(&mut self, event: Event) {
(**self).push_event(event)
}
#[inline]
fn pop_event(&mut self) -> Option<Event> {
(**self).pop_event()
}
#[inline]
fn generate_xid(&mut self) -> Option<XID> {
(**self).generate_xid()
}
#[inline]
fn add_pending_item(&mut self, req_id: u16, item: PendingItem) {
(**self).add_pending_item(req_id, item)
}
#[inline]
fn get_pending_item(&mut self, req_id: u16) -> Option<PendingItem> {
(**self).get_pending_item(req_id)
}
#[inline]
fn take_pending_item(&mut self, req_id: u16) -> Option<PendingItem> {
(**self).take_pending_item(req_id)
}
#[inline]
fn create_special_event_queue(&mut self, xid: XID) {
(**self).create_special_event_queue(xid)
}
#[inline]
fn push_special_event(&mut self, xid: XID, event: Event) -> Result<(), Event> {
(**self).push_special_event(xid, event)
}
#[inline]
fn pop_special_event(&mut self, xid: XID) -> Option<Event> {
(**self).pop_special_event(xid)
}
#[inline]
fn delete_special_event_queue(&mut self, xid: XID) {
(**self).delete_special_event_queue(xid)
}
#[inline]
fn checked(&self) -> bool {
(**self).checked()
}
#[inline]
fn set_checked(&mut self, checked: bool) {
(**self).set_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).get_extension_opcode(key)
}
#[inline]
fn set_extension_opcode(&mut self, key: [u8; EXT_KEY_SIZE], opcode: u8) {
(**self).set_extension_opcode(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).set_wm_protocols_atom(a)
}
}
pub trait Display: DisplayBase {
fn wait(&mut self) -> crate::Result;
fn send_request_raw(&mut self, request_info: RequestInfo) -> crate::Result<u16>;
#[inline]
fn synchronize(&mut self) -> crate::Result {
log::debug!("Synchronizing display");
let mut gifr = RequestInfo::from_request(
GetInputFocusRequest::default(),
self.bigreq_enabled(),
self.max_request_len(),
);
gifr.discard_reply = true;
let sequence = self.send_request_raw(gifr)?;
while {
self.wait()?;
self.get_pending_request(sequence).is_some()
} {}
Ok(())
}
#[inline]
fn resolve_request_raw(&mut self, req_id: u16) -> crate::Result<PendingReply> {
loop {
match self.take_pending_reply(req_id) {
Some(p) => return Ok(p),
None => self.wait()?,
}
}
}
#[inline]
fn wait_for_event(&mut self) -> crate::Result<Event> {
loop {
match self.pop_event() {
Some(e) => return Ok(e),
None => self.wait()?,
}
}
}
#[inline]
fn wait_for_special_event(&mut self, xid: XID) -> crate::Result<Event> {
loop {
match self.pop_special_event(xid) {
Some(e) => break Ok(e),
None => self.wait()?,
}
}
}
}
impl<D: Display + ?Sized> Display for &mut D {
#[inline]
fn wait(&mut self) -> crate::Result {
(**self).wait()
}
#[inline]
fn send_request_raw(&mut self, request_info: RequestInfo) -> crate::Result<u16> {
(**self).send_request_raw(request_info)
}
}
#[cfg(feature = "async")]
pub trait AsyncDisplay: DisplayBase {
fn poll_wait(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result>;
fn begin_send_request_raw(
&mut self,
req: RequestInfo,
cx: &mut Context<'_>,
) -> PollOr<(), RequestInfo>;
fn poll_send_request_raw(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<u16>>;
}
#[cfg(feature = "async")]
impl<D: AsyncDisplay + ?Sized> AsyncDisplay for &mut D {
#[inline]
fn poll_wait(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result> {
(**self).poll_wait(cx)
}
#[inline]
fn begin_send_request_raw(
&mut self,
req: RequestInfo,
cx: &mut Context<'_>,
) -> PollOr<(), RequestInfo> {
(**self).begin_send_request_raw(req, cx)
}
#[inline]
fn poll_send_request_raw(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<u16>> {
(**self).poll_send_request_raw(cx)
}
}
pub trait DisplayExt {
fn send_request<R: Request>(&mut self, request: R) -> crate::Result<RequestCookie<R>>;
fn resolve_request<R: Request>(&mut self, token: RequestCookie<R>) -> crate::Result<R::Reply>
where
R::Reply: Default;
#[inline]
fn exchange_request<R: Request>(&mut self, request: R) -> crate::Result<R::Reply>
where
R::Reply: Default,
{
log::info!("Sending {} to server", core::any::type_name::<R>());
let tok = self.send_request(request)?;
log::info!("Resolving request...");
self.resolve_request(tok)
}
}
impl<D: Display + ?Sized> DisplayExt for D {
#[inline]
fn send_request<R: Request>(&mut self, request: R) -> crate::Result<RequestCookie<R>> {
let r = RequestInfo::from_request(request, self.bigreq_enabled(), self.max_request_len());
let req_id = self.send_request_raw(r)?;
Ok(RequestCookie::from_sequence(req_id))
}
#[inline]
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 {
if self.checked() {
self.synchronize()?;
let seq = token.sequence();
self.take_pending_request(seq);
self.check_for_pending_error(seq)?;
}
return Ok(Default::default());
}
let PendingReply { data, fds } = self.resolve_request_raw(token.sequence())?;
decode_reply::<R>(&data, fds)
}
}
#[cfg(feature = "async")]
pub trait AsyncDisplayExt: AsyncDisplay {
fn wait_async(&mut self) -> WaitFuture<'_, Self>;
fn send_request_raw_async(&mut self, req: RequestInfo) -> SendRequestRawFuture<'_, Self>;
fn send_request_async<R: Request>(&mut self, request: R) -> SendRequestFuture<'_, Self, R>;
fn resolve_request_async<R: Request>(
&mut self,
token: RequestCookie<R>,
) -> ResolveRequestFuture<'_, Self, R>
where
R::Reply: Default;
fn synchronize_async(&mut self) -> SynchronizeFuture<'_, Self>;
fn resolve_request_raw_async(&mut self, req_id: u16) -> ResolveRequestRawFuture<'_, Self>;
fn wait_for_event_async(&mut self) -> WaitForEventFuture<'_, Self>;
fn wait_for_special_event_async(&mut self, xid: XID) -> WaitForSpecialEventFuture<'_, Self>;
fn exchange_request_async<R: Request>(
&mut self,
request: R,
) -> ExchangeRequestFuture<'_, Self, R>;
fn exchange_xid_async<R: Request, U: XidType + Unpin, F: FnOnce(U) -> R>(
&mut self,
to_request: F,
) -> ExchangeXidFuture<'_, Self, R, U, F>;
}
#[cfg(feature = "async")]
impl<D: AsyncDisplay + ?Sized> AsyncDisplayExt for D {
#[inline]
fn wait_async(&mut self) -> WaitFuture<Self> {
WaitFuture::run(self)
}
#[inline]
fn send_request_raw_async(&mut self, req: RequestInfo) -> SendRequestRawFuture<'_, Self> {
SendRequestRawFuture::run(self, req)
}
#[inline]
fn send_request_async<R: Request>(&mut self, request: R) -> SendRequestFuture<'_, Self, R> {
SendRequestFuture::run(self, request)
}
#[inline]
fn resolve_request_async<R: Request>(
&mut self,
token: RequestCookie<R>,
) -> ResolveRequestFuture<'_, Self, R>
where
R::Reply: Default,
{
ResolveRequestFuture::run(self, token)
}
#[inline]
fn synchronize_async(&mut self) -> SynchronizeFuture<'_, Self> {
SynchronizeFuture::run(self)
}
#[inline]
fn resolve_request_raw_async(&mut self, req_id: u16) -> ResolveRequestRawFuture<'_, Self> {
ResolveRequestRawFuture::run(self, req_id)
}
#[inline]
fn wait_for_event_async(&mut self) -> WaitForEventFuture<'_, Self> {
WaitForEventFuture::run(self)
}
#[inline]
fn wait_for_special_event_async(&mut self, xid: XID) -> WaitForSpecialEventFuture<'_, Self> {
WaitForSpecialEventFuture::run(self, xid)
}
#[inline]
fn exchange_request_async<R: Request>(
&mut self,
request: R,
) -> ExchangeRequestFuture<'_, Self, R> {
ExchangeRequestFuture::run(self, request)
}
#[inline]
fn exchange_xid_async<R: Request, U: XidType + Unpin, F: FnOnce(U) -> R>(
&mut self,
to_request: F,
) -> ExchangeXidFuture<'_, Self, R, U, F> {
ExchangeXidFuture::run(self, to_request)
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct RequestInfo {
pub(crate) data: TinyVec<[u8; 32]>,
pub(crate) fds: Vec<Fd>,
pub(crate) zero_sized_reply: bool,
pub(crate) opcode: u8,
pub(crate) extension: Option<&'static str>,
pub(crate) expects_fds: bool,
pub(crate) discard_reply: bool,
pub(crate) sequence: Option<u16>,
}
impl RequestInfo {
#[inline]
pub fn from_request<R: Request>(mut req: R, use_bigreq: bool, max_request_len: usize) -> Self {
const SHORT_REQUEST_LIMIT: usize = (u16::MAX as usize) * 4;
debug_assert!(use_bigreq || max_request_len <= SHORT_REQUEST_LIMIT);
let mut data = iter::repeat(0)
.take(req.size())
.collect::<TinyVec<[u8; 32]>>();
let mut len = req.as_bytes(&mut data);
len = (len + 3) & (!0x03);
expand_or_truncate_to_length(&mut data, len);
assert!(
max_request_len >= len,
"Request's size was larger than the maximum request length"
);
let x_len = len / 4;
log::trace!("xlen is {}", x_len);
if use_bigreq {
let length_bytes = ((x_len + 1) as u32).to_ne_bytes();
data[2] = 0;
data[3] = 0;
data.extend_from_slice(&length_bytes);
data[4..].rotate_right(length_bytes.len());
} else {
let len_bytes = (x_len as u16).to_ne_bytes();
data[2] = len_bytes[0];
data[3] = len_bytes[1];
}
RequestInfo {
data,
fds: match req.file_descriptors() {
Some(fd) => mem::take(fd),
None => Vec::new(),
},
zero_sized_reply: mem::size_of::<R::Reply>() == 0,
opcode: R::OPCODE,
extension: R::EXTENSION,
expects_fds: R::REPLY_EXPECTS_FDS,
discard_reply: false,
sequence: None,
}
}
#[inline]
pub(crate) fn set_sequence(&mut self, seq: u16) {
self.sequence = Some(seq);
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PendingReply {
pub data: TinyVec<[u8; 32]>,
pub fds: Box<[Fd]>,
}
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Default, Eq, Hash)]
#[repr(transparent)]
pub struct RequestCookie<R: Request> {
sequence: u16,
_phantom: PhantomData<Option<R::Reply>>,
}
impl<R: Request> fmt::Debug for RequestCookie<R> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RequestCookie")
.field("sequence", &self.sequence)
.finish()
}
}
impl<R: Request> RequestCookie<R> {
#[must_use]
#[inline]
pub fn from_sequence(sequence: u16) -> Self {
Self {
sequence,
_phantom: PhantomData,
}
}
#[inline]
#[must_use]
pub fn sequence(self) -> u16 {
self.sequence
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct PendingRequest {
pub request: u16,
pub flags: PendingRequestFlags,
}
#[derive(Default, Debug, Copy, Clone)]
pub struct PendingRequestFlags {
pub discard_reply: bool,
pub checked: bool,
pub expects_fds: bool,
pub workaround: RequestWorkaround,
}
#[derive(Debug, Copy, Clone)]
pub enum RequestWorkaround {
NoWorkaround,
GlxFbconfigBug,
}
impl Default for RequestWorkaround {
#[inline]
fn default() -> Self {
Self::NoWorkaround
}
}
#[derive(Debug, Clone)]
pub enum PendingItem {
Request(PendingRequest),
Reply(PendingReply),
Error(BreadError),
}
impl PendingItem {
#[must_use]
#[inline]
pub fn request(self) -> Option<PendingRequest> {
match self {
PendingItem::Request(pr) => Some(pr),
_ => None,
}
}
#[must_use]
#[inline]
pub fn reply(self) -> Option<PendingReply> {
match self {
PendingItem::Reply(pr) => Some(pr),
_ => None,
}
}
#[must_use]
#[inline]
pub fn error(self) -> Option<BreadError> {
match self {
PendingItem::Error(err) => Some(err),
_ => None,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PollOr<T, D> {
Ready(T),
Pending(D),
}
#[inline]
pub(crate) fn decode_reply<R: Request>(reply: &[u8], fds: Box<[Fd]>) -> crate::Result<R::Reply> {
let mut r = R::Reply::from_bytes(reply)
.ok_or(BreadError::BadObjectRead(None))?
.0;
if let Some(fdslot) = r.file_descriptors() {
*fdslot = fds.into_vec();
}
Ok(r)
}
#[inline]
pub(crate) fn generate_xid<D: DisplayBase + ?Sized>(display: &mut D) -> crate::Result<XID> {
display
.generate_xid()
.ok_or(crate::BreadError::StaticMsg("Ran out of XIDs"))
}