diff options
author | Tony Crisci <tony@dubstepdish.com> | 2017-10-11 15:48:40 -0400 |
---|---|---|
committer | Tony Crisci <tony@dubstepdish.com> | 2017-10-15 05:59:52 -0400 |
commit | 6a7560fae05147ac5a1ac0dd3474670f1bd6c871 (patch) | |
tree | b3cc7127ba2a6c8c526bf5d9267b71d70da239b3 | |
parent | 2b09105bde84ef52ed8f683782dbf2091dcccb08 (diff) |
wlr-data-device interface
-rw-r--r-- | include/rootston/server.h | 2 | ||||
-rw-r--r-- | include/wlr/interfaces/wlr_data_source.h | 16 | ||||
-rw-r--r-- | include/wlr/types/wlr_data_device.h | 31 | ||||
-rw-r--r-- | include/wlr/types/wlr_data_device_manager.h | 26 | ||||
-rw-r--r-- | include/wlr/types/wlr_data_source.h | 32 | ||||
-rw-r--r-- | include/wlr/types/wlr_seat.h | 5 | ||||
-rw-r--r-- | rootston/main.c | 4 | ||||
-rw-r--r-- | types/meson.build | 3 | ||||
-rw-r--r-- | types/wlr_data_device.c | 229 | ||||
-rw-r--r-- | types/wlr_data_device_manager.c | 198 | ||||
-rw-r--r-- | types/wlr_data_source.c | 140 |
11 files changed, 268 insertions, 418 deletions
diff --git a/include/rootston/server.h b/include/rootston/server.h index a4eacb7f..8fc6530e 100644 --- a/include/rootston/server.h +++ b/include/rootston/server.h @@ -3,7 +3,7 @@ #include <wayland-server.h> #include <wlr/backend.h> #include <wlr/backend/session.h> -#include <wlr/types/wlr_data_device_manager.h> +#include <wlr/types/wlr_data_device.h> #include <wlr/render.h> #ifdef HAS_XWAYLAND #include <wlr/xwayland.h> diff --git a/include/wlr/interfaces/wlr_data_source.h b/include/wlr/interfaces/wlr_data_source.h deleted file mode 100644 index 821bdea0..00000000 --- a/include/wlr/interfaces/wlr_data_source.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef WLR_INTERFACES_WLR_DATA_SOURCE_H -#define WLR_INTERFACES_WLR_DATA_SOURCE_H - -#include <wlr/types/wlr_data_source.h> - -struct wlr_data_source_impl { - void (*send)(struct wlr_data_source *data_source, const char *type, int fd); - void (*accepted)(struct wlr_data_source *data_source, const char *type); - void (*cancelled)(struct wlr_data_source *data_source); -}; - -bool wlr_data_source_init(struct wlr_data_source *source, - struct wlr_data_source_impl *impl); -void wlr_data_source_finish(struct wlr_data_source *source); - -#endif diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h new file mode 100644 index 00000000..38d1467c --- /dev/null +++ b/include/wlr/types/wlr_data_device.h @@ -0,0 +1,31 @@ +#ifndef WLR_TYPES_WLR_DATA_DEVICE_H +#define WLR_TYPES_WLR_DATA_DEVICE_H + +#include <wayland-server.h> + +struct wlr_data_device_manager { + struct wl_global *global; +}; + +struct wlr_data_offer { + struct wl_resource *resource; +}; + +struct wlr_data_source { + struct wl_resource *resource; + struct wlr_data_offer *offer; + struct wlr_seat_handle *seat; + struct wl_array mime_types; + + struct { + struct wl_signal destroy; + } events; +}; + +/** + * Create a wl data device manager global for this display. + */ +struct wlr_data_device_manager *wlr_data_device_manager_create( + struct wl_display *display); + +#endif diff --git a/include/wlr/types/wlr_data_device_manager.h b/include/wlr/types/wlr_data_device_manager.h deleted file mode 100644 index 500f8acd..00000000 --- a/include/wlr/types/wlr_data_device_manager.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef WLR_TYPES_WLR_DATA_DEVICE_MANAGER_H -#define WLR_TYPES_WLR_DATA_DEVICE_MANAGER_H - -#include <wayland-server.h> - -struct wlr_data_device_manager { - struct wl_global *global; -}; - -struct wlr_data_device_manager *wlr_data_device_manager_create(struct wl_display *dpy); -void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager); - -struct wlr_data_device { - struct wlr_seat *seat; - struct wlr_data_source *selection; - struct wl_listener selection_destroyed; - - struct { - struct wl_signal selection_change; - } events; -}; - -void wlr_data_device_set_selection(struct wlr_data_device *manager, - struct wlr_data_source *source); - -#endif diff --git a/include/wlr/types/wlr_data_source.h b/include/wlr/types/wlr_data_source.h deleted file mode 100644 index 19834cb6..00000000 --- a/include/wlr/types/wlr_data_source.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef WLR_TYPES_WLR_DATA_SOURCE_H -#define WLR_TYPES_WLR_DATA_SOURCE_H - -#include <wayland-server.h> -#include <wlr/util/list.h> - -struct wlr_data_source_impl; - -struct wlr_data_source { - struct wlr_data_source_impl *impl; - list_t *types; - void *data; - - struct { - struct wl_signal destroy; - } events; -}; - -void wlr_data_source_send(struct wlr_data_source *src, const char *type, int fd); -void wlr_data_source_accepted(struct wlr_data_source *src, const char *type); -void wlr_data_source_cancelled(struct wlr_data_source *src); - -struct wlr_wl_data_source { - struct wlr_data_source base; - struct wl_resource *resource; -}; - -struct wlr_wl_data_source *wlr_wl_data_source_create( - struct wl_client *client, - uint32_t version, uint32_t id); - -#endif diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index d267924c..c84a1370 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -111,7 +111,10 @@ struct wlr_seat { struct wl_list keyboards; char *name; uint32_t capabilities; - struct wlr_data_device *data_device; + + struct wlr_data_device *data_device; // TODO needed? + struct wlr_data_source *selection_source; + uint32_t selection_serial; struct wlr_seat_pointer_state pointer_state; struct wlr_seat_keyboard_state keyboard_state; diff --git a/rootston/main.c b/rootston/main.c index 5a60000c..81343dfc 100644 --- a/rootston/main.c +++ b/rootston/main.c @@ -22,8 +22,8 @@ int main(int argc, char **argv) { wl_display_init_shm(server.wl_display); server.desktop = desktop_create(&server, server.config); server.input = input_create(&server, server.config); - server.data_device_manager = wlr_data_device_manager_create( - server.wl_display); + server.data_device_manager = + wlr_data_device_manager_create(server.wl_display); const char *socket = wl_display_add_socket_auto(server.wl_display); if (!socket) { diff --git a/types/meson.build b/types/meson.build index a151e8a3..706cfc61 100644 --- a/types/meson.build +++ b/types/meson.build @@ -1,8 +1,7 @@ lib_wlr_types = static_library( 'wlr_types', files( - 'wlr_data_device_manager.c', - 'wlr_data_source.c', + 'wlr_data_device.c', 'wlr_input_device.c', 'wlr_keyboard.c', 'wlr_output.c', diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c new file mode 100644 index 00000000..4c310962 --- /dev/null +++ b/types/wlr_data_device.c @@ -0,0 +1,229 @@ +#define _XOPEN_SOURCE 700 +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <wayland-server.h> +#include <wlr/util/log.h> +#include <wlr/types/wlr_seat.h> +#include <wlr/types/wlr_data_device.h> + +static void data_device_start_drag(struct wl_client *client, struct wl_resource + *resource, struct wl_resource *source_resource, + struct wl_resource *origin, struct wl_resource *icon, uint32_t serial) { + wlr_log(L_DEBUG, "TODO: data device start drag"); +} + +static struct wlr_data_offer *wlr_data_source_send_offer( + struct wlr_data_source *source, + struct wl_resource *data_device_resourec) { + // TODO + return NULL; +} + + +static void wlr_seat_handle_send_selection(struct wlr_seat_handle *handle) { + if (!handle->data_device) { + return; + } + + if (handle->wlr_seat->selection_source) { + struct wlr_data_offer *offer = + wlr_data_source_send_offer(handle->wlr_seat->selection_source, + handle->data_device); + wl_data_device_send_selection(handle->data_device, offer->resource); + } else { + wl_data_device_send_selection(handle->data_device, NULL); + } +} + +static void wlr_seat_set_selection(struct wlr_seat *seat, + struct wlr_data_source *source, uint32_t serial) { + if (seat->selection_source && + seat->selection_serial - serial < UINT32_MAX / 2) { + return; + } + + if (seat->selection_source) { + // TODO cancel + } + + seat->selection_source = source; + seat->selection_serial = serial; + + struct wlr_seat_handle *focused_handle = + seat->keyboard_state.focused_handle; + + if (focused_handle) { + // TODO send selection to keyboard + wlr_seat_handle_send_selection(focused_handle); + } + + // TODO emit selection signal + + if (source) { + // TODO set destroy listener + } +} + +static void data_device_set_selection(struct wl_client *client, + struct wl_resource *seat_resource, struct wl_resource *source_resource, + uint32_t serial) { + if (!source_resource) { + return; + } + + struct wlr_data_source *source = wl_resource_get_user_data(source_resource); + struct wlr_seat_handle *handle = wl_resource_get_user_data(seat_resource); + + // TODO: store serial and check against incoming serial here + wlr_seat_set_selection(handle->wlr_seat, source, serial); +} + +static void data_device_release(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct wl_data_device_interface data_device_impl = { + .start_drag = data_device_start_drag, + .set_selection = data_device_set_selection, + .release = data_device_release, +}; + +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_handle *handle = wl_resource_get_user_data(seat_resource); + + struct wl_resource *resource = + wl_resource_create(client, + &wl_data_device_interface, + wl_resource_get_version(manager_resource), id); + if (resource == NULL) { + wl_resource_post_no_memory(manager_resource); + return; + } + + // TODO handle a seat handle having multiple data devices + assert(handle->data_device == NULL); + handle->data_device = resource; + + wl_resource_set_implementation(resource, &data_device_impl, + handle, NULL); +} + +static void data_source_resource_destroy(struct wl_resource *resource) { + struct wlr_data_source *source = + wl_resource_get_user_data(resource); + char **p; + + wl_signal_emit(&source->events.destroy, source); + + wl_array_for_each(p, &source->mime_types) { + free(*p); + } + + wl_array_release(&source->mime_types); + + free(source); +} + +static void data_source_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void data_source_set_actions(struct wl_client *client, + struct wl_resource *resource, uint32_t dnd_actions) { + wlr_log(L_DEBUG, "TODO: data source set actions"); +} + +static void data_source_offer(struct wl_client *client, + struct wl_resource *resource, const char *mime_type) { + struct wlr_data_source *source = + wl_resource_get_user_data(resource); + char **p; + + p = wl_array_add(&source->mime_types, sizeof *p); + + if (p) { + *p = strdup(mime_type); + } + if (!p || !*p){ + wl_resource_post_no_memory(resource); + } +} + +static 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_device_manager_create_data_source(struct wl_client *client, + struct wl_resource *resource, uint32_t id) { + struct wlr_data_source *source = calloc(1, sizeof(struct wlr_data_source)); + if (source == NULL) { + wl_resource_post_no_memory(resource); + return; + } + + source->resource = + wl_resource_create(client, &wl_data_source_interface, + wl_resource_get_version(resource), id); + if (source->resource == NULL) { + free(source); + wl_resource_post_no_memory(resource); + return; + } + + wl_array_init(&source->mime_types); + wl_signal_init(&source->events.destroy); + + wl_resource_set_implementation(source->resource, &data_source_impl, + source, data_source_resource_destroy); +} + +static const struct wl_data_device_manager_interface +data_device_manager_impl = { + .create_data_source = data_device_manager_create_data_source, + .get_data_device = data_device_manager_get_data_device, +}; + +static void data_device_manager_bind(struct wl_client *client, + void *data, uint32_t version, uint32_t id) { + struct wl_resource *resource; + + resource = wl_resource_create(client, + &wl_data_device_manager_interface, + version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &data_device_manager_impl, + NULL, NULL); +} + +struct wlr_data_device_manager *wlr_data_device_manager_create( + struct wl_display *display) { + struct wlr_data_device_manager *manager = + calloc(1, sizeof(struct wlr_data_device_manager)); + if (manager == NULL) { + wlr_log(L_ERROR, "could not create data device manager"); + return NULL; + } + + manager->global = + wl_global_create(display, &wl_data_device_manager_interface, + 3, NULL, data_device_manager_bind); + + if (!manager->global) { + wlr_log(L_ERROR, "could not create data device manager wl global"); + free(manager); + return NULL; + } + + return manager; +} diff --git a/types/wlr_data_device_manager.c b/types/wlr_data_device_manager.c deleted file mode 100644 index a813754c..00000000 --- a/types/wlr_data_device_manager.c +++ /dev/null @@ -1,198 +0,0 @@ -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <wayland-server.h> -#include <wlr/util/log.h> -#include <wlr/types/wlr_data_device_manager.h> -#include <wlr/types/wlr_data_source.h> -#include <wlr/types/wlr_seat.h> - -static void resource_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void data_device_start_drag(struct wl_client *client, - struct wl_resource *res, struct wl_resource *source_resource, - struct wl_resource *origin_res, struct wl_resource *icon_res, - uint32_t serial) { - wlr_log(L_DEBUG, "TODO: implement data_device:start_drag"); - - // Will probably look like this: - // struct wlr_seat_handle *handle = wl_resource_get_user_data(res); - // struct wlr_data_device *device = handle->wlr_seat->data_device; - // struct wlr_data_source *src = wl_resource_get_user_data(src_res); - // struct wlr_surface *origin = wl_resource_get_user_data(origin_res); - // struct wlr_surface *icon; - // if (icon_res) - // icon = wl_resource_get_user_data(icon_res); - // wlr_seat_start_drag(serial, device->seat, src, - // origin, icon); // will set surface roles and emit signal for user -} - -static void data_device_set_selection(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *source_resource, - uint32_t serial) { - if (!source_resource) { - return; - } - - // TODO: serial validation - struct wlr_seat_handle *handle = wl_resource_get_user_data(resource); - struct wlr_data_device *device = handle->wlr_seat->data_device; - struct wlr_data_source *source = wl_resource_get_user_data(source_resource); - wlr_data_device_set_selection(device, source); -} - -static struct wl_data_device_interface data_device_impl = { - .start_drag = data_device_start_drag, - .set_selection = data_device_set_selection, - .release = resource_destroy -}; - -static void data_device_selection_destroy(struct wl_listener *listener, - void *data) { - struct wlr_data_device *device = - wl_container_of(listener, device, selection_destroyed); - assert(data == device->selection); - device->selection = NULL; // make sure no cancel is sent - wlr_data_device_set_selection(device, NULL); -} - -static struct wlr_data_device *seat_ensure_data_device( - struct wlr_data_device_manager *manager, struct wlr_seat *seat) { - if (seat->data_device) { - return seat->data_device; - } - - seat->data_device = calloc(1, sizeof(*seat->data_device)); - if (!seat->data_device) { - wlr_log(L_ERROR, "Failed to allocate wlr_data_device"); - return NULL; - } - - seat->data_device->seat = seat; - wl_signal_init(&seat->data_device->events.selection_change); - seat->data_device->selection_destroyed.notify = - data_device_selection_destroy; - return seat->data_device; -} - -static void data_device_destroy(struct wl_resource *resource) { - struct wlr_seat_handle *handle = wl_resource_get_user_data(resource); - handle->data_device = NULL; -} - -static void data_device_manager_create_data_source(struct wl_client *client, - struct wl_resource *resource, uint32_t id) { - uint32_t version = wl_resource_get_version(resource); - if (!wlr_wl_data_source_create(client, version, id)) { - wlr_log(L_ERROR, "Failed to create wlr_wl_data_source"); - wl_resource_post_no_memory(resource); - return; - } -} - -static void data_device_manager_get_data_device(struct wl_client *client, - struct wl_resource *resource, uint32_t id, - struct wl_resource *seat_resource) { - struct wlr_data_device_manager *manager = - wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = - wl_resource_get_user_data(seat_resource); - struct wlr_data_device *device; - if (!(device = seat_ensure_data_device(manager, seat_handle->wlr_seat))) { - wl_resource_post_no_memory(resource); - return; - } - - if (seat_handle->data_device) { - // TODO: implement resource lists for seat related handles - // this is a protocol violation, see the todos in wlr_seat.c - wl_resource_destroy(seat_handle->data_device); - } - - seat_handle->data_device = wl_resource_create(client, - &wl_data_device_interface, wl_resource_get_version(resource), id); - if (!seat_handle->data_device) { - wlr_log(L_ERROR, "Failed to create wl_data_device resource"); - wl_resource_post_no_memory(resource); - return; - } - - wl_resource_set_implementation(seat_handle->data_device, &data_device_impl, - seat_handle, data_device_destroy); -} - -struct wl_data_device_manager_interface data_device_manager_impl = { - .create_data_source = data_device_manager_create_data_source, - .get_data_device = data_device_manager_get_data_device -}; - -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; - assert(client && manager); - if (version > 3) { - wlr_log(L_ERROR, "Client requested unsupported data_device_manager " - "version, disconnecting"); - wl_client_destroy(client); - return; - } - struct wl_resource *resource = wl_resource_create( - client, &wl_data_device_manager_interface, version, id); - if (!resource) { - wlr_log(L_ERROR, "Failed to allocate wl_data_device_manager resource"); - wl_client_post_no_memory(client); - return; - } - wl_resource_set_implementation(resource, &data_device_manager_impl, - manager, NULL); -} - -struct wlr_data_device_manager *wlr_data_device_manager_create( - struct wl_display *display) { - struct wlr_data_device_manager *manager = calloc(1, sizeof(*manager)); - if (!manager) { - wlr_log(L_ERROR, "Failed to allocated wlr_data_device_manager"); - return NULL; - } - - manager->global = - wl_global_create(display, &wl_data_device_manager_interface, 3, manager, - data_device_manager_bind); - - if (!manager->global) { - wlr_log(L_ERROR, "Failed to create global for wlr_data_device_manager"); - free(manager); - return NULL; - } - - return manager; -} - -void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager) { - if (manager) { - wl_global_destroy(manager->global); - free(manager); - } -} - -void wlr_data_device_set_selection(struct wlr_data_device *device, - struct wlr_data_source *source) { - if (device->selection == source) { - return; - } - - if (device->selection) { - wl_list_remove(&device->selection_destroyed.link); - wlr_data_source_cancelled(device->selection); - } - - device->selection = source; - wl_signal_emit(&device->events.selection_change, device); - - if (source) { - wl_signal_add(&source->events.destroy, &device->selection_destroyed); - } -} diff --git a/types/wlr_data_source.c b/types/wlr_data_source.c deleted file mode 100644 index 83064fac..00000000 --- a/types/wlr_data_source.c +++ /dev/null @@ -1,140 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <wayland-server.h> -#include <wlr/util/list.h> -#include <wlr/util/log.h> -#include <wlr/types/wlr_data_source.h> -#include <wlr/types/wlr_data_device_manager.h> -#include <wlr/interfaces/wlr_data_source.h> - -bool wlr_data_source_init(struct wlr_data_source *source, - struct wlr_data_source_impl *impl) { - source->impl = impl; - wl_signal_init(&source->events.destroy); - return (source->types = list_create()); -} - -void wlr_data_source_finish(struct wlr_data_source *source) { - if (source) { - wl_signal_emit(&source->events.destroy, source); - if (source->types) { - list_foreach(source->types, free); - } - list_free(source->types); - } -} - -void wlr_data_source_send(struct wlr_data_source *src, const char *type, - int fd) { - assert(src && src->impl && src->impl->send); - src->impl->send(src, type, fd); -} - -void wlr_data_source_accepted(struct wlr_data_source *src, const char *type) { - assert(src && src->impl); - if (src->impl->accepted) { - src->impl->accepted(src, type); - } -} - -void wlr_data_source_cancelled(struct wlr_data_source *src) { - assert(src && src->impl); - if (src->impl->cancelled) { - src->impl->cancelled(src); - } -} - -static void data_source_send(struct wlr_data_source *src, - const char *type, int fd) { - struct wlr_wl_data_source *wl_src = (struct wlr_wl_data_source *) src; - wl_data_source_send_send(wl_src->resource, type, fd); - close(fd); -} - -static void data_source_accepted(struct wlr_data_source *src, - const char *type) { - struct wlr_wl_data_source *wl_src = (struct wlr_wl_data_source *) src; - wl_data_source_send_target(wl_src->resource, type); -} - -static void data_source_cancelled(struct wlr_data_source *src) { - struct wlr_wl_data_source *wl_src = (struct wlr_wl_data_source *) src; - wl_data_source_send_cancelled(wl_src->resource); -} - -static struct wlr_data_source_impl data_source_wl_impl = { - .send = data_source_send, - .accepted = data_source_accepted, - .cancelled = data_source_cancelled, -}; - -static void data_source_offer(struct wl_client *client, - struct wl_resource *resource, - const char *type) { - struct wlr_wl_data_source *src = wl_resource_get_user_data(resource); - char *dtype = strdup(type); - if (!dtype) { - wl_resource_post_no_memory(resource); - return; - } - - list_add(src->base.types, dtype); -} - -static void data_source_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void data_source_set_actions(struct wl_client *client, - struct wl_resource *resource, uint32_t dnd_actions) { - wlr_log(L_DEBUG, "TODO: data source set actions"); -} - -static struct wl_data_source_interface wl_data_source_impl = { - .offer = data_source_offer, - .destroy = data_source_destroy, - .set_actions = data_source_set_actions, -}; - -static void destroy_wl_data_source(struct wl_resource *resource) { - struct wlr_wl_data_source *src = wl_resource_get_user_data(resource); - wlr_data_source_finish(&src->base); - free(src); -} - -struct wlr_wl_data_source *wlr_wl_data_source_create( - struct wl_client *client, - uint32_t version, uint32_t id) { - struct wlr_wl_data_source *src = calloc(1, sizeof(*src)); - if (!src) { - wlr_log(L_ERROR, "Failed to allocator wlr_wl_data_source"); - wl_client_post_no_memory(client); - return NULL; - } - - if (!wlr_data_source_init(&src->base, &data_source_wl_impl)) { - wlr_log(L_ERROR, "Failed to init wlr_wl_data_source"); - wl_client_post_no_memory(client); - goto err; - } - - if (!(src->resource = wl_resource_create(client, &wl_data_source_interface, - version, id))) { - wlr_log(L_ERROR, "Failed to create wl_resource for wlr_wl_data_source"); - wl_client_post_no_memory(client); - goto err; - } - - wl_resource_set_implementation(src->resource, &wl_data_source_impl, src, - destroy_wl_data_source); - return src; - -err: - wlr_data_source_finish(&src->base); - free(src); - return NULL; -} |