perf(toplevel_info): optimize send_toplevel_to_client

PR #1279 tried to throttle `send_toplevel_to_client`, which was rejected. This takes (what I think is) a better approach, and instead makes some optimizations. We delay grabbing the mutex until it's actually needed, and we also checks to see if the state actually needs to be resent. This resolves some lock contention, and also avoids having to generate the state in the first place. Since `wayland-rs` uses a single mutex to lock the entire state, this both massively reduces lock contention and avoids making (apparently quite a lot of) unnecessary computation.

I decided to give this one to AI since I'm a bit busy right now (although I am still manually writing the commit messages and descriptions). I think it generally did a pretty good job, although I did have to make a few manual tweaks. While I don't have any empirical data, cosmic-comp idle CPU has gone down from ~3% all-core to 0-0.5%, even stress testing it with far more windows open. I can't say it *liked* opening 30-some windows in 2 seconds, but after it finished opening them all, it was still buttery smooth. Overall very happy with the results.

Assisted-by: Claude:claude-4-opus
This commit is contained in:
Gavin John 2026-06-04 20:00:49 -07:00 committed by Victoria Brekenfeld
parent db0b1afeb5
commit d4c5714c10

View file

@ -495,35 +495,18 @@ where
.unwrap()
.lock()
.unwrap();
let foreign_toplevel_handle = state.foreign_handle.as_ref();
let mut changed = false;
if handle_state.title != window.title() {
handle_state.title = window.title();
if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE {
instance.title(handle_state.title.clone());
}
if let Some(handle) = foreign_toplevel_handle {
handle.send_title(&handle_state.title);
}
changed = true;
}
if handle_state.app_id != window.app_id() {
handle_state.app_id = window.app_id();
if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE {
instance.app_id(handle_state.app_id.clone());
}
if let Some(handle) = foreign_toplevel_handle {
handle.send_app_id(&handle_state.app_id);
}
changed = true;
}
let new_title = (handle_state.title != window.title()).then(|| window.title());
let new_app_id = (handle_state.app_id != window.app_id()).then(|| window.app_id());
if handle_state.states.as_ref().is_none_or(|states| {
let new_states = if handle_state.states.as_ref().is_none_or(|states| {
(states.contains(&States::Maximized) != window.is_maximized())
|| (states.contains(&States::Fullscreen) != window.is_fullscreen())
|| (states.contains(&States::Activated) != window.is_activated())
|| (states.contains(&States::Minimized) != window.is_minimized())
|| (instance.version() >= zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE
&& states.contains(&States::Sticky) != window.is_sticky())
}) {
let mut states = Vec::new();
if window.is_maximized() {
@ -543,8 +526,64 @@ where
{
states.push(States::Sticky);
}
handle_state.states = Some(states.clone());
Some(states)
} else {
None
};
let geometry_changed = if !window.is_resizing() {
let geometry = window.global_geometry();
if handle_state.geometry != geometry {
handle_state.geometry = geometry;
true
} else {
false
}
} else {
false
};
let outputs_changed = state.outputs != handle_state.outputs
|| handle_state.wl_outputs.iter().any(|o| !o.is_alive());
let workspaces_changed = state.workspaces != handle_state.workspaces;
if new_title.is_none()
&& new_app_id.is_none()
&& new_states.is_none()
&& !geometry_changed
&& !outputs_changed
&& !workspaces_changed
{
return false;
}
let foreign_toplevel_handle = state.foreign_handle.as_ref();
if let Some(title) = new_title {
handle_state.title = title;
if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE {
instance.title(handle_state.title.clone());
}
if let Some(handle) = foreign_toplevel_handle {
handle.send_title(&handle_state.title);
}
changed = true;
}
if let Some(app_id) = new_app_id {
handle_state.app_id = app_id;
if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE {
instance.app_id(handle_state.app_id.clone());
}
if let Some(handle) = foreign_toplevel_handle {
handle.send_app_id(&handle_state.app_id);
}
changed = true;
}
if let Some(states) = new_states {
handle_state.states = Some(states.clone());
let states = states
.iter()
.flat_map(|state| (*state as u32).to_ne_bytes())
@ -553,17 +592,9 @@ where
changed = true;
}
let mut geometry_changed = false;
if !window.is_resizing() {
let geometry = window.global_geometry();
if handle_state.geometry != geometry {
handle_state.geometry = geometry;
changed = true;
geometry_changed = true;
}
}
if let Ok(client) = dh.get_client(instance.id()) {
if (outputs_changed || geometry_changed)
&& let Ok(client) = dh.get_client(instance.id())
{
handle_state.outputs = state.outputs.clone();
let handle_state = &mut *handle_state;
@ -599,27 +630,29 @@ where
});
}
for new_workspace in state
.workspaces
.iter()
.filter(|w| !handle_state.workspaces.contains(w))
{
for handle in workspace_state.raw_ext_workspace_handles(new_workspace, &instance.id()) {
instance.ext_workspace_enter(handle);
changed = true;
if workspaces_changed {
for new_workspace in state
.workspaces
.iter()
.filter(|w| !handle_state.workspaces.contains(w))
{
for handle in workspace_state.raw_ext_workspace_handles(new_workspace, &instance.id()) {
instance.ext_workspace_enter(handle);
changed = true;
}
}
}
for old_workspace in handle_state
.workspaces
.iter()
.filter(|w| !state.workspaces.contains(w))
{
for handle in workspace_state.raw_ext_workspace_handles(old_workspace, &instance.id()) {
instance.ext_workspace_leave(handle);
changed = true;
for old_workspace in handle_state
.workspaces
.iter()
.filter(|w| !state.workspaces.contains(w))
{
for handle in workspace_state.raw_ext_workspace_handles(old_workspace, &instance.id()) {
instance.ext_workspace_leave(handle);
changed = true;
}
}
handle_state.workspaces = state.workspaces.clone();
}
handle_state.workspaces = state.workspaces.clone();
if changed {
if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE {