Add wl_fixes.ack_global_remove()

The wl_global_remove() function was introduce to help mitigate clients
getting unintentionally disconnected if a global is added and removed in
a short burst.

The intended usage was:

 - the compositor calls wl_global_remove()
 - after a certain period of time, the compositor calls
   wl_global_destroy()

Unfortunately, it did not fully fix the issue due to the way monotonic
clock works on Linux. Specifically, it can tick even during sleep.

This change adds a slightly better way to handle global removal. With
the proposed changes, the clients need to signal to the compositor that
they won't bind the global anymore.

After all clients have acknowledged a wl_registry.global_remove, the
compositor can finally destroy the global.

Signed-off-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
This commit is contained in:
Vlad Zahorodnii 2026-03-13 17:35:27 +02:00
parent bec2bcddd8
commit 268e8373ae
6 changed files with 521 additions and 50 deletions

View file

@ -491,14 +491,15 @@ registry_handle_globals(void *data, struct wl_registry *registry,
{
struct client *c = data;
if (strcmp(intf, "test") != 0)
return;
if (strcmp(intf, "test") == 0) {
c->tc = wl_registry_bind(registry, id, &test_compositor_interface, ver);
assert(c->tc && "Failed binding to registry");
c->tc = wl_registry_bind(registry, id, &test_compositor_interface, ver);
assert(c->tc && "Failed binding to registry");
wl_proxy_add_listener((struct wl_proxy *) c->tc,
(void *) &tc_listener, c);
wl_proxy_add_listener((struct wl_proxy *) c->tc,
(void *) &tc_listener, c);
} else if (strcmp(intf, wl_fixes_interface.name) == 0) {
c->wl_fixes = wl_registry_bind(registry, id, &wl_fixes_interface, 2);
}
}
static const struct wl_registry_listener registry_listener =
@ -524,6 +525,9 @@ struct client *client_connect(void)
wl_display_roundtrip(c->wl_display);
assert(c->tc);
if (c->wl_fixes) {
wl_fixes_destroy_registry(c->wl_fixes, reg);
}
wl_registry_destroy(reg);
return c;
@ -556,6 +560,10 @@ client_disconnect(struct client *c)
/* check for errors */
check_error(c->wl_display);
if (c->wl_fixes) {
wl_fixes_destroy(c->wl_fixes);
}
wl_proxy_destroy((struct wl_proxy *) c->tc);
wl_display_disconnect(c->wl_display);
free(c);