compositor: quick fix for sub-surface mapping
[profile/ivi/weston-ivi-shell.git] / src / clipboard.c
1 /*
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 #include "config.h"
24
25 #include <stdlib.h>
26 #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
34 struct clipboard_source {
35         struct weston_data_source base;
36         struct wl_array contents;
37         struct clipboard *clipboard;
38         struct wl_event_source *event_source;
39         uint32_t serial;
40         int refcount;
41         int fd;
42 };
43
44 struct 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
51 static void clipboard_client_create(struct clipboard_source *source, int fd);
52
53 static void
54 clipboard_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                 close(source->fd);
65         }
66         wl_signal_emit(&source->base.destroy_signal,
67                        &source->base);
68         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
75 static int
76 clipboard_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);
93                 close(fd);
94                 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
105 static void
106 clipboard_source_accept(struct weston_data_source *source,
107                         uint32_t time, const char *mime_type)
108 {
109 }
110
111 static void
112 clipboard_source_send(struct weston_data_source *base,
113                       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
126 static void
127 clipboard_source_cancel(struct weston_data_source *source)
128 {
129 }
130
131 static struct clipboard_source *
132 clipboard_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);
141         if (source == NULL)
142                 return NULL;
143
144         wl_array_init(&source->contents);
145         wl_array_init(&source->base.mime_types);
146         source->base.resource = NULL;
147         source->base.accept = clipboard_source_accept;
148         source->base.send = clipboard_source_send;
149         source->base.cancel = clipboard_source_cancel;
150         wl_signal_init(&source->base.destroy_signal);
151         source->refcount = 1;
152         source->clipboard = clipboard;
153         source->serial = serial;
154
155         s = wl_array_add(&source->base.mime_types, sizeof *s);
156         if (s == NULL)
157                 goto err_add;
158         *s = strdup(mime_type);
159         if (*s == NULL)
160                 goto err_strdup;
161         source->event_source =
162                 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
163                                      clipboard_source_data, source);
164         if (source->event_source == NULL)
165                 goto err_source;
166
167         return source;
168
169  err_source:
170         free(*s);
171  err_strdup:
172         wl_array_release(&source->base.mime_types);
173  err_add:
174         free(source);
175
176         return NULL;
177 }
178
179 struct clipboard_client {
180         struct wl_event_source *event_source;
181         size_t offset;
182         struct clipboard_source *source;
183 };
184
185 static int
186 clipboard_client_data(int fd, uint32_t mask, void *data)
187 {
188         struct clipboard_client *client = data;
189         char *p;
190         size_t size;
191         int len;
192
193         size = client->source->contents.size;
194         p = client->source->contents.data;
195         len = write(fd, p + client->offset, size - client->offset);
196         if (len > 0)
197                 client->offset += len;
198
199         if (client->offset == size || len <= 0) {
200                 close(fd);
201                 wl_event_source_remove(client->event_source);
202                 clipboard_source_unref(client->source);
203                 free(client);
204         }
205
206         return 1;
207 }
208
209 static void
210 clipboard_client_create(struct clipboard_source *source, int fd)
211 {
212         struct weston_seat *seat = source->clipboard->seat;
213         struct clipboard_client *client;
214         struct wl_event_loop *loop =
215                 wl_display_get_event_loop(seat->compositor->wl_display);
216
217         client = malloc(sizeof *client);
218
219         client->offset = 0;
220         client->source = source;
221         source->refcount++;
222         client->event_source =
223                 wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
224                                      clipboard_client_data, client);
225 }
226
227 static void
228 clipboard_set_selection(struct wl_listener *listener, void *data)
229 {
230         struct clipboard *clipboard =
231                 container_of(listener, struct clipboard, selection_listener);
232         struct weston_seat *seat = data;
233         struct weston_data_source *source = seat->selection_data_source;
234         const char **mime_types;
235         int p[2];
236
237         if (source == NULL) {
238                 if (clipboard->source)
239                         weston_seat_set_selection(seat,
240                                                   &clipboard->source->base,
241                                                   clipboard->source->serial);
242                 return;
243         } else if (source->accept == clipboard_source_accept) {
244                 /* Callback for our data source. */
245                 return;
246         }
247
248         if (clipboard->source)
249                 clipboard_source_unref(clipboard->source);
250
251         clipboard->source = NULL;
252
253         mime_types = source->mime_types.data;
254
255         if (pipe2(p, O_CLOEXEC) == -1)
256                 return;
257
258         source->send(source, mime_types[0], p[1]);
259
260         clipboard->source =
261                 clipboard_source_create(clipboard, mime_types[0],
262                                         seat->selection_serial, p[0]);
263         if (clipboard->source == NULL) {
264                 close(p[0]);
265                 return;
266         }
267 }
268
269 static void
270 clipboard_destroy(struct wl_listener *listener, void *data)
271 {
272         struct clipboard *clipboard =
273                 container_of(listener, struct clipboard, destroy_listener);
274
275         wl_list_remove(&clipboard->selection_listener.link);
276         wl_list_remove(&clipboard->destroy_listener.link);
277
278         free(clipboard);
279 }
280
281 struct clipboard *
282 clipboard_create(struct weston_seat *seat)
283 {
284         struct clipboard *clipboard;
285
286         clipboard = zalloc(sizeof *clipboard);
287         if (clipboard == NULL)
288                 return NULL;
289
290         clipboard->seat = seat;
291         clipboard->selection_listener.notify = clipboard_set_selection;
292         clipboard->destroy_listener.notify = clipboard_destroy;
293
294         wl_signal_add(&seat->selection_signal,
295                       &clipboard->selection_listener);
296         wl_signal_add(&seat->destroy_signal,
297                       &clipboard->destroy_listener);
298
299         return clipboard;
300 }