diff --git a/include/wlr/types/wlr_xdg_system_bell_v1.h b/include/wlr/types/wlr_xdg_system_bell_v1.h new file mode 100644 index 000000000..8cb592d14 --- /dev/null +++ b/include/wlr/types/wlr_xdg_system_bell_v1.h @@ -0,0 +1,34 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_XDG_SYSTEM_BELL_V1_H +#define WLR_TYPES_WLR_XDG_SYSTEM_BELL_V1_H + +#include + +struct wlr_xdg_system_bell_v1 { + struct wl_global *global; + + struct { + struct wl_signal ring; // struct wlr_xdg_system_bell_v1_ring_event + } events; + + struct { + struct wl_listener display_destroy; + } WLR_PRIVATE; +}; + +struct wlr_xdg_system_bell_v1_ring_event { + struct wl_client *client; + struct wlr_surface *surface; // May be NULL +}; + +struct wlr_xdg_system_bell_v1 *wlr_xdg_system_bell_v1_create(struct wl_display *display, + uint32_t version); + +#endif diff --git a/protocol/meson.build b/protocol/meson.build index 3e385d4ec..f4aafaf57 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -32,6 +32,7 @@ protocols = { 'security-context-v1': wl_protocol_dir / 'staging/security-context/security-context-v1.xml', 'single-pixel-buffer-v1': wl_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', 'xdg-activation-v1': wl_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml', + 'xdg-system-bell-v1': wl_protocol_dir / 'staging/xdg-system-bell/xdg-system-bell-v1.xml', 'xwayland-shell-v1': wl_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml', 'tearing-control-v1': wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', diff --git a/types/wlr_xdg_system_bell_v1.c b/types/wlr_xdg_system_bell_v1.c new file mode 100644 index 000000000..d1ad7b002 --- /dev/null +++ b/types/wlr_xdg_system_bell_v1.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include "xdg-system-bell-v1-protocol.h" + +#define XDG_SYSTEM_BELL_V1_VERSION 1 + +static const struct xdg_system_bell_v1_interface bell_impl; + +static struct wlr_xdg_system_bell_v1 *bell_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_system_bell_v1_interface, &bell_impl)); + return wl_resource_get_user_data(resource); +} + +static void bell_handle_destroy(struct wl_client *client, struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void bell_handle_ring(struct wl_client *client, + struct wl_resource *bell_resource, struct wl_resource *surface_resource) { + struct wlr_xdg_system_bell_v1 *bell = bell_from_resource(bell_resource); + + struct wlr_surface *surface = NULL; + if (surface_resource != NULL) { + surface = wlr_surface_from_resource(surface_resource); + } + + struct wlr_xdg_system_bell_v1_ring_event event = { + .client = client, + .surface = surface, + }; + wl_signal_emit_mutable(&bell->events.ring, &event); +} + +static const struct xdg_system_bell_v1_interface bell_impl = { + .destroy = bell_handle_destroy, + .ring = bell_handle_ring, +}; + +static void bell_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + struct wl_resource *resource = wl_resource_create(client, + &xdg_system_bell_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &bell_impl, NULL, NULL); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_xdg_system_bell_v1 *bell = wl_container_of(listener, bell, display_destroy); + wl_list_remove(&bell->display_destroy.link); + wl_global_destroy(bell->global); + free(bell); +} + +struct wlr_xdg_system_bell_v1 *wlr_xdg_system_bell_v1_create(struct wl_display *display, + uint32_t version) { + assert(version <= XDG_SYSTEM_BELL_V1_VERSION); + + struct wlr_xdg_system_bell_v1 *bell = calloc(1, sizeof(*bell)); + if (bell == NULL) { + return NULL; + } + + bell->global = wl_global_create(display, &xdg_system_bell_v1_interface, + version, NULL, bell_bind); + if (bell->global == NULL) { + free(bell); + return NULL; + } + + bell->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &bell->display_destroy); + + wl_signal_init(&bell->events.ring); + + return bell; +}