1use crate::platform::Wake;
3use crate::state::Session;
4use crate::*;
5use std::collections::VecDeque;
6use std::os::fd::{AsRawFd, RawFd};
7use std::sync::atomic::{AtomicBool, Ordering};
8use std::sync::mpsc::{self, Receiver, SyncSender, TryRecvError, TrySendError};
9use std::sync::{Arc, Mutex, MutexGuard};
10use std::thread::{self, JoinHandle};
11
12const EVENT_CAPACITY: usize = 64;
13#[derive(Default)]
14struct Mailbox {
15 events: VecDeque<Event>,
16 failure: Option<(io::ErrorKind, String)>,
17}
18impl Mailbox {
19 fn push(&mut self, event: Event) -> io::Result<()> {
20 if let (
21 Some(Event::Input(Input {
22 frame_serial: previous_frame,
23 event: InputEvent::RelativeMotion { dx, dy, time_usec },
24 })),
25 Event::Input(Input {
26 frame_serial,
27 event:
28 InputEvent::RelativeMotion {
29 dx: next_dx,
30 dy: next_dy,
31 time_usec: next_time,
32 },
33 }),
34 ) = (self.events.back_mut(), &event)
35 {
36 if previous_frame == frame_serial {
37 if let (Some(x), Some(y)) = (dx.checked_add(*next_dx), dy.checked_add(*next_dy)) {
38 *dx = x;
39 *dy = y;
40 *time_usec = *next_time;
41 return Ok(());
42 }
43 }
45 }
46 let incoming_motion = coalescible_motion(&event);
47 if self.events.len() == EVENT_CAPACITY {
48 if let Some(key) = incoming_motion {
49 if self.events.back().and_then(coalescible_motion) == Some(key) {
50 *self.events.back_mut().expect("nonempty mailbox") = event;
51 }
52 return Ok(());
54 }
55 if let Some(index) = self
56 .events
57 .iter()
58 .position(|event| coalescible_motion(event).is_some())
59 {
60 self.events.remove(index);
61 } else {
62 return Err(invalid("native window essential event queue is full"));
63 }
64 }
65 self.events.push_back(event);
66 Ok(())
67 }
68 fn fail(&mut self, error: io::Error) {
69 if self.failure.is_none() {
70 self.failure = Some((error.kind(), error.to_string().chars().take(160).collect()));
71 }
72 }
73}
74fn coalescible_motion(event: &Event) -> Option<(u64, Option<i32>)> {
75 let Event::Input(Input {
76 frame_serial,
77 event,
78 }) = event
79 else {
80 return None;
81 };
82 match event {
83 InputEvent::Motion { .. } => Some((*frame_serial, None)),
84 InputEvent::Touch {
85 id,
86 phase: TouchPhase::Motion,
87 ..
88 } => Some((*frame_serial, Some(*id))),
89 _ => None,
90 }
91}
92
93#[derive(Default)]
94struct Shared {
95 mailbox: Mutex<Mailbox>,
96 stop: AtomicBool,
97 exited: AtomicBool,
98}
99impl Shared {
100 fn mailbox(&self) -> MutexGuard<'_, Mailbox> {
101 self.mailbox.lock().unwrap_or_else(|e| e.into_inner())
102 }
103}
104struct ExitNotice {
105 shared: Arc<Shared>,
106 wake: Arc<Wake>,
107}
108impl Drop for ExitNotice {
109 fn drop(&mut self) {
110 self.shared.exited.store(true, Ordering::Release);
111 let _ = self.wake.signal();
112 }
113}
114
115enum Command {
116 Frame(Frame),
117 Confinement(PointerConfinementRequest),
118}
119
120pub struct WorkerWindow {
124 shared: Arc<Shared>,
125 frames: SyncSender<Command>,
126 owner_wake: Arc<Wake>,
127 worker_wake: Arc<Wake>,
128 worker: Option<JoinHandle<()>>,
129 state: Session,
130 failed: bool,
131 options: ClientOptions,
132}
133impl WorkerWindow {
134 pub fn connect(path: &Path, create: Create) -> io::Result<Self> {
135 Self::connect_with_options(path, create, ClientOptions::default())
136 }
137 pub fn connect_with_options(
139 path: &Path,
140 create: Create,
141 options: ClientOptions,
142 ) -> io::Result<Self> {
143 create.validate()?;
144 if !path.is_absolute() {
145 return Err(invalid("native window endpoint must be absolute"));
146 }
147 let shared = Arc::new(Shared::default());
148 let owner_wake = Arc::new(Wake::new()?);
149 let worker_wake = Arc::new(Wake::new()?);
150 let (frames, receiver) = mpsc::sync_channel(1);
151 let thread_shared = Arc::clone(&shared);
152 let thread_owner = Arc::clone(&owner_wake);
153 let thread_wake = Arc::clone(&worker_wake);
154 let path = path.to_owned();
155 let worker = thread::Builder::new()
156 .name("aen-window-client".into())
157 .spawn(move || {
158 let _exit = ExitNotice {
159 shared: Arc::clone(&thread_shared),
160 wake: Arc::clone(&thread_owner),
161 };
162 let result =
163 Client::connect_with_options(&path, create, options).and_then(|client| {
164 run(
165 client,
166 receiver,
167 &thread_shared,
168 &thread_owner,
169 &thread_wake,
170 )
171 });
172 if let Err(error) = result {
173 thread_shared.mailbox().fail(error);
174 }
175 })?;
176 Ok(Self {
177 shared,
178 frames,
179 owner_wake,
180 worker_wake,
181 worker: Some(worker),
182 state: Session::default(),
183 failed: false,
184 options,
185 })
186 }
187 pub fn relative_pointer_enabled(&self) -> bool {
189 !self.failed
190 && !self.shared.exited.load(Ordering::Acquire)
191 && self.options.relative_pointer
192 && self.state.configuration().is_some()
193 }
194 pub fn pointer_confinement_enabled(&self) -> bool {
195 !self.failed
196 && !self.shared.exited.load(Ordering::Acquire)
197 && self.options.pointer_confinement
198 && self.state.configuration().is_some()
199 }
200 pub fn pointer_confined(&self) -> bool {
201 !self.failed
202 && !self.shared.exited.load(Ordering::Acquire)
203 && self.state.confinement_active.is_some()
204 }
205 pub fn request_pointer_confinement(&mut self, confined: bool) -> io::Result<u64> {
208 if !self.pointer_confinement_enabled() {
209 return Err(invalid("native pointer confinement was not negotiated"));
210 }
211 let request = self.state.next_confinement_request(confined)?;
212 match self.frames.try_send(Command::Confinement(request)) {
213 Ok(()) => {
214 self.state.request_confinement(request)?;
215 self.worker_wake.signal()?;
216 Ok(request.request_serial)
217 }
218 Err(TrySendError::Full(_)) => Err(io::ErrorKind::WouldBlock.into()),
219 Err(TrySendError::Disconnected(_)) => Err(io::ErrorKind::BrokenPipe.into()),
220 }
221 }
222 pub fn configuration(&self) -> Option<Configure> {
223 self.state.configuration()
224 }
225 pub fn window_id(&self) -> Option<u64> {
226 self.configuration().map(|c| c.window_id)
227 }
228 pub fn can_submit(&self) -> bool {
229 !self.failed
230 && !self.shared.exited.load(Ordering::Acquire)
231 && self.configuration().is_some()
232 && !self.state.credit_occupied()
233 }
234 pub fn wants_write(&self) -> bool {
235 false
236 }
237 pub fn submit(&mut self, frame: Frame) -> io::Result<()> {
238 if self.failed || self.shared.exited.load(Ordering::Acquire) {
239 return Err(io::ErrorKind::BrokenPipe.into());
240 }
241 self.state.validate_submit(&frame)?;
242 match self.frames.try_send(Command::Frame(frame.clone())) {
243 Ok(()) => {
244 self.state.submit(&frame)?;
245 self.worker_wake.signal()
246 }
247 Err(TrySendError::Full(_)) => Err(io::ErrorKind::WouldBlock.into()),
248 Err(TrySendError::Disconnected(_)) => Err(io::ErrorKind::BrokenPipe.into()),
249 }
250 }
251 pub fn poll(&mut self) -> io::Result<Vec<Event>> {
252 if self.failed {
253 return Err(io::ErrorKind::BrokenPipe.into());
254 }
255 self.owner_wake.drain()?;
256 let events = {
257 let mut mailbox = self.shared.mailbox();
258 if let Some((kind, message)) = mailbox.failure.take() {
259 self.failed = true;
260 self.shared.stop.store(true, Ordering::Release);
261 let _ = self.worker_wake.signal();
262 return Err(io::Error::new(kind, message));
263 }
264 if self.shared.exited.load(Ordering::Acquire) {
265 self.failed = true;
266 return Err(io::ErrorKind::BrokenPipe.into());
267 }
268 mailbox.events.drain(..).collect::<Vec<_>>()
269 };
270 for event in &events {
271 if let Err(error) = receive(&mut self.state, event.clone()) {
272 self.failed = true;
273 self.shared.stop.store(true, Ordering::Release);
274 let _ = self.worker_wake.signal();
275 return Err(error);
276 }
277 }
278 Ok(events)
279 }
280}
281fn receive(state: &mut Session, event: Event) -> io::Result<()> {
282 match event {
283 Event::Configured(c) => state.configure(c),
284 Event::FrameAccepted {
285 frame_serial,
286 configure_serial,
287 } => state.acknowledge(frame_serial, configure_serial, true),
288 Event::FrameDiscarded {
289 frame_serial,
290 configure_serial,
291 } => state.acknowledge(frame_serial, configure_serial, false),
292 Event::Input(input) => state.input(input),
293 Event::CloseRequested => Ok(()),
294 }
295}
296impl AsRawFd for WorkerWindow {
297 fn as_raw_fd(&self) -> RawFd {
298 self.owner_wake.as_raw_fd()
299 }
300}
301impl Drop for WorkerWindow {
302 fn drop(&mut self) {
303 self.shared.stop.store(true, Ordering::Release);
304 let _ = self.worker_wake.signal();
305 if let Some(worker) = self.worker.take() {
306 let _ = worker.join();
307 }
308 }
309}
310fn run(
311 mut client: Client,
312 frames: Receiver<Command>,
313 shared: &Shared,
314 owner: &Wake,
315 wake: &Wake,
316) -> io::Result<()> {
317 while !shared.stop.load(Ordering::Acquire) {
318 for event in client.poll()? {
319 shared.mailbox().push(event)?;
320 owner.signal()?;
321 }
322 match frames.try_recv() {
323 Ok(Command::Frame(frame)) => client.submit(frame)?,
324 Ok(Command::Confinement(request)) => {
325 let serial = client.request_pointer_confinement(request.confined)?;
326 if serial != request.request_serial {
327 return Err(invalid("native pointer worker request mismatch"));
328 }
329 }
330 Err(TryRecvError::Empty) => {}
331 Err(TryRecvError::Disconnected) => break,
332 }
333 crate::platform::wait(client.as_raw_fd(), wake.as_raw_fd(), client.wants_write())?;
334 wake.drain()?;
335 }
336 Ok(())
337}
338
339#[cfg(test)]
340mod tests {
341 use super::*;
342 fn configure() -> Configure {
343 Configure {
344 window_id: 1,
345 configure_serial: 1,
346 width: 1,
347 height: 1,
348 scale: 1,
349 }
350 }
351 fn frame(serial: u64) -> Frame {
352 Frame {
353 frame_serial: serial,
354 configure_serial: 1,
355 width: 1,
356 height: 1,
357 pixels: vec![0; 4].into(),
358 }
359 }
360 #[test]
361 fn owner_credit_waits_until_application_drains_exact_ack() {
362 let mut owner = Session::default();
363 receive(&mut owner, Event::Configured(configure())).unwrap();
364 owner.submit(&frame(1)).unwrap();
365 let mut mailbox = Mailbox::default();
366 mailbox
367 .push(Event::FrameAccepted {
368 frame_serial: 1,
369 configure_serial: 1,
370 })
371 .unwrap();
372 assert!(owner.validate_submit(&frame(2)).is_err());
373 receive(&mut owner, mailbox.events.pop_front().unwrap()).unwrap();
374 owner.validate_submit(&frame(2)).unwrap();
375 assert!(receive(
376 &mut owner,
377 Event::FrameAccepted {
378 frame_serial: 1,
379 configure_serial: 1
380 }
381 )
382 .is_err());
383 }
384 #[test]
385 fn bounded_mailbox_never_drops_essential_input_or_crosses_motion_fences() {
386 let mut mailbox = Mailbox::default();
387 for _ in 0..EVENT_CAPACITY - 1 {
388 mailbox.push(Event::CloseRequested).unwrap();
389 }
390 let motion = |serial, x| {
391 Event::Input(Input {
392 frame_serial: serial,
393 event: InputEvent::Motion { x, y: 0 },
394 })
395 };
396 mailbox.push(motion(1, 1)).unwrap();
397 mailbox.push(motion(2, 2)).unwrap();
398 assert_eq!(mailbox.events.back(), Some(&motion(1, 1)));
399 mailbox.push(motion(1, 3)).unwrap();
400 assert_eq!(mailbox.events.back(), Some(&motion(1, 3)));
401 mailbox.push(Event::CloseRequested).unwrap();
402 assert_eq!(mailbox.events.len(), EVENT_CAPACITY);
403 assert!(mailbox.push(Event::CloseRequested).is_err());
404
405 let touch_motion = |id, x| {
406 Event::Input(Input {
407 frame_serial: 9,
408 event: InputEvent::Touch {
409 id,
410 phase: TouchPhase::Motion,
411 x,
412 y: 0,
413 },
414 })
415 };
416 let mut mailbox = Mailbox::default();
417 for _ in 0..EVENT_CAPACITY - 1 {
418 mailbox.push(Event::CloseRequested).unwrap();
419 }
420 mailbox.push(touch_motion(4, 1)).unwrap();
421 mailbox.push(touch_motion(4, 2)).unwrap();
422 assert_eq!(mailbox.events.back(), Some(&touch_motion(4, 2)));
423 mailbox.push(touch_motion(5, 3)).unwrap();
424 assert_eq!(mailbox.events.len(), EVENT_CAPACITY);
425 assert_eq!(mailbox.events.back(), Some(&touch_motion(4, 2)));
426 mailbox.push(touch_motion(4, 5)).unwrap();
427 assert_eq!(mailbox.events.back(), Some(&touch_motion(4, 5)));
428
429 let mut essential = Mailbox::default();
430 for _ in 0..EVENT_CAPACITY - 1 {
431 essential.push(Event::CloseRequested).unwrap();
432 }
433 essential.push(touch_motion(8, 4)).unwrap();
434 essential.push(Event::CloseRequested).unwrap();
435 assert_eq!(essential.events.len(), EVENT_CAPACITY);
436 assert!(!essential
437 .events
438 .iter()
439 .any(|event| coalescible_motion(event).is_some()));
440 assert!(essential
441 .push(Event::Input(Input {
442 frame_serial: 9,
443 event: InputEvent::Touch {
444 id: 8,
445 phase: TouchPhase::Down,
446 x: 4,
447 y: 0,
448 },
449 }))
450 .is_err());
451 }
452 #[test]
453 fn one_queued_frame_has_no_implicit_replacement_or_replay() {
454 let (sender, receiver) = mpsc::sync_channel(1);
455 sender.try_send(frame(1)).unwrap();
456 assert!(matches!(
457 sender.try_send(frame(2)),
458 Err(TrySendError::Full(_))
459 ));
460 assert_eq!(receiver.try_recv().unwrap().frame_serial, 1);
461 assert!(receiver.try_recv().is_err());
462 }
463 #[test]
464 fn error_text_is_bounded_and_first_failure_retained() {
465 let mut mailbox = Mailbox::default();
466 mailbox.fail(io::Error::new(io::ErrorKind::TimedOut, "x".repeat(4000)));
467 mailbox.fail(io::ErrorKind::BrokenPipe.into());
468 let (kind, message) = mailbox.failure.unwrap();
469 assert_eq!(kind, io::ErrorKind::TimedOut);
470 assert_eq!(message.len(), 160);
471 }
472}
473
474#[cfg(test)]
475mod relative_tests {
476 use super::*;
477 fn delta(frame: u64, dx: i32, dy: i32, time_usec: u64) -> Event {
478 Event::Input(Input {
479 frame_serial: frame,
480 event: InputEvent::RelativeMotion { dx, dy, time_usec },
481 })
482 }
483 #[test]
484 fn relative_mailbox_preserves_total_motion_and_frame_lifecycle_fences() {
485 let mut mailbox = Mailbox::default();
486 mailbox.push(delta(1, 20, -5, 1)).unwrap();
487 mailbox.push(delta(1, -3, 2, 2)).unwrap();
488 assert_eq!(mailbox.events.pop_front(), Some(delta(1, 17, -3, 2)));
489 mailbox.push(delta(1, 1, 2, 3)).unwrap();
490 mailbox
491 .push(Event::Input(Input {
492 frame_serial: 1,
493 event: InputEvent::Leave,
494 }))
495 .unwrap();
496 mailbox.push(delta(1, 3, 4, 4)).unwrap();
497 mailbox.push(delta(2, 5, 6, 5)).unwrap();
498 assert_eq!(mailbox.events.len(), 4);
499 assert_eq!(mailbox.events[0], delta(1, 1, 2, 3));
500 assert_eq!(mailbox.events[2], delta(1, 3, 4, 4));
501 assert_eq!(mailbox.events[3], delta(2, 5, 6, 5));
502 }
503 #[test]
504 fn relative_mailbox_overflow_is_essential_and_never_wraps_or_discards_deltas() {
505 let mut mailbox = Mailbox::default();
506 mailbox.push(delta(1, i32::MAX, i32::MIN, 1)).unwrap();
507 mailbox.push(delta(1, 1, -1, 2)).unwrap();
508 assert_eq!(mailbox.events.len(), 2);
509 assert_eq!(mailbox.events[0], delta(1, i32::MAX, i32::MIN, 1));
510 assert_eq!(mailbox.events[1], delta(1, 1, -1, 2));
511 for _ in mailbox.events.len()..EVENT_CAPACITY {
512 mailbox.push(Event::CloseRequested).unwrap();
513 }
514 assert!(mailbox.push(delta(1, 1, 1, 3)).is_err());
515 assert!(mailbox.push(Event::CloseRequested).is_err());
516 assert_eq!(mailbox.events[0], delta(1, i32::MAX, i32::MIN, 1));
517 assert_eq!(mailbox.events[1], delta(1, 1, -1, 2));
518 }
519}