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