blob: 023cd411fcdfd4d006b0ceb1d90f3ae16aeea747 [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"
36
37struct clipboard_source {
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -070038 struct weston_data_source base;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040039 struct wl_array contents;
40 struct clipboard *clipboard;
41 struct wl_event_source *event_source;
42 uint32_t serial;
43 int refcount;
Kristian Høgsberg46118f82013-07-25 16:21:41 -070044 int fd;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040045};
46
47struct clipboard {
48 struct weston_seat *seat;
49 struct wl_listener selection_listener;
50 struct wl_listener destroy_listener;
51 struct clipboard_source *source;
52};
53
54static void clipboard_client_create(struct clipboard_source *source, int fd);
55
56static void
57clipboard_source_unref(struct clipboard_source *source)
58{
59 char **s;
60
61 source->refcount--;
62 if (source->refcount > 0)
63 return;
64
Kristian Høgsberg46118f82013-07-25 16:21:41 -070065 if (source->event_source) {
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040066 wl_event_source_remove(source->event_source);
Kristian Høgsberg46118f82013-07-25 16:21:41 -070067 close(source->fd);
68 }
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -050069 wl_signal_emit(&source->base.destroy_signal,
70 &source->base);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040071 s = source->base.mime_types.data;
72 free(*s);
73 wl_array_release(&source->base.mime_types);
74 wl_array_release(&source->contents);
75 free(source);
76}
77
78static int
79clipboard_source_data(int fd, uint32_t mask, void *data)
80{
81 struct clipboard_source *source = data;
82 struct clipboard *clipboard = source->clipboard;
83 char *p;
84 int len, size;
85
86 if (source->contents.alloc - source->contents.size < 1024) {
87 wl_array_add(&source->contents, 1024);
88 source->contents.size -= 1024;
89 }
90
91 p = source->contents.data + source->contents.size;
92 size = source->contents.alloc - source->contents.size;
93 len = read(fd, p, size);
94 if (len == 0) {
95 wl_event_source_remove(source->event_source);
Kristian Høgsberg46118f82013-07-25 16:21:41 -070096 close(fd);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040097 source->event_source = NULL;
98 } else if (len < 0) {
99 clipboard_source_unref(source);
100 clipboard->source = NULL;
101 } else {
102 source->contents.size += len;
103 }
104
105 return 1;
106}
107
108static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700109clipboard_source_accept(struct weston_data_source *source,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400110 uint32_t time, const char *mime_type)
111{
112}
113
114static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700115clipboard_source_send(struct weston_data_source *base,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400116 const char *mime_type, int32_t fd)
117{
118 struct clipboard_source *source =
119 container_of(base, struct clipboard_source, base);
120 char **s;
121
122 s = source->base.mime_types.data;
123 if (strcmp(mime_type, s[0]) == 0)
124 clipboard_client_create(source, fd);
125 else
126 close(fd);
127}
128
129static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700130clipboard_source_cancel(struct weston_data_source *source)
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400131{
132}
133
134static struct clipboard_source *
135clipboard_source_create(struct clipboard *clipboard,
136 const char *mime_type, uint32_t serial, int fd)
137{
138 struct wl_display *display = clipboard->seat->compositor->wl_display;
139 struct wl_event_loop *loop = wl_display_get_event_loop(display);
140 struct clipboard_source *source;
141 char **s;
142
143 source = malloc(sizeof *source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700144 if (source == NULL)
145 return NULL;
146
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400147 wl_array_init(&source->contents);
148 wl_array_init(&source->base.mime_types);
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500149 source->base.resource = NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400150 source->base.accept = clipboard_source_accept;
151 source->base.send = clipboard_source_send;
152 source->base.cancel = clipboard_source_cancel;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500153 wl_signal_init(&source->base.destroy_signal);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400154 source->refcount = 1;
155 source->clipboard = clipboard;
156 source->serial = serial;
Marek Chalupa389a10d2014-12-10 12:07:58 +0100157 source->fd = fd;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400158
159 s = wl_array_add(&source->base.mime_types, sizeof *s);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700160 if (s == NULL)
161 goto err_add;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400162 *s = strdup(mime_type);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700163 if (*s == NULL)
164 goto err_strdup;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400165 source->event_source =
166 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
167 clipboard_source_data, source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700168 if (source->event_source == NULL)
169 goto err_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400170
171 return source;
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700172
173 err_source:
174 free(*s);
175 err_strdup:
176 wl_array_release(&source->base.mime_types);
177 err_add:
178 free(source);
179
180 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400181}
182
183struct clipboard_client {
184 struct wl_event_source *event_source;
185 size_t offset;
186 struct clipboard_source *source;
187};
188
189static int
190clipboard_client_data(int fd, uint32_t mask, void *data)
191{
192 struct clipboard_client *client = data;
193 char *p;
194 size_t size;
195 int len;
196
197 size = client->source->contents.size;
198 p = client->source->contents.data;
199 len = write(fd, p + client->offset, size - client->offset);
200 if (len > 0)
201 client->offset += len;
202
203 if (client->offset == size || len <= 0) {
204 close(fd);
205 wl_event_source_remove(client->event_source);
206 clipboard_source_unref(client->source);
207 free(client);
208 }
209
210 return 1;
211}
212
213static void
214clipboard_client_create(struct clipboard_source *source, int fd)
215{
216 struct weston_seat *seat = source->clipboard->seat;
217 struct clipboard_client *client;
218 struct wl_event_loop *loop =
219 wl_display_get_event_loop(seat->compositor->wl_display);
220
Bryce Harringtonde447612014-11-20 22:21:55 -0800221 client = zalloc(sizeof *client);
222 if (client == NULL)
223 return;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400224
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400225 client->source = source;
226 source->refcount++;
227 client->event_source =
228 wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
229 clipboard_client_data, client);
230}
231
232static void
233clipboard_set_selection(struct wl_listener *listener, void *data)
234{
235 struct clipboard *clipboard =
236 container_of(listener, struct clipboard, selection_listener);
237 struct weston_seat *seat = data;
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700238 struct weston_data_source *source = seat->selection_data_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400239 const char **mime_types;
240 int p[2];
241
242 if (source == NULL) {
243 if (clipboard->source)
Kristian Høgsberge3148752013-05-06 23:19:49 -0400244 weston_seat_set_selection(seat,
245 &clipboard->source->base,
246 clipboard->source->serial);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400247 return;
248 } else if (source->accept == clipboard_source_accept) {
249 /* Callback for our data source. */
250 return;
251 }
252
253 if (clipboard->source)
254 clipboard_source_unref(clipboard->source);
255
256 clipboard->source = NULL;
257
258 mime_types = source->mime_types.data;
259
Giulio Camuffo6a94a992015-05-01 00:13:55 +0300260 if (!mime_types || pipe2(p, O_CLOEXEC) == -1)
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400261 return;
262
263 source->send(source, mime_types[0], p[1]);
264
265 clipboard->source =
266 clipboard_source_create(clipboard, mime_types[0],
Kristian Høgsberge3148752013-05-06 23:19:49 -0400267 seat->selection_serial, p[0]);
Kristian Høgsberg46118f82013-07-25 16:21:41 -0700268 if (clipboard->source == NULL) {
269 close(p[0]);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400270 return;
Kristian Høgsberg46118f82013-07-25 16:21:41 -0700271 }
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400272}
273
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200274static void
275clipboard_destroy(struct wl_listener *listener, void *data)
276{
277 struct clipboard *clipboard =
278 container_of(listener, struct clipboard, destroy_listener);
279
280 wl_list_remove(&clipboard->selection_listener.link);
Rob Bradfordc30c4bd2013-07-24 16:57:33 +0100281 wl_list_remove(&clipboard->destroy_listener.link);
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200282
283 free(clipboard);
284}
285
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400286struct clipboard *
287clipboard_create(struct weston_seat *seat)
288{
289 struct clipboard *clipboard;
290
Peter Huttererf3d62272013-08-08 11:57:05 +1000291 clipboard = zalloc(sizeof *clipboard);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400292 if (clipboard == NULL)
293 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400294
295 clipboard->seat = seat;
296 clipboard->selection_listener.notify = clipboard_set_selection;
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200297 clipboard->destroy_listener.notify = clipboard_destroy;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400298
Kristian Høgsberge3148752013-05-06 23:19:49 -0400299 wl_signal_add(&seat->selection_signal,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400300 &clipboard->selection_listener);
Kristian Høgsberg49124542013-05-06 22:27:40 -0400301 wl_signal_add(&seat->destroy_signal,
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200302 &clipboard->destroy_listener);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400303
304 return clipboard;
305}