diff options
| author | Tony Crisci <tony@dubstepdish.com> | 2017-10-12 11:41:11 -0400 | 
|---|---|---|
| committer | Tony Crisci <tony@dubstepdish.com> | 2017-10-15 05:59:52 -0400 | 
| commit | 3892acecac773b825532f84da4671c2a55f5e82a (patch) | |
| tree | 642dfb4a5335b93c3e1c437d3caa7dccf8263ac3 | |
| parent | 6a7560fae05147ac5a1ac0dd3474670f1bd6c871 (diff) | |
| download | wlroots-3892acecac773b825532f84da4671c2a55f5e82a.tar.xz | |
wlr-data-device: basic clipboard
| -rw-r--r-- | include/wlr/types/wlr_data_device.h | 19 | ||||
| -rw-r--r-- | include/wlr/types/wlr_seat.h | 2 | ||||
| -rw-r--r-- | types/wlr_data_device.c | 187 | ||||
| -rw-r--r-- | types/wlr_seat.c | 3 | 
4 files changed, 204 insertions, 7 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 <stdlib.h>  #include <string.h>  #include <assert.h> +#include <unistd.h>  #include <wayland-server.h>  #include <wlr/util/log.h>  #include <wlr/types/wlr_seat.h> @@ -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 <wlr/types/wlr_seat.h>  #include <wlr/types/wlr_input_device.h>  #include <wlr/util/log.h> +#include <wlr/types/wlr_data_device.h>  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 | 
