From fc960e5d060c78015e0037616ac568cbd7d64b07 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 14 Sep 2018 19:32:33 +0200 Subject: layer-shell: add _v1 suffix --- include/rootston/desktop.h | 4 +- include/rootston/layers.h | 4 +- include/rootston/seat.h | 4 +- include/wlr/types/meson.build | 2 +- include/wlr/types/wlr_layer_shell.h | 133 -------- include/wlr/types/wlr_layer_shell_v1.h | 134 ++++++++ rootston/cursor.c | 4 +- rootston/desktop.c | 6 +- rootston/layer_shell.c | 24 +- rootston/output.c | 6 +- rootston/seat.c | 4 +- types/meson.build | 2 +- types/wlr_layer_shell.c | 565 --------------------------------- types/wlr_layer_shell_v1.c | 564 ++++++++++++++++++++++++++++++++ 14 files changed, 728 insertions(+), 728 deletions(-) delete mode 100644 include/wlr/types/wlr_layer_shell.h create mode 100644 include/wlr/types/wlr_layer_shell_v1.h delete mode 100644 types/wlr_layer_shell.c create mode 100644 types/wlr_layer_shell_v1.c diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 3496fb43..89d8af4a 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -52,7 +52,7 @@ struct roots_desktop { struct wlr_idle *idle; struct wlr_idle_inhibit_manager_v1 *idle_inhibit; struct wlr_input_inhibit_manager *input_inhibit; - struct wlr_layer_shell *layer_shell; + struct wlr_layer_shell_v1 *layer_shell; struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; struct wlr_screencopy_manager_v1 *screencopy; struct wlr_tablet_manager_v2 *tablet_v2; diff --git a/include/rootston/layers.h b/include/rootston/layers.h index 9eab53ca..0dacf20f 100644 --- a/include/rootston/layers.h +++ b/include/rootston/layers.h @@ -3,10 +3,10 @@ #include #include #include -#include +#include struct roots_layer_surface { - struct wlr_layer_surface *layer_surface; + struct wlr_layer_surface_v1 *layer_surface; struct wl_list link; struct wl_listener destroy; diff --git a/include/rootston/seat.h b/include/rootston/seat.h index 3ddb97c5..c5e584b6 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -17,7 +17,7 @@ struct roots_seat { double touch_x, touch_y; // If the focused layer is set, views cannot receive keyboard focus - struct wlr_layer_surface *focused_layer; + struct wlr_layer_surface_v1 *focused_layer; // If non-null, only this client can receive input events struct wl_client *exclusive_client; @@ -140,7 +140,7 @@ struct roots_view *roots_seat_get_focus(struct roots_seat *seat); void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view); void roots_seat_set_focus_layer(struct roots_seat *seat, - struct wlr_layer_surface *layer); + struct wlr_layer_surface_v1 *layer); void roots_seat_cycle_focus(struct roots_seat *seat); diff --git a/include/wlr/types/meson.build b/include/wlr/types/meson.build index 8c81cb0e..8f44259e 100644 --- a/include/wlr/types/meson.build +++ b/include/wlr/types/meson.build @@ -12,7 +12,7 @@ install_headers( 'wlr_input_device.h', 'wlr_input_inhibitor.h', 'wlr_keyboard.h', - 'wlr_layer_shell.h', + 'wlr_layer_shell_v1.h', 'wlr_linux_dmabuf_v1.h', 'wlr_list.h', 'wlr_matrix.h', diff --git a/include/wlr/types/wlr_layer_shell.h b/include/wlr/types/wlr_layer_shell.h deleted file mode 100644 index c7ddd180..00000000 --- a/include/wlr/types/wlr_layer_shell.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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_LAYER_SHELL_H -#define WLR_TYPES_WLR_LAYER_SHELL_H -#include -#include -#include -#include -#include -#include "wlr-layer-shell-unstable-v1-protocol.h" - -/** - * wlr_layer_shell allows clients to arrange themselves in "layers" on the - * desktop in accordance with the wlr-layer-shell protocol. When a client is - * added, the new_surface signal will be raised and passed a reference to our - * wlr_layer_surface. At this time, the client will have configured the surface - * as it desires, including information like desired anchors and margins. The - * compositor should use this information to decide how to arrange the layer - * on-screen, then determine the dimensions of the layer and call - * wlr_layer_surface_configure. The client will then attach a buffer and commit - * the surface, at which point the wlr_layer_surface map signal is raised and - * the compositor should begin rendering the surface. - */ -struct wlr_layer_shell { - struct wl_global *global; - struct wl_list client_resources; // wl_resource - struct wl_list surfaces; // wl_layer_surface - - struct wl_listener display_destroy; - - struct { - // struct wlr_layer_surface * - // Note: the output may be NULL. In this case, it is your - // responsibility to assign an output before returning. - struct wl_signal new_surface; - struct wl_signal destroy; - } events; - - void *data; -}; - -struct wlr_layer_surface_state { - uint32_t anchor; - int32_t exclusive_zone; - struct { - uint32_t top, right, bottom, left; - } margin; - bool keyboard_interactive; - uint32_t desired_width, desired_height; - uint32_t actual_width, actual_height; -}; - -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 wl_list link; // wlr_layer_shell::surfaces - struct wlr_surface *surface; - struct wlr_output *output; - struct wl_resource *resource; - struct wlr_layer_shell *shell; - struct wl_list popups; // wlr_xdg_popup::link - - char *namespace; - enum zwlr_layer_shell_v1_layer layer; - - bool added, configured, mapped, closed; - uint32_t configure_serial; - struct wl_event_source *configure_idle; - uint32_t configure_next_serial; - struct wl_list configure_list; - - struct wlr_layer_surface_configure *acked_configure; - - struct wlr_layer_surface_state client_pending; - struct wlr_layer_surface_state server_pending; - struct wlr_layer_surface_state current; - - struct wl_listener surface_destroy; - - struct { - struct wl_signal destroy; - struct wl_signal map; - struct wl_signal unmap; - struct wl_signal new_popup; - } 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); - -/** - * Notifies the layer surface to configure itself with this width/height. The - * layer_surface will signal its map event when the surface is ready to assume - * this size. - */ -void wlr_layer_surface_configure(struct wlr_layer_surface *surface, - uint32_t width, uint32_t height); - -/** - * Unmaps this layer surface and notifies the client that it has been closed. - */ -void wlr_layer_surface_close(struct wlr_layer_surface *surface); - -bool wlr_surface_is_layer_surface(struct wlr_surface *surface); - -struct wlr_layer_surface *wlr_layer_surface_from_wlr_surface( - struct wlr_surface *surface); - -/* Calls the iterator function for each sub-surface and popup of this surface */ -void wlr_layer_surface_for_each_surface(struct wlr_layer_surface *surface, - wlr_surface_iterator_func_t iterator, void *user_data); - -/** - * Find a surface within this layer-surface tree at the given surface-local - * coordinates. Returns the surface and coordinates in the leaf surface - * coordinate system or NULL if no surface is found at that location. - */ -struct wlr_surface *wlr_layer_surface_surface_at( - struct wlr_layer_surface *surface, double sx, double sy, - double *sub_x, double *sub_y); -#endif diff --git a/include/wlr/types/wlr_layer_shell_v1.h b/include/wlr/types/wlr_layer_shell_v1.h new file mode 100644 index 00000000..838b2e83 --- /dev/null +++ b/include/wlr/types/wlr_layer_shell_v1.h @@ -0,0 +1,134 @@ +/* + * 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_LAYER_SHELL_V1_H +#define WLR_TYPES_WLR_LAYER_SHELL_V1_H +#include +#include +#include +#include +#include +#include "wlr-layer-shell-unstable-v1-protocol.h" + +/** + * wlr_layer_shell_v1 allows clients to arrange themselves in "layers" on the + * desktop in accordance with the wlr-layer-shell protocol. When a client is + * added, the new_surface signal will be raised and passed a reference to our + * wlr_layer_surface_v1. At this time, the client will have configured the + * surface as it desires, including information like desired anchors and + * margins. The compositor should use this information to decide how to arrange + * the layer on-screen, then determine the dimensions of the layer and call + * wlr_layer_surface_v1_configure. The client will then attach a buffer and + * commit the surface, at which point the wlr_layer_surface_v1 map signal is + * raised and the compositor should begin rendering the surface. + */ +struct wlr_layer_shell_v1 { + struct wl_global *global; + struct wl_list resources; // wl_resource + struct wl_list surfaces; // wl_layer_surface + + struct wl_listener display_destroy; + + struct { + // struct wlr_layer_surface_v1 * + // Note: the output may be NULL. In this case, it is your + // responsibility to assign an output before returning. + struct wl_signal new_surface; + struct wl_signal destroy; + } events; + + void *data; +}; + +struct wlr_layer_surface_v1_state { + uint32_t anchor; + int32_t exclusive_zone; + struct { + uint32_t top, right, bottom, left; + } margin; + bool keyboard_interactive; + uint32_t desired_width, desired_height; + uint32_t actual_width, actual_height; +}; + +struct wlr_layer_surface_v1_configure { + struct wl_list link; // wlr_layer_surface_v1::configure_list + uint32_t serial; + struct wlr_layer_surface_v1_state state; +}; + +struct wlr_layer_surface_v1 { + struct wl_list link; // wlr_layer_shell_v1::surfaces + struct wlr_surface *surface; + struct wlr_output *output; + struct wl_resource *resource; + struct wlr_layer_shell_v1 *shell; + struct wl_list popups; // wlr_xdg_popup::link + + char *namespace; + enum zwlr_layer_shell_v1_layer layer; + + bool added, configured, mapped, closed; + uint32_t configure_serial; + struct wl_event_source *configure_idle; + uint32_t configure_next_serial; + struct wl_list configure_list; + + struct wlr_layer_surface_v1_configure *acked_configure; + + struct wlr_layer_surface_v1_state client_pending; + struct wlr_layer_surface_v1_state server_pending; + struct wlr_layer_surface_v1_state current; + + struct wl_listener surface_destroy; + + struct { + struct wl_signal destroy; + struct wl_signal map; + struct wl_signal unmap; + struct wl_signal new_popup; + } events; + + void *data; +}; + +struct wlr_layer_shell_v1 *wlr_layer_shell_v1_create(struct wl_display *display); +void wlr_layer_shell_v1_destroy(struct wlr_layer_shell_v1 *layer_shell); + +/** + * Notifies the layer surface to configure itself with this width/height. The + * layer_surface will signal its map event when the surface is ready to assume + * this size. + */ +void wlr_layer_surface_v1_configure(struct wlr_layer_surface_v1 *surface, + uint32_t width, uint32_t height); + +/** + * Unmaps this layer surface and notifies the client that it has been closed. + */ +void wlr_layer_surface_v1_close(struct wlr_layer_surface_v1 *surface); + +bool wlr_surface_is_layer_surface(struct wlr_surface *surface); + +struct wlr_layer_surface_v1 *wlr_layer_surface_v1_from_wlr_surface( + struct wlr_surface *surface); + +/* Calls the iterator function for each sub-surface and popup of this surface */ +void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface, + wlr_surface_iterator_func_t iterator, void *user_data); + +/** + * Find a surface within this layer-surface tree at the given surface-local + * coordinates. Returns the surface and coordinates in the leaf surface + * coordinate system or NULL if no surface is found at that location. + */ +struct wlr_surface *wlr_layer_surface_v1_surface_at( + struct wlr_layer_surface_v1 *surface, double sx, double sy, + double *sub_x, double *sub_y); + +#endif diff --git a/rootston/cursor.c b/rootston/cursor.c index 9a9f9af6..2b8d9a3e 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -275,8 +275,8 @@ static void roots_cursor_press_button(struct roots_cursor *cursor, roots_seat_set_focus(seat, view); } if (surface && wlr_surface_is_layer_surface(surface)) { - struct wlr_layer_surface *layer = - wlr_layer_surface_from_wlr_surface(surface); + struct wlr_layer_surface_v1 *layer = + wlr_layer_surface_v1_from_wlr_surface(surface); if (layer->current.keyboard_interactive) { roots_seat_set_focus_layer(seat, layer); } diff --git a/rootston/desktop.c b/rootston/desktop.c index efb7581a..39d25d1b 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -667,7 +667,7 @@ static struct wlr_surface *layer_surface_at(struct roots_output *output, double _sx = ox - roots_surface->geo.x; double _sy = oy - roots_surface->geo.y; - struct wlr_surface *sub = wlr_layer_surface_surface_at( + struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( roots_surface->layer_surface, _sx, _sy, sx, sy); if (sub) { @@ -817,7 +817,7 @@ struct roots_desktop *desktop_create(struct roots_server *server, &desktop->wl_shell_surface); desktop->wl_shell_surface.notify = handle_wl_shell_surface; - desktop->layer_shell = wlr_layer_shell_create(server->wl_display); + desktop->layer_shell = wlr_layer_shell_v1_create(server->wl_display); wl_signal_add(&desktop->layer_shell->events.new_surface, &desktop->layer_shell_surface); desktop->layer_shell_surface.notify = handle_layer_shell_surface; diff --git a/rootston/layer_shell.c b/rootston/layer_shell.c index 39054079..4daa20d1 100644 --- a/rootston/layer_shell.c +++ b/rootston/layer_shell.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include "rootston/desktop.h" #include "rootston/layers.h" @@ -111,8 +111,8 @@ static void arrange_layer(struct wlr_output *output, wlr_output_effective_resolution(output, &full_area.width, &full_area.height); wl_list_for_each_reverse(roots_surface, list, link) { - struct wlr_layer_surface *layer = roots_surface->layer_surface; - struct wlr_layer_surface_state *state = &layer->current; + struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; + struct wlr_layer_surface_v1_state *state = &layer->current; if (exclusive != (state->exclusive_zone > 0)) { continue; } @@ -171,7 +171,7 @@ static void arrange_layer(struct wlr_output *output, } if (box.width < 0 || box.height < 0) { // TODO: Bubble up a protocol error? - wlr_layer_surface_close(layer); + wlr_layer_surface_v1_close(layer); continue; } @@ -181,7 +181,7 @@ static void arrange_layer(struct wlr_output *output, apply_exclusive(usable_area, state->anchor, state->exclusive_zone, state->margin.top, state->margin.right, state->margin.bottom, state->margin.left); - wlr_layer_surface_configure(layer, box.width, box.height); + wlr_layer_surface_v1_configure(layer, box.width, box.height); // Having a cursor newly end up over the moved layer will not // automatically send a motion event to the surface. The event needs to @@ -270,13 +270,13 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) { wl_container_of(listener, layer, output_destroy); layer->layer_surface->output = NULL; wl_list_remove(&layer->output_destroy.link); - wlr_layer_surface_close(layer->layer_surface); + wlr_layer_surface_v1_close(layer->layer_surface); } static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_layer_surface *layer = wl_container_of(listener, layer, surface_commit); - struct wlr_layer_surface *layer_surface = layer->layer_surface; + struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; struct wlr_output *wlr_output = layer_surface->output; if (wlr_output != NULL) { struct roots_output *output = wlr_output->data; @@ -308,7 +308,7 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { } } -static void unmap(struct wlr_layer_surface *layer_surface) { +static void unmap(struct wlr_layer_surface_v1 *layer_surface) { struct roots_layer_surface *layer = layer_surface->data; struct wlr_output *wlr_output = layer_surface->output; if (wlr_output != NULL) { @@ -337,7 +337,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { } static void handle_map(struct wl_listener *listener, void *data) { - struct wlr_layer_surface *layer_surface = data; + struct wlr_layer_surface_v1 *layer_surface = data; struct roots_layer_surface *layer = layer_surface->data; struct wlr_output *wlr_output = layer_surface->output; struct roots_output *output = wlr_output->data; @@ -430,7 +430,7 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { } void handle_layer_shell_surface(struct wl_listener *listener, void *data) { - struct wlr_layer_surface *layer_surface = data; + struct wlr_layer_surface_v1 *layer_surface = data; struct roots_desktop *desktop = wl_container_of(listener, desktop, layer_shell_surface); wlr_log(WLR_DEBUG, "new layer surface: namespace %s layer %d anchor %d " @@ -460,7 +460,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { if (output) { layer_surface->output = output; } else { - wlr_layer_surface_close(layer_surface); + wlr_layer_surface_v1_close(layer_surface); return; } } @@ -497,7 +497,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { // Temporarily set the layer's current state to client_pending // So that we can easily arrange it - struct wlr_layer_surface_state old_state = layer_surface->current; + struct wlr_layer_surface_v1_state old_state = layer_surface->current; layer_surface->current = layer_surface->client_pending; arrange_layers(output); diff --git a/rootston/output.c b/rootston/output.c index 8677f491..4207f0d0 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -363,14 +363,14 @@ static void render_layer(struct roots_output *output, struct wl_list *layer) { struct roots_layer_surface *roots_surface; wl_list_for_each(roots_surface, layer, link) { - struct wlr_layer_surface *layer = roots_surface->layer_surface; + struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; surface_for_each_surface(layer->surface, roots_surface->geo.x + output_layout_box->x, roots_surface->geo.y + output_layout_box->y, 0, &data->layout, render_surface, data); - wlr_layer_surface_for_each_surface(layer, render_surface, data); + wlr_layer_surface_v1_for_each_surface(layer, render_surface, data); } } @@ -380,7 +380,7 @@ static void layers_send_done( for (size_t i = 0; i < len; ++i) { struct roots_layer_surface *roots_surface; wl_list_for_each(roots_surface, &output->layers[i], link) { - struct wlr_layer_surface *layer = roots_surface->layer_surface; + struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; wlr_surface_send_frame_done(layer->surface, when); struct wlr_xdg_popup *popup; wl_list_for_each(popup, &roots_surface->layer_surface->popups, link) { diff --git a/rootston/seat.c b/rootston/seat.c index 1ae098bc..507254d4 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -1194,7 +1194,7 @@ void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view) { * You also cannot alt-tab between layer surfaces and shell surfaces. */ void roots_seat_set_focus_layer(struct roots_seat *seat, - struct wlr_layer_surface *layer) { + struct wlr_layer_surface_v1 *layer) { if (!layer) { seat->focused_layer = NULL; return; diff --git a/types/meson.build b/types/meson.build index 23c6cd13..dc1fbe7b 100644 --- a/types/meson.build +++ b/types/meson.build @@ -31,7 +31,7 @@ lib_wlr_types = static_library( 'wlr_input_device.c', 'wlr_input_inhibitor.c', 'wlr_keyboard.c', - 'wlr_layer_shell.c', + 'wlr_layer_shell_v1.c', 'wlr_linux_dmabuf_v1.c', 'wlr_list.c', 'wlr_matrix.c', diff --git a/types/wlr_layer_shell.c b/types/wlr_layer_shell.c deleted file mode 100644 index 52e5088e..00000000 --- a/types/wlr_layer_shell.c +++ /dev/null @@ -1,565 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "util/signal.h" -#include "wlr-layer-shell-unstable-v1-protocol.h" - -static void resource_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static const struct zwlr_layer_shell_v1_interface layer_shell_implementation; -static const struct zwlr_layer_surface_v1_interface layer_surface_implementation; - -static struct wlr_layer_shell *layer_shell_from_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zwlr_layer_shell_v1_interface, - &layer_shell_implementation)); - 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_implementation)); - return wl_resource_get_user_data(resource); -} - -static const struct wlr_surface_role layer_surface_role; - -bool wlr_surface_is_layer_surface(struct wlr_surface *surface) { - return surface->role == &layer_surface_role; -} - -struct wlr_layer_surface *wlr_layer_surface_from_wlr_surface( - struct wlr_surface *surface) { - assert(wlr_surface_is_layer_surface(surface)); - return (struct wlr_layer_surface *)surface->role_data; -} - -static void layer_surface_configure_destroy( - struct wlr_layer_surface_configure *configure) { - if (configure == NULL) { - return; - } - wl_list_remove(&configure->link); - free(configure); -} - -static void layer_surface_handle_ack_configure(struct wl_client *client, - struct wl_resource *resource, uint32_t serial) { - struct wlr_layer_surface *surface = layer_surface_from_resource(resource); - - bool found = false; - struct wlr_layer_surface_configure *configure, *tmp; - wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { - if (configure->serial < serial) { - layer_surface_configure_destroy(configure); - } else if (configure->serial == serial) { - found = true; - break; - } else { - break; - } - } - if (!found) { - wl_resource_post_error(resource, - ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE, - "wrong configure serial: %u", serial); - return; - } - - if (surface->acked_configure) { - layer_surface_configure_destroy(surface->acked_configure); - } - surface->acked_configure = configure; - wl_list_remove(&configure->link); - wl_list_init(&configure->link); -} - -static void layer_surface_handle_set_size(struct wl_client *client, - struct wl_resource *resource, uint32_t width, uint32_t height) { - struct wlr_layer_surface *surface = layer_surface_from_resource(resource); - surface->client_pending.desired_width = width; - surface->client_pending.desired_height = height; -} - -static void layer_surface_handle_set_anchor(struct wl_client *client, - struct wl_resource *resource, uint32_t anchor) { - const uint32_t max_anchor = - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - if (anchor > max_anchor) { - wl_resource_post_error(resource, - ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR, - "invalid anchor %d", anchor); - } - struct wlr_layer_surface *surface = layer_surface_from_resource(resource); - surface->client_pending.anchor = anchor; -} - -static void layer_surface_handle_set_exclusive_zone(struct wl_client *client, - struct wl_resource *resource, int32_t zone) { - struct wlr_layer_surface *surface = layer_surface_from_resource(resource); - surface->client_pending.exclusive_zone = zone; -} - -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) { - struct wlr_layer_surface *surface = layer_surface_from_resource(resource); - surface->client_pending.margin.top = top; - surface->client_pending.margin.right = right; - surface->client_pending.margin.bottom = bottom; - surface->client_pending.margin.left = left; -} - -static void layer_surface_handle_set_keyboard_interactivity( - struct wl_client *client, struct wl_resource *resource, - uint32_t interactive) { - struct wlr_layer_surface *surface = layer_surface_from_resource(resource); - surface->client_pending.keyboard_interactive = !!interactive; -} - -static void layer_surface_handle_get_popup(struct wl_client *client, - struct wl_resource *layer_resource, - struct wl_resource *popup_resource) { - struct wlr_layer_surface *parent = - layer_surface_from_resource(layer_resource); - struct wlr_xdg_surface *popup_surface = - wlr_xdg_surface_from_popup_resource(popup_resource); - - assert(popup_surface->role == WLR_XDG_SURFACE_ROLE_POPUP); - struct wlr_xdg_popup *popup = popup_surface->popup; - popup->parent = parent->surface; - wl_list_insert(&parent->popups, &popup->link); - wlr_signal_emit_safe(&parent->events.new_popup, popup); -} - -static const struct zwlr_layer_surface_v1_interface layer_surface_implementation = { - .destroy = resource_handle_destroy, - .ack_configure = layer_surface_handle_ack_configure, - .set_size = layer_surface_handle_set_size, - .set_anchor = layer_surface_handle_set_anchor, - .set_exclusive_zone = layer_surface_handle_set_exclusive_zone, - .set_margin = layer_surface_handle_set_margin, - .set_keyboard_interactivity = layer_surface_handle_set_keyboard_interactivity, - .get_popup = layer_surface_handle_get_popup, -}; - -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->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) { - if (surface->configured && surface->mapped) { - layer_surface_unmap(surface); - } - wlr_signal_emit_safe(&surface->events.destroy, surface); - wl_resource_set_user_data(surface->resource, NULL); - surface->surface->role_data = NULL; - wl_list_remove(&surface->surface_destroy.link); - wl_list_remove(&surface->link); - free(surface->namespace); - 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 bool layer_surface_state_changed(struct wlr_layer_surface *surface) { - struct wlr_layer_surface_state *state; - if (wl_list_empty(&surface->configure_list)) { - if (surface->acked_configure) { - state = &surface->acked_configure->state; - } else if (!surface->configured) { - return true; - } else { - state = &surface->current; - } - } else { - struct wlr_layer_surface_configure *configure = - wl_container_of(surface->configure_list.prev, configure, link); - state = &configure->state; - } - - bool changed = state->actual_width != surface->server_pending.actual_width - || state->actual_height != surface->server_pending.actual_height; - return changed; -} - -void wlr_layer_surface_configure(struct wlr_layer_surface *surface, - uint32_t width, uint32_t height) { - surface->server_pending.actual_width = width; - surface->server_pending.actual_height = height; - if (layer_surface_state_changed(surface)) { - struct wl_display *display = - wl_client_get_display(wl_resource_get_client(surface->resource)); - struct wlr_layer_surface_configure *configure = - calloc(1, sizeof(struct wlr_layer_surface_configure)); - if (configure == NULL) { - wl_client_post_no_memory(wl_resource_get_client(surface->resource)); - return; - } - surface->configure_next_serial = wl_display_next_serial(display); - wl_list_insert(surface->configure_list.prev, &configure->link); - configure->state.actual_width = width; - configure->state.actual_height = height; - configure->serial = surface->configure_next_serial; - zwlr_layer_surface_v1_send_configure(surface->resource, - configure->serial, configure->state.actual_width, - configure->state.actual_height); - } -} - -void wlr_layer_surface_close(struct wlr_layer_surface *surface) { - if (surface->closed) { - return; - } - surface->closed = true; - layer_surface_unmap(surface); - zwlr_layer_surface_v1_send_closed(surface->resource); -} - -static void layer_surface_role_commit(struct wlr_surface *wlr_surface) { - struct wlr_layer_surface *surface = - wlr_layer_surface_from_wlr_surface(wlr_surface); - if (surface == NULL) { - return; - } - - if (surface->closed) { - // Ignore commits after the compositor has closed it - return; - } - - if (surface->acked_configure) { - struct wlr_layer_surface_configure *configure = - surface->acked_configure; - surface->configured = true; - surface->configure_serial = configure->serial; - surface->current.actual_width = configure->state.actual_width; - surface->current.actual_height = configure->state.actual_height; - layer_surface_configure_destroy(configure); - surface->acked_configure = NULL; - } - - 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; - } - - surface->current.anchor = surface->client_pending.anchor; - surface->current.exclusive_zone = surface->client_pending.exclusive_zone; - surface->current.margin = surface->client_pending.margin; - surface->current.keyboard_interactive = - surface->client_pending.keyboard_interactive; - surface->current.desired_width = surface->client_pending.desired_width; - surface->current.desired_height = surface->client_pending.desired_height; - - if (!surface->added) { - surface->added = true; - wlr_signal_emit_safe(&surface->shell->events.new_surface, - surface); - // either the compositor found a suitable output or it must - // have closed the surface - assert(surface->output || surface->closed); - } - 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 const struct wlr_surface_role layer_surface_role = { - .name = "zwlr_layer_surface_v1", - .commit = layer_surface_role_commit, -}; - -static void handle_surface_destroyed(struct wl_listener *listener, - void *data) { - struct wlr_layer_surface *layer_surface = - wl_container_of(listener, layer_surface, surface_destroy); - 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_shell *shell = - layer_shell_from_resource(client_resource); - struct wlr_surface *wlr_surface = - wlr_surface_from_resource(surface_resource); - - struct wlr_layer_surface *surface = - calloc(1, sizeof(struct wlr_layer_surface)); - if (surface == NULL) { - wl_client_post_no_memory(wl_client); - return; - } - - if (!wlr_surface_set_role(wlr_surface, &layer_surface_role, surface, - client_resource, ZWLR_LAYER_SHELL_V1_ERROR_ROLE)) { - free(surface); - return; - } - - surface->shell = shell; - surface->surface = wlr_surface; - if (output_resource) { - surface->output = wlr_output_from_resource(output_resource); - } - surface->layer = layer; - if (layer > ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) { - free(surface); - wl_resource_post_error(client_resource, - ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER, - "Invalid layer %d", layer); - return; - } - surface->namespace = strdup(namespace); - if (surface->namespace == NULL) { - free(surface); - wl_client_post_no_memory(wl_client); - return; - } - surface->resource = wl_resource_create(wl_client, - &zwlr_layer_surface_v1_interface, - wl_resource_get_version(client_resource), - id); - if (surface->resource == NULL) { - free(surface->namespace); - free(surface); - wl_client_post_no_memory(wl_client); - return; - } - - wl_list_init(&surface->configure_list); - wl_list_init(&surface->popups); - - wl_signal_init(&surface->events.destroy); - wl_signal_init(&surface->events.map); - wl_signal_init(&surface->events.unmap); - wl_signal_init(&surface->events.new_popup); - - wl_signal_add(&surface->surface->events.destroy, - &surface->surface_destroy); - surface->surface_destroy.notify = handle_surface_destroyed; - - wlr_log(WLR_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(&shell->surfaces, &surface->link); -} - -static const struct zwlr_layer_shell_v1_interface layer_shell_implementation = { - .get_layer_surface = layer_shell_handle_get_layer_surface, -}; - -static void client_handle_destroy(struct wl_resource *resource) { - struct wl_client *client = wl_resource_get_client(resource); - struct wlr_layer_shell *shell = layer_shell_from_resource(resource); - struct wlr_layer_surface *surface, *tmp = NULL; - wl_list_for_each_safe(surface, tmp, &shell->surfaces, link) { - if (wl_resource_get_client(surface->resource) == client) { - layer_surface_destroy(surface); - } - } - wl_list_remove(wl_resource_get_link(resource)); -} - -static void layer_shell_bind(struct wl_client *wl_client, void *data, - uint32_t version, uint32_t id) { - struct wlr_layer_shell *layer_shell = data; - assert(wl_client && layer_shell); - - struct wl_resource *resource = wl_resource_create( - wl_client, &zwlr_layer_shell_v1_interface, version, id); - if (resource == NULL) { - wl_client_post_no_memory(wl_client); - return; - } - wl_resource_set_implementation(resource, - &layer_shell_implementation, layer_shell, client_handle_destroy); - wl_list_insert(&layer_shell->client_resources, - wl_resource_get_link(resource)); -} - -static void handle_display_destroy(struct wl_listener *listener, void *data) { - struct wlr_layer_shell *layer_shell = - wl_container_of(listener, layer_shell, display_destroy); - wlr_layer_shell_destroy(layer_shell); -} - -struct wlr_layer_shell *wlr_layer_shell_create(struct wl_display *display) { - struct wlr_layer_shell *layer_shell = - calloc(1, sizeof(struct wlr_layer_shell)); - if (!layer_shell) { - return NULL; - } - - wl_list_init(&layer_shell->client_resources); - wl_list_init(&layer_shell->surfaces); - - struct wl_global *global = wl_global_create(display, - &zwlr_layer_shell_v1_interface, 1, layer_shell, layer_shell_bind); - if (!global) { - free(layer_shell); - return NULL; - } - layer_shell->global = global; - - wl_signal_init(&layer_shell->events.new_surface); - wl_signal_init(&layer_shell->events.destroy); - - layer_shell->display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(display, &layer_shell->display_destroy); - - return layer_shell; -} - -void wlr_layer_shell_destroy(struct wlr_layer_shell *layer_shell) { - if (!layer_shell) { - return; - } - struct wl_resource *client, *tmp; - wl_resource_for_each_safe(client, tmp, &layer_shell->client_resources) { - wl_resource_destroy(client); - } - wlr_signal_emit_safe(&layer_shell->events.destroy, layer_shell); - wl_list_remove(&layer_shell->display_destroy.link); - wl_global_destroy(layer_shell->global); - free(layer_shell); -} - -struct layer_surface_iterator_data { - wlr_surface_iterator_func_t user_iterator; - void *user_data; - int x, y; -}; - -static void layer_surface_iterator(struct wlr_surface *surface, - int sx, int sy, void *data) { - struct layer_surface_iterator_data *iter_data = data; - iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy, - iter_data->user_data); -} - -static void xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, - int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { - struct layer_surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .x = x, .y = y, - }; - wlr_surface_for_each_surface( - surface->surface, layer_surface_iterator, &data); - - struct wlr_xdg_popup *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface *popup = popup_state->base; - if (!popup->configured) { - continue; - } - - double popup_sx = popup_state->geometry.x - popup_state->base->geometry.x; - double popup_sy = popup_state->geometry.y - popup_state->base->geometry.y; - - xdg_surface_for_each_surface(popup, - x + popup_sx, - y + popup_sy, - iterator, user_data); - } -} - -static void layer_surface_for_each_surface(struct wlr_layer_surface *surface, - int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { - struct layer_surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .x = x, .y = y, - }; - wlr_surface_for_each_surface(surface->surface, - layer_surface_iterator, &data); - - struct wlr_xdg_popup *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface *popup = popup_state->base; - if (!popup->configured) { - continue; - } - - double popup_sx, popup_sy; - popup_sx = popup->popup->geometry.x - popup->geometry.x; - popup_sy = popup->popup->geometry.y - popup->geometry.y; - - xdg_surface_for_each_surface(popup, - popup_sx, popup_sy, iterator, user_data); - } -} - -void wlr_layer_surface_for_each_surface(struct wlr_layer_surface *surface, - wlr_surface_iterator_func_t iterator, void *user_data) { - layer_surface_for_each_surface(surface, 0, 0, iterator, user_data); -} - -struct wlr_surface *wlr_layer_surface_surface_at( - struct wlr_layer_surface *surface, double sx, double sy, - double *sub_x, double *sub_y) { - struct wlr_xdg_popup *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface *popup = popup_state->base; - - double popup_sx = popup_state->geometry.x - popup->geometry.x; - double popup_sy = popup_state->geometry.y - popup->geometry.y; - - struct wlr_surface *sub = wlr_xdg_surface_surface_at(popup, - sx - popup_sx, - sy - popup_sy, - sub_x, sub_y); - if (sub != NULL) { - return sub; - } - } - - return wlr_surface_surface_at(surface->surface, sx, sy, sub_x, sub_y); -} diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c new file mode 100644 index 00000000..aa959d89 --- /dev/null +++ b/types/wlr_layer_shell_v1.c @@ -0,0 +1,564 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util/signal.h" +#include "wlr-layer-shell-unstable-v1-protocol.h" + +static void resource_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct zwlr_layer_shell_v1_interface layer_shell_implementation; +static const struct zwlr_layer_surface_v1_interface layer_surface_implementation; + +static struct wlr_layer_shell_v1 *layer_shell_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zwlr_layer_shell_v1_interface, + &layer_shell_implementation)); + return wl_resource_get_user_data(resource); +} + +static struct wlr_layer_surface_v1 *layer_surface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zwlr_layer_surface_v1_interface, + &layer_surface_implementation)); + return wl_resource_get_user_data(resource); +} + +static const struct wlr_surface_role layer_surface_role; + +bool wlr_surface_is_layer_surface(struct wlr_surface *surface) { + return surface->role == &layer_surface_role; +} + +struct wlr_layer_surface_v1 *wlr_layer_surface_v1_from_wlr_surface( + struct wlr_surface *surface) { + assert(wlr_surface_is_layer_surface(surface)); + return (struct wlr_layer_surface_v1 *)surface->role_data; +} + +static void layer_surface_configure_destroy( + struct wlr_layer_surface_v1_configure *configure) { + if (configure == NULL) { + return; + } + wl_list_remove(&configure->link); + free(configure); +} + +static void layer_surface_handle_ack_configure(struct wl_client *client, + struct wl_resource *resource, uint32_t serial) { + struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + + bool found = false; + struct wlr_layer_surface_v1_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + if (configure->serial < serial) { + layer_surface_configure_destroy(configure); + } else if (configure->serial == serial) { + found = true; + break; + } else { + break; + } + } + if (!found) { + wl_resource_post_error(resource, + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE, + "wrong configure serial: %u", serial); + return; + } + + if (surface->acked_configure) { + layer_surface_configure_destroy(surface->acked_configure); + } + surface->acked_configure = configure; + wl_list_remove(&configure->link); + wl_list_init(&configure->link); +} + +static void layer_surface_handle_set_size(struct wl_client *client, + struct wl_resource *resource, uint32_t width, uint32_t height) { + struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + surface->client_pending.desired_width = width; + surface->client_pending.desired_height = height; +} + +static void layer_surface_handle_set_anchor(struct wl_client *client, + struct wl_resource *resource, uint32_t anchor) { + const uint32_t max_anchor = + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + if (anchor > max_anchor) { + wl_resource_post_error(resource, + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR, + "invalid anchor %d", anchor); + } + struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + surface->client_pending.anchor = anchor; +} + +static void layer_surface_handle_set_exclusive_zone(struct wl_client *client, + struct wl_resource *resource, int32_t zone) { + struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + surface->client_pending.exclusive_zone = zone; +} + +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) { + struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + surface->client_pending.margin.top = top; + surface->client_pending.margin.right = right; + surface->client_pending.margin.bottom = bottom; + surface->client_pending.margin.left = left; +} + +static void layer_surface_handle_set_keyboard_interactivity( + struct wl_client *client, struct wl_resource *resource, + uint32_t interactive) { + struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + surface->client_pending.keyboard_interactive = !!interactive; +} + +static void layer_surface_handle_get_popup(struct wl_client *client, + struct wl_resource *layer_resource, + struct wl_resource *popup_resource) { + struct wlr_layer_surface_v1 *parent = + layer_surface_from_resource(layer_resource); + struct wlr_xdg_surface *popup_surface = + wlr_xdg_surface_from_popup_resource(popup_resource); + + assert(popup_surface->role == WLR_XDG_SURFACE_ROLE_POPUP); + struct wlr_xdg_popup *popup = popup_surface->popup; + popup->parent = parent->surface; + wl_list_insert(&parent->popups, &popup->link); + wlr_signal_emit_safe(&parent->events.new_popup, popup); +} + +static const struct zwlr_layer_surface_v1_interface layer_surface_implementation = { + .destroy = resource_handle_destroy, + .ack_configure = layer_surface_handle_ack_configure, + .set_size = layer_surface_handle_set_size, + .set_anchor = layer_surface_handle_set_anchor, + .set_exclusive_zone = layer_surface_handle_set_exclusive_zone, + .set_margin = layer_surface_handle_set_margin, + .set_keyboard_interactivity = layer_surface_handle_set_keyboard_interactivity, + .get_popup = layer_surface_handle_get_popup, +}; + +static void layer_surface_unmap(struct wlr_layer_surface_v1 *surface) { + // TODO: probably need to ungrab before this event + wlr_signal_emit_safe(&surface->events.unmap, surface); + + struct wlr_layer_surface_v1_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + layer_surface_configure_destroy(configure); + } + + 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_v1 *surface) { + if (surface->configured && surface->mapped) { + layer_surface_unmap(surface); + } + wlr_signal_emit_safe(&surface->events.destroy, surface); + wl_resource_set_user_data(surface->resource, NULL); + surface->surface->role_data = NULL; + wl_list_remove(&surface->surface_destroy.link); + wl_list_remove(&surface->link); + free(surface->namespace); + free(surface); +} + +static void layer_surface_resource_destroy(struct wl_resource *resource) { + struct wlr_layer_surface_v1 *surface = + layer_surface_from_resource(resource); + if (surface != NULL) { + layer_surface_destroy(surface); + } +} + +static bool layer_surface_state_changed(struct wlr_layer_surface_v1 *surface) { + struct wlr_layer_surface_v1_state *state; + if (wl_list_empty(&surface->configure_list)) { + if (surface->acked_configure) { + state = &surface->acked_configure->state; + } else if (!surface->configured) { + return true; + } else { + state = &surface->current; + } + } else { + struct wlr_layer_surface_v1_configure *configure = + wl_container_of(surface->configure_list.prev, configure, link); + state = &configure->state; + } + + bool changed = state->actual_width != surface->server_pending.actual_width + || state->actual_height != surface->server_pending.actual_height; + return changed; +} + +void wlr_layer_surface_v1_configure(struct wlr_layer_surface_v1 *surface, + uint32_t width, uint32_t height) { + surface->server_pending.actual_width = width; + surface->server_pending.actual_height = height; + if (layer_surface_state_changed(surface)) { + struct wl_display *display = + wl_client_get_display(wl_resource_get_client(surface->resource)); + struct wlr_layer_surface_v1_configure *configure = + calloc(1, sizeof(struct wlr_layer_surface_v1_configure)); + if (configure == NULL) { + wl_client_post_no_memory(wl_resource_get_client(surface->resource)); + return; + } + surface->configure_next_serial = wl_display_next_serial(display); + wl_list_insert(surface->configure_list.prev, &configure->link); + configure->state.actual_width = width; + configure->state.actual_height = height; + configure->serial = surface->configure_next_serial; + zwlr_layer_surface_v1_send_configure(surface->resource, + configure->serial, configure->state.actual_width, + configure->state.actual_height); + } +} + +void wlr_layer_surface_v1_close(struct wlr_layer_surface_v1 *surface) { + if (surface->closed) { + return; + } + surface->closed = true; + layer_surface_unmap(surface); + zwlr_layer_surface_v1_send_closed(surface->resource); +} + +static void layer_surface_role_commit(struct wlr_surface *wlr_surface) { + struct wlr_layer_surface_v1 *surface = + wlr_layer_surface_v1_from_wlr_surface(wlr_surface); + if (surface == NULL) { + return; + } + + if (surface->closed) { + // Ignore commits after the compositor has closed it + return; + } + + if (surface->acked_configure) { + struct wlr_layer_surface_v1_configure *configure = + surface->acked_configure; + surface->configured = true; + surface->configure_serial = configure->serial; + surface->current.actual_width = configure->state.actual_width; + surface->current.actual_height = configure->state.actual_height; + layer_surface_configure_destroy(configure); + surface->acked_configure = NULL; + } + + 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; + } + + surface->current.anchor = surface->client_pending.anchor; + surface->current.exclusive_zone = surface->client_pending.exclusive_zone; + surface->current.margin = surface->client_pending.margin; + surface->current.keyboard_interactive = + surface->client_pending.keyboard_interactive; + surface->current.desired_width = surface->client_pending.desired_width; + surface->current.desired_height = surface->client_pending.desired_height; + + if (!surface->added) { + surface->added = true; + wlr_signal_emit_safe(&surface->shell->events.new_surface, + surface); + // either the compositor found a suitable output or it must + // have closed the surface + assert(surface->output || surface->closed); + } + 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 const struct wlr_surface_role layer_surface_role = { + .name = "zwlr_layer_surface_v1", + .commit = layer_surface_role_commit, +}; + +static void handle_surface_destroyed(struct wl_listener *listener, + void *data) { + struct wlr_layer_surface_v1 *layer_surface = + wl_container_of(listener, layer_surface, surface_destroy); + 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_shell_v1 *shell = + layer_shell_from_resource(client_resource); + struct wlr_surface *wlr_surface = + wlr_surface_from_resource(surface_resource); + + struct wlr_layer_surface_v1 *surface = + calloc(1, sizeof(struct wlr_layer_surface_v1)); + if (surface == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + if (!wlr_surface_set_role(wlr_surface, &layer_surface_role, surface, + client_resource, ZWLR_LAYER_SHELL_V1_ERROR_ROLE)) { + free(surface); + return; + } + + surface->shell = shell; + surface->surface = wlr_surface; + if (output_resource) { + surface->output = wlr_output_from_resource(output_resource); + } + surface->layer = layer; + if (layer > ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) { + free(surface); + wl_resource_post_error(client_resource, + ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER, + "Invalid layer %d", layer); + return; + } + surface->namespace = strdup(namespace); + if (surface->namespace == NULL) { + free(surface); + wl_client_post_no_memory(wl_client); + return; + } + surface->resource = wl_resource_create(wl_client, + &zwlr_layer_surface_v1_interface, + wl_resource_get_version(client_resource), + id); + if (surface->resource == NULL) { + free(surface->namespace); + free(surface); + wl_client_post_no_memory(wl_client); + return; + } + + wl_list_init(&surface->configure_list); + wl_list_init(&surface->popups); + + wl_signal_init(&surface->events.destroy); + wl_signal_init(&surface->events.map); + wl_signal_init(&surface->events.unmap); + wl_signal_init(&surface->events.new_popup); + + wl_signal_add(&surface->surface->events.destroy, + &surface->surface_destroy); + surface->surface_destroy.notify = handle_surface_destroyed; + + wlr_log(WLR_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(&shell->surfaces, &surface->link); +} + +static const struct zwlr_layer_shell_v1_interface layer_shell_implementation = { + .get_layer_surface = layer_shell_handle_get_layer_surface, +}; + +static void client_handle_destroy(struct wl_resource *resource) { + struct wl_client *client = wl_resource_get_client(resource); + struct wlr_layer_shell_v1 *shell = layer_shell_from_resource(resource); + struct wlr_layer_surface_v1 *surface, *tmp = NULL; + wl_list_for_each_safe(surface, tmp, &shell->surfaces, link) { + if (wl_resource_get_client(surface->resource) == client) { + layer_surface_destroy(surface); + } + } + wl_list_remove(wl_resource_get_link(resource)); +} + +static void layer_shell_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) { + struct wlr_layer_shell_v1 *layer_shell = data; + assert(wl_client && layer_shell); + + struct wl_resource *resource = wl_resource_create( + wl_client, &zwlr_layer_shell_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + wl_resource_set_implementation(resource, + &layer_shell_implementation, layer_shell, client_handle_destroy); + wl_list_insert(&layer_shell->resources, wl_resource_get_link(resource)); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_layer_shell_v1 *layer_shell = + wl_container_of(listener, layer_shell, display_destroy); + wlr_layer_shell_v1_destroy(layer_shell); +} + +struct wlr_layer_shell_v1 *wlr_layer_shell_v1_create(struct wl_display *display) { + struct wlr_layer_shell_v1 *layer_shell = + calloc(1, sizeof(struct wlr_layer_shell_v1)); + if (!layer_shell) { + return NULL; + } + + wl_list_init(&layer_shell->resources); + wl_list_init(&layer_shell->surfaces); + + struct wl_global *global = wl_global_create(display, + &zwlr_layer_shell_v1_interface, 1, layer_shell, layer_shell_bind); + if (!global) { + free(layer_shell); + return NULL; + } + layer_shell->global = global; + + wl_signal_init(&layer_shell->events.new_surface); + wl_signal_init(&layer_shell->events.destroy); + + layer_shell->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &layer_shell->display_destroy); + + return layer_shell; +} + +void wlr_layer_shell_v1_destroy(struct wlr_layer_shell_v1 *layer_shell) { + if (!layer_shell) { + return; + } + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &layer_shell->resources) { + wl_resource_destroy(resource); + } + wlr_signal_emit_safe(&layer_shell->events.destroy, layer_shell); + wl_list_remove(&layer_shell->display_destroy.link); + wl_global_destroy(layer_shell->global); + free(layer_shell); +} + +struct layer_surface_iterator_data { + wlr_surface_iterator_func_t user_iterator; + void *user_data; + int x, y; +}; + +static void layer_surface_iterator(struct wlr_surface *surface, + int sx, int sy, void *data) { + struct layer_surface_iterator_data *iter_data = data; + iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy, + iter_data->user_data); +} + +static void xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, + int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { + struct layer_surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .x = x, .y = y, + }; + wlr_surface_for_each_surface( + surface->surface, layer_surface_iterator, &data); + + struct wlr_xdg_popup *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface *popup = popup_state->base; + if (!popup->configured) { + continue; + } + + double popup_sx = popup_state->geometry.x - popup_state->base->geometry.x; + double popup_sy = popup_state->geometry.y - popup_state->base->geometry.y; + + xdg_surface_for_each_surface(popup, + x + popup_sx, + y + popup_sy, + iterator, user_data); + } +} + +static void layer_surface_for_each_surface(struct wlr_layer_surface_v1 *surface, + int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { + struct layer_surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .x = x, .y = y, + }; + wlr_surface_for_each_surface(surface->surface, + layer_surface_iterator, &data); + + struct wlr_xdg_popup *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface *popup = popup_state->base; + if (!popup->configured) { + continue; + } + + double popup_sx, popup_sy; + popup_sx = popup->popup->geometry.x - popup->geometry.x; + popup_sy = popup->popup->geometry.y - popup->geometry.y; + + xdg_surface_for_each_surface(popup, + popup_sx, popup_sy, iterator, user_data); + } +} + +void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface, + wlr_surface_iterator_func_t iterator, void *user_data) { + layer_surface_for_each_surface(surface, 0, 0, iterator, user_data); +} + +struct wlr_surface *wlr_layer_surface_v1_surface_at( + struct wlr_layer_surface_v1 *surface, double sx, double sy, + double *sub_x, double *sub_y) { + struct wlr_xdg_popup *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface *popup = popup_state->base; + + double popup_sx = popup_state->geometry.x - popup->geometry.x; + double popup_sy = popup_state->geometry.y - popup->geometry.y; + + struct wlr_surface *sub = wlr_xdg_surface_surface_at(popup, + sx - popup_sx, + sy - popup_sy, + sub_x, sub_y); + if (sub != NULL) { + return sub; + } + } + + return wlr_surface_surface_at(surface->surface, sx, sy, sub_x, sub_y); +} -- cgit v1.2.3