1 | //! Some wrappers around the generated code to simplify use. |
2 | |
3 | use super::cookie::VoidCookie; |
4 | use super::errors::{ConnectionError, ReplyError}; |
5 | use super::protocol::xproto::{Atom, ConnectionExt as XProtoConnectionExt, PropMode, Window}; |
6 | |
7 | /// Extension trait that simplifies API use |
8 | pub 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 | } |
102 | impl<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)] |
114 | pub struct GrabServer<'c, C: XProtoConnectionExt>(&'c C); |
115 | |
116 | impl<'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 | |
127 | impl<C: XProtoConnectionExt> Drop for GrabServer<'_, C> { |
128 | fn drop(&mut self) { |
129 | let _ = (self.0).ungrab_server(); |
130 | } |
131 | } |
132 | |