blob: cff7804681655a596036954264edec88c5e643b6 [file] [log] [blame]
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -04001/*
2 * Copyright © 2010 Kristian Høgsberg
3 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -07004 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040010 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -070011 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040022 */
23
Andrew Wedgbury9cd661e2014-04-07 12:40:35 +010024#include "config.h"
25
Philipp Brüschweilerf22d0ec2012-08-13 20:04:54 +020026#include <assert.h>
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040027#include <stdint.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <math.h>
34#include <sys/time.h>
35#include <cairo.h>
Kristian Høgsberg3a696272011-09-14 17:33:48 -040036#include <sys/epoll.h>
Derek Foremanba0f33d2014-11-20 15:32:40 -060037#include <stdbool.h>
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040038
Pekka Paalanen50719bc2011-11-22 14:18:50 +020039#include <wayland-client.h>
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +030040#include <wayland-cursor.h>
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040041
42#include "window.h"
Kristian Høgsberg5a315bc2012-05-15 22:33:43 -040043#include "../shared/cairo-util.h"
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040044
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +030045struct dnd_drag;
46
Derek Foremanba0f33d2014-11-20 15:32:40 -060047struct pointer {
48 struct input *input;
49 bool dragging;
50 struct wl_list link;
51};
52
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040053struct dnd {
54 struct window *window;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -050055 struct widget *widget;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040056 struct display *display;
57 uint32_t key;
58 struct item *items[16];
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +030059 int self_only;
60 struct dnd_drag *current_drag;
Derek Foremanba0f33d2014-11-20 15:32:40 -060061 struct wl_list pointers;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -040062};
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -040063
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -040064struct dnd_drag {
65 cairo_surface_t *translucent;
66 cairo_surface_t *opaque;
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -040067 int hotspot_x, hotspot_y;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -040068 struct dnd *dnd;
69 struct input *input;
Kristian Høgsbergce457ba2010-09-14 15:39:45 -040070 uint32_t time;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080071 struct item *item;
72 int x_offset, y_offset;
Kristian Høgsberg679f7162012-03-27 16:44:57 -040073 int width, height;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080074 const char *mime_type;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -040075
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +020076 struct wl_surface *drag_surface;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -040077 struct wl_data_source *data_source;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040078};
79
80struct item {
81 cairo_surface_t *surface;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080082 int seed;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040083 int x, y;
84};
85
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080086struct dnd_flower_message {
87 int seed, x_offset, y_offset;
88};
89
90
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040091static const int item_width = 64;
92static const int item_height = 64;
93static const int item_padding = 16;
94
Kristian Høgsberg938f1022013-09-04 19:36:49 -070095static const char flower_mime_type[] = "application/x-wayland-dnd-flower";
Kristian Høgsberg735bda22013-09-09 15:03:27 -070096static const char text_mime_type[] = "text/plain;charset=utf-8";
Kristian Høgsberg938f1022013-09-04 19:36:49 -070097
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -040098static struct item *
Joel Teichroeb0c007ae2010-11-30 10:22:16 -080099item_create(struct display *display, int x, int y, int seed)
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400100{
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800101 struct item *item;
102 struct timeval tv;
103
104 item = malloc(sizeof *item);
105 if (item == NULL)
106 return NULL;
Michael Vetter2a18a522015-05-15 17:17:47 +0200107
108
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800109 gettimeofday(&tv, NULL);
110 item->seed = seed ? seed : tv.tv_usec;
111 srandom(item->seed);
Michael Vetter2a18a522015-05-15 17:17:47 +0200112
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400113 const int petal_count = 3 + random() % 5;
114 const double r1 = 20 + random() % 10;
115 const double r2 = 5 + random() % 12;
116 const double u = (10 + random() % 90) / 100.0;
117 const double v = (random() % 90) / 100.0;
118
119 cairo_t *cr;
120 int i;
121 double t, dt = 2 * M_PI / (petal_count * 2);
122 double x1, y1, x2, y2, x3, y3;
123 struct rectangle rect;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400124
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400125
126 rect.width = item_width;
127 rect.height = item_height;
Ander Conselvan de Oliveira210eb9d2012-05-25 16:03:06 +0300128 item->surface =
129 display_create_surface(display, NULL, &rect, SURFACE_SHM);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400130
131 item->x = x;
132 item->y = y;
133
134 cr = cairo_create(item->surface);
135 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
136 cairo_set_source_rgba(cr, 0, 0, 0, 0);
137 cairo_paint(cr);
138
139 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
140 cairo_translate(cr, item_width / 2, item_height / 2);
141 t = random();
142 cairo_move_to(cr, cos(t) * r1, sin(t) * r1);
143 for (i = 0; i < petal_count; i++, t += dt * 2) {
144 x1 = cos(t) * r1;
145 y1 = sin(t) * r1;
146 x2 = cos(t + dt) * r2;
147 y2 = sin(t + dt) * r2;
148 x3 = cos(t + 2 * dt) * r1;
149 y3 = sin(t + 2 * dt) * r1;
150
151 cairo_curve_to(cr,
152 x1 - y1 * u, y1 + x1 * u,
153 x2 + y2 * v, y2 - x2 * v,
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400154 x2, y2);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400155
156 cairo_curve_to(cr,
157 x2 - y2 * v, y2 + x2 * v,
158 x3 + y3 * u, y3 - x3 * u,
159 x3, y3);
160 }
161
162 cairo_close_path(cr);
163
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
170 cairo_fill_preserve(cr);
171
172 cairo_set_line_width(cr, 1);
173 cairo_set_source_rgba(cr,
174 0.5 + (random() % 50) / 49.0,
175 0.5 + (random() % 50) / 49.0,
176 0.5 + (random() % 50) / 49.0,
177 0.5 + (random() % 100) / 99.0);
178 cairo_stroke(cr);
179
180 cairo_destroy(cr);
181
182 return item;
183}
184
185static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500186dnd_redraw_handler(struct widget *widget, void *data)
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400187{
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500188 struct dnd *dnd = data;
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500189 struct rectangle allocation;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400190 cairo_t *cr;
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500191 cairo_surface_t *surface;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400192 unsigned int i;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400193
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500194 surface = window_get_surface(dnd->window);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400195 cr = cairo_create(surface);
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500196 widget_get_allocation(dnd->widget, &allocation);
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500197 cairo_rectangle(cr, allocation.x, allocation.y,
198 allocation.width, allocation.height);
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500199
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400200 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
201 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400202 cairo_fill(cr);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400203
Kristian Høgsberg0fd49aa2012-07-23 21:32:46 -0400204 cairo_rectangle(cr, allocation.x, allocation.y,
205 allocation.width, allocation.height);
206 cairo_clip(cr);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400207 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
208 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
209 if (!dnd->items[i])
210 continue;
211 cairo_set_source_surface(cr, dnd->items[i]->surface,
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400212 dnd->items[i]->x + allocation.x,
213 dnd->items[i]->y + allocation.y);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400214 cairo_paint(cr);
215 }
216
217 cairo_destroy(cr);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400218 cairo_surface_destroy(surface);
219}
220
221static void
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400222keyboard_focus_handler(struct window *window,
223 struct input *device, void *data)
224{
225 struct dnd *dnd = data;
226
227 window_schedule_redraw(dnd->window);
228}
229
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800230static int
231dnd_add_item(struct dnd *dnd, struct item *item)
232{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400233 unsigned int i;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800234
235 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
236 if (dnd->items[i] == 0) {
237 dnd->items[i] = item;
238 return i;
239 }
240 }
241 return -1;
242}
243
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400244static struct item *
245dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
246{
247 struct item *item;
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500248 struct rectangle allocation;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400249 unsigned int i;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400250
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500251 widget_get_allocation(dnd->widget, &allocation);
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400252
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500253 x -= allocation.x;
254 y -= allocation.y;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400255
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400256 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
257 item = dnd->items[i];
258 if (item &&
259 item->x <= x && x < item->x + item_width &&
260 item->y <= y && y < item->y + item_height)
261 return item;
262 }
263
264 return NULL;
265}
266
267static void
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400268data_source_target(void *data,
269 struct wl_data_source *source, const char *mime_type)
Kristian Høgsberg506e20e2010-08-19 17:26:02 -0400270{
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400271 struct dnd_drag *dnd_drag = data;
272 struct dnd *dnd = dnd_drag->dnd;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400273 cairo_surface_t *surface;
274 struct wl_buffer *buffer;
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -0400275
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800276 dnd_drag->mime_type = mime_type;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400277 if (mime_type)
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400278 surface = dnd_drag->opaque;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400279 else
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400280 surface = dnd_drag->translucent;
281
282 buffer = display_get_buffer_for_surface(dnd->display, surface);
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200283 wl_surface_attach(dnd_drag->drag_surface, buffer, 0, 0);
Kristian Høgsberg679f7162012-03-27 16:44:57 -0400284 wl_surface_damage(dnd_drag->drag_surface, 0, 0,
285 dnd_drag->width, dnd_drag->height);
Pekka Paalanenc9e00c02012-10-10 12:49:24 +0300286 wl_surface_commit(dnd_drag->drag_surface);
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400287}
288
289static void
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400290data_source_send(void *data, struct wl_data_source *source,
291 const char *mime_type, int32_t fd)
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400292{
Michael Vetter2a18a522015-05-15 17:17:47 +0200293 struct dnd_flower_message dnd_flower_message;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400294 struct dnd_drag *dnd_drag = data;
Kristian Høgsberg735bda22013-09-09 15:03:27 -0700295 char buffer[128];
296 int n;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800297
Kristian Høgsberg735bda22013-09-09 15:03:27 -0700298 if (strcmp(mime_type, flower_mime_type) == 0) {
299 dnd_flower_message.seed = dnd_drag->item->seed;
300 dnd_flower_message.x_offset = dnd_drag->x_offset;
301 dnd_flower_message.y_offset = dnd_drag->y_offset;
302
303 if (write(fd, &dnd_flower_message,
304 sizeof dnd_flower_message) < 0)
305 abort();
306 } else if (strcmp(mime_type, text_mime_type) == 0) {
307 n = snprintf(buffer, sizeof buffer, "seed=%d x=%d y=%d\n",
308 dnd_drag->item->seed,
309 dnd_drag->x_offset,
310 dnd_drag->y_offset);
311
312 if (write(fd, buffer, n) < 0)
313 abort();
314 }
Jonas Ådahl3685c3a2012-03-30 23:10:27 +0200315
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400316 close(fd);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400317}
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400318
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400319static void
320data_source_cancelled(void *data, struct wl_data_source *source)
321{
322 struct dnd_drag *dnd_drag = data;
323
324 /* The 'cancelled' event means that the source is no longer in
325 * use by the drag (or current selection). We need to clean
326 * up the drag object created and the local state. */
327
328 wl_data_source_destroy(dnd_drag->data_source);
Michael Vetter2a18a522015-05-15 17:17:47 +0200329
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800330 /* Destroy the item that has been dragged out */
331 cairo_surface_destroy(dnd_drag->item->surface);
332 free(dnd_drag->item);
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200333
334 wl_surface_destroy(dnd_drag->drag_surface);
335
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400336 cairo_surface_destroy(dnd_drag->translucent);
337 cairo_surface_destroy(dnd_drag->opaque);
338 free(dnd_drag);
339}
340
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400341static const struct wl_data_source_listener data_source_listener = {
342 data_source_target,
343 data_source_send,
344 data_source_cancelled
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400345};
346
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400347static cairo_surface_t *
Kristian Høgsberg617e9a32013-11-22 11:37:16 -0800348create_drag_icon(struct dnd_drag *dnd_drag,
349 struct item *item, int32_t x, int32_t y, double opacity)
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400350{
351 struct dnd *dnd = dnd_drag->dnd;
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +0300352 cairo_surface_t *surface;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400353 struct rectangle rectangle;
354 cairo_pattern_t *pattern;
355 cairo_t *cr;
356
Kristian Høgsberg617e9a32013-11-22 11:37:16 -0800357 rectangle.width = item_width;
358 rectangle.height = item_height;
Ander Conselvan de Oliveira210eb9d2012-05-25 16:03:06 +0300359 surface = display_create_surface(dnd->display, NULL, &rectangle,
360 SURFACE_SHM);
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400361
362 cr = cairo_create(surface);
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400363 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400364 cairo_set_source_surface(cr, item->surface, 0, 0);
365 pattern = cairo_pattern_create_rgba(0, 0, 0, opacity);
366 cairo_mask(cr, pattern);
367 cairo_pattern_destroy(pattern);
368
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400369 cairo_destroy(cr);
370
Kristian Høgsberg617e9a32013-11-22 11:37:16 -0800371 dnd_drag->hotspot_x = x - item->x;
372 dnd_drag->hotspot_y = y - item->y;
Kristian Høgsberg679f7162012-03-27 16:44:57 -0400373 dnd_drag->width = rectangle.width;
374 dnd_drag->height = rectangle.height;
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400375
376 return surface;
377}
378
Xiong Zhang853a7792013-11-25 18:42:50 +0800379static int
380create_drag_source(struct dnd *dnd,
381 struct input *input, uint32_t time,
382 int32_t x, int32_t y)
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400383{
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400384 struct item *item;
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500385 struct rectangle allocation;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400386 struct dnd_drag *dnd_drag;
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200387 struct display *display;
388 struct wl_compositor *compositor;
389 struct wl_buffer *buffer;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400390 unsigned int i;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400391 uint32_t serial;
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300392 cairo_surface_t *icon;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400393
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500394 widget_get_allocation(dnd->widget, &allocation);
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400395 item = dnd_get_item(dnd, x, y);
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500396 x -= allocation.x;
397 y -= allocation.y;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400398
Xiong Zhang853a7792013-11-25 18:42:50 +0800399 if (item) {
Brian Lovinbc919262013-08-07 15:34:59 -0700400 dnd_drag = xmalloc(sizeof *dnd_drag);
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400401 dnd_drag->dnd = dnd;
402 dnd_drag->input = input;
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400403 dnd_drag->time = time;
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800404 dnd_drag->item = item;
405 dnd_drag->x_offset = x - item->x;
406 dnd_drag->y_offset = y - item->y;
407
408 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
409 if (item == dnd->items[i]){
410 dnd->items[i] = 0;
411 break;
412 }
413 }
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400414
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200415 display = window_get_display(dnd->window);
416 compositor = display_get_compositor(display);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400417 serial = display_get_serial(display);
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200418 dnd_drag->drag_surface =
419 wl_compositor_create_surface(compositor);
420
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300421 if (dnd->self_only) {
422 dnd_drag->data_source = NULL;
423 } else {
424 dnd_drag->data_source =
425 display_create_data_source(dnd->display);
426 wl_data_source_add_listener(dnd_drag->data_source,
427 &data_source_listener,
428 dnd_drag);
429 wl_data_source_offer(dnd_drag->data_source,
Kristian Høgsberg735bda22013-09-09 15:03:27 -0700430 flower_mime_type);
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300431 wl_data_source_offer(dnd_drag->data_source,
Kristian Høgsberg735bda22013-09-09 15:03:27 -0700432 text_mime_type);
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300433 }
434
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400435 wl_data_device_start_drag(input_get_data_device(input),
436 dnd_drag->data_source,
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500437 window_get_wl_surface(dnd->window),
Ander Conselvan de Oliveirae47c3a32012-02-15 17:02:58 +0200438 dnd_drag->drag_surface,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400439 serial);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400440
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400441 dnd_drag->opaque =
Kristian Høgsberg617e9a32013-11-22 11:37:16 -0800442 create_drag_icon(dnd_drag, item, x, y, 1);
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400443 dnd_drag->translucent =
Kristian Høgsberg617e9a32013-11-22 11:37:16 -0800444 create_drag_icon(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);
Xiong Zhang853a7792013-11-25 18:42:50 +0800460
461 return 0;
462 } else
463 return -1;
464}
465
Derek Foremanba0f33d2014-11-20 15:32:40 -0600466static int
467lookup_cursor(struct dnd *dnd, int x, int y)
468{
469 struct item *item;
470
471 item = dnd_get_item(dnd, x, y);
472 if (item)
473 return CURSOR_HAND1;
474 else
475 return CURSOR_LEFT_PTR;
476}
477
478/* Update all the mouse pointers in the window appropriately.
479 * Optionally, skip one (which will be the current pointer just
480 * about to start a drag). This is done here to save a scan
481 * through the pointer list.
482 */
483static void
484update_pointer_images_except(struct dnd *dnd, struct input *except)
485{
486 struct pointer *pointer;
487 int32_t x, y;
488
489 wl_list_for_each(pointer, &dnd->pointers, link) {
490 if (pointer->input == except) {
491 pointer->dragging = true;
492 continue;
493 }
494 input_get_position(pointer->input, &x, &y);
495 input_set_pointer_image(pointer->input,
496 lookup_cursor(dnd, x, y));
497 }
498}
499
Xiong Zhang853a7792013-11-25 18:42:50 +0800500static void
501dnd_button_handler(struct widget *widget,
502 struct input *input, uint32_t time,
503 uint32_t button, enum wl_pointer_button_state state,
504 void *data)
505{
506 struct dnd *dnd = data;
507 int32_t x, y;
508
509 input_get_position(input, &x, &y);
510 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
511 input_ungrab(input);
Derek Foremanba0f33d2014-11-20 15:32:40 -0600512 if (create_drag_source(dnd, input, time, x, y) == 0) {
Xiong Zhang853a7792013-11-25 18:42:50 +0800513 input_set_pointer_image(input, CURSOR_DRAGGING);
Derek Foremanba0f33d2014-11-20 15:32:40 -0600514 update_pointer_images_except(dnd, input);
515 }
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400516 }
517}
518
Xiong Zhang853a7792013-11-25 18:42:50 +0800519static void
520dnd_touch_down_handler(struct widget *widget,
521 struct input *input, uint32_t serial,
522 uint32_t time, int32_t id,
523 float x, float y, void *data)
524{
525 struct dnd *dnd = data;
526 int32_t int_x, int_y;
527
528 if (id > 0)
529 return;
530
531 int_x = (int32_t)x;
532 int_y = (int32_t)y;
Xiong Zhangbf3c1c62013-11-25 18:42:51 +0800533 if (create_drag_source(dnd, input, time, int_x, int_y) == 0)
534 touch_grab(input, 0);
Xiong Zhang853a7792013-11-25 18:42:50 +0800535}
536
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400537static int
Kristian Høgsbergac7619f2012-01-09 09:26:38 -0500538dnd_enter_handler(struct widget *widget,
Kristian Høgsberg80680c72012-05-10 12:21:37 -0400539 struct input *input, float x, float y, void *data)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400540{
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300541 struct dnd *dnd = data;
Derek Foremanba0f33d2014-11-20 15:32:40 -0600542 struct pointer *new_pointer = malloc(sizeof *new_pointer);
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300543
544 dnd->current_drag = NULL;
545
Derek Foremanba0f33d2014-11-20 15:32:40 -0600546 if (new_pointer) {
547 new_pointer->input = input;
548 new_pointer->dragging = false;
549 wl_list_insert(dnd->pointers.prev, &new_pointer->link);
550 }
551
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300552 return lookup_cursor(dnd, x, y);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400553}
554
Derek Foremanba0f33d2014-11-20 15:32:40 -0600555static void
556dnd_leave_handler(struct widget *widget,
557 struct input *input, void *data)
558{
559 struct dnd *dnd = data;
560 struct pointer *pointer, *tmp;
561
562 wl_list_for_each_safe(pointer, tmp, &dnd->pointers, link)
563 if (pointer->input == input) {
564 wl_list_remove(&pointer->link);
565 free(pointer);
566 }
567}
568
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400569static int
Kristian Høgsberg5f190ef2012-01-09 09:44:45 -0500570dnd_motion_handler(struct widget *widget,
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400571 struct input *input, uint32_t time,
Kristian Høgsberg80680c72012-05-10 12:21:37 -0400572 float x, float y, void *data)
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400573{
Derek Foremanba0f33d2014-11-20 15:32:40 -0600574 struct dnd *dnd = data;
575 struct pointer *pointer;
576
577 wl_list_for_each(pointer, &dnd->pointers, link)
578 if (pointer->input == input) {
579 if (pointer->dragging)
580 return CURSOR_DRAGGING;
581 break;
582 }
583
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500584 return lookup_cursor(data, x, y);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400585}
586
587static void
588dnd_data_handler(struct window *window,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400589 struct input *input,
Kristian Høgsberg80680c72012-05-10 12:21:37 -0400590 float x, float y, const char **types, void *data)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400591{
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400592 struct dnd *dnd = data;
Kristian Høgsberg938f1022013-09-04 19:36:49 -0700593 int i, has_flower = 0;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400594
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300595 if (!types)
596 return;
Kristian Høgsberg938f1022013-09-04 19:36:49 -0700597 for (i = 0; types[i]; i++)
598 if (strcmp(types[i], flower_mime_type) == 0)
599 has_flower = 1;
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300600
Kristian Høgsberg938f1022013-09-04 19:36:49 -0700601 if (dnd_get_item(dnd, x, y) || dnd->self_only || !has_flower) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400602 input_accept(input, NULL);
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300603 } else {
Kristian Høgsberg938f1022013-09-04 19:36:49 -0700604 input_accept(input, flower_mime_type);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400605 }
606}
607
608static void
609dnd_receive_func(void *data, size_t len, int32_t x, int32_t y, void *user_data)
610{
611 struct dnd *dnd = user_data;
612 struct dnd_flower_message *message = data;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400613 struct item *item;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400614 struct rectangle allocation;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400615
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400616 if (len == 0) {
617 return;
618 } else if (len != sizeof *message) {
Damien Lespiau4df7e272012-10-26 01:15:44 +0100619 fprintf(stderr, "odd message length %zu, expected %zu\n",
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400620 len, sizeof *message);
621 return;
622 }
Michael Vetter2a18a522015-05-15 17:17:47 +0200623
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500624 widget_get_allocation(dnd->widget, &allocation);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400625 item = item_create(dnd->display,
626 x - message->x_offset - allocation.x,
627 y - message->y_offset - allocation.y,
628 message->seed);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400629
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400630 dnd_add_item(dnd, item);
Derek Foremanba0f33d2014-11-20 15:32:40 -0600631 update_pointer_images_except(dnd, NULL);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400632 window_schedule_redraw(dnd->window);
633}
634
635static void
636dnd_drop_handler(struct window *window, struct input *input,
637 int32_t x, int32_t y, void *data)
638{
639 struct dnd *dnd = data;
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300640 struct dnd_flower_message message;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400641
642 if (dnd_get_item(dnd, x, y)) {
643 fprintf(stderr, "got 'drop', but no target\n");
644 return;
645 }
646
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300647 if (!dnd->self_only) {
648 input_receive_drag_data(input,
Kristian Høgsberg938f1022013-09-04 19:36:49 -0700649 flower_mime_type,
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300650 dnd_receive_func, dnd);
651 } else if (dnd->current_drag) {
652 message.seed = dnd->current_drag->item->seed;
653 message.x_offset = dnd->current_drag->x_offset;
654 message.y_offset = dnd->current_drag->y_offset;
655 dnd_receive_func(&message, sizeof message, x, y, dnd);
656 dnd->current_drag = NULL;
657 } else {
658 fprintf(stderr, "ignoring drop from another client\n");
659 }
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400660}
661
662static struct dnd *
663dnd_create(struct display *display)
664{
665 struct dnd *dnd;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400666 int x, y;
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500667 int32_t width, height;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400668 unsigned int i;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400669
Peter Huttererf3d62272013-08-08 11:57:05 +1000670 dnd = xzalloc(sizeof *dnd);
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -0500671 dnd->window = window_create(display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -0500672 dnd->widget = window_frame_create(dnd->window, dnd);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500673 window_set_title(dnd->window, "Wayland Drag and Drop Demo");
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400674
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400675 dnd->display = display;
676 dnd->key = 100;
677
Derek Foremanba0f33d2014-11-20 15:32:40 -0600678 wl_list_init(&dnd->pointers);
679
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400680 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
681 x = (i % 4) * (item_width + item_padding) + item_padding;
682 y = (i / 4) * (item_height + item_padding) + item_padding;
683 if ((i ^ (i >> 2)) & 1)
Joel Teichroeb0c007ae2010-11-30 10:22:16 -0800684 dnd->items[i] = item_create(display, x, y, 0);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400685 else
686 dnd->items[i] = NULL;
687 }
688
689 window_set_user_data(dnd->window, dnd);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400690 window_set_keyboard_focus_handler(dnd->window,
691 keyboard_focus_handler);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400692 window_set_data_handler(dnd->window, dnd_data_handler);
693 window_set_drop_handler(dnd->window, dnd_drop_handler);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400694
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500695 widget_set_redraw_handler(dnd->widget, dnd_redraw_handler);
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500696 widget_set_enter_handler(dnd->widget, dnd_enter_handler);
Derek Foremanba0f33d2014-11-20 15:32:40 -0600697 widget_set_leave_handler(dnd->widget, dnd_leave_handler);
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500698 widget_set_motion_handler(dnd->widget, dnd_motion_handler);
699 widget_set_button_handler(dnd->widget, dnd_button_handler);
Xiong Zhang853a7792013-11-25 18:42:50 +0800700 widget_set_touch_down_handler(dnd->widget, dnd_touch_down_handler);
Kristian Høgsbergac7619f2012-01-09 09:26:38 -0500701
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500702 width = 4 * (item_width + item_padding) + item_padding;
703 height = 4 * (item_height + item_padding) + item_padding;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400704
Jason Ekstrandee7fefc2013-10-13 19:08:38 -0500705 window_frame_set_child_size(dnd->widget, width, height);
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400706
707 return dnd;
708}
709
vivek31732f72014-05-15 18:58:16 +0530710static void
711dnd_destroy(struct dnd *dnd)
712{
713 widget_destroy(dnd->widget);
714 window_destroy(dnd->window);
715 free(dnd);
716}
717
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400718int
719main(int argc, char *argv[])
720{
721 struct display *d;
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300722 struct dnd *dnd;
Bill Spitzak6fd10c62014-08-08 12:59:57 -0700723 int self_only = 0;
724
725 if (argc == 2 && !strcmp(argv[1], "--self-only"))
726 self_only = 1;
727 else if (argc > 1) {
728 printf("Usage: %s [OPTIONS]\n --self-only\n", argv[0]);
729 return 1;
730 }
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400731
Kristian Høgsberg4172f662013-02-20 15:27:49 -0500732 d = display_create(&argc, argv);
Yuval Fledele9f5e362010-11-22 21:34:19 +0200733 if (d == NULL) {
734 fprintf(stderr, "failed to create display: %m\n");
735 return -1;
736 }
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400737
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +0300738 dnd = dnd_create(d);
Bill Spitzak6fd10c62014-08-08 12:59:57 -0700739 if (self_only)
740 dnd->self_only = 1;
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400741
742 display_run(d);
743
vivek31732f72014-05-15 18:58:16 +0530744 dnd_destroy(dnd);
745 display_destroy(d);
746
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400747 return 0;
748}