util/signal: Introduce wlr_signal_emit_final

wlr_signal_emit_final is conceptually similar to wl_signal_emit_mutable
(i.e., our old wlr_signal_emit_safe), but instead of running all
listeners that were added at the time the signal emit started, we run
until the list is empty, removing entries as we go along.

This ensures that newly added signals are run all the same.
This commit is contained in:
Kenny Levinsen 2025-05-06 00:30:24 +02:00
parent 156d47c866
commit b222fe2a4a
4 changed files with 29 additions and 1 deletions

View file

@ -10,6 +10,7 @@ wlr_files += files(
'region.c',
'set.c',
'shm.c',
'signal.c',
'time.c',
'token.c',
'transform.c',

18
util/signal.c Normal file
View file

@ -0,0 +1,18 @@
#include "util/signal.h"
void wlr_signal_emit_final(struct wl_signal *signal, void *data) {
// We need to run all listeners one final time. To support all types of list mutations and to
// ensure that all listeners including those added during this execution is run, we run until
// the list is empty, removing listeners just before we run them. To not affect the behavior of
// the listener, we re-initialize the listener's link element.
while (signal->listener_list.next != &signal->listener_list) {
struct wl_list *pos = signal->listener_list.next;
struct wl_listener *l = wl_container_of(pos, l, link);
wl_list_remove(pos);
wl_list_init(pos);
l->notify(l, data);
}
}