blob: ea2d3f94bd40fb702bf6d148c9fd9ab7b5ff1b4f [file] [log] [blame]
Jason Ekstrand549a53f2014-04-05 09:22:15 -05001/*
2 * Copyright © 2014 Jason Ekstrand
3 * Copyright © 2011 Benjamin Franzke
4 * Copyright © 2010 Intel Corporation
5 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -07006 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
Jason Ekstrand549a53f2014-04-05 09:22:15 -050012 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -070013 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
Jason Ekstrand549a53f2014-04-05 09:22:15 -050024 */
25
Bryce Harringtonb4dae9b2016-06-15 18:13:07 -070026#include "config.h"
Jason Ekstrand549a53f2014-04-05 09:22:15 -050027
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030028#include <stdint.h>
Jason Ekstrand549a53f2014-04-05 09:22:15 -050029#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdbool.h>
33#include <assert.h>
34#include <unistd.h>
35#include <sys/mman.h>
36#include <sys/time.h>
37#include <signal.h>
38
39#include <wayland-client.h>
Jon Cruz4678bab2015-06-15 15:37:07 -070040#include "shared/os-compatibility.h"
Bryce Harrington0d1a6222016-02-11 16:42:49 -080041#include "shared/zalloc.h"
Jonas Ådahla74eff92016-08-11 23:39:31 +080042#include "xdg-shell-unstable-v6-client-protocol.h"
Jonas Ådahl496adb32015-11-17 16:00:27 +080043#include "fullscreen-shell-unstable-v1-client-protocol.h"
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +030044#include "viewporter-client-protocol.h"
Jason Ekstrand549a53f2014-04-05 09:22:15 -050045
46int print_debug = 0;
47
48struct display {
49 struct wl_display *display;
50 struct wl_registry *registry;
51 int compositor_version;
52 struct wl_compositor *compositor;
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +030053 struct wp_viewporter *viewporter;
Jonas Ådahla74eff92016-08-11 23:39:31 +080054 struct zxdg_shell_v6 *shell;
Jonas Ådahl496adb32015-11-17 16:00:27 +080055 struct zwp_fullscreen_shell_v1 *fshell;
Jason Ekstrand549a53f2014-04-05 09:22:15 -050056 struct wl_shm *shm;
57 uint32_t formats;
58};
59
60struct buffer {
61 struct wl_buffer *buffer;
62 uint32_t *shm_data;
63 int busy;
64};
65
66enum window_flags {
67 WINDOW_FLAG_USE_VIEWPORT = 0x1,
68 WINDOW_FLAG_ROTATING_TRANSFORM = 0x2,
Derek Foremanfb1e1262015-11-18 16:32:34 -060069 WINDOW_FLAG_USE_DAMAGE_BUFFER = 0x4,
Jason Ekstrand549a53f2014-04-05 09:22:15 -050070};
71
72struct window {
73 struct display *display;
74 int width, height, border;
75 struct wl_surface *surface;
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +030076 struct wp_viewport *viewport;
Jonas Ådahla74eff92016-08-11 23:39:31 +080077 struct zxdg_surface_v6 *xdg_surface;
78 struct zxdg_toplevel_v6 *xdg_toplevel;
Jason Ekstrand549a53f2014-04-05 09:22:15 -050079 struct wl_callback *callback;
80 struct buffer buffers[2];
81 struct buffer *prev_buffer;
Jonas Ådahla74eff92016-08-11 23:39:31 +080082 bool wait_for_configure;
Jason Ekstrand549a53f2014-04-05 09:22:15 -050083
84 enum window_flags flags;
85 int scale;
86 enum wl_output_transform transform;
87
88 struct {
89 float x, y; /* position in pixels */
90 float dx, dy; /* velocity in pixels/second */
91 int radius; /* radius in pixels */
92 uint32_t prev_time;
93 } ball;
94};
95
96static int running = 1;
97
98static void
Jonas Ådahla74eff92016-08-11 23:39:31 +080099redraw(void *data, struct wl_callback *callback, uint32_t time);
100
101static void
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500102buffer_release(void *data, struct wl_buffer *buffer)
103{
104 struct buffer *mybuf = data;
105
106 mybuf->busy = 0;
107}
108
109static const struct wl_buffer_listener buffer_listener = {
110 buffer_release
111};
112
113static int
114create_shm_buffer(struct display *display, struct buffer *buffer,
115 int width, int height, uint32_t format)
116{
117 struct wl_shm_pool *pool;
118 int fd, size, pitch;
119 void *data;
120
121 pitch = width * 4;
122 size = pitch * height;
123
124 fd = os_create_anonymous_file(size);
125 if (fd < 0) {
126 fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
127 size);
128 return -1;
129 }
130
131 data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
132 if (data == MAP_FAILED) {
133 fprintf(stderr, "mmap failed: %m\n");
134 close(fd);
135 return -1;
136 }
137
138 pool = wl_shm_create_pool(display->shm, fd, size);
139 buffer->buffer = wl_shm_pool_create_buffer(pool, 0,
140 width, height,
141 pitch, format);
142 wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
143 wl_shm_pool_destroy(pool);
144 close(fd);
145
146 buffer->shm_data = data;
147
148 return 0;
149}
150
151static void
Jonas Ådahla74eff92016-08-11 23:39:31 +0800152xdg_surface_handle_configure(void *data, struct zxdg_surface_v6 *surface,
153 uint32_t serial)
154{
155 struct window *window = data;
156
157 zxdg_surface_v6_ack_configure(surface, serial);
158
159 if (window->wait_for_configure) {
160 redraw(window, NULL, 0);
161 window->wait_for_configure = false;
162 }
163}
164
165static const struct zxdg_surface_v6_listener xdg_surface_listener = {
166 xdg_surface_handle_configure,
167};
168
169static void
170xdg_toplevel_handle_configure(void *data, struct zxdg_toplevel_v6 *toplevel,
171 int32_t width, int32_t height,
172 struct wl_array *states)
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500173{
174}
175
176static void
Jonas Ådahla74eff92016-08-11 23:39:31 +0800177xdg_toplevel_handle_close(void *data, struct zxdg_toplevel_v6 *xdg_toplevel)
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500178{
179 running = 0;
180}
181
Jonas Ådahla74eff92016-08-11 23:39:31 +0800182static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
183 xdg_toplevel_handle_configure,
184 xdg_toplevel_handle_close,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500185};
186
187static float
188bounded_randf(float a, float b)
189{
190 return a + ((float)rand() / (float)RAND_MAX) * (b - a);
191}
192
193static void
194window_init_game(struct window *window)
195{
196 int ax1, ay1, ax2, ay2; /* playable arena size */
197 struct timeval tv;
198
199 gettimeofday(&tv, NULL);
200 srand(tv.tv_usec);
201
202 window->ball.radius = 10;
203
204 ax1 = window->border + window->ball.radius;
205 ay1 = window->border + window->ball.radius;
206 ax2 = window->width - window->border - window->ball.radius;
207 ay2 = window->height - window->border - window->ball.radius;
208
209 window->ball.x = bounded_randf(ax1, ax2);
210 window->ball.y = bounded_randf(ay1, ay2);
211
212 window->ball.dx = bounded_randf(0, window->width);
213 window->ball.dy = bounded_randf(0, window->height);
214
215 window->ball.prev_time = 0;
216}
217
218static void
219window_advance_game(struct window *window, uint32_t timestamp)
220{
221 int ax1, ay1, ax2, ay2; /* Arena size */
222 float dt;
223
224 if (window->ball.prev_time == 0) {
225 /* first pass, don't do anything */
226 window->ball.prev_time = timestamp;
227 return;
228 }
229
230 /* dt in seconds */
231 dt = (float)(timestamp - window->ball.prev_time) / 1000.0f;
232
233 ax1 = window->border + window->ball.radius;
234 ay1 = window->border + window->ball.radius;
235 ax2 = window->width - window->border - window->ball.radius;
236 ay2 = window->height - window->border - window->ball.radius;
237
238 window->ball.x += window->ball.dx * dt;
239 while (window->ball.x < ax1 || ax2 < window->ball.x) {
240 if (window->ball.x < ax1)
241 window->ball.x = 2 * ax1 - window->ball.x;
242 if (ax2 <= window->ball.x)
243 window->ball.x = 2 * ax2 - window->ball.x;
244
245 window->ball.dx *= -1.0f;
246 }
247
248 window->ball.y += window->ball.dy * dt;
249 while (window->ball.y < ay1 || ay2 < window->ball.y) {
250 if (window->ball.y < ay1)
251 window->ball.y = 2 * ay1 - window->ball.y;
252 if (ay2 <= window->ball.y)
253 window->ball.y = 2 * ay2 - window->ball.y;
254
255 window->ball.dy *= -1.0f;
256 }
257
258 window->ball.prev_time = timestamp;
259}
260
261static struct window *
262create_window(struct display *display, int width, int height,
263 enum wl_output_transform transform, int scale,
264 enum window_flags flags)
265{
266 struct window *window;
267
268 if (display->compositor_version < 2 &&
269 (transform != WL_OUTPUT_TRANSFORM_NORMAL ||
270 flags & WINDOW_FLAG_ROTATING_TRANSFORM)) {
271 fprintf(stderr, "wl_surface.buffer_transform unsupported in "
272 "wl_surface version %d\n",
273 display->compositor_version);
274 exit(1);
275 }
276
277 if (display->compositor_version < 3 &&
278 (! (flags & WINDOW_FLAG_USE_VIEWPORT)) && scale != 1) {
279 fprintf(stderr, "wl_surface.buffer_scale unsupported in "
280 "wl_surface version %d\n",
281 display->compositor_version);
282 exit(1);
283 }
284
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300285 if (display->viewporter == NULL && (flags & WINDOW_FLAG_USE_VIEWPORT)) {
286 fprintf(stderr, "Compositor does not support wp_viewport");
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500287 exit(1);
288 }
289
Christopher Michaele1434d32015-12-20 07:41:52 -0500290 if (display->compositor_version <
291 WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION &&
Derek Foremanfb1e1262015-11-18 16:32:34 -0600292 (flags & WINDOW_FLAG_USE_DAMAGE_BUFFER)) {
293 fprintf(stderr, "wl_surface.damage_buffer unsupported in "
294 "wl_surface version %d\n",
295 display->compositor_version);
296 exit(1);
297 }
298
Bryce Harrington0d1a6222016-02-11 16:42:49 -0800299 window = zalloc(sizeof *window);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500300 if (!window)
301 return NULL;
302
303 window->callback = NULL;
304 window->display = display;
305 window->width = width;
306 window->height = height;
307 window->border = 10;
308 window->flags = flags;
309 window->transform = transform;
310 window->scale = scale;
311
312 window_init_game(window);
313
314 window->surface = wl_compositor_create_surface(display->compositor);
315
316 if (window->flags & WINDOW_FLAG_USE_VIEWPORT)
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300317 window->viewport = wp_viewporter_get_viewport(display->viewporter,
318 window->surface);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500319
320 if (display->shell) {
321 window->xdg_surface =
Jonas Ådahla74eff92016-08-11 23:39:31 +0800322 zxdg_shell_v6_get_xdg_surface(display->shell,
323 window->surface);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500324
325 assert(window->xdg_surface);
326
Jonas Ådahla74eff92016-08-11 23:39:31 +0800327 zxdg_surface_v6_add_listener(window->xdg_surface,
328 &xdg_surface_listener, window);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500329
Jonas Ådahla74eff92016-08-11 23:39:31 +0800330 window->xdg_toplevel =
331 zxdg_surface_v6_get_toplevel(window->xdg_surface);
332
333 assert(window->xdg_toplevel);
334
335 zxdg_toplevel_v6_add_listener(window->xdg_toplevel,
336 &xdg_toplevel_listener, window);
337
338 zxdg_toplevel_v6_set_title(window->xdg_toplevel, "simple-damage");
339
340 window->wait_for_configure = true;
341 wl_surface_commit(window->surface);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500342 } else if (display->fshell) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800343 zwp_fullscreen_shell_v1_present_surface(display->fshell,
344 window->surface,
345 ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
346 NULL);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500347 } else {
348 assert(0);
349 }
350
351 /* Initialise damage to full surface, so the padding gets painted */
Derek Foremanfb1e1262015-11-18 16:32:34 -0600352 if (window->flags & WINDOW_FLAG_USE_DAMAGE_BUFFER) {
353 wl_surface_damage_buffer(window->surface, 0, 0,
354 INT32_MAX, INT32_MAX);
355 } else {
356 wl_surface_damage(window->surface, 0, 0, INT32_MAX, INT32_MAX);
357 }
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500358 return window;
359}
360
361static void
362destroy_window(struct window *window)
363{
364 if (window->callback)
365 wl_callback_destroy(window->callback);
366
367 if (window->buffers[0].buffer)
368 wl_buffer_destroy(window->buffers[0].buffer);
369 if (window->buffers[1].buffer)
370 wl_buffer_destroy(window->buffers[1].buffer);
371
Jonas Ådahla74eff92016-08-11 23:39:31 +0800372 if (window->xdg_toplevel)
373 zxdg_toplevel_v6_destroy(window->xdg_toplevel);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500374 if (window->xdg_surface)
Jonas Ådahla74eff92016-08-11 23:39:31 +0800375 zxdg_surface_v6_destroy(window->xdg_surface);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500376 if (window->viewport)
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300377 wp_viewport_destroy(window->viewport);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500378 wl_surface_destroy(window->surface);
379 free(window);
380}
381
382static struct buffer *
383window_next_buffer(struct window *window)
384{
385 struct buffer *buffer;
386 int ret = 0, bwidth, bheight;
387
388 if (!window->buffers[0].busy)
389 buffer = &window->buffers[0];
390 else if (!window->buffers[1].busy)
391 buffer = &window->buffers[1];
392 else
393 return NULL;
394
395 switch (window->transform) {
396 default:
397 case WL_OUTPUT_TRANSFORM_NORMAL:
398 case WL_OUTPUT_TRANSFORM_180:
399 case WL_OUTPUT_TRANSFORM_FLIPPED:
400 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
401 bwidth = window->width * window->scale;
402 bheight = window->height * window->scale;
403 break;
404 case WL_OUTPUT_TRANSFORM_90:
405 case WL_OUTPUT_TRANSFORM_270:
406 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
407 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
408 bwidth = window->height * window->scale;
409 bheight = window->width * window->scale;
410 break;
411 }
412
413 if (!buffer->buffer) {
414 ret = create_shm_buffer(window->display, buffer,
415 bwidth, bheight,
416 WL_SHM_FORMAT_ARGB8888);
417
418 if (ret < 0)
419 return NULL;
420 }
421
422 return buffer;
423}
424
425static void
426paint_box(uint32_t *pixels, int pitch, int x, int y, int width, int height,
427 uint32_t color)
428{
429 int i, j;
430
431 for (j = y; j < y + height; ++j)
432 for (i = x; i < x + width; ++i)
433 pixels[i + j * pitch] = color;
434}
435
436static void
437paint_circle(uint32_t *pixels, int pitch, float x, float y, int radius,
438 uint32_t color)
439{
440 int i, j;
441
442 for (j = y - radius; j <= (int)(y + radius); ++j)
443 for (i = x - radius; i <= (int)(x + radius); ++i)
444 if ((j+0.5f-y)*(j+0.5f-y) + (i+0.5f-x)*(i+0.5f-x) <= radius * radius)
445 pixels[i + j * pitch] = color;
446}
447
448static void
449window_get_transformed_ball(struct window *window, float *bx, float *by)
450{
451 float wx, wy;
452
453 wx = window->ball.x;
454 wy = window->ball.y;
455
456 switch (window->transform) {
457 default:
458 case WL_OUTPUT_TRANSFORM_NORMAL:
459 *bx = wx;
460 *by = wy;
461 break;
462 case WL_OUTPUT_TRANSFORM_90:
463 *bx = window->height - wy;
464 *by = wx;
465 break;
466 case WL_OUTPUT_TRANSFORM_180:
467 *bx = window->width - wx;
468 *by = window->height - wy;
469 break;
470 case WL_OUTPUT_TRANSFORM_270:
471 *bx = wy;
472 *by = window->width - wx;
473 break;
474 case WL_OUTPUT_TRANSFORM_FLIPPED:
475 *bx = window->width - wx;
476 *by = wy;
477 break;
478 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
479 *bx = window->height - wy;
480 *by = window->width - wx;
481 break;
482 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
483 *bx = wx;
484 *by = window->height - wy;
485 break;
486 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
487 *bx = wy;
488 *by = wx;
489 break;
490 }
491
492 *bx *= window->scale;
493 *by *= window->scale;
494
495 if (window->viewport) {
496 /* We're drawing half-size because of the viewport */
497 *bx /= 2;
498 *by /= 2;
499 }
500}
501
502static const struct wl_callback_listener frame_listener;
503
504static void
505redraw(void *data, struct wl_callback *callback, uint32_t time)
506{
507 struct window *window = data;
508 struct buffer *buffer;
Derek Foreman29b846e2015-11-18 16:32:33 -0600509 int off_x = 0, off_y = 0;
510 int bwidth, bheight, bborder, bpitch, bradius;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500511 float bx, by;
512
513 buffer = window_next_buffer(window);
514 if (!buffer) {
515 fprintf(stderr,
516 !callback ? "Failed to create the first buffer.\n" :
517 "Both buffers busy at redraw(). Server bug?\n");
518 abort();
519 }
520
521 /* Rotate the damage, but keep the even/odd parity so the
522 * dimensions of the buffers don't change */
523 if (window->flags & WINDOW_FLAG_ROTATING_TRANSFORM)
524 window->transform = (window->transform + 2) % 8;
525
526 switch (window->transform) {
527 default:
528 case WL_OUTPUT_TRANSFORM_NORMAL:
529 case WL_OUTPUT_TRANSFORM_180:
530 case WL_OUTPUT_TRANSFORM_FLIPPED:
531 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
532 bwidth = window->width * window->scale;
533 bheight = window->height * window->scale;
534 break;
535 case WL_OUTPUT_TRANSFORM_90:
536 case WL_OUTPUT_TRANSFORM_270:
537 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
538 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
539 bwidth = window->height * window->scale;
540 bheight = window->width * window->scale;
541 break;
542 }
543
544 bpitch = bwidth;
545
546 bborder = window->border * window->scale;
547 bradius = window->ball.radius * window->scale;
548
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500549 if (window->viewport) {
Derek Foreman29b846e2015-11-18 16:32:33 -0600550 int tx, ty;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500551 /* Fill the whole thing with red to detect viewport errors */
552 paint_box(buffer->shm_data, bpitch, 0, 0, bwidth, bheight,
553 0xffff0000);
554
555 /* The buffer is the same size. However, we crop it
556 * and scale it up by a factor of 2 */
557 bborder /= 2;
558 bradius /= 2;
559 bwidth /= 2;
560 bheight /= 2;
561
562 /* Offset the drawing region */
Derek Foreman29b846e2015-11-18 16:32:33 -0600563 tx = (window->width / 3) * window->scale;
564 ty = (window->height / 5) * window->scale;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500565 switch (window->transform) {
566 default:
567 case WL_OUTPUT_TRANSFORM_NORMAL:
Derek Foreman29b846e2015-11-18 16:32:33 -0600568 off_y = ty;
569 off_x = tx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500570 break;
571 case WL_OUTPUT_TRANSFORM_90:
Derek Foreman29b846e2015-11-18 16:32:33 -0600572 off_y = tx;
573 off_x = bwidth - ty;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500574 break;
575 case WL_OUTPUT_TRANSFORM_180:
Derek Foreman29b846e2015-11-18 16:32:33 -0600576 off_y = bheight - ty;
577 off_x = bwidth - tx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500578 break;
579 case WL_OUTPUT_TRANSFORM_270:
Derek Foreman29b846e2015-11-18 16:32:33 -0600580 off_y = bheight - tx;
581 off_x = ty;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500582 break;
583 case WL_OUTPUT_TRANSFORM_FLIPPED:
Derek Foreman29b846e2015-11-18 16:32:33 -0600584 off_y = ty;
585 off_x = bwidth - tx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500586 break;
587 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
Derek Foreman29b846e2015-11-18 16:32:33 -0600588 off_y = bheight - tx;
589 off_x = bwidth - ty;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500590 break;
591 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
Derek Foreman29b846e2015-11-18 16:32:33 -0600592 off_y = bheight - ty;
593 off_x = tx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500594 break;
595 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
Derek Foreman29b846e2015-11-18 16:32:33 -0600596 off_y = tx;
597 off_x = ty;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500598 break;
599 }
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300600 wp_viewport_set_source(window->viewport,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500601 wl_fixed_from_int(window->width / 3),
602 wl_fixed_from_int(window->height / 5),
603 wl_fixed_from_int(window->width / 2),
604 wl_fixed_from_int(window->height / 2));
605 }
606
607 /* Paint the border */
Derek Foreman29b846e2015-11-18 16:32:33 -0600608 paint_box(buffer->shm_data, bpitch, off_x, off_y,
609 bwidth, bborder, 0xffffffff);
610 paint_box(buffer->shm_data, bpitch, off_x, off_y,
611 bborder, bheight, 0xffffffff);
612 paint_box(buffer->shm_data, bpitch, off_x + bwidth - bborder, off_y,
613 bborder, bheight, 0xffffffff);
614 paint_box(buffer->shm_data, bpitch, off_x, off_y + bheight - bborder,
615 bwidth, bborder, 0xffffffff);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500616
617 /* fill with translucent */
Derek Foreman29b846e2015-11-18 16:32:33 -0600618 paint_box(buffer->shm_data, bpitch, off_x + bborder, off_y + bborder,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500619 bwidth - 2 * bborder, bheight - 2 * bborder, 0x80000000);
620
621 /* Damage where the ball was */
Derek Foremanfb1e1262015-11-18 16:32:34 -0600622 if (window->flags & WINDOW_FLAG_USE_DAMAGE_BUFFER) {
623 window_get_transformed_ball(window, &bx, &by);
624 wl_surface_damage_buffer(window->surface,
625 bx - bradius + off_x,
626 by - bradius + off_y,
627 bradius * 2 + 1,
628 bradius * 2 + 1);
629 } else {
630 wl_surface_damage(window->surface,
631 window->ball.x - window->ball.radius,
632 window->ball.y - window->ball.radius,
633 window->ball.radius * 2 + 1,
634 window->ball.radius * 2 + 1);
635 }
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500636 window_advance_game(window, time);
637
638 window_get_transformed_ball(window, &bx, &by);
639
640 /* Paint the ball */
Derek Foreman29b846e2015-11-18 16:32:33 -0600641 paint_circle(buffer->shm_data, bpitch, off_x + bx, off_y + by,
642 bradius, 0xff00ff00);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500643
644 if (print_debug) {
645 printf("Ball now located at (%f, %f)\n",
646 window->ball.x, window->ball.y);
647
648 printf("Circle painted at (%f, %f), radius %d\n", bx, by,
649 bradius);
650
651 printf("Buffer damage rectangle: (%d, %d) @ %dx%d\n",
Derek Foreman29b846e2015-11-18 16:32:33 -0600652 (int)(bx - bradius) + off_x,
653 (int)(by - bradius) + off_y,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500654 bradius * 2 + 1, bradius * 2 + 1);
655 }
656
657 /* Damage where the ball is now */
Derek Foremanfb1e1262015-11-18 16:32:34 -0600658 if (window->flags & WINDOW_FLAG_USE_DAMAGE_BUFFER) {
659 wl_surface_damage_buffer(window->surface,
660 bx - bradius + off_x,
661 by - bradius + off_y,
662 bradius * 2 + 1,
663 bradius * 2 + 1);
664 } else {
665 wl_surface_damage(window->surface,
666 window->ball.x - window->ball.radius,
667 window->ball.y - window->ball.radius,
668 window->ball.radius * 2 + 1,
669 window->ball.radius * 2 + 1);
670 }
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500671 wl_surface_attach(window->surface, buffer->buffer, 0, 0);
672
673 if (window->display->compositor_version >= 2 &&
674 (window->transform != WL_OUTPUT_TRANSFORM_NORMAL ||
675 window->flags & WINDOW_FLAG_ROTATING_TRANSFORM))
676 wl_surface_set_buffer_transform(window->surface,
677 window->transform);
678
679 if (window->viewport)
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300680 wp_viewport_set_destination(window->viewport,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500681 window->width,
682 window->height);
683
684 if (window->scale != 1)
685 wl_surface_set_buffer_scale(window->surface,
686 window->scale);
687
688 if (callback)
689 wl_callback_destroy(callback);
690
691 window->callback = wl_surface_frame(window->surface);
692 wl_callback_add_listener(window->callback, &frame_listener, window);
693 wl_surface_commit(window->surface);
694 buffer->busy = 1;
695}
696
697static const struct wl_callback_listener frame_listener = {
698 redraw
699};
700
701static void
702shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
703{
704 struct display *d = data;
705
706 d->formats |= (1 << format);
707}
708
709struct wl_shm_listener shm_listener = {
710 shm_format
711};
712
713static void
Jonas Ådahla74eff92016-08-11 23:39:31 +0800714xdg_shell_ping(void *data, struct zxdg_shell_v6*shell, uint32_t serial)
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500715{
Jonas Ådahla74eff92016-08-11 23:39:31 +0800716 zxdg_shell_v6_pong(shell, serial);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500717}
718
Jonas Ådahla74eff92016-08-11 23:39:31 +0800719static const struct zxdg_shell_v6_listener xdg_shell_listener = {
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500720 xdg_shell_ping,
721};
722
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500723static void
724registry_handle_global(void *data, struct wl_registry *registry,
725 uint32_t id, const char *interface, uint32_t version)
726{
727 struct display *d = data;
728
729 if (strcmp(interface, "wl_compositor") == 0) {
730 if (d->compositor_version > (int)version) {
731 fprintf(stderr, "Compositor does not support "
732 "wl_surface version %d\n", d->compositor_version);
733 exit(1);
734 }
735
736 if (d->compositor_version < 0)
737 d->compositor_version = version;
738
739 d->compositor =
740 wl_registry_bind(registry,
741 id, &wl_compositor_interface,
742 d->compositor_version);
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300743 } else if (strcmp(interface, "wp_viewporter") == 0) {
744 d->viewporter = wl_registry_bind(registry, id,
745 &wp_viewporter_interface, 1);
Jonas Ådahla74eff92016-08-11 23:39:31 +0800746 } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500747 d->shell = wl_registry_bind(registry,
Jonas Ådahla74eff92016-08-11 23:39:31 +0800748 id, &zxdg_shell_v6_interface, 1);
749 zxdg_shell_v6_add_listener(d->shell, &xdg_shell_listener, d);
Jonas Ådahl496adb32015-11-17 16:00:27 +0800750 } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500751 d->fshell = wl_registry_bind(registry,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800752 id, &zwp_fullscreen_shell_v1_interface, 1);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500753 } else if (strcmp(interface, "wl_shm") == 0) {
754 d->shm = wl_registry_bind(registry,
755 id, &wl_shm_interface, 1);
756 wl_shm_add_listener(d->shm, &shm_listener, d);
757 }
758}
759
760static void
761registry_handle_global_remove(void *data, struct wl_registry *registry,
762 uint32_t name)
763{
764}
765
766static const struct wl_registry_listener registry_listener = {
767 registry_handle_global,
768 registry_handle_global_remove
769};
770
771static struct display *
772create_display(int version)
773{
774 struct display *display;
775
776 display = malloc(sizeof *display);
777 if (display == NULL) {
778 fprintf(stderr, "out of memory\n");
779 exit(1);
780 }
781 display->display = wl_display_connect(NULL);
782 assert(display->display);
783
784 display->compositor_version = version;
785 display->formats = 0;
786 display->registry = wl_display_get_registry(display->display);
787 wl_registry_add_listener(display->registry,
788 &registry_listener, display);
789 wl_display_roundtrip(display->display);
790 if (display->shm == NULL) {
791 fprintf(stderr, "No wl_shm global\n");
792 exit(1);
793 }
794
795 wl_display_roundtrip(display->display);
796
797 if (!(display->formats & (1 << WL_SHM_FORMAT_XRGB8888))) {
798 fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
799 exit(1);
800 }
801
802 return display;
803}
804
805static void
806destroy_display(struct display *display)
807{
808 if (display->shm)
809 wl_shm_destroy(display->shm);
810
811 if (display->shell)
Jonas Ådahla74eff92016-08-11 23:39:31 +0800812 zxdg_shell_v6_destroy(display->shell);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500813
814 if (display->fshell)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800815 zwp_fullscreen_shell_v1_release(display->fshell);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500816
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300817 if (display->viewporter)
818 wp_viewporter_destroy(display->viewporter);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500819
820 if (display->compositor)
821 wl_compositor_destroy(display->compositor);
822
823 wl_registry_destroy(display->registry);
824 wl_display_flush(display->display);
825 wl_display_disconnect(display->display);
826 free(display);
827}
828
829static void
830signal_int(int signum)
831{
832 running = 0;
833}
834
835static void
836print_usage(int retval)
837{
838 printf(
839 "usage: weston-simple-damage [options]\n\n"
840 "options:\n"
841 " -h, --help\t\tPring this help\n"
842 " --verbose\t\tPrint verbose log information\n"
843 " --version=VERSION\tVersion of wl_surface to use\n"
844 " --width=WIDTH\t\tWidth of the window\n"
845 " --height=HEIGHT\tHeight of the window\n"
846 " --scale=SCALE\t\tScale factor for the surface\n"
847 " --transform=TRANSFORM\tTransform for the surface\n"
848 " --rotating-transform\tUse a different buffer_transform for each frame\n"
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300849 " --use-viewport\tUse wp_viewport\n"
Derek Foremanfb1e1262015-11-18 16:32:34 -0600850 " --use-damage-buffer\tUse damage_buffer to post damage\n"
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500851 );
852
853 exit(retval);
854}
855
856static int
857parse_transform(const char *str, enum wl_output_transform *transform)
858{
859 int i;
860 static const struct {
861 const char *name;
862 enum wl_output_transform transform;
863 } names[] = {
864 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
865 { "90", WL_OUTPUT_TRANSFORM_90 },
866 { "180", WL_OUTPUT_TRANSFORM_180 },
867 { "270", WL_OUTPUT_TRANSFORM_270 },
868 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
869 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
870 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
871 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
872 };
873
874 for (i = 0; i < 8; i++) {
875 if (strcmp(names[i].name, str) == 0) {
876 *transform = names[i].transform;
877 return 1;
878 }
879 }
880
881 return 0;
882}
883
884int
885main(int argc, char **argv)
886{
887 struct sigaction sigint;
888 struct display *display;
889 struct window *window;
890 int i, ret = 0;
891 int version = -1;
892 int width = 300, height = 200, scale = 1;
893 enum wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
894 enum window_flags flags = 0;
895
896 for (i = 1; i < argc; ++i) {
897 if (strcmp(argv[i], "--help") == 0 ||
898 strcmp(argv[i], "-h") == 0) {
899 print_usage(0);
900 } else if (sscanf(argv[i], "--version=%d", &version) > 0) {
Derek Foremanfb1e1262015-11-18 16:32:34 -0600901 if (version < 1 || version > 4) {
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500902 fprintf(stderr, "Unsupported wl_surface version: %d\n",
903 version);
904 return 1;
905 }
906 continue;
907 } else if (strcmp(argv[i], "--verbose") == 0) {
908 print_debug = 1;
909 continue;
910 } else if (sscanf(argv[i], "--width=%d", &width) > 0) {
911 continue;
912 } else if (sscanf(argv[i], "--height=%d", &height) > 0) {
913 continue;
914 } else if (strncmp(argv[i], "--transform=", 12) == 0 &&
915 parse_transform(argv[i] + 12, &transform) > 0) {
916 continue;
917 } else if (strcmp(argv[i], "--rotating-transform") == 0) {
918 flags |= WINDOW_FLAG_ROTATING_TRANSFORM;
919 continue;
920 } else if (sscanf(argv[i], "--scale=%d", &scale) > 0) {
921 continue;
922 } else if (strcmp(argv[i], "--use-viewport") == 0) {
923 flags |= WINDOW_FLAG_USE_VIEWPORT;
924 continue;
Derek Foremanfb1e1262015-11-18 16:32:34 -0600925 } else if (strcmp(argv[i], "--use-damage-buffer") == 0) {
926 flags |= WINDOW_FLAG_USE_DAMAGE_BUFFER;
927 continue;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500928 } else {
929 printf("Invalid option: %s\n", argv[i]);
930 print_usage(255);
931 }
932 }
933
934 display = create_display(version);
935
936 window = create_window(display, width, height, transform, scale, flags);
937 if (!window)
938 return 1;
939
940 sigint.sa_handler = signal_int;
941 sigemptyset(&sigint.sa_mask);
942 sigint.sa_flags = SA_RESETHAND;
943 sigaction(SIGINT, &sigint, NULL);
944
Jonas Ådahla74eff92016-08-11 23:39:31 +0800945 if (!window->wait_for_configure)
946 redraw(window, NULL, 0);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500947
948 while (running && ret != -1)
949 ret = wl_display_dispatch(display->display);
950
951 fprintf(stderr, "simple-shm exiting\n");
952 destroy_window(window);
953 destroy_display(display);
954
955 return 0;
956}