smithay_client_toolkit/
presentation_time.rs

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    /// Bind `wp_presentation` global, if it exists
26    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    /// Request feedback for current submission to surface.
35    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    /// Content update displayed to user at indicated time
56    #[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    /// Content update not displayed
71    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(); // XXX unwrap
137                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}