blob: f5caf418ebf78e7e80b980ef58ff2b8bc85b8b71 [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
23#define _GNU_SOURCE
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <linux/input.h>
29#include <fcntl.h>
30#include <unistd.h>
31#include <sys/uio.h>
32
33#include "compositor.h"
34
35struct clipboard_source {
36 struct wl_data_source base;
37 struct wl_array contents;
38 struct clipboard *clipboard;
39 struct wl_event_source *event_source;
40 uint32_t serial;
41 int refcount;
42};
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
62 if (source->event_source)
63 wl_event_source_remove(source->event_source);
64 wl_signal_emit(&source->base.resource.destroy_signal,
65 &source->base.resource);
66 s = source->base.mime_types.data;
67 free(*s);
68 wl_array_release(&source->base.mime_types);
69 wl_array_release(&source->contents);
70 free(source);
71}
72
73static int
74clipboard_source_data(int fd, uint32_t mask, void *data)
75{
76 struct clipboard_source *source = data;
77 struct clipboard *clipboard = source->clipboard;
78 char *p;
79 int len, size;
80
81 if (source->contents.alloc - source->contents.size < 1024) {
82 wl_array_add(&source->contents, 1024);
83 source->contents.size -= 1024;
84 }
85
86 p = source->contents.data + source->contents.size;
87 size = source->contents.alloc - source->contents.size;
88 len = read(fd, p, size);
89 if (len == 0) {
90 wl_event_source_remove(source->event_source);
91 source->event_source = NULL;
92 } else if (len < 0) {
93 clipboard_source_unref(source);
94 clipboard->source = NULL;
95 } else {
96 source->contents.size += len;
97 }
98
99 return 1;
100}
101
102static void
103clipboard_source_accept(struct wl_data_source *source,
104 uint32_t time, const char *mime_type)
105{
106}
107
108static void
109clipboard_source_send(struct wl_data_source *base,
110 const char *mime_type, int32_t fd)
111{
112 struct clipboard_source *source =
113 container_of(base, struct clipboard_source, base);
114 char **s;
115
116 s = source->base.mime_types.data;
117 if (strcmp(mime_type, s[0]) == 0)
118 clipboard_client_create(source, fd);
119 else
120 close(fd);
121}
122
123static void
124clipboard_source_cancel(struct wl_data_source *source)
125{
126}
127
128static struct clipboard_source *
129clipboard_source_create(struct clipboard *clipboard,
130 const char *mime_type, uint32_t serial, int fd)
131{
132 struct wl_display *display = clipboard->seat->compositor->wl_display;
133 struct wl_event_loop *loop = wl_display_get_event_loop(display);
134 struct clipboard_source *source;
135 char **s;
136
137 source = malloc(sizeof *source);
138 wl_array_init(&source->contents);
139 wl_array_init(&source->base.mime_types);
140 source->base.accept = clipboard_source_accept;
141 source->base.send = clipboard_source_send;
142 source->base.cancel = clipboard_source_cancel;
143 source->base.resource.data = &source->base;
144 wl_signal_init(&source->base.resource.destroy_signal);
145 source->refcount = 1;
146 source->clipboard = clipboard;
147 source->serial = serial;
148
149 s = wl_array_add(&source->base.mime_types, sizeof *s);
150 *s = strdup(mime_type);
151
152 source->event_source =
153 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
154 clipboard_source_data, source);
155
156 return source;
157}
158
159struct clipboard_client {
160 struct wl_event_source *event_source;
161 size_t offset;
162 struct clipboard_source *source;
163};
164
165static int
166clipboard_client_data(int fd, uint32_t mask, void *data)
167{
168 struct clipboard_client *client = data;
169 char *p;
170 size_t size;
171 int len;
172
173 size = client->source->contents.size;
174 p = client->source->contents.data;
175 len = write(fd, p + client->offset, size - client->offset);
176 if (len > 0)
177 client->offset += len;
178
179 if (client->offset == size || len <= 0) {
180 close(fd);
181 wl_event_source_remove(client->event_source);
182 clipboard_source_unref(client->source);
183 free(client);
184 }
185
186 return 1;
187}
188
189static void
190clipboard_client_create(struct clipboard_source *source, int fd)
191{
192 struct weston_seat *seat = source->clipboard->seat;
193 struct clipboard_client *client;
194 struct wl_event_loop *loop =
195 wl_display_get_event_loop(seat->compositor->wl_display);
196
197 client = malloc(sizeof *client);
198
199 client->offset = 0;
200 client->source = source;
201 source->refcount++;
202 client->event_source =
203 wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
204 clipboard_client_data, client);
205}
206
207static void
208clipboard_set_selection(struct wl_listener *listener, void *data)
209{
210 struct clipboard *clipboard =
211 container_of(listener, struct clipboard, selection_listener);
212 struct weston_seat *seat = data;
213 struct wl_data_source *source = seat->seat.selection_data_source;
214 const char **mime_types;
215 int p[2];
216
217 if (source == NULL) {
218 if (clipboard->source)
219 wl_seat_set_selection(&seat->seat,
220 &clipboard->source->base,
221 clipboard->source->serial);
222 return;
223 } else if (source->accept == clipboard_source_accept) {
224 /* Callback for our data source. */
225 return;
226 }
227
228 if (clipboard->source)
229 clipboard_source_unref(clipboard->source);
230
231 clipboard->source = NULL;
232
233 mime_types = source->mime_types.data;
234
235 if (pipe2(p, O_CLOEXEC) == -1)
236 return;
237
238 source->send(source, mime_types[0], p[1]);
239
240 clipboard->source =
241 clipboard_source_create(clipboard, mime_types[0],
242 seat->seat.selection_serial, p[0]);
243 if (clipboard->source == NULL)
244 return;
245}
246
247struct clipboard *
248clipboard_create(struct weston_seat *seat)
249{
250 struct clipboard *clipboard;
251
252 clipboard = malloc(sizeof *clipboard);
253 if (clipboard == NULL)
254 return NULL;
255
256 clipboard->seat = seat;
257 clipboard->selection_listener.notify = clipboard_set_selection;
258
259 wl_signal_add(&seat->seat.selection_signal,
260 &clipboard->selection_listener);
261
262 return clipboard;
263}