main neuswc / libswc / data_device.c
  1/* swc: data_device.c
  2 *
  3 * Copyright (c) 2013-2020 Michael Forney
  4 *
  5 * Permission is hereby granted, free of charge, to any person obtaining a copy
  6 * of this software and associated documentation files (the "Software"), to deal
  7 * in the Software without restriction, including without limitation the rights
  8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9 * copies of the Software, and to permit persons to whom the Software is
 10 * furnished to do so, subject to the following conditions:
 11 *
 12 * The above copyright notice and this permission notice shall be included in
 13 * all copies or substantial portions of the Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21 * SOFTWARE.
 22 */
 23
 24#include "data_device.h"
 25#include "data.h"
 26#include "event.h"
 27#include "util.h"
 28
 29static void
 30start_drag(struct wl_client *client, struct wl_resource *resource,
 31           struct wl_resource *source_resource,
 32           struct wl_resource *origin_resource,
 33           struct wl_resource *icon_resource, uint32_t serial)
 34{
 35	/* XXX: Implement */
 36}
 37
 38static void
 39set_selection(struct wl_client *client, struct wl_resource *resource,
 40              struct wl_resource *data_source, uint32_t serial)
 41{
 42	struct data_device *data_device = wl_resource_get_user_data(resource);
 43
 44	/* Check if this data source is already the current selection. */
 45	if (data_source == data_device->selection) {
 46		return;
 47	}
 48
 49	if (data_device->selection) {
 50		wl_data_source_send_cancelled(data_device->selection);
 51		wl_list_remove(&data_device->selection_destroy_listener.link);
 52	}
 53
 54	data_device->selection = data_source;
 55
 56	if (data_source) {
 57		wl_resource_add_destroy_listener(
 58		    data_source, &data_device->selection_destroy_listener);
 59	}
 60
 61	send_event(&data_device->event_signal, DATA_DEVICE_EVENT_SELECTION_CHANGED,
 62	           NULL);
 63}
 64
 65static const struct wl_data_device_interface data_device_impl = {
 66    .start_drag = start_drag,
 67    .set_selection = set_selection,
 68    .release = destroy_resource,
 69};
 70
 71static void
 72handle_selection_destroy(struct wl_listener *listener, void *data)
 73{
 74	struct data_device *data_device =
 75	    wl_container_of(listener, data_device, selection_destroy_listener);
 76
 77	data_device->selection = NULL;
 78	send_event(&data_device->event_signal, DATA_DEVICE_EVENT_SELECTION_CHANGED,
 79	           NULL);
 80}
 81
 82struct data_device *
 83data_device_create(void)
 84{
 85	struct data_device *data_device;
 86
 87	data_device = malloc(sizeof(*data_device));
 88	if (!data_device) {
 89		return NULL;
 90	}
 91	data_device->selection = NULL;
 92	data_device->selection_destroy_listener.notify = &handle_selection_destroy;
 93	wl_signal_init(&data_device->event_signal);
 94	wl_list_init(&data_device->resources);
 95
 96	return data_device;
 97}
 98
 99void
100data_device_destroy(struct data_device *data_device)
101{
102	struct wl_resource *resource, *tmp;
103
104	wl_list_for_each_safe(resource, tmp, &data_device->resources, link)
105	    wl_resource_destroy(resource);
106	free(data_device);
107}
108
109struct wl_resource *
110data_device_bind(struct data_device *data_device, struct wl_client *client,
111                 uint32_t version, uint32_t id)
112{
113	struct wl_resource *resource;
114
115	resource =
116	    wl_resource_create(client, &wl_data_device_interface, version, id);
117	if (!resource) {
118		return NULL;
119	}
120	wl_resource_set_implementation(resource, &data_device_impl, data_device,
121	                               &remove_resource);
122	wl_list_insert(&data_device->resources, &resource->link);
123
124	return resource;
125}
126
127static struct wl_resource *
128new_offer(struct wl_resource *resource, struct wl_client *client,
129          struct wl_resource *source)
130{
131	struct wl_resource *offer;
132
133	offer = data_offer_new(client, source, wl_resource_get_version(resource));
134	if (!offer) {
135		return NULL;
136	}
137	wl_data_device_send_data_offer(resource, offer);
138	data_send_mime_types(source, offer);
139
140	return offer;
141}
142
143void
144data_device_offer_selection(struct data_device *data_device,
145                            struct wl_client *client)
146{
147	struct wl_resource *resource;
148	struct wl_resource *offer = NULL;
149
150	/* Look for the client's data_device resource. */
151	resource = wl_resource_find_for_client(&data_device->resources, client);
152
153	/* If the client does not have a data device, there is nothing to do. */
154	if (!resource) {
155		return;
156	}
157
158	/* If we have a selection, create a new offer for the client. */
159	if (data_device->selection) {
160		offer = new_offer(resource, client, data_device->selection);
161	}
162
163	wl_data_device_send_selection(resource, offer);
164}