diff --git a/shared/meson.build b/shared/meson.build index 8073dcdb..9a4af530 100644 --- a/shared/meson.build +++ b/shared/meson.build @@ -1,11 +1,12 @@ srcs_libshared = [ 'config-parser.c', 'option-parser.c', + 'signal.c', 'file-util.c', 'os-compatibility.c', 'xalloc.c', ] -deps_libshared = dep_wayland_client +deps_libshared = [dep_wayland_client, dep_wayland_server] lib_libshared = static_library( 'shared', diff --git a/shared/signal.c b/shared/signal.c new file mode 100644 index 00000000..68870f0a --- /dev/null +++ b/shared/signal.c @@ -0,0 +1,67 @@ +/* + * Copyright 2018 Simon Ser + * Copyright 2021 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* Implementation copied from wlroots util/signal.c file */ + +#include "signal.h" + +static void +handle_noop(struct wl_listener *listener, void *data) +{ + /* Do nothing */ +} + +void +weston_signal_emit_mutable(struct wl_signal *signal, void *data) +{ + struct wl_listener cursor; + struct wl_listener end; + + /* Add two special markers: one cursor and one end marker. This way, we + * know that we've already called listeners on the left of the cursor + * and that we don't want to call listeners on the right of the end + * marker. The 'it' function can remove any element it wants from the + * list without troubles. + * + * There was a previous attempt that used to steal the whole list of + * listeners but then that broke wl_signal_get(). + * + * wl_list_for_each_safe tries to be safe but it fails: it works fine + * if the current item is removed, but not if the next one is. */ + wl_list_insert(&signal->listener_list, &cursor.link); + cursor.notify = handle_noop; + wl_list_insert(signal->listener_list.prev, &end.link); + end.notify = handle_noop; + + while (cursor.link.next != &end.link) { + struct wl_list *pos = cursor.link.next; + struct wl_listener *l = wl_container_of(pos, l, link); + + wl_list_remove(&cursor.link); + wl_list_insert(pos, &cursor.link); + + l->notify(l, data); + } + + wl_list_remove(&cursor.link); + wl_list_remove(&end.link); +} diff --git a/shared/signal.h b/shared/signal.h new file mode 100644 index 00000000..4f96762e --- /dev/null +++ b/shared/signal.h @@ -0,0 +1,53 @@ +/* + * Copyright 2018 Simon Ser + * Copyright 2021 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef WESTON_SIGNAL_H +#define WESTON_SIGNAL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* A safer version of wl_signal_emit() which can gracefully handle additions + * and deletions of any signal listener from within listener notification + * callbacks. + * + * Listeners deleted during a signal emission and which have not already been + * notified at the time of deletion are not notified by that emission. + * + * Listeners added (or readded) during signal emission are ignored by that + * emission. + * + * Note that repurposing a listener without explicitly removing it and readding + * it is not supported and can lead to unexpected behavior. + */ + +void +weston_signal_emit_mutable(struct wl_signal *signal, void *data); + +#ifdef __cplusplus +} +#endif + +#endif /* WESTON_SIGNAL_H */