blob: 5772e8e2aefe914a3d62742e9ec91a41407fad04 [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
210dnd_button_handler(struct window *window,
211 struct input *input, uint32_t time,
212 int button, int state, void *data)
213{
214 struct dnd *dnd = data;
215 int32_t x, y, hotspot_x, hotspot_y, pointer_width, pointer_height;
216 struct rectangle rectangle;
217 struct item *item;
218 struct wl_buffer *buffer;
219 cairo_surface_t *surface, *pointer;
220 cairo_t *cr;
221
222 input_get_position(input, &x, &y);
223 window_get_child_rectangle(dnd->window, &rectangle);
224
225 x -= rectangle.x;
226 y -= rectangle.y;
227 item = dnd_get_item(dnd, x, y);
228
229 if (item && state == 1) {
230 fprintf(stderr, "start drag, item %p\n", item);
231
232 pointer = display_get_pointer_surface(dnd->display,
233 POINTER_DRAGGING,
234 &pointer_width,
235 &pointer_height,
236 &hotspot_x,
237 &hotspot_y);
238
239 rectangle.width = item_width + 2 * pointer_width;
240 rectangle.height = item_height + 2 * pointer_height;
241 surface = display_create_surface(dnd->display, &rectangle);
242
243 cr = cairo_create(surface);
244 cairo_translate(cr, pointer_width, pointer_height);
245
246 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
247 cairo_set_source_rgba(cr, 0, 0, 0, 0);
248 cairo_paint(cr);
249
250 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
251 cairo_set_source_surface(cr, item->surface, 0, 0);
252 cairo_paint(cr);
253
254 cairo_set_source_surface(cr, pointer,
255 x - item->x - hotspot_x,
256 y - item->y - hotspot_y);
257 cairo_surface_destroy(pointer);
258 cairo_paint(cr);
259 cairo_destroy(cr);
260
261 buffer = display_get_buffer_for_surface(dnd->display,
262 surface);
263 window_start_drag(window, input, time,
264 buffer,
265 pointer_width + x - item->x,
266 pointer_height + y - item->y);
267
268 /* FIXME: We leak the surface because we can't free it
269 * until the server has referenced it. */
270 }
271}
272
273static int
274dnd_motion_handler(struct window *window,
275 struct input *input, uint32_t time,
276 int32_t x, int32_t y,
277 int32_t sx, int32_t sy, void *data)
278{
279 struct dnd *dnd = data;
280 struct item *item;
281 struct rectangle rectangle;
282
283 window_get_child_rectangle(dnd->window, &rectangle);
284 item = dnd_get_item(dnd, sx - rectangle.x, sy - rectangle.y);
285
286 if (item)
287 return POINTER_HAND1;
288 else
289 return POINTER_LEFT_PTR;
290}
291
292static struct dnd *
293dnd_create(struct display *display)
294{
295 struct dnd *dnd;
296 gchar *title;
297 int i, x, y;
298 struct rectangle rectangle;
299
300 dnd = malloc(sizeof *dnd);
301 if (dnd == NULL)
302 return dnd;
303 memset(dnd, 0, sizeof *dnd);
304
305 title = g_strdup_printf("Wayland Drag and Drop Demo");
306
307 dnd->window = window_create(display, title, 100, 100, 500, 400);
308 dnd->display = display;
309 dnd->key = 100;
310
311 for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
312 x = (i % 4) * (item_width + item_padding) + item_padding;
313 y = (i / 4) * (item_height + item_padding) + item_padding;
314 if ((i ^ (i >> 2)) & 1)
315 dnd->items[i] = item_create(display, x, y);
316 else
317 dnd->items[i] = NULL;
318 }
319
320 window_set_user_data(dnd->window, dnd);
321 window_set_redraw_handler(dnd->window, redraw_handler);
322 window_set_keyboard_focus_handler(dnd->window,
323 keyboard_focus_handler);
324 window_set_button_handler(dnd->window,
325 dnd_button_handler);
326
327 window_set_motion_handler(dnd->window,
328 dnd_motion_handler);
329
330 rectangle.width = 4 * (item_width + item_padding) + item_padding;
331 rectangle.height = 4 * (item_height + item_padding) + item_padding;
332 window_set_child_size(dnd->window, &rectangle);
333
334 dnd_draw(dnd);
335
336 return dnd;
337}
338
339static const GOptionEntry option_entries[] = {
340 { NULL }
341};
342
343int
344main(int argc, char *argv[])
345{
346 struct display *d;
347 struct dnd *dnd;
348 struct timeval tv;
349
350 gettimeofday(&tv, NULL);
351 srandom(tv.tv_usec);
352
353 d = display_create(&argc, &argv, option_entries);
354
355 dnd = dnd_create (d);
356
357 display_run(d);
358
359 return 0;
360}