blob: 7d60351a7ecd3a00630fb8c5a58c34764f05a8b2 [file] [log] [blame]
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -04001/*
2 * Copyright © 2012 Intel Corporation
3 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040011 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040024 */
25
Daniel Stonec228e232013-05-22 18:03:19 +030026#include "config.h"
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040027
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030028#include <stdint.h>
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040029#include <stdlib.h>
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040030#include <string.h>
31#include <linux/input.h>
32#include <fcntl.h>
33#include <unistd.h>
34#include <sys/uio.h>
35
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020036#include <libweston/libweston.h>
Guillaume Champagnef1e8fc92020-01-27 20:14:29 -050037#include "libweston-internal.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070038#include "shared/helpers.h"
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040039
40struct clipboard_source {
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -070041 struct weston_data_source base;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040042 struct wl_array contents;
43 struct clipboard *clipboard;
44 struct wl_event_source *event_source;
45 uint32_t serial;
46 int refcount;
Kristian Høgsberg46118f82013-07-25 16:21:41 -070047 int fd;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040048};
49
50struct clipboard {
51 struct weston_seat *seat;
52 struct wl_listener selection_listener;
53 struct wl_listener destroy_listener;
54 struct clipboard_source *source;
55};
56
57static void clipboard_client_create(struct clipboard_source *source, int fd);
58
59static void
60clipboard_source_unref(struct clipboard_source *source)
61{
62 char **s;
63
64 source->refcount--;
65 if (source->refcount > 0)
66 return;
67
Kristian Høgsberg46118f82013-07-25 16:21:41 -070068 if (source->event_source) {
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040069 wl_event_source_remove(source->event_source);
Kristian Høgsberg46118f82013-07-25 16:21:41 -070070 close(source->fd);
71 }
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -050072 wl_signal_emit(&source->base.destroy_signal,
73 &source->base);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040074 s = source->base.mime_types.data;
75 free(*s);
76 wl_array_release(&source->base.mime_types);
77 wl_array_release(&source->contents);
78 free(source);
79}
80
81static int
82clipboard_source_data(int fd, uint32_t mask, void *data)
83{
84 struct clipboard_source *source = data;
85 struct clipboard *clipboard = source->clipboard;
86 char *p;
87 int len, size;
88
89 if (source->contents.alloc - source->contents.size < 1024) {
90 wl_array_add(&source->contents, 1024);
91 source->contents.size -= 1024;
92 }
93
94 p = source->contents.data + source->contents.size;
95 size = source->contents.alloc - source->contents.size;
96 len = read(fd, p, size);
97 if (len == 0) {
98 wl_event_source_remove(source->event_source);
Kristian Høgsberg46118f82013-07-25 16:21:41 -070099 close(fd);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400100 source->event_source = NULL;
101 } else if (len < 0) {
102 clipboard_source_unref(source);
103 clipboard->source = NULL;
104 } else {
105 source->contents.size += len;
106 }
107
108 return 1;
109}
110
111static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700112clipboard_source_accept(struct weston_data_source *source,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400113 uint32_t time, const char *mime_type)
114{
115}
116
117static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700118clipboard_source_send(struct weston_data_source *base,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400119 const char *mime_type, int32_t fd)
120{
121 struct clipboard_source *source =
122 container_of(base, struct clipboard_source, base);
123 char **s;
124
125 s = source->base.mime_types.data;
126 if (strcmp(mime_type, s[0]) == 0)
127 clipboard_client_create(source, fd);
128 else
129 close(fd);
130}
131
132static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700133clipboard_source_cancel(struct weston_data_source *source)
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400134{
135}
136
137static struct clipboard_source *
138clipboard_source_create(struct clipboard *clipboard,
139 const char *mime_type, uint32_t serial, int fd)
140{
141 struct wl_display *display = clipboard->seat->compositor->wl_display;
142 struct wl_event_loop *loop = wl_display_get_event_loop(display);
143 struct clipboard_source *source;
144 char **s;
145
Carlos Garnacho15902bf2016-02-01 20:28:14 +0100146 source = zalloc(sizeof *source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700147 if (source == NULL)
148 return NULL;
149
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400150 wl_array_init(&source->contents);
151 wl_array_init(&source->base.mime_types);
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500152 source->base.resource = NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400153 source->base.accept = clipboard_source_accept;
154 source->base.send = clipboard_source_send;
155 source->base.cancel = clipboard_source_cancel;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500156 wl_signal_init(&source->base.destroy_signal);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400157 source->refcount = 1;
158 source->clipboard = clipboard;
159 source->serial = serial;
Marek Chalupa389a10d2014-12-10 12:07:58 +0100160 source->fd = fd;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400161
162 s = wl_array_add(&source->base.mime_types, sizeof *s);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700163 if (s == NULL)
164 goto err_add;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400165 *s = strdup(mime_type);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700166 if (*s == NULL)
167 goto err_strdup;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400168 source->event_source =
169 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
170 clipboard_source_data, source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700171 if (source->event_source == NULL)
172 goto err_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400173
174 return source;
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700175
176 err_source:
177 free(*s);
178 err_strdup:
179 wl_array_release(&source->base.mime_types);
180 err_add:
181 free(source);
182
183 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400184}
185
186struct clipboard_client {
187 struct wl_event_source *event_source;
188 size_t offset;
189 struct clipboard_source *source;
190};
191
192static int
193clipboard_client_data(int fd, uint32_t mask, void *data)
194{
195 struct clipboard_client *client = data;
196 char *p;
197 size_t size;
198 int len;
199
200 size = client->source->contents.size;
201 p = client->source->contents.data;
202 len = write(fd, p + client->offset, size - client->offset);
203 if (len > 0)
204 client->offset += len;
205
206 if (client->offset == size || len <= 0) {
207 close(fd);
208 wl_event_source_remove(client->event_source);
209 clipboard_source_unref(client->source);
210 free(client);
211 }
212
213 return 1;
214}
215
216static void
217clipboard_client_create(struct clipboard_source *source, int fd)
218{
219 struct weston_seat *seat = source->clipboard->seat;
220 struct clipboard_client *client;
221 struct wl_event_loop *loop =
222 wl_display_get_event_loop(seat->compositor->wl_display);
223
Bryce Harringtonde447612014-11-20 22:21:55 -0800224 client = zalloc(sizeof *client);
225 if (client == NULL)
226 return;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400227
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400228 client->source = source;
229 source->refcount++;
230 client->event_source =
231 wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
232 clipboard_client_data, client);
233}
234
235static void
236clipboard_set_selection(struct wl_listener *listener, void *data)
237{
238 struct clipboard *clipboard =
239 container_of(listener, struct clipboard, selection_listener);
240 struct weston_seat *seat = data;
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700241 struct weston_data_source *source = seat->selection_data_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400242 const char **mime_types;
243 int p[2];
244
245 if (source == NULL) {
246 if (clipboard->source)
Kristian Høgsberge3148752013-05-06 23:19:49 -0400247 weston_seat_set_selection(seat,
248 &clipboard->source->base,
249 clipboard->source->serial);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400250 return;
251 } else if (source->accept == clipboard_source_accept) {
252 /* Callback for our data source. */
253 return;
254 }
255
256 if (clipboard->source)
257 clipboard_source_unref(clipboard->source);
258
259 clipboard->source = NULL;
260
261 mime_types = source->mime_types.data;
262
Giulio Camuffo6a94a992015-05-01 00:13:55 +0300263 if (!mime_types || pipe2(p, O_CLOEXEC) == -1)
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400264 return;
265
266 source->send(source, mime_types[0], p[1]);
267
268 clipboard->source =
269 clipboard_source_create(clipboard, mime_types[0],
Kristian Høgsberge3148752013-05-06 23:19:49 -0400270 seat->selection_serial, p[0]);
Kristian Høgsberg46118f82013-07-25 16:21:41 -0700271 if (clipboard->source == NULL) {
272 close(p[0]);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400273 return;
Kristian Høgsberg46118f82013-07-25 16:21:41 -0700274 }
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400275}
276
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200277static void
278clipboard_destroy(struct wl_listener *listener, void *data)
279{
280 struct clipboard *clipboard =
281 container_of(listener, struct clipboard, destroy_listener);
282
283 wl_list_remove(&clipboard->selection_listener.link);
Rob Bradfordc30c4bd2013-07-24 16:57:33 +0100284 wl_list_remove(&clipboard->destroy_listener.link);
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200285
286 free(clipboard);
287}
288
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400289struct clipboard *
290clipboard_create(struct weston_seat *seat)
291{
292 struct clipboard *clipboard;
293
Peter Huttererf3d62272013-08-08 11:57:05 +1000294 clipboard = zalloc(sizeof *clipboard);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400295 if (clipboard == NULL)
296 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400297
298 clipboard->seat = seat;
299 clipboard->selection_listener.notify = clipboard_set_selection;
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200300 clipboard->destroy_listener.notify = clipboard_destroy;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400301
Kristian Høgsberge3148752013-05-06 23:19:49 -0400302 wl_signal_add(&seat->selection_signal,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400303 &clipboard->selection_listener);
Kristian Høgsberg49124542013-05-06 22:27:40 -0400304 wl_signal_add(&seat->destroy_signal,
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200305 &clipboard->destroy_listener);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400306
307 return clipboard;
308}