blob: 54a578f0b2253377fbb992044cd9cfc9510b6ae0 [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
28#include <stdlib.h>
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040029#include <string.h>
30#include <linux/input.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <sys/uio.h>
34
35#include "compositor.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070036#include "shared/helpers.h"
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040037
38struct clipboard_source {
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -070039 struct weston_data_source base;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040040 struct wl_array contents;
41 struct clipboard *clipboard;
42 struct wl_event_source *event_source;
43 uint32_t serial;
44 int refcount;
Kristian Høgsberg46118f82013-07-25 16:21:41 -070045 int fd;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040046};
47
48struct clipboard {
49 struct weston_seat *seat;
50 struct wl_listener selection_listener;
51 struct wl_listener destroy_listener;
52 struct clipboard_source *source;
53};
54
55static void clipboard_client_create(struct clipboard_source *source, int fd);
56
57static void
58clipboard_source_unref(struct clipboard_source *source)
59{
60 char **s;
61
62 source->refcount--;
63 if (source->refcount > 0)
64 return;
65
Kristian Høgsberg46118f82013-07-25 16:21:41 -070066 if (source->event_source) {
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040067 wl_event_source_remove(source->event_source);
Kristian Høgsberg46118f82013-07-25 16:21:41 -070068 close(source->fd);
69 }
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -050070 wl_signal_emit(&source->base.destroy_signal,
71 &source->base);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040072 s = source->base.mime_types.data;
73 free(*s);
74 wl_array_release(&source->base.mime_types);
75 wl_array_release(&source->contents);
76 free(source);
77}
78
79static int
80clipboard_source_data(int fd, uint32_t mask, void *data)
81{
82 struct clipboard_source *source = data;
83 struct clipboard *clipboard = source->clipboard;
84 char *p;
85 int len, size;
86
87 if (source->contents.alloc - source->contents.size < 1024) {
88 wl_array_add(&source->contents, 1024);
89 source->contents.size -= 1024;
90 }
91
92 p = source->contents.data + source->contents.size;
93 size = source->contents.alloc - source->contents.size;
94 len = read(fd, p, size);
95 if (len == 0) {
96 wl_event_source_remove(source->event_source);
Kristian Høgsberg46118f82013-07-25 16:21:41 -070097 close(fd);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040098 source->event_source = NULL;
99 } else if (len < 0) {
100 clipboard_source_unref(source);
101 clipboard->source = NULL;
102 } else {
103 source->contents.size += len;
104 }
105
106 return 1;
107}
108
109static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700110clipboard_source_accept(struct weston_data_source *source,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400111 uint32_t time, const char *mime_type)
112{
113}
114
115static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700116clipboard_source_send(struct weston_data_source *base,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400117 const char *mime_type, int32_t fd)
118{
119 struct clipboard_source *source =
120 container_of(base, struct clipboard_source, base);
121 char **s;
122
123 s = source->base.mime_types.data;
124 if (strcmp(mime_type, s[0]) == 0)
125 clipboard_client_create(source, fd);
126 else
127 close(fd);
128}
129
130static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700131clipboard_source_cancel(struct weston_data_source *source)
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400132{
133}
134
135static struct clipboard_source *
136clipboard_source_create(struct clipboard *clipboard,
137 const char *mime_type, uint32_t serial, int fd)
138{
139 struct wl_display *display = clipboard->seat->compositor->wl_display;
140 struct wl_event_loop *loop = wl_display_get_event_loop(display);
141 struct clipboard_source *source;
142 char **s;
143
Carlos Garnacho15902bf2016-02-01 20:28:14 +0100144 source = zalloc(sizeof *source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700145 if (source == NULL)
146 return NULL;
147
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400148 wl_array_init(&source->contents);
149 wl_array_init(&source->base.mime_types);
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500150 source->base.resource = NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400151 source->base.accept = clipboard_source_accept;
152 source->base.send = clipboard_source_send;
153 source->base.cancel = clipboard_source_cancel;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500154 wl_signal_init(&source->base.destroy_signal);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400155 source->refcount = 1;
156 source->clipboard = clipboard;
157 source->serial = serial;
Marek Chalupa389a10d2014-12-10 12:07:58 +0100158 source->fd = fd;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400159
160 s = wl_array_add(&source->base.mime_types, sizeof *s);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700161 if (s == NULL)
162 goto err_add;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400163 *s = strdup(mime_type);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700164 if (*s == NULL)
165 goto err_strdup;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400166 source->event_source =
167 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
168 clipboard_source_data, source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700169 if (source->event_source == NULL)
170 goto err_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400171
172 return source;
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700173
174 err_source:
175 free(*s);
176 err_strdup:
177 wl_array_release(&source->base.mime_types);
178 err_add:
179 free(source);
180
181 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400182}
183
184struct clipboard_client {
185 struct wl_event_source *event_source;
186 size_t offset;
187 struct clipboard_source *source;
188};
189
190static int
191clipboard_client_data(int fd, uint32_t mask, void *data)
192{
193 struct clipboard_client *client = data;
194 char *p;
195 size_t size;
196 int len;
197
198 size = client->source->contents.size;
199 p = client->source->contents.data;
200 len = write(fd, p + client->offset, size - client->offset);
201 if (len > 0)
202 client->offset += len;
203
204 if (client->offset == size || len <= 0) {
205 close(fd);
206 wl_event_source_remove(client->event_source);
207 clipboard_source_unref(client->source);
208 free(client);
209 }
210
211 return 1;
212}
213
214static void
215clipboard_client_create(struct clipboard_source *source, int fd)
216{
217 struct weston_seat *seat = source->clipboard->seat;
218 struct clipboard_client *client;
219 struct wl_event_loop *loop =
220 wl_display_get_event_loop(seat->compositor->wl_display);
221
Bryce Harringtonde447612014-11-20 22:21:55 -0800222 client = zalloc(sizeof *client);
223 if (client == NULL)
224 return;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400225
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400226 client->source = source;
227 source->refcount++;
228 client->event_source =
229 wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
230 clipboard_client_data, client);
231}
232
233static void
234clipboard_set_selection(struct wl_listener *listener, void *data)
235{
236 struct clipboard *clipboard =
237 container_of(listener, struct clipboard, selection_listener);
238 struct weston_seat *seat = data;
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700239 struct weston_data_source *source = seat->selection_data_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400240 const char **mime_types;
241 int p[2];
242
243 if (source == NULL) {
244 if (clipboard->source)
Kristian Høgsberge3148752013-05-06 23:19:49 -0400245 weston_seat_set_selection(seat,
246 &clipboard->source->base,
247 clipboard->source->serial);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400248 return;
249 } else if (source->accept == clipboard_source_accept) {
250 /* Callback for our data source. */
251 return;
252 }
253
254 if (clipboard->source)
255 clipboard_source_unref(clipboard->source);
256
257 clipboard->source = NULL;
258
259 mime_types = source->mime_types.data;
260
Giulio Camuffo6a94a992015-05-01 00:13:55 +0300261 if (!mime_types || pipe2(p, O_CLOEXEC) == -1)
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400262 return;
263
264 source->send(source, mime_types[0], p[1]);
265
266 clipboard->source =
267 clipboard_source_create(clipboard, mime_types[0],
Kristian Høgsberge3148752013-05-06 23:19:49 -0400268 seat->selection_serial, p[0]);
Kristian Høgsberg46118f82013-07-25 16:21:41 -0700269 if (clipboard->source == NULL) {
270 close(p[0]);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400271 return;
Kristian Høgsberg46118f82013-07-25 16:21:41 -0700272 }
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400273}
274
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200275static void
276clipboard_destroy(struct wl_listener *listener, void *data)
277{
278 struct clipboard *clipboard =
279 container_of(listener, struct clipboard, destroy_listener);
280
281 wl_list_remove(&clipboard->selection_listener.link);
Rob Bradfordc30c4bd2013-07-24 16:57:33 +0100282 wl_list_remove(&clipboard->destroy_listener.link);
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200283
284 free(clipboard);
285}
286
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400287struct clipboard *
288clipboard_create(struct weston_seat *seat)
289{
290 struct clipboard *clipboard;
291
Peter Huttererf3d62272013-08-08 11:57:05 +1000292 clipboard = zalloc(sizeof *clipboard);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400293 if (clipboard == NULL)
294 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400295
296 clipboard->seat = seat;
297 clipboard->selection_listener.notify = clipboard_set_selection;
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200298 clipboard->destroy_listener.notify = clipboard_destroy;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400299
Kristian Høgsberge3148752013-05-06 23:19:49 -0400300 wl_signal_add(&seat->selection_signal,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400301 &clipboard->selection_listener);
Kristian Høgsberg49124542013-05-06 22:27:40 -0400302 wl_signal_add(&seat->destroy_signal,
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200303 &clipboard->destroy_listener);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400304
305 return clipboard;
306}