blob: f37508cbd7971b5127dcae322876dccabde38970 [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
36#include "compositor.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070037#include "shared/helpers.h"
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040038
39struct clipboard_source {
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -070040 struct weston_data_source base;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040041 struct wl_array contents;
42 struct clipboard *clipboard;
43 struct wl_event_source *event_source;
44 uint32_t serial;
45 int refcount;
Kristian Høgsberg46118f82013-07-25 16:21:41 -070046 int fd;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040047};
48
49struct clipboard {
50 struct weston_seat *seat;
51 struct wl_listener selection_listener;
52 struct wl_listener destroy_listener;
53 struct clipboard_source *source;
54};
55
56static void clipboard_client_create(struct clipboard_source *source, int fd);
57
58static void
59clipboard_source_unref(struct clipboard_source *source)
60{
61 char **s;
62
63 source->refcount--;
64 if (source->refcount > 0)
65 return;
66
Kristian Høgsberg46118f82013-07-25 16:21:41 -070067 if (source->event_source) {
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040068 wl_event_source_remove(source->event_source);
Kristian Høgsberg46118f82013-07-25 16:21:41 -070069 close(source->fd);
70 }
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -050071 wl_signal_emit(&source->base.destroy_signal,
72 &source->base);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040073 s = source->base.mime_types.data;
74 free(*s);
75 wl_array_release(&source->base.mime_types);
76 wl_array_release(&source->contents);
77 free(source);
78}
79
80static int
81clipboard_source_data(int fd, uint32_t mask, void *data)
82{
83 struct clipboard_source *source = data;
84 struct clipboard *clipboard = source->clipboard;
85 char *p;
86 int len, size;
87
88 if (source->contents.alloc - source->contents.size < 1024) {
89 wl_array_add(&source->contents, 1024);
90 source->contents.size -= 1024;
91 }
92
93 p = source->contents.data + source->contents.size;
94 size = source->contents.alloc - source->contents.size;
95 len = read(fd, p, size);
96 if (len == 0) {
97 wl_event_source_remove(source->event_source);
Kristian Høgsberg46118f82013-07-25 16:21:41 -070098 close(fd);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040099 source->event_source = NULL;
100 } else if (len < 0) {
101 clipboard_source_unref(source);
102 clipboard->source = NULL;
103 } else {
104 source->contents.size += len;
105 }
106
107 return 1;
108}
109
110static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700111clipboard_source_accept(struct weston_data_source *source,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400112 uint32_t time, const char *mime_type)
113{
114}
115
116static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700117clipboard_source_send(struct weston_data_source *base,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400118 const char *mime_type, int32_t fd)
119{
120 struct clipboard_source *source =
121 container_of(base, struct clipboard_source, base);
122 char **s;
123
124 s = source->base.mime_types.data;
125 if (strcmp(mime_type, s[0]) == 0)
126 clipboard_client_create(source, fd);
127 else
128 close(fd);
129}
130
131static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700132clipboard_source_cancel(struct weston_data_source *source)
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400133{
134}
135
136static struct clipboard_source *
137clipboard_source_create(struct clipboard *clipboard,
138 const char *mime_type, uint32_t serial, int fd)
139{
140 struct wl_display *display = clipboard->seat->compositor->wl_display;
141 struct wl_event_loop *loop = wl_display_get_event_loop(display);
142 struct clipboard_source *source;
143 char **s;
144
Carlos Garnacho15902bf2016-02-01 20:28:14 +0100145 source = zalloc(sizeof *source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700146 if (source == NULL)
147 return NULL;
148
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400149 wl_array_init(&source->contents);
150 wl_array_init(&source->base.mime_types);
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500151 source->base.resource = NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400152 source->base.accept = clipboard_source_accept;
153 source->base.send = clipboard_source_send;
154 source->base.cancel = clipboard_source_cancel;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500155 wl_signal_init(&source->base.destroy_signal);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400156 source->refcount = 1;
157 source->clipboard = clipboard;
158 source->serial = serial;
Marek Chalupa389a10d2014-12-10 12:07:58 +0100159 source->fd = fd;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400160
161 s = wl_array_add(&source->base.mime_types, sizeof *s);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700162 if (s == NULL)
163 goto err_add;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400164 *s = strdup(mime_type);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700165 if (*s == NULL)
166 goto err_strdup;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400167 source->event_source =
168 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
169 clipboard_source_data, source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700170 if (source->event_source == NULL)
171 goto err_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400172
173 return source;
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700174
175 err_source:
176 free(*s);
177 err_strdup:
178 wl_array_release(&source->base.mime_types);
179 err_add:
180 free(source);
181
182 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400183}
184
185struct clipboard_client {
186 struct wl_event_source *event_source;
187 size_t offset;
188 struct clipboard_source *source;
189};
190
191static int
192clipboard_client_data(int fd, uint32_t mask, void *data)
193{
194 struct clipboard_client *client = data;
195 char *p;
196 size_t size;
197 int len;
198
199 size = client->source->contents.size;
200 p = client->source->contents.data;
201 len = write(fd, p + client->offset, size - client->offset);
202 if (len > 0)
203 client->offset += len;
204
205 if (client->offset == size || len <= 0) {
206 close(fd);
207 wl_event_source_remove(client->event_source);
208 clipboard_source_unref(client->source);
209 free(client);
210 }
211
212 return 1;
213}
214
215static void
216clipboard_client_create(struct clipboard_source *source, int fd)
217{
218 struct weston_seat *seat = source->clipboard->seat;
219 struct clipboard_client *client;
220 struct wl_event_loop *loop =
221 wl_display_get_event_loop(seat->compositor->wl_display);
222
Bryce Harringtonde447612014-11-20 22:21:55 -0800223 client = zalloc(sizeof *client);
224 if (client == NULL)
225 return;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400226
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400227 client->source = source;
228 source->refcount++;
229 client->event_source =
230 wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
231 clipboard_client_data, client);
232}
233
234static void
235clipboard_set_selection(struct wl_listener *listener, void *data)
236{
237 struct clipboard *clipboard =
238 container_of(listener, struct clipboard, selection_listener);
239 struct weston_seat *seat = data;
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700240 struct weston_data_source *source = seat->selection_data_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400241 const char **mime_types;
242 int p[2];
243
244 if (source == NULL) {
245 if (clipboard->source)
Kristian Høgsberge3148752013-05-06 23:19:49 -0400246 weston_seat_set_selection(seat,
247 &clipboard->source->base,
248 clipboard->source->serial);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400249 return;
250 } else if (source->accept == clipboard_source_accept) {
251 /* Callback for our data source. */
252 return;
253 }
254
255 if (clipboard->source)
256 clipboard_source_unref(clipboard->source);
257
258 clipboard->source = NULL;
259
260 mime_types = source->mime_types.data;
261
Giulio Camuffo6a94a992015-05-01 00:13:55 +0300262 if (!mime_types || pipe2(p, O_CLOEXEC) == -1)
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400263 return;
264
265 source->send(source, mime_types[0], p[1]);
266
267 clipboard->source =
268 clipboard_source_create(clipboard, mime_types[0],
Kristian Høgsberge3148752013-05-06 23:19:49 -0400269 seat->selection_serial, p[0]);
Kristian Høgsberg46118f82013-07-25 16:21:41 -0700270 if (clipboard->source == NULL) {
271 close(p[0]);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400272 return;
Kristian Høgsberg46118f82013-07-25 16:21:41 -0700273 }
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400274}
275
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200276static void
277clipboard_destroy(struct wl_listener *listener, void *data)
278{
279 struct clipboard *clipboard =
280 container_of(listener, struct clipboard, destroy_listener);
281
282 wl_list_remove(&clipboard->selection_listener.link);
Rob Bradfordc30c4bd2013-07-24 16:57:33 +0100283 wl_list_remove(&clipboard->destroy_listener.link);
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200284
285 free(clipboard);
286}
287
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400288struct clipboard *
289clipboard_create(struct weston_seat *seat)
290{
291 struct clipboard *clipboard;
292
Peter Huttererf3d62272013-08-08 11:57:05 +1000293 clipboard = zalloc(sizeof *clipboard);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400294 if (clipboard == NULL)
295 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400296
297 clipboard->seat = seat;
298 clipboard->selection_listener.notify = clipboard_set_selection;
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200299 clipboard->destroy_listener.notify = clipboard_destroy;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400300
Kristian Høgsberge3148752013-05-06 23:19:49 -0400301 wl_signal_add(&seat->selection_signal,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400302 &clipboard->selection_listener);
Kristian Høgsberg49124542013-05-06 22:27:40 -0400303 wl_signal_add(&seat->destroy_signal,
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200304 &clipboard->destroy_listener);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400305
306 return clipboard;
307}