compositor-x11: Rename the output make to "weston-X11"
[platform/upstream/weston.git] / clients / dnd.c
1 /*
2  * Copyright © 2010 Kristian Høgsberg
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22
23 #include "config.h"
24
25 #include <assert.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <math.h>
33 #include <sys/time.h>
34 #include <cairo.h>
35 #include <sys/epoll.h>
36
37 #include <wayland-client.h>
38 #include <wayland-cursor.h>
39
40 #include "window.h"
41 #include "../shared/cairo-util.h"
42
43 struct dnd_drag;
44
45 struct dnd {
46         struct window *window;
47         struct widget *widget;
48         struct display *display;
49         uint32_t key;
50         struct item *items[16];
51         int self_only;
52         struct dnd_drag *current_drag;
53 };
54
55 struct dnd_drag {
56         cairo_surface_t *translucent;
57         cairo_surface_t *opaque;
58         int hotspot_x, hotspot_y;
59         struct dnd *dnd;
60         struct input *input;
61         uint32_t time;
62         struct item *item;
63         int x_offset, y_offset;
64         int width, height;
65         const char *mime_type;
66
67         struct wl_surface *drag_surface;
68         struct wl_data_source *data_source;
69 };
70
71 struct item {
72         cairo_surface_t *surface;
73         int seed;
74         int x, y;
75 };
76
77 struct dnd_flower_message {
78         int seed, x_offset, y_offset;
79 };
80
81
82 static const int item_width = 64;
83 static const int item_height = 64;
84 static const int item_padding = 16;
85
86 static const char flower_mime_type[] = "application/x-wayland-dnd-flower";
87 static const char text_mime_type[] = "text/plain;charset=utf-8";
88
89 static struct item *
90 item_create(struct display *display, int x, int y, int seed)
91 {
92         struct item *item;
93         struct timeval tv;
94
95         item = malloc(sizeof *item);
96         if (item == NULL)
97                 return NULL;
98         
99         
100         gettimeofday(&tv, NULL);
101         item->seed = seed ? seed : tv.tv_usec;
102         srandom(item->seed);
103         
104         const int petal_count = 3 + random() % 5;
105         const double r1 = 20 + random() % 10;
106         const double r2 = 5 + random() % 12;
107         const double u = (10 + random() % 90) / 100.0;
108         const double v = (random() % 90) / 100.0;
109
110         cairo_t *cr;
111         int i;
112         double t, dt = 2 * M_PI / (petal_count * 2);
113         double x1, y1, x2, y2, x3, y3;
114         struct rectangle rect;
115
116
117         rect.width = item_width;
118         rect.height = item_height;
119         item->surface =
120                 display_create_surface(display, NULL, &rect, SURFACE_SHM);
121
122         item->x = x;
123         item->y = y;
124
125         cr = cairo_create(item->surface);
126         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
127         cairo_set_source_rgba(cr, 0, 0, 0, 0);
128         cairo_paint(cr);
129
130         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
131         cairo_translate(cr, item_width / 2, item_height / 2);
132         t = random();
133         cairo_move_to(cr, cos(t) * r1, sin(t) * r1);
134         for (i = 0; i < petal_count; i++, t += dt * 2) {
135                 x1 = cos(t) * r1;
136                 y1 = sin(t) * r1;
137                 x2 = cos(t + dt) * r2;
138                 y2 = sin(t + dt) * r2;
139                 x3 = cos(t + 2 * dt) * r1;
140                 y3 = sin(t + 2 * dt) * r1;
141
142                 cairo_curve_to(cr,
143                                x1 - y1 * u, y1 + x1 * u,
144                                x2 + y2 * v, y2 - x2 * v,
145                                x2, y2);
146
147                 cairo_curve_to(cr,
148                                x2 - y2 * v, y2 + x2 * v,
149                                x3 + y3 * u, y3 - x3 * u,
150                                x3, y3);
151         }
152
153         cairo_close_path(cr);
154
155         cairo_set_source_rgba(cr,
156                               0.5 + (random() % 50) / 49.0,
157                               0.5 + (random() % 50) / 49.0,
158                               0.5 + (random() % 50) / 49.0,
159                               0.5 + (random() % 100) / 99.0);
160
161         cairo_fill_preserve(cr);
162
163         cairo_set_line_width(cr, 1);
164         cairo_set_source_rgba(cr,
165                               0.5 + (random() % 50) / 49.0,
166                               0.5 + (random() % 50) / 49.0,
167                               0.5 + (random() % 50) / 49.0,
168                               0.5 + (random() % 100) / 99.0);
169         cairo_stroke(cr);
170
171         cairo_destroy(cr);
172
173         return item;
174 }
175
176 static void
177 dnd_redraw_handler(struct widget *widget, void *data)
178 {
179         struct dnd *dnd = data;
180         struct rectangle allocation;
181         cairo_t *cr;
182         cairo_surface_t *surface;
183         unsigned int i;
184
185         surface = window_get_surface(dnd->window);
186         cr = cairo_create(surface);
187         widget_get_allocation(dnd->widget, &allocation);
188         cairo_rectangle(cr, allocation.x, allocation.y,
189                         allocation.width, allocation.height);
190
191         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
192         cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
193         cairo_fill(cr);
194
195         cairo_rectangle(cr, allocation.x, allocation.y,
196                         allocation.width, allocation.height);
197         cairo_clip(cr);
198         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
199         for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
200                 if (!dnd->items[i])
201                         continue;
202                 cairo_set_source_surface(cr, dnd->items[i]->surface,
203                                          dnd->items[i]->x + allocation.x,
204                                          dnd->items[i]->y + allocation.y);
205                 cairo_paint(cr);
206         }
207
208         cairo_destroy(cr);
209         cairo_surface_destroy(surface);
210 }
211
212 static void
213 keyboard_focus_handler(struct window *window,
214                        struct input *device, void *data)
215 {
216         struct dnd *dnd = data;
217
218         window_schedule_redraw(dnd->window);
219 }
220
221 static int
222 dnd_add_item(struct dnd *dnd, struct item *item)
223 {
224         unsigned int i;
225
226         for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
227                 if (dnd->items[i] == 0) {
228                         dnd->items[i] = item;
229                         return i;
230                 }
231         }
232         return -1;
233 }
234
235 static struct item *
236 dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
237 {
238         struct item *item;
239         struct rectangle allocation;
240         unsigned int i;
241
242         widget_get_allocation(dnd->widget, &allocation);
243
244         x -= allocation.x;
245         y -= allocation.y;
246
247         for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
248                 item = dnd->items[i];
249                 if (item &&
250                     item->x <= x && x < item->x + item_width &&
251                     item->y <= y && y < item->y + item_height)
252                         return item;
253         }
254
255         return NULL;
256 }
257
258 static void
259 data_source_target(void *data,
260                    struct wl_data_source *source, const char *mime_type)
261 {
262         struct dnd_drag *dnd_drag = data;
263         struct dnd *dnd = dnd_drag->dnd;
264         cairo_surface_t *surface;
265         struct wl_buffer *buffer;
266
267         dnd_drag->mime_type = mime_type;
268         if (mime_type)
269                 surface = dnd_drag->opaque;
270         else
271                 surface = dnd_drag->translucent;
272
273         buffer = display_get_buffer_for_surface(dnd->display, surface);
274         wl_surface_attach(dnd_drag->drag_surface, buffer, 0, 0);
275         wl_surface_damage(dnd_drag->drag_surface, 0, 0,
276                           dnd_drag->width, dnd_drag->height);
277         wl_surface_commit(dnd_drag->drag_surface);
278 }
279
280 static void
281 data_source_send(void *data, struct wl_data_source *source,
282                  const char *mime_type, int32_t fd)
283 {
284         struct dnd_flower_message dnd_flower_message;   
285         struct dnd_drag *dnd_drag = data;
286         char buffer[128];
287         int n;
288
289         if (strcmp(mime_type, flower_mime_type) == 0) {
290                 dnd_flower_message.seed = dnd_drag->item->seed;
291                 dnd_flower_message.x_offset = dnd_drag->x_offset;
292                 dnd_flower_message.y_offset = dnd_drag->y_offset;
293
294                 if (write(fd, &dnd_flower_message,
295                           sizeof dnd_flower_message) < 0)
296                         abort();
297         } else if (strcmp(mime_type, text_mime_type) == 0) {
298                 n = snprintf(buffer, sizeof buffer, "seed=%d x=%d y=%d\n",
299                              dnd_drag->item->seed,
300                              dnd_drag->x_offset,
301                              dnd_drag->y_offset);
302
303                 if (write(fd, buffer, n) < 0)
304                         abort();
305         }
306
307         close(fd);
308 }
309
310 static void
311 data_source_cancelled(void *data, struct wl_data_source *source)
312 {
313         struct dnd_drag *dnd_drag = data;
314
315         /* The 'cancelled' event means that the source is no longer in
316          * use by the drag (or current selection).  We need to clean
317          * up the drag object created and the local state. */
318
319         wl_data_source_destroy(dnd_drag->data_source);
320         
321         /* Destroy the item that has been dragged out */
322         cairo_surface_destroy(dnd_drag->item->surface);
323         free(dnd_drag->item);
324
325         wl_surface_destroy(dnd_drag->drag_surface);
326
327         cairo_surface_destroy(dnd_drag->translucent);
328         cairo_surface_destroy(dnd_drag->opaque);
329         free(dnd_drag);
330 }
331
332 static const struct wl_data_source_listener data_source_listener = {
333         data_source_target,
334         data_source_send,
335         data_source_cancelled
336 };
337
338 static cairo_surface_t *
339 create_drag_icon(struct dnd_drag *dnd_drag,
340                  struct item *item, int32_t x, int32_t y, double opacity)
341 {
342         struct dnd *dnd = dnd_drag->dnd;
343         cairo_surface_t *surface;
344         struct rectangle rectangle;
345         cairo_pattern_t *pattern;
346         cairo_t *cr;
347
348         rectangle.width = item_width;
349         rectangle.height = item_height;
350         surface = display_create_surface(dnd->display, NULL, &rectangle,
351                                          SURFACE_SHM);
352
353         cr = cairo_create(surface);
354         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
355         cairo_set_source_surface(cr, item->surface, 0, 0);
356         pattern = cairo_pattern_create_rgba(0, 0, 0, opacity);
357         cairo_mask(cr, pattern);
358         cairo_pattern_destroy(pattern);
359
360         cairo_destroy(cr);
361
362         dnd_drag->hotspot_x = x - item->x;
363         dnd_drag->hotspot_y = y - item->y;
364         dnd_drag->width = rectangle.width;
365         dnd_drag->height = rectangle.height;
366
367         return surface;
368 }
369
370 static int
371 create_drag_source(struct dnd *dnd,
372                 struct input *input, uint32_t time,
373                 int32_t x, int32_t y)
374 {
375         struct item *item;
376         struct rectangle allocation;
377         struct dnd_drag *dnd_drag;
378         struct display *display;
379         struct wl_compositor *compositor;
380         struct wl_buffer *buffer;
381         unsigned int i;
382         uint32_t serial;
383         cairo_surface_t *icon;
384
385         widget_get_allocation(dnd->widget, &allocation);
386         item = dnd_get_item(dnd, x, y);
387         x -= allocation.x;
388         y -= allocation.y;
389
390         if (item) {
391                 dnd_drag = xmalloc(sizeof *dnd_drag);
392                 dnd_drag->dnd = dnd;
393                 dnd_drag->input = input;
394                 dnd_drag->time = time;
395                 dnd_drag->item = item;
396                 dnd_drag->x_offset = x - item->x;
397                 dnd_drag->y_offset = y - item->y;
398
399                 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
400                         if (item == dnd->items[i]){
401                                 dnd->items[i] = 0;
402                                 break;
403                         }
404                 }
405
406                 display = window_get_display(dnd->window);
407                 compositor = display_get_compositor(display);
408                 serial = display_get_serial(display);
409                 dnd_drag->drag_surface =
410                         wl_compositor_create_surface(compositor);
411
412                 if (dnd->self_only) {
413                         dnd_drag->data_source = NULL;
414                 } else {
415                         dnd_drag->data_source =
416                                 display_create_data_source(dnd->display);
417                         wl_data_source_add_listener(dnd_drag->data_source,
418                                                     &data_source_listener,
419                                                     dnd_drag);
420                         wl_data_source_offer(dnd_drag->data_source,
421                                              flower_mime_type);
422                         wl_data_source_offer(dnd_drag->data_source,
423                                              text_mime_type);
424                 }
425
426                 wl_data_device_start_drag(input_get_data_device(input),
427                                           dnd_drag->data_source,
428                                           window_get_wl_surface(dnd->window),
429                                           dnd_drag->drag_surface,
430                                           serial);
431
432                 dnd_drag->opaque =
433                         create_drag_icon(dnd_drag, item, x, y, 1);
434                 dnd_drag->translucent =
435                         create_drag_icon(dnd_drag, item, x, y, 0.2);
436
437                 if (dnd->self_only)
438                         icon = dnd_drag->opaque;
439                 else
440                         icon = dnd_drag->translucent;
441
442                 buffer = display_get_buffer_for_surface(dnd->display, icon);
443                 wl_surface_attach(dnd_drag->drag_surface, buffer,
444                                   -dnd_drag->hotspot_x, -dnd_drag->hotspot_y);
445                 wl_surface_damage(dnd_drag->drag_surface, 0, 0,
446                                   dnd_drag->width, dnd_drag->height);
447                 wl_surface_commit(dnd_drag->drag_surface);
448
449                 dnd->current_drag = dnd_drag;
450                 window_schedule_redraw(dnd->window);
451
452                 return 0;
453         } else
454                 return -1;
455 }
456
457 static void
458 dnd_button_handler(struct widget *widget,
459                    struct input *input, uint32_t time,
460                    uint32_t button, enum wl_pointer_button_state state,
461                    void *data)
462 {
463         struct dnd *dnd = data;
464         int32_t x, y;
465
466         input_get_position(input, &x, &y);
467         if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
468                 input_ungrab(input);
469                 if (create_drag_source(dnd, input, time, x, y) == 0)
470                         input_set_pointer_image(input, CURSOR_DRAGGING);
471         }
472 }
473
474 static void
475 dnd_touch_down_handler(struct widget *widget,
476                 struct input *input, uint32_t serial,
477                 uint32_t time, int32_t id,
478                 float x, float y, void *data)
479 {
480         struct dnd *dnd = data;
481         int32_t int_x, int_y;
482
483         if (id > 0)
484                 return;
485
486         int_x = (int32_t)x;
487         int_y = (int32_t)y;
488         if (create_drag_source(dnd, input, time, int_x, int_y) == 0)
489                 touch_grab(input, 0);
490 }
491
492 static int
493 lookup_cursor(struct dnd *dnd, int x, int y)
494 {
495         struct item *item;
496
497         item = dnd_get_item(dnd, x, y);
498         if (item)
499                 return CURSOR_HAND1;
500         else
501                 return CURSOR_LEFT_PTR;
502 }
503
504 static int
505 dnd_enter_handler(struct widget *widget,
506                   struct input *input, float x, float y, void *data)
507 {
508         struct dnd *dnd = data;
509
510         dnd->current_drag = NULL;
511
512         return lookup_cursor(dnd, x, y);
513 }
514
515 static int
516 dnd_motion_handler(struct widget *widget,
517                    struct input *input, uint32_t time,
518                    float x, float y, void *data)
519 {
520         return lookup_cursor(data, x, y);
521 }
522
523 static void
524 dnd_data_handler(struct window *window,
525                  struct input *input,
526                  float x, float y, const char **types, void *data)
527 {
528         struct dnd *dnd = data;
529         int i, has_flower = 0;
530
531         if (!types)
532                 return;
533         for (i = 0; types[i]; i++)
534                 if (strcmp(types[i], flower_mime_type) == 0)
535                         has_flower = 1;
536
537         if (dnd_get_item(dnd, x, y) || dnd->self_only || !has_flower) {
538                 input_accept(input, NULL);
539         } else {
540                 input_accept(input, flower_mime_type);
541         }
542 }
543
544 static void
545 dnd_receive_func(void *data, size_t len, int32_t x, int32_t y, void *user_data)
546 {
547         struct dnd *dnd = user_data;
548         struct dnd_flower_message *message = data;
549         struct item *item;
550         struct rectangle allocation;
551
552         if (len == 0) {
553                 return;
554         } else if (len != sizeof *message) {
555                 fprintf(stderr, "odd message length %zu, expected %zu\n",
556                         len, sizeof *message);
557                 return;
558         }
559                 
560         widget_get_allocation(dnd->widget, &allocation);
561         item = item_create(dnd->display,
562                            x - message->x_offset - allocation.x,
563                            y - message->y_offset - allocation.y,
564                            message->seed);
565
566         dnd_add_item(dnd, item);
567         window_schedule_redraw(dnd->window);
568 }
569
570 static void
571 dnd_drop_handler(struct window *window, struct input *input,
572                  int32_t x, int32_t y, void *data)
573 {
574         struct dnd *dnd = data;
575         struct dnd_flower_message message;
576
577         if (dnd_get_item(dnd, x, y)) {
578                 fprintf(stderr, "got 'drop', but no target\n");
579                 return;
580         }
581
582         if (!dnd->self_only) {
583                 input_receive_drag_data(input,
584                                         flower_mime_type,
585                                         dnd_receive_func, dnd);
586         } else if (dnd->current_drag) {
587                 message.seed = dnd->current_drag->item->seed;
588                 message.x_offset = dnd->current_drag->x_offset;
589                 message.y_offset = dnd->current_drag->y_offset;
590                 dnd_receive_func(&message, sizeof message, x, y, dnd);
591                 dnd->current_drag = NULL;
592         } else {
593                 fprintf(stderr, "ignoring drop from another client\n");
594         }
595 }
596
597 static struct dnd *
598 dnd_create(struct display *display)
599 {
600         struct dnd *dnd;
601         int x, y;
602         int32_t width, height;
603         unsigned int i;
604
605         dnd = xzalloc(sizeof *dnd);
606         dnd->window = window_create(display);
607         dnd->widget = window_frame_create(dnd->window, dnd);
608         window_set_title(dnd->window, "Wayland Drag and Drop Demo");
609
610         dnd->display = display;
611         dnd->key = 100;
612
613         for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
614                 x = (i % 4) * (item_width + item_padding) + item_padding;
615                 y = (i / 4) * (item_height + item_padding) + item_padding;
616                 if ((i ^ (i >> 2)) & 1)
617                         dnd->items[i] = item_create(display, x, y, 0);
618                 else
619                         dnd->items[i] = NULL;
620         }
621
622         window_set_user_data(dnd->window, dnd);
623         window_set_keyboard_focus_handler(dnd->window,
624                                           keyboard_focus_handler);
625         window_set_data_handler(dnd->window, dnd_data_handler);
626         window_set_drop_handler(dnd->window, dnd_drop_handler);
627
628         widget_set_redraw_handler(dnd->widget, dnd_redraw_handler);
629         widget_set_enter_handler(dnd->widget, dnd_enter_handler);
630         widget_set_motion_handler(dnd->widget, dnd_motion_handler);
631         widget_set_button_handler(dnd->widget, dnd_button_handler);
632         widget_set_touch_down_handler(dnd->widget, dnd_touch_down_handler);
633
634         width = 4 * (item_width + item_padding) + item_padding;
635         height = 4 * (item_height + item_padding) + item_padding;
636
637         window_frame_set_child_size(dnd->widget, width, height);
638
639         return dnd;
640 }
641
642 static void
643 dnd_destroy(struct dnd *dnd)
644 {
645         widget_destroy(dnd->widget);
646         window_destroy(dnd->window);
647         free(dnd);
648 }
649
650 int
651 main(int argc, char *argv[])
652 {
653         struct display *d;
654         struct dnd *dnd;
655         int self_only = 0;
656
657         if (argc == 2 && !strcmp(argv[1], "--self-only"))
658                 self_only = 1;
659         else if (argc > 1) {
660                 printf("Usage: %s [OPTIONS]\n  --self-only\n", argv[0]);
661                 return 1;
662         }
663
664         d = display_create(&argc, argv);
665         if (d == NULL) {
666                 fprintf(stderr, "failed to create display: %m\n");
667                 return -1;
668         }
669
670         dnd = dnd_create(d);
671         if (self_only)
672                 dnd->self_only = 1;
673
674         display_run(d);
675
676         dnd_destroy(dnd);
677         display_destroy(d);
678
679         return 0;
680 }