From 6a7560fae05147ac5a1ac0dd3474670f1bd6c871 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 11 Oct 2017 15:48:40 -0400 Subject: wlr-data-device interface --- 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 ++++- 5 files changed, 35 insertions(+), 75 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 (limited to 'include/wlr') 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; -- cgit v1.2.3 From 3892acecac773b825532f84da4671c2a55f5e82a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 12 Oct 2017 11:41:11 -0400 Subject: 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 | 187 ++++++++++++++++++++++++++++++++++-- types/wlr_seat.c | 3 + 4 files changed, 204 insertions(+), 7 deletions(-) (limited to 'include/wlr') 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 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 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 *data_device_resourec) { - // TODO - return NULL; + 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; } -static void wlr_seat_handle_send_selection(struct wlr_seat_handle *handle) { +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 -- cgit v1.2.3 From 25831d287eb03d9d61cf4fd476e3d463124d1fce Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 13 Oct 2017 07:58:46 -0400 Subject: 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(-) (limited to 'include/wlr') 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) { -- cgit v1.2.3 From 07259cf8ea7eae1666b2a62bd3b9cc120d0a4276 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 13 Oct 2017 08:05:53 -0400 Subject: 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(-) (limited to 'include/wlr') 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, -- cgit v1.2.3 From a1bfa4a2f2e8c72761486b7219fe19a61c9dbda2 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 14 Oct 2017 15:53:30 -0400 Subject: 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(-) (limited to 'include/wlr') 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( -- cgit v1.2.3 From df0a8d3abe6a7a8cd010e07f078c0e92ea2fb516 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 15 Oct 2017 11:06:03 -0400 Subject: 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(-) (limited to 'include/wlr') 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) { -- cgit v1.2.3 From 02f4acc69f8d94657f341b80364180c8c2e3ce33 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 15 Oct 2017 14:49:43 -0400 Subject: 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(-) (limited to 'include/wlr') 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); -- cgit v1.2.3 From 34f27ff691d046355d68c7d6a2e0dfb438bd7755 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 05:07:09 -0400 Subject: 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(-) (limited to 'include/wlr') 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); -- cgit v1.2.3 From 3f3110452c28abf017bba7559ec9da7eabf099ea Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 06:31:53 -0400 Subject: 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(-) (limited to 'include/wlr') 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, -- cgit v1.2.3 From 2d35e20691c86600fdb3a20dffdf71c765683e10 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 16 Oct 2017 07:29:18 -0400 Subject: 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(-) (limited to 'include/wlr') 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, -- cgit v1.2.3