diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fc5ccd9b..41f504bc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -171,7 +171,7 @@ Try to keep the use of macros to a minimum, especially if a function can do the job. If you do need to use them, try to keep them close to where they're being used and `#undef` them after. -## Example +### Example ```c struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { @@ -232,3 +232,125 @@ error_session: return NULL; } ``` + +## Wayland protocol implementation + +Each protocol generally lives in a file with the same name, usually containing +at leats one struct for each interface in the protocol. For instance, +`xdg_shell` lives in `types/wlr_xdg_shell.h` and has a `wlr_xdg_surface` struct. + +### Globals + +Global interfaces generally have public constructors and destructors. Their +struct has a field holding the `wl_global` itself, a list of resources clients +created by binding to the global, a destroy signal and a `wl_display` destroy +listener. Example: + +```c +struct wlr_compositor { + struct wl_global *wl_global; + struct wl_list wl_resources; + … + + struct wl_listener display_destroy; + + struct { + struct wl_signal new_surface; + struct wl_signal destroy; + } events; +}; +``` + +When the destructor is called, it should emit the destroy signal, remove the +display destroy listener, destroy the `wl_global`, destroy all bound resources +and then destroy the struct. + +### Resources + +Resources are the representation of Wayland objects on the compositor side. They +generally have an associated struct, called the _object struct_, stored in their +`user_data` field. + +Object structs can be retrieved from resources via `wl_resource_get_data`. To +prevent bad casts, a safe helper function checking the type of the resource is +used: + +```c +static const struct wl_surface_interface surface_impl; + +struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_surface_interface, + &surface_impl)); + return wl_resource_get_user_data(resource); +} +``` + +### Destroying resources + +Object structs should only be destroyed when their resource is destroyed, ie. +in the resource destroy handler (set with `wl_resource_set_implementation`). +Destructor requests should only call `wl_resource_destroy`. + +The compositor should not destroy resources on its own. + +### Inert resources + +Some resources can become inert in situations described in the protocol or when +the compositor decides to get rid of them. All requests made to inert resources +should be ignored, except the destructor. This is achieved by: + +1. When the resource becomes inert: destroy the object struct and call + `wl_resource_set_user_data(resource, NULL)`. Do not destroy the resource. +2. For each request made to a resource that can be inert: add a NULL check to + ignore the request if the resource is inert. +3. When the client calls the destructor request on the resource: call + `wl_resource_destroy(resource)` as usual. +4. When the resource is destroyed, if the resource isn't inert, destroy the + object struct. + +Example: + +```c +// Handles the destroy request +static void subsurface_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +// Handles a regular request +static void subsurface_set_position(struct wl_client *client, + struct wl_resource *resource, int32_t x, int32_t y) { + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + if (subsurface == NULL) { + return; + } + + … +} + +// Destroys the wlr_subsurface struct +static void subsurface_destroy(struct wlr_subsurface *subsurface) { + if (subsurface == NULL) { + return; + } + + wl_resource_set_user_data(subsurface->resource, NULL); + + … + free(subsurface); +} + +// Resource destroy listener +static void subsurface_handle_resource_destroy(struct wl_resource *resource) { + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + subsurface_destroy(subsurface); +} + +// Makes the resource inert +static void subsurface_handle_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_subsurface *subsurface = + wl_container_of(listener, subsurface, surface_destroy); + subsurface_destroy(subsurface); +} +``` diff --git a/include/types/wlr_data_device.h b/include/types/wlr_data_device.h index 4aa53dc0..ee423f80 100644 --- a/include/types/wlr_data_device.h +++ b/include/types/wlr_data_device.h @@ -18,7 +18,8 @@ struct wlr_data_offer *data_offer_create(struct wl_client *client, void data_offer_update_action(struct wlr_data_offer *offer); struct wlr_client_data_source *client_data_source_create( - struct wl_client *client, uint32_t version, uint32_t id); + struct wl_client *client, uint32_t version, uint32_t id, + struct wl_list *resource_list); struct wlr_client_data_source *client_data_source_from_resource( struct wl_resource *resource); struct wlr_data_offer *data_source_send_offer(struct wlr_data_source *source, diff --git a/include/types/wlr_seat.h b/include/types/wlr_seat.h index b76525ec..15f1dc38 100644 --- a/include/types/wlr_seat.h +++ b/include/types/wlr_seat.h @@ -10,11 +10,14 @@ const struct wlr_touch_grab_interface default_touch_grab_impl; void seat_client_create_pointer(struct wlr_seat_client *seat_client, uint32_t version, uint32_t id); +void seat_client_destroy_pointer(struct wl_resource *resource); void seat_client_create_keyboard(struct wlr_seat_client *seat_client, uint32_t version, uint32_t id); +void seat_client_destroy_keyboard(struct wl_resource *resource); void seat_client_create_touch(struct wlr_seat_client *seat_client, uint32_t version, uint32_t id); +void seat_client_destroy_touch(struct wl_resource *resource); #endif diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 6fb41c29..80d4bc8b 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -15,8 +15,16 @@ wlr_touch_grab_interface wlr_data_device_touch_drag_interface; struct wlr_data_device_manager { struct wl_global *global; + struct wl_list wl_resources; + struct wl_list data_sources; struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + } events; + + void *data; }; struct wlr_data_offer { diff --git a/include/wlr/types/wlr_linux_dmabuf.h b/include/wlr/types/wlr_linux_dmabuf.h index 3fe8e1fc..531e68ab 100644 --- a/include/wlr/types/wlr_linux_dmabuf.h +++ b/include/wlr/types/wlr_linux_dmabuf.h @@ -25,8 +25,7 @@ struct wlr_dmabuf_buffer_attribs { uint64_t modifier[WLR_LINUX_DMABUF_MAX_PLANES]; int fd[WLR_LINUX_DMABUF_MAX_PLANES]; /* set via params_create */ - int32_t width; - int32_t height; + int32_t width, height; uint32_t format; uint32_t flags; }; @@ -61,8 +60,15 @@ struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource( /* the protocol interface */ struct wlr_linux_dmabuf { struct wl_global *wl_global; - struct wl_listener display_destroy; struct wlr_renderer *renderer; + struct wl_list wl_resources; + + struct { + struct wl_signal destroy; + } events; + + struct wl_listener display_destroy; + struct wl_listener renderer_destroy; }; /** diff --git a/types/data_device/wlr_data_device.c b/types/data_device/wlr_data_device.c index fffb2f1b..70ba3bfa 100644 --- a/types/data_device/wlr_data_device.c +++ b/types/data_device/wlr_data_device.c @@ -11,6 +11,8 @@ #include "types/wlr_data_device.h" #include "util/signal.h" +#define DATA_DEVICE_MANAGER_VERSION 3 + static const struct wl_data_device_interface data_device_impl; static struct wlr_seat_client *seat_client_from_data_device_resource( @@ -83,7 +85,7 @@ static const struct wl_data_device_interface data_device_impl = { .release = data_device_release, }; -static void data_device_destroy(struct wl_resource *resource) { +static void data_device_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); } @@ -164,6 +166,15 @@ void wlr_seat_set_selection(struct wlr_seat *seat, } +static const struct wl_data_device_manager_interface data_device_manager_impl; + +static struct wlr_data_device_manager *data_device_manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_data_device_manager_interface, + &data_device_manager_impl)); + return wl_resource_get_user_data(resource); +} + static void data_device_manager_get_data_device(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *seat_resource) { @@ -178,13 +189,17 @@ static void data_device_manager_get_data_device(struct wl_client *client, return; } wl_resource_set_implementation(resource, &data_device_impl, seat_client, - &data_device_destroy); + &data_device_handle_resource_destroy); wl_list_insert(&seat_client->data_devices, wl_resource_get_link(resource)); } static void data_device_manager_create_data_source(struct wl_client *client, - struct wl_resource *resource, uint32_t id) { - client_data_source_create(client, wl_resource_get_version(resource), id); + struct wl_resource *manager_resource, uint32_t id) { + struct wlr_data_device_manager *manager = + data_device_manager_from_resource(manager_resource); + + client_data_source_create(client, wl_resource_get_version(manager_resource), + id, &manager->data_sources); } static const struct wl_data_device_manager_interface @@ -193,8 +208,15 @@ static const struct wl_data_device_manager_interface .get_data_device = data_device_manager_get_data_device, }; +static void data_device_manager_handle_resource_destroy( + struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + static void data_device_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { + struct wlr_data_device_manager *manager = data; + struct wl_resource *resource = wl_resource_create(client, &wl_data_device_manager_interface, version, id); @@ -202,18 +224,26 @@ static void data_device_manager_bind(struct wl_client *client, wl_client_post_no_memory(client); return; } - wl_resource_set_implementation(resource, &data_device_manager_impl, - NULL, NULL); + manager, data_device_manager_handle_resource_destroy); + + wl_list_insert(&manager->wl_resources, wl_resource_get_link(resource)); } void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager) { if (!manager) { return; } + wlr_signal_emit_safe(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); - // TODO: free wl_resources wl_global_destroy(manager->global); + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &manager->wl_resources) { + wl_resource_destroy(resource); + } + wl_resource_for_each_safe(resource, tmp, &manager->data_sources) { + wl_resource_destroy(resource); + } free(manager); } @@ -232,11 +262,15 @@ struct wlr_data_device_manager *wlr_data_device_manager_create( return NULL; } + wl_list_init(&manager->wl_resources); + wl_list_init(&manager->data_sources); + wl_signal_init(&manager->events.destroy); + manager->global = wl_global_create(display, &wl_data_device_manager_interface, - 3, NULL, data_device_manager_bind); + DATA_DEVICE_MANAGER_VERSION, manager, data_device_manager_bind); if (!manager->global) { - wlr_log(L_ERROR, "could not create data device manager wl global"); + wlr_log(L_ERROR, "could not create data device manager wl_global"); free(manager); return NULL; } diff --git a/types/data_device/wlr_data_offer.c b/types/data_device/wlr_data_offer.c index dfaf054c..a5ea9183 100644 --- a/types/data_device/wlr_data_offer.c +++ b/types/data_device/wlr_data_offer.c @@ -145,7 +145,7 @@ static void data_offer_set_actions(struct wl_client *client, data_offer_update_action(offer); } -static void data_offer_resource_destroy(struct wl_resource *resource) { +static void data_offer_handle_resource_destroy(struct wl_resource *resource) { struct wlr_data_offer *offer = data_offer_from_resource(resource); if (!offer->source) { @@ -208,7 +208,7 @@ struct wlr_data_offer *data_offer_create(struct wl_client *client, return NULL; } wl_resource_set_implementation(offer->resource, &data_offer_impl, offer, - data_offer_resource_destroy); + data_offer_handle_resource_destroy); offer->source_destroy.notify = handle_offer_source_destroyed; wl_signal_add(&source->events.destroy, &offer->source_destroy); diff --git a/types/data_device/wlr_data_source.c b/types/data_device/wlr_data_source.c index 7c554d35..bf638f5a 100644 --- a/types/data_device/wlr_data_source.c +++ b/types/data_device/wlr_data_source.c @@ -245,11 +245,13 @@ static void data_source_handle_resource_destroy(struct wl_resource *resource) { struct wlr_client_data_source *source = client_data_source_from_resource(resource); wlr_data_source_finish(&source->source); + wl_list_remove(wl_resource_get_link(source->resource)); free(source); } struct wlr_client_data_source *client_data_source_create( - struct wl_client *client, uint32_t version, uint32_t id) { + struct wl_client *client, uint32_t version, uint32_t id, + struct wl_list *resource_list) { struct wlr_client_data_source *source = calloc(1, sizeof(struct wlr_client_data_source)); if (source == NULL) { @@ -265,6 +267,7 @@ struct wlr_client_data_source *client_data_source_create( } wl_resource_set_implementation(source->resource, &data_source_impl, source, data_source_handle_resource_destroy); + wl_list_insert(resource_list, wl_resource_get_link(source->resource)); source->impl.accept = client_data_source_accept; source->impl.send = client_data_source_send; diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index dc876f04..4a680157 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -12,11 +12,15 @@ #include "types/wlr_seat.h" #include "util/signal.h" +#define SEAT_VERSION 6 + static void seat_handle_get_pointer(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) { + wlr_log(L_ERROR, "Client sent get_pointer on seat without the " + "pointer capability"); return; } @@ -29,6 +33,8 @@ static void seat_handle_get_keyboard(struct wl_client *client, struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { + wlr_log(L_ERROR, "Client sent get_keyboard on seat without the " + "keyboard capability"); return; } @@ -41,6 +47,8 @@ static void seat_handle_get_touch(struct wl_client *client, struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) { + wlr_log(L_ERROR, "Client sent get_touch on seat without the " + "touch capability"); return; } @@ -48,7 +56,8 @@ static void seat_handle_get_touch(struct wl_client *client, seat_client_create_touch(seat_client, version, id); } -static void seat_client_resource_destroy(struct wl_resource *seat_resource) { +static void seat_client_handle_resource_destroy( + struct wl_resource *seat_resource) { struct wlr_seat_client *client = wlr_seat_client_from_resource(seat_resource); wlr_signal_emit_safe(&client->events.destroy, client); @@ -120,7 +129,7 @@ static void seat_handle_bind(struct wl_client *client, void *_wlr_seat, wl_list_init(&seat_client->data_devices); wl_list_init(&seat_client->primary_selection_devices); wl_resource_set_implementation(seat_client->wl_resource, &seat_impl, - seat_client, seat_client_resource_destroy); + seat_client, seat_client_handle_resource_destroy); wl_list_insert(&wlr_seat->clients, &seat_client->link); if (version >= WL_SEAT_NAME_SINCE_VERSION) { wl_seat_send_name(seat_client->wl_resource, wlr_seat->name); @@ -170,41 +179,41 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { } struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { - struct wlr_seat *wlr_seat = calloc(1, sizeof(struct wlr_seat)); - if (!wlr_seat) { + struct wlr_seat *seat = calloc(1, sizeof(struct wlr_seat)); + if (!seat) { return NULL; } // pointer state - wlr_seat->pointer_state.seat = wlr_seat; - wl_list_init(&wlr_seat->pointer_state.surface_destroy.link); + seat->pointer_state.seat = seat; + wl_list_init(&seat->pointer_state.surface_destroy.link); struct wlr_seat_pointer_grab *pointer_grab = calloc(1, sizeof(struct wlr_seat_pointer_grab)); if (!pointer_grab) { - free(wlr_seat); + free(seat); return NULL; } pointer_grab->interface = &default_pointer_grab_impl; - pointer_grab->seat = wlr_seat; - wlr_seat->pointer_state.default_grab = pointer_grab; - wlr_seat->pointer_state.grab = pointer_grab; + pointer_grab->seat = seat; + seat->pointer_state.default_grab = pointer_grab; + seat->pointer_state.grab = pointer_grab; // keyboard state struct wlr_seat_keyboard_grab *keyboard_grab = calloc(1, sizeof(struct wlr_seat_keyboard_grab)); if (!keyboard_grab) { free(pointer_grab); - free(wlr_seat); + free(seat); return NULL; } keyboard_grab->interface = &default_keyboard_grab_impl; - keyboard_grab->seat = wlr_seat; - wlr_seat->keyboard_state.default_grab = keyboard_grab; - wlr_seat->keyboard_state.grab = keyboard_grab; + keyboard_grab->seat = seat; + seat->keyboard_state.default_grab = keyboard_grab; + seat->keyboard_state.grab = keyboard_grab; - wlr_seat->keyboard_state.seat = wlr_seat; - wl_list_init(&wlr_seat->keyboard_state.surface_destroy.link); + seat->keyboard_state.seat = seat; + wl_list_init(&seat->keyboard_state.surface_destroy.link); // touch state struct wlr_seat_touch_grab *touch_grab = @@ -212,57 +221,58 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { if (!touch_grab) { free(pointer_grab); free(keyboard_grab); - free(wlr_seat); + free(seat); return NULL; } touch_grab->interface = &default_touch_grab_impl; - touch_grab->seat = wlr_seat; - wlr_seat->touch_state.default_grab = touch_grab; - wlr_seat->touch_state.grab = touch_grab; + touch_grab->seat = seat; + seat->touch_state.default_grab = touch_grab; + seat->touch_state.grab = touch_grab; - wlr_seat->touch_state.seat = wlr_seat; - wl_list_init(&wlr_seat->touch_state.touch_points); + seat->touch_state.seat = seat; + wl_list_init(&seat->touch_state.touch_points); - struct wl_global *wl_global = wl_global_create(display, - &wl_seat_interface, 6, wlr_seat, seat_handle_bind); - if (!wl_global) { - free(wlr_seat); + seat->wl_global = wl_global_create(display, &wl_seat_interface, + SEAT_VERSION, seat, seat_handle_bind); + if (seat->wl_global == NULL) { + free(touch_grab); + free(pointer_grab); + free(keyboard_grab); + free(seat); return NULL; } - wlr_seat->wl_global = wl_global; - wlr_seat->display = display; - wlr_seat->name = strdup(name); - wl_list_init(&wlr_seat->clients); - wl_list_init(&wlr_seat->drag_icons); + seat->display = display; + seat->name = strdup(name); + wl_list_init(&seat->clients); + wl_list_init(&seat->drag_icons); - wl_signal_init(&wlr_seat->events.start_drag); - wl_signal_init(&wlr_seat->events.new_drag_icon); + wl_signal_init(&seat->events.start_drag); + wl_signal_init(&seat->events.new_drag_icon); - wl_signal_init(&wlr_seat->events.request_set_cursor); + wl_signal_init(&seat->events.request_set_cursor); - wl_signal_init(&wlr_seat->events.selection); - wl_signal_init(&wlr_seat->events.primary_selection); + wl_signal_init(&seat->events.selection); + wl_signal_init(&seat->events.primary_selection); - wl_signal_init(&wlr_seat->events.pointer_grab_begin); - wl_signal_init(&wlr_seat->events.pointer_grab_end); + wl_signal_init(&seat->events.pointer_grab_begin); + wl_signal_init(&seat->events.pointer_grab_end); - wl_signal_init(&wlr_seat->events.keyboard_grab_begin); - wl_signal_init(&wlr_seat->events.keyboard_grab_end); + wl_signal_init(&seat->events.keyboard_grab_begin); + wl_signal_init(&seat->events.keyboard_grab_end); - wl_signal_init(&wlr_seat->events.touch_grab_begin); - wl_signal_init(&wlr_seat->events.touch_grab_end); + wl_signal_init(&seat->events.touch_grab_begin); + wl_signal_init(&seat->events.touch_grab_end); - wl_signal_init(&wlr_seat->events.destroy); + wl_signal_init(&seat->events.destroy); - wlr_seat->display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(display, &wlr_seat->display_destroy); + seat->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &seat->display_destroy); - return wlr_seat; + return seat; } struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat, struct wl_client *wl_client) { - assert(wlr_seat); struct wlr_seat_client *seat_client; wl_list_for_each(seat_client, &wlr_seat->clients, link) { if (seat_client->client == wl_client) { @@ -275,8 +285,29 @@ struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat, void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat, uint32_t capabilities) { wlr_seat->capabilities = capabilities; + struct wlr_seat_client *client; wl_list_for_each(client, &wlr_seat->clients, link) { + // Make resources inert if necessary + if ((capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) { + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &client->pointers) { + seat_client_destroy_pointer(resource); + } + } + if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0) { + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &client->keyboards) { + seat_client_destroy_keyboard(resource); + } + } + if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) == 0) { + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &client->touches) { + seat_client_destroy_touch(resource); + } + } + wl_seat_send_capabilities(client->wl_resource, capabilities); } } diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index 975b195c..77fda68f 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -48,8 +48,16 @@ static const struct wl_keyboard_interface keyboard_impl = { .release = keyboard_release, }; +static struct wlr_seat_client *seat_client_from_keyboard_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_keyboard_interface, + &keyboard_impl)); + return wl_resource_get_user_data(resource); +} + static void keyboard_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); + seat_client_destroy_keyboard(resource); } @@ -63,6 +71,10 @@ void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time, uint32_t serial = wl_display_next_serial(wlr_seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } + wl_keyboard_send_key(resource, serial, time, key, state); } } @@ -188,6 +200,10 @@ void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, uint32_t serial = wl_display_next_serial(seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } + if (modifiers == NULL) { wl_keyboard_send_modifiers(resource, serial, 0, 0, 0, 0); } else { @@ -223,6 +239,9 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, uint32_t serial = wl_display_next_serial(seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &focused_client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } wl_keyboard_send_leave(resource, serial, focused_surface->resource); } } @@ -243,6 +262,9 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, uint32_t serial = wl_display_next_serial(seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } wl_keyboard_send_enter(resource, serial, surface->resource, &keys); } wl_array_release(&keys); @@ -312,6 +334,10 @@ static void seat_client_send_keymap(struct wlr_seat_client *client, // keyboard struct wl_resource *resource; wl_resource_for_each(resource, &client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } + wl_keyboard_send_keymap(resource, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keyboard->keymap_fd, keyboard->keymap_size); @@ -326,6 +352,10 @@ static void seat_client_send_repeat_info(struct wlr_seat_client *client, struct wl_resource *resource; wl_resource_for_each(resource, &client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } + if (wl_resource_get_version(resource) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { wl_keyboard_send_repeat_info(resource, @@ -343,7 +373,7 @@ void seat_client_create_keyboard(struct wlr_seat_client *seat_client, return; } wl_resource_set_implementation(resource, &keyboard_impl, seat_client, - &keyboard_handle_resource_destroy); + keyboard_handle_resource_destroy); wl_list_insert(&seat_client->keyboards, wl_resource_get_link(resource)); struct wlr_keyboard *keyboard = seat_client->seat->keyboard_state.keyboard; @@ -353,3 +383,12 @@ void seat_client_create_keyboard(struct wlr_seat_client *seat_client, // TODO possibly handle the case where this keyboard needs an enter // right away } + +void seat_client_destroy_keyboard(struct wl_resource *resource) { + struct wlr_seat_client *seat_client = + seat_client_from_keyboard_resource(resource); + if (seat_client == NULL) { + return; + } + wl_resource_set_user_data(resource, NULL); +} diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 344597b5..4a0bcef1 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -64,30 +64,27 @@ static void pointer_set_cursor(struct wl_client *client, int32_t hotspot_x, int32_t hotspot_y) { struct wlr_seat_client *seat_client = seat_client_from_pointer_resource(pointer_resource); + if (seat_client == NULL) { + return; + } + struct wlr_surface *surface = NULL; if (surface_resource != NULL) { surface = wlr_surface_from_resource(surface_resource); - if (wlr_surface_set_role(surface, "wl_pointer-cursor", surface_resource, WL_POINTER_ERROR_ROLE) < 0) { return; } } - struct wlr_seat_pointer_request_set_cursor_event *event = - calloc(1, sizeof(struct wlr_seat_pointer_request_set_cursor_event)); - if (event == NULL) { - return; - } - event->seat_client = seat_client; - event->surface = surface; - event->serial = serial; - event->hotspot_x = hotspot_x; - event->hotspot_y = hotspot_y; - - wlr_signal_emit_safe(&seat_client->seat->events.request_set_cursor, event); - - free(event); + struct wlr_seat_pointer_request_set_cursor_event event = { + .seat_client = seat_client, + .surface = surface, + .serial = serial, + .hotspot_x = hotspot_x, + .hotspot_y = hotspot_y, + }; + wlr_signal_emit_safe(&seat_client->seat->events.request_set_cursor, &event); } static void pointer_release(struct wl_client *client, @@ -102,6 +99,7 @@ static const struct wl_pointer_interface pointer_impl = { static void pointer_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); + seat_client_destroy_pointer(resource); } @@ -112,8 +110,8 @@ bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat, static void seat_pointer_handle_surface_destroy(struct wl_listener *listener, void *data) { - struct wlr_seat_pointer_state *state = wl_container_of( - listener, state, surface_destroy); + struct wlr_seat_pointer_state *state = + wl_container_of(listener, state, surface_destroy); wl_list_remove(&state->surface_destroy.link); wl_list_init(&state->surface_destroy.link); wlr_seat_pointer_clear_focus(state->seat); @@ -121,8 +119,6 @@ static void seat_pointer_handle_surface_destroy(struct wl_listener *listener, void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, struct wlr_surface *surface, double sx, double sy) { - assert(wlr_seat); - if (wlr_seat->pointer_state.focused_surface == surface) { // this surface already got an enter notify return; @@ -144,6 +140,10 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, uint32_t serial = wl_display_next_serial(wlr_seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &focused_client->pointers) { + if (seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + wl_pointer_send_leave(resource, serial, focused_surface->resource); pointer_send_frame(resource); } @@ -154,6 +154,10 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, uint32_t serial = wl_display_next_serial(wlr_seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { + if (seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + wl_pointer_send_enter(resource, serial, surface->resource, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); pointer_send_frame(resource); @@ -189,6 +193,10 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { + if (seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + wl_pointer_send_motion(resource, time, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); pointer_send_frame(resource); @@ -205,6 +213,10 @@ uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, uint32_t serial = wl_display_next_serial(wlr_seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { + if (seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + wl_pointer_send_button(resource, serial, time, button, state); pointer_send_frame(resource); } @@ -220,6 +232,10 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { + if (seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + if (value) { wl_pointer_send_axis(resource, time, orientation, wl_fixed_from_double(value)); @@ -235,7 +251,6 @@ void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat, struct wlr_seat_pointer_grab *grab) { assert(wlr_seat); grab->seat = wlr_seat; - assert(grab->seat); wlr_seat->pointer_state.grab = grab; wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_begin, grab); @@ -312,3 +327,12 @@ void seat_client_create_pointer(struct wlr_seat_client *seat_client, &pointer_handle_resource_destroy); wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource)); } + +void seat_client_destroy_pointer(struct wl_resource *resource) { + struct wlr_seat_client *seat_client = + seat_client_from_pointer_resource(resource); + if (seat_client == NULL) { + return; + } + wl_resource_set_user_data(resource, NULL); +} diff --git a/types/seat/wlr_seat_touch.c b/types/seat/wlr_seat_touch.c index a81369df..489882ba 100644 --- a/types/seat/wlr_seat_touch.c +++ b/types/seat/wlr_seat_touch.c @@ -9,8 +9,8 @@ #include "types/wlr_seat.h" #include "util/signal.h" -static uint32_t default_touch_down(struct wlr_seat_touch_grab *grab, uint32_t time, - struct wlr_touch_point *point) { +static uint32_t default_touch_down(struct wlr_seat_touch_grab *grab, + uint32_t time, struct wlr_touch_point *point) { return wlr_seat_touch_send_down(grab->seat, point->surface, time, point->touch_id, point->sx, point->sy); } @@ -57,6 +57,14 @@ static const struct wl_touch_interface touch_impl = { static void touch_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); + seat_client_destroy_touch(resource); +} + +static struct wlr_seat_client *seat_client_from_touch_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_touch_interface, + &touch_impl)); + return wl_resource_get_user_data(resource); } @@ -273,6 +281,9 @@ uint32_t wlr_seat_touch_send_down(struct wlr_seat *seat, uint32_t serial = wl_display_next_serial(seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &point->client->touches) { + if (seat_client_from_touch_resource(resource) == NULL) { + continue; + } wl_touch_send_down(resource, serial, time, surface->resource, touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); wl_touch_send_frame(resource); @@ -291,6 +302,9 @@ void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time, int32_t touch_ uint32_t serial = wl_display_next_serial(seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &point->client->touches) { + if (seat_client_from_touch_resource(resource) == NULL) { + continue; + } wl_touch_send_up(resource, serial, time, touch_id); wl_touch_send_frame(resource); } @@ -306,6 +320,9 @@ void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, int32_t to struct wl_resource *resource; wl_resource_for_each(resource, &point->client->touches) { + if (seat_client_from_touch_resource(resource) == NULL) { + continue; + } wl_touch_send_motion(resource, time, touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); wl_touch_send_frame(resource); @@ -333,3 +350,12 @@ void seat_client_create_touch(struct wlr_seat_client *seat_client, &touch_handle_resource_destroy); wl_list_insert(&seat_client->touches, wl_resource_get_link(resource)); } + +void seat_client_destroy_touch(struct wl_resource *resource) { + struct wlr_seat_client *seat_client = + seat_client_from_touch_resource(resource); + if (seat_client == NULL) { + return; + } + wl_resource_set_user_data(resource, NULL); +} diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index f10d891c..e4fd41dc 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -7,6 +7,9 @@ #include #include "util/signal.h" +#define COMPOSITOR_VERSION 4 +#define SUBCOMPOSITOR_VERSION 1 + static const char *subsurface_role = "wl_subsurface"; bool wlr_surface_is_subsurface(struct wlr_surface *surface) { @@ -105,7 +108,8 @@ static void subcompositor_bind(struct wl_client *client, void *data, static void subcompositor_init(struct wlr_subcompositor *subcompositor, struct wl_display *display) { subcompositor->wl_global = wl_global_create(display, - &wl_subcompositor_interface, 1, subcompositor, subcompositor_bind); + &wl_subcompositor_interface, SUBCOMPOSITOR_VERSION, subcompositor, + subcompositor_bind); if (subcompositor->wl_global == NULL) { wlr_log_errno(L_ERROR, "Could not allocate subcompositor global"); return; @@ -136,7 +140,7 @@ static struct wlr_compositor *compositor_from_resource( return wl_resource_get_user_data(resource); } -static void wl_compositor_create_surface(struct wl_client *client, +static void compositor_create_surface(struct wl_client *client, struct wl_resource *resource, uint32_t id) { struct wlr_compositor *compositor = compositor_from_resource(resource); @@ -150,7 +154,7 @@ static void wl_compositor_create_surface(struct wl_client *client, wlr_signal_emit_safe(&compositor->events.new_surface, surface); } -static void wl_compositor_create_region(struct wl_client *client, +static void compositor_create_region(struct wl_client *client, struct wl_resource *resource, uint32_t id) { struct wlr_compositor *compositor = compositor_from_resource(resource); @@ -158,15 +162,15 @@ static void wl_compositor_create_region(struct wl_client *client, } static const struct wl_compositor_interface compositor_impl = { - .create_surface = wl_compositor_create_surface, - .create_region = wl_compositor_create_region, + .create_surface = compositor_create_surface, + .create_region = compositor_create_region, }; static void compositor_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); } -static void wl_compositor_bind(struct wl_client *wl_client, void *data, +static void compositor_bind(struct wl_client *wl_client, void *data, uint32_t version, uint32_t id) { struct wlr_compositor *compositor = data; assert(wl_client && compositor); @@ -218,14 +222,13 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display, return NULL; } - struct wl_global *compositor_global = wl_global_create(display, - &wl_compositor_interface, 4, compositor, wl_compositor_bind); - if (!compositor_global) { - wlr_log_errno(L_ERROR, "Could not allocate compositor global"); + compositor->wl_global = wl_global_create(display, &wl_compositor_interface, + COMPOSITOR_VERSION, compositor, compositor_bind); + if (!compositor->wl_global) { free(compositor); + wlr_log_errno(L_ERROR, "Could not allocate compositor global"); return NULL; } - compositor->wl_global = compositor_global; compositor->renderer = renderer; wl_list_init(&compositor->wl_resources); diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c index f190be24..9bcd473f 100644 --- a/types/wlr_linux_dmabuf.c +++ b/types/wlr_linux_dmabuf.c @@ -7,26 +7,29 @@ #include #include #include "linux-dmabuf-unstable-v1-protocol.h" +#include "util/signal.h" -static void wl_buffer_destroy(struct wl_client *client, +#define LINUX_DMABUF_VERSION 3 + +static void buffer_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } -static const struct wl_buffer_interface wl_buffer_impl = { - wl_buffer_destroy, +static const struct wl_buffer_interface buffer_impl = { + .destroy = buffer_handle_destroy, }; bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) { if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface, - &wl_buffer_impl)) { + &buffer_impl)) { return false; } struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(buffer_resource); if (buffer && buffer->buffer_resource && !buffer->params_resource && - buffer->buffer_resource == buffer_resource) { + buffer->buffer_resource == buffer_resource) { return true; } @@ -36,7 +39,7 @@ bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) { struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource( struct wl_resource *buffer_resource) { assert(wl_resource_instance_of(buffer_resource, &wl_buffer_interface, - &wl_buffer_impl)); + &buffer_impl)); struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(buffer_resource); @@ -103,11 +106,9 @@ static void params_add(struct wl_client *client, buffer->attributes.n_planes++; } -static void handle_buffer_destroy(struct wl_resource *buffer_resource) -{ +static void buffer_handle_resource_destroy(struct wl_resource *buffer_resource) { struct wlr_dmabuf_buffer *buffer = wlr_dmabuf_buffer_from_buffer_resource(buffer_resource); - linux_dmabuf_buffer_destroy(buffer); } @@ -144,7 +145,7 @@ static void params_create_common(struct wl_client *client, if ((buffer->attributes.fd[3] >= 0 || buffer->attributes.fd[2] >= 0) && (buffer->attributes.fd[2] == -1 || buffer->attributes.fd[1] == -1)) { - wl_resource_post_error (params_resource, + wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "gap in dmabuf planes"); goto err_out; @@ -229,7 +230,7 @@ static void params_create_common(struct wl_client *client, } wl_resource_set_implementation(buffer->buffer_resource, - &wl_buffer_impl, buffer, handle_buffer_destroy); + &buffer_impl, buffer, buffer_handle_resource_destroy); /* send 'created' event when the request is not for an immediate * import, that is buffer_id is zero */ @@ -324,8 +325,7 @@ static void linux_dmabuf_create_params(struct wl_client *client, buffer->renderer = linux_dmabuf->renderer; buffer->params_resource = wl_resource_create(client, - &zwp_linux_buffer_params_v1_interface, - version, params_id); + &zwp_linux_buffer_params_v1_interface, version, params_id); if (!buffer->params_resource) { goto err_free; } @@ -400,6 +400,10 @@ static void linux_dmabuf_send_modifiers(struct wlr_linux_dmabuf *linux_dmabuf, free(formats); } +static void linux_dmabuf_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + static void linux_dmabuf_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct wlr_linux_dmabuf *linux_dmabuf = data; @@ -410,21 +414,29 @@ static void linux_dmabuf_bind(struct wl_client *client, void *data, wl_client_post_no_memory(client); return; } - wl_resource_set_implementation(resource, &linux_dmabuf_impl, - linux_dmabuf, NULL); - if (version < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) { - return; - } + linux_dmabuf, linux_dmabuf_resource_destroy); + wl_list_insert(&linux_dmabuf->wl_resources, wl_resource_get_link(resource)); - linux_dmabuf_send_modifiers(linux_dmabuf, resource); + if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) { + linux_dmabuf_send_modifiers(linux_dmabuf, resource); + } } void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf) { if (!linux_dmabuf) { return; } + + wlr_signal_emit_safe(&linux_dmabuf->events.destroy, linux_dmabuf); + wl_list_remove(&linux_dmabuf->display_destroy.link); + wl_list_remove(&linux_dmabuf->renderer_destroy.link); + + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &linux_dmabuf->wl_resources) { + wl_resource_destroy(resource); + } wl_global_destroy(linux_dmabuf->wl_global); free(linux_dmabuf); @@ -436,6 +448,12 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { wlr_linux_dmabuf_destroy(linux_dmabuf); } +static void handle_renderer_destroy(struct wl_listener *listener, void *data) { + struct wlr_linux_dmabuf *linux_dmabuf = + wl_container_of(listener, linux_dmabuf, renderer_destroy); + wlr_linux_dmabuf_destroy(linux_dmabuf); +} + struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display, struct wlr_renderer *renderer) { struct wlr_linux_dmabuf *linux_dmabuf = @@ -446,9 +464,12 @@ struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display, } linux_dmabuf->renderer = renderer; + wl_list_init(&linux_dmabuf->wl_resources); + wl_signal_init(&linux_dmabuf->events.destroy); + linux_dmabuf->wl_global = wl_global_create(display, &zwp_linux_dmabuf_v1_interface, - 3, linux_dmabuf, linux_dmabuf_bind); + LINUX_DMABUF_VERSION, linux_dmabuf, linux_dmabuf_bind); if (!linux_dmabuf->wl_global) { wlr_log(L_ERROR, "could not create linux dmabuf v1 wl global"); free(linux_dmabuf); @@ -458,5 +479,8 @@ struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display, linux_dmabuf->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &linux_dmabuf->display_destroy); + linux_dmabuf->renderer_destroy.notify = handle_renderer_destroy; + wl_signal_add(&renderer->events.destroy, &linux_dmabuf->renderer_destroy); + return linux_dmabuf; } diff --git a/types/wlr_output.c b/types/wlr_output.c index a8361ead..d45e91a4 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -7,15 +7,17 @@ #include #include #include -#include #include +#include #include #include #include #include #include "util/signal.h" -static void wl_output_send_to_resource(struct wl_resource *resource) { +#define OUTPUT_VERSION 3 + +static void output_send_to_resource(struct wl_resource *resource) { struct wlr_output *output = wlr_output_from_resource(resource); const uint32_t version = wl_resource_get_version(resource); if (version >= WL_OUTPUT_GEOMETRY_SINCE_VERSION) { @@ -70,42 +72,33 @@ static void output_send_current_mode_to_resource( } } -static void wl_output_destroy(struct wl_resource *resource) { - struct wlr_output *output = wlr_output_from_resource(resource); - struct wl_resource *_resource; - wl_resource_for_each(_resource, &output->wl_resources) { - if (_resource == resource) { - struct wl_list *link = wl_resource_get_link(_resource); - wl_list_remove(link); - break; - } - } +static void output_handle_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); } -static void wl_output_release(struct wl_client *client, +static void output_handle_release(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } -static struct wl_output_interface wl_output_impl = { - .release = wl_output_release, +static const struct wl_output_interface output_impl = { + .release = output_handle_release, }; static void wl_output_bind(struct wl_client *wl_client, void *data, uint32_t version, uint32_t id) { struct wlr_output *wlr_output = data; - struct wl_resource *wl_resource = wl_resource_create(wl_client, + struct wl_resource *resource = wl_resource_create(wl_client, &wl_output_interface, version, id); - if (wl_resource == NULL) { + if (resource == NULL) { wl_client_post_no_memory(wl_client); return; } - wl_resource_set_implementation(wl_resource, &wl_output_impl, wlr_output, - wl_output_destroy); - wl_list_insert(&wlr_output->wl_resources, - wl_resource_get_link(wl_resource)); - wl_output_send_to_resource(wl_resource); + wl_resource_set_implementation(resource, &output_impl, wlr_output, + output_handle_resource_destroy); + wl_list_insert(&wlr_output->wl_resources, wl_resource_get_link(resource)); + output_send_to_resource(resource); } void wlr_output_create_global(struct wlr_output *output) { @@ -113,7 +106,7 @@ void wlr_output_create_global(struct wlr_output *output) { return; } struct wl_global *wl_global = wl_global_create(output->display, - &wl_output_interface, 3, output, wl_output_bind); + &wl_output_interface, OUTPUT_VERSION, output, wl_output_bind); output->wl_global = wl_global; } @@ -205,7 +198,7 @@ void wlr_output_set_transform(struct wlr_output *output, // TODO: only send geometry and done struct wl_resource *resource; wl_resource_for_each(resource, &output->wl_resources) { - wl_output_send_to_resource(resource); + output_send_to_resource(resource); } wlr_signal_emit_safe(&output->events.transform, output); @@ -223,7 +216,7 @@ void wlr_output_set_position(struct wlr_output *output, int32_t lx, // TODO: only send geometry and done struct wl_resource *resource; wl_resource_for_each(resource, &output->wl_resources) { - wl_output_send_to_resource(resource); + output_send_to_resource(resource); } } @@ -237,7 +230,7 @@ void wlr_output_set_scale(struct wlr_output *output, float scale) { // TODO: only send mode and done struct wl_resource *resource; wl_resource_for_each(resource, &output->wl_resources) { - wl_output_send_to_resource(resource); + output_send_to_resource(resource); } wlr_signal_emit_safe(&output->events.scale, output); @@ -649,7 +642,7 @@ void wlr_output_set_fullscreen_surface(struct wlr_output *output, struct wlr_output *wlr_output_from_resource(struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &wl_output_interface, - &wl_output_impl)); + &output_impl)); return wl_resource_get_user_data(resource); } diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 0cf8fec2..775f7adf 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -11,6 +11,10 @@ #include #include "util/signal.h" +#define CALLBACK_VERSION 1 +#define SURFACE_VERSION 4 +#define SUBSURFACE_VERSION 1 + static void surface_state_reset_buffer(struct wlr_surface_state *state) { if (state->buffer) { wl_list_remove(&state->buffer_destroy_listener.link); @@ -18,29 +22,29 @@ static void surface_state_reset_buffer(struct wlr_surface_state *state) { } } -static void buffer_destroy(struct wl_listener *listener, void *data) { +static void surface_handle_buffer_destroy(struct wl_listener *listener, + void *data) { struct wlr_surface_state *state = wl_container_of(listener, state, buffer_destroy_listener); - - wl_list_remove(&state->buffer_destroy_listener.link); - state->buffer = NULL; + surface_state_reset_buffer(state); } static void surface_state_release_buffer(struct wlr_surface_state *state) { if (state->buffer) { wl_resource_post_event(state->buffer, WL_BUFFER_RELEASE); - wl_list_remove(&state->buffer_destroy_listener.link); - state->buffer = NULL; + surface_state_reset_buffer(state); } } static void surface_state_set_buffer(struct wlr_surface_state *state, struct wl_resource *buffer) { + surface_state_reset_buffer(state); + state->buffer = buffer; if (buffer) { wl_resource_add_destroy_listener(buffer, &state->buffer_destroy_listener); - state->buffer_destroy_listener.notify = buffer_destroy; + state->buffer_destroy_listener.notify = surface_handle_buffer_destroy; } } @@ -57,7 +61,6 @@ static void surface_attach(struct wl_client *client, surface->pending->invalid |= WLR_SURFACE_INVALID_BUFFER; surface->pending->sx = sx; surface->pending->sy = sy; - surface_state_reset_buffer(surface->pending); surface_state_set_buffer(surface->pending, buffer); } @@ -80,7 +83,7 @@ static struct wlr_frame_callback *frame_callback_from_resource( return wl_resource_get_user_data(resource); } -static void destroy_frame_callback(struct wl_resource *resource) { +static void callback_handle_resource_destroy(struct wl_resource *resource) { struct wlr_frame_callback *cb = frame_callback_from_resource(resource); wl_list_remove(&cb->link); free(cb); @@ -97,16 +100,15 @@ static void surface_frame(struct wl_client *client, return; } - cb->resource = wl_resource_create(client, &wl_callback_interface, 1, - callback); + cb->resource = wl_resource_create(client, &wl_callback_interface, + CALLBACK_VERSION, callback); if (cb->resource == NULL) { free(cb); wl_resource_post_no_memory(resource); return; } - wl_resource_set_implementation(cb->resource, NULL, cb, - destroy_frame_callback); + callback_handle_resource_destroy); wl_list_insert(surface->pending->frame_callback_list.prev, &cb->link); @@ -548,7 +550,7 @@ static void surface_damage_buffer(struct wl_client *client, x, y, width, height); } -const struct wl_surface_interface surface_interface = { +static const struct wl_surface_interface surface_interface = { .destroy = surface_destroy, .attach = surface_attach, .damage = surface_damage, @@ -584,7 +586,6 @@ static struct wlr_surface_state *surface_state_create() { pixman_region32_init_rect(&state->input, INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX); - return state; } @@ -604,6 +605,10 @@ static void surface_state_destroy(struct wlr_surface_state *state) { } static void subsurface_destroy(struct wlr_subsurface *subsurface) { + if (subsurface == NULL) { + return; + } + wlr_signal_emit_safe(&subsurface->events.destroy, subsurface); wl_list_remove(&subsurface->surface_destroy.link); @@ -615,8 +620,6 @@ static void subsurface_destroy(struct wlr_subsurface *subsurface) { wl_list_remove(&subsurface->parent_destroy.link); } - wl_list_remove(wl_resource_get_link(subsurface->resource)); - wl_resource_set_user_data(subsurface->resource, NULL); if (subsurface->surface) { subsurface->surface->role_data = NULL; @@ -649,6 +652,8 @@ static void surface_handle_renderer_destroy(struct wl_listener *listener, struct wlr_surface *wlr_surface_create(struct wl_client *client, uint32_t version, uint32_t id, struct wlr_renderer *renderer, struct wl_list *resource_list) { + assert(version <= SURFACE_VERSION); + struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface)); if (!surface) { wl_client_post_no_memory(client); @@ -726,10 +731,8 @@ static struct wlr_subsurface *subsurface_from_resource( static void subsurface_resource_destroy(struct wl_resource *resource) { struct wlr_subsurface *subsurface = subsurface_from_resource(resource); - - if (subsurface) { - subsurface_destroy(subsurface); - } + wl_list_remove(wl_resource_get_link(resource)); + subsurface_destroy(subsurface); } static void subsurface_handle_destroy(struct wl_client *client, @@ -737,13 +740,15 @@ static void subsurface_handle_destroy(struct wl_client *client, wl_resource_destroy(resource); } -static void subsurface_set_position(struct wl_client *client, +static void subsurface_handle_set_position(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + if (subsurface == NULL) { + return; + } + struct wlr_surface *surface = subsurface->surface; - surface->pending->invalid |= WLR_SURFACE_INVALID_SUBSURFACE_POSITION; - surface->pending->subsurface_position.x = x; surface->pending->subsurface_position.y = y; } @@ -762,9 +767,12 @@ static struct wlr_subsurface *subsurface_find_sibling( return NULL; } -static void subsurface_place_above(struct wl_client *client, +static void subsurface_handle_place_above(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource) { struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + if (subsurface == NULL) { + return; + } struct wlr_surface *sibling_surface = wlr_surface_from_resource(sibling_resource); @@ -786,9 +794,12 @@ static void subsurface_place_above(struct wl_client *client, subsurface->reordered = true; } -static void subsurface_place_below(struct wl_client *client, +static void subsurface_handle_place_below(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource) { struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + if (subsurface == NULL) { + return; + } struct wlr_surface *sibling_surface = wlr_surface_from_resource(sibling_resource); @@ -810,20 +821,24 @@ static void subsurface_place_below(struct wl_client *client, subsurface->reordered = true; } -static void subsurface_set_sync(struct wl_client *client, +static void subsurface_handle_set_sync(struct wl_client *client, struct wl_resource *resource) { struct wlr_subsurface *subsurface = subsurface_from_resource(resource); - - if (subsurface) { - subsurface->synchronized = true; + if (subsurface == NULL) { + return; } + + subsurface->synchronized = true; } -static void subsurface_set_desync(struct wl_client *client, +static void subsurface_handle_set_desync(struct wl_client *client, struct wl_resource *resource) { struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + if (subsurface == NULL) { + return; + } - if (subsurface && subsurface->synchronized) { + if (subsurface->synchronized) { subsurface->synchronized = false; if (!subsurface_is_synchronized(subsurface)) { @@ -835,11 +850,11 @@ static void subsurface_set_desync(struct wl_client *client, static const struct wl_subsurface_interface subsurface_implementation = { .destroy = subsurface_handle_destroy, - .set_position = subsurface_set_position, - .place_above = subsurface_place_above, - .place_below = subsurface_place_below, - .set_sync = subsurface_set_sync, - .set_desync = subsurface_set_desync, + .set_position = subsurface_handle_set_position, + .place_above = subsurface_handle_place_above, + .place_below = subsurface_handle_place_below, + .set_sync = subsurface_handle_set_sync, + .set_desync = subsurface_handle_set_desync, }; static void subsurface_handle_parent_destroy(struct wl_listener *listener, @@ -862,6 +877,8 @@ static void subsurface_handle_surface_destroy(struct wl_listener *listener, struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface, struct wlr_surface *parent, uint32_t version, uint32_t id, struct wl_list *resource_list) { + assert(version <= SUBSURFACE_VERSION); + struct wl_client *client = wl_resource_get_client(surface->resource); struct wlr_subsurface *subsurface =