diff --git a/include/wlr/types/wlr_layer_shell.h b/include/wlr/types/wlr_layer_shell.h index fbea1334..33bda351 100644 --- a/include/wlr/types/wlr_layer_shell.h +++ b/include/wlr/types/wlr_layer_shell.h @@ -1,5 +1,11 @@ #ifndef WLR_TYPES_WLR_LAYER_SHELL_H #define WLR_TYPES_WLR_LAYER_SHELL_H +#include +#include +#include +#include +#include +#include "wlr-layer-shell-unstable-v1-protocol.h" struct wlr_layer_shell { struct wl_global *wl_global; @@ -23,6 +29,50 @@ struct wlr_layer_client { struct wl_list link; // wlr_layer_shell::clients }; +struct wlr_layer_surface_state { + uint32_t anchor; + uint32_t exclusive_zone; + struct { + uint32_t top, right, bottom, left; + } margin; +}; + +struct wlr_layer_surface_configure { + struct wl_list link; // wlr_layer_surface::configure_list + uint32_t serial; + struct wlr_layer_surface_state *state; +}; + +struct wlr_layer_surface { + struct wlr_surface *surface; + struct wlr_layer_client *client; + struct wl_resource *resource; + struct wl_list link; // wlr_layer_client:surfaces + + const char *namespace; + enum zwlr_layer_shell_v1_layer layer; + + bool added, configured, mapped; + uint32_t configure_serial; + struct wl_event_source *configure_idle; + uint32_t configure_next_serial; + struct wl_list configure_list; + + struct wlr_layer_surface_state next; // client protocol requests + struct wlr_layer_surface_state pending; // our configure requests + struct wlr_layer_surface_state current; + + struct wl_listener surface_destroy_listener; + + struct { + struct wl_signal destroy; + struct wl_signal map; + struct wl_signal unmap; + } events; + + void *data; +}; + struct wlr_layer_shell *wlr_layer_shell_create(struct wl_display *display); void wlr_layer_shell_destroy(struct wlr_layer_shell *layer_shell); diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index a5cd3d54..18596462 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -79,7 +79,7 @@ struct wlr_xdg_toplevel { bool added; struct wlr_xdg_toplevel_state next; // client protocol requests - struct wlr_xdg_toplevel_state pending; // user configure requests + struct wlr_xdg_toplevel_state pending; // our configure requests struct wlr_xdg_toplevel_state current; char *title; diff --git a/types/wlr_layer_shell.c b/types/wlr_layer_shell.c index 51d50b17..120f2197 100644 --- a/types/wlr_layer_shell.c +++ b/types/wlr_layer_shell.c @@ -1,22 +1,21 @@ +#define _POSIX_C_SOURCE 200809L #include #include +#include #include #include +#include +#include +#include "util/signal.h" #include "wlr-layer-shell-unstable-v1-protocol.h" -static void layer_shell_handle_get_layer_surface(struct wl_client *client, - struct wl_resource *resource, - uint32_t id, - struct wl_resource *surface, - struct wl_resource *output, - uint32_t layer, - const char *namespace) { - // TODO +static void resource_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); } -static struct zwlr_layer_shell_v1_interface layer_shell_impl = { - .get_layer_surface = layer_shell_handle_get_layer_surface, -}; +static struct zwlr_layer_shell_v1_interface layer_shell_impl; +static struct zwlr_layer_surface_v1_interface layer_surface_impl; static struct wlr_layer_client *layer_client_from_resource( struct wl_resource *resource) { @@ -25,6 +24,181 @@ static struct wlr_layer_client *layer_client_from_resource( return wl_resource_get_user_data(resource); } +static struct wlr_layer_surface *layer_surface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zwlr_layer_surface_v1_interface, + &layer_surface_impl)); + return wl_resource_get_user_data(resource); +} + +static void layer_surface_handle_ack_configure(struct wl_client *client, + struct wl_resource *resource, uint32_t serial) { + // TODO +} + +static void layer_surface_handle_set_anchor(struct wl_client *client, + struct wl_resource *resource, uint32_t anchor) { + // TODO +} + +static void layer_surface_handle_set_exclusive_zone(struct wl_client *client, + struct wl_resource *resource, uint32_t zone) { + // TODO +} + +static void layer_surface_handle_set_margin(struct wl_client *client, + struct wl_resource *resource, int32_t top, int32_t right, + int32_t bottom, int32_t left) { + // TODO +} + +static void layer_surface_handle_get_popup(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *popup) { + // TODO +} + +static void layer_surface_handle_get_input(struct wl_client *client, + struct wl_resource *resource, uint32_t id, struct wl_resource *seat) { + // TODO +} + +static const struct zwlr_layer_surface_v1_interface layer_surface_implementation = { + .destroy = resource_handle_destroy, + .ack_configure = layer_surface_handle_ack_configure, + .set_anchor = layer_surface_handle_set_anchor, + .set_exclusive_zone = layer_surface_handle_set_exclusive_zone, + .set_margin = layer_surface_handle_set_margin, + .get_popup = layer_surface_handle_get_popup, + .get_input = layer_surface_handle_get_input, +}; + +static void layer_surface_configure_destroy( + struct wlr_layer_surface_configure *configure) { + if (configure == NULL) { + return; + } + wl_list_remove(&configure->link); + free(configure->state); + free(configure); +} + +static void layer_surface_unmap(struct wlr_layer_surface *surface) { + // TODO: probably need to ungrab before this event + wlr_signal_emit_safe(&surface->events.unmap, surface); + + struct wlr_layer_surface_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + layer_surface_configure_destroy(configure); + } + + surface->added = surface->configured = surface->mapped = false; + surface->configure_serial = 0; + if (surface->configure_idle) { + wl_event_source_remove(surface->configure_idle); + surface->configure_idle = NULL; + } + surface->configure_next_serial = 0; +} + +static void layer_surface_destroy(struct wlr_layer_surface *surface) { + layer_surface_unmap(surface); + wlr_signal_emit_safe(&surface->events.destroy, surface); + wl_resource_set_user_data(surface->resource, NULL); + wl_list_remove(&surface->link); + wl_list_remove(&surface->surface_destroy_listener.link); + wlr_surface_set_role_committed(surface->surface, NULL, NULL); + free(surface); +} + +static void layer_surface_resource_destroy(struct wl_resource *resource) { + struct wlr_layer_surface *surface = + layer_surface_from_resource(resource); + if (surface != NULL) { + layer_surface_destroy(surface); + } +} + +static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, + void *role_data) { + struct wlr_layer_surface *surface = role_data; + + if (wlr_surface_has_buffer(surface->surface) && !surface->configured) { + wl_resource_post_error(surface->resource, + ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED, + "layer_surface has never been configured"); + return; + } + if (!surface->added) { + surface->added = true; + wlr_signal_emit_safe( + &surface->client->shell->events.new_surface, surface); + } + if (surface->configured && wlr_surface_has_buffer(surface->surface) && + !surface->mapped) { + surface->mapped = true; + wlr_signal_emit_safe(&surface->events.map, surface); + } + if (surface->configured && !wlr_surface_has_buffer(surface->surface) && + surface->mapped) { + layer_surface_unmap(surface); + } +} + +static void handle_wlr_surface_destroyed(struct wl_listener *listener, + void *data) { + struct wlr_layer_surface *layer_surface = + wl_container_of(listener, layer_surface, surface_destroy_listener); + layer_surface_destroy(layer_surface); +} + +static void layer_shell_handle_get_layer_surface(struct wl_client *wl_client, + struct wl_resource *client_resource, uint32_t id, + struct wl_resource *surface_resource, + struct wl_resource *output_resource, + uint32_t layer, const char *namespace) { + struct wlr_layer_client *client = + layer_client_from_resource(client_resource); + + struct wlr_layer_surface *surface = + calloc(1, sizeof(struct wlr_layer_surface)); + if (surface == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + surface->client = client; + surface->surface = wlr_surface_from_resource(surface_resource); + surface->resource = wl_resource_create(wl_client, + &zwlr_layer_surface_v1_interface, + wl_resource_get_version(client_resource), + id); + surface->namespace = strdup(namespace); + surface->layer = layer; + if (surface->resource == NULL || surface->namespace == NULL) { + free(surface); + wl_client_post_no_memory(wl_client); + return; + } + + wl_signal_init(&surface->events.destroy); + wl_signal_add(&surface->surface->events.destroy, + &surface->surface_destroy_listener); + surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed; + + wlr_surface_set_role_committed(surface->surface, + handle_wlr_surface_committed, surface); + + wlr_log(L_DEBUG, "new layer_surface %p (res %p)", + surface, surface->resource); + wl_resource_set_implementation(surface->resource, + &layer_surface_implementation, surface, layer_surface_resource_destroy); + wl_list_insert(&client->surfaces, &surface->link); +} + +static struct zwlr_layer_shell_v1_interface layer_shell_impl = { + .get_layer_surface = layer_shell_handle_get_layer_surface, +}; + static void wlr_layer_client_destroy(struct wl_resource *resource) { struct wlr_layer_client *client = layer_client_from_resource(resource);