blob: 0557ed9b0be7d7ab8d70a9835d189933ecd8863a [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
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <fcntl.h>
28#include <unistd.h>
29#include <math.h>
30#include <sys/time.h>
31#include <cairo.h>
32#include <glib.h>
33#include <gdk-pixbuf/gdk-pixbuf.h>
34
35#include "wayland-client.h"
36#include "wayland-glib.h"
37
38#include "window.h"
39
40static const char socket_name[] = "\0wayland";
41
42struct dnd {
43 struct window *window;
44 struct display *display;
45 uint32_t key;
46 struct item *items[16];
47};
48
49struct item {
50 cairo_surface_t *surface;
51 int x, y;
52};
53
54static const int item_width = 64;
55static const int item_height = 64;
56static const int item_padding = 16;
57
58static struct item *
59item_create(struct display *display, int x, int y)
60{
61 const int petal_count = 3 + random() % 5;
62 const double r1 = 20 + random() % 10;
63 const double r2 = 5 + random() % 12;
64 const double u = (10 + random() % 90) / 100.0;
65 const double v = (random() % 90) / 100.0;
66
67 cairo_t *cr;
68 int i;
69 double t, dt = 2 * M_PI / (petal_count * 2);
70 double x1, y1, x2, y2, x3, y3;
71 struct rectangle rect;
72 struct item *item;
73
74 item = malloc(sizeof *item);
75 if (item == NULL)
76 return NULL;
77
78 rect.width = item_width;
79 rect.height = item_height;
80 item->surface = display_create_surface(display, &rect);
81
82 item->x = x;
83 item->y = y;
84
85 cr = cairo_create(item->surface);
86 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
87 cairo_set_source_rgba(cr, 0, 0, 0, 0);
88 cairo_paint(cr);
89
90 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
91 cairo_translate(cr, item_width / 2, item_height / 2);
92 t = random();
93 cairo_move_to(cr, cos(t) * r1, sin(t) * r1);
94 for (i = 0; i < petal_count; i++, t += dt * 2) {
95 x1 = cos(t) * r1;
96 y1 = sin(t) * r1;
97 x2 = cos(t + dt) * r2;
98 y2 = sin(t + dt) * r2;
99 x3 = cos(t + 2 * dt) * r1;
100 y3 = sin(t + 2 * dt) * r1;
101
102 cairo_curve_to(cr,
103 x1 - y1 * u, y1 + x1 * u,
104 x2 + y2 * v, y2 - x2 * v,
105 x2, y2);
106
107 cairo_curve_to(cr,
108 x2 - y2 * v, y2 + x2 * v,
109 x3 + y3 * u, y3 - x3 * u,
110 x3, y3);
111 }
112
113 cairo_close_path(cr);
114
115 cairo_set_source_rgba(cr,
116 0.5 + (random() % 50) / 49.0,
117 0.5 + (random() % 50) / 49.0,
118 0.5 + (random() % 50) / 49.0,
119 0.5 + (random() % 100) / 99.0);
120
121 cairo_fill_preserve(cr);
122
123 cairo_set_line_width(cr, 1);
124 cairo_set_source_rgba(cr,
125 0.5 + (random() % 50) / 49.0,
126 0.5 + (random() % 50) / 49.0,
127 0.5 + (random() % 50) / 49.0,
128 0.5 + (random() % 100) / 99.0);
129 cairo_stroke(cr);
130
131 cairo_destroy(cr);
132
133 return item;
134}
135
136static void
137dnd_draw(struct dnd *dnd)
138{
139 struct rectangle rectangle;
140 cairo_t *cr;
141 cairo_surface_t *wsurface, *surface;
142 int i;
143
144 window_draw(dnd->window);
145
146 window_get_child_rectangle(dnd->window, &rectangle);
147
148 wsurface = window_get_surface(dnd->window);
149 surface = cairo_surface_create_similar(wsurface,
150 CAIRO_CONTENT_COLOR_ALPHA,
151 rectangle.width,
152 rectangle.height);
153
154 cr = cairo_create(surface);
155 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
156 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
157 cairo_paint(cr);
158
159 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
160 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
161 if (!dnd->items[i])
162 continue;
163 cairo_set_source_surface(cr, dnd->items[i]->surface,
164 dnd->items[i]->x, dnd->items[i]->y);
165 cairo_paint(cr);
166 }
167
168 cairo_destroy(cr);
169
170 window_copy_surface(dnd->window, &rectangle, surface);
171 window_commit(dnd->window, dnd->key);
172 cairo_surface_destroy(surface);
173}
174
175static void
176redraw_handler(struct window *window, void *data)
177{
178 struct dnd *dnd = data;
179
180 dnd_draw(dnd);
181}
182
183static void
184keyboard_focus_handler(struct window *window,
185 struct input *device, void *data)
186{
187 struct dnd *dnd = data;
188
189 window_schedule_redraw(dnd->window);
190}
191
192static struct item *
193dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
194{
195 struct item *item;
196 int i;
197
198 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
199 item = dnd->items[i];
200 if (item &&
201 item->x <= x && x < item->x + item_width &&
202 item->y <= y && y < item->y + item_height)
203 return item;
204 }
205
206 return NULL;
207}
208
209static void
Kristian Høgsberg506e20e2010-08-19 17:26:02 -0400210drag_handle_device(void *data,
211 struct wl_drag *drag, struct wl_input_device *device)
212{
213}
214
215static void
216drag_pointer_focus(void *data,
217 struct wl_drag *drag,
218 uint32_t time, struct wl_surface *surface,
219 int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
220{
221 fprintf(stderr, "drag pointer focus %p\n", surface);
222
223 wl_drag_accept(drag, "text/plain");
224}
225
226static void
227drag_offer(void *data,
228 struct wl_drag *drag, const char *type)
229{
230 fprintf(stderr, "drag offer %s\n", type);
231}
232
233static void
234drag_motion(void *data,
235 struct wl_drag *drag,
236 uint32_t time,
237 int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
238{
239 fprintf(stderr, "drag motion %d,%d\n", surface_x, surface_y);
240
241 /* FIXME: Need to correlate this with the offer event.
242 * Problem is, we don't know when we've seen that last offer
243 * event, and we might need to look at all of them before we
244 * can decide which one to go with. */
245 wl_drag_accept(drag, "text/plain");
246}
247
248static void
249drag_target(void *data,
250 struct wl_drag *drag, const char *mime_type)
251{
252 fprintf(stderr, "target %s\n", mime_type);
253}
254
255static void
256drag_finish(void *data, struct wl_drag *drag)
257{
258 fprintf(stderr, "drag finish\n");
259 struct wl_array a;
260 char text[] = "[drop data]";
261
262 a.data = text;
263 a.size = sizeof text;
264
265 wl_drag_send(drag, &a);
266}
267
268static void
269drag_data(void *data,
270 struct wl_drag *drag, struct wl_array *contents)
271{
272 fprintf(stderr, "drag drop, data %s\n", contents->data);
273}
274
275static const struct wl_drag_listener drag_listener = {
276 drag_handle_device,
277 drag_pointer_focus,
278 drag_offer,
279 drag_motion,
280 drag_target,
281 drag_finish,
282 drag_data
283};
284
285static void
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400286dnd_button_handler(struct window *window,
287 struct input *input, uint32_t time,
288 int button, int state, void *data)
289{
290 struct dnd *dnd = data;
291 int32_t x, y, hotspot_x, hotspot_y, pointer_width, pointer_height;
292 struct rectangle rectangle;
293 struct item *item;
294 struct wl_buffer *buffer;
295 cairo_surface_t *surface, *pointer;
296 cairo_t *cr;
297
298 input_get_position(input, &x, &y);
299 window_get_child_rectangle(dnd->window, &rectangle);
300
301 x -= rectangle.x;
302 y -= rectangle.y;
303 item = dnd_get_item(dnd, x, y);
304
305 if (item && state == 1) {
306 fprintf(stderr, "start drag, item %p\n", item);
307
308 pointer = display_get_pointer_surface(dnd->display,
309 POINTER_DRAGGING,
310 &pointer_width,
311 &pointer_height,
312 &hotspot_x,
313 &hotspot_y);
314
315 rectangle.width = item_width + 2 * pointer_width;
316 rectangle.height = item_height + 2 * pointer_height;
317 surface = display_create_surface(dnd->display, &rectangle);
318
319 cr = cairo_create(surface);
320 cairo_translate(cr, pointer_width, pointer_height);
321
322 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
323 cairo_set_source_rgba(cr, 0, 0, 0, 0);
324 cairo_paint(cr);
325
326 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
327 cairo_set_source_surface(cr, item->surface, 0, 0);
328 cairo_paint(cr);
329
330 cairo_set_source_surface(cr, pointer,
331 x - item->x - hotspot_x,
332 y - item->y - hotspot_y);
333 cairo_surface_destroy(pointer);
334 cairo_paint(cr);
335 cairo_destroy(cr);
336
337 buffer = display_get_buffer_for_surface(dnd->display,
338 surface);
339 window_start_drag(window, input, time,
340 buffer,
341 pointer_width + x - item->x,
342 pointer_height + y - item->y);
343
344 /* FIXME: We leak the surface because we can't free it
345 * until the server has referenced it. */
346 }
347}
348
349static int
350dnd_motion_handler(struct window *window,
351 struct input *input, uint32_t time,
352 int32_t x, int32_t y,
353 int32_t sx, int32_t sy, void *data)
354{
355 struct dnd *dnd = data;
356 struct item *item;
357 struct rectangle rectangle;
358
359 window_get_child_rectangle(dnd->window, &rectangle);
360 item = dnd_get_item(dnd, sx - rectangle.x, sy - rectangle.y);
361
362 if (item)
363 return POINTER_HAND1;
364 else
365 return POINTER_LEFT_PTR;
366}
367
368static struct dnd *
369dnd_create(struct display *display)
370{
371 struct dnd *dnd;
372 gchar *title;
373 int i, x, y;
374 struct rectangle rectangle;
375
376 dnd = malloc(sizeof *dnd);
377 if (dnd == NULL)
378 return dnd;
379 memset(dnd, 0, sizeof *dnd);
380
381 title = g_strdup_printf("Wayland Drag and Drop Demo");
382
383 dnd->window = window_create(display, title, 100, 100, 500, 400);
384 dnd->display = display;
385 dnd->key = 100;
386
387 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
388 x = (i % 4) * (item_width + item_padding) + item_padding;
389 y = (i / 4) * (item_height + item_padding) + item_padding;
390 if ((i ^ (i >> 2)) & 1)
391 dnd->items[i] = item_create(display, x, y);
392 else
393 dnd->items[i] = NULL;
394 }
395
396 window_set_user_data(dnd->window, dnd);
397 window_set_redraw_handler(dnd->window, redraw_handler);
398 window_set_keyboard_focus_handler(dnd->window,
399 keyboard_focus_handler);
400 window_set_button_handler(dnd->window,
401 dnd_button_handler);
402
403 window_set_motion_handler(dnd->window,
404 dnd_motion_handler);
405
406 rectangle.width = 4 * (item_width + item_padding) + item_padding;
407 rectangle.height = 4 * (item_height + item_padding) + item_padding;
408 window_set_child_size(dnd->window, &rectangle);
409
410 dnd_draw(dnd);
411
412 return dnd;
413}
414
415static const GOptionEntry option_entries[] = {
416 { NULL }
417};
418
419int
420main(int argc, char *argv[])
421{
422 struct display *d;
423 struct dnd *dnd;
424 struct timeval tv;
425
426 gettimeofday(&tv, NULL);
427 srandom(tv.tv_usec);
428
429 d = display_create(&argc, &argv, option_entries);
430
Kristian Høgsberg506e20e2010-08-19 17:26:02 -0400431 display_add_drag_listener(d, &drag_listener, d);
432
Kristian Høgsbergb8cc24e2010-08-18 20:31:06 -0400433 dnd = dnd_create (d);
434
435 display_run(d);
436
437 return 0;
438}