From 6a7560fae05147ac5a1ac0dd3474670f1bd6c871 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 11 Oct 2017 15:48:40 -0400 Subject: [PATCH 01/19] wlr-data-device interface --- include/rootston/server.h | 2 +- include/wlr/interfaces/wlr_data_source.h | 16 -- include/wlr/types/wlr_data_device.h | 31 +++ include/wlr/types/wlr_data_device_manager.h | 26 --- include/wlr/types/wlr_data_source.h | 32 --- include/wlr/types/wlr_seat.h | 5 +- rootston/main.c | 4 +- types/meson.build | 3 +- types/wlr_data_device.c | 229 ++++++++++++++++++++ types/wlr_data_device_manager.c | 198 ----------------- types/wlr_data_source.c | 140 ------------ 11 files changed, 268 insertions(+), 418 deletions(-) delete mode 100644 include/wlr/interfaces/wlr_data_source.h create mode 100644 include/wlr/types/wlr_data_device.h delete mode 100644 include/wlr/types/wlr_data_device_manager.h delete mode 100644 include/wlr/types/wlr_data_source.h create mode 100644 types/wlr_data_device.c delete mode 100644 types/wlr_data_device_manager.c delete mode 100644 types/wlr_data_source.c 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 #include #include -#include +#include #include #ifdef HAS_XWAYLAND #include 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 - -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 + +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 - -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 -#include - -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 +#include +#include +#include +#include +#include +#include + +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 -#include -#include -#include -#include -#include -#include -#include - -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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; -} From 3892acecac773b825532f84da4671c2a55f5e82a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 12 Oct 2017 11:41:11 -0400 Subject: [PATCH 02/19] wlr-data-device: basic clipboard --- include/wlr/types/wlr_data_device.h | 19 +++ include/wlr/types/wlr_seat.h | 2 + types/wlr_data_device.c | 191 ++++++++++++++++++++++++++-- types/wlr_seat.c | 3 + 4 files changed, 206 insertions(+), 9 deletions(-) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 38d1467c..5cb839bd 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -9,6 +9,9 @@ struct wlr_data_device_manager { struct wlr_data_offer { struct wl_resource *resource; + struct wlr_data_source *source; + + struct wl_listener source_destroy; }; struct wlr_data_source { @@ -17,6 +20,11 @@ struct wlr_data_source { struct wlr_seat_handle *seat; struct wl_array mime_types; + bool accepted; + + // TODO + //bool actions_set; + struct { struct wl_signal destroy; } events; @@ -28,4 +36,15 @@ struct wlr_data_source { struct wlr_data_device_manager *wlr_data_device_manager_create( struct wl_display *display); +/** + * Creates a new wl_data_offer if there is a wl_data_source currently set as the + * seat selection and sends it to the client for this handle, followed by the + * wl_data_device.selection() event. + * If there is no current selection, the wl_data_device.selection() event will + * carry a NULL wl_data_offer. + * If the client does not have a wl_data_device for the seat nothing * will be + * done. + */ +void wlr_seat_handle_send_selection(struct wlr_seat_handle *handle); + #endif diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index c84a1370..88d42112 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -119,6 +119,8 @@ struct wlr_seat { struct wlr_seat_pointer_state pointer_state; struct wlr_seat_keyboard_state keyboard_state; + struct wl_listener selection_data_source_destroy; + struct { struct wl_signal client_bound; struct wl_signal client_unbound; diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 4c310962..769974a9 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -12,16 +13,172 @@ static void data_device_start_drag(struct wl_client *client, struct wl_resource struct wl_resource *origin, struct wl_resource *icon, uint32_t serial) { wlr_log(L_DEBUG, "TODO: data device start drag"); } +static void data_source_accept(struct wlr_data_source *source, + uint32_t time, const char *mime_type) { + wl_data_source_send_target(source->resource, mime_type); +} -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 data_source_send(struct wlr_data_source *source, + const char *mime_type, int32_t fd) { + wl_data_source_send_send(source->resource, mime_type, fd); + close(fd); +} + +static void data_source_cancel(struct wlr_data_source *source) { + wl_data_source_send_cancelled(source->resource); } -static void wlr_seat_handle_send_selection(struct wlr_seat_handle *handle) { +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); + + if (!offer->source || offer != offer->source->offer) { + return; + } + + // TODO check that client is currently focused by the input device + + data_source_accept(offer->source, serial, mime_type); + offer->source->accepted = (mime_type != NULL); +} + +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); + + if (offer->source && offer == offer->source->offer) { + data_source_send(offer->source, mime_type, fd); + } else { + close(fd); + } +} +static void data_offer_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void data_source_notify_finish(struct wlr_data_source *source) { + // TODO + /* + if (!source->actions_set) { + return; + } + + if (source->offer->in_ask && + wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION) { + wl_data_source_send_action(source->resource, + source->current_dnd_action); + } + + if (wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { + wl_data_source_send_dnd_finished(source->resource); + } + */ + + source->offer = NULL; +} + +static void data_offer_finish(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + + if (!offer->source || offer->source->offer != offer) { + return; + } + + data_source_notify_finish(offer->source); +} + +static void data_offer_set_actions(struct wl_client *client, + struct wl_resource *resource, uint32_t dnd_actions, + uint32_t preferred_action) { + // TODO +} + +static void data_offer_resource_destroy(struct wl_resource *resource) { + struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + + if (!offer->source) { + goto out; + } + + wl_list_remove(&offer->source_destroy.link); + + if (offer->source->offer != offer) { + goto out; + } + + // If the drag destination has version < 3, wl_data_offer.finish + // won't be called, so do this here as a safety net, because + // we still want the version >=3 drag source to be happy. + if (wl_resource_get_version(offer->resource) < + WL_DATA_OFFER_ACTION_SINCE_VERSION) { + data_source_notify_finish(offer->source); + } else if (offer->source->resource && + wl_resource_get_version(offer->source->resource) >= + WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { + wl_data_source_send_cancelled(offer->source->resource); + } + + offer->source->offer = NULL; +out: + free(offer); +} + +static const struct wl_data_offer_interface data_offer_impl = { + .accept = data_offer_accept, + .receive = data_offer_receive, + .destroy = data_offer_destroy, + .finish = data_offer_finish, + .set_actions = data_offer_set_actions, +}; + +static void handle_offer_source_destroyed(struct wl_listener *listener, + void *data) { + struct wlr_data_offer *offer = + wl_container_of(listener, offer, source_destroy); + + offer->source = NULL; +} + +static struct wlr_data_offer *wlr_data_source_send_offer( + struct wlr_data_source *source, + struct wl_resource *target) { + struct wlr_data_offer *offer = calloc(1, sizeof(struct wlr_data_offer)); + + offer->resource = + wl_resource_create(wl_resource_get_client(target), + &wl_data_offer_interface, + wl_resource_get_version(target), 0); + if (offer->resource == NULL) { + free(offer); + return NULL; + } + + wl_resource_set_implementation(offer->resource, &data_offer_impl, offer, + data_offer_resource_destroy); + + offer->source_destroy.notify = handle_offer_source_destroyed; + wl_signal_add(&source->events.destroy, &offer->source_destroy); + + wl_data_device_send_data_offer(target, offer->resource); + char **p; + wl_array_for_each(p, &source->mime_types) { + wl_data_offer_send_offer(offer->resource, *p); + } + + offer->source = source; + source->offer = offer; + source->accepted = false; + + return offer; +} + + +void wlr_seat_handle_send_selection(struct wlr_seat_handle *handle) { if (!handle->data_device) { return; } @@ -36,6 +193,18 @@ static void wlr_seat_handle_send_selection(struct wlr_seat_handle *handle) { } } +static void seat_handle_selection_data_source_destroy( + struct wl_listener *listener, void *data) { + struct wlr_seat *seat = + wl_container_of(listener, seat, selection_data_source_destroy); + + // TODO send null selection to focused keyboard + + seat->selection_source = NULL; + + // TODO emit selection signal +} + static void wlr_seat_set_selection(struct wlr_seat *seat, struct wlr_data_source *source, uint32_t serial) { if (seat->selection_source && @@ -44,7 +213,9 @@ static void wlr_seat_set_selection(struct wlr_seat *seat, } if (seat->selection_source) { - // TODO cancel + data_source_cancel(seat->selection_source); + seat->selection_source = NULL; + wl_list_remove(&seat->selection_data_source_destroy.link); } seat->selection_source = source; @@ -54,14 +225,16 @@ static void wlr_seat_set_selection(struct wlr_seat *seat, 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 + seat->selection_data_source_destroy.notify = + seat_handle_selection_data_source_destroy; + wl_signal_add(&source->events.destroy, + &seat->selection_data_source_destroy); } } diff --git a/types/wlr_seat.c b/types/wlr_seat.c index bbb66142..162f97b9 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -6,6 +6,7 @@ #include #include #include +#include static void resource_destroy(struct wl_client *client, struct wl_resource *resource) { @@ -23,6 +24,7 @@ static void wl_pointer_set_cursor(struct wl_client *client, struct wl_resource *resource, uint32_t serial, struct wl_resource *surface_resource, int32_t hotspot_x, int32_t hotspot_y) { + return; struct wlr_seat_handle *handle = wl_resource_get_user_data(resource); struct wlr_surface *surface = NULL; if (surface_resource != NULL) { @@ -750,6 +752,7 @@ void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat, uint32_t serial = wl_display_next_serial(wlr_seat->display); wl_keyboard_send_enter(handle->keyboard, serial, surface->resource, &keys); + wlr_seat_handle_send_selection(handle); } // reinitialize the focus destroy events From 25831d287eb03d9d61cf4fd476e3d463124d1fce Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 13 Oct 2017 07:58:46 -0400 Subject: [PATCH 03/19] wlr-data-device: offer set actions --- include/wlr/types/wlr_data_device.h | 10 ++- types/wlr_data_device.c | 97 ++++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 5cb839bd..d5be311f 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -11,6 +11,10 @@ struct wlr_data_offer { struct wl_resource *resource; struct wlr_data_source *source; + uint32_t dnd_actions; + enum wl_data_device_manager_dnd_action preferred_dnd_action; + bool in_ask; + struct wl_listener source_destroy; }; @@ -22,8 +26,10 @@ struct wlr_data_source { bool accepted; - // TODO - //bool actions_set; + // drag and drop + enum wl_data_device_manager_dnd_action current_dnd_action; + uint32_t dnd_actions; + uint32_t compositor_action; struct { struct wl_signal destroy; diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 769974a9..5760cfc3 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -1,6 +1,7 @@ #define _XOPEN_SOURCE 700 #include #include +#include #include #include #include @@ -8,6 +9,11 @@ #include #include + +#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \ + WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \ + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) + 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) { @@ -92,10 +98,99 @@ static void data_offer_finish(struct wl_client *client, data_source_notify_finish(offer->source); } +static uint32_t data_offer_choose_action(struct wlr_data_offer *offer) { + uint32_t available_actions, preferred_action = 0; + uint32_t source_actions, offer_actions; + + if (wl_resource_get_version(offer->resource) >= + WL_DATA_OFFER_ACTION_SINCE_VERSION) { + offer_actions = offer->dnd_actions; + preferred_action = offer->preferred_dnd_action; + } else { + offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + } + + if (wl_resource_get_version(offer->source->resource) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION) { + source_actions = offer->source->dnd_actions; + } else { + source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + } + + available_actions = offer_actions & source_actions; + + if (!available_actions) { + return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; + } + + if (offer->source->seat && + offer->source->compositor_action & available_actions) { + return offer->source->compositor_action; + } + + // If the dest side has a preferred DnD action, use it + if ((preferred_action & available_actions) != 0) { + return preferred_action; + } + + // Use the first found action, in bit order + return 1 << (ffs(available_actions) - 1); +} + +static void data_offer_update_action(struct wlr_data_offer *offer) { + uint32_t action; + + if (!offer->source) { + return; + } + + action = data_offer_choose_action(offer); + + if (offer->source->current_dnd_action == action) { + return; + } + + offer->source->current_dnd_action = action; + + if (offer->in_ask) { + return; + } + + if (wl_resource_get_version(offer->source->resource) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION) { + wl_data_source_send_action(offer->source->resource, action); + } + + if (wl_resource_get_version(offer->resource) >= + WL_DATA_OFFER_ACTION_SINCE_VERSION) { + wl_data_offer_send_action(offer->resource, action); + } +} + static void data_offer_set_actions(struct wl_client *client, struct wl_resource *resource, uint32_t dnd_actions, uint32_t preferred_action) { - // TODO + struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + + if (dnd_actions & ~ALL_ACTIONS) { + wl_resource_post_error(offer->resource, + WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK, + "invalid action mask %x", dnd_actions); + return; + } + + if (preferred_action && (!(preferred_action & dnd_actions) || + __builtin_popcount(preferred_action) > 1)) { + wl_resource_post_error(offer->resource, + WL_DATA_OFFER_ERROR_INVALID_ACTION, + "invalid action %x", preferred_action); + return; + } + + offer->dnd_actions = dnd_actions; + offer->preferred_dnd_action = preferred_action; + + data_offer_update_action(offer); } static void data_offer_resource_destroy(struct wl_resource *resource) { From 07259cf8ea7eae1666b2a62bd3b9cc120d0a4276 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 13 Oct 2017 08:05:53 -0400 Subject: [PATCH 04/19] wlr-data-device: source actions --- include/wlr/types/wlr_data_device.h | 1 + types/wlr_data_device.c | 36 +++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index d5be311f..3074a6e3 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -30,6 +30,7 @@ struct wlr_data_source { enum wl_data_device_manager_dnd_action current_dnd_action; uint32_t dnd_actions; uint32_t compositor_action; + bool actions_set; struct { struct wl_signal destroy; diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 5760cfc3..2dae555e 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -65,24 +65,20 @@ static void data_offer_destroy(struct wl_client *client, } static void data_source_notify_finish(struct wlr_data_source *source) { - // TODO - /* if (!source->actions_set) { return; } - if (source->offer->in_ask && - wl_resource_get_version(source->resource) >= + if (source->offer->in_ask && wl_resource_get_version(source->resource) >= WL_DATA_SOURCE_ACTION_SINCE_VERSION) { wl_data_source_send_action(source->resource, - source->current_dnd_action); + source->current_dnd_action); } if (wl_resource_get_version(source->resource) >= WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { wl_data_source_send_dnd_finished(source->resource); } - */ source->offer = NULL; } @@ -403,7 +399,33 @@ 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) { - wlr_log(L_DEBUG, "TODO: data source set actions"); + struct wlr_data_source *source = + wl_resource_get_user_data(resource); + + if (source->actions_set) { + wl_resource_post_error(source->resource, + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, + "cannot set actions more than once"); + return; + } + + if (dnd_actions & ~ALL_ACTIONS) { + wl_resource_post_error(source->resource, + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, + "invalid action mask %x", dnd_actions); + return; + } + + if (source->seat) { + wl_resource_post_error(source->resource, + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, + "invalid action change after " + "wl_data_device.start_drag"); + return; + } + + source->dnd_actions = dnd_actions; + source->actions_set = true; } static void data_source_offer(struct wl_client *client, From a1bfa4a2f2e8c72761486b7219fe19a61c9dbda2 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 14 Oct 2017 15:53:30 -0400 Subject: [PATCH 05/19] wlr-data-device: basic drag and drop --- include/wlr/types/wlr_data_device.h | 15 ++ types/wlr_data_device.c | 398 ++++++++++++++++++++++------ 2 files changed, 330 insertions(+), 83 deletions(-) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 3074a6e3..cb867741 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -2,6 +2,7 @@ #define WLR_TYPES_WLR_DATA_DEVICE_H #include +#include struct wlr_data_device_manager { struct wl_global *global; @@ -37,6 +38,20 @@ struct wlr_data_source { } events; }; +struct wlr_drag { + struct wlr_seat_pointer_grab pointer_grab; + struct wlr_seat_handle *handle; + struct wlr_seat_handle *focus_handle; + + struct wlr_surface *icon; + struct wlr_surface *focus; + struct wlr_data_source *source; + + struct wl_listener icon_destroy; + struct wl_listener source_destroy; + struct wl_listener handle_unbound; +}; + /** * Create a wl data device manager global for this display. */ diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 2dae555e..e9c0aa10 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -9,16 +9,79 @@ #include #include - #define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) -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 uint32_t data_offer_choose_action(struct wlr_data_offer *offer) { + uint32_t available_actions, preferred_action = 0; + uint32_t source_actions, offer_actions; + + if (wl_resource_get_version(offer->resource) >= + WL_DATA_OFFER_ACTION_SINCE_VERSION) { + offer_actions = offer->dnd_actions; + preferred_action = offer->preferred_dnd_action; + } else { + offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + } + + if (wl_resource_get_version(offer->source->resource) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION) { + source_actions = offer->source->dnd_actions; + } else { + source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + } + + available_actions = offer_actions & source_actions; + + if (!available_actions) { + return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; + } + + if (offer->source->seat && + offer->source->compositor_action & available_actions) { + return offer->source->compositor_action; + } + + // If the dest side has a preferred DnD action, use it + if ((preferred_action & available_actions) != 0) { + return preferred_action; + } + + // Use the first found action, in bit order + return 1 << (ffs(available_actions) - 1); } + +static void data_offer_update_action(struct wlr_data_offer *offer) { + uint32_t action; + + if (!offer->source) { + return; + } + + action = data_offer_choose_action(offer); + + if (offer->source->current_dnd_action == action) { + return; + } + + offer->source->current_dnd_action = action; + + if (offer->in_ask) { + return; + } + + if (wl_resource_get_version(offer->source->resource) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION) { + wl_data_source_send_action(offer->source->resource, action); + } + + if (wl_resource_get_version(offer->resource) >= + WL_DATA_OFFER_ACTION_SINCE_VERSION) { + wl_data_offer_send_action(offer->resource, action); + } +} + static void data_source_accept(struct wlr_data_source *source, uint32_t time, const char *mime_type) { wl_data_source_send_target(source->resource, mime_type); @@ -94,75 +157,6 @@ static void data_offer_finish(struct wl_client *client, data_source_notify_finish(offer->source); } -static uint32_t data_offer_choose_action(struct wlr_data_offer *offer) { - uint32_t available_actions, preferred_action = 0; - uint32_t source_actions, offer_actions; - - if (wl_resource_get_version(offer->resource) >= - WL_DATA_OFFER_ACTION_SINCE_VERSION) { - offer_actions = offer->dnd_actions; - preferred_action = offer->preferred_dnd_action; - } else { - offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; - } - - if (wl_resource_get_version(offer->source->resource) >= - WL_DATA_SOURCE_ACTION_SINCE_VERSION) { - source_actions = offer->source->dnd_actions; - } else { - source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; - } - - available_actions = offer_actions & source_actions; - - if (!available_actions) { - return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; - } - - if (offer->source->seat && - offer->source->compositor_action & available_actions) { - return offer->source->compositor_action; - } - - // If the dest side has a preferred DnD action, use it - if ((preferred_action & available_actions) != 0) { - return preferred_action; - } - - // Use the first found action, in bit order - return 1 << (ffs(available_actions) - 1); -} - -static void data_offer_update_action(struct wlr_data_offer *offer) { - uint32_t action; - - if (!offer->source) { - return; - } - - action = data_offer_choose_action(offer); - - if (offer->source->current_dnd_action == action) { - return; - } - - offer->source->current_dnd_action = action; - - if (offer->in_ask) { - return; - } - - if (wl_resource_get_version(offer->source->resource) >= - WL_DATA_SOURCE_ACTION_SINCE_VERSION) { - wl_data_source_send_action(offer->source->resource, action); - } - - if (wl_resource_get_version(offer->resource) >= - WL_DATA_OFFER_ACTION_SINCE_VERSION) { - wl_data_offer_send_action(offer->resource, action); - } -} - static void data_offer_set_actions(struct wl_client *client, struct wl_resource *resource, uint32_t dnd_actions, uint32_t preferred_action) { @@ -348,6 +342,244 @@ static void data_device_release(struct wl_client *client, wl_resource_destroy(resource); } +static void drag_handle_seat_unbound(struct wl_listener *listener, void *data) { + struct wlr_drag *drag = wl_container_of(listener, drag, handle_unbound); + struct wlr_seat_handle *unbound_handle = data; + + if (drag->focus_handle == unbound_handle) { + drag->focus_handle = NULL; + } +} + +static void wlr_drag_set_focus(struct wlr_drag *drag, + struct wlr_surface *surface, double sx, double sy) { + if (drag->focus == surface) { + return; + } + + if (drag->focus_handle && drag->focus_handle->data_device) { + wl_list_remove(&drag->handle_unbound.link); + wl_data_device_send_leave(drag->focus_handle->data_device); + drag->focus_handle = NULL; + drag->focus = NULL; + } + + if (!surface || !surface->resource) { + return; + } + + if (!drag->source && + wl_resource_get_client(surface->resource) != + wl_resource_get_client(drag->handle->wl_resource)) { + return; + } + + if (drag->source && drag->source->offer) { + // unlink the offer from the source + wl_list_remove(&drag->source->offer->source_destroy.link); + drag->source->offer->source = NULL; + drag->source->offer = NULL; + } + + struct wlr_seat_handle *focus_handle = + wlr_seat_handle_for_client(drag->handle->wlr_seat, + wl_resource_get_client(surface->resource)); + + if (!focus_handle || !focus_handle->data_device) { + return; + } + + struct wl_resource *offer_resource = NULL; + if (drag->source) { + drag->source->accepted = false; + struct wlr_data_offer *offer = + wlr_data_source_send_offer(drag->source, focus_handle->data_device); + if (offer == NULL) { + return; + } + + data_offer_update_action(offer); + + if (wl_resource_get_version(offer->resource) >= + WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) { + wl_data_offer_send_source_actions(offer->resource, + drag->source->dnd_actions); + } + + offer_resource = offer->resource; + } + + uint32_t serial = wl_display_next_serial(drag->handle->wlr_seat->display); + + wl_data_device_send_enter(focus_handle->data_device, serial, + surface->resource, wl_fixed_from_double(sx), + wl_fixed_from_double(sy), offer_resource); + + drag->focus = surface; + drag->focus_handle = focus_handle; + drag->handle_unbound.notify = drag_handle_seat_unbound; + wl_signal_add(&focus_handle->wlr_seat->events.client_unbound, + &drag->handle_unbound); +} + +static void wlr_drag_end(struct wlr_drag *drag) { + if (drag->icon) { + wl_list_remove(&drag->icon_destroy.link); + } + + if (drag->source) { + wl_list_remove(&drag->source_destroy.link); + } + + wlr_drag_set_focus(drag, NULL, 0, 0); + wlr_seat_pointer_end_grab(drag->pointer_grab.seat); + free(drag); +} + +static void pointer_drag_enter(struct wlr_seat_pointer_grab *grab, + struct wlr_surface *surface, double sx, double sy) { + struct wlr_drag *drag = grab->data; + wlr_drag_set_focus(drag, surface, sx, sy); +} + +static void pointer_drag_motion(struct wlr_seat_pointer_grab *grab, + uint32_t time, double sx, double sy) { + struct wlr_drag *drag = grab->data; + if (drag->focus && drag->focus_handle && drag->focus_handle->data_device) { + wl_data_device_send_motion(drag->focus_handle->data_device, time, + wl_fixed_from_double(sx), wl_fixed_from_double(sy)); + } +} + +static uint32_t pointer_drag_button(struct wlr_seat_pointer_grab *grab, + uint32_t time, uint32_t button, uint32_t state) { + struct wlr_drag *drag = grab->data; + + // TODO check no buttons are pressed to end the drag + // TODO make sure the button pressed to do the drag was the same to end the + // drag + + if (state == WL_POINTER_BUTTON_STATE_RELEASED) { + if (drag->source) { + if (drag->focus_handle && drag->focus_handle->data_device && + drag->source->current_dnd_action && + drag->source->accepted) { + wl_data_device_send_drop(drag->focus_handle->data_device); + if (wl_resource_get_version(drag->source->resource) >= + WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) { + wl_data_source_send_dnd_drop_performed( + drag->source->resource); + } + + drag->source->offer->in_ask = + drag->source->current_dnd_action == + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; + } + } else if (wl_resource_get_version(drag->source->resource) >= + WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { + wl_data_source_send_cancelled(drag->source->resource); + } + + wlr_drag_end(drag); + } + + return 0; +} + +static void pointer_drag_axis(struct wlr_seat_pointer_grab *grab, uint32_t time, + enum wlr_axis_orientation orientation, double value) { +} + +static void pointer_drag_cancel(struct wlr_seat_pointer_grab *grab) { + struct wlr_drag *drag = grab->data; + wlr_drag_end(drag); +} + +static const struct wlr_pointer_grab_interface pointer_drag_interface = { + .enter = pointer_drag_enter, + .motion = pointer_drag_motion, + .button = pointer_drag_button, + .axis = pointer_drag_axis, + .cancel = pointer_drag_cancel, +}; + +static void drag_handle_icon_destroy(struct wl_listener *listener, void *data) { + struct wlr_drag *drag = wl_container_of(listener, drag, icon_destroy); + drag->icon = NULL; +} + +static void drag_handle_drag_source_destroy(struct wl_listener *listener, + void *data) { + struct wlr_drag *drag = wl_container_of(listener, drag, source_destroy); + wlr_drag_end(drag); +} + +static bool seat_handle_start_drag(struct wlr_seat_handle *handle, + struct wlr_data_source *source, struct wlr_surface *icon) { + struct wlr_drag *drag = calloc(1, sizeof(struct wlr_drag)); + if (drag == NULL) { + return false; + } + + if (drag->icon) { + drag->icon_destroy.notify = drag_handle_icon_destroy; + wl_signal_add(&icon->events.destroy, &drag->icon_destroy); + drag->icon = icon; + } + + if (source) { + drag->source_destroy.notify = drag_handle_drag_source_destroy; + wl_signal_add(&source->events.destroy, &drag->source_destroy); + drag->source = source; + } + + drag->handle = handle; + drag->pointer_grab.data = drag; + drag->pointer_grab.interface = &pointer_drag_interface; + + wlr_seat_pointer_clear_focus(handle->wlr_seat); + + wlr_seat_pointer_start_grab(handle->wlr_seat, &drag->pointer_grab); + + // TODO keyboard grab + + return true; +} + +static void data_device_start_drag(struct wl_client *client, + struct wl_resource *handle_resource, + struct wl_resource *source_resource, + struct wl_resource *origin_resource, struct wl_resource *icon_resource, + uint32_t serial) { + struct wlr_seat_handle *handle = wl_resource_get_user_data(handle_resource); + struct wlr_surface *origin = wl_resource_get_user_data(origin_resource); + struct wlr_data_source *source = NULL; + struct wlr_surface *icon = NULL; + + if (source_resource) { + source = wl_resource_get_user_data(source_resource); + } + + if (icon_resource) { + icon = wl_resource_get_user_data(icon_resource); + } + if (icon) { + if (wlr_surface_set_role(icon, "wl_data_device-icon", + handle_resource, WL_DATA_DEVICE_ERROR_ROLE) < 0) { + return; + } + } + + // TODO touch grab + if (handle->wlr_seat->pointer_state.focused_surface == origin) { + if (!seat_handle_start_drag(handle, source, icon)) { + wl_resource_post_no_memory(handle_resource); + } else { + source->seat = handle; + } + } +} + static const struct wl_data_device_interface data_device_impl = { .start_drag = data_device_start_drag, .set_selection = data_device_set_selection, @@ -404,23 +636,23 @@ static void data_source_set_actions(struct wl_client *client, if (source->actions_set) { wl_resource_post_error(source->resource, - WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, - "cannot set actions more than once"); + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, + "cannot set actions more than once"); return; } if (dnd_actions & ~ALL_ACTIONS) { wl_resource_post_error(source->resource, - WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, - "invalid action mask %x", dnd_actions); + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, + "invalid action mask %x", dnd_actions); return; } if (source->seat) { wl_resource_post_error(source->resource, - WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, - "invalid action change after " - "wl_data_device.start_drag"); + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, + "invalid action change after " + "wl_data_device.start_drag"); return; } @@ -492,8 +724,8 @@ static void data_device_manager_bind(struct wl_client *client, return; } - wl_resource_set_implementation(resource, &data_device_manager_impl, - NULL, NULL); + wl_resource_set_implementation(resource, + &data_device_manager_impl, NULL, NULL); } struct wlr_data_device_manager *wlr_data_device_manager_create( From df0a8d3abe6a7a8cd010e07f078c0e92ea2fb516 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 15 Oct 2017 11:06:03 -0400 Subject: [PATCH 06/19] wlr-data-device: drag icons --- include/rootston/input.h | 11 +++++++ include/wlr/types/wlr_data_device.h | 3 ++ rootston/cursor.c | 49 +++++++++++++++++++++++++++++ rootston/input.c | 2 ++ rootston/main.c | 4 +-- rootston/output.c | 15 +++++++++ types/wlr_data_device.c | 8 +++-- types/wlr_surface.c | 2 ++ 8 files changed, 89 insertions(+), 5 deletions(-) diff --git a/include/rootston/input.h b/include/rootston/input.h index fbabbdb6..8b4fc3b3 100644 --- a/include/rootston/input.h +++ b/include/rootston/input.h @@ -70,6 +70,15 @@ struct roots_input_event { struct wlr_input_device *device; }; +struct roots_drag_icon { + struct wlr_surface *surface; + struct wl_list link; // roots_input::drag_icons + bool mapped; + + struct wl_listener surface_destroy; + struct wl_listener surface_commit; +}; + struct roots_input { struct roots_config *config; struct roots_server *server; @@ -80,6 +89,7 @@ struct roots_input { struct wlr_xcursor *xcursor; struct wlr_seat *wl_seat; struct roots_view *client_cursor_view; + struct wl_list drag_icons; enum roots_cursor_mode mode; struct roots_view *active_view, *last_active_view; @@ -107,6 +117,7 @@ struct roots_input { struct wl_listener cursor_tool_axis; struct wl_listener cursor_tool_tip; + struct wl_listener pointer_grab_begin; struct wl_listener pointer_grab_end; struct wl_listener request_set_cursor; diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index cb867741..6c5dc097 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -4,6 +4,9 @@ #include #include +extern const struct +wlr_pointer_grab_interface wlr_data_device_pointer_drag_interface; + struct wlr_data_device_manager { struct wl_global *global; }; diff --git a/rootston/cursor.c b/rootston/cursor.c index 8790934c..19f015aa 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -1,8 +1,10 @@ #define _XOPEN_SOURCE 700 +#include #include #include #include #include +#include #ifdef __linux__ #include #elif __FreeBSD__ @@ -11,6 +13,7 @@ #include #include #include +#include #include "rootston/config.h" #include "rootston/input.h" #include "rootston/desktop.h" @@ -289,6 +292,49 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) { (uint32_t)(event->time_usec / 1000), BTN_LEFT, event->state); } +static void handle_drag_icon_destroy(struct wl_listener *listener, void *data) { + struct roots_drag_icon *drag_icon = + wl_container_of(listener, drag_icon, surface_destroy); + wl_list_remove(&drag_icon->link); + wl_list_remove(&drag_icon->surface_destroy.link); + wl_list_remove(&drag_icon->surface_commit.link); + free(drag_icon); +} + +static void handle_drag_icon_commit(struct wl_listener *listener, void *data) { + struct roots_drag_icon *drag_icon = + wl_container_of(listener, drag_icon, surface_commit); + // TODO the spec hints at rules that can determine whether the drag icon is + // mapped here, but it is not completely clear so we need to test more + // toolkits to see how we should interpret the surface state here. + drag_icon->mapped = drag_icon->surface->texture->valid; +} + +static void handle_pointer_grab_begin(struct wl_listener *listener, + void *data) { + struct roots_input *input = + wl_container_of(listener, input, pointer_grab_begin); + struct wlr_seat_pointer_grab *grab = data; + + if (grab->interface == &wlr_data_device_pointer_drag_interface) { + struct wlr_drag *drag = grab->data; + if (drag->icon) { + struct roots_drag_icon *drag_icon = + calloc(1, sizeof(struct roots_drag_icon)); + drag_icon->surface = drag->icon; + wl_list_insert(&input->drag_icons, &drag_icon->link); + + wl_signal_add(&drag->icon->events.destroy, + &drag_icon->surface_destroy); + drag_icon->surface_destroy.notify = handle_drag_icon_destroy; + + wl_signal_add(&drag->icon->events.commit, + &drag_icon->surface_commit); + drag_icon->surface_commit.notify = handle_drag_icon_commit; + } + } +} + static void handle_pointer_grab_end(struct wl_listener *listener, void *data) { struct roots_input *input = wl_container_of(listener, input, pointer_grab_end); @@ -358,6 +404,9 @@ void cursor_initialize(struct roots_input *input) { wl_signal_add(&input->wl_seat->events.pointer_grab_end, &input->pointer_grab_end); input->pointer_grab_end.notify = handle_pointer_grab_end; + wl_signal_add(&input->wl_seat->events.pointer_grab_begin, &input->pointer_grab_begin); + input->pointer_grab_begin.notify = handle_pointer_grab_begin; + wl_list_init(&input->request_set_cursor.link); wl_signal_add(&input->wl_seat->events.request_set_cursor, &input->request_set_cursor); diff --git a/rootston/input.c b/rootston/input.c index 86a87e24..f08b735a 100644 --- a/rootston/input.c +++ b/rootston/input.c @@ -110,6 +110,8 @@ struct roots_input *input_create(struct roots_server *server, cursor_load_config(config, input->cursor, input, server->desktop); + wl_list_init(&input->drag_icons); + return input; } diff --git a/rootston/main.c b/rootston/main.c index 81343dfc..f262a30f 100644 --- a/rootston/main.c +++ b/rootston/main.c @@ -19,11 +19,11 @@ int main(int argc, char **argv) { assert(server.backend = wlr_backend_autocreate(server.wl_display)); assert(server.renderer = wlr_gles2_renderer_create(server.backend)); + server.data_device_manager = + wlr_data_device_manager_create(server.wl_display); 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); const char *socket = wl_display_add_socket_auto(server.wl_display); if (!socket) { diff --git a/rootston/output.c b/rootston/output.c index 39a90fe3..b431cbc3 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -150,6 +150,21 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { render_view(view, desktop, wlr_output, &now); } + struct roots_drag_icon *drag_icon = NULL; + wl_list_for_each(drag_icon, &server->input->drag_icons, link) { + if (!drag_icon->mapped) { + continue; + } + + struct wlr_surface *icon = drag_icon->surface; + struct wlr_cursor *cursor = server->input->cursor; + // TODO should also use the hotspot to determine the location, but + // hotspot is broken right now. + double icon_x = cursor->x - icon->current->sx; + double icon_y = cursor->y - icon->current->sy; + render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); + } + wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output); diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index e9c0aa10..5c6d5717 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -495,7 +495,8 @@ static void pointer_drag_cancel(struct wlr_seat_pointer_grab *grab) { wlr_drag_end(drag); } -static const struct wlr_pointer_grab_interface pointer_drag_interface = { +const struct +wlr_pointer_grab_interface wlr_data_device_pointer_drag_interface = { .enter = pointer_drag_enter, .motion = pointer_drag_motion, .button = pointer_drag_button, @@ -521,7 +522,8 @@ static bool seat_handle_start_drag(struct wlr_seat_handle *handle, return false; } - if (drag->icon) { + if (icon) { + drag->icon = icon; drag->icon_destroy.notify = drag_handle_icon_destroy; wl_signal_add(&icon->events.destroy, &drag->icon_destroy); drag->icon = icon; @@ -535,7 +537,7 @@ static bool seat_handle_start_drag(struct wlr_seat_handle *handle, drag->handle = handle; drag->pointer_grab.data = drag; - drag->pointer_grab.interface = &pointer_drag_interface; + drag->pointer_grab.interface = &wlr_data_device_pointer_drag_interface; wlr_seat_pointer_clear_focus(handle->wlr_seat); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 9e38d701..6e56d6aa 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -269,6 +269,8 @@ static void wlr_surface_move_state(struct wlr_surface *surface, struct wlr_surfa wlr_surface_state_release_buffer(state); wlr_surface_state_set_buffer(state, next->buffer); wlr_surface_state_reset_buffer(next); + state->sx = next->sx; + state->sy = next->sy; update_size = true; } if (update_size) { From 02f4acc69f8d94657f341b80364180c8c2e3ce33 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 15 Oct 2017 14:49:43 -0400 Subject: [PATCH 07/19] data-device: refactor set selections for xwayland --- include/wlr/types/wlr_data_device.h | 9 +++++++++ types/wlr_data_device.c | 20 ++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 6c5dc097..b4aa024a 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -36,6 +36,12 @@ struct wlr_data_source { uint32_t compositor_action; bool actions_set; + void (*accept)(struct wlr_data_source *source, uint32_t serial, + const char *mime_type); + void (*send)(struct wlr_data_source *source, const char *mime_type, + int32_t fd); + void (*cancel)(struct wlr_data_source *source); + struct { struct wl_signal destroy; } events; @@ -72,4 +78,7 @@ struct wlr_data_device_manager *wlr_data_device_manager_create( */ void wlr_seat_handle_send_selection(struct wlr_seat_handle *handle); +void wlr_seat_set_selection(struct wlr_seat *seat, + struct wlr_data_source *source, uint32_t serial); + #endif diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 5c6d5717..d5782830 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -82,18 +82,18 @@ static void data_offer_update_action(struct wlr_data_offer *offer) { } } -static void data_source_accept(struct wlr_data_source *source, - uint32_t time, const char *mime_type) { +static void client_data_source_accept(struct wlr_data_source *source, + uint32_t serial, const char *mime_type) { wl_data_source_send_target(source->resource, mime_type); } -static void data_source_send(struct wlr_data_source *source, +static void client_data_source_send(struct wlr_data_source *source, const char *mime_type, int32_t fd) { wl_data_source_send_send(source->resource, mime_type, fd); close(fd); } -static void data_source_cancel(struct wlr_data_source *source) { +static void client_data_source_cancel(struct wlr_data_source *source) { wl_data_source_send_cancelled(source->resource); } @@ -108,7 +108,7 @@ static void data_offer_accept(struct wl_client *client, // TODO check that client is currently focused by the input device - data_source_accept(offer->source, serial, mime_type); + offer->source->accept(offer->source, serial, mime_type); offer->source->accepted = (mime_type != NULL); } @@ -117,7 +117,7 @@ static void data_offer_receive(struct wl_client *client, struct wlr_data_offer *offer = wl_resource_get_user_data(resource); if (offer->source && offer == offer->source->offer) { - data_source_send(offer->source, mime_type, fd); + offer->source->send(offer->source, mime_type, fd); } else { close(fd); } @@ -290,7 +290,7 @@ static void seat_handle_selection_data_source_destroy( // TODO emit selection signal } -static void wlr_seat_set_selection(struct wlr_seat *seat, +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) { @@ -298,7 +298,7 @@ static void wlr_seat_set_selection(struct wlr_seat *seat, } if (seat->selection_source) { - data_source_cancel(seat->selection_source); + seat->selection_source->cancel(seat->selection_source); seat->selection_source = NULL; wl_list_remove(&seat->selection_data_source_destroy.link); } @@ -701,6 +701,10 @@ static void data_device_manager_create_data_source(struct wl_client *client, return; } + source->accept = client_data_source_accept; + source->send = client_data_source_send; + source->cancel = client_data_source_cancel; + wl_array_init(&source->mime_types); wl_signal_init(&source->events.destroy); From fb25adae36bd07fd3e159ae77c9827abf8742dfc Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 15 Oct 2017 14:50:21 -0400 Subject: [PATCH 08/19] xwayland: use xfixes extension --- meson.build | 1 + xwayland/meson.build | 9 ++++++++- xwayland/xwm.c | 22 ++++++++++++++++++++++ xwayland/xwm.h | 2 ++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 3e4cab38..e4b5a39f 100644 --- a/meson.build +++ b/meson.build @@ -51,6 +51,7 @@ udev = dependency('libudev') pixman = dependency('pixman-1') xcb = dependency('xcb') xcb_composite = dependency('xcb-composite') +xcb_xfixes = dependency('xcb-xfixes') xcb_icccm = dependency('xcb-icccm', required: false) x11_xcb = dependency('x11-xcb') libcap = dependency('libcap', required: false) diff --git a/xwayland/meson.build b/xwayland/meson.build index d989f6dd..a05ae584 100644 --- a/xwayland/meson.build +++ b/xwayland/meson.build @@ -6,5 +6,12 @@ lib_wlr_xwayland = static_library( 'xwm.c', ), include_directories: wlr_inc, - dependencies: [wayland_server, xcb, xcb_composite, xcb_icccm, pixman], + dependencies: [ + wayland_server, + xcb, + xcb_composite, + xcb_xfixes, + xcb_icccm, + pixman, + ], ) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index bc1bb4de..fd70fe4c 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -3,6 +3,7 @@ #endif #include #include +#include #include "wlr/util/log.h" #include "wlr/types/wlr_surface.h" #include "wlr/xwayland.h" @@ -825,9 +826,30 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) { // TODO more xcb init // xcb_prefetch_extension_data(xwm->xcb_conn, &xcb_composite_id); + xcb_prefetch_extension_data(xwm->xcb_conn, &xcb_xfixes_id); + xcb_get_resources(xwm); xcb_init_wm(xwm); + xwm->xfixes = xcb_get_extension_data(xwm->xcb_conn, &xcb_xfixes_id); + + if (!xwm->xfixes || !xwm->xfixes->present) { + wlr_log(L_DEBUG, "xfixes not available"); + } + + xcb_xfixes_query_version_cookie_t xfixes_cookie; + xcb_xfixes_query_version_reply_t *xfixes_reply; + xfixes_cookie = + xcb_xfixes_query_version(xwm->xcb_conn, XCB_XFIXES_MAJOR_VERSION, + XCB_XFIXES_MINOR_VERSION); + xfixes_reply = + xcb_xfixes_query_version_reply(xwm->xcb_conn, xfixes_cookie, NULL); + + wlr_log(L_DEBUG, "xfixes version: %d.%d", + xfixes_reply->major_version, xfixes_reply->minor_version); + + free(xfixes_reply); + xwm->surface_create_listener.notify = create_surface_handler; wl_signal_add(&wlr_xwayland->compositor->events.create_surface, &xwm->surface_create_listener); diff --git a/xwayland/xwm.h b/xwayland/xwm.h index be710a1b..a04b1065 100644 --- a/xwayland/xwm.h +++ b/xwayland/xwm.h @@ -85,6 +85,8 @@ struct wlr_xwm { struct wl_list new_surfaces; struct wl_list unpaired_surfaces; + + const xcb_query_extension_reply_t *xfixes; }; void xwm_destroy(struct wlr_xwm *xwm); From 34f27ff691d046355d68c7d6a2e0dfb438bd7755 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 05:07:09 -0400 Subject: [PATCH 09/19] wlr-seat: selection signal --- include/wlr/types/wlr_seat.h | 2 ++ types/wlr_data_device.c | 11 ++++++++--- types/wlr_seat.c | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 88d42112..cc7a5927 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -132,6 +132,8 @@ struct wlr_seat { struct wl_signal keyboard_grab_end; struct wl_signal request_set_cursor; + + struct wl_signal selection; } events; void *data; diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index d5782830..d992424a 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -283,11 +283,16 @@ static void seat_handle_selection_data_source_destroy( struct wlr_seat *seat = wl_container_of(listener, seat, selection_data_source_destroy); - // TODO send null selection to focused keyboard + if (seat->keyboard_state.focused_handle && + seat->keyboard_state.focused_surface && + seat->keyboard_state.focused_handle->data_device) { + wl_data_device_send_selection( + seat->keyboard_state.focused_handle->data_device, NULL); + } seat->selection_source = NULL; - // TODO emit selection signal + wl_signal_emit(&seat->events.selection, seat); } void wlr_seat_set_selection(struct wlr_seat *seat, @@ -313,7 +318,7 @@ void wlr_seat_set_selection(struct wlr_seat *seat, wlr_seat_handle_send_selection(focused_handle); } - // TODO emit selection signal + wl_signal_emit(&seat->events.selection, seat); if (source) { seat->selection_data_source_destroy.notify = diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 162f97b9..1285f2ee 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -309,7 +309,9 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { wl_signal_init(&wlr_seat->events.client_bound); wl_signal_init(&wlr_seat->events.client_unbound); + wl_signal_init(&wlr_seat->events.request_set_cursor); + wl_signal_init(&wlr_seat->events.selection); wl_signal_init(&wlr_seat->events.pointer_grab_begin); wl_signal_init(&wlr_seat->events.pointer_grab_end); From 3f3110452c28abf017bba7559ec9da7eabf099ea Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 06:31:53 -0400 Subject: [PATCH 10/19] wlr-seat: pointer state button info --- include/wlr/types/wlr_seat.h | 11 ++++++++--- types/wlr_seat.c | 18 +++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index cc7a5927..f5d5c357 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -75,11 +75,16 @@ struct wlr_seat_pointer_state { struct wlr_seat_handle *focused_handle; struct wlr_surface *focused_surface; - struct wl_listener surface_destroy; - struct wl_listener resource_destroy; - struct wlr_seat_pointer_grab *grab; struct wlr_seat_pointer_grab *default_grab; + + uint32_t button_count; + uint32_t grab_button; + uint32_t grab_serial; + uint32_t grab_time; + + struct wl_listener surface_destroy; + struct wl_listener resource_destroy; }; struct wlr_seat_keyboard { diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 1285f2ee..bad0e5cf 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -538,8 +538,24 @@ void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time, uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat, uint32_t time, uint32_t button, uint32_t state) { + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (wlr_seat->pointer_state.button_count == 0) { + wlr_seat->pointer_state.grab_button = button; + wlr_seat->pointer_state.grab_time = time; + } + wlr_seat->pointer_state.button_count++; + } else { + wlr_seat->pointer_state.button_count--; + } + struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; - return grab->interface->button(grab, time, button, state); + uint32_t serial = grab->interface->button(grab, time, button, state); + + if (wlr_seat->pointer_state.button_count == 1) { + wlr_seat->pointer_state.grab_serial = serial; + } + + return serial; } void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time, From 570a951947be8def68d66ad3c9aff32756867f50 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 06:43:41 -0400 Subject: [PATCH 11/19] data-device: button release drag bugfixes --- types/wlr_data_device.c | 62 ++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index d992424a..0ee88161 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -460,31 +460,30 @@ static uint32_t pointer_drag_button(struct wlr_seat_pointer_grab *grab, uint32_t time, uint32_t button, uint32_t state) { struct wlr_drag *drag = grab->data; - // TODO check no buttons are pressed to end the drag - // TODO make sure the button pressed to do the drag was the same to end the - // drag - - if (state == WL_POINTER_BUTTON_STATE_RELEASED) { - if (drag->source) { - if (drag->focus_handle && drag->focus_handle->data_device && - drag->source->current_dnd_action && - drag->source->accepted) { - wl_data_device_send_drop(drag->focus_handle->data_device); - if (wl_resource_get_version(drag->source->resource) >= - WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) { - wl_data_source_send_dnd_drop_performed( + if (drag->source && + grab->seat->pointer_state.grab_button == button && + state == WL_POINTER_BUTTON_STATE_RELEASED) { + if (drag->focus_handle && drag->focus_handle->data_device && + drag->source->current_dnd_action && + drag->source->accepted) { + wl_data_device_send_drop(drag->focus_handle->data_device); + if (wl_resource_get_version(drag->source->resource) >= + WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) { + wl_data_source_send_dnd_drop_performed( drag->source->resource); - } - - drag->source->offer->in_ask = - drag->source->current_dnd_action == - WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; } + + drag->source->offer->in_ask = + drag->source->current_dnd_action == + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; } else if (wl_resource_get_version(drag->source->resource) >= WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { wl_data_source_send_cancelled(drag->source->resource); } + } + if (grab->seat->pointer_state.button_count == 0 && + state == WL_POINTER_BUTTON_STATE_RELEASED) { wlr_drag_end(drag); } @@ -527,6 +526,8 @@ static bool seat_handle_start_drag(struct wlr_seat_handle *handle, return false; } + struct wlr_seat *seat = handle->wlr_seat; + if (icon) { drag->icon = icon; drag->icon_destroy.notify = drag_handle_icon_destroy; @@ -544,9 +545,9 @@ static bool seat_handle_start_drag(struct wlr_seat_handle *handle, drag->pointer_grab.data = drag; drag->pointer_grab.interface = &wlr_data_device_pointer_drag_interface; - wlr_seat_pointer_clear_focus(handle->wlr_seat); + wlr_seat_pointer_clear_focus(seat); - wlr_seat_pointer_start_grab(handle->wlr_seat, &drag->pointer_grab); + wlr_seat_pointer_start_grab(seat, &drag->pointer_grab); // TODO keyboard grab @@ -559,10 +560,20 @@ 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_handle *handle = wl_resource_get_user_data(handle_resource); + struct wlr_seat *seat = handle->wlr_seat; struct wlr_surface *origin = wl_resource_get_user_data(origin_resource); struct wlr_data_source *source = NULL; struct wlr_surface *icon = NULL; + bool is_pointer_grab = seat->pointer_state.button_count == 1 && + seat->pointer_state.grab_serial == serial && + seat->pointer_state.focused_surface && + seat->pointer_state.focused_surface == origin; + + if (!is_pointer_grab) { + return; + } + if (source_resource) { source = wl_resource_get_user_data(source_resource); } @@ -578,12 +589,11 @@ static void data_device_start_drag(struct wl_client *client, } // TODO touch grab - if (handle->wlr_seat->pointer_state.focused_surface == origin) { - if (!seat_handle_start_drag(handle, source, icon)) { - wl_resource_post_no_memory(handle_resource); - } else { - source->seat = handle; - } + + if (!seat_handle_start_drag(handle, source, icon)) { + wl_resource_post_no_memory(handle_resource); + } else { + source->seat = handle; } } From 2d35e20691c86600fdb3a20dffdf71c765683e10 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 07:29:18 -0400 Subject: [PATCH 12/19] data-device: keyboard grabs --- include/wlr/types/wlr_data_device.h | 5 +++++ types/wlr_data_device.c | 35 +++++++++++++++++++++++++++++ types/wlr_seat.c | 6 +++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index b4aa024a..e1e1e516 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -7,6 +7,9 @@ extern const struct wlr_pointer_grab_interface wlr_data_device_pointer_drag_interface; +extern const struct +wlr_keyboard_grab_interface wlr_data_device_keyboard_drag_interface; + struct wlr_data_device_manager { struct wl_global *global; }; @@ -49,6 +52,8 @@ struct wlr_data_source { struct wlr_drag { struct wlr_seat_pointer_grab pointer_grab; + struct wlr_seat_keyboard_grab keyboard_grab; + struct wlr_seat_handle *handle; struct wlr_seat_handle *focus_handle; diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 0ee88161..6616c338 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -438,6 +438,7 @@ static void wlr_drag_end(struct wlr_drag *drag) { wlr_drag_set_focus(drag, NULL, 0, 0); wlr_seat_pointer_end_grab(drag->pointer_grab.seat); + wlr_seat_keyboard_end_grab(drag->keyboard_grab.seat); free(drag); } @@ -508,6 +509,36 @@ wlr_pointer_grab_interface wlr_data_device_pointer_drag_interface = { .cancel = pointer_drag_cancel, }; +static void keyboard_drag_enter(struct wlr_seat_keyboard_grab *grab, + struct wlr_surface *surface) { + // nothing has keyboard focus during drags +} + +static void keyboard_drag_key(struct wlr_seat_keyboard_grab *grab, + uint32_t time, uint32_t key, uint32_t state) { + // no keyboard input during drags +} + +static void keyboard_drag_modifiers(struct wlr_seat_keyboard_grab *grab, + uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) { + // TODO change the dnd action based on what modifier is pressed on the + // keyboard +} + +static void keyboard_drag_cancel(struct wlr_seat_keyboard_grab *grab) { + struct wlr_drag *drag = grab->data; + wlr_drag_end(drag); +} + +const struct +wlr_keyboard_grab_interface wlr_data_device_keyboard_drag_interface = { + .enter = keyboard_drag_enter, + .key = keyboard_drag_key, + .modifiers = keyboard_drag_modifiers, + .cancel = keyboard_drag_cancel, +}; + static void drag_handle_icon_destroy(struct wl_listener *listener, void *data) { struct wlr_drag *drag = wl_container_of(listener, drag, icon_destroy); drag->icon = NULL; @@ -545,8 +576,12 @@ static bool seat_handle_start_drag(struct wlr_seat_handle *handle, drag->pointer_grab.data = drag; drag->pointer_grab.interface = &wlr_data_device_pointer_drag_interface; + drag->keyboard_grab.data = drag; + drag->keyboard_grab.interface = &wlr_data_device_keyboard_drag_interface; + wlr_seat_pointer_clear_focus(seat); + wlr_seat_keyboard_start_grab(seat, &drag->keyboard_grab); wlr_seat_pointer_start_grab(seat, &drag->pointer_grab); // TODO keyboard grab diff --git a/types/wlr_seat.c b/types/wlr_seat.c index bad0e5cf..a4721e22 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -696,9 +696,11 @@ void wlr_seat_keyboard_start_grab(struct wlr_seat *wlr_seat, void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat) { struct wlr_seat_keyboard_grab *grab = wlr_seat->keyboard_state.grab; - wlr_seat->keyboard_state.grab = wlr_seat->keyboard_state.default_grab; - wl_signal_emit(&wlr_seat->events.keyboard_grab_end, grab); + if (grab != wlr_seat->keyboard_state.default_grab) { + wlr_seat->keyboard_state.grab = wlr_seat->keyboard_state.default_grab; + wl_signal_emit(&wlr_seat->events.keyboard_grab_end, grab); + } } static void keyboard_surface_destroy_notify(struct wl_listener *listener, From b8de0a29b4f53700eef40edc76653ff318bbcf89 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 08:00:01 -0400 Subject: [PATCH 13/19] rootston: handle icon already being in the list --- rootston/cursor.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rootston/cursor.c b/rootston/cursor.c index 19f015aa..5867528e 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -319,6 +319,14 @@ static void handle_pointer_grab_begin(struct wl_listener *listener, if (grab->interface == &wlr_data_device_pointer_drag_interface) { struct wlr_drag *drag = grab->data; if (drag->icon) { + struct roots_drag_icon *iter_icon; + wl_list_for_each(iter_icon, &input->drag_icons, link) { + if (iter_icon->surface == drag->icon) { + // already in the list + return; + } + } + struct roots_drag_icon *drag_icon = calloc(1, sizeof(struct roots_drag_icon)); drag_icon->surface = drag->icon; From c0e8585a4cd3ef5b9616efa2f61fe5b029c5d147 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 08:56:59 -0400 Subject: [PATCH 14/19] data-device: handle multiple data devices --- types/wlr_data_device.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 6616c338..3fcd5873 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -652,8 +652,12 @@ void data_device_manager_get_data_device(struct wl_client *client, return; } - // TODO handle a seat handle having multiple data devices - assert(handle->data_device == NULL); + if (handle->data_device != NULL) { + // XXX this is probably a protocol violation, but it simplfies our code + // and it's stupid to create several data devices for the same seat. + wl_resource_destroy(handle->data_device); + } + handle->data_device = resource; wl_resource_set_implementation(resource, &data_device_impl, From f9d578700e6f28d2d4dc1db3c81469640484473e Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 09:14:16 -0400 Subject: [PATCH 15/19] bug: fix seat handle destroy handler --- types/wlr_data_device.c | 1 + types/wlr_seat.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 3fcd5873..8902c894 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -353,6 +353,7 @@ static void drag_handle_seat_unbound(struct wl_listener *listener, void *data) { if (drag->focus_handle == unbound_handle) { drag->focus_handle = NULL; + wl_list_remove(&drag->handle_unbound.link); } } diff --git a/types/wlr_seat.c b/types/wlr_seat.c index a4721e22..60db8d2e 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -142,6 +142,8 @@ static void wl_seat_get_touch(struct wl_client *client, static void wlr_seat_handle_resource_destroy(struct wl_resource *resource) { struct wlr_seat_handle *handle = wl_resource_get_user_data(resource); + wl_signal_emit(&handle->wlr_seat->events.client_unbound, handle); + if (handle == handle->wlr_seat->pointer_state.focused_handle) { handle->wlr_seat->pointer_state.focused_handle = NULL; } @@ -161,7 +163,6 @@ static void wlr_seat_handle_resource_destroy(struct wl_resource *resource) { if (handle->data_device) { wl_resource_destroy(handle->data_device); } - wl_signal_emit(&handle->wlr_seat->events.client_unbound, handle); wl_list_remove(&handle->link); free(handle); } From 09f16058c890cc3329c8aa39593f229b2bf31443 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 10:00:32 -0400 Subject: [PATCH 16/19] cleanup: redo buggy set pointer function --- types/wlr_seat.c | 1 - 1 file changed, 1 deletion(-) diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 60db8d2e..69199a63 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -24,7 +24,6 @@ static void wl_pointer_set_cursor(struct wl_client *client, struct wl_resource *resource, uint32_t serial, struct wl_resource *surface_resource, int32_t hotspot_x, int32_t hotspot_y) { - return; struct wlr_seat_handle *handle = wl_resource_get_user_data(resource); struct wlr_surface *surface = NULL; if (surface_resource != NULL) { From c00a94ca76cfc81353b78174e88539f17e9db7e0 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 17 Oct 2017 17:21:11 -0400 Subject: [PATCH 17/19] data-device: fix drag icon position --- include/rootston/input.h | 3 +++ rootston/cursor.c | 3 +++ rootston/output.c | 6 ++---- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/rootston/input.h b/include/rootston/input.h index 40aea80a..357991ee 100644 --- a/include/rootston/input.h +++ b/include/rootston/input.h @@ -75,6 +75,9 @@ struct roots_drag_icon { struct wl_list link; // roots_input::drag_icons bool mapped; + int32_t sx; + int32_t sy; + struct wl_listener surface_destroy; struct wl_listener surface_commit; }; diff --git a/rootston/cursor.c b/rootston/cursor.c index bd988a41..6b509640 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -313,6 +313,9 @@ static void handle_drag_icon_commit(struct wl_listener *listener, void *data) { // TODO the spec hints at rules that can determine whether the drag icon is // mapped here, but it is not completely clear so we need to test more // toolkits to see how we should interpret the surface state here. + drag_icon->sx += drag_icon->surface->current->sx; + drag_icon->sy += drag_icon->surface->current->sy; + drag_icon->mapped = drag_icon->surface->texture->valid; } diff --git a/rootston/output.c b/rootston/output.c index b431cbc3..f50306a3 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -158,10 +158,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct wlr_surface *icon = drag_icon->surface; struct wlr_cursor *cursor = server->input->cursor; - // TODO should also use the hotspot to determine the location, but - // hotspot is broken right now. - double icon_x = cursor->x - icon->current->sx; - double icon_y = cursor->y - icon->current->sy; + double icon_x = cursor->x + drag_icon->sx; + double icon_y = cursor->y + drag_icon->sy; render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); } From 6fcac087fe1d7b7fa3cd0628a6b7818d26222678 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 21 Oct 2017 09:59:35 -0400 Subject: [PATCH 18/19] rootston: remove mostly unused mapped icon param --- include/rootston/input.h | 1 - rootston/cursor.c | 2 -- rootston/output.c | 4 ---- 3 files changed, 7 deletions(-) diff --git a/include/rootston/input.h b/include/rootston/input.h index aacb3016..33750d7b 100644 --- a/include/rootston/input.h +++ b/include/rootston/input.h @@ -67,7 +67,6 @@ struct roots_input_event { struct roots_drag_icon { struct wlr_surface *surface; struct wl_list link; // roots_input::drag_icons - bool mapped; int32_t sx; int32_t sy; diff --git a/rootston/cursor.c b/rootston/cursor.c index 83581101..200a6d37 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -374,8 +374,6 @@ static void handle_drag_icon_commit(struct wl_listener *listener, void *data) { // toolkits to see how we should interpret the surface state here. drag_icon->sx += drag_icon->surface->current->sx; drag_icon->sy += drag_icon->surface->current->sy; - - drag_icon->mapped = drag_icon->surface->texture->valid; } static void handle_pointer_grab_begin(struct wl_listener *listener, diff --git a/rootston/output.c b/rootston/output.c index fce14fea..f560061d 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -152,10 +152,6 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct roots_drag_icon *drag_icon = NULL; wl_list_for_each(drag_icon, &server->input->drag_icons, link) { - if (!drag_icon->mapped) { - continue; - } - struct wlr_surface *icon = drag_icon->surface; struct wlr_cursor *cursor = server->input->cursor; double icon_x = cursor->x + drag_icon->sx; From 6e7caaee6be066a742f732a40bbb713866d410b4 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 23 Oct 2017 09:09:12 -0400 Subject: [PATCH 19/19] Revert "wlr-surface: destroy texture on null buffer commit" This reverts commit 0e7d13fab7f23658a85df58ad26c6c77c9638bff. --- types/wlr_surface.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index f8689d8e..79905fae 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -406,8 +406,7 @@ static void wlr_surface_commit_pending(struct wlr_surface *surface) { wlr_surface_move_state(surface, surface->pending, surface->current); if (null_buffer_commit) { - wlr_texture_destroy(surface->texture); - surface->texture = NULL; + surface->texture->valid = false; } bool reupload_buffer = oldw != surface->current->buffer_width ||