• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2012 Intel Corporation
3  *
4  * 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:
11  *
12  * 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.
24  */
25 
26 #include "config.h"
27 
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <linux/input.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <sys/uio.h>
35 
36 #include <libweston/libweston.h>
37 #include "libweston-internal.h"
38 #include "shared/helpers.h"
39 
40 struct clipboard_source {
41 	struct weston_data_source base;
42 	struct wl_array contents;
43 	struct clipboard *clipboard;
44 	struct wl_event_source *event_source;
45 	uint32_t serial;
46 	int refcount;
47 	int fd;
48 };
49 
50 struct clipboard {
51 	struct weston_seat *seat;
52 	struct wl_listener selection_listener;
53 	struct wl_listener destroy_listener;
54 	struct clipboard_source *source;
55 };
56 
57 static void clipboard_client_create(struct clipboard_source *source, int fd);
58 
59 static void
clipboard_source_unref(struct clipboard_source * source)60 clipboard_source_unref(struct clipboard_source *source)
61 {
62 	char **s;
63 
64 	source->refcount--;
65 	if (source->refcount > 0)
66 		return;
67 
68 	if (source->event_source) {
69 		wl_event_source_remove(source->event_source);
70 		close(source->fd);
71 	}
72 	wl_signal_emit(&source->base.destroy_signal,
73 		       &source->base);
74 	s = source->base.mime_types.data;
75 	free(*s);
76 	wl_array_release(&source->base.mime_types);
77 	wl_array_release(&source->contents);
78 	free(source);
79 }
80 
81 static int
clipboard_source_data(int fd,uint32_t mask,void * data)82 clipboard_source_data(int fd, uint32_t mask, void *data)
83 {
84 	struct clipboard_source *source = data;
85 	struct clipboard *clipboard = source->clipboard;
86 	char *p;
87 	int len, size;
88 
89 	if (source->contents.alloc - source->contents.size < 1024) {
90 		wl_array_add(&source->contents, 1024);
91 		source->contents.size -= 1024;
92 	}
93 
94 	p = source->contents.data + source->contents.size;
95 	size = source->contents.alloc - source->contents.size;
96 	len = read(fd, p, size);
97 	if (len == 0) {
98 		wl_event_source_remove(source->event_source);
99 		close(fd);
100 		source->event_source = NULL;
101 	} else if (len < 0) {
102 		clipboard_source_unref(source);
103 		clipboard->source = NULL;
104 	} else {
105 		source->contents.size += len;
106 	}
107 
108 	return 1;
109 }
110 
111 static void
clipboard_source_accept(struct weston_data_source * source,uint32_t time,const char * mime_type)112 clipboard_source_accept(struct weston_data_source *source,
113 			uint32_t time, const char *mime_type)
114 {
115 }
116 
117 static void
clipboard_source_send(struct weston_data_source * base,const char * mime_type,int32_t fd)118 clipboard_source_send(struct weston_data_source *base,
119 		      const char *mime_type, int32_t fd)
120 {
121 	struct clipboard_source *source =
122 		container_of(base, struct clipboard_source, base);
123 	char **s;
124 
125 	s = source->base.mime_types.data;
126 	if (strcmp(mime_type, s[0]) == 0)
127 		clipboard_client_create(source, fd);
128 	else
129 		close(fd);
130 }
131 
132 static void
clipboard_source_cancel(struct weston_data_source * source)133 clipboard_source_cancel(struct weston_data_source *source)
134 {
135 }
136 
137 static struct clipboard_source *
clipboard_source_create(struct clipboard * clipboard,const char * mime_type,uint32_t serial,int fd)138 clipboard_source_create(struct clipboard *clipboard,
139 			const char *mime_type, uint32_t serial, int fd)
140 {
141 	struct wl_display *display = clipboard->seat->compositor->wl_display;
142 	struct wl_event_loop *loop = wl_display_get_event_loop(display);
143 	struct clipboard_source *source;
144 	char **s;
145 
146 	source = zalloc(sizeof *source);
147 	if (source == NULL)
148 		return NULL;
149 
150 	wl_array_init(&source->contents);
151 	wl_array_init(&source->base.mime_types);
152 	source->base.resource = NULL;
153 	source->base.accept = clipboard_source_accept;
154 	source->base.send = clipboard_source_send;
155 	source->base.cancel = clipboard_source_cancel;
156 	wl_signal_init(&source->base.destroy_signal);
157 	source->refcount = 1;
158 	source->clipboard = clipboard;
159 	source->serial = serial;
160 	source->fd = fd;
161 
162 	s = wl_array_add(&source->base.mime_types, sizeof *s);
163 	if (s == NULL)
164 		goto err_add;
165 	*s = strdup(mime_type);
166 	if (*s == NULL)
167 		goto err_strdup;
168 	source->event_source =
169 		wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
170 				     clipboard_source_data, source);
171 	if (source->event_source == NULL)
172 		goto err_source;
173 
174 	return source;
175 
176  err_source:
177 	free(*s);
178  err_strdup:
179 	wl_array_release(&source->base.mime_types);
180  err_add:
181 	free(source);
182 
183 	return NULL;
184 }
185 
186 struct clipboard_client {
187 	struct wl_event_source *event_source;
188 	size_t offset;
189 	struct clipboard_source *source;
190 };
191 
192 static int
clipboard_client_data(int fd,uint32_t mask,void * data)193 clipboard_client_data(int fd, uint32_t mask, void *data)
194 {
195 	struct clipboard_client *client = data;
196 	char *p;
197 	size_t size;
198 	int len;
199 
200 	size = client->source->contents.size;
201 	p = client->source->contents.data;
202 	len = write(fd, p + client->offset, size - client->offset);
203 	if (len > 0)
204 		client->offset += len;
205 
206 	if (client->offset == size || len <= 0) {
207 		close(fd);
208 		wl_event_source_remove(client->event_source);
209 		clipboard_source_unref(client->source);
210 		free(client);
211 	}
212 
213 	return 1;
214 }
215 
216 static void
clipboard_client_create(struct clipboard_source * source,int fd)217 clipboard_client_create(struct clipboard_source *source, int fd)
218 {
219 	struct weston_seat *seat = source->clipboard->seat;
220 	struct clipboard_client *client;
221 	struct wl_event_loop *loop =
222 		wl_display_get_event_loop(seat->compositor->wl_display);
223 
224 	client = zalloc(sizeof *client);
225 	if (client == NULL)
226 		return;
227 
228 	client->source = source;
229 	source->refcount++;
230 	client->event_source =
231 		wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
232 				     clipboard_client_data, client);
233 }
234 
235 static void
clipboard_set_selection(struct wl_listener * listener,void * data)236 clipboard_set_selection(struct wl_listener *listener, void *data)
237 {
238 	struct clipboard *clipboard =
239 		container_of(listener, struct clipboard, selection_listener);
240 	struct weston_seat *seat = data;
241 	struct weston_data_source *source = seat->selection_data_source;
242 	const char **mime_types;
243 	int p[2];
244 
245 	if (source == NULL) {
246 		if (clipboard->source)
247 			weston_seat_set_selection(seat,
248 						  &clipboard->source->base,
249 						  clipboard->source->serial);
250 		return;
251 	} else if (source->accept == clipboard_source_accept) {
252 		/* Callback for our data source. */
253 		return;
254 	}
255 
256 	if (clipboard->source)
257 		clipboard_source_unref(clipboard->source);
258 
259 	clipboard->source = NULL;
260 
261 	mime_types = source->mime_types.data;
262 
263 	if (!mime_types || pipe2(p, O_CLOEXEC) == -1)
264 		return;
265 
266 	source->send(source, mime_types[0], p[1]);
267 
268 	clipboard->source =
269 		clipboard_source_create(clipboard, mime_types[0],
270 					seat->selection_serial, p[0]);
271 	if (clipboard->source == NULL) {
272 		close(p[0]);
273 		return;
274 	}
275 }
276 
277 static void
clipboard_destroy(struct wl_listener * listener,void * data)278 clipboard_destroy(struct wl_listener *listener, void *data)
279 {
280 	struct clipboard *clipboard =
281 		container_of(listener, struct clipboard, destroy_listener);
282 
283 	wl_list_remove(&clipboard->selection_listener.link);
284 	wl_list_remove(&clipboard->destroy_listener.link);
285 
286 	free(clipboard);
287 }
288 
289 struct clipboard *
clipboard_create(struct weston_seat * seat)290 clipboard_create(struct weston_seat *seat)
291 {
292 	struct clipboard *clipboard;
293 
294 	clipboard = zalloc(sizeof *clipboard);
295 	if (clipboard == NULL)
296 		return NULL;
297 
298 	clipboard->seat = seat;
299 	clipboard->selection_listener.notify = clipboard_set_selection;
300 	clipboard->destroy_listener.notify = clipboard_destroy;
301 
302 	wl_signal_add(&seat->selection_signal,
303 		      &clipboard->selection_listener);
304 	wl_signal_add(&seat->destroy_signal,
305 		      &clipboard->destroy_listener);
306 
307 	return clipboard;
308 }
309