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}