blob: 81b7b19bec588ad5a2592dc8c2f2a73dbf08cd8e [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;
41};
42
43struct clipboard {
44 struct weston_seat *seat;
45 struct wl_listener selection_listener;
46 struct wl_listener destroy_listener;
47 struct clipboard_source *source;
48};
49
50static void clipboard_client_create(struct clipboard_source *source, int fd);
51
52static void
53clipboard_source_unref(struct clipboard_source *source)
54{
55 char **s;
56
57 source->refcount--;
58 if (source->refcount > 0)
59 return;
60
61 if (source->event_source)
62 wl_event_source_remove(source->event_source);
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -050063 wl_signal_emit(&source->base.destroy_signal,
64 &source->base);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -040065 s = source->base.mime_types.data;
66 free(*s);
67 wl_array_release(&source->base.mime_types);
68 wl_array_release(&source->contents);
69 free(source);
70}
71
72static int
73clipboard_source_data(int fd, uint32_t mask, void *data)
74{
75 struct clipboard_source *source = data;
76 struct clipboard *clipboard = source->clipboard;
77 char *p;
78 int len, size;
79
80 if (source->contents.alloc - source->contents.size < 1024) {
81 wl_array_add(&source->contents, 1024);
82 source->contents.size -= 1024;
83 }
84
85 p = source->contents.data + source->contents.size;
86 size = source->contents.alloc - source->contents.size;
87 len = read(fd, p, size);
88 if (len == 0) {
89 wl_event_source_remove(source->event_source);
90 source->event_source = NULL;
91 } else if (len < 0) {
92 clipboard_source_unref(source);
93 clipboard->source = NULL;
94 } else {
95 source->contents.size += len;
96 }
97
98 return 1;
99}
100
101static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700102clipboard_source_accept(struct weston_data_source *source,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400103 uint32_t time, const char *mime_type)
104{
105}
106
107static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700108clipboard_source_send(struct weston_data_source *base,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400109 const char *mime_type, int32_t fd)
110{
111 struct clipboard_source *source =
112 container_of(base, struct clipboard_source, base);
113 char **s;
114
115 s = source->base.mime_types.data;
116 if (strcmp(mime_type, s[0]) == 0)
117 clipboard_client_create(source, fd);
118 else
119 close(fd);
120}
121
122static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700123clipboard_source_cancel(struct weston_data_source *source)
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400124{
125}
126
127static struct clipboard_source *
128clipboard_source_create(struct clipboard *clipboard,
129 const char *mime_type, uint32_t serial, int fd)
130{
131 struct wl_display *display = clipboard->seat->compositor->wl_display;
132 struct wl_event_loop *loop = wl_display_get_event_loop(display);
133 struct clipboard_source *source;
134 char **s;
135
136 source = malloc(sizeof *source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700137 if (source == NULL)
138 return NULL;
139
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400140 wl_array_init(&source->contents);
141 wl_array_init(&source->base.mime_types);
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500142 source->base.resource = NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400143 source->base.accept = clipboard_source_accept;
144 source->base.send = clipboard_source_send;
145 source->base.cancel = clipboard_source_cancel;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500146 wl_signal_init(&source->base.destroy_signal);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400147 source->refcount = 1;
148 source->clipboard = clipboard;
149 source->serial = serial;
150
151 s = wl_array_add(&source->base.mime_types, sizeof *s);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700152 if (s == NULL)
153 goto err_add;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400154 *s = strdup(mime_type);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700155 if (*s == NULL)
156 goto err_strdup;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400157 source->event_source =
158 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
159 clipboard_source_data, source);
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700160 if (source->event_source == NULL)
161 goto err_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400162
163 return source;
Kristian Høgsberg862814b2013-07-25 15:32:55 -0700164
165 err_source:
166 free(*s);
167 err_strdup:
168 wl_array_release(&source->base.mime_types);
169 err_add:
170 free(source);
171
172 return NULL;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400173}
174
175struct clipboard_client {
176 struct wl_event_source *event_source;
177 size_t offset;
178 struct clipboard_source *source;
179};
180
181static int
182clipboard_client_data(int fd, uint32_t mask, void *data)
183{
184 struct clipboard_client *client = data;
185 char *p;
186 size_t size;
187 int len;
188
189 size = client->source->contents.size;
190 p = client->source->contents.data;
191 len = write(fd, p + client->offset, size - client->offset);
192 if (len > 0)
193 client->offset += len;
194
195 if (client->offset == size || len <= 0) {
196 close(fd);
197 wl_event_source_remove(client->event_source);
198 clipboard_source_unref(client->source);
199 free(client);
200 }
201
202 return 1;
203}
204
205static void
206clipboard_client_create(struct clipboard_source *source, int fd)
207{
208 struct weston_seat *seat = source->clipboard->seat;
209 struct clipboard_client *client;
210 struct wl_event_loop *loop =
211 wl_display_get_event_loop(seat->compositor->wl_display);
212
213 client = malloc(sizeof *client);
214
215 client->offset = 0;
216 client->source = source;
217 source->refcount++;
218 client->event_source =
219 wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
220 clipboard_client_data, client);
221}
222
223static void
224clipboard_set_selection(struct wl_listener *listener, void *data)
225{
226 struct clipboard *clipboard =
227 container_of(listener, struct clipboard, selection_listener);
228 struct weston_seat *seat = data;
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700229 struct weston_data_source *source = seat->selection_data_source;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400230 const char **mime_types;
231 int p[2];
232
233 if (source == NULL) {
234 if (clipboard->source)
Kristian Høgsberge3148752013-05-06 23:19:49 -0400235 weston_seat_set_selection(seat,
236 &clipboard->source->base,
237 clipboard->source->serial);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400238 return;
239 } else if (source->accept == clipboard_source_accept) {
240 /* Callback for our data source. */
241 return;
242 }
243
244 if (clipboard->source)
245 clipboard_source_unref(clipboard->source);
246
247 clipboard->source = NULL;
248
249 mime_types = source->mime_types.data;
250
251 if (pipe2(p, O_CLOEXEC) == -1)
252 return;
253
254 source->send(source, mime_types[0], p[1]);
255
256 clipboard->source =
257 clipboard_source_create(clipboard, mime_types[0],
Kristian Høgsberge3148752013-05-06 23:19:49 -0400258 seat->selection_serial, p[0]);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400259 if (clipboard->source == NULL)
260 return;
261}
262
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200263static void
264clipboard_destroy(struct wl_listener *listener, void *data)
265{
266 struct clipboard *clipboard =
267 container_of(listener, struct clipboard, destroy_listener);
268
269 wl_list_remove(&clipboard->selection_listener.link);
270
271 free(clipboard);
272}
273
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400274struct clipboard *
275clipboard_create(struct weston_seat *seat)
276{
277 struct clipboard *clipboard;
278
279 clipboard = malloc(sizeof *clipboard);
280 if (clipboard == NULL)
281 return NULL;
Rafal Mielniczuk340a4342012-06-30 18:33:34 +0200282 memset(clipboard, 0, sizeof *clipboard);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400283
284 clipboard->seat = seat;
285 clipboard->selection_listener.notify = clipboard_set_selection;
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200286 clipboard->destroy_listener.notify = clipboard_destroy;
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400287
Kristian Høgsberge3148752013-05-06 23:19:49 -0400288 wl_signal_add(&seat->selection_signal,
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400289 &clipboard->selection_listener);
Kristian Høgsberg49124542013-05-06 22:27:40 -0400290 wl_signal_add(&seat->destroy_signal,
Rafal Mielniczuk96ddcb22012-07-11 18:48:12 +0200291 &clipboard->destroy_listener);
Kristian Høgsberga7ceaff2012-06-03 10:20:13 -0400292
293 return clipboard;
294}