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::{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> Dispatch<wp_presentation::WpPresentation, GlobalData, D> for PresentationTimeState
88where
89 D: Dispatch<wp_presentation::WpPresentation, GlobalData> + PresentationTimeHandler,
90{
91 fn event(
92 data: &mut D,
93 _presentation: &wp_presentation::WpPresentation,
94 event: wp_presentation::Event,
95 _: &GlobalData,
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> Dispatch<wp_presentation_feedback::WpPresentationFeedback, PresentationTimeData, D>
109 for PresentationTimeState
110where
111 D: Dispatch<wp_presentation_feedback::WpPresentationFeedback, PresentationTimeData>
112 + PresentationTimeHandler,
113{
114 fn event(
115 data: &mut D,
116 feedback: &wp_presentation_feedback::WpPresentationFeedback,
117 event: wp_presentation_feedback::Event,
118 udata: &PresentationTimeData,
119 conn: &Connection,
120 qh: &QueueHandle<D>,
121 ) {
122 match event {
123 wp_presentation_feedback::Event::SyncOutput { output } => {
124 udata.sync_outputs.lock().unwrap().push(output);
125 }
126 wp_presentation_feedback::Event::Presented {
127 tv_sec_hi,
128 tv_sec_lo,
129 tv_nsec,
130 refresh,
131 seq_hi,
132 seq_lo,
133 flags,
134 } => {
135 let sync_outputs = mem::take(&mut *udata.sync_outputs.lock().unwrap());
136 let clk_id = data.presentation_time_state().clk_id.unwrap(); let time = PresentTime {
138 clk_id,
139 tv_sec: ((tv_sec_hi as u64) << 32) | (tv_sec_lo as u64),
140 tv_nsec,
141 };
142 let seq = ((seq_hi as u64) << 32) | (seq_lo as u64);
143 data.presented(
144 conn,
145 qh,
146 feedback,
147 &udata.wl_surface,
148 sync_outputs,
149 time,
150 refresh,
151 seq,
152 flags,
153 );
154 }
155 wp_presentation_feedback::Event::Discarded => {
156 data.discarded(conn, qh, feedback, &udata.wl_surface)
157 }
158 _ => {}
159 }
160 }
161}
162
163#[macro_export]
164macro_rules! delegate_presentation_time {
165 ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
166 $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
167 $crate::reexports::protocols::wp::presentation_time::client::wp_presentation::WpPresentation: $crate::globals::GlobalData
168 ] => $crate::presentation_time::PresentationTimeState);
169 $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
170 $crate::reexports::protocols::wp::presentation_time::client::wp_presentation_feedback::WpPresentationFeedback: $crate::presentation_time::PresentationTimeData
171 ] => $crate::presentation_time::PresentationTimeState);
172 };
173}