input: Rename wl_pointer to weston_pointer
[platform/upstream/weston.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 #define _GNU_SOURCE
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 wl_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 };
42
43 struct 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
50 static void clipboard_client_create(struct clipboard_source *source, int fd);
51
52 static void
53 clipboard_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);
63         wl_signal_emit(&source->base.resource.destroy_signal,
64                        &source->base.resource);
65         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
72 static int
73 clipboard_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
101 static void
102 clipboard_source_accept(struct wl_data_source *source,
103                         uint32_t time, const char *mime_type)
104 {
105 }
106
107 static void
108 clipboard_source_send(struct wl_data_source *base,
109                       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
122 static void
123 clipboard_source_cancel(struct wl_data_source *source)
124 {
125 }
126
127 static struct clipboard_source *
128 clipboard_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);
137         wl_array_init(&source->contents);
138         wl_array_init(&source->base.mime_types);
139         source->base.accept = clipboard_source_accept;
140         source->base.send = clipboard_source_send;
141         source->base.cancel = clipboard_source_cancel;
142         source->base.resource.data = &source->base;
143         wl_signal_init(&source->base.resource.destroy_signal);
144         source->refcount = 1;
145         source->clipboard = clipboard;
146         source->serial = serial;
147
148         s = wl_array_add(&source->base.mime_types, sizeof *s);
149         *s = strdup(mime_type);
150
151         source->event_source =
152                 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
153                                      clipboard_source_data, source);
154
155         return source;
156 }
157
158 struct clipboard_client {
159         struct wl_event_source *event_source;
160         size_t offset;
161         struct clipboard_source *source;
162 };
163
164 static int
165 clipboard_client_data(int fd, uint32_t mask, void *data)
166 {
167         struct clipboard_client *client = data;
168         char *p;
169         size_t size;
170         int len;
171
172         size = client->source->contents.size;
173         p = client->source->contents.data;
174         len = write(fd, p + client->offset, size - client->offset);
175         if (len > 0)
176                 client->offset += len;
177
178         if (client->offset == size || len <= 0) {
179                 close(fd);
180                 wl_event_source_remove(client->event_source);
181                 clipboard_source_unref(client->source);
182                 free(client);
183         }
184
185         return 1;
186 }
187
188 static void
189 clipboard_client_create(struct clipboard_source *source, int fd)
190 {
191         struct weston_seat *seat = source->clipboard->seat;
192         struct clipboard_client *client;
193         struct wl_event_loop *loop =
194                 wl_display_get_event_loop(seat->compositor->wl_display);
195
196         client = malloc(sizeof *client);
197
198         client->offset = 0;
199         client->source = source;
200         source->refcount++;
201         client->event_source =
202                 wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
203                                      clipboard_client_data, client);
204 }
205
206 static void
207 clipboard_set_selection(struct wl_listener *listener, void *data)
208 {
209         struct clipboard *clipboard =
210                 container_of(listener, struct clipboard, selection_listener);
211         struct weston_seat *seat = data;
212         struct wl_data_source *source = seat->seat.selection_data_source;
213         const char **mime_types;
214         int p[2];
215
216         if (source == NULL) {
217                 if (clipboard->source)
218                         wl_seat_set_selection(&seat->seat,
219                                               &clipboard->source->base,
220                                               clipboard->source->serial);
221                 return;
222         } else if (source->accept == clipboard_source_accept) {
223                 /* Callback for our data source. */
224                 return;
225         }
226
227         if (clipboard->source)
228                 clipboard_source_unref(clipboard->source);
229
230         clipboard->source = NULL;
231
232         mime_types = source->mime_types.data;
233
234         if (pipe2(p, O_CLOEXEC) == -1)
235                 return;
236
237         source->send(source, mime_types[0], p[1]);
238
239         clipboard->source =
240                 clipboard_source_create(clipboard, mime_types[0],
241                                         seat->seat.selection_serial, p[0]);
242         if (clipboard->source == NULL)
243                 return;
244 }
245
246 static void
247 clipboard_destroy(struct wl_listener *listener, void *data)
248 {
249         struct clipboard *clipboard =
250                 container_of(listener, struct clipboard, destroy_listener);
251
252         wl_list_remove(&clipboard->selection_listener.link);
253
254         free(clipboard);
255 }
256
257 struct clipboard *
258 clipboard_create(struct weston_seat *seat)
259 {
260         struct clipboard *clipboard;
261
262         clipboard = malloc(sizeof *clipboard);
263         if (clipboard == NULL)
264                 return NULL;
265         memset(clipboard, 0, sizeof *clipboard);
266
267         clipboard->seat = seat;
268         clipboard->selection_listener.notify = clipboard_set_selection;
269         clipboard->destroy_listener.notify = clipboard_destroy;
270
271         wl_signal_add(&seat->seat.selection_signal,
272                       &clipboard->selection_listener);
273         wl_signal_add(&seat->seat.destroy_signal,
274                       &clipboard->destroy_listener);
275
276         return clipboard;
277 }