From 9944ac65cf060a62d2af31fd92298a4e6dfa019a Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 22 Jul 2025 22:48:19 +0200 Subject: [PATCH] xdg-shell: batch xdg_surface.configure events --- src/compositor.rs | 11 ++++- src/ifs/wl_surface/xdg_surface.rs | 40 +++++++++++++++++-- src/ifs/wl_surface/xdg_surface/xdg_popup.rs | 2 +- .../wl_surface/xdg_surface/xdg_toplevel.rs | 6 +-- src/state.rs | 3 ++ 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/compositor.rs b/src/compositor.rs index 392ee32d..a337c9c2 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -35,7 +35,10 @@ use { jay_screencast::{perform_screencast_realloc, perform_toplevel_screencasts}, wl_output::{OutputId, PersistentOutputState, WlOutputGlobal}, wl_seat::handle_position_hint_requests, - wl_surface::{NoneSurfaceExt, zwp_input_popup_surface_v2::input_popup_positioning}, + wl_surface::{ + NoneSurfaceExt, xdg_surface::handle_xdg_surface_configure_events, + zwp_input_popup_surface_v2::input_popup_positioning, + }, wlr_output_manager::wlr_output_manager_done, workspace_manager::workspace_manager_done, }, @@ -353,6 +356,7 @@ fn start_compositor2( head_managers_async: Default::default(), show_bar: Cell::new(true), enable_primary_selection: Cell::new(true), + xdg_surface_configure_events: Default::default(), }); state.tracker.register(ClientId::from_raw(0)); create_dummy_output(&state); @@ -546,6 +550,11 @@ fn start_global_event_handlers(state: &Rc) -> Vec> { Phase::Layout, handle_jay_head_manager_done(state.clone()), ), + eng.spawn2( + "xdg_surface configure events", + Phase::PostLayout, + handle_xdg_surface_configure_events(state.clone()), + ), ] } diff --git a/src/ifs/wl_surface/xdg_surface.rs b/src/ifs/wl_surface/xdg_surface.rs index f74bfebe..06ea59ef 100644 --- a/src/ifs/wl_surface/xdg_surface.rs +++ b/src/ifs/wl_surface/xdg_surface.rs @@ -18,6 +18,7 @@ use { leaks::Tracker, object::Object, rect::Rect, + state::State, tree::{ FindTreeResult, FoundNode, Node, NodeLayerLink, NodeLocation, OutputNode, StackedNode, WorkspaceNode, @@ -41,6 +42,22 @@ use { thiserror::Error, }; +pub struct XdgSurfaceConfigureEvent { + xdg: Rc, + serial: u32, +} + +pub async fn handle_xdg_surface_configure_events(state: Rc) { + loop { + let ev = state.xdg_surface_configure_events.pop().await; + ev.xdg.configure_scheduled.set(false); + if ev.xdg.destroyed.get() { + continue; + } + ev.xdg.send_configure(ev.serial); + } +} + #[expect(dead_code)] const NOT_CONSTRUCTED: u32 = 1; const ALREADY_CONSTRUCTED: u32 = 2; @@ -81,6 +98,8 @@ pub struct XdgSurface { pub workspace: CloneCell>>, pub tracker: Tracker, have_initial_commit: Cell, + configure_scheduled: Cell, + destroyed: Cell, } struct Popup { @@ -236,6 +255,8 @@ impl XdgSurface { workspace: Default::default(), tracker: Default::default(), have_initial_commit: Default::default(), + configure_scheduled: Default::default(), + destroyed: Default::default(), } } @@ -319,9 +340,19 @@ impl XdgSurface { self.geometry.get() } - pub fn do_send_configure(&self) { - let serial = self.requested_serial.fetch_add(1) + 1; - self.send_configure(serial); + pub fn schedule_configure(self: &Rc) { + if self.configure_scheduled.replace(true) { + return; + } + let serial = self.requested_serial.add_fetch(1); + self.surface + .client + .state + .xdg_surface_configure_events + .push(XdgSurfaceConfigureEvent { + xdg: self.clone(), + serial, + }); } pub fn send_configure(&self, serial: u32) { @@ -375,6 +406,7 @@ impl XdgSurfaceRequestHandler for XdgSurface { type Error = XdgSurfaceError; fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { + self.destroyed.set(true); if self.ext.is_some() { return Err(XdgSurfaceError::RoleNotYetDestroyed(self.id)); } @@ -564,7 +596,7 @@ impl SurfaceExt for XdgSurface { && let Some(ext) = self.ext.get() { ext.initial_configure()?; - self.do_send_configure(); + self.schedule_configure(); self.have_initial_commit.set(true); } if let Some(pending) = &mut pending.xdg_surface diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs index d70f8236..64808810 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs @@ -245,7 +245,7 @@ impl XdgPopupRequestHandler for XdgPopup { let rel = self.relative_position.get(); self.send_repositioned(req.token); self.send_configure(rel.x1(), rel.y1(), rel.width(), rel.height()); - self.xdg.do_send_configure(); + self.xdg.schedule_configure(); } Ok(()) } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index 11ac6f33..3056116a 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -195,7 +195,7 @@ impl XdgToplevel { let rect = self.xdg.absolute_desired_extents.get(); self.send_configure_checked(rect.width(), rect.height()); } - self.xdg.do_send_configure(); + self.xdg.schedule_configure(); } fn send_configure_checked(&self, mut width: i32, mut height: i32) { @@ -658,7 +658,7 @@ impl ToplevelNodeBase for XdgToplevel { if changed { let rect = self.xdg.absolute_desired_extents.get(); self.send_configure_checked(rect.width(), rect.height()); - self.xdg.do_send_configure(); + self.xdg.schedule_configure(); } } @@ -677,7 +677,7 @@ impl ToplevelNodeBase for XdgToplevel { let de = self.xdg.absolute_desired_extents.get(); if de.width() != nw || de.height() != nh { self.send_configure_checked(nw, nh); - self.xdg.do_send_configure(); + self.xdg.schedule_configure(); // self.xdg.surface.client.flush(); } self.xdg.set_absolute_desired_extents(rect); diff --git a/src/state.rs b/src/state.rs index 60c40c1c..a05fd28d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -64,6 +64,7 @@ use { tray::TrayItemIds, wl_subsurface::SubsurfaceIds, x_surface::xwindow::{Xwindow, XwindowId}, + xdg_surface::XdgSurfaceConfigureEvent, zwp_idle_inhibitor_v1::{IdleInhibitorId, IdleInhibitorIds, ZwpIdleInhibitorV1}, zwp_input_popup_surface_v2::ZwpInputPopupSurfaceV2, }, @@ -273,6 +274,7 @@ pub struct State { pub head_managers_async: AsyncQueue, pub show_bar: Cell, pub enable_primary_selection: Cell, + pub xdg_surface_configure_events: AsyncQueue, } // impl Drop for State { @@ -1079,6 +1081,7 @@ impl State { self.cursor_user_group_hardware_cursor.take(); self.cpu_worker.clear(); self.wait_for_sync_obj.clear(); + self.xdg_surface_configure_events.clear(); } pub fn remove_toplevel_id(&self, id: ToplevelIdentifier) {