blob: c1091a9c44faf978401dc8705c3fa128cc8ac726 [file] [log] [blame]
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -04001/*
2 * Copyright © 2012 Intel Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
Daniel Stonec228e232013-05-22 18:03:19 +030023#include "config.h"
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040024
25#include <stdlib.h>
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040026#include <string.h>
27#include <linux/input.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <sys/uio.h>
31
32#include "compositor.h"
33
34struct clipboard_source {
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -070035 struct weston_data_source base;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040036 struct wl_array contents;
37 struct clipboard *clipboard;
38 struct wl_event_source *event_source;
39 uint32_t serial;
40 int refcount;
Kristian Høgsberg46118f82013-07-25 16:21:41 -070041 int fd;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040042};
43
44struct clipboard {
45 struct weston_seat *seat;
46 struct wl_listener selection_listener;
47 struct wl_listener destroy_listener;
48 struct clipboard_source *source;
49};
50
51static void clipboard_client_create(struct clipboard_source *source, int fd);
52
53static void
54clipboard_source_unref(struct clipboard_source *source)
55{
56 char **s;
57
58 source->refcount--;
59 if (source->refcount > 0)
60 return;
61
Kristian Høgsberg46118f82013-07-25 16:21:41 -070062 if (source->event_source) {
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040063 wl_event_source_remove(source->event_source);
Kristian Høgsberg46118f82013-07-25 16:21:41 -070064 close(source->fd);
65 }
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -050066 wl_signal_emit(&source->base.destroy_signal,
67 &source->base);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040068 s = source->base.mime_types.data;
69 free(*s);
70 wl_array_release(&source->base.mime_types);
71 wl_array_release(&source->contents);
72 free(source);
73}
74
75static int
76clipboard_source_data(int fd, uint32_t mask, void *data)
77{
78 struct clipboard_source *source = data;
79 struct clipboard *clipboard = source->clipboard;
80 char *p;
81 int len, size;
82
83 if (source->contents.alloc - source->contents.size < 1024) {
84 wl_array_add(&source->contents, 1024);
85 source->contents.size -= 1024;
86 }
87
88 p = source->contents.data + source->contents.size;
89 size = source->contents.alloc - source->contents.size;
90 len = read(fd, p, size);
91 if (len == 0) {
92 wl_event_source_remove(source->event_source);
Kristian Høgsberg46118f82013-07-25 16:21:41 -070093 close(fd);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040094 source->event_source = NULL;
95 } else if (len < 0) {
96 clipboard_source_unref(source);
97 clipboard->source = NULL;
98 } else {
99 source->contents.size += len;
100 }
101
102 return 1;
103}
104
105static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700106clipboard_source_accept(struct weston_data_source *source,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400107 uint32_t time, const char *mime_type)
108{
109}
110
111static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700112clipboard_source_send(struct weston_data_source *base,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400113 const char *mime_type, int32_t fd)
114{
115 struct clipboard_source *source =
116 container_of(base, struct clipboard_source, base);
117 char **s;
118
119 s = source->base.mime_types.data;
120 if (strcmp(mime_type, s[0]) == 0)
121 clipboard_client_create(source, fd);
122 else
123 close(fd);
124}
125
126static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700127clipboard_source_cancel(struct weston_data_source *source)
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400128{
129}
130
131static struct clipboard_source *
132clipboard_source_create(struct clipboard *clipboard,
133 const char *mime_type, uint32_t serial, int fd)
134{
135 struct wl_display *display = clipboard->seat->compositor->wl_display;
136 struct wl_event_loop *loop = wl_display_get_event_loop(display);
137 struct clipboard_source *source;
138 char **s;
139
140 source = malloc(sizeof *source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700141 if (source == NULL)
142 return NULL;
143
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400144 wl_array_init(&source->contents);
145 wl_array_init(&source->base.mime_types);
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500146 source->base.resource = NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400147 source->base.accept = clipboard_source_accept;
148 source->base.send = clipboard_source_send;
149 source->base.cancel = clipboard_source_cancel;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500150 wl_signal_init(&source->base.destroy_signal);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400151 source->refcount = 1;
152 source->clipboard = clipboard;
153 source->serial = serial;
Marek Chalupa389a10d2014-12-10 12:07:58 +0100154 source->fd = fd;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400155
156 s = wl_array_add(&source->base.mime_types, sizeof *s);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700157 if (s == NULL)
158 goto err_add;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400159 *s = strdup(mime_type);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700160 if (*s == NULL)
161 goto err_strdup;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400162 source->event_source =
163 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
164 clipboard_source_data, source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700165 if (source->event_source == NULL)
166 goto err_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400167
168 return source;
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700169
170 err_source:
171 free(*s);
172 err_strdup:
173 wl_array_release(&source->base.mime_types);
174 err_add:
175 free(source);
176
177 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400178}
179
180struct clipboard_client {
181 struct wl_event_source *event_source;
182 size_t offset;
183 struct clipboard_source *source;
184};
185
186static int
187clipboard_client_data(int fd, uint32_t mask, void *data)
188{
189 struct clipboard_client *client = data;
190 char *p;
191 size_t size;
192 int len;
193
194 size = client->source->contents.size;
195 p = client->source->contents.data;
196 len = write(fd, p + client->offset, size - client->offset);
197 if (len > 0)
198 client->offset += len;
199
200 if (client->offset == size || len <= 0) {
201 close(fd);
202 wl_event_source_remove(client->event_source);
203 clipboard_source_unref(client->source);
204 free(client);
205 }
206
207 return 1;
208}
209
210static void
211clipboard_client_create(struct clipboard_source *source, int fd)
212{
213 struct weston_seat *seat = source->clipboard->seat;
214 struct clipboard_client *client;
215 struct wl_event_loop *loop =
216 wl_display_get_event_loop(seat->compositor->wl_display);
217
Bryce Harringtonde447612014-11-20 22:21:55 -0800218 client = zalloc(sizeof *client);
219 if (client == NULL)
220 return;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400221
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400222 client->source = source;
223 source->refcount++;
224 client->event_source =
225 wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
226 clipboard_client_data, client);
227}
228
229static void
230clipboard_set_selection(struct wl_listener *listener, void *data)
231{
232 struct clipboard *clipboard =
233 container_of(listener, struct clipboard, selection_listener);
234 struct weston_seat *seat = data;
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700235 struct weston_data_source *source = seat->selection_data_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400236 const char **mime_types;
237 int p[2];
238
239 if (source == NULL) {
240 if (clipboard->source)
Kristian Høgsberge3148752013-05-06 23:19:49 -0400241 weston_seat_set_selection(seat,
242 &clipboard->source->base,
243 clipboard->source->serial);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400244 return;
245 } else if (source->accept == clipboard_source_accept) {
246 /* Callback for our data source. */
247 return;
248 }
249
250 if (clipboard->source)
251 clipboard_source_unref(clipboard->source);
252
253 clipboard->source = NULL;
254
255 mime_types = source->mime_types.data;
256
257 if (pipe2(p, O_CLOEXEC) == -1)
258 return;
259
260 source->send(source, mime_types[0], p[1]);
261
262 clipboard->source =
263 clipboard_source_create(clipboard, mime_types[0],
Kristian Høgsberge3148752013-05-06 23:19:49 -0400264 seat->selection_serial, p[0]);
Kristian Høgsberg46118f82013-07-25 16:21:41 -0700265 if (clipboard->source == NULL) {
266 close(p[0]);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400267 return;
Kristian Høgsberg46118f82013-07-25 16:21:41 -0700268 }
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400269}
270
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200271static void
272clipboard_destroy(struct wl_listener *listener, void *data)
273{
274 struct clipboard *clipboard =
275 container_of(listener, struct clipboard, destroy_listener);
276
277 wl_list_remove(&clipboard->selection_listener.link);
Rob Bradfordc30c4bd2013-07-24 16:57:33 +0100278 wl_list_remove(&clipboard->destroy_listener.link);
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200279
280 free(clipboard);
281}
282
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400283struct clipboard *
284clipboard_create(struct weston_seat *seat)
285{
286 struct clipboard *clipboard;
287
Peter Huttererf3d62272013-08-08 11:57:05 +1000288 clipboard = zalloc(sizeof *clipboard);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400289 if (clipboard == NULL)
290 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400291
292 clipboard->seat = seat;
293 clipboard->selection_listener.notify = clipboard_set_selection;
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200294 clipboard->destroy_listener.notify = clipboard_destroy;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400295
Kristian Høgsberge3148752013-05-06 23:19:49 -0400296 wl_signal_add(&seat->selection_signal,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400297 &clipboard->selection_listener);
Kristian Høgsberg49124542013-05-06 22:27:40 -0400298 wl_signal_add(&seat->destroy_signal,
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200299 &clipboard->destroy_listener);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400300
301 return clipboard;
302}