From 392d54a35d34ff08baaffdd50b9d11072481706e Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 13 Feb 2018 23:48:46 +0100 Subject: [PATCH 01/13] Wrap wl_resource_get_user_data into safer helper functions This ensures we're not incorrectly casting a resource. Fixes #628 --- include/wlr/types/wlr_output.h | 1 + include/wlr/types/wlr_region.h | 7 +- include/wlr/types/wlr_seat.h | 2 + include/wlr/types/wlr_surface.h | 2 + types/wlr_compositor.c | 18 ++- types/wlr_data_device.c | 67 ++++++--- types/wlr_gamma_control.c | 28 +++- types/wlr_idle.c | 39 ++++-- types/wlr_output.c | 12 +- types/wlr_primary_selection.c | 35 +++-- types/wlr_region.c | 17 ++- types/wlr_screenshooter.c | 24 +++- types/wlr_seat.c | 29 +++- types/wlr_server_decoration.c | 33 ++++- types/wlr_surface.c | 68 ++++++--- types/wlr_wl_shell.c | 63 +++++---- types/wlr_xdg_shell_v6.c | 240 ++++++++++++++++++++------------ xwayland/xwm.c | 2 +- 18 files changed, 474 insertions(+), 213 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 5c2ffee0..a8138a80 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -157,6 +157,7 @@ void wlr_output_set_gamma(struct wlr_output *output, uint32_t wlr_output_get_gamma_size(struct wlr_output *output); void wlr_output_set_fullscreen_surface(struct wlr_output *output, struct wlr_surface *surface); +struct wlr_output *wlr_output_from_resource(struct wl_resource *resource); struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output); diff --git a/include/wlr/types/wlr_region.h b/include/wlr/types/wlr_region.h index 6d59ee5e..ffacea72 100644 --- a/include/wlr/types/wlr_region.h +++ b/include/wlr/types/wlr_region.h @@ -1,13 +1,16 @@ #ifndef WLR_TYPES_WLR_REGION_H #define WLR_TYPES_WLR_REGION_H +#include + struct wl_resource; /* * Implements the given resource as region. - * Sets the associated pixman_region32_t as userdata. */ void wlr_region_create(struct wl_client *client, struct wl_resource *res, - uint32_t id); + uint32_t id); + +pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource); #endif diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index b03cab6e..124c1cb8 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -530,4 +530,6 @@ bool wlr_seat_touch_has_grab(struct wlr_seat *seat); */ bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial); +struct wlr_seat_client *wlr_seat_client_from_resource(struct wl_resource *resource); + #endif diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 998b5ae5..203345bd 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -164,4 +164,6 @@ void wlr_surface_set_role_committed(struct wlr_surface *surface, void (*role_committed)(struct wlr_surface *surface, void *role_data), void *role_data); +struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource); + #endif diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 925e0019..008f2e51 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -7,13 +7,21 @@ #include #include "util/signal.h" +static const struct wl_compositor_interface wl_compositor_impl; + +static struct wlr_compositor *compositor_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_compositor_interface, + &wl_compositor_impl)); + return wl_resource_get_user_data(resource); +} + static void destroy_surface_listener(struct wl_listener *listener, void *data) { wl_list_remove(wl_resource_get_link(data)); } static void wl_compositor_create_surface(struct wl_client *client, struct wl_resource *resource, uint32_t id) { - struct wlr_compositor *compositor = wl_resource_get_user_data(resource); + struct wlr_compositor *compositor = compositor_from_resource(resource); struct wl_resource *surface_resource = wl_resource_create(client, &wl_surface_interface, wl_resource_get_version(resource), id); @@ -44,13 +52,13 @@ static void wl_compositor_create_region(struct wl_client *client, wlr_region_create(client, resource, id); } -struct wl_compositor_interface wl_compositor_impl = { +static const struct wl_compositor_interface wl_compositor_impl = { .create_surface = wl_compositor_create_surface, .create_region = wl_compositor_create_region }; static void wl_compositor_destroy(struct wl_resource *resource) { - struct wlr_compositor *compositor = wl_resource_get_user_data(resource); + struct wlr_compositor *compositor = compositor_from_resource(resource); struct wl_resource *_resource = NULL; wl_resource_for_each(_resource, &compositor->wl_resources) { if (_resource == resource) { @@ -96,8 +104,8 @@ static void subcompositor_get_subsurface(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource, struct wl_resource *parent_resource) { - struct wlr_surface *surface = wl_resource_get_user_data(surface_resource); - struct wlr_surface *parent = wl_resource_get_user_data(parent_resource); + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); + struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); static const char msg[] = "get_subsurface: wl_subsurface@"; diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index b8ef820b..50c94bc5 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -14,6 +14,24 @@ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) +static const struct wl_data_offer_interface data_offer_impl; + +static struct wlr_data_offer *data_offer_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_data_offer_interface, + &data_offer_impl)); + return wl_resource_get_user_data(resource); +} + +static const struct wl_data_source_interface data_source_impl; + +static struct client_data_source *client_data_source_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_data_source_interface, + &data_source_impl)); + return wl_resource_get_user_data(resource); +} + static uint32_t data_offer_choose_action(struct wlr_data_offer *offer) { uint32_t offer_actions, preferred_action = 0; if (wl_resource_get_version(offer->resource) >= @@ -78,7 +96,7 @@ static void data_offer_update_action(struct wlr_data_offer *offer) { static void data_offer_accept(struct wl_client *client, struct wl_resource *resource, uint32_t serial, const char *mime_type) { - struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + struct wlr_data_offer *offer = data_offer_from_resource(resource); if (!offer->source || offer != offer->source->offer) { return; @@ -94,7 +112,7 @@ static void data_offer_accept(struct wl_client *client, static void data_offer_receive(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd) { - struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + struct wlr_data_offer *offer = data_offer_from_resource(resource); if (offer->source && offer == offer->source->offer) { offer->source->send(offer->source, mime_type, fd); @@ -126,7 +144,7 @@ static void data_source_notify_finish(struct wlr_data_source *source) { static void data_offer_finish(struct wl_client *client, struct wl_resource *resource) { - struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + struct wlr_data_offer *offer = data_offer_from_resource(resource); if (!offer->source || offer->source->offer != offer) { return; @@ -138,7 +156,7 @@ static void data_offer_finish(struct wl_client *client, static void data_offer_set_actions(struct wl_client *client, struct wl_resource *resource, uint32_t actions, uint32_t preferred_action) { - struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + struct wlr_data_offer *offer = data_offer_from_resource(resource); if (actions & ~ALL_ACTIONS) { wl_resource_post_error(offer->resource, @@ -162,7 +180,7 @@ static void data_offer_set_actions(struct wl_client *client, } static void data_offer_resource_destroy(struct wl_resource *resource) { - struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + struct wlr_data_offer *offer = data_offer_from_resource(resource); if (!offer->source) { goto out; @@ -332,16 +350,25 @@ void wlr_seat_set_selection(struct wlr_seat *seat, } } +static const struct wl_data_device_interface data_device_impl; + +static struct wlr_seat_client *seat_client_from_data_device_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_data_device_interface, + &data_device_impl)); + return wl_resource_get_user_data(resource); +} + static void data_device_set_selection(struct wl_client *client, - struct wl_resource *dd_resource, struct wl_resource *source_resource, - uint32_t serial) { + struct wl_resource *device_resource, + struct wl_resource *source_resource, uint32_t serial) { struct client_data_source *source = NULL; if (source_resource != NULL) { - source = wl_resource_get_user_data(source_resource); + source = client_data_source_from_resource(source_resource); } struct wlr_seat_client *seat_client = - wl_resource_get_user_data(dd_resource); + seat_client_from_data_device_resource(device_resource); struct wlr_data_source *wlr_source = (struct wlr_data_source *)source; wlr_seat_set_selection(seat_client->seat, wlr_source, serial); @@ -783,17 +810,19 @@ static void data_device_start_drag(struct wl_client *client, struct wl_resource *origin_resource, struct wl_resource *icon_resource, uint32_t serial) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(device_resource); - struct wlr_surface *origin = wl_resource_get_user_data(origin_resource); + seat_client_from_data_device_resource(device_resource); + struct wlr_surface *origin = wlr_surface_from_resource(origin_resource); struct wlr_data_source *source = NULL; struct wlr_surface *icon = NULL; if (source_resource) { - source = wl_resource_get_user_data(source_resource); + struct client_data_source *client_source = + client_data_source_from_resource(source_resource); + source = (struct wlr_data_source *)client_source; } if (icon_resource) { - icon = wl_resource_get_user_data(icon_resource); + icon = wlr_surface_from_resource(icon_resource); } if (icon) { if (wlr_surface_set_role(icon, "wl_data_device-icon", @@ -876,7 +905,7 @@ static void data_source_destroy(struct wl_client *client, static void data_source_set_actions(struct wl_client *client, struct wl_resource *resource, uint32_t dnd_actions) { struct client_data_source *source = - wl_resource_get_user_data(resource); + client_data_source_from_resource(resource); if (source->source.actions >= 0) { wl_resource_post_error(source->resource, @@ -905,7 +934,8 @@ static void data_source_set_actions(struct wl_client *client, static void data_source_offer(struct wl_client *client, struct wl_resource *resource, const char *mime_type) { - struct client_data_source *source = wl_resource_get_user_data(resource); + struct client_data_source *source = + client_data_source_from_resource(resource); char **p = wl_array_add(&source->source.mime_types, sizeof(*p)); if (p) { @@ -919,14 +949,15 @@ static void data_source_offer(struct wl_client *client, } } -static struct wl_data_source_interface data_source_impl = { +static const struct wl_data_source_interface data_source_impl = { .offer = data_source_offer, .destroy = data_source_destroy, .set_actions = data_source_set_actions, }; static void data_source_resource_handle_destroy(struct wl_resource *resource) { - struct client_data_source *source = wl_resource_get_user_data(resource); + struct client_data_source *source = + client_data_source_from_resource(resource); wlr_data_source_finish(&source->source); free(source); } @@ -956,7 +987,7 @@ void data_device_manager_get_data_device(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *seat_resource) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); struct wl_resource *resource = wl_resource_create(client, &wl_data_device_interface, wl_resource_get_version(manager_resource), diff --git a/types/wlr_gamma_control.c b/types/wlr_gamma_control.c index 861427bd..61c058c4 100644 --- a/types/wlr_gamma_control.c +++ b/types/wlr_gamma_control.c @@ -23,9 +23,18 @@ static void gamma_control_destroy(struct wlr_gamma_control *gamma_control) { free(gamma_control); } +static const struct gamma_control_interface gamma_control_impl; + +struct wlr_gamma_control *gamma_control_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &gamma_control_interface, + &gamma_control_impl)); + return wl_resource_get_user_data(resource); +} + static void gamma_control_destroy_resource(struct wl_resource *resource) { struct wlr_gamma_control *gamma_control = - wl_resource_get_user_data(resource); + gamma_control_from_resource(resource); gamma_control_destroy(gamma_control); } @@ -40,7 +49,7 @@ static void gamma_control_set_gamma(struct wl_client *client, struct wl_resource *gamma_control_resource, struct wl_array *red, struct wl_array *green, struct wl_array *blue) { struct wlr_gamma_control *gamma_control = - wl_resource_get_user_data(gamma_control_resource); + gamma_control_from_resource(gamma_control_resource); if (red->size != green->size || red->size != blue->size) { wl_resource_post_error(gamma_control_resource, @@ -68,12 +77,21 @@ static const struct gamma_control_interface gamma_control_impl = { .reset_gamma = gamma_control_reset_gamma, }; +static const struct gamma_control_manager_interface gamma_control_manager_impl; + +struct wlr_gamma_control_manager *gamma_control_manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &gamma_control_manager_interface, + &gamma_control_manager_impl)); + return wl_resource_get_user_data(resource); +} + static void gamma_control_manager_get_gamma_control(struct wl_client *client, struct wl_resource *gamma_control_manager_resource, uint32_t id, struct wl_resource *output_resource) { struct wlr_gamma_control_manager *manager = - wl_resource_get_user_data(gamma_control_manager_resource); - struct wlr_output *output = wl_resource_get_user_data(output_resource); + gamma_control_manager_from_resource(gamma_control_manager_resource); + struct wlr_output *output = wlr_output_from_resource(output_resource); struct wlr_gamma_control *gamma_control = calloc(1, sizeof(struct wlr_gamma_control)); @@ -109,7 +127,7 @@ static void gamma_control_manager_get_gamma_control(struct wl_client *client, wlr_output_get_gamma_size(output)); } -static struct gamma_control_manager_interface gamma_control_manager_impl = { +static const struct gamma_control_manager_interface gamma_control_manager_impl = { .get_gamma_control = gamma_control_manager_get_gamma_control, }; diff --git a/types/wlr_idle.c b/types/wlr_idle.c index 9eddc42b..51963aea 100644 --- a/types/wlr_idle.c +++ b/types/wlr_idle.c @@ -7,6 +7,15 @@ #include "idle-protocol.h" #include "util/signal.h" +static const struct org_kde_kwin_idle_timeout_interface idle_timeout_impl; + +static struct wlr_idle_timeout *idle_timeout_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &org_kde_kwin_idle_timeout_interface, &idle_timeout_impl)); + return wl_resource_get_user_data(resource); +} + static void idle_timeout_destroy(struct wlr_idle_timeout *timer) { wl_list_remove(&timer->input_listener.link); wl_list_remove(&timer->seat_destroy.link); @@ -34,7 +43,7 @@ static void handle_activity(struct wlr_idle_timeout *timer) { } static void handle_timer_resource_destroy(struct wl_resource *timer_resource) { - struct wlr_idle_timeout *timer = wl_resource_get_user_data(timer_resource); + struct wlr_idle_timeout *timer = idle_timeout_from_resource(timer_resource); if (timer != NULL) { idle_timeout_destroy(timer); } @@ -54,17 +63,27 @@ static void release_idle_timeout(struct wl_client *client, static void simulate_activity(struct wl_client *client, struct wl_resource *resource){ - struct wlr_idle_timeout *timer = wl_resource_get_user_data(resource); + struct wlr_idle_timeout *timer = idle_timeout_from_resource(resource); handle_activity(timer); } -static struct org_kde_kwin_idle_timeout_interface idle_timeout_impl = { +static const struct org_kde_kwin_idle_timeout_interface idle_timeout_impl = { .release = release_idle_timeout, .simulate_user_activity = simulate_activity, }; +static const struct org_kde_kwin_idle_interface idle_impl; + +static struct wlr_idle *idle_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &org_kde_kwin_idle_interface, + &idle_impl)); + return wl_resource_get_user_data(resource); +} + static void handle_input_notification(struct wl_listener *listener, void *data) { - struct wlr_idle_timeout *timer = wl_container_of(listener, timer, input_listener); + struct wlr_idle_timeout *timer = + wl_container_of(listener, timer, input_listener); struct wlr_seat *seat = data; if (timer->seat == seat) { handle_activity(timer); @@ -72,13 +91,11 @@ static void handle_input_notification(struct wl_listener *listener, void *data) } static void create_idle_timer(struct wl_client *client, - struct wl_resource *idle_resource, - uint32_t id, - struct wl_resource *seat_resource, - uint32_t timeout) { - struct wlr_idle *idle = wl_resource_get_user_data(idle_resource); + struct wl_resource *idle_resource, uint32_t id, + struct wl_resource *seat_resource, uint32_t timeout) { + struct wlr_idle *idle = idle_from_resource(idle_resource); struct wlr_seat_client *client_seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); struct wlr_idle_timeout *timer = calloc(1, sizeof(struct wlr_idle_timeout)); @@ -122,7 +139,7 @@ static void create_idle_timer(struct wl_client *client, wl_event_source_timer_update(timer->idle_source, timer->timeout); } -static struct org_kde_kwin_idle_interface idle_impl = { +static const struct org_kde_kwin_idle_interface idle_impl = { .get_idle_timeout = create_idle_timer, }; diff --git a/types/wlr_output.c b/types/wlr_output.c index 504d0209..809b1959 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -17,7 +17,7 @@ static void wl_output_send_to_resource(struct wl_resource *resource) { assert(resource); - struct wlr_output *output = wl_resource_get_user_data(resource); + struct wlr_output *output = wlr_output_from_resource(resource); assert(output); const uint32_t version = wl_resource_get_version(resource); if (version >= WL_OUTPUT_GEOMETRY_SINCE_VERSION) { @@ -53,7 +53,7 @@ static void wl_output_send_to_resource(struct wl_resource *resource) { static void wlr_output_send_current_mode_to_resource( struct wl_resource *resource) { assert(resource); - struct wlr_output *output = wl_resource_get_user_data(resource); + struct wlr_output *output = wlr_output_from_resource(resource); assert(output); const uint32_t version = wl_resource_get_version(resource); if (version < WL_OUTPUT_MODE_SINCE_VERSION) { @@ -75,7 +75,7 @@ static void wlr_output_send_current_mode_to_resource( } static void wl_output_destroy(struct wl_resource *resource) { - struct wlr_output *output = wl_resource_get_user_data(resource); + struct wlr_output *output = wlr_output_from_resource(resource); struct wl_resource *_resource = NULL; wl_resource_for_each(_resource, &output->wl_resources) { if (_resource == resource) { @@ -648,6 +648,12 @@ void wlr_output_set_fullscreen_surface(struct wlr_output *output, &output->fullscreen_surface_destroy); } +struct wlr_output *wlr_output_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_output_interface, + &wl_output_impl)); + return wl_resource_get_user_data(resource); +} + static void output_cursor_damage_whole(struct wlr_output_cursor *cursor) { struct wlr_box box; diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c index 28fe63c1..c68d7696 100644 --- a/types/wlr_primary_selection.c +++ b/types/wlr_primary_selection.c @@ -9,10 +9,18 @@ #include #include "util/signal.h" +static const struct gtk_primary_selection_offer_interface offer_impl; + +static struct wlr_primary_selection_offer *offer_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + >k_primary_selection_offer_interface, &offer_impl)); + return wl_resource_get_user_data(resource); +} + static void offer_handle_receive(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd) { - struct wlr_primary_selection_offer *offer = - wl_resource_get_user_data(resource); + struct wlr_primary_selection_offer *offer = offer_from_resource(resource); if (offer->source && offer == offer->source->offer) { offer->source->send(offer->source, mime_type, fd); @@ -32,8 +40,7 @@ static const struct gtk_primary_selection_offer_interface offer_impl = { }; static void offer_resource_handle_destroy(struct wl_resource *resource) { - struct wlr_primary_selection_offer *offer = - wl_resource_get_user_data(resource); + struct wlr_primary_selection_offer *offer = offer_from_resource(resource); if (!offer->source) { goto out; @@ -122,9 +129,19 @@ static struct wlr_primary_selection_offer *source_send_offer( return offer; } +static const struct gtk_primary_selection_source_interface source_impl; + +static struct client_data_source *client_data_source_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + >k_primary_selection_source_interface, &source_impl)); + return wl_resource_get_user_data(resource); +} + static void source_handle_offer(struct wl_client *client, struct wl_resource *resource, const char *mime_type) { - struct client_data_source *source = wl_resource_get_user_data(resource); + struct client_data_source *source = + client_data_source_from_resource(resource); char **p = wl_array_add(&source->source.mime_types, sizeof(*p)); if (p) { @@ -150,7 +167,7 @@ static const struct gtk_primary_selection_source_interface source_impl = { static void source_resource_handle_destroy(struct wl_resource *resource) { struct client_data_source *source = - wl_resource_get_user_data(resource); + client_data_source_from_resource(resource); wlr_primary_selection_source_finish(&source->source); free(source); } @@ -241,11 +258,11 @@ static void device_handle_set_selection(struct wl_client *client, uint32_t serial) { struct client_data_source *source = NULL; if (source_resource != NULL) { - source = wl_resource_get_user_data(source_resource); + source = client_data_source_from_resource(source_resource); } struct wlr_seat_client *seat_client = - wl_resource_get_user_data(resource); + wlr_seat_client_from_resource(resource); struct wlr_primary_selection_source *wlr_source = (struct wlr_primary_selection_source *)source; @@ -317,7 +334,7 @@ void device_manager_handle_get_device(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *seat_resource) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); uint32_t version = wl_resource_get_version(manager_resource); struct wl_resource *resource = wl_resource_create(client, diff --git a/types/wlr_region.c b/types/wlr_region.c index 322088b5..6309c1a9 100644 --- a/types/wlr_region.c +++ b/types/wlr_region.c @@ -3,16 +3,17 @@ #include #include #include +#include static void region_add(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - pixman_region32_t *region = wl_resource_get_user_data(resource); + pixman_region32_t *region = wlr_region_from_resource(resource); pixman_region32_union_rect(region, region, x, y, width, height); } static void region_subtract(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - pixman_region32_t *region = wl_resource_get_user_data(resource); + pixman_region32_t *region = wlr_region_from_resource(resource); pixman_region32_union_rect(region, region, x, y, width, height); pixman_region32_t rect; @@ -25,14 +26,14 @@ static void region_destroy(struct wl_client *client, struct wl_resource *resourc wl_resource_destroy(resource); } -static const struct wl_region_interface region_interface = { +static const struct wl_region_interface region_impl = { .destroy = region_destroy, .add = region_add, .subtract = region_subtract, }; static void destroy_region(struct wl_resource *resource) { - pixman_region32_t *reg = wl_resource_get_user_data(resource); + pixman_region32_t *reg = wlr_region_from_resource(resource); pixman_region32_fini(reg); free(reg); } @@ -54,6 +55,12 @@ void wlr_region_create(struct wl_client *client, struct wl_resource *res, wl_resource_post_no_memory(res); return; } - wl_resource_set_implementation(region_resource, ®ion_interface, region, + wl_resource_set_implementation(region_resource, ®ion_impl, region, destroy_region); } + +pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_region_interface, + ®ion_impl)); + return wl_resource_get_user_data(resource); +} diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index 04757fb6..e756b6aa 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -9,6 +9,13 @@ #include #include "screenshooter-protocol.h" +static struct wlr_screenshot *screenshot_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &orbital_screenshot_interface, + NULL)); + return wl_resource_get_user_data(resource); +} + struct screenshot_state { struct wl_shm_buffer *shm_buffer; struct wlr_screenshot *screenshot; @@ -24,7 +31,7 @@ static void screenshot_destroy(struct wlr_screenshot *screenshot) { static void handle_screenshot_resource_destroy( struct wl_resource *screenshot_resource) { struct wlr_screenshot *screenshot = - wl_resource_get_user_data(screenshot_resource); + screenshot_from_resource(screenshot_resource); if (screenshot != NULL) { screenshot_destroy(screenshot); } @@ -59,13 +66,22 @@ cleanup: free(state); } +static const struct orbital_screenshooter_interface screenshooter_impl; + +static struct wlr_screenshooter *screenshooter_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &orbital_screenshooter_interface, + &screenshooter_impl)); + return wl_resource_get_user_data(resource); +} + static void screenshooter_shoot(struct wl_client *client, struct wl_resource *screenshooter_resource, uint32_t id, struct wl_resource *output_resource, struct wl_resource *buffer_resource) { struct wlr_screenshooter *screenshooter = - wl_resource_get_user_data(screenshooter_resource); - struct wlr_output *output = wl_resource_get_user_data(output_resource); + screenshooter_from_resource(screenshooter_resource); + struct wlr_output *output = wlr_output_from_resource(output_resource); struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); if (renderer == NULL) { @@ -133,7 +149,7 @@ static void screenshooter_shoot(struct wl_client *client, wlr_output_schedule_frame(output); } -static struct orbital_screenshooter_interface screenshooter_impl = { +static const struct orbital_screenshooter_interface screenshooter_impl = { .shoot = screenshooter_shoot, }; diff --git a/types/wlr_seat.c b/types/wlr_seat.c index d60e0e0d..93f6d872 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -23,15 +23,24 @@ static void pointer_send_frame(struct wl_resource *resource) { } } +static const struct wl_pointer_interface wl_pointer_impl; + +static struct wlr_seat_client *seat_client_from_pointer_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_pointer_interface, + &wl_pointer_impl)); + return wl_resource_get_user_data(resource); +} + static void wl_pointer_set_cursor(struct wl_client *client, struct wl_resource *pointer_resource, uint32_t serial, struct wl_resource *surface_resource, int32_t hotspot_x, int32_t hotspot_y) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(pointer_resource); + seat_client_from_pointer_resource(pointer_resource); struct wlr_surface *surface = NULL; if (surface_resource != NULL) { - surface = wl_resource_get_user_data(surface_resource); + surface = wlr_surface_from_resource(surface_resource); if (wlr_surface_set_role(surface, "wl_pointer-cursor", surface_resource, WL_POINTER_ERROR_ROLE) < 0) { @@ -67,7 +76,7 @@ static void wl_pointer_destroy(struct wl_resource *resource) { static void wl_seat_get_pointer(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) { return; } @@ -126,7 +135,7 @@ static void seat_client_send_repeat_info(struct wlr_seat_client *client, static void wl_seat_get_keyboard(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { return; } @@ -160,7 +169,7 @@ static void wl_touch_destroy(struct wl_resource *resource) { static void wl_seat_get_touch(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) { return; } @@ -177,7 +186,8 @@ static void wl_seat_get_touch(struct wl_client *client, } static void wlr_seat_client_resource_destroy(struct wl_resource *seat_resource) { - struct wlr_seat_client *client = wl_resource_get_user_data(seat_resource); + struct wlr_seat_client *client = + wlr_seat_client_from_resource(seat_resource); wlr_signal_emit_safe(&client->events.destroy, client); if (client == client->seat->pointer_state.focused_client) { @@ -1250,3 +1260,10 @@ bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial) { return serial == seat->pointer_state.grab_serial || serial == seat->touch_state.grab_serial; } + +struct wlr_seat_client *wlr_seat_client_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_seat_interface, + &wl_seat_impl)); + return wl_resource_get_user_data(resource); +} diff --git a/types/wlr_server_decoration.c b/types/wlr_server_decoration.c index 556193e2..2ab3b14c 100644 --- a/types/wlr_server_decoration.c +++ b/types/wlr_server_decoration.c @@ -6,6 +6,16 @@ #include #include "util/signal.h" +static const struct org_kde_kwin_server_decoration_interface + server_decoration_impl; + +static struct wlr_server_decoration *decoration_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &org_kde_kwin_server_decoration_interface, &server_decoration_impl)); + return wl_resource_get_user_data(resource); +} + static void server_decoration_handle_release(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -14,7 +24,7 @@ static void server_decoration_handle_release(struct wl_client *client, static void server_decoration_handle_request_mode(struct wl_client *client, struct wl_resource *resource, uint32_t mode) { struct wlr_server_decoration *decoration = - wl_resource_get_user_data(resource); + decoration_from_resource(resource); if (decoration->mode == mode) { return; } @@ -35,7 +45,7 @@ static void server_decoration_destroy( static void server_decoration_destroy_resource(struct wl_resource *resource) { struct wlr_server_decoration *decoration = - wl_resource_get_user_data(resource); + decoration_from_resource(resource); if (decoration != NULL) { server_decoration_destroy(decoration); } @@ -49,17 +59,28 @@ static void server_decoration_handle_surface_destroy( } static const struct org_kde_kwin_server_decoration_interface -server_decoration_impl = { + server_decoration_impl = { .release = server_decoration_handle_release, .request_mode = server_decoration_handle_request_mode, }; +static const struct org_kde_kwin_server_decoration_manager_interface + server_decoration_manager_impl; + +static struct wlr_server_decoration_manager *manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &org_kde_kwin_server_decoration_manager_interface, + &server_decoration_manager_impl)); + return wl_resource_get_user_data(resource); +} + static void server_decoration_manager_handle_create(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *surface_resource) { struct wlr_server_decoration_manager *manager = - wl_resource_get_user_data(manager_resource); - struct wlr_surface *surface = wl_resource_get_user_data(surface_resource); + manager_from_resource(manager_resource); + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); struct wlr_server_decoration *decoration = calloc(1, sizeof(struct wlr_server_decoration)); @@ -102,7 +123,7 @@ static void server_decoration_manager_handle_create(struct wl_client *client, } static const struct org_kde_kwin_server_decoration_manager_interface -server_decoration_manager_impl = { + server_decoration_manager_impl = { .create = server_decoration_manager_handle_create, }; diff --git a/types/wlr_surface.c b/types/wlr_surface.c index c47565c4..e2588167 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,7 @@ static void surface_destroy(struct wl_client *client, static void surface_attach(struct wl_client *client, struct wl_resource *resource, struct wl_resource *buffer, int32_t sx, int32_t sy) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending->invalid |= WLR_SURFACE_INVALID_BUFFER; surface->pending->sx = sx; @@ -62,7 +63,7 @@ static void surface_attach(struct wl_client *client, static void surface_damage(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); if (width < 0 || height < 0) { return; } @@ -72,15 +73,21 @@ static void surface_damage(struct wl_client *client, x, y, width, height); } +static struct wlr_frame_callback *frame_callback_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_callback_interface, NULL)); + return wl_resource_get_user_data(resource); +} + static void destroy_frame_callback(struct wl_resource *resource) { - struct wlr_frame_callback *cb = wl_resource_get_user_data(resource); + struct wlr_frame_callback *cb = frame_callback_from_resource(resource); wl_list_remove(&cb->link); free(cb); } static void surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); struct wlr_frame_callback *cb = calloc(1, sizeof(struct wlr_frame_callback)); @@ -97,8 +104,8 @@ static void surface_frame(struct wl_client *client, return; } - wl_resource_set_implementation(cb->resource, - NULL, cb, destroy_frame_callback); + wl_resource_set_implementation(cb->resource, NULL, cb, + destroy_frame_callback); wl_list_insert(surface->pending->frame_callback_list.prev, &cb->link); @@ -108,13 +115,13 @@ static void surface_frame(struct wl_client *client, static void surface_set_opaque_region(struct wl_client *client, struct wl_resource *resource, struct wl_resource *region_resource) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); if ((surface->pending->invalid & WLR_SURFACE_INVALID_OPAQUE_REGION)) { pixman_region32_clear(&surface->pending->opaque); } surface->pending->invalid |= WLR_SURFACE_INVALID_OPAQUE_REGION; if (region_resource) { - pixman_region32_t *region = wl_resource_get_user_data(region_resource); + pixman_region32_t *region = wlr_region_from_resource(region_resource); pixman_region32_copy(&surface->pending->opaque, region); } else { pixman_region32_clear(&surface->pending->opaque); @@ -124,10 +131,10 @@ static void surface_set_opaque_region(struct wl_client *client, static void surface_set_input_region(struct wl_client *client, struct wl_resource *resource, struct wl_resource *region_resource) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending->invalid |= WLR_SURFACE_INVALID_INPUT_REGION; if (region_resource) { - pixman_region32_t *region = wl_resource_get_user_data(region_resource); + pixman_region32_t *region = wlr_region_from_resource(region_resource); pixman_region32_copy(&surface->pending->input, region); } else { pixman_region32_init_rect(&surface->pending->input, @@ -465,7 +472,7 @@ static void wlr_subsurface_commit(struct wlr_subsurface *subsurface) { static void surface_commit(struct wl_client *client, struct wl_resource *resource) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); struct wlr_subsurface *subsurface = surface->subsurface; if (subsurface) { @@ -483,7 +490,7 @@ static void surface_commit(struct wl_client *client, static void surface_set_buffer_transform(struct wl_client *client, struct wl_resource *resource, int transform) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending->invalid |= WLR_SURFACE_INVALID_TRANSFORM; surface->pending->transform = transform; } @@ -491,7 +498,7 @@ static void surface_set_buffer_transform(struct wl_client *client, static void surface_set_buffer_scale(struct wl_client *client, struct wl_resource *resource, int32_t scale) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending->invalid |= WLR_SURFACE_INVALID_SCALE; surface->pending->scale = scale; } @@ -500,7 +507,7 @@ static void surface_damage_buffer(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); if (width < 0 || height < 0) { return; } @@ -523,6 +530,12 @@ const struct wl_surface_interface surface_interface = { .damage_buffer = surface_damage_buffer }; +struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_surface_interface, + &surface_interface)); + return wl_resource_get_user_data(resource); +} + static struct wlr_surface_state *wlr_surface_state_create() { struct wlr_surface_state *state = calloc(1, sizeof(struct wlr_surface_state)); @@ -578,7 +591,7 @@ void wlr_subsurface_destroy(struct wlr_subsurface *subsurface) { } static void destroy_surface(struct wl_resource *resource) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); wlr_signal_emit_safe(&surface->events.destroy, surface); if (surface->subsurface) { @@ -658,8 +671,17 @@ int wlr_surface_set_role(struct wlr_surface *surface, const char *role, return -1; } +static const struct wl_subsurface_interface subsurface_implementation; + +static struct wlr_subsurface *subsurface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_subsurface_interface, + &subsurface_implementation)); + return wl_resource_get_user_data(resource); +} + static void subsurface_resource_destroy(struct wl_resource *resource) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); if (subsurface) { wlr_subsurface_destroy(subsurface); @@ -673,7 +695,7 @@ static void subsurface_destroy(struct wl_client *client, static void subsurface_set_position(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); struct wlr_surface *surface = subsurface->surface; surface->pending->invalid |= WLR_SURFACE_INVALID_SUBSURFACE_POSITION; @@ -698,10 +720,10 @@ static struct wlr_subsurface *subsurface_find_sibling( static void subsurface_place_above(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); struct wlr_surface *sibling_surface = - wl_resource_get_user_data(sibling_resource); + wlr_surface_from_resource(sibling_resource); struct wlr_subsurface *sibling = subsurface_find_sibling(subsurface, sibling_surface); @@ -722,10 +744,10 @@ static void subsurface_place_above(struct wl_client *client, static void subsurface_place_below(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); struct wlr_surface *sibling_surface = - wl_resource_get_user_data(sibling_resource); + wlr_surface_from_resource(sibling_resource); struct wlr_subsurface *sibling = subsurface_find_sibling(subsurface, sibling_surface); @@ -746,7 +768,7 @@ static void subsurface_place_below(struct wl_client *client, static void subsurface_set_sync(struct wl_client *client, struct wl_resource *resource) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); if (subsurface) { subsurface->synchronized = true; @@ -755,7 +777,7 @@ static void subsurface_set_sync(struct wl_client *client, static void subsurface_set_desync(struct wl_client *client, struct wl_resource *resource) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); if (subsurface && subsurface->synchronized) { subsurface->synchronized = false; diff --git a/types/wlr_wl_shell.c b/types/wlr_wl_shell.c index 85749ddd..cac64c44 100644 --- a/types/wlr_wl_shell.c +++ b/types/wlr_wl_shell.c @@ -94,10 +94,19 @@ static const struct wlr_pointer_grab_interface shell_pointer_grab_impl = { .axis = shell_pointer_grab_axis, }; +static const struct wl_shell_surface_interface shell_surface_impl; + +static struct wlr_wl_shell_surface *shell_surface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_shell_surface_interface, + &shell_surface_impl)); + return wl_resource_get_user_data(resource); +} + static void shell_surface_protocol_pong(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { wlr_log(L_DEBUG, "got shell surface pong"); - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); if (surface->ping_serial != serial) { return; } @@ -109,9 +118,8 @@ static void shell_surface_protocol_pong(struct wl_client *client, static void shell_surface_protocol_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); - struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); + struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource); if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { wlr_log(L_DEBUG, "invalid serial for grab"); @@ -172,9 +180,8 @@ static void shell_surface_destroy_popup_state( static void shell_surface_protocol_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, enum wl_shell_surface_resize edges) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); - struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); + struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource); if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { wlr_log(L_DEBUG, "invalid serial for grab"); @@ -207,7 +214,7 @@ static void shell_surface_set_state(struct wlr_wl_shell_surface *surface, static void shell_surface_protocol_set_toplevel(struct wl_client *client, struct wl_resource *resource) { wlr_log(L_DEBUG, "got shell surface toplevel"); - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); shell_surface_set_state(surface, WLR_WL_SHELL_SURFACE_STATE_TOPLEVEL, NULL, NULL); } @@ -243,9 +250,8 @@ static void shell_surface_protocol_set_transient(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource, int32_t x, int32_t y, enum wl_shell_surface_transient flags) { wlr_log(L_DEBUG, "got shell surface transient"); - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); - struct wlr_surface *parent = - wl_resource_get_user_data(parent_resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); + struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); // TODO: check if parent_resource == NULL? struct wlr_wl_shell_surface *wl_parent = @@ -275,10 +281,10 @@ static void shell_surface_protocol_set_fullscreen(struct wl_client *client, struct wl_resource *resource, enum wl_shell_surface_fullscreen_method method, uint32_t framerate, struct wl_resource *output_resource) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); struct wlr_output *output = NULL; if (output_resource != NULL) { - output = wl_resource_get_user_data(output_resource); + output = wlr_output_from_resource(output_resource); } shell_surface_set_state(surface, WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN, @@ -298,11 +304,10 @@ static void shell_surface_protocol_set_popup(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, struct wl_resource *parent_resource, int32_t x, int32_t y, enum wl_shell_surface_transient flags) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); - struct wlr_surface *parent = - wl_resource_get_user_data(parent_resource); + wlr_seat_client_from_resource(seat_resource); + struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); struct wlr_wl_shell_popup_grab *grab = shell_popup_grab_from_seat(surface->shell, seat_client->seat); if (!grab) { @@ -355,10 +360,10 @@ static void shell_surface_protocol_set_popup(struct wl_client *client, static void shell_surface_protocol_set_maximized(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); struct wlr_output *output = NULL; if (output_resource != NULL) { - output = wl_resource_get_user_data(output_resource); + output = wlr_output_from_resource(output_resource); } shell_surface_set_state(surface, WLR_WL_SHELL_SURFACE_STATE_MAXIMIZED, @@ -375,7 +380,7 @@ static void shell_surface_protocol_set_maximized(struct wl_client *client, static void shell_surface_protocol_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { wlr_log(L_DEBUG, "new shell surface title: %s", title); - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); char *tmp = strdup(title); if (tmp == NULL) { @@ -391,7 +396,7 @@ static void shell_surface_protocol_set_title(struct wl_client *client, static void shell_surface_protocol_set_class(struct wl_client *client, struct wl_resource *resource, const char *class) { wlr_log(L_DEBUG, "new shell surface class: %s", class); - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); char *tmp = strdup(class); if (tmp == NULL) { @@ -439,7 +444,7 @@ static void shell_surface_destroy(struct wlr_wl_shell_surface *surface) { } static void shell_surface_resource_destroy(struct wl_resource *resource) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); if (surface != NULL) { shell_surface_destroy(surface); } @@ -480,16 +485,24 @@ static int shell_surface_ping_timeout(void *user_data) { return 1; } +static const struct wl_shell_interface shell_impl; + +static struct wlr_wl_shell *shell_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_shell_interface, &shell_impl)); + return wl_resource_get_user_data(resource); +} + static void shell_protocol_get_shell_surface(struct wl_client *client, struct wl_resource *shell_resource, uint32_t id, struct wl_resource *surface_resource) { - struct wlr_surface *surface = wl_resource_get_user_data(surface_resource); + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); if (wlr_surface_set_role(surface, wlr_wl_shell_surface_role, shell_resource, WL_SHELL_ERROR_ROLE)) { return; } - struct wlr_wl_shell *wl_shell = wl_resource_get_user_data(shell_resource); + struct wlr_wl_shell *wl_shell = shell_from_resource(shell_resource); struct wlr_wl_shell_surface *wl_surface = calloc(1, sizeof(struct wlr_wl_shell_surface)); if (wl_surface == NULL) { @@ -548,7 +561,7 @@ static void shell_protocol_get_shell_surface(struct wl_client *client, wl_list_insert(&wl_shell->surfaces, &wl_surface->link); } -static struct wl_shell_interface shell_impl = { +static const struct wl_shell_interface shell_impl = { .get_shell_surface = shell_protocol_get_shell_surface }; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index eb18f022..1ea29664 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -223,9 +223,19 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { } +static const struct zxdg_positioner_v6_interface + zxdg_positioner_v6_implementation; + +static struct wlr_xdg_positioner_v6 *xdg_positioner_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zxdg_positioner_v6_interface, + &zxdg_positioner_v6_implementation)); + return wl_resource_get_user_data(resource); +} + static void xdg_positioner_destroy(struct wl_resource *resource) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); free(positioner); } @@ -233,7 +243,7 @@ static void xdg_positioner_destroy(struct wl_resource *resource) { static void xdg_positioner_protocol_set_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (width < 1 || height < 1) { wl_resource_post_error(resource, @@ -250,7 +260,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (width < 1 || height < 1) { wl_resource_post_error(resource, @@ -268,7 +278,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, static void xdg_positioner_protocol_set_anchor(struct wl_client *client, struct wl_resource *resource, uint32_t anchor) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (((anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP ) && (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) || @@ -286,7 +296,7 @@ static void xdg_positioner_protocol_set_anchor(struct wl_client *client, static void xdg_positioner_protocol_set_gravity(struct wl_client *client, struct wl_resource *resource, uint32_t gravity) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (((gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) && (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) || @@ -305,7 +315,7 @@ static void xdg_positioner_protocol_set_constraint_adjustment( struct wl_client *client, struct wl_resource *resource, uint32_t constraint_adjustment) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); positioner->constraint_adjustment = constraint_adjustment; } @@ -313,7 +323,7 @@ static void xdg_positioner_protocol_set_constraint_adjustment( static void xdg_positioner_protocol_set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); positioner->offset.x = x; positioner->offset.y = y; @@ -355,52 +365,6 @@ static void xdg_shell_create_positioner(struct wl_client *wl_client, positioner, xdg_positioner_destroy); } -static void xdg_popup_protocol_grab(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_seat_client *seat_client = wl_resource_get_user_data(seat_resource); - - if (surface->popup_state->committed) { - wl_resource_post_error(surface->popup_state->resource, - ZXDG_POPUP_V6_ERROR_INVALID_GRAB, - "xdg_popup is already mapped"); - return; - } - - struct wlr_xdg_popup_grab_v6 *popup_grab = - xdg_shell_popup_grab_from_seat(surface->client->shell, - seat_client->seat); - - struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(popup_grab); - bool parent_is_toplevel = - surface->popup_state->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; - - if ((topmost == NULL && !parent_is_toplevel) || - (topmost != NULL && topmost != surface->popup_state->parent)) { - wl_resource_post_error(surface->client->resource, - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, - "xdg_popup was not created on the topmost popup"); - return; - } - - popup_grab->client = surface->client->client; - surface->popup_state->seat = seat_client->seat; - - wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); - - wlr_seat_pointer_start_grab(seat_client->seat, - &popup_grab->pointer_grab); - wlr_seat_keyboard_start_grab(seat_client->seat, - &popup_grab->keyboard_grab); -} - -static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = { - .destroy = resource_destroy, - .grab = xdg_popup_protocol_grab, -}; - - static struct wlr_box xdg_positioner_get_geometry( struct wlr_xdg_positioner_v6 *positioner, struct wlr_xdg_surface_v6 *surface, struct wlr_xdg_surface_v6 *parent) { @@ -456,23 +420,89 @@ static struct wlr_box xdg_positioner_get_geometry( return geometry; } + +static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation; + +static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_popup_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zxdg_popup_v6_interface, + &zxdg_popup_v6_implementation)); + return wl_resource_get_user_data(resource); +} + +static void xdg_popup_protocol_grab(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial) { + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_popup_resource(resource); + struct wlr_seat_client *seat_client = + wlr_seat_client_from_resource(seat_resource); + + if (surface->popup_state->committed) { + wl_resource_post_error(surface->popup_state->resource, + ZXDG_POPUP_V6_ERROR_INVALID_GRAB, + "xdg_popup is already mapped"); + return; + } + + struct wlr_xdg_popup_grab_v6 *popup_grab = + xdg_shell_popup_grab_from_seat(surface->client->shell, + seat_client->seat); + + struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(popup_grab); + bool parent_is_toplevel = + surface->popup_state->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; + + if ((topmost == NULL && !parent_is_toplevel) || + (topmost != NULL && topmost != surface->popup_state->parent)) { + wl_resource_post_error(surface->client->resource, + ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was not created on the topmost popup"); + return; + } + + popup_grab->client = surface->client->client; + surface->popup_state->seat = seat_client->seat; + + wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); + + wlr_seat_pointer_start_grab(seat_client->seat, + &popup_grab->pointer_grab); + wlr_seat_keyboard_start_grab(seat_client->seat, + &popup_grab->keyboard_grab); +} + +static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = { + .destroy = resource_destroy, + .grab = xdg_popup_protocol_grab, +}; + static void xdg_popup_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_popup_resource(resource); if (surface != NULL) { xdg_surface_destroy(surface); } } +static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation; + +static struct wlr_xdg_surface_v6 *xdg_surface_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zxdg_surface_v6_interface, + &zxdg_surface_v6_implementation)); + return wl_resource_get_user_data(resource); +} + static void xdg_surface_get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent_resource, struct wl_resource *positioner_resource) { struct wlr_xdg_surface_v6 *surface = - wl_resource_get_user_data(resource); + xdg_surface_from_resource(resource); struct wlr_xdg_surface_v6 *parent = - wl_resource_get_user_data(parent_resource); + xdg_surface_from_resource(parent_resource); struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(positioner_resource); + xdg_positioner_from_resource(positioner_resource); if (positioner->size.width == 0 || positioner->anchor_rect.width == 0) { wl_resource_post_error(resource, @@ -516,13 +546,23 @@ static void xdg_surface_get_popup(struct wl_client *client, } +static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation; + +static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_toplevel_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zxdg_toplevel_v6_interface, + &zxdg_toplevel_v6_implementation)); + return wl_resource_get_user_data(resource); +} + static void xdg_toplevel_protocol_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_xdg_surface_v6 *parent = NULL; + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + struct wlr_xdg_surface_v6 *parent = NULL; if (parent_resource != NULL) { - parent = wl_resource_get_user_data(parent_resource); + parent = xdg_surface_from_xdg_toplevel_resource(parent_resource); } surface->toplevel_state->parent = parent; @@ -530,10 +570,10 @@ static void xdg_toplevel_protocol_set_parent(struct wl_client *client, static void xdg_toplevel_protocol_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - char *tmp; + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); - tmp = strdup(title); + char *tmp = strdup(title); if (tmp == NULL) { return; } @@ -544,10 +584,10 @@ static void xdg_toplevel_protocol_set_title(struct wl_client *client, static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - char *tmp; + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); - tmp = strdup(app_id); + char *tmp = strdup(app_id); if (tmp == NULL) { return; } @@ -559,9 +599,10 @@ static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { wl_resource_post_error(surface->toplevel_state->resource, @@ -589,9 +630,10 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, static void xdg_toplevel_protocol_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { wl_resource_post_error(surface->toplevel_state->resource, @@ -617,9 +659,10 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, static void xdg_toplevel_protocol_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { wl_resource_post_error(surface->toplevel_state->resource, @@ -645,39 +688,44 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.max_width = width; surface->toplevel_state->next.max_height = height; } static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.min_width = width; surface->toplevel_state->next.min_height = height; } static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.maximized = true; wlr_signal_emit_safe(&surface->events.request_maximize, surface); } static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.maximized = false; wlr_signal_emit_safe(&surface->events.request_maximize, surface); } static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_output *output = NULL; if (output_resource != NULL) { - output = wl_resource_get_user_data(output_resource); + output = wlr_output_from_resource(output_resource); } surface->toplevel_state->next.fullscreen = true; @@ -693,7 +741,8 @@ static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.fullscreen = false; @@ -708,7 +757,8 @@ static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); wlr_signal_emit_safe(&surface->events.request_minimize, surface); } @@ -731,14 +781,15 @@ static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = }; static void xdg_surface_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); if (surface != NULL) { xdg_surface_destroy(surface); } } static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); if (surface != NULL) { xdg_surface_destroy(surface); } @@ -746,7 +797,7 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { static void xdg_surface_get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role, resource, ZXDG_SHELL_V6_ERROR_ROLE)) { @@ -788,7 +839,7 @@ static void wlr_xdg_toplevel_v6_ack_configure( static void xdg_surface_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { wl_resource_post_error(surface->resource, @@ -838,7 +889,7 @@ static void xdg_surface_ack_configure(struct wl_client *client, static void xdg_surface_set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { wl_resource_post_error(surface->resource, @@ -1128,11 +1179,20 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, } } +static const struct zxdg_shell_v6_interface xdg_shell_impl; + +static struct wlr_xdg_client_v6 *xdg_client_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zxdg_shell_v6_interface, + &xdg_shell_impl)); + return wl_resource_get_user_data(resource); +} + static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, struct wl_resource *client_resource, uint32_t id, struct wl_resource *surface_resource) { struct wlr_xdg_client_v6 *client = - wl_resource_get_user_data(client_resource); + xdg_client_from_resource(client_resource); struct wlr_xdg_surface_v6 *surface; if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface_v6)))) { @@ -1155,7 +1215,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, surface->client = client; surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; - surface->surface = wl_resource_get_user_data(surface_resource); + surface->surface = wlr_surface_from_resource(surface_resource); surface->resource = wl_resource_create(wl_client, &zxdg_surface_v6_interface, wl_resource_get_version(client_resource), id); @@ -1206,7 +1266,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, static void xdg_shell_pong(struct wl_client *wl_client, struct wl_resource *resource, uint32_t serial) { - struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); + struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); if (client->ping_serial != serial) { return; @@ -1216,7 +1276,7 @@ static void xdg_shell_pong(struct wl_client *wl_client, client->ping_serial = 0; } -static struct zxdg_shell_v6_interface xdg_shell_impl = { +static const struct zxdg_shell_v6_interface xdg_shell_impl = { .destroy = resource_destroy, .create_positioner = xdg_shell_create_positioner, .get_xdg_surface = xdg_shell_get_xdg_surface, @@ -1224,7 +1284,7 @@ static struct zxdg_shell_v6_interface xdg_shell_impl = { }; static void wlr_xdg_client_v6_destroy(struct wl_resource *resource) { - struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); + struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); struct wlr_xdg_surface_v6 *surface, *tmp = NULL; wl_list_for_each_safe(surface, tmp, &client->surfaces, link) { diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 10bc2e30..94dfdaab 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -742,7 +742,7 @@ static void xwm_handle_surface_id_message(struct wlr_xwm *xwm, struct wl_resource *resource = wl_client_get_object(xwm->xwayland->client, id); if (resource) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); xsurface->surface_id = 0; xwm_map_shell_surface(xwm, xsurface, surface); } else { From 7d26a6debd6e9808d4a4bf7d39b71ad5f5031f79 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 14 Feb 2018 12:40:13 +0100 Subject: [PATCH 02/13] xdg-shell stable: copy-pasta implementation --- include/rootston/desktop.h | 4 + include/rootston/view.h | 26 + include/wlr/types/wlr_xdg_shell.h | 232 +++++ protocol/meson.build | 2 + rootston/desktop.c | 6 + rootston/meson.build | 1 + rootston/output.c | 37 + rootston/xdg_shell.c | 363 +++++++ types/meson.build | 1 + types/wlr_xdg_shell.c | 1457 +++++++++++++++++++++++++++++ 10 files changed, 2129 insertions(+) create mode 100644 include/wlr/types/wlr_xdg_shell.h create mode 100644 rootston/xdg_shell.c create mode 100644 types/wlr_xdg_shell.c diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 6572b242..0132a7e8 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "rootston/config.h" #include "rootston/output.h" #include "rootston/view.h" @@ -34,6 +35,7 @@ struct roots_desktop { struct wlr_compositor *compositor; struct wlr_wl_shell *wl_shell; struct wlr_xdg_shell_v6 *xdg_shell_v6; + struct wlr_xdg_shell *xdg_shell; struct wlr_gamma_control_manager *gamma_control_manager; struct wlr_screenshooter *screenshooter; struct wlr_server_decoration_manager *server_decoration_manager; @@ -43,6 +45,7 @@ struct roots_desktop { struct wl_listener new_output; struct wl_listener layout_change; struct wl_listener xdg_shell_v6_surface; + struct wl_listener xdg_shell_surface; struct wl_listener wl_shell_surface; struct wl_listener decoration_new; @@ -72,6 +75,7 @@ void view_update_position(struct roots_view *view, double x, double y); void view_update_size(struct roots_view *view, uint32_t width, uint32_t height); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); +void handle_xdg_shell_surface(struct wl_listener *listener, void *data); void handle_wl_shell_surface(struct wl_listener *listener, void *data); void handle_xwayland_surface(struct wl_listener *listener, void *data); diff --git a/include/rootston/view.h b/include/rootston/view.h index b61ac330..198086c1 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -6,6 +6,7 @@ #include #include #include +#include struct roots_wl_shell_surface { struct roots_view *view; @@ -36,6 +37,21 @@ struct roots_xdg_surface_v6 { uint32_t pending_move_resize_configure_serial; }; +struct roots_xdg_surface { + struct roots_view *view; + + struct wl_listener destroy; + struct wl_listener new_popup; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener request_fullscreen; + + struct wl_listener surface_commit; + + uint32_t pending_move_resize_configure_serial; +}; + struct roots_xwayland_surface { struct roots_view *view; @@ -54,6 +70,7 @@ struct roots_xwayland_surface { enum roots_view_type { ROOTS_WL_SHELL_VIEW, ROOTS_XDG_SHELL_V6_VIEW, + ROOTS_XDG_SHELL_VIEW, #ifdef WLR_HAS_XWAYLAND ROOTS_XWAYLAND_VIEW, #endif @@ -90,6 +107,7 @@ struct roots_view { union { struct wlr_wl_shell_surface *wl_shell_surface; struct wlr_xdg_surface_v6 *xdg_surface_v6; + struct wlr_xdg_surface *xdg_surface; #ifdef WLR_HAS_XWAYLAND struct wlr_xwayland_surface *xwayland_surface; #endif @@ -97,6 +115,7 @@ struct roots_view { union { struct roots_wl_shell_surface *roots_wl_shell_surface; struct roots_xdg_surface_v6 *roots_xdg_surface_v6; + struct roots_xdg_surface *roots_xdg_surface; #ifdef WLR_HAS_XWAYLAND struct roots_xwayland_surface *roots_xwayland_surface; #endif @@ -154,6 +173,13 @@ struct roots_xdg_popup_v6 { struct wl_listener new_popup; }; +struct roots_xdg_popup { + struct roots_view_child view_child; + struct wlr_xdg_popup *wlr_popup; + struct wl_listener destroy; + struct wl_listener new_popup; +}; + void view_get_box(const struct roots_view *view, struct wlr_box *box); void view_activate(struct roots_view *view, bool active); void view_move(struct roots_view *view, double x, double y); diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h new file mode 100644 index 00000000..8422863c --- /dev/null +++ b/include/wlr/types/wlr_xdg_shell.h @@ -0,0 +1,232 @@ +#ifndef WLR_TYPES_WLR_XDG_SHELL_H +#define WLR_TYPES_WLR_XDG_SHELL_H + +#include +#include +#include + +struct wlr_xdg_shell { + struct wl_global *wl_global; + struct wl_list clients; + struct wl_list popup_grabs; + uint32_t ping_timeout; + + struct wl_listener display_destroy; + + struct { + struct wl_signal new_surface; + } events; + + void *data; +}; + +struct wlr_xdg_client { + struct wlr_xdg_shell *shell; + struct wl_resource *resource; + struct wl_client *client; + struct wl_list surfaces; + + struct wl_list link; // wlr_xdg_shell::clients + + uint32_t ping_serial; + struct wl_event_source *ping_timer; +}; + +struct wlr_xdg_popup { + struct wlr_xdg_surface *base; + struct wl_list link; + + struct wl_resource *resource; + bool committed; + struct wlr_xdg_surface *parent; + struct wlr_seat *seat; + struct wlr_box geometry; + + struct wl_list grab_link; // wlr_xdg_popup_grab::popups +}; + +// each seat gets a popup grab +struct wlr_xdg_popup_grab { + struct wl_client *client; + struct wlr_seat_pointer_grab pointer_grab; + struct wlr_seat_keyboard_grab keyboard_grab; + struct wlr_seat *seat; + struct wl_list popups; + struct wl_list link; // wlr_xdg_shell::popup_grabs +}; + +enum wlr_xdg_surface_role { + WLR_XDG_SURFACE_ROLE_NONE, + WLR_XDG_SURFACE_ROLE_TOPLEVEL, + WLR_XDG_SURFACE_ROLE_POPUP, +}; + +struct wlr_xdg_toplevel_state { + bool maximized; + bool fullscreen; + bool resizing; + bool activated; + + uint32_t width; + uint32_t height; + + uint32_t max_width; + uint32_t max_height; + + uint32_t min_width; + uint32_t min_height; +}; + +struct wlr_xdg_toplevel { + struct wl_resource *resource; + struct wlr_xdg_surface *base; + struct wlr_xdg_surface *parent; + 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 current; +}; + +struct wlr_xdg_surface_configure { + struct wl_list link; // wlr_xdg_surface::configure_list + uint32_t serial; + struct wlr_xdg_toplevel_state state; +}; + +struct wlr_xdg_surface { + struct wlr_xdg_client *client; + struct wl_resource *resource; + struct wlr_surface *surface; + struct wl_list link; // wlr_xdg_client::surfaces + enum wlr_xdg_surface_role role; + + union { + struct wlr_xdg_toplevel *toplevel_state; + struct wlr_xdg_popup *popup_state; + }; + + struct wl_list popups; // wlr_xdg_popup::link + + bool configured; + bool added; + uint32_t configure_serial; + struct wl_event_source *configure_idle; + uint32_t configure_next_serial; + struct wl_list configure_list; + + char *title; + char *app_id; + + bool has_next_geometry; + struct wlr_box *next_geometry; + struct wlr_box *geometry; + + struct wl_listener surface_destroy_listener; + + struct { + struct wl_signal destroy; + struct wl_signal ping_timeout; + struct wl_signal new_popup; + + struct wl_signal request_maximize; + struct wl_signal request_fullscreen; + struct wl_signal request_minimize; + struct wl_signal request_move; + struct wl_signal request_resize; + struct wl_signal request_show_window_menu; + } events; + + void *data; +}; + +struct wlr_xdg_toplevel_move_event { + struct wlr_xdg_surface *surface; + struct wlr_seat_client *seat; + uint32_t serial; +}; + +struct wlr_xdg_toplevel_resize_event { + struct wlr_xdg_surface *surface; + struct wlr_seat_client *seat; + uint32_t serial; + uint32_t edges; +}; + +struct wlr_xdg_toplevel_set_fullscreen_event { + struct wlr_xdg_surface *surface; + bool fullscreen; + struct wlr_output *output; +}; + +struct wlr_xdg_toplevel_show_window_menu_event { + struct wlr_xdg_surface *surface; + struct wlr_seat_client *seat; + uint32_t serial; + uint32_t x, y; +}; + +struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display); +void wlr_xdg_shell_destroy(struct wlr_xdg_shell *xdg_shell); + +/** + * Send a ping to the surface. If the surface does not respond in a reasonable + * amount of time, the ping_timeout event will be emitted. + */ +void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface); + +/** + * Request that this toplevel surface be the given size. Returns the associated + * configure serial. + */ +uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface, + uint32_t width, uint32_t height); + +/** + * Request that this toplevel surface show itself in an activated or deactivated + * state. Returns the associated configure serial. + */ +uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface, + bool activated); + +/** + * Request that this toplevel surface consider itself maximized or not + * maximized. Returns the associated configure serial. + */ +uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface, + bool maximized); + +/** + * Request that this toplevel surface consider itself fullscreen or not + * fullscreen. Returns the associated configure serial. + */ +uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface, + bool fullscreen); + +/** + * Request that this toplevel surface consider itself to be resizing or not + * resizing. Returns the associated configure serial. + */ +uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface, + bool resizing); + +/** + * Request that this toplevel surface closes. + */ +void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface); + +/** + * Compute the popup position in surface-local coordinates. + */ +void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface, + double *popup_sx, double *popup_sy); + +/** + * Find a popup within this surface at the surface-local coordinates. Returns + * the popup and coordinates in the topmost surface coordinate system or NULL if + * no popup is found at that location. + */ +struct wlr_xdg_surface *wlr_xdg_surface_popup_at( + struct wlr_xdg_surface *surface, double sx, double sy, + double *popup_sx, double *popup_sy); + +#endif diff --git a/protocol/meson.build b/protocol/meson.build index 0db7c03c..514a6dde 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -22,6 +22,7 @@ wayland_scanner_client = generator( protocols = [ [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], + [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], 'gamma-control.xml', 'gtk-primary-selection.xml', 'idle.xml', @@ -31,6 +32,7 @@ protocols = [ client_protocols = [ [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], + [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], 'gamma-control.xml', 'gtk-primary-selection.xml', 'idle.xml', diff --git a/rootston/desktop.c b/rootston/desktop.c index 80ccbc25..6b28a41c 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "rootston/seat.h" #include "rootston/server.h" @@ -639,6 +640,11 @@ struct roots_desktop *desktop_create(struct roots_server *server, &desktop->xdg_shell_v6_surface); desktop->xdg_shell_v6_surface.notify = handle_xdg_shell_v6_surface; + desktop->xdg_shell = wlr_xdg_shell_create(server->wl_display); + wl_signal_add(&desktop->xdg_shell->events.new_surface, + &desktop->xdg_shell_surface); + desktop->xdg_shell_surface.notify = handle_xdg_shell_surface; + desktop->wl_shell = wlr_wl_shell_create(server->wl_display); wl_signal_add(&desktop->wl_shell->events.new_surface, &desktop->wl_shell_surface); diff --git a/rootston/meson.build b/rootston/meson.build index a53812e3..9dbe37c2 100644 --- a/rootston/meson.build +++ b/rootston/meson.build @@ -10,6 +10,7 @@ sources = [ 'seat.c', 'wl_shell.c', 'xdg_shell_v6.c', + 'xdg_shell.c', ] if get_option('enable_xwayland') sources += ['xwayland.c'] diff --git a/rootston/output.c b/rootston/output.c index 1ea4412e..8ef383c3 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include "rootston/config.h" @@ -81,6 +82,34 @@ static void xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, } } +static void xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, + double base_x, double base_y, float rotation, + surface_iterator_func_t iterator, void *user_data) { + double width = surface->surface->current->width; + double height = surface->surface->current->height; + + 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_width = popup->surface->current->width; + double popup_height = popup->surface->current->height; + + double popup_sx, popup_sy; + wlr_xdg_surface_popup_get_position(popup, &popup_sx, &popup_sy); + rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, + width, height, rotation); + + surface_for_each_surface(popup->surface, base_x + popup_sx, + base_y + popup_sy, rotation, iterator, user_data); + xdg_surface_for_each_surface(popup, base_x + popup_sx, + base_y + popup_sy, rotation, iterator, user_data); + } +} + static void wl_shell_surface_for_each_surface( struct wlr_wl_shell_surface *surface, double lx, double ly, float rotation, bool is_child, surface_iterator_func_t iterator, @@ -117,6 +146,12 @@ static void view_for_each_surface(struct roots_view *view, xdg_surface_v6_for_each_surface(view->xdg_surface_v6, view->x, view->y, view->rotation, iterator, user_data); break; + case ROOTS_XDG_SHELL_VIEW: + surface_for_each_surface(view->wlr_surface, view->x, view->y, + view->rotation, iterator, user_data); + xdg_surface_for_each_surface(view->xdg_surface, view->x, view->y, + view->rotation, iterator, user_data); + break; case ROOTS_WL_SHELL_VIEW: wl_shell_surface_for_each_surface(view->wl_shell_surface, view->x, view->y, view->rotation, false, iterator, user_data); @@ -337,6 +372,8 @@ static bool has_standalone_surface(struct roots_view *view) { switch (view->type) { case ROOTS_XDG_SHELL_V6_VIEW: return wl_list_empty(&view->xdg_surface_v6->popups); + case ROOTS_XDG_SHELL_VIEW: + return wl_list_empty(&view->xdg_surface->popups); case ROOTS_WL_SHELL_VIEW: return wl_list_empty(&view->wl_shell_surface->popups); #ifdef WLR_HAS_XWAYLAND diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c new file mode 100644 index 00000000..8340de46 --- /dev/null +++ b/rootston/xdg_shell.c @@ -0,0 +1,363 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "rootston/desktop.h" +#include "rootston/input.h" +#include "rootston/server.h" + +static void popup_destroy(struct roots_view_child *child) { + assert(child->destroy == popup_destroy); + struct roots_xdg_popup *popup = (struct roots_xdg_popup *)child; + if (popup == NULL) { + return; + } + wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->new_popup.link); + view_child_finish(&popup->view_child); + free(popup); +} + +static void popup_handle_destroy(struct wl_listener *listener, void *data) { + struct roots_xdg_popup *popup = + wl_container_of(listener, popup, destroy); + popup_destroy((struct roots_view_child *)popup); +} + +static struct roots_xdg_popup *popup_create(struct roots_view *view, + struct wlr_xdg_popup *wlr_popup); + +static void popup_handle_new_popup(struct wl_listener *listener, void *data) { + struct roots_xdg_popup *popup = + wl_container_of(listener, popup, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + popup_create(popup->view_child.view, wlr_popup); +} + +static struct roots_xdg_popup *popup_create(struct roots_view *view, + struct wlr_xdg_popup *wlr_popup) { + struct roots_xdg_popup *popup = + calloc(1, sizeof(struct roots_xdg_popup)); + if (popup == NULL) { + return NULL; + } + popup->wlr_popup = wlr_popup; + popup->view_child.destroy = popup_destroy; + view_child_init(&popup->view_child, view, wlr_popup->base->surface); + popup->destroy.notify = popup_handle_destroy; + wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); + popup->new_popup.notify = popup_handle_new_popup; + wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); + return popup; +} + + +static void get_size(const struct roots_view *view, struct wlr_box *box) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + + if (surface->geometry->width > 0 && surface->geometry->height > 0) { + box->width = surface->geometry->width; + box->height = surface->geometry->height; + } else { + box->width = view->wlr_surface->current->width; + box->height = view->wlr_surface->current->height; + } +} + +static void activate(struct roots_view *view, bool active) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + wlr_xdg_toplevel_set_activated(surface, active); + } +} + +static void apply_size_constraints(struct wlr_xdg_surface *surface, + uint32_t width, uint32_t height, uint32_t *dest_width, + uint32_t *dest_height) { + *dest_width = width; + *dest_height = height; + + struct wlr_xdg_toplevel_state *state = &surface->toplevel_state->current; + if (width < state->min_width) { + *dest_width = state->min_width; + } else if (state->max_width > 0 && + width > state->max_width) { + *dest_width = state->max_width; + } + if (height < state->min_height) { + *dest_height = state->min_height; + } else if (state->max_height > 0 && + height > state->max_height) { + *dest_height = state->max_height; + } +} + +static void resize(struct roots_view *view, uint32_t width, uint32_t height) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + uint32_t constrained_width, constrained_height; + apply_size_constraints(surface, width, height, &constrained_width, + &constrained_height); + + wlr_xdg_toplevel_set_size(surface, constrained_width, + constrained_height); +} + +static void move_resize(struct roots_view *view, double x, double y, + uint32_t width, uint32_t height) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct roots_xdg_surface *roots_surface = view->roots_xdg_surface; + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + bool update_x = x != view->x; + bool update_y = y != view->y; + + uint32_t constrained_width, constrained_height; + apply_size_constraints(surface, width, height, &constrained_width, + &constrained_height); + + if (update_x) { + x = x + width - constrained_width; + } + if (update_y) { + y = y + height - constrained_height; + } + + view->pending_move_resize.update_x = update_x; + view->pending_move_resize.update_y = update_y; + view->pending_move_resize.x = x; + view->pending_move_resize.y = y; + view->pending_move_resize.width = constrained_width; + view->pending_move_resize.height = constrained_height; + + uint32_t serial = wlr_xdg_toplevel_set_size(surface, constrained_width, + constrained_height); + if (serial > 0) { + roots_surface->pending_move_resize_configure_serial = serial; + } else if (roots_surface->pending_move_resize_configure_serial == 0) { + view_update_position(view, x, y); + } +} + +static void maximize(struct roots_view *view, bool maximized) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + wlr_xdg_toplevel_set_maximized(surface, maximized); +} + +static void set_fullscreen(struct roots_view *view, bool fullscreen) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + wlr_xdg_toplevel_set_fullscreen(surface, fullscreen); +} + +static void close(struct roots_view *view) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + wlr_xdg_toplevel_send_close(surface); + } +} + +static void handle_request_move(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, request_move); + struct roots_view *view = roots_xdg_surface->view; + struct roots_input *input = view->desktop->server->input; + struct wlr_xdg_toplevel_move_event *e = data; + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + // TODO verify event serial + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { + return; + } + roots_seat_begin_move(seat, view); +} + +static void handle_request_resize(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, request_resize); + struct roots_view *view = roots_xdg_surface->view; + struct roots_input *input = view->desktop->server->input; + struct wlr_xdg_toplevel_resize_event *e = data; + // TODO verify event serial + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + assert(seat); + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { + return; + } + roots_seat_begin_resize(seat, view, e->edges); +} + +static void handle_request_maximize(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, request_maximize); + struct roots_view *view = roots_xdg_surface->view; + struct wlr_xdg_surface *surface = view->xdg_surface; + + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + view_maximize(view, surface->toplevel_state->next.maximized); +} + +static void handle_request_fullscreen(struct wl_listener *listener, + void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, request_fullscreen); + struct roots_view *view = roots_xdg_surface->view; + struct wlr_xdg_surface *surface = view->xdg_surface; + struct wlr_xdg_toplevel_set_fullscreen_event *e = data; + + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + view_set_fullscreen(view, e->fullscreen, e->output); +} + +static void handle_surface_commit(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_surface = + wl_container_of(listener, roots_surface, surface_commit); + struct roots_view *view = roots_surface->view; + struct wlr_xdg_surface *surface = view->xdg_surface; + + view_apply_damage(view); + + struct wlr_box size; + get_size(view, &size); + view_update_size(view, size.width, size.height); + + uint32_t pending_serial = + roots_surface->pending_move_resize_configure_serial; + if (pending_serial > 0 && pending_serial >= surface->configure_serial) { + double x = view->x; + double y = view->y; + if (view->pending_move_resize.update_x) { + x = view->pending_move_resize.x + view->pending_move_resize.width - + size.width; + } + if (view->pending_move_resize.update_y) { + y = view->pending_move_resize.y + view->pending_move_resize.height - + size.height; + } + view_update_position(view, x, y); + + if (pending_serial == surface->configure_serial) { + roots_surface->pending_move_resize_configure_serial = 0; + } + } +} + +static void handle_new_popup(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + popup_create(roots_xdg_surface->view, wlr_popup); +} + +static void handle_destroy(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, destroy); + wl_list_remove(&roots_xdg_surface->surface_commit.link); + wl_list_remove(&roots_xdg_surface->destroy.link); + wl_list_remove(&roots_xdg_surface->new_popup.link); + wl_list_remove(&roots_xdg_surface->request_move.link); + wl_list_remove(&roots_xdg_surface->request_resize.link); + wl_list_remove(&roots_xdg_surface->request_maximize.link); + wl_list_remove(&roots_xdg_surface->request_fullscreen.link); + wl_list_remove(&roots_xdg_surface->view->link); + view_finish(roots_xdg_surface->view); + free(roots_xdg_surface->view); + free(roots_xdg_surface); +} + +void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { + struct wlr_xdg_surface *surface = data; + assert(surface->role != WLR_XDG_SURFACE_ROLE_NONE); + + if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + wlr_log(L_DEBUG, "new xdg popup"); + return; + } + + struct roots_desktop *desktop = + wl_container_of(listener, desktop, xdg_shell_surface); + + wlr_log(L_DEBUG, "new xdg toplevel: title=%s, app_id=%s", + surface->title, surface->app_id); + wlr_xdg_surface_ping(surface); + + struct roots_xdg_surface *roots_surface = + calloc(1, sizeof(struct roots_xdg_surface)); + if (!roots_surface) { + return; + } + roots_surface->surface_commit.notify = handle_surface_commit; + wl_signal_add(&surface->surface->events.commit, + &roots_surface->surface_commit); + roots_surface->destroy.notify = handle_destroy; + wl_signal_add(&surface->events.destroy, &roots_surface->destroy); + roots_surface->request_move.notify = handle_request_move; + wl_signal_add(&surface->events.request_move, &roots_surface->request_move); + roots_surface->request_resize.notify = handle_request_resize; + wl_signal_add(&surface->events.request_resize, + &roots_surface->request_resize); + roots_surface->request_maximize.notify = handle_request_maximize; + wl_signal_add(&surface->events.request_maximize, + &roots_surface->request_maximize); + roots_surface->request_fullscreen.notify = handle_request_fullscreen; + wl_signal_add(&surface->events.request_fullscreen, + &roots_surface->request_fullscreen); + roots_surface->new_popup.notify = handle_new_popup; + wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); + + struct roots_view *view = calloc(1, sizeof(struct roots_view)); + if (!view) { + free(roots_surface); + return; + } + view->type = ROOTS_XDG_SHELL_VIEW; + + view->xdg_surface = surface; + view->roots_xdg_surface = roots_surface; + view->wlr_surface = surface->surface; + view->activate = activate; + view->resize = resize; + view->move_resize = move_resize; + view->maximize = maximize; + view->set_fullscreen = set_fullscreen; + view->close = close; + roots_surface->view = view; + + struct wlr_box box; + get_size(view, &box); + view->width = box.width; + view->height = box.height; + + view_init(view, desktop); + wl_list_insert(&desktop->views, &view->link); + + view_setup(view); +} diff --git a/types/meson.build b/types/meson.build index 2731f9bc..da47aeff 100644 --- a/types/meson.build +++ b/types/meson.build @@ -26,6 +26,7 @@ lib_wlr_types = static_library( 'wlr_wl_shell.c', 'wlr_xcursor_manager.c', 'wlr_xdg_shell_v6.c', + 'wlr_xdg_shell.c', ), include_directories: wlr_inc, dependencies: [wayland_server, pixman, wlr_protos], diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c new file mode 100644 index 00000000..6b2d42ee --- /dev/null +++ b/types/wlr_xdg_shell.c @@ -0,0 +1,1457 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util/signal.h" +#include "xdg-shell-protocol.h" + +static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel"; +static const char *wlr_desktop_xdg_popup_role = "xdg_popup"; + +struct wlr_xdg_positioner { + struct wl_resource *resource; + + struct wlr_box anchor_rect; + enum xdg_positioner_anchor anchor; + enum xdg_positioner_gravity gravity; + enum xdg_positioner_constraint_adjustment constraint_adjustment; + + struct { + int32_t width, height; + } size; + + struct { + int32_t x, y; + } offset; +}; + + +static void resource_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static struct wlr_xdg_surface *xdg_popup_grab_get_topmost( + struct wlr_xdg_popup_grab *grab) { + struct wlr_xdg_popup *popup; + wl_list_for_each(popup, &grab->popups, grab_link) { + return popup->base; + } + + return NULL; +} + +static void xdg_pointer_grab_end(struct wlr_seat_pointer_grab *grab) { + struct wlr_xdg_popup_grab *popup_grab = grab->data; + + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &popup_grab->popups, grab_link) { + xdg_popup_send_popup_done(popup->resource); + } + + wlr_seat_pointer_end_grab(grab->seat); +} + +static void xdg_pointer_grab_enter(struct wlr_seat_pointer_grab *grab, + struct wlr_surface *surface, double sx, double sy) { + struct wlr_xdg_popup_grab *popup_grab = grab->data; + if (wl_resource_get_client(surface->resource) == popup_grab->client) { + wlr_seat_pointer_enter(grab->seat, surface, sx, sy); + } else { + wlr_seat_pointer_clear_focus(grab->seat); + } +} + +static void xdg_pointer_grab_motion(struct wlr_seat_pointer_grab *grab, + uint32_t time, double sx, double sy) { + wlr_seat_pointer_send_motion(grab->seat, time, sx, sy); +} + +static uint32_t xdg_pointer_grab_button(struct wlr_seat_pointer_grab *grab, + uint32_t time, uint32_t button, uint32_t state) { + uint32_t serial = + wlr_seat_pointer_send_button(grab->seat, time, button, state); + if (serial) { + return serial; + } else { + xdg_pointer_grab_end(grab); + return 0; + } +} + +static void xdg_pointer_grab_axis(struct wlr_seat_pointer_grab *grab, + uint32_t time, enum wlr_axis_orientation orientation, double value) { + wlr_seat_pointer_send_axis(grab->seat, time, orientation, value); +} + +static void xdg_pointer_grab_cancel(struct wlr_seat_pointer_grab *grab) { + xdg_pointer_grab_end(grab); +} + +static const struct wlr_pointer_grab_interface xdg_pointer_grab_impl = { + .enter = xdg_pointer_grab_enter, + .motion = xdg_pointer_grab_motion, + .button = xdg_pointer_grab_button, + .cancel = xdg_pointer_grab_cancel, + .axis = xdg_pointer_grab_axis, +}; + +static void xdg_keyboard_grab_enter(struct wlr_seat_keyboard_grab *grab, + struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes, + struct wlr_keyboard_modifiers *modifiers) { + // keyboard focus should remain on the popup +} + +static void xdg_keyboard_grab_key(struct wlr_seat_keyboard_grab *grab, uint32_t time, + uint32_t key, uint32_t state) { + wlr_seat_keyboard_send_key(grab->seat, time, key, state); +} + +static void xdg_keyboard_grab_modifiers(struct wlr_seat_keyboard_grab *grab, + struct wlr_keyboard_modifiers *modifiers) { + wlr_seat_keyboard_send_modifiers(grab->seat, modifiers); +} + +static void xdg_keyboard_grab_cancel(struct wlr_seat_keyboard_grab *grab) { + wlr_seat_keyboard_end_grab(grab->seat); +} + +static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = { + .enter = xdg_keyboard_grab_enter, + .key = xdg_keyboard_grab_key, + .modifiers = xdg_keyboard_grab_modifiers, + .cancel = xdg_keyboard_grab_cancel, +}; + +static struct wlr_xdg_popup_grab *xdg_shell_popup_grab_from_seat( + struct wlr_xdg_shell *shell, struct wlr_seat *seat) { + struct wlr_xdg_popup_grab *xdg_grab; + wl_list_for_each(xdg_grab, &shell->popup_grabs, link) { + if (xdg_grab->seat == seat) { + return xdg_grab; + } + } + + xdg_grab = calloc(1, sizeof(struct wlr_xdg_popup_grab)); + if (!xdg_grab) { + return NULL; + } + + xdg_grab->pointer_grab.data = xdg_grab; + xdg_grab->pointer_grab.interface = &xdg_pointer_grab_impl; + xdg_grab->keyboard_grab.data = xdg_grab; + xdg_grab->keyboard_grab.interface = &xdg_keyboard_grab_impl; + + wl_list_init(&xdg_grab->popups); + + wl_list_insert(&shell->popup_grabs, &xdg_grab->link); + xdg_grab->seat = seat; + + return xdg_grab; +} + + +static void xdg_surface_destroy(struct wlr_xdg_surface *surface) { + // TODO: probably need to ungrab before this event + wlr_signal_emit_safe(&surface->events.destroy, surface); + + if (surface->configure_idle) { + wl_event_source_remove(surface->configure_idle); + } + + struct wlr_xdg_surface_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + free(configure); + } + + if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + wl_resource_set_user_data(surface->toplevel_state->resource, NULL); + free(surface->toplevel_state); + } + + if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + wl_resource_set_user_data(surface->popup_state->resource, NULL); + + if (surface->popup_state->seat) { + struct wlr_xdg_popup_grab *grab = + xdg_shell_popup_grab_from_seat(surface->client->shell, + surface->popup_state->seat); + + struct wlr_xdg_surface *topmost = + xdg_popup_grab_get_topmost(grab); + + if (topmost != surface) { + wl_resource_post_error(surface->client->resource, + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was destroyed while it was not the topmost " + "popup."); + } + + wl_list_remove(&surface->popup_state->grab_link); + + if (wl_list_empty(&grab->popups)) { + if (grab->seat->pointer_state.grab == &grab->pointer_grab) { + wlr_seat_pointer_end_grab(grab->seat); + } + if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) { + wlr_seat_keyboard_end_grab(grab->seat); + } + } + } + + wl_list_remove(&surface->popup_state->link); + free(surface->popup_state); + } + + 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->geometry); + free(surface->next_geometry); + free(surface->title); + free(surface->app_id); + free(surface); +} + + +static void xdg_positioner_destroy(struct wl_resource *resource) { + struct wlr_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + free(positioner); + +} + +static void xdg_positioner_protocol_set_size(struct wl_client *client, + struct wl_resource *resource, int32_t width, int32_t height) { + struct wlr_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + if (width < 1 || height < 1) { + wl_resource_post_error(resource, + XDG_POSITIONER_ERROR_INVALID_INPUT, + "width and height must be positives and non-zero"); + return; + } + + positioner->size.width = width; + positioner->size.height = height; +} + +static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, + struct wl_resource *resource, int32_t x, int32_t y, int32_t width, + int32_t height) { + struct wlr_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + if (width < 1 || height < 1) { + wl_resource_post_error(resource, + XDG_POSITIONER_ERROR_INVALID_INPUT, + "width and height must be positives and non-zero"); + return; + } + + positioner->anchor_rect.x = x; + positioner->anchor_rect.y = y; + positioner->anchor_rect.width = width; + positioner->anchor_rect.height = height; +} + +static void xdg_positioner_protocol_set_anchor(struct wl_client *client, + struct wl_resource *resource, uint32_t anchor) { + struct wlr_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + /* post error if anchor > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT ? */ + + positioner->anchor = anchor; +} + +static void xdg_positioner_protocol_set_gravity(struct wl_client *client, + struct wl_resource *resource, uint32_t gravity) { + struct wlr_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + /* post error if gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT ? */ + + positioner->gravity = gravity; +} + +static void xdg_positioner_protocol_set_constraint_adjustment( + struct wl_client *client, struct wl_resource *resource, + uint32_t constraint_adjustment) { + struct wlr_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + positioner->constraint_adjustment = constraint_adjustment; +} + +static void xdg_positioner_protocol_set_offset(struct wl_client *client, + struct wl_resource *resource, int32_t x, int32_t y) { + struct wlr_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + positioner->offset.x = x; + positioner->offset.y = y; +} + +static const struct xdg_positioner_interface + xdg_positioner_implementation = { + .destroy = resource_destroy, + .set_size = xdg_positioner_protocol_set_size, + .set_anchor_rect = xdg_positioner_protocol_set_anchor_rect, + .set_anchor = xdg_positioner_protocol_set_anchor, + .set_gravity = xdg_positioner_protocol_set_gravity, + .set_constraint_adjustment = + xdg_positioner_protocol_set_constraint_adjustment, + .set_offset = xdg_positioner_protocol_set_offset, +}; + +static void xdg_shell_create_positioner(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t id) { + struct wlr_xdg_positioner *positioner = + calloc(1, sizeof(struct wlr_xdg_positioner)); + if (positioner == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + positioner->resource = wl_resource_create(wl_client, + &xdg_positioner_interface, + wl_resource_get_version(resource), + id); + if (positioner->resource == NULL) { + free(positioner); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(positioner->resource, + &xdg_positioner_implementation, + positioner, xdg_positioner_destroy); +} + +static void xdg_popup_protocol_grab(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_seat_client *seat_client = wl_resource_get_user_data(seat_resource); + + if (surface->popup_state->committed) { + wl_resource_post_error(surface->popup_state->resource, + XDG_POPUP_ERROR_INVALID_GRAB, + "xdg_popup is already mapped"); + return; + } + + struct wlr_xdg_popup_grab *popup_grab = + xdg_shell_popup_grab_from_seat(surface->client->shell, + seat_client->seat); + + struct wlr_xdg_surface *topmost = xdg_popup_grab_get_topmost(popup_grab); + bool parent_is_toplevel = + surface->popup_state->parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL; + + if ((topmost == NULL && !parent_is_toplevel) || + (topmost != NULL && topmost != surface->popup_state->parent)) { + wl_resource_post_error(surface->client->resource, + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was not created on the topmost popup"); + return; + } + + popup_grab->client = surface->client->client; + surface->popup_state->seat = seat_client->seat; + + wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); + + wlr_seat_pointer_start_grab(seat_client->seat, + &popup_grab->pointer_grab); + wlr_seat_keyboard_start_grab(seat_client->seat, + &popup_grab->keyboard_grab); +} + +static const struct xdg_popup_interface xdg_popup_implementation = { + .destroy = resource_destroy, + .grab = xdg_popup_protocol_grab, +}; + + +static struct wlr_box xdg_positioner_get_geometry( + struct wlr_xdg_positioner *positioner, + struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent) { + struct wlr_box geometry = { + .x = positioner->offset.x, + .y = positioner->offset.y, + .width = positioner->size.width, + .height = positioner->size.height, + }; + + switch (positioner->anchor) { + case XDG_POSITIONER_ANCHOR_TOP: + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + geometry.y += positioner->anchor_rect.y; + break; + case XDG_POSITIONER_ANCHOR_BOTTOM: + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + geometry.y += + positioner->anchor_rect.y + positioner->anchor_rect.height; + break; + default: + geometry.y += + positioner->anchor_rect.y + positioner->anchor_rect.height / 2; + } + + switch (positioner->anchor) { + case XDG_POSITIONER_ANCHOR_LEFT: + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + geometry.x += positioner->anchor_rect.x; + break; + case XDG_POSITIONER_ANCHOR_RIGHT: + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width; + break; + default: + geometry.x += + positioner->anchor_rect.x + positioner->anchor_rect.width / 2; + } + + switch (positioner->gravity) { + case XDG_POSITIONER_GRAVITY_TOP: + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + geometry.y -= geometry.height; + break; + case XDG_POSITIONER_GRAVITY_BOTTOM: + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + geometry.y = geometry.y; + break; + default: + geometry.y -= geometry.height / 2; + } + + switch (positioner->gravity) { + case XDG_POSITIONER_GRAVITY_LEFT: + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + geometry.x -= geometry.width; + break; + case XDG_POSITIONER_GRAVITY_RIGHT: + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + geometry.x = geometry.x; + break; + default: + geometry.x -= geometry.width / 2; + } + + if (positioner->constraint_adjustment == + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE) { + return geometry; + } + + // TODO: add compositor policy configuration and the code here + + return geometry; +} + +static void xdg_popup_resource_destroy(struct wl_resource *resource) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + if (surface != NULL) { + xdg_surface_destroy(surface); + } +} + +static void xdg_surface_get_popup(struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *parent_resource, + struct wl_resource *positioner_resource) { + struct wlr_xdg_surface *surface = + wl_resource_get_user_data(resource); + struct wlr_xdg_surface *parent = + wl_resource_get_user_data(parent_resource); + struct wlr_xdg_positioner *positioner = + wl_resource_get_user_data(positioner_resource); + + if (positioner->size.width == 0 || positioner->anchor_rect.width == 0) { + wl_resource_post_error(resource, + XDG_WM_BASE_ERROR_INVALID_POSITIONER, + "positioner object is not complete"); + return; + } + + if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_popup_role, + resource, XDG_WM_BASE_ERROR_ROLE)) { + return; + } + + surface->popup_state = calloc(1, sizeof(struct wlr_xdg_popup)); + if (!surface->popup_state) { + wl_resource_post_no_memory(resource); + return; + } + + surface->popup_state->resource = + wl_resource_create(client, &xdg_popup_interface, + wl_resource_get_version(resource), id); + if (surface->popup_state->resource == NULL) { + free(surface->popup_state); + wl_resource_post_no_memory(resource); + return; + } + + surface->role = WLR_XDG_SURFACE_ROLE_POPUP; + surface->popup_state->base = surface; + surface->popup_state->parent = parent; + surface->popup_state->geometry = + xdg_positioner_get_geometry(positioner, surface, parent); + wl_list_insert(&parent->popups, &surface->popup_state->link); + + wl_resource_set_implementation(surface->popup_state->resource, + &xdg_popup_implementation, surface, + xdg_popup_resource_destroy); + + wlr_signal_emit_safe(&parent->events.new_popup, surface->popup_state); +} + + +static void xdg_toplevel_protocol_set_parent(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *parent_resource) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *parent = NULL; + + if (parent_resource != NULL) { + parent = wl_resource_get_user_data(parent_resource); + } + + surface->toplevel_state->parent = parent; +} + +static void xdg_toplevel_protocol_set_title(struct wl_client *client, + struct wl_resource *resource, const char *title) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + char *tmp; + + tmp = strdup(title); + if (tmp == NULL) { + return; + } + + free(surface->title); + surface->title = tmp; +} + +static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, + struct wl_resource *resource, const char *app_id) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + char *tmp; + + tmp = strdup(app_id); + if (tmp == NULL) { + return; + } + + free(surface->app_id); + surface->app_id = tmp; +} + +static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial, int32_t x, int32_t y) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_seat_client *seat = + wl_resource_get_user_data(seat_resource); + + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { + wlr_log(L_DEBUG, "invalid serial for grab"); + return; + } + + struct wlr_xdg_toplevel_show_window_menu_event event = { + .surface = surface, + .seat = seat, + .serial = serial, + .x = x, + .y = y, + }; + + wlr_signal_emit_safe(&surface->events.request_show_window_menu, &event); +} + +static void xdg_toplevel_protocol_move(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_seat_client *seat = + wl_resource_get_user_data(seat_resource); + + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { + wlr_log(L_DEBUG, "invalid serial for grab"); + return; + } + + struct wlr_xdg_toplevel_move_event event = { + .surface = surface, + .seat = seat, + .serial = serial, + }; + + wlr_signal_emit_safe(&surface->events.request_move, &event); +} + +static void xdg_toplevel_protocol_resize(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial, uint32_t edges) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_seat_client *seat = + wl_resource_get_user_data(seat_resource); + + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { + wlr_log(L_DEBUG, "invalid serial for grab"); + return; + } + + struct wlr_xdg_toplevel_resize_event event = { + .surface = surface, + .seat = seat, + .serial = serial, + .edges = edges, + }; + + wlr_signal_emit_safe(&surface->events.request_resize, &event); +} + +static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, + struct wl_resource *resource, int32_t width, int32_t height) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.max_width = width; + surface->toplevel_state->next.max_height = height; +} + +static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, + struct wl_resource *resource, int32_t width, int32_t height) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.min_width = width; + surface->toplevel_state->next.min_height = height; +} + +static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.maximized = true; + wlr_signal_emit_safe(&surface->events.request_maximize, surface); +} + +static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.maximized = false; + wlr_signal_emit_safe(&surface->events.request_maximize, surface); +} + +static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *output_resource) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + + struct wlr_output *output = NULL; + if (output_resource != NULL) { + output = wl_resource_get_user_data(output_resource); + } + + surface->toplevel_state->next.fullscreen = true; + + struct wlr_xdg_toplevel_set_fullscreen_event event = { + .surface = surface, + .fullscreen = true, + .output = output, + }; + + wlr_signal_emit_safe(&surface->events.request_fullscreen, &event); +} + +static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + + surface->toplevel_state->next.fullscreen = false; + + struct wlr_xdg_toplevel_set_fullscreen_event event = { + .surface = surface, + .fullscreen = false, + .output = NULL, + }; + + wlr_signal_emit_safe(&surface->events.request_fullscreen, &event); +} + +static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + wlr_signal_emit_safe(&surface->events.request_minimize, surface); +} + +static const struct xdg_toplevel_interface xdg_toplevel_implementation = +{ + .destroy = resource_destroy, + .set_parent = xdg_toplevel_protocol_set_parent, + .set_title = xdg_toplevel_protocol_set_title, + .set_app_id = xdg_toplevel_protocol_set_app_id, + .show_window_menu = xdg_toplevel_protocol_show_window_menu, + .move = xdg_toplevel_protocol_move, + .resize = xdg_toplevel_protocol_resize, + .set_max_size = xdg_toplevel_protocol_set_max_size, + .set_min_size = xdg_toplevel_protocol_set_min_size, + .set_maximized = xdg_toplevel_protocol_set_maximized, + .unset_maximized = xdg_toplevel_protocol_unset_maximized, + .set_fullscreen = xdg_toplevel_protocol_set_fullscreen, + .unset_fullscreen = xdg_toplevel_protocol_unset_fullscreen, + .set_minimized = xdg_toplevel_protocol_set_minimized +}; + +static void xdg_surface_resource_destroy(struct wl_resource *resource) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + if (surface != NULL) { + xdg_surface_destroy(surface); + } +} + +static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + if (surface != NULL) { + xdg_surface_destroy(surface); + } +} + +static void xdg_surface_get_toplevel(struct wl_client *client, + struct wl_resource *resource, uint32_t id) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + + if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role, + resource, XDG_WM_BASE_ERROR_ROLE)) { + return; + } + + surface->toplevel_state = calloc(1, sizeof(struct wlr_xdg_toplevel)); + if (surface->toplevel_state == NULL) { + wl_resource_post_no_memory(resource); + return; + } + + surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL; + surface->toplevel_state->base = surface; + + struct wl_resource *toplevel_resource = wl_resource_create(client, + &xdg_toplevel_interface, wl_resource_get_version(resource), id); + if (toplevel_resource == NULL) { + free(surface->toplevel_state); + wl_resource_post_no_memory(resource); + return; + } + + surface->toplevel_state->resource = toplevel_resource; + + wl_resource_set_implementation(toplevel_resource, + &xdg_toplevel_implementation, surface, + xdg_toplevel_resource_destroy); +} + +static void wlr_xdg_toplevel_ack_configure( + struct wlr_xdg_surface *surface, + struct wlr_xdg_surface_configure *configure) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->next = configure->state; + surface->toplevel_state->pending.width = 0; + surface->toplevel_state->pending.height = 0; +} + +static void xdg_surface_ack_configure(struct wl_client *client, + struct wl_resource *resource, uint32_t serial) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + + if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) { + wl_resource_post_error(surface->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + return; + } + + bool found = false; + struct wlr_xdg_surface_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + if (configure->serial < serial) { + wl_list_remove(&configure->link); + free(configure); + } else if (configure->serial == serial) { + wl_list_remove(&configure->link); + found = true; + break; + } else { + break; + } + } + if (!found) { + wl_resource_post_error(surface->client->resource, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, + "wrong configure serial: %u", serial); + return; + } + + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_NONE: + assert(0 && "not reached"); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + wlr_xdg_toplevel_ack_configure(surface, configure); + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + break; + } + + surface->configured = true; + surface->configure_serial = serial; + + free(configure); +} + +static void xdg_surface_set_window_geometry(struct wl_client *client, + struct wl_resource *resource, int32_t x, int32_t y, int32_t width, + int32_t height) { + struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + + if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) { + wl_resource_post_error(surface->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + return; + } + + surface->has_next_geometry = true; + surface->next_geometry->height = height; + surface->next_geometry->width = width; + surface->next_geometry->x = x; + surface->next_geometry->y = y; + +} + +static const struct xdg_surface_interface xdg_surface_implementation = { + .destroy = resource_destroy, + .get_toplevel = xdg_surface_get_toplevel, + .get_popup = xdg_surface_get_popup, + .ack_configure = xdg_surface_ack_configure, + .set_window_geometry = xdg_surface_set_window_geometry, +}; + +static bool wlr_xdg_surface_toplevel_state_compare( + struct wlr_xdg_toplevel *state) { + struct { + struct wlr_xdg_toplevel_state state; + uint32_t width; + uint32_t height; + + } configured; + + // is pending state different from current state? + if (!state->base->configured) { + return false; + } + + if (wl_list_empty(&state->base->configure_list)) { + // last configure is actually the current state, just use it + configured.state = state->current; + configured.width = state->base->surface->current->width; + configured.height = state->base->surface->current->width; + } else { + struct wlr_xdg_surface_configure *configure = + wl_container_of(state->base->configure_list.prev, configure, link); + configured.state = configure->state; + configured.width = configure->state.width; + configured.height = configure->state.height; + } + + if (state->pending.activated != configured.state.activated) { + return false; + } + if (state->pending.fullscreen != configured.state.fullscreen) { + return false; + } + if (state->pending.maximized != configured.state.maximized) { + return false; + } + if (state->pending.resizing != configured.state.resizing) { + return false; + } + + if (state->pending.width == configured.width && + state->pending.height == configured.height) { + return true; + } + + if (state->pending.width == 0 && state->pending.height == 0) { + return true; + } + + return false; +} + +static void wlr_xdg_toplevel_send_configure( + struct wlr_xdg_surface *surface, + struct wlr_xdg_surface_configure *configure) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + uint32_t *s; + struct wl_array states; + + configure->state = surface->toplevel_state->pending; + + wl_array_init(&states); + if (surface->toplevel_state->pending.maximized) { + s = wl_array_add(&states, sizeof(uint32_t)); + if (!s) { + wlr_log(L_ERROR, "Could not allocate state for maximized xdg_toplevel"); + goto error_out; + } + *s = XDG_TOPLEVEL_STATE_MAXIMIZED; + } + if (surface->toplevel_state->pending.fullscreen) { + s = wl_array_add(&states, sizeof(uint32_t)); + if (!s) { + wlr_log(L_ERROR, "Could not allocate state for fullscreen xdg_toplevel"); + goto error_out; + } + *s = XDG_TOPLEVEL_STATE_FULLSCREEN; + } + if (surface->toplevel_state->pending.resizing) { + s = wl_array_add(&states, sizeof(uint32_t)); + if (!s) { + wlr_log(L_ERROR, "Could not allocate state for resizing xdg_toplevel"); + goto error_out; + } + *s = XDG_TOPLEVEL_STATE_RESIZING; + } + if (surface->toplevel_state->pending.activated) { + s = wl_array_add(&states, sizeof(uint32_t)); + if (!s) { + wlr_log(L_ERROR, "Could not allocate state for activated xdg_toplevel"); + goto error_out; + } + *s = XDG_TOPLEVEL_STATE_ACTIVATED; + } + + uint32_t width = surface->toplevel_state->pending.width; + uint32_t height = surface->toplevel_state->pending.height; + + if (width == 0 || height == 0) { + width = surface->geometry->width; + height = surface->geometry->height; + } + + xdg_toplevel_send_configure(surface->toplevel_state->resource, width, + height, &states); + + wl_array_release(&states); + return; + +error_out: + wl_array_release(&states); + wl_resource_post_no_memory(surface->toplevel_state->resource); +} + +static void wlr_xdg_surface_send_configure(void *user_data) { + struct wlr_xdg_surface *surface = user_data; + + surface->configure_idle = NULL; + + struct wlr_xdg_surface_configure *configure = + calloc(1, sizeof(struct wlr_xdg_surface_configure)); + if (configure == NULL) { + wl_client_post_no_memory(surface->client->client); + return; + } + + wl_list_insert(surface->configure_list.prev, &configure->link); + configure->serial = surface->configure_next_serial; + + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_NONE: + assert(0 && "not reached"); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + wlr_xdg_toplevel_send_configure(surface, configure); + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + xdg_popup_send_configure(surface->popup_state->resource, + surface->popup_state->geometry.x, + surface->popup_state->geometry.y, + surface->popup_state->geometry.width, + surface->popup_state->geometry.height); + break; + } + + xdg_surface_send_configure(surface->resource, configure->serial); +} + +static uint32_t wlr_xdg_surface_schedule_configure( + struct wlr_xdg_surface *surface) { + struct wl_display *display = wl_client_get_display(surface->client->client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + bool pending_same = false; + + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_NONE: + assert(0 && "not reached"); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + pending_same = + wlr_xdg_surface_toplevel_state_compare(surface->toplevel_state); + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + break; + } + + if (surface->configure_idle != NULL) { + if (!pending_same) { + // configure request already scheduled + return surface->configure_next_serial; + } + + // configure request not necessary anymore + wl_event_source_remove(surface->configure_idle); + surface->configure_idle = NULL; + return 0; + } else { + if (pending_same) { + // configure request not necessary + return 0; + } + + surface->configure_next_serial = wl_display_next_serial(display); + surface->configure_idle = wl_event_loop_add_idle(loop, + wlr_xdg_surface_send_configure, surface); + return surface->configure_next_serial; + } +} + +static void handle_wlr_surface_destroyed(struct wl_listener *listener, + void *data) { + struct wlr_xdg_surface *xdg_surface = + wl_container_of(listener, xdg_surface, surface_destroy_listener); + xdg_surface_destroy(xdg_surface); +} + +static void wlr_xdg_surface_toplevel_committed( + struct wlr_xdg_surface *surface) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + + if (!wlr_surface_has_buffer(surface->surface) + && !surface->toplevel_state->added) { + // on the first commit, send a configure request to tell the client it + // is added + wlr_xdg_surface_schedule_configure(surface); + surface->toplevel_state->added = true; + return; + } + + if (!wlr_surface_has_buffer(surface->surface)) { + return; + } + + surface->toplevel_state->current = surface->toplevel_state->next; +} + +static void wlr_xdg_surface_popup_committed( + struct wlr_xdg_surface *surface) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); + + if (!surface->popup_state->committed) { + wlr_xdg_surface_schedule_configure(surface); + surface->popup_state->committed = true; + } +} + +static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, + void *role_data) { + struct wlr_xdg_surface *surface = role_data; + + if (wlr_surface_has_buffer(surface->surface) && !surface->configured) { + wl_resource_post_error(surface->resource, + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface has never been configured"); + return; + } + + if (surface->has_next_geometry) { + surface->has_next_geometry = false; + surface->geometry->x = surface->next_geometry->x; + surface->geometry->y = surface->next_geometry->y; + surface->geometry->width = surface->next_geometry->width; + surface->geometry->height = surface->next_geometry->height; + } + + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_NONE: + wl_resource_post_error(surface->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + wlr_xdg_surface_toplevel_committed(surface); + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + wlr_xdg_surface_popup_committed(surface); + break; + } + + if (surface->configured && !surface->added) { + surface->added = true; + wlr_signal_emit_safe(&surface->client->shell->events.new_surface, surface); + } +} + +static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, + struct wl_resource *client_resource, uint32_t id, + struct wl_resource *surface_resource) { + struct wlr_xdg_client *client = + wl_resource_get_user_data(client_resource); + + struct wlr_xdg_surface *surface; + if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface)))) { + wl_client_post_no_memory(wl_client); + return; + } + + if (!(surface->geometry = calloc(1, sizeof(struct wlr_box)))) { + free(surface); + wl_client_post_no_memory(wl_client); + return; + } + + if (!(surface->next_geometry = calloc(1, sizeof(struct wlr_box)))) { + free(surface->geometry); + free(surface); + wl_client_post_no_memory(wl_client); + return; + } + + surface->client = client; + surface->role = WLR_XDG_SURFACE_ROLE_NONE; + surface->surface = wl_resource_get_user_data(surface_resource); + surface->resource = wl_resource_create(wl_client, + &xdg_surface_interface, wl_resource_get_version(client_resource), + id); + if (surface->resource == NULL) { + free(surface->next_geometry); + free(surface->geometry); + free(surface); + wl_client_post_no_memory(wl_client); + return; + } + + if (wlr_surface_has_buffer(surface->surface)) { + wl_resource_destroy(surface->resource); + free(surface->next_geometry); + free(surface->geometry); + free(surface); + wl_resource_post_error(surface_resource, + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface must not have a buffer at creation"); + return; + } + + wl_list_init(&surface->configure_list); + wl_list_init(&surface->popups); + + wl_signal_init(&surface->events.request_maximize); + wl_signal_init(&surface->events.request_fullscreen); + wl_signal_init(&surface->events.request_minimize); + wl_signal_init(&surface->events.request_move); + wl_signal_init(&surface->events.request_resize); + wl_signal_init(&surface->events.request_show_window_menu); + wl_signal_init(&surface->events.destroy); + wl_signal_init(&surface->events.ping_timeout); + wl_signal_init(&surface->events.new_popup); + + 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 xdg_surface %p (res %p)", surface, surface->resource); + wl_resource_set_implementation(surface->resource, + &xdg_surface_implementation, surface, xdg_surface_resource_destroy); + wl_list_insert(&client->surfaces, &surface->link); +} + +static void xdg_shell_pong(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t serial) { + struct wlr_xdg_client *client = wl_resource_get_user_data(resource); + + if (client->ping_serial != serial) { + return; + } + + wl_event_source_timer_update(client->ping_timer, 0); + client->ping_serial = 0; +} + +static struct xdg_wm_base_interface xdg_shell_impl = { + .destroy = resource_destroy, + .create_positioner = xdg_shell_create_positioner, + .get_xdg_surface = xdg_shell_get_xdg_surface, + .pong = xdg_shell_pong, +}; + +static void wlr_xdg_client_destroy(struct wl_resource *resource) { + struct wlr_xdg_client *client = wl_resource_get_user_data(resource); + + struct wlr_xdg_surface *surface, *tmp = NULL; + wl_list_for_each_safe(surface, tmp, &client->surfaces, link) { + xdg_surface_destroy(surface); + } + + if (client->ping_timer != NULL) { + wl_event_source_remove(client->ping_timer); + } + + wl_list_remove(&client->link); + free(client); +} + +static int wlr_xdg_client_ping_timeout(void *user_data) { + struct wlr_xdg_client *client = user_data; + + struct wlr_xdg_surface *surface; + wl_list_for_each(surface, &client->surfaces, link) { + wlr_signal_emit_safe(&surface->events.ping_timeout, surface); + } + + client->ping_serial = 0; + return 1; +} + +static void xdg_shell_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) { + struct wlr_xdg_shell *xdg_shell = data; + assert(wl_client && xdg_shell); + + struct wlr_xdg_client *client = + calloc(1, sizeof(struct wlr_xdg_client)); + if (client == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + wl_list_init(&client->surfaces); + + client->resource = + wl_resource_create(wl_client, &xdg_wm_base_interface, version, id); + if (client->resource == NULL) { + free(client); + wl_client_post_no_memory(wl_client); + return; + } + client->client = wl_client; + client->shell = xdg_shell; + + wl_resource_set_implementation(client->resource, &xdg_shell_impl, client, + wlr_xdg_client_destroy); + wl_list_insert(&xdg_shell->clients, &client->link); + + struct wl_display *display = wl_client_get_display(client->client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + client->ping_timer = wl_event_loop_add_timer(loop, + wlr_xdg_client_ping_timeout, client); + if (client->ping_timer == NULL) { + wl_client_post_no_memory(client->client); + } +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_xdg_shell *xdg_shell = + wl_container_of(listener, xdg_shell, display_destroy); + wlr_xdg_shell_destroy(xdg_shell); +} + +struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display) { + struct wlr_xdg_shell *xdg_shell = + calloc(1, sizeof(struct wlr_xdg_shell)); + if (!xdg_shell) { + return NULL; + } + + xdg_shell->ping_timeout = 10000; + + wl_list_init(&xdg_shell->clients); + wl_list_init(&xdg_shell->popup_grabs); + + struct wl_global *wl_global = wl_global_create(display, + &xdg_wm_base_interface, 1, xdg_shell, xdg_shell_bind); + if (!wl_global) { + free(xdg_shell); + return NULL; + } + xdg_shell->wl_global = wl_global; + + wl_signal_init(&xdg_shell->events.new_surface); + + xdg_shell->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &xdg_shell->display_destroy); + + return xdg_shell; +} + +void wlr_xdg_shell_destroy(struct wlr_xdg_shell *xdg_shell) { + if (!xdg_shell) { + return; + } + wl_list_remove(&xdg_shell->display_destroy.link); + wl_global_destroy(xdg_shell->wl_global); + free(xdg_shell); +} + +void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface) { + if (surface->client->ping_serial != 0) { + // already pinged + return; + } + + surface->client->ping_serial = + wl_display_next_serial(wl_client_get_display(surface->client->client)); + wl_event_source_timer_update(surface->client->ping_timer, + surface->client->shell->ping_timeout); + xdg_wm_base_send_ping(surface->client->resource, + surface->client->ping_serial); +} + +uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface, + uint32_t width, uint32_t height) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->pending.width = width; + surface->toplevel_state->pending.height = height; + + return wlr_xdg_surface_schedule_configure(surface); +} + +uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface, + bool activated) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->pending.activated = activated; + + return wlr_xdg_surface_schedule_configure(surface); +} + +uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface, + bool maximized) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->pending.maximized = maximized; + + return wlr_xdg_surface_schedule_configure(surface); +} + +uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface, + bool fullscreen) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->pending.fullscreen = fullscreen; + + return wlr_xdg_surface_schedule_configure(surface); +} + +uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface, + bool resizing) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->pending.resizing = resizing; + + return wlr_xdg_surface_schedule_configure(surface); +} + +void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + xdg_toplevel_send_close(surface->toplevel_state->resource); +} + +void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface, + double *popup_sx, double *popup_sy) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); + struct wlr_xdg_surface *parent = surface->popup_state->parent; + *popup_sx = parent->geometry->x + surface->popup_state->geometry.x - + surface->geometry->x; + *popup_sy = parent->geometry->y + surface->popup_state->geometry.y - + surface->geometry->y; +} + +struct wlr_xdg_surface *wlr_xdg_surface_popup_at( + struct wlr_xdg_surface *surface, double sx, double sy, + double *popup_sx, double *popup_sy) { + // XXX: I think this is so complicated because we're mixing geometry + // coordinates with surface coordinates. Input handling should only deal + // with surface coordinates. + 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 = + surface->geometry->x + popup_state->geometry.x; + double _popup_sy = + surface->geometry->y + popup_state->geometry.y; + int popup_width = popup_state->geometry.width; + int popup_height = popup_state->geometry.height; + + struct wlr_xdg_surface *_popup = + wlr_xdg_surface_popup_at(popup, + sx - _popup_sx + popup->geometry->x, + sy - _popup_sy + popup->geometry->y, + popup_sx, popup_sy); + if (_popup) { + *popup_sx = *popup_sx + _popup_sx - popup->geometry->x; + *popup_sy = *popup_sy + _popup_sy - popup->geometry->y; + return _popup; + } + + if ((sx > _popup_sx && sx < _popup_sx + popup_width) && + (sy > _popup_sy && sy < _popup_sy + popup_height)) { + if (pixman_region32_contains_point(&popup->surface->current->input, + sx - _popup_sx + popup->geometry->x, + sy - _popup_sy + popup->geometry->y, NULL)) { + *popup_sx = _popup_sx - popup->geometry->x; + *popup_sy = _popup_sy - popup->geometry->y; + return popup; + } + } + } + + return NULL; +} From 1080bf69f8b9d1b25287fd987266f45602480735 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 14 Feb 2018 19:02:24 +0100 Subject: [PATCH 03/13] xdg_shell: add input validatoin for positioner anchor/gravity --- types/wlr_xdg_shell.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 6b2d42ee..985c180a 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -270,7 +270,12 @@ static void xdg_positioner_protocol_set_anchor(struct wl_client *client, struct wlr_xdg_positioner *positioner = wl_resource_get_user_data(resource); - /* post error if anchor > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT ? */ + if (anchor > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT) { + wl_resource_post_error(resource, + XDG_POSITIONER_ERROR_INVALID_INPUT, + "invalid anchor value"); + return; + } positioner->anchor = anchor; } @@ -280,7 +285,12 @@ static void xdg_positioner_protocol_set_gravity(struct wl_client *client, struct wlr_xdg_positioner *positioner = wl_resource_get_user_data(resource); - /* post error if gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT ? */ + if (gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) { + wl_resource_post_error(resource, + XDG_POSITIONER_ERROR_INVALID_INPUT, + "invalid gravity value"); + return; + } positioner->gravity = gravity; } From db9c2c11f65dbc1e01485b8afaa21c874d15140f Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 14 Feb 2018 19:02:45 +0100 Subject: [PATCH 04/13] meson: require wayland-protocols >=1.12 for xdg-shell stable --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 1cf7781a..2fc78d33 100644 --- a/meson.build +++ b/meson.build @@ -49,7 +49,7 @@ add_project_arguments('-DWL_HIDE_DEPRECATED', language: 'c') wayland_server = dependency('wayland-server') wayland_client = dependency('wayland-client') wayland_egl = dependency('wayland-egl') -wayland_protos = dependency('wayland-protocols') +wayland_protos = dependency('wayland-protocols', version: '>=1.12') egl = dependency('egl') glesv2 = dependency('glesv2') drm = dependency('libdrm') From 168e26489a0e6301ce6c383413ff9cc415d4f8ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Louren=C3=A7o?= Date: Wed, 14 Feb 2018 18:27:31 +0000 Subject: [PATCH 05/13] Add missing dependencies --- backend/meson.build | 9 +++++---- render/meson.build | 2 +- types/meson.build | 2 +- xwayland/meson.build | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/backend/meson.build b/backend/meson.build index bac43063..c0ed76f1 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -28,14 +28,15 @@ backend_files = files( ) backend_deps = [ - wayland_server, + drm, egl, gbm, libinput, - wlr_render, - wlr_protos, - drm, pixman, + xkbcommon, + wayland_server, + wlr_protos, + wlr_render, ] if host_machine.system().startswith('freebsd') diff --git a/render/meson.build b/render/meson.build index 1a5a85b8..8aa70cea 100644 --- a/render/meson.build +++ b/render/meson.build @@ -22,7 +22,7 @@ lib_wlr_render = static_library( glapi[0], glapi[1], include_directories: wlr_inc, - dependencies: [glesv2, egl, pixman], + dependencies: [egl, glesv2, pixman, wayland_server], ) wlr_render = declare_dependency( diff --git a/types/meson.build b/types/meson.build index 2731f9bc..329009bf 100644 --- a/types/meson.build +++ b/types/meson.build @@ -28,5 +28,5 @@ lib_wlr_types = static_library( 'wlr_xdg_shell_v6.c', ), include_directories: wlr_inc, - dependencies: [wayland_server, pixman, wlr_protos], + dependencies: [pixman, xkbcommon, wayland_server, wlr_protos], ) diff --git a/xwayland/meson.build b/xwayland/meson.build index de05cfaa..2ccdf4cb 100644 --- a/xwayland/meson.build +++ b/xwayland/meson.build @@ -15,6 +15,7 @@ lib_wlr_xwayland = static_library( xcb_image, xcb_render, xcb_icccm, + xkbcommon, pixman, ], ) From 6ae96c4832626642670aa6fdc207f659812753f3 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Thu, 15 Feb 2018 07:16:28 +0100 Subject: [PATCH 06/13] wlr_xdg_shell: (style) add break to final switch case --- types/wlr_xdg_shell.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 985c180a..0735d416 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -420,6 +420,7 @@ static struct wlr_box xdg_positioner_get_geometry( default: geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height / 2; + break; } switch (positioner->anchor) { @@ -436,6 +437,7 @@ static struct wlr_box xdg_positioner_get_geometry( default: geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width / 2; + break; } switch (positioner->gravity) { @@ -451,6 +453,7 @@ static struct wlr_box xdg_positioner_get_geometry( break; default: geometry.y -= geometry.height / 2; + break; } switch (positioner->gravity) { @@ -466,6 +469,7 @@ static struct wlr_box xdg_positioner_get_geometry( break; default: geometry.x -= geometry.width / 2; + break; } if (positioner->constraint_adjustment == From d1b28ec812248b337fd53f9478c36234f44c71f3 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Thu, 15 Feb 2018 07:17:02 +0100 Subject: [PATCH 07/13] wayland protocol headers: use double-quote for includes These headers are not installed so we should look for these locally --- examples/idle.c | 2 +- examples/screenshot.c | 12 ++++++------ types/wlr_primary_selection.c | 2 +- types/wlr_server_decoration.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/idle.c b/examples/idle.c index 57c366d1..2b155c68 100644 --- a/examples/idle.c +++ b/examples/idle.c @@ -6,8 +6,8 @@ #include #include #include -#include #include +#include "idle-client-protocol.h" static struct org_kde_kwin_idle *idle_manager = NULL; static struct wl_seat *seat = NULL; diff --git a/examples/screenshot.c b/examples/screenshot.c index 7de2ab8e..c163df75 100644 --- a/examples/screenshot.c +++ b/examples/screenshot.c @@ -23,20 +23,20 @@ #define _XOPEN_SOURCE 700 #define _POSIX_C_SOURCE 199309L +#include +#include +#include #include #include #include #include +#include #include #include -#include -#include #include -#include -#include -#include -#include "util/os-compatibility.h" #include +#include "screenshooter-client-protocol.h" +#include "util/os-compatibility.h" static struct wl_shm *shm = NULL; static struct orbital_screenshooter *screenshooter = NULL; diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c index 28fe63c1..2ce071e7 100644 --- a/types/wlr_primary_selection.c +++ b/types/wlr_primary_selection.c @@ -1,12 +1,12 @@ #define _XOPEN_SOURCE 700 #include -#include #include #include #include #include #include #include +#include "gtk-primary-selection-protocol.h" #include "util/signal.h" static void offer_handle_receive(struct wl_client *client, diff --git a/types/wlr_server_decoration.c b/types/wlr_server_decoration.c index 556193e2..f483d741 100644 --- a/types/wlr_server_decoration.c +++ b/types/wlr_server_decoration.c @@ -1,9 +1,9 @@ #include -#include #include #include #include #include +#include "server-decoration-protocol.h" #include "util/signal.h" static void server_decoration_handle_release(struct wl_client *client, From b46cc3cafd38fcb9fdeddfb3c26cff71f17e40bd Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Thu, 15 Feb 2018 07:18:15 +0100 Subject: [PATCH 08/13] wayland protocol build: remove client protocols we do not use Only include client protocols that we use on the client side. Since these are not installed, there should not be any change with this. Testers - please note 'ninja -C build clean' does not remove the old headers, you need to start from a new directory. --- protocol/meson.build | 4 ---- 1 file changed, 4 deletions(-) diff --git a/protocol/meson.build b/protocol/meson.build index 514a6dde..2853971f 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -32,12 +32,8 @@ protocols = [ client_protocols = [ [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], - [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], - 'gamma-control.xml', - 'gtk-primary-selection.xml', 'idle.xml', 'screenshooter.xml', - 'server-decoration.xml', ] wl_protos_src = [] From 714f90a9d0027d562bf22a563edee23ca877e618 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Thu, 15 Feb 2018 07:29:55 +0100 Subject: [PATCH 09/13] xdg_shell stable: allow zero-sized positioner set_anchor_rect This is a protocol difference with xdg-shell-unstable-v6 --- types/wlr_xdg_shell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 0735d416..914ee322 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -252,10 +252,10 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, struct wlr_xdg_positioner *positioner = wl_resource_get_user_data(resource); - if (width < 1 || height < 1) { + if (width < 0 || height < 0) { wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT, - "width and height must be positives and non-zero"); + "width and height must be positives"); return; } From 56ab3e9b10fdaaf41eef6e47f81ffe54fd9d5a77 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Thu, 15 Feb 2018 08:07:57 +0100 Subject: [PATCH 10/13] xdg_shell stable: fix zero-sized positioner anchor_rect We used 0 as unset-check value before, which was fine when 0-width was invalid, but isn't anymore --- types/wlr_xdg_shell.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 914ee322..53ff25d0 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -334,6 +334,10 @@ static void xdg_shell_create_positioner(struct wl_client *wl_client, return; } + /* set widths to detect improper usages of get_popup */ + positioner->size.width = -1; + positioner->anchor_rect.width = -1; + positioner->resource = wl_resource_create(wl_client, &xdg_positioner_interface, wl_resource_get_version(resource), @@ -500,7 +504,7 @@ static void xdg_surface_get_popup(struct wl_client *client, struct wlr_xdg_positioner *positioner = wl_resource_get_user_data(positioner_resource); - if (positioner->size.width == 0 || positioner->anchor_rect.width == 0) { + if (positioner->size.width == -1 || positioner->anchor_rect.width == -1) { wl_resource_post_error(resource, XDG_WM_BASE_ERROR_INVALID_POSITIONER, "positioner object is not complete"); From 4d496802dd8d5c01c8b87453e705362f73260e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 14 Feb 2018 20:21:12 +0100 Subject: [PATCH 11/13] Log GL and EGL vendor useful for debugging --- render/egl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/render/egl.c b/render/egl.c index f1208a72..21c446f1 100644 --- a/render/egl.c +++ b/render/egl.c @@ -132,7 +132,9 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, wlr_log(L_INFO, "Using EGL %d.%d", (int)major, (int)minor); wlr_log(L_INFO, "Supported EGL extensions: %s", egl->egl_exts_str); + wlr_log(L_INFO, "EGL vendor: %s", eglQueryString(egl->display, EGL_VENDOR)); wlr_log(L_INFO, "Using %s", glGetString(GL_VERSION)); + wlr_log(L_INFO, "GL vendor: %s", glGetString(GL_VENDOR)); wlr_log(L_INFO, "Supported OpenGL ES extensions: %s", egl->gl_exts_str); if (strstr(egl->egl_exts_str, "EGL_WL_bind_wayland_display") == NULL || From ac78bdb6bceb8e50fd490570c7d106209c9a0a0a Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Thu, 15 Feb 2018 12:26:20 +0100 Subject: [PATCH 12/13] xdg shells: fix typo s/positives/positive/ --- types/wlr_xdg_shell.c | 4 ++-- types/wlr_xdg_shell_v6.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 53ff25d0..48ace842 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -238,7 +238,7 @@ static void xdg_positioner_protocol_set_size(struct wl_client *client, if (width < 1 || height < 1) { wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT, - "width and height must be positives and non-zero"); + "width and height must be positive and non-zero"); return; } @@ -255,7 +255,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, if (width < 0 || height < 0) { wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT, - "width and height must be positives"); + "width and height must be positive"); return; } diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index eb18f022..a3bd16d2 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -238,7 +238,7 @@ static void xdg_positioner_protocol_set_size(struct wl_client *client, if (width < 1 || height < 1) { wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "width and height must be positives and non-zero"); + "width and height must be positive and non-zero"); return; } @@ -255,7 +255,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, if (width < 1 || height < 1) { wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "width and height must be positives and non-zero"); + "width and height must be positive and non-zero"); return; } From 4b354745fedba78de8cb3402873464b33a818806 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 16 Feb 2018 18:38:06 +0100 Subject: [PATCH 13/13] xdg-shell: wrap wl_resource_get_user_data --- types/wlr_xdg_shell.c | 241 ++++++++++++++++++++++++--------------- types/wlr_xdg_shell_v6.c | 7 +- 2 files changed, 153 insertions(+), 95 deletions(-) diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 53ff25d0..fcedf804 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -223,17 +223,25 @@ static void xdg_surface_destroy(struct wlr_xdg_surface *surface) { } +static const struct xdg_positioner_interface xdg_positioner_implementation; + +static struct wlr_xdg_positioner *xdg_positioner_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_positioner_interface, + &xdg_positioner_implementation)); + return wl_resource_get_user_data(resource); +} + static void xdg_positioner_destroy(struct wl_resource *resource) { struct wlr_xdg_positioner *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); free(positioner); - } static void xdg_positioner_protocol_set_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_positioner *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (width < 1 || height < 1) { wl_resource_post_error(resource, @@ -250,7 +258,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { struct wlr_xdg_positioner *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (width < 0 || height < 0) { wl_resource_post_error(resource, @@ -268,7 +276,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, static void xdg_positioner_protocol_set_anchor(struct wl_client *client, struct wl_resource *resource, uint32_t anchor) { struct wlr_xdg_positioner *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (anchor > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT) { wl_resource_post_error(resource, @@ -283,7 +291,7 @@ static void xdg_positioner_protocol_set_anchor(struct wl_client *client, static void xdg_positioner_protocol_set_gravity(struct wl_client *client, struct wl_resource *resource, uint32_t gravity) { struct wlr_xdg_positioner *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) { wl_resource_post_error(resource, @@ -299,7 +307,7 @@ static void xdg_positioner_protocol_set_constraint_adjustment( struct wl_client *client, struct wl_resource *resource, uint32_t constraint_adjustment) { struct wlr_xdg_positioner *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); positioner->constraint_adjustment = constraint_adjustment; } @@ -307,7 +315,7 @@ static void xdg_positioner_protocol_set_constraint_adjustment( static void xdg_positioner_protocol_set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { struct wlr_xdg_positioner *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); positioner->offset.x = x; positioner->offset.y = y; @@ -353,52 +361,6 @@ static void xdg_shell_create_positioner(struct wl_client *wl_client, positioner, xdg_positioner_destroy); } -static void xdg_popup_protocol_grab(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); - struct wlr_seat_client *seat_client = wl_resource_get_user_data(seat_resource); - - if (surface->popup_state->committed) { - wl_resource_post_error(surface->popup_state->resource, - XDG_POPUP_ERROR_INVALID_GRAB, - "xdg_popup is already mapped"); - return; - } - - struct wlr_xdg_popup_grab *popup_grab = - xdg_shell_popup_grab_from_seat(surface->client->shell, - seat_client->seat); - - struct wlr_xdg_surface *topmost = xdg_popup_grab_get_topmost(popup_grab); - bool parent_is_toplevel = - surface->popup_state->parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL; - - if ((topmost == NULL && !parent_is_toplevel) || - (topmost != NULL && topmost != surface->popup_state->parent)) { - wl_resource_post_error(surface->client->resource, - XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, - "xdg_popup was not created on the topmost popup"); - return; - } - - popup_grab->client = surface->client->client; - surface->popup_state->seat = seat_client->seat; - - wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); - - wlr_seat_pointer_start_grab(seat_client->seat, - &popup_grab->pointer_grab); - wlr_seat_keyboard_start_grab(seat_client->seat, - &popup_grab->keyboard_grab); -} - -static const struct xdg_popup_interface xdg_popup_implementation = { - .destroy = resource_destroy, - .grab = xdg_popup_protocol_grab, -}; - - static struct wlr_box xdg_positioner_get_geometry( struct wlr_xdg_positioner *positioner, struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent) { @@ -486,23 +448,90 @@ static struct wlr_box xdg_positioner_get_geometry( return geometry; } + +static const struct xdg_popup_interface xdg_popup_implementation; + +static struct wlr_xdg_surface *xdg_surface_from_xdg_popup_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_popup_interface, + &xdg_popup_implementation)); + return wl_resource_get_user_data(resource); +} + +static void xdg_popup_protocol_grab(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_popup_resource(resource); + struct wlr_seat_client *seat_client = + wlr_seat_client_from_resource(seat_resource); + + if (surface->popup_state->committed) { + wl_resource_post_error(surface->popup_state->resource, + XDG_POPUP_ERROR_INVALID_GRAB, + "xdg_popup is already mapped"); + return; + } + + struct wlr_xdg_popup_grab *popup_grab = + xdg_shell_popup_grab_from_seat(surface->client->shell, + seat_client->seat); + + struct wlr_xdg_surface *topmost = xdg_popup_grab_get_topmost(popup_grab); + bool parent_is_toplevel = + surface->popup_state->parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL; + + if ((topmost == NULL && !parent_is_toplevel) || + (topmost != NULL && topmost != surface->popup_state->parent)) { + wl_resource_post_error(surface->client->resource, + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was not created on the topmost popup"); + return; + } + + popup_grab->client = surface->client->client; + surface->popup_state->seat = seat_client->seat; + + wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); + + wlr_seat_pointer_start_grab(seat_client->seat, + &popup_grab->pointer_grab); + wlr_seat_keyboard_start_grab(seat_client->seat, + &popup_grab->keyboard_grab); +} + +static const struct xdg_popup_interface xdg_popup_implementation = { + .destroy = resource_destroy, + .grab = xdg_popup_protocol_grab, +}; + static void xdg_popup_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_popup_resource(resource); if (surface != NULL) { xdg_surface_destroy(surface); } } +static const struct xdg_surface_interface xdg_surface_implementation; + +static struct wlr_xdg_surface *xdg_surface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_surface_interface, + &xdg_surface_implementation)); + return wl_resource_get_user_data(resource); +} + static void xdg_surface_get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent_resource, struct wl_resource *positioner_resource) { struct wlr_xdg_surface *surface = - wl_resource_get_user_data(resource); + xdg_surface_from_resource(resource); struct wlr_xdg_surface *parent = - wl_resource_get_user_data(parent_resource); + xdg_surface_from_resource(parent_resource); struct wlr_xdg_positioner *positioner = - wl_resource_get_user_data(positioner_resource); + xdg_positioner_from_resource(positioner_resource); if (positioner->size.width == -1 || positioner->anchor_rect.width == -1) { wl_resource_post_error(resource, @@ -546,13 +575,23 @@ static void xdg_surface_get_popup(struct wl_client *client, } +static const struct xdg_toplevel_interface xdg_toplevel_implementation; + +static struct wlr_xdg_surface *xdg_surface_from_xdg_toplevel_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_toplevel_interface, + &xdg_toplevel_implementation)); + return wl_resource_get_user_data(resource); +} + static void xdg_toplevel_protocol_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_xdg_surface *parent = NULL; if (parent_resource != NULL) { - parent = wl_resource_get_user_data(parent_resource); + parent = xdg_surface_from_xdg_toplevel_resource(parent_resource); } surface->toplevel_state->parent = parent; @@ -560,7 +599,8 @@ static void xdg_toplevel_protocol_set_parent(struct wl_client *client, static void xdg_toplevel_protocol_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); char *tmp; tmp = strdup(title); @@ -574,7 +614,8 @@ static void xdg_toplevel_protocol_set_title(struct wl_client *client, static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); char *tmp; tmp = strdup(app_id); @@ -589,9 +630,10 @@ static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { wl_resource_post_error(surface->toplevel_state->resource, @@ -619,9 +661,10 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, static void xdg_toplevel_protocol_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { wl_resource_post_error(surface->toplevel_state->resource, @@ -647,9 +690,10 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, static void xdg_toplevel_protocol_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { wl_resource_post_error(surface->toplevel_state->resource, @@ -675,39 +719,44 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.max_width = width; surface->toplevel_state->next.max_height = height; } static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.min_width = width; surface->toplevel_state->next.min_height = height; } static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.maximized = true; wlr_signal_emit_safe(&surface->events.request_maximize, surface); } static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.maximized = false; wlr_signal_emit_safe(&surface->events.request_maximize, surface); } static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_output *output = NULL; if (output_resource != NULL) { - output = wl_resource_get_user_data(output_resource); + output = wlr_output_from_resource(output_resource); } surface->toplevel_state->next.fullscreen = true; @@ -723,7 +772,8 @@ static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.fullscreen = false; @@ -738,12 +788,12 @@ static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); wlr_signal_emit_safe(&surface->events.request_minimize, surface); } -static const struct xdg_toplevel_interface xdg_toplevel_implementation = -{ +static const struct xdg_toplevel_interface xdg_toplevel_implementation = { .destroy = resource_destroy, .set_parent = xdg_toplevel_protocol_set_parent, .set_title = xdg_toplevel_protocol_set_title, @@ -761,14 +811,16 @@ static const struct xdg_toplevel_interface xdg_toplevel_implementation = }; static void xdg_surface_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_resource(resource); if (surface != NULL) { xdg_surface_destroy(surface); } } static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); if (surface != NULL) { xdg_surface_destroy(surface); } @@ -776,7 +828,7 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { static void xdg_surface_get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role, resource, XDG_WM_BASE_ERROR_ROLE)) { @@ -818,7 +870,7 @@ static void wlr_xdg_toplevel_ack_configure( static void xdg_surface_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) { wl_resource_post_error(surface->resource, @@ -868,7 +920,7 @@ static void xdg_surface_ack_configure(struct wl_client *client, static void xdg_surface_set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - struct wlr_xdg_surface *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) { wl_resource_post_error(surface->resource, @@ -897,9 +949,7 @@ static bool wlr_xdg_surface_toplevel_state_compare( struct wlr_xdg_toplevel *state) { struct { struct wlr_xdg_toplevel_state state; - uint32_t width; - uint32_t height; - + uint32_t width, height; } configured; // is pending state different from current state? @@ -1158,11 +1208,20 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, } } +static const struct xdg_wm_base_interface xdg_shell_impl; + +static struct wlr_xdg_client *xdg_client_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_wm_base_interface, + &xdg_shell_impl)); + return wl_resource_get_user_data(resource); +} + static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, struct wl_resource *client_resource, uint32_t id, struct wl_resource *surface_resource) { struct wlr_xdg_client *client = - wl_resource_get_user_data(client_resource); + xdg_client_from_resource(client_resource); struct wlr_xdg_surface *surface; if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface)))) { @@ -1185,7 +1244,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, surface->client = client; surface->role = WLR_XDG_SURFACE_ROLE_NONE; - surface->surface = wl_resource_get_user_data(surface_resource); + surface->surface = wlr_surface_from_resource(surface_resource); surface->resource = wl_resource_create(wl_client, &xdg_surface_interface, wl_resource_get_version(client_resource), id); @@ -1236,7 +1295,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, static void xdg_shell_pong(struct wl_client *wl_client, struct wl_resource *resource, uint32_t serial) { - struct wlr_xdg_client *client = wl_resource_get_user_data(resource); + struct wlr_xdg_client *client = xdg_client_from_resource(resource); if (client->ping_serial != serial) { return; @@ -1246,7 +1305,7 @@ static void xdg_shell_pong(struct wl_client *wl_client, client->ping_serial = 0; } -static struct xdg_wm_base_interface xdg_shell_impl = { +static const struct xdg_wm_base_interface xdg_shell_impl = { .destroy = resource_destroy, .create_positioner = xdg_shell_create_positioner, .get_xdg_surface = xdg_shell_get_xdg_surface, @@ -1254,7 +1313,7 @@ static struct xdg_wm_base_interface xdg_shell_impl = { }; static void wlr_xdg_client_destroy(struct wl_resource *resource) { - struct wlr_xdg_client *client = wl_resource_get_user_data(resource); + struct wlr_xdg_client *client = xdg_client_from_resource(resource); struct wlr_xdg_surface *surface, *tmp = NULL; wl_list_for_each_safe(surface, tmp, &client->surfaces, link) { diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 1ea29664..aa833695 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -487,7 +487,8 @@ static void xdg_popup_resource_destroy(struct wl_resource *resource) { static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation; -static struct wlr_xdg_surface_v6 *xdg_surface_from_resource(struct wl_resource *resource) { +static struct wlr_xdg_surface_v6 *xdg_surface_from_resource( + struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &zxdg_surface_v6_interface, &zxdg_surface_v6_implementation)); return wl_resource_get_user_data(resource); @@ -918,9 +919,7 @@ static bool wlr_xdg_surface_v6_toplevel_state_compare( struct wlr_xdg_toplevel_v6 *state) { struct { struct wlr_xdg_toplevel_v6_state state; - uint32_t width; - uint32_t height; - + uint32_t width, height; } configured; // is pending state different from current state?