1use crate::{OutputHandle, OutputInfo};
2use std::fmt::{Debug, Formatter, Result as FmtResult};
3use std::sync::Arc;
4
5#[derive(Debug, Clone)]
7pub struct SurfaceInfo {
8 pub name: String,
10 pub output: OutputHandle,
12}
13
14#[derive(Clone)]
18pub enum Surface {
19 All,
21 Named(String),
23 Any(Vec<String>),
25 Filter(Arc<dyn Fn(&SurfaceInfo) -> bool + Send + Sync>),
27 Not(Box<Surface>),
29 Or(Vec<Surface>),
31}
32
33impl Surface {
34 pub fn all() -> Self {
36 Self::All
37 }
38
39 pub fn named(name: impl Into<String>) -> Self {
41 Self::Named(name.into())
42 }
43
44 pub fn any(names: impl IntoIterator<Item = impl Into<String>>) -> Self {
46 Self::Any(names.into_iter().map(Into::into).collect())
47 }
48
49 pub fn matching<F>(predicate: F) -> Self
51 where
52 F: Fn(&SurfaceInfo) -> bool + Send + Sync + 'static,
53 {
54 Self::Filter(Arc::new(predicate))
55 }
56
57 pub fn on(self, output: Output) -> Selector {
59 Selector {
60 surface: self,
61 output,
62 }
63 }
64
65 #[must_use]
67 pub fn except(self, other: impl Into<Surface>) -> Self {
68 Self::Not(Box::new(other.into()))
69 }
70
71 #[must_use]
73 pub fn or(self, other: impl Into<Surface>) -> Self {
74 match self {
75 Self::Or(mut selectors) => {
76 selectors.push(other.into());
77 Self::Or(selectors)
78 }
79 _ => Self::Or(vec![self, other.into()]),
80 }
81 }
82
83 pub(crate) fn matches(&self, info: &SurfaceInfo) -> bool {
84 match self {
85 Self::All => true,
86 Self::Named(name) => &info.name == name,
87 Self::Any(names) => names.iter().any(|name| name == &info.name),
88 Self::Filter(predicate) => predicate(info),
89 Self::Not(selector) => !selector.matches(info),
90 Self::Or(selectors) => selectors.iter().any(|s| s.matches(info)),
91 }
92 }
93}
94
95impl Debug for Surface {
96 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
97 match self {
98 Self::All => write!(f, "Surface::All"),
99 Self::Named(name) => write!(f, "Surface::Named({:?})", name),
100 Self::Any(names) => write!(f, "Surface::Any({:?})", names),
101 Self::Filter(_) => write!(f, "Surface::Filter(<fn>)"),
102 Self::Not(selector) => write!(f, "Surface::Not({:?})", selector),
103 Self::Or(selectors) => write!(f, "Surface::Or({:?})", selectors),
104 }
105 }
106}
107
108#[derive(Clone)]
110pub enum Output {
111 All,
113 Primary,
115 Active,
117 Handle(OutputHandle),
119 Named(String),
121 Filter(Arc<dyn Fn(&OutputInfo) -> bool + Send + Sync>),
123 Not(Box<Output>),
125 Or(Vec<Output>),
127}
128
129impl Output {
130 pub fn all() -> Self {
132 Self::All
133 }
134
135 pub fn primary() -> Self {
137 Self::Primary
138 }
139
140 pub fn active() -> Self {
142 Self::Active
143 }
144
145 pub fn handle(handle: OutputHandle) -> Self {
147 Self::Handle(handle)
148 }
149
150 pub fn named(name: impl Into<String>) -> Self {
152 Self::Named(name.into())
153 }
154
155 pub fn matching<F>(predicate: F) -> Self
157 where
158 F: Fn(&OutputInfo) -> bool + Send + Sync + 'static,
159 {
160 Self::Filter(Arc::new(predicate))
161 }
162
163 #[must_use]
165 pub fn except(self, other: impl Into<Output>) -> Self {
166 Self::Not(Box::new(other.into()))
167 }
168
169 #[must_use]
171 pub fn or(self, other: impl Into<Output>) -> Self {
172 match self {
173 Self::Or(mut selectors) => {
174 selectors.push(other.into());
175 Self::Or(selectors)
176 }
177 _ => Self::Or(vec![self, other.into()]),
178 }
179 }
180
181 pub(crate) fn matches(
182 &self,
183 handle: OutputHandle,
184 info: Option<&OutputInfo>,
185 primary: Option<OutputHandle>,
186 active: Option<OutputHandle>,
187 ) -> bool {
188 match self {
189 Self::All => true,
190 Self::Primary => primary == Some(handle),
191 Self::Active => active == Some(handle),
192 Self::Handle(h) => *h == handle,
193 Self::Named(name) => info.is_some_and(|i| i.name() == Some(name.as_str())),
194 Self::Filter(predicate) => info.is_some_and(|i| predicate(i)),
195 Self::Not(selector) => !selector.matches(handle, info, primary, active),
196 Self::Or(selectors) => selectors
197 .iter()
198 .any(|s| s.matches(handle, info, primary, active)),
199 }
200 }
201}
202
203impl Debug for Output {
204 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
205 match self {
206 Self::All => write!(f, "Output::All"),
207 Self::Primary => write!(f, "Output::Primary"),
208 Self::Active => write!(f, "Output::Active"),
209 Self::Handle(h) => write!(f, "Output::Handle({:?})", h),
210 Self::Named(name) => write!(f, "Output::Named({:?})", name),
211 Self::Filter(_) => write!(f, "Output::Filter(<fn>)"),
212 Self::Not(selector) => write!(f, "Output::Not({:?})", selector),
213 Self::Or(selectors) => write!(f, "Output::Or({:?})", selectors),
214 }
215 }
216}
217
218#[derive(Clone, Debug)]
222pub struct Selector {
223 pub surface: Surface,
224 pub output: Output,
225}
226
227impl Selector {
228 pub fn all() -> Self {
230 Self {
231 surface: Surface::All,
232 output: Output::All,
233 }
234 }
235
236 pub(crate) fn matches(
237 &self,
238 surface_info: &SurfaceInfo,
239 output_info: Option<&OutputInfo>,
240 primary: Option<OutputHandle>,
241 active: Option<OutputHandle>,
242 ) -> bool {
243 self.surface.matches(surface_info)
244 && self
245 .output
246 .matches(surface_info.output, output_info, primary, active)
247 }
248}
249
250impl From<Surface> for Selector {
251 fn from(surface: Surface) -> Self {
252 Self {
253 surface,
254 output: Output::All,
255 }
256 }
257}
258
259impl From<Output> for Selector {
260 fn from(output: Output) -> Self {
261 Self {
262 surface: Surface::All,
263 output,
264 }
265 }
266}