x11rb/x11_utils.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
//! Some utilities for working with X11.
pub use x11rb_protocol::x11_utils::{
parse_request_header, BigRequests, ExtInfoProvider, ExtensionInformation, ReplyParsingFunction,
Request, RequestHeader, Serialize, TryParse, TryParseFd, X11Error,
};
/// A helper macro for managing atoms
///
/// In X11, one often has to work with many different atoms that are already known at compile time.
/// This macro can simplify managing such a list of atoms.
///
/// The following macro invocation:
/// ```
/// # use x11rb::atom_manager;
/// atom_manager! {
/// /// A collection of Atoms.
/// pub AtomCollection:
/// /// A handle to a response from the X11 server.
/// AtomCollectionCookie {
/// _NET_WM_NAME,
/// _NET_WM_ICON,
/// ATOM_WITH_SPACES: b"ATOM WITH SPACES",
/// WHATEVER,
/// }
/// }
/// ```
/// ...expands to this:
/// ```
/// # use x11rb::protocol::xproto::{Atom, ConnectionExt, InternAtomReply};
/// # use x11rb::errors::{ConnectionError, ReplyError};
/// # use x11rb::cookie::Cookie;
/// #[allow(non_snake_case)]
/// #[derive(Debug, Clone, Copy)]
/// /// A collection of Atoms.
/// pub struct AtomCollection {
/// pub _NET_WM_NAME: Atom,
/// pub _NET_WM_ICON: Atom,
/// pub ATOM_WITH_SPACES: Atom,
/// pub WHATEVER: Atom,
/// }
///
/// #[allow(non_snake_case)]
/// #[derive(Debug)]
/// /// A handle to a response from the X11 server.
/// struct AtomCollectionCookie<'c, C: ConnectionExt> {
/// // please treat the actual members as private
/// # phantom: std::marker::PhantomData<&'c C>,
/// # _NET_WM_NAME: Cookie<'c, C, InternAtomReply>,
/// # _NET_WM_ICON: Cookie<'c, C, InternAtomReply>,
/// # ATOM_WITH_SPACES: Cookie<'c, C, InternAtomReply>,
/// # WHATEVER: Cookie<'c, C, InternAtomReply>,
/// }
///
/// impl AtomCollection {
/// pub fn new<C: ConnectionExt>(
/// conn: &C,
/// ) -> Result<AtomCollectionCookie<'_, C>, ConnectionError> {
/// // This is just an example for readability; the actual code is more efficient.
/// Ok(AtomCollectionCookie {
/// phantom: std::marker::PhantomData,
/// _NET_WM_NAME: conn.intern_atom(false, b"_NET_WM_NAME")?,
/// _NET_WM_ICON: conn.intern_atom(false, b"_NET_WM_ICON")?,
/// ATOM_WITH_SPACES: conn.intern_atom(false, b"ATOM WITH SPACES")?,
/// WHATEVER: conn.intern_atom(false, b"WHATEVER")?,
/// })
/// }
/// }
///
/// impl<'c, C> AtomCollectionCookie<'c, C>
/// where
/// C: ConnectionExt,
/// {
/// pub fn reply(self) -> Result<AtomCollection, ReplyError> {
/// // This is just an example for readability; the actual code is different.
/// Ok(AtomCollection {
/// _NET_WM_NAME: self._NET_WM_NAME.reply()?.atom,
/// _NET_WM_ICON: self._NET_WM_ICON.reply()?.atom,
/// ATOM_WITH_SPACES: self.ATOM_WITH_SPACES.reply()?.atom,
/// WHATEVER: self.WHATEVER.reply()?.atom,
/// })
/// }
/// }
/// ```
#[macro_export]
macro_rules! atom_manager {
{
$(#[$struct_meta:meta])*
$vis:vis $struct_name:ident:
$(#[$cookie_meta:meta])*
$cookie_name:ident {
$($field_name:ident$(: $atom_value:expr)?,)*
}
} => {
// Cookie version
#[allow(non_snake_case)]
#[derive(Debug)]
$(#[$cookie_meta])*
$vis struct $cookie_name<'a, C: $crate::protocol::xproto::ConnectionExt> {
__private_phantom: ::std::marker::PhantomData<&'a C>,
__private_cookies: ::std::vec::Vec<$crate::cookie::Cookie<'a, C, $crate::protocol::xproto::InternAtomReply>>,
}
// Replies
#[allow(non_snake_case)]
#[derive(Debug, Clone, Copy)]
$(#[$struct_meta])*
$vis struct $struct_name {
$(
$vis $field_name: $crate::protocol::xproto::Atom,
)*
}
impl $struct_name {
$vis fn new<C: $crate::protocol::xproto::ConnectionExt>(
_conn: &C,
) -> ::std::result::Result<$cookie_name<'_, C>, $crate::errors::ConnectionError> {
let names = [
$($crate::__atom_manager_atom_value!($field_name$(: $atom_value)?),)*
];
let cookies: ::std::result::Result<::std::vec::Vec<_>, _>
= names.into_iter().map(|name| _conn.intern_atom(false, name)).collect();
Ok($cookie_name {
__private_phantom: ::std::marker::PhantomData,
__private_cookies: cookies?,
})
}
}
impl<'a, C: $crate::protocol::xproto::ConnectionExt> $cookie_name<'a, C> {
$vis fn reply(self) -> ::std::result::Result<$struct_name, $crate::errors::ReplyError> {
let mut replies = self.__private_cookies.into_iter();
Ok($struct_name {
$(
$field_name: replies.next().expect("new() should have constructed a Vec of the correct size").reply()?.atom,
)*
})
}
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __atom_manager_atom_value {
($field_name:ident) => {
stringify!($field_name).as_bytes()
};
($field_name:ident: $atom_value:expr) => {
$atom_value
};
}