git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commit2786a1eec4947747ae3502a6d89466cb03720fbc
parentd18d72d16e
authorLucas Galante <[email protected]>
date2026-06-22 15:01
Implement Wayland frame callback throttling to resolve window flickering

 src/backend/window_runner.rs | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index 5310c1d..097422f 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -21,7 +21,7 @@ use smithay_client_toolkit::{
 };
 use wayland_client::{
     globals::{registry_queue_init, GlobalList},
-    protocol::{wl_keyboard, wl_output, wl_pointer, wl_seat, wl_surface, wl_registry, wl_region},
+    protocol::{wl_keyboard, wl_output, wl_pointer, wl_seat, wl_surface, wl_registry, wl_region, wl_callback},
     Connection, QueueHandle, Proxy,
 };
 use smithay_client_toolkit::shell::xdg::popup::{Popup, PopupHandler, PopupConfigure};
@@ -1034,6 +1034,7 @@ pub struct EngineState<A: Application> {
     
     pub exit: bool,
     pub redraw: bool,
+    pub frame_callback_pending: bool,
     pub first_configure_received: bool,
     pub ctrl_pressed: bool,
     pub shift_pressed: bool,
@@ -1279,6 +1280,11 @@ impl<A: Application> EngineState<A> {
             }
         }
         
+        if let Some(ref surface) = self.surface {
+            let _callback = surface.frame(&self.qh, ());
+            self.frame_callback_pending = true;
+        }
+
         adapter.queue.submit(std::iter::once(encoder.finish()));
         output.present();
         
@@ -1534,6 +1540,7 @@ impl<A: Application> WindowHandler for EngineState<A> {
             self.resize(w, h);
         }
         self.redraw = true;
+        self.frame_callback_pending = false;
         self.first_configure_received = true;
     }
     
@@ -1950,6 +1957,21 @@ impl<A: Application> wayland_client::Dispatch<wl_region::WlRegion, ()> for Engin
     ) {}
 }
 
+impl<A: Application> wayland_client::Dispatch<wl_callback::WlCallback, ()> for EngineState<A> {
+    fn event(
+        state: &mut Self,
+        _proxy: &wl_callback::WlCallback,
+        event: wl_callback::Event,
+        _data: &(),
+        _conn: &Connection,
+        _qh: &QueueHandle<Self>,
+    ) {
+        if let wl_callback::Event::Done { .. } = event {
+            state.frame_callback_pending = false;
+        }
+    }
+}
+
 pub fn run<A: Application>() {
     let conn = Connection::connect_to_env().unwrap();
     let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
@@ -1990,6 +2012,7 @@ pub fn run<A: Application>() {
         logical_height: settings.height as f32,
         exit: false,
         redraw: false,
+        frame_callback_pending: false,
         first_configure_received: false,
         ctrl_pressed: false,
         shift_pressed: false,
@@ -2210,7 +2233,7 @@ pub fn run<A: Application>() {
             }
         }
 
-        if engine_state.redraw {
+        if engine_state.redraw && !engine_state.frame_callback_pending {
             engine_state.redraw = false;
             if engine_state.first_configure_received {
                 engine_state.render();