x11rb/wrapper.rs
1//! Some wrappers around the generated code to simplify use.
2
3use super::cookie::VoidCookie;
4use super::errors::{ConnectionError, ReplyError};
5use super::protocol::xproto::{Atom, ConnectionExt as XProtoConnectionExt, PropMode, Window};
6
7/// Extension trait that simplifies API use
8pub trait ConnectionExt: XProtoConnectionExt {
9 /// Change a property on a window with format 8.
10 fn change_property8<A, B>(
11 &self,
12 mode: PropMode,
13 window: Window,
14 property: A,
15 type_: B,
16 data: &[u8],
17 ) -> Result<VoidCookie<'_, Self>, ConnectionError>
18 where
19 A: Into<Atom>,
20 B: Into<Atom>,
21 {
22 self.change_property(
23 mode,
24 window,
25 property,
26 type_,
27 8,
28 data.len().try_into().expect("`data` has too many elements"),
29 data,
30 )
31 }
32
33 /// Change a property on a window with format 16.
34 fn change_property16<A, B>(
35 &self,
36 mode: PropMode,
37 window: Window,
38 property: A,
39 type_: B,
40 data: &[u16],
41 ) -> Result<VoidCookie<'_, Self>, ConnectionError>
42 where
43 A: Into<Atom>,
44 B: Into<Atom>,
45 {
46 let mut data_u8 = Vec::with_capacity(data.len() * 2);
47 for item in data {
48 data_u8.extend(item.to_ne_bytes());
49 }
50 self.change_property(
51 mode,
52 window,
53 property,
54 type_,
55 16,
56 data.len().try_into().expect("`data` has too many elements"),
57 &data_u8,
58 )
59 }
60
61 /// Change a property on a window with format 32.
62 fn change_property32<A, B>(
63 &self,
64 mode: PropMode,
65 window: Window,
66 property: A,
67 type_: B,
68 data: &[u32],
69 ) -> Result<VoidCookie<'_, Self>, ConnectionError>
70 where
71 A: Into<Atom>,
72 B: Into<Atom>,
73 {
74 let mut data_u8 = Vec::with_capacity(data.len() * 4);
75 for item in data {
76 data_u8.extend(item.to_ne_bytes());
77 }
78 self.change_property(
79 mode,
80 window,
81 property,
82 type_,
83 32,
84 data.len().try_into().expect("`data` has too many elements"),
85 &data_u8,
86 )
87 }
88
89 /// Synchronise with the X11 server.
90 ///
91 /// This function synchronises with the X11 server. This means that all requests that are still
92 /// in the output buffer are sent to the server. Then, we wait until the X11 server processed
93 /// all requests.
94 fn sync(&self) -> Result<(), ReplyError> {
95 // When a new request is generated, it is appended to the output buffer. Thus, this causes
96 // all previous requests to be sent.
97 // The X11 server is single-threaded and processes requests in-order. Thus, it will only
98 // reply to our GetInputFocus after everything before was processed.
99 self.get_input_focus()?.reply().and(Ok(()))
100 }
101}
102impl<C: XProtoConnectionExt + ?Sized> ConnectionExt for C {}
103
104/// A RAII-like wrapper around [super::protocol::xproto::grab_server] and
105/// [super::protocol::xproto::ungrab_server].
106///
107/// Instances of this struct represent that we sent a [super::protocol::xproto::grab_server]
108/// request. When this struct is dropped, an [super::protocol::xproto::ungrab_server] request is
109/// sent.
110///
111/// Any errors during `Drop` are silently ignored. Most likely an error here means that your
112/// X11 connection is broken and later requests will also fail.
113#[derive(Debug)]
114pub struct GrabServer<'c, C: XProtoConnectionExt>(&'c C);
115
116impl<'c, C: XProtoConnectionExt> GrabServer<'c, C> {
117 /// Grab the server by sending a [super::protocol::xproto::grab_server] request.
118 ///
119 /// The returned type will call [super::protocol::xproto::ungrab_server] when it is dropped.
120 pub fn grab(conn: &'c C) -> Result<Self, ConnectionError> {
121 // Grab the server, return any errors, ignore the resulting VoidCookie
122 drop(conn.grab_server()?);
123 Ok(Self(conn))
124 }
125}
126
127impl<C: XProtoConnectionExt> Drop for GrabServer<'_, C> {
128 fn drop(&mut self) {
129 let _ = (self.0).ungrab_server();
130 }
131}