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}