diff --git a/anvil/src/shell.rs b/anvil/src/shell.rs index f74bc7c..a56657c 100644 --- a/anvil/src/shell.rs +++ b/anvil/src/shell.rs @@ -677,7 +677,7 @@ pub struct CommitedState { pub buffer: Option, pub input_region: Option, pub dimensions: Option<(i32, i32)>, - pub frame_callback: Option, + pub frame_callbacks: Vec, pub sub_location: (i32, i32), } @@ -734,12 +734,6 @@ impl SurfaceData { buffer.release(); } } - // ping the previous callback if relevant - if into.frame_callback != next.frame_callback { - if let Some(callback) = into.frame_callback.take() { - callback.done(0); - } - } *into = next; new_buffer @@ -784,7 +778,7 @@ impl SurfaceData { /// Send the frame callback if it had been requested pub fn send_frame(&mut self, time: u32) { - if let Some(callback) = self.current_state.frame_callback.take() { + for callback in self.current_state.frame_callbacks.drain(..) { callback.done(time); } } @@ -863,12 +857,10 @@ fn surface_commit( None => {} } - if let Some(frame_cb) = attributes.frame_callback.take() { - if let Some(old_cb) = next_state.frame_callback.take() { - old_cb.done(0); - } - next_state.frame_callback = Some(frame_cb); - } + // Append the current frame callbacks to the next state + next_state + .frame_callbacks + .extend(attributes.frame_callbacks.drain(..)); data.apply_cache(next_state); diff --git a/src/wayland/compositor/handlers.rs b/src/wayland/compositor/handlers.rs index df5064d..292d03d 100644 --- a/src/wayland/compositor/handlers.rs +++ b/src/wayland/compositor/handlers.rs @@ -83,7 +83,7 @@ where } wl_surface::Request::Frame { callback } => { SurfaceData::::with_data(&surface, move |d| { - d.frame_callback = Some((*callback).clone()); + d.frame_callbacks.push((*callback).clone()); }); } wl_surface::Request::SetOpaqueRegion { region } => { diff --git a/src/wayland/compositor/mod.rs b/src/wayland/compositor/mod.rs index 4f9b61b..70175b3 100644 --- a/src/wayland/compositor/mod.rs +++ b/src/wayland/compositor/mod.rs @@ -156,14 +156,22 @@ pub struct SurfaceAttributes { /// Hint provided by the client to suggest that only this part /// of the surface was changed and needs to be redrawn pub damage: Vec, - /// The frame callback associated with this surface for the commit + /// The frame callbacks associated with this surface for the commit /// - /// The be triggered to notify the client about when it would be a - /// good time to start drawing its next frame. + /// The server must send the notifications so that a client + /// will not send excessive updates, while still allowing + /// the highest possible update rate for clients that wait for the reply + /// before drawing again. The server should give some time for the client + /// to draw and commit after sending the frame callback events to let it + /// hit the next output refresh. + /// + /// A server should avoid signaling the frame callbacks if the + /// surface is not visible in any way, e.g. the surface is off-screen, + /// or completely obscured by other opaque surfaces. /// /// An example possibility would be to trigger it once the frame /// associated with this commit has been displayed on the screen. - pub frame_callback: Option, + pub frame_callbacks: Vec, /// User-controlled data /// /// This is your field to host whatever you need. @@ -180,7 +188,7 @@ impl fmt::Debug for SurfaceAttributes { .field("opaque_region", &self.opaque_region) .field("input_region", &self.input_region) .field("damage", &self.damage) - .field("frame_callback", &self.frame_callback) + .field("frame_callbacks", &self.frame_callbacks) .field("user_data", &"...") .finish() } @@ -195,7 +203,7 @@ impl Default for SurfaceAttributes { opaque_region: None, input_region: None, damage: Vec::new(), - frame_callback: None, + frame_callbacks: Vec::new(), user_data: UserDataMap::new(), } }