jay_config/client.rs
1//! Tools for inspecting and manipulating clients.
2
3use {
4 serde::{Deserialize, Serialize},
5 std::ops::Deref,
6};
7
8/// A client connected to the compositor.
9#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
10pub struct Client(pub u64);
11
12impl Client {
13 /// Returns whether the client exists.
14 pub fn exists(self) -> bool {
15 self.0 != 0 && get!(false).client_exists(self)
16 }
17
18 /// Returns whether the client does not exist.
19 ///
20 /// This is a shorthand for `!self.exists()`.
21 pub fn does_not_exist(self) -> bool {
22 !self.exists()
23 }
24
25 /// Returns whether this client is XWayland.
26 pub fn is_xwayland(self) -> bool {
27 get!(false).client_is_xwayland(self)
28 }
29
30 /// Disconnects the client.
31 pub fn kill(self) {
32 get!().client_kill(self)
33 }
34}
35
36/// Returns all current clients.
37pub fn clients() -> Vec<Client> {
38 get!().clients()
39}
40
41/// A client matcher.
42#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
43pub struct ClientMatcher(pub u64);
44
45/// A matched client.
46#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
47pub struct MatchedClient {
48 pub(crate) matcher: ClientMatcher,
49 pub(crate) client: Client,
50}
51
52/// A criterion for matching a client.
53#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
54#[non_exhaustive]
55pub enum ClientCriterion<'a> {
56 /// Matches if the contained matcher matches.
57 Matcher(ClientMatcher),
58 /// Matches if the contained criterion does not match.
59 Not(&'a ClientCriterion<'a>),
60 /// Matches if all of the contained criteria match.
61 All(&'a [ClientCriterion<'a>]),
62 /// Matches if any of the contained criteria match.
63 Any(&'a [ClientCriterion<'a>]),
64 /// Matches if an exact number of the contained criteria match.
65 Exactly(usize, &'a [ClientCriterion<'a>]),
66 /// Matches the engine name of the client's sandbox verbatim.
67 SandboxEngine(&'a str),
68 /// Matches the engine name of the client's sandbox with a regular expression.
69 SandboxEngineRegex(&'a str),
70 /// Matches the app id of the client's sandbox verbatim.
71 SandboxAppId(&'a str),
72 /// Matches the app id of the client's sandbox with a regular expression.
73 SandboxAppIdRegex(&'a str),
74 /// Matches the instance id of the client's sandbox verbatim.
75 SandboxInstanceId(&'a str),
76 /// Matches the instance id of the client's sandbox with a regular expression.
77 SandboxInstanceIdRegex(&'a str),
78 /// Matches if the client is sandboxed.
79 Sandboxed,
80 /// Matches the user ID of the client.
81 Uid(i32),
82 /// Matches the process ID of the client.
83 Pid(i32),
84 /// Matches if the client is Xwayland.
85 IsXwayland,
86 /// Matches the `/proc/pid/comm` of the client verbatim.
87 Comm(&'a str),
88 /// Matches the `/proc/pid/comm` of the client with a regular expression.
89 CommRegex(&'a str),
90 /// Matches the `/proc/pid/exe` of the client verbatim.
91 Exe(&'a str),
92 /// Matches the `/proc/pid/exe` of the client with a regular expression.
93 ExeRegex(&'a str),
94 /// Matches the tag of the client verbatim.
95 Tag(&'a str),
96 /// Matches the tag of the client with a regular expression.
97 TagRegex(&'a str),
98}
99
100impl ClientCriterion<'_> {
101 /// Converts the criterion to a matcher.
102 pub fn to_matcher(self) -> ClientMatcher {
103 get!(ClientMatcher(0)).create_client_matcher(self)
104 }
105
106 /// Binds a function to execute when the criterion matches a client.
107 ///
108 /// This leaks the matcher.
109 pub fn bind<F: FnMut(MatchedClient) + 'static>(self, cb: F) {
110 self.to_matcher().bind(cb);
111 }
112
113 /// Sets the capabilities granted to clients matching this matcher.
114 ///
115 /// This leaks the matcher.
116 pub fn set_capabilities(self, caps: ClientCapabilities) {
117 self.to_matcher().set_capabilities(caps);
118 }
119
120 /// Sets the upper capability bounds for clients in sandboxes created by this client.
121 ///
122 /// This leaks the matcher.
123 pub fn set_sandbox_bounding_capabilities(self, caps: ClientCapabilities) {
124 self.to_matcher().set_sandbox_bounding_capabilities(caps);
125 }
126}
127
128impl ClientMatcher {
129 /// Destroys the matcher.
130 ///
131 /// Any bound callback will no longer be executed.
132 pub fn destroy(self) {
133 get!().destroy_client_matcher(self);
134 }
135
136 /// Sets a function to execute when the criterion matches a client.
137 ///
138 /// Replaces any already bound callback.
139 pub fn bind<F: FnMut(MatchedClient) + 'static>(self, cb: F) {
140 get!().set_client_matcher_handler(self, cb);
141 }
142
143 /// Sets the capabilities granted to clients matching this matcher.
144 ///
145 /// If multiple matchers match a client, the capabilities are added.
146 ///
147 /// If no matcher matches a client, it is granted the default capabilities depending
148 /// on whether it's sandboxed or not. If it is not sandboxed, it is granted the
149 /// capabilities [`CC_LAYER_SHELL`] and [`CC_DRM_LEASE`]. Otherwise it is granted the
150 /// capability [`CC_DRM_LEASE`].
151 ///
152 /// Regardless of any capabilities set through this function, the capabilities of the
153 /// client can never exceed its bounding capabilities.
154 pub fn set_capabilities(self, caps: ClientCapabilities) {
155 get!().set_client_matcher_capabilities(self, caps);
156 }
157
158 /// Sets the upper capability bounds for clients in sandboxes created by this client.
159 ///
160 /// If multiple matchers match a client, the capabilities are added.
161 ///
162 /// If no matcher matches a client, the bounding capabilities for sandboxes depend on
163 /// whether the client is itself sandboxed. If it is sandboxed, the bounding
164 /// capabilities are the effective capabilities of the client. Otherwise the bounding
165 /// capabilities are all capabilities.
166 ///
167 /// Regardless of any capabilities set through this function, the capabilities set
168 /// through this function can never exceed the client's bounding capabilities.
169 pub fn set_sandbox_bounding_capabilities(self, caps: ClientCapabilities) {
170 get!().set_client_matcher_bounding_capabilities(self, caps);
171 }
172}
173
174impl MatchedClient {
175 /// Returns the client that matched.
176 pub fn client(self) -> Client {
177 self.client
178 }
179
180 /// Returns the matcher.
181 pub fn matcher(self) -> ClientMatcher {
182 self.matcher
183 }
184
185 /// Latches a function to be executed when the client no longer matches the criteria.
186 pub fn latch<F: FnOnce() + 'static>(self, cb: F) {
187 get!().set_client_matcher_latch_handler(self.matcher, self.client, cb);
188 }
189}
190
191impl Deref for MatchedClient {
192 type Target = Client;
193
194 fn deref(&self) -> &Self::Target {
195 &self.client
196 }
197}
198
199bitflags! {
200 /// Capabilities granted to a client.
201 #[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq)]
202 pub struct ClientCapabilities(pub u64) {
203 /// Grants access to the `ext_data_control_manager_v1` and
204 /// `zwlr_data_control_manager_v1` globals.
205 pub const CC_DATA_CONTROL = 1 << 0,
206 /// Grants access to the `zwp_virtual_keyboard_manager_v1` global.
207 pub const CC_VIRTUAL_KEYBOARD = 1 << 1,
208 /// Grants access to the `ext_foreign_toplevel_list_v1` global.
209 pub const CC_FOREIGN_TOPLEVEL_LIST = 1 << 2,
210 /// Grants access to the `ext_idle_notifier_v1` global.
211 pub const CC_IDLE_NOTIFIER = 1 << 3,
212 /// Grants access to the `ext_session_lock_manager_v1` global.
213 pub const CC_SESSION_LOCK = 1 << 4,
214 /// Grants access to the `zwlr_layer_shell_v1` global.
215 pub const CC_LAYER_SHELL = 1 << 6,
216 /// Grants access to the `ext_image_copy_capture_manager_v1` and
217 /// `zwlr_screencopy_manager_v1` globals.
218 pub const CC_SCREENCOPY = 1 << 7,
219 /// Grants access to the `ext_transient_seat_manager_v1` global.
220 pub const CC_SEAT_MANAGER = 1 << 8,
221 /// Grants access to the `wp_drm_lease_device_v1` global.
222 pub const CC_DRM_LEASE = 1 << 9,
223 /// Grants access to the `zwp_input_method_manager_v2` global.
224 pub const CC_INPUT_METHOD = 1 << 10,
225 /// Grants access to the `ext_workspace_manager_v1` global.
226 pub const CC_WORKSPACE_MANAGER = 1 << 11,
227 /// Grants access to the `zwlr_foreign_toplevel_manager_v1` global.
228 pub const CC_FOREIGN_TOPLEVEL_MANAGER = 1 << 12,
229 /// Grants access to the `jay_head_manager_v1` and `zwlr_output_manager_v1`
230 /// globals.
231 pub const CC_HEAD_MANAGER = 1 << 13,
232 /// Grants access to the `zwlr_gamma_control_manager_v1` global.
233 pub const CC_GAMMA_CONTROL_MANAGER = 1 << 14,
234 }
235}