diff options
| author | emersion <contact@emersion.fr> | 2018-11-21 10:59:11 +0100 | 
|---|---|---|
| committer | emersion <contact@emersion.fr> | 2018-11-21 11:16:25 +0100 | 
| commit | b9a2e4ba4c92cd4c19f8cf5ed7e6603731eca9ab (patch) | |
| tree | 2bba6f5007ad5a46c9d6874d2e32d0148e843ec6 | |
| parent | 040d62de0076a349612b7c2c28c5dc5e93bb9760 (diff) | |
| download | wlroots-b9a2e4ba4c92cd4c19f8cf5ed7e6603731eca9ab.tar.xz | |
gtk-primary-selection: support multiple devices
When a client was creating multiple data devices for the same seat, we were
only creating one resource. This is a protocol error.
Instead, create one offer per data device.
This commit also makes offers inert when their source is destroyed.
Fixes part of https://github.com/swaywm/wlroots/issues/1041
Supersedes https://github.com/swaywm/wlroots/pull/1113
| -rw-r--r-- | include/wlr/types/wlr_primary_selection.h | 3 | ||||
| -rw-r--r-- | types/wlr_primary_selection.c | 96 | 
2 files changed, 40 insertions, 59 deletions
| diff --git a/include/wlr/types/wlr_primary_selection.h b/include/wlr/types/wlr_primary_selection.h index f33f6368..c11e2fab 100644 --- a/include/wlr/types/wlr_primary_selection.h +++ b/include/wlr/types/wlr_primary_selection.h @@ -24,8 +24,6 @@ struct wlr_primary_selection_device_manager {  	void *data;  }; -struct wlr_primary_selection_offer; -  struct wlr_primary_selection_source {  	// source metadata  	struct wl_array mime_types; @@ -36,7 +34,6 @@ struct wlr_primary_selection_source {  	void (*cancel)(struct wlr_primary_selection_source *source);  	// source status -	struct wlr_primary_selection_offer *offer;  	struct wlr_seat_client *seat_client;  	struct { diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c index 3fed0f64..0539773b 100644 --- a/types/wlr_primary_selection.c +++ b/types/wlr_primary_selection.c @@ -9,6 +9,8 @@  #include "gtk-primary-selection-protocol.h"  #include "util/signal.h" +#define DEVICE_MANAGER_VERSION 1 +  static const struct gtk_primary_selection_offer_interface offer_impl;  static struct wlr_primary_selection_offer *offer_from_resource( @@ -21,12 +23,12 @@ static struct wlr_primary_selection_offer *offer_from_resource(  static void offer_handle_receive(struct wl_client *client,  		struct wl_resource *resource, const char *mime_type, int32_t fd) {  	struct wlr_primary_selection_offer *offer = offer_from_resource(resource); - -	if (offer->source && offer == offer->source->offer) { -		offer->source->send(offer->source, mime_type, fd); -	} else { +	if (offer == NULL) {  		close(fd); +		return;  	} + +	offer->source->send(offer->source, mime_type, fd);  }  static void offer_handle_destroy(struct wl_client *client, @@ -39,31 +41,26 @@ static const struct gtk_primary_selection_offer_interface offer_impl = {  	.destroy = offer_handle_destroy,  }; -static void offer_resource_handle_destroy(struct wl_resource *resource) { -	struct wlr_primary_selection_offer *offer = offer_from_resource(resource); - -	if (!offer->source) { -		goto out; +static void offer_destroy(struct wlr_primary_selection_offer *offer) { +	if (offer == NULL) { +		return;  	} - +	// Make resource inert +	wl_resource_set_user_data(offer->resource, NULL);  	wl_list_remove(&offer->source_destroy.link); - -	if (offer->source->offer != offer) { -		goto out; -	} - -	offer->source->offer = NULL; - -out:  	free(offer);  } +static void offer_handle_resource_destroy(struct wl_resource *resource) { +	struct wlr_primary_selection_offer *offer = offer_from_resource(resource); +	offer_destroy(offer); +} +  static void offer_handle_source_destroy(struct wl_listener *listener,  		void *data) {  	struct wlr_primary_selection_offer *offer =  		wl_container_of(listener, offer, source_destroy); - -	offer->source = NULL; +	offer_destroy(offer);  } @@ -85,38 +82,32 @@ static void client_source_cancel(  	gtk_primary_selection_source_send_cancelled(source->resource);  } -static struct wlr_primary_selection_offer *source_send_offer( -		struct wlr_primary_selection_source *source, -		struct wlr_seat_client *target) { -	if (wl_list_empty(&target->primary_selection_devices)) { -		return NULL; -	} - +static void source_send_offer(struct wlr_primary_selection_source *source, +		struct wl_resource *device_resource) {  	struct wlr_primary_selection_offer *offer =  		calloc(1, sizeof(struct wlr_primary_selection_offer));  	if (offer == NULL) { -		return NULL; +		wl_resource_post_no_memory(device_resource); +		return;  	} -	uint32_t version = wl_resource_get_version( -		wl_resource_from_link(target->primary_selection_devices.next)); -	offer->resource = wl_resource_create(target->client, +	struct wl_client *client = wl_resource_get_client(device_resource); +	uint32_t version = wl_resource_get_version(device_resource); +	offer->resource = wl_resource_create(client,  		>k_primary_selection_offer_interface, version, 0);  	if (offer->resource == NULL) {  		free(offer); -		return NULL; +		wl_resource_post_no_memory(device_resource); +		return;  	}  	wl_resource_set_implementation(offer->resource, &offer_impl, offer, -		offer_resource_handle_destroy); +		offer_handle_resource_destroy);  	offer->source_destroy.notify = offer_handle_source_destroy;  	wl_signal_add(&source->events.destroy, &offer->source_destroy); -	struct wl_resource *target_resource; -	wl_resource_for_each(target_resource, &target->primary_selection_devices) { -		gtk_primary_selection_device_send_data_offer(target_resource, -			offer->resource); -	} +	gtk_primary_selection_device_send_data_offer(device_resource, +		offer->resource);  	char **p;  	wl_array_for_each(p, &source->mime_types) { @@ -124,9 +115,9 @@ static struct wlr_primary_selection_offer *source_send_offer(  	}  	offer->source = source; -	source->offer = offer; -	return offer; +	gtk_primary_selection_device_send_selection(device_resource, +		offer->resource);  }  static const struct gtk_primary_selection_source_interface source_impl; @@ -179,20 +170,13 @@ void wlr_seat_client_send_primary_selection(  		return;  	} -	if (seat_client->seat->primary_selection_source) { -		struct wlr_primary_selection_offer *offer = source_send_offer( -			seat_client->seat->primary_selection_source, seat_client); -		if (offer == NULL) { -			return; -		} - -		struct wl_resource *resource; -		wl_resource_for_each(resource, &seat_client->primary_selection_devices) { -			gtk_primary_selection_device_send_selection(resource, offer->resource); -		} -	} else { -		struct wl_resource *resource; -		wl_resource_for_each(resource, &seat_client->primary_selection_devices) { +	struct wlr_primary_selection_source *source = +		seat_client->seat->primary_selection_source; +	struct wl_resource *resource; +	wl_resource_for_each(resource, &seat_client->primary_selection_devices) { +		if (source) { +			source_send_offer(source, resource); +		} else {  			gtk_primary_selection_device_send_selection(resource, NULL);  		}  	} @@ -401,8 +385,8 @@ struct wlr_primary_selection_device_manager *  		return NULL;  	}  	manager->global = wl_global_create(display, -		>k_primary_selection_device_manager_interface, 1, manager, -		primary_selection_device_manager_bind); +		>k_primary_selection_device_manager_interface, DEVICE_MANAGER_VERSION, +		manager, primary_selection_device_manager_bind);  	if (manager->global == NULL) {  		free(manager);  		return NULL; | 
