1use std::{mem, sync::Mutex};
2use wayland_client::{
3 globals::GlobalList,
4 protocol::{wl_output, wl_surface},
5 Connection, Dispatch, QueueHandle, WEnum,
6};
7use wayland_protocols::wp::presentation_time::client::{wp_presentation, wp_presentation_feedback};
8
9use crate::{dispatch2::Dispatch2, error::GlobalError, globals::GlobalData, registry::GlobalProxy};
10
11#[derive(Debug)]
12pub struct PresentTime {
13 pub clk_id: u32,
14 pub tv_sec: u64,
15 pub tv_nsec: u32,
16}
17
18#[derive(Debug)]
19pub struct PresentationTimeState {
20 presentation: GlobalProxy<wp_presentation::WpPresentation>,
21 clk_id: Option<u32>,
22}
23
24impl PresentationTimeState {
25 pub fn bind<D>(globals: &GlobalList, qh: &QueueHandle<D>) -> Self
27 where
28 D: Dispatch<wp_presentation::WpPresentation, GlobalData> + 'static,
29 {
30 let presentation = GlobalProxy::from(globals.bind(qh, 1..=1, GlobalData));
31 Self { presentation, clk_id: None }
32 }
33
34 pub fn feedback<D>(
36 &self,
37 surface: &wl_surface::WlSurface,
38 qh: &QueueHandle<D>,
39 ) -> Result<wp_presentation_feedback::WpPresentationFeedback, GlobalError>
40 where
41 D: Dispatch<wp_presentation_feedback::WpPresentationFeedback, PresentationTimeData>
42 + 'static,
43 {
44 let udata = PresentationTimeData {
45 wl_surface: surface.clone(),
46 sync_outputs: Mutex::new(Vec::new()),
47 };
48 Ok(self.presentation.get()?.feedback(surface, qh, udata))
49 }
50}
51
52pub trait PresentationTimeHandler: Sized {
53 fn presentation_time_state(&mut self) -> &mut PresentationTimeState;
54
55 #[allow(clippy::too_many_arguments)]
57 fn presented(
58 &mut self,
59 conn: &Connection,
60 qh: &QueueHandle<Self>,
61 feedback: &wp_presentation_feedback::WpPresentationFeedback,
62 surface: &wl_surface::WlSurface,
63 outputs: Vec<wl_output::WlOutput>,
64 time: PresentTime,
65 refresh: u32,
66 seq: u64,
67 flags: WEnum<wp_presentation_feedback::Kind>,
68 );
69
70 fn discarded(
72 &mut self,
73 conn: &Connection,
74 qh: &QueueHandle<Self>,
75 feedback: &wp_presentation_feedback::WpPresentationFeedback,
76 surface: &wl_surface::WlSurface,
77 );
78}
79
80#[doc(hidden)]
81#[derive(Debug)]
82pub struct PresentationTimeData {
83 wl_surface: wl_surface::WlSurface,
84 sync_outputs: Mutex<Vec<wl_output::WlOutput>>,
85}
86
87impl<D> Dispatch2<wp_presentation::WpPresentation, D> for GlobalData
88where
89 D: PresentationTimeHandler,
90{
91 fn event(
92 &self,
93 data: &mut D,
94 _presentation: &wp_presentation::WpPresentation,
95 event: wp_presentation::Event,
96 _conn: &Connection,
97 _qh: &QueueHandle<D>,
98 ) {
99 match event {
100 wp_presentation::Event::ClockId { clk_id } => {
101 data.presentation_time_state().clk_id = Some(clk_id);
102 }
103 _ => unreachable!(),
104 }
105 }
106}
107
108impl<D> Dispatch2<wp_presentation_feedback::WpPresentationFeedback, D> for PresentationTimeData
109where
110 D: PresentationTimeHandler,
111{
112 fn event(
113 &self,
114 data: &mut D,
115 feedback: &wp_presentation_feedback::WpPresentationFeedback,
116 event: wp_presentation_feedback::Event,
117 conn: &Connection,
118 qh: &QueueHandle<D>,
119 ) {
120 match event {
121 wp_presentation_feedback::Event::SyncOutput { output } => {
122 self.sync_outputs.lock().unwrap().push(output);
123 }
124 wp_presentation_feedback::Event::Presented {
125 tv_sec_hi,
126 tv_sec_lo,
127 tv_nsec,
128 refresh,
129 seq_hi,
130 seq_lo,
131 flags,
132 } => {
133 let sync_outputs = mem::take(&mut *self.sync_outputs.lock().unwrap());
134 let clk_id = data.presentation_time_state().clk_id.unwrap(); let time = PresentTime {
136 clk_id,
137 tv_sec: ((tv_sec_hi as u64) << 32) | (tv_sec_lo as u64),
138 tv_nsec,
139 };
140 let seq = ((seq_hi as u64) << 32) | (seq_lo as u64);
141 data.presented(
142 conn,
143 qh,
144 feedback,
145 &self.wl_surface,
146 sync_outputs,
147 time,
148 refresh,
149 seq,
150 flags,
151 );
152 }
153 wp_presentation_feedback::Event::Discarded => {
154 data.discarded(conn, qh, feedback, &self.wl_surface)
155 }
156 _ => {}
157 }
158 }
159}