blob: 81711934b06e72eec6a69fc8413a5aaf31b72c84 [file] [log] [blame]
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -04001/*
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
Philipp Brüschweilerf22d0ec2012-08-13 20:04:54 +020023#include <assert.h>
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040024#include <stdint.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <math.h>
31#include <sys/time.h>
32#include <cairo.h>
Kristian Høgsberg3a696272011-09-14 17:33:48 -040033#include <sys/epoll.h>
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040034
Pekka Paalanen50719bc2011-11-22 14:18:50 +020035#include <wayland-client.h>
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +030036#include <wayland-cursor.h>
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040037
38#include "window.h"
Kristian Høgsberg5a315bc2012-05-15 22:33:43 -040039#include "../shared/cairo-util.h"
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040040
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +030041struct dnd_drag;
42
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040043struct dnd {
44 struct window *window;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -050045 struct widget *widget;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040046 struct display *display;
47 uint32_t key;
48 struct item *items[16];
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +030049 int self_only;
50 struct dnd_drag *current_drag;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -040051};
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -040052
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -040053struct dnd_drag {
54 cairo_surface_t *translucent;
55 cairo_surface_t *opaque;
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -040056 int hotspot_x, hotspot_y;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -040057 struct dnd *dnd;
58 struct input *input;
Kristian Høgsbergce457ba2010-09-14 15:39:45 -040059 uint32_t time;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080060 struct item *item;
61 int x_offset, y_offset;
Kristian Høgsberg679f7162012-03-27 16:44:57 -040062 int width, height;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080063 const char *mime_type;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -040064
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +020065 struct wl_surface *drag_surface;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -040066 struct wl_data_source *data_source;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040067};
68
69struct item {
70 cairo_surface_t *surface;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080071 int seed;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040072 int x, y;
73};
74
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080075struct dnd_flower_message {
76 int seed, x_offset, y_offset;
77};
78
79
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040080static const int item_width = 64;
81static const int item_height = 64;
82static const int item_padding = 16;
83
Kristian Høgsberg938f1022013-09-04 19:36:49 -070084static const char flower_mime_type[] = "application/x-wayland-dnd-flower";
85
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040086static struct item *
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080087item_create(struct display *display, int x, int y, int seed)
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040088{
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080089 struct item *item;
90 struct timeval tv;
91
92 item = malloc(sizeof *item);
93 if (item == NULL)
94 return NULL;
95
96
97 gettimeofday(&tv, NULL);
98 item->seed = seed ? seed : tv.tv_usec;
99 srandom(item->seed);
100
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400101 const int petal_count = 3 + random() % 5;
102 const double r1 = 20 + random() % 10;
103 const double r2 = 5 + random() % 12;
104 const double u = (10 + random() % 90) / 100.0;
105 const double v = (random() % 90) / 100.0;
106
107 cairo_t *cr;
108 int i;
109 double t, dt = 2 * M_PI / (petal_count * 2);
110 double x1, y1, x2, y2, x3, y3;
111 struct rectangle rect;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400112
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400113
114 rect.width = item_width;
115 rect.height = item_height;
Ander Conselvan de Oliveira210eb9d2012-05-25 16:03:06 +0300116 item->surface =
117 display_create_surface(display, NULL, &rect, SURFACE_SHM);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400118
119 item->x = x;
120 item->y = y;
121
122 cr = cairo_create(item->surface);
123 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
124 cairo_set_source_rgba(cr, 0, 0, 0, 0);
125 cairo_paint(cr);
126
127 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
128 cairo_translate(cr, item_width / 2, item_height / 2);
129 t = random();
130 cairo_move_to(cr, cos(t) * r1, sin(t) * r1);
131 for (i = 0; i < petal_count; i++, t += dt * 2) {
132 x1 = cos(t) * r1;
133 y1 = sin(t) * r1;
134 x2 = cos(t + dt) * r2;
135 y2 = sin(t + dt) * r2;
136 x3 = cos(t + 2 * dt) * r1;
137 y3 = sin(t + 2 * dt) * r1;
138
139 cairo_curve_to(cr,
140 x1 - y1 * u, y1 + x1 * u,
141 x2 + y2 * v, y2 - x2 * v,
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400142 x2, y2);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400143
144 cairo_curve_to(cr,
145 x2 - y2 * v, y2 + x2 * v,
146 x3 + y3 * u, y3 - x3 * u,
147 x3, y3);
148 }
149
150 cairo_close_path(cr);
151
152 cairo_set_source_rgba(cr,
153 0.5 + (random() % 50) / 49.0,
154 0.5 + (random() % 50) / 49.0,
155 0.5 + (random() % 50) / 49.0,
156 0.5 + (random() % 100) / 99.0);
157
158 cairo_fill_preserve(cr);
159
160 cairo_set_line_width(cr, 1);
161 cairo_set_source_rgba(cr,
162 0.5 + (random() % 50) / 49.0,
163 0.5 + (random() % 50) / 49.0,
164 0.5 + (random() % 50) / 49.0,
165 0.5 + (random() % 100) / 99.0);
166 cairo_stroke(cr);
167
168 cairo_destroy(cr);
169
170 return item;
171}
172
173static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500174dnd_redraw_handler(struct widget *widget, void *data)
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400175{
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500176 struct dnd *dnd = data;
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500177 struct rectangle allocation;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400178 cairo_t *cr;
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500179 cairo_surface_t *surface;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400180 unsigned int i;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400181
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500182 surface = window_get_surface(dnd->window);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400183 cr = cairo_create(surface);
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500184 widget_get_allocation(dnd->widget, &allocation);
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500185 cairo_rectangle(cr, allocation.x, allocation.y,
186 allocation.width, allocation.height);
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500187
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400188 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
189 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400190 cairo_fill(cr);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400191
Kristian Høgsberg0fd49aa2012-07-23 21:32:46 -0400192 cairo_rectangle(cr, allocation.x, allocation.y,
193 allocation.width, allocation.height);
194 cairo_clip(cr);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400195 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
196 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
197 if (!dnd->items[i])
198 continue;
199 cairo_set_source_surface(cr, dnd->items[i]->surface,
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400200 dnd->items[i]->x + allocation.x,
201 dnd->items[i]->y + allocation.y);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400202 cairo_paint(cr);
203 }
204
205 cairo_destroy(cr);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400206 cairo_surface_destroy(surface);
207}
208
209static void
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400210keyboard_focus_handler(struct window *window,
211 struct input *device, void *data)
212{
213 struct dnd *dnd = data;
214
215 window_schedule_redraw(dnd->window);
216}
217
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800218static int
219dnd_add_item(struct dnd *dnd, struct item *item)
220{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400221 unsigned int i;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800222
223 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
224 if (dnd->items[i] == 0) {
225 dnd->items[i] = item;
226 return i;
227 }
228 }
229 return -1;
230}
231
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400232static struct item *
233dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
234{
235 struct item *item;
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500236 struct rectangle allocation;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400237 unsigned int i;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400238
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500239 widget_get_allocation(dnd->widget, &allocation);
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400240
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500241 x -= allocation.x;
242 y -= allocation.y;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400243
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400244 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
245 item = dnd->items[i];
246 if (item &&
247 item->x <= x && x < item->x + item_width &&
248 item->y <= y && y < item->y + item_height)
249 return item;
250 }
251
252 return NULL;
253}
254
255static void
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400256data_source_target(void *data,
257 struct wl_data_source *source, const char *mime_type)
Kristian Høgsberg506e20e2010-08-19 17:26:02 -0400258{
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400259 struct dnd_drag *dnd_drag = data;
260 struct dnd *dnd = dnd_drag->dnd;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400261 cairo_surface_t *surface;
262 struct wl_buffer *buffer;
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -0400263
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800264 dnd_drag->mime_type = mime_type;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400265 if (mime_type)
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400266 surface = dnd_drag->opaque;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400267 else
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400268 surface = dnd_drag->translucent;
269
270 buffer = display_get_buffer_for_surface(dnd->display, surface);
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200271 wl_surface_attach(dnd_drag->drag_surface, buffer, 0, 0);
Kristian Høgsberg679f7162012-03-27 16:44:57 -0400272 wl_surface_damage(dnd_drag->drag_surface, 0, 0,
273 dnd_drag->width, dnd_drag->height);
Pekka Paalanenc9e00c02012-10-10 12:49:24 +0300274 wl_surface_commit(dnd_drag->drag_surface);
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400275}
276
277static void
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400278data_source_send(void *data, struct wl_data_source *source,
279 const char *mime_type, int32_t fd)
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400280{
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800281 struct dnd_flower_message dnd_flower_message;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400282 struct dnd_drag *dnd_drag = data;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800283
284 dnd_flower_message.seed = dnd_drag->item->seed;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800285 dnd_flower_message.x_offset = dnd_drag->x_offset;
286 dnd_flower_message.y_offset = dnd_drag->y_offset;
287
Jonas Ådahl3685c3a2012-03-30 23:10:27 +0200288 if (write(fd, &dnd_flower_message, sizeof dnd_flower_message) < 0)
289 abort();
290
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400291 close(fd);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400292}
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400293
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400294static void
295data_source_cancelled(void *data, struct wl_data_source *source)
296{
297 struct dnd_drag *dnd_drag = data;
298
299 /* The 'cancelled' event means that the source is no longer in
300 * use by the drag (or current selection). We need to clean
301 * up the drag object created and the local state. */
302
303 wl_data_source_destroy(dnd_drag->data_source);
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800304
305 /* Destroy the item that has been dragged out */
306 cairo_surface_destroy(dnd_drag->item->surface);
307 free(dnd_drag->item);
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200308
309 wl_surface_destroy(dnd_drag->drag_surface);
310
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400311 cairo_surface_destroy(dnd_drag->translucent);
312 cairo_surface_destroy(dnd_drag->opaque);
313 free(dnd_drag);
314}
315
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400316static const struct wl_data_source_listener data_source_listener = {
317 data_source_target,
318 data_source_send,
319 data_source_cancelled
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400320};
321
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400322static cairo_surface_t *
323create_drag_cursor(struct dnd_drag *dnd_drag,
324 struct item *item, int32_t x, int32_t y, double opacity)
325{
326 struct dnd *dnd = dnd_drag->dnd;
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +0300327 cairo_surface_t *surface;
328 struct wl_cursor_image *pointer;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400329 struct rectangle rectangle;
330 cairo_pattern_t *pattern;
331 cairo_t *cr;
332
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +0300333 pointer = display_get_pointer_image(dnd->display, CURSOR_DRAGGING);
Philipp Brüschweilerf22d0ec2012-08-13 20:04:54 +0200334 if (!pointer) {
335 fprintf(stderr, "WARNING: grabbing cursor image not found\n");
336 pointer = display_get_pointer_image(dnd->display,
337 CURSOR_LEFT_PTR);
338 assert(pointer && "no cursor image found");
339 }
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400340
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +0300341 rectangle.width = item_width + 2 * pointer->width;
342 rectangle.height = item_height + 2 * pointer->height;
Ander Conselvan de Oliveira210eb9d2012-05-25 16:03:06 +0300343 surface = display_create_surface(dnd->display, NULL, &rectangle,
344 SURFACE_SHM);
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400345
346 cr = cairo_create(surface);
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +0300347 cairo_translate(cr, pointer->width, pointer->height);
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400348
349 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
350 cairo_set_source_rgba(cr, 0, 0, 0, 0);
351 cairo_paint(cr);
352
353 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
354 cairo_set_source_surface(cr, item->surface, 0, 0);
355 pattern = cairo_pattern_create_rgba(0, 0, 0, opacity);
356 cairo_mask(cr, pattern);
357 cairo_pattern_destroy(pattern);
358
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400359 /* FIXME: more cairo-gl brokeness */
Benjamin Franzke47eb8f42011-10-07 09:08:56 +0200360 surface_flush_device(surface);
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400361 cairo_destroy(cr);
362
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +0300363 dnd_drag->hotspot_x = pointer->width + x - item->x;
364 dnd_drag->hotspot_y = pointer->height + y - item->y;
Kristian Høgsberg679f7162012-03-27 16:44:57 -0400365 dnd_drag->width = rectangle.width;
366 dnd_drag->height = rectangle.height;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400367
368 return surface;
369}
370
Kristian Høgsberg506e20e2010-08-19 17:26:02 -0400371static void
Kristian Høgsberga8a0db32012-01-09 11:12:05 -0500372dnd_button_handler(struct widget *widget,
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400373 struct input *input, uint32_t time,
Daniel Stone4dbadb12012-05-30 16:31:51 +0100374 uint32_t button, enum wl_pointer_button_state state,
375 void *data)
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400376{
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500377 struct dnd *dnd = data;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400378 int32_t x, y;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400379 struct item *item;
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500380 struct rectangle allocation;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400381 struct dnd_drag *dnd_drag;
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200382 struct display *display;
383 struct wl_compositor *compositor;
384 struct wl_buffer *buffer;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400385 unsigned int i;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400386 uint32_t serial;
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300387 cairo_surface_t *icon;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400388
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500389 widget_get_allocation(dnd->widget, &allocation);
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400390 input_get_position(input, &x, &y);
391 item = dnd_get_item(dnd, x, y);
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500392 x -= allocation.x;
393 y -= allocation.y;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400394
Daniel Stone4dbadb12012-05-30 16:31:51 +0100395 if (item && state == WL_POINTER_BUTTON_STATE_PRESSED) {
Brian Lovinbc919262013-08-07 15:34:59 -0700396 dnd_drag = xmalloc(sizeof *dnd_drag);
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400397 dnd_drag->dnd = dnd;
398 dnd_drag->input = input;
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400399 dnd_drag->time = time;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800400 dnd_drag->item = item;
401 dnd_drag->x_offset = x - item->x;
402 dnd_drag->y_offset = y - item->y;
403
404 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
405 if (item == dnd->items[i]){
406 dnd->items[i] = 0;
407 break;
408 }
409 }
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400410
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200411 display = window_get_display(dnd->window);
412 compositor = display_get_compositor(display);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400413 serial = display_get_serial(display);
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200414 dnd_drag->drag_surface =
415 wl_compositor_create_surface(compositor);
416
Kristian Høgsberga6c8b002012-04-13 12:55:45 -0400417 input_ungrab(input);
418
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300419 if (dnd->self_only) {
420 dnd_drag->data_source = NULL;
421 } else {
422 dnd_drag->data_source =
423 display_create_data_source(dnd->display);
424 wl_data_source_add_listener(dnd_drag->data_source,
425 &data_source_listener,
426 dnd_drag);
427 wl_data_source_offer(dnd_drag->data_source,
428 "application/x-wayland-dnd-flower");
429 wl_data_source_offer(dnd_drag->data_source,
430 "text/plain; charset=utf-8");
431 }
432
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400433 wl_data_device_start_drag(input_get_data_device(input),
434 dnd_drag->data_source,
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500435 window_get_wl_surface(dnd->window),
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200436 dnd_drag->drag_surface,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400437 serial);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400438
Kristian Høgsberg5a4e9ff2012-06-04 16:04:07 -0400439 input_set_pointer_image(input, CURSOR_DRAGGING);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400440
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400441 dnd_drag->opaque =
442 create_drag_cursor(dnd_drag, item, x, y, 1);
443 dnd_drag->translucent =
444 create_drag_cursor(dnd_drag, item, x, y, 0.2);
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -0400445
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300446 if (dnd->self_only)
447 icon = dnd_drag->opaque;
448 else
449 icon = dnd_drag->translucent;
450
451 buffer = display_get_buffer_for_surface(dnd->display, icon);
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200452 wl_surface_attach(dnd_drag->drag_surface, buffer,
453 -dnd_drag->hotspot_x, -dnd_drag->hotspot_y);
Kristian Høgsberg679f7162012-03-27 16:44:57 -0400454 wl_surface_damage(dnd_drag->drag_surface, 0, 0,
455 dnd_drag->width, dnd_drag->height);
Pekka Paalanenc9e00c02012-10-10 12:49:24 +0300456 wl_surface_commit(dnd_drag->drag_surface);
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200457
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300458 dnd->current_drag = dnd_drag;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800459 window_schedule_redraw(dnd->window);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400460 }
461}
462
463static int
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400464lookup_cursor(struct dnd *dnd, int x, int y)
465{
466 struct item *item;
467
468 item = dnd_get_item(dnd, x, y);
469 if (item)
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +0300470 return CURSOR_HAND1;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400471 else
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +0300472 return CURSOR_LEFT_PTR;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400473}
474
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -0500475static int
Kristian Høgsbergac7619f2012-01-09 09:26:38 -0500476dnd_enter_handler(struct widget *widget,
Kristian Høgsberg80680c72012-05-10 12:21:37 -0400477 struct input *input, float x, float y, void *data)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400478{
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300479 struct dnd *dnd = data;
480
481 dnd->current_drag = NULL;
482
483 return lookup_cursor(dnd, x, y);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400484}
485
486static int
Kristian Høgsberg5f190ef2012-01-09 09:44:45 -0500487dnd_motion_handler(struct widget *widget,
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400488 struct input *input, uint32_t time,
Kristian Høgsberg80680c72012-05-10 12:21:37 -0400489 float x, float y, void *data)
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400490{
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500491 return lookup_cursor(data, x, y);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400492}
493
494static void
495dnd_data_handler(struct window *window,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400496 struct input *input,
Kristian Høgsberg80680c72012-05-10 12:21:37 -0400497 float x, float y, const char **types, void *data)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400498{
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400499 struct dnd *dnd = data;
Kristian Høgsberg938f1022013-09-04 19:36:49 -0700500 int i, has_flower = 0;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400501
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300502 if (!types)
503 return;
Kristian Høgsberg938f1022013-09-04 19:36:49 -0700504 for (i = 0; types[i]; i++)
505 if (strcmp(types[i], flower_mime_type) == 0)
506 has_flower = 1;
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300507
Kristian Høgsberg938f1022013-09-04 19:36:49 -0700508 if (dnd_get_item(dnd, x, y) || dnd->self_only || !has_flower) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400509 input_accept(input, NULL);
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300510 } else {
Kristian Høgsberg938f1022013-09-04 19:36:49 -0700511 input_accept(input, flower_mime_type);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400512 }
513}
514
515static void
516dnd_receive_func(void *data, size_t len, int32_t x, int32_t y, void *user_data)
517{
518 struct dnd *dnd = user_data;
519 struct dnd_flower_message *message = data;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400520 struct item *item;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400521 struct rectangle allocation;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400522
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400523 if (len == 0) {
524 return;
525 } else if (len != sizeof *message) {
Damien Lespiau4df7e272012-10-26 01:15:44 +0100526 fprintf(stderr, "odd message length %zu, expected %zu\n",
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400527 len, sizeof *message);
528 return;
529 }
530
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500531 widget_get_allocation(dnd->widget, &allocation);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400532 item = item_create(dnd->display,
533 x - message->x_offset - allocation.x,
534 y - message->y_offset - allocation.y,
535 message->seed);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400536
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400537 dnd_add_item(dnd, item);
538 window_schedule_redraw(dnd->window);
539}
540
541static void
542dnd_drop_handler(struct window *window, struct input *input,
543 int32_t x, int32_t y, void *data)
544{
545 struct dnd *dnd = data;
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300546 struct dnd_flower_message message;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400547
548 if (dnd_get_item(dnd, x, y)) {
549 fprintf(stderr, "got 'drop', but no target\n");
550 return;
551 }
552
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300553 if (!dnd->self_only) {
554 input_receive_drag_data(input,
Kristian Høgsberg938f1022013-09-04 19:36:49 -0700555 flower_mime_type,
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300556 dnd_receive_func, dnd);
557 } else if (dnd->current_drag) {
558 message.seed = dnd->current_drag->item->seed;
559 message.x_offset = dnd->current_drag->x_offset;
560 message.y_offset = dnd->current_drag->y_offset;
561 dnd_receive_func(&message, sizeof message, x, y, dnd);
562 dnd->current_drag = NULL;
563 } else {
564 fprintf(stderr, "ignoring drop from another client\n");
565 }
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400566}
567
568static struct dnd *
569dnd_create(struct display *display)
570{
571 struct dnd *dnd;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400572 int x, y;
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500573 int32_t width, height;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400574 unsigned int i;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400575
Peter Huttererf3d62272013-08-08 11:57:05 +1000576 dnd = xzalloc(sizeof *dnd);
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -0500577 dnd->window = window_create(display);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -0500578 dnd->widget = frame_create(dnd->window, dnd);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500579 window_set_title(dnd->window, "Wayland Drag and Drop Demo");
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400580
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400581 dnd->display = display;
582 dnd->key = 100;
583
584 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
585 x = (i % 4) * (item_width + item_padding) + item_padding;
586 y = (i / 4) * (item_height + item_padding) + item_padding;
587 if ((i ^ (i >> 2)) & 1)
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800588 dnd->items[i] = item_create(display, x, y, 0);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400589 else
590 dnd->items[i] = NULL;
591 }
592
593 window_set_user_data(dnd->window, dnd);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400594 window_set_keyboard_focus_handler(dnd->window,
595 keyboard_focus_handler);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400596 window_set_data_handler(dnd->window, dnd_data_handler);
597 window_set_drop_handler(dnd->window, dnd_drop_handler);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400598
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500599 widget_set_redraw_handler(dnd->widget, dnd_redraw_handler);
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500600 widget_set_enter_handler(dnd->widget, dnd_enter_handler);
601 widget_set_motion_handler(dnd->widget, dnd_motion_handler);
602 widget_set_button_handler(dnd->widget, dnd_button_handler);
Kristian Høgsbergac7619f2012-01-09 09:26:38 -0500603
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500604 width = 4 * (item_width + item_padding) + item_padding;
605 height = 4 * (item_height + item_padding) + item_padding;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400606
Kristian Høgsberga1627922012-06-20 17:30:03 -0400607 frame_set_child_size(dnd->widget, width, height);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400608
609 return dnd;
610}
611
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400612int
613main(int argc, char *argv[])
614{
615 struct display *d;
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300616 struct dnd *dnd;
617 int i;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400618
Kristian Høgsberg4172f662013-02-20 15:27:49 -0500619 d = display_create(&argc, argv);
Yuval Fledele9f5e362010-11-22 21:34:19 +0200620 if (d == NULL) {
621 fprintf(stderr, "failed to create display: %m\n");
622 return -1;
623 }
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400624
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300625 dnd = dnd_create(d);
626
627 for (i = 1; i < argc; i++)
628 if (strcmp("--self-only", argv[i]) == 0)
629 dnd->self_only = 1;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400630
631 display_run(d);
632
633 return 0;
634}