blob: 6b099bd64b4d5ec732365cb7e437242362980199 [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>
Antonio Borneo39578632019-04-26 23:57:31 +020038#include <errno.h>
Jason Ekstrand549a53f2014-04-05 09:22:15 -050039
40#include <wayland-client.h>
Jon Cruz4678bab2015-06-15 15:37:07 -070041#include "shared/os-compatibility.h"
Pekka Paalanenecbdcfd2019-04-04 14:46:00 +030042#include <libweston/zalloc.h>
ant8mef99fac22018-11-28 22:46:37 +010043#include "xdg-shell-client-protocol.h"
Jonas Ådahl496adb32015-11-17 16:00:27 +080044#include "fullscreen-shell-unstable-v1-client-protocol.h"
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +030045#include "viewporter-client-protocol.h"
Jason Ekstrand549a53f2014-04-05 09:22:15 -050046
47int print_debug = 0;
48
49struct display {
50 struct wl_display *display;
51 struct wl_registry *registry;
52 int compositor_version;
53 struct wl_compositor *compositor;
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +030054 struct wp_viewporter *viewporter;
ant8mef99fac22018-11-28 22:46:37 +010055 struct xdg_wm_base *wm_base;
Jonas Ådahl496adb32015-11-17 16:00:27 +080056 struct zwp_fullscreen_shell_v1 *fshell;
Jason Ekstrand549a53f2014-04-05 09:22:15 -050057 struct wl_shm *shm;
58 uint32_t formats;
59};
60
61struct buffer {
62 struct wl_buffer *buffer;
63 uint32_t *shm_data;
64 int busy;
65};
66
67enum window_flags {
68 WINDOW_FLAG_USE_VIEWPORT = 0x1,
69 WINDOW_FLAG_ROTATING_TRANSFORM = 0x2,
Derek Foremanfb1e1262015-11-18 16:32:34 -060070 WINDOW_FLAG_USE_DAMAGE_BUFFER = 0x4,
Jason Ekstrand549a53f2014-04-05 09:22:15 -050071};
72
73struct window {
74 struct display *display;
75 int width, height, border;
76 struct wl_surface *surface;
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +030077 struct wp_viewport *viewport;
ant8mef99fac22018-11-28 22:46:37 +010078 struct xdg_surface *xdg_surface;
79 struct xdg_toplevel *xdg_toplevel;
Jason Ekstrand549a53f2014-04-05 09:22:15 -050080 struct wl_callback *callback;
81 struct buffer buffers[2];
82 struct buffer *prev_buffer;
Jonas Ådahla74eff92016-08-11 23:39:31 +080083 bool wait_for_configure;
Jason Ekstrand549a53f2014-04-05 09:22:15 -050084
85 enum window_flags flags;
86 int scale;
87 enum wl_output_transform transform;
88
89 struct {
90 float x, y; /* position in pixels */
91 float dx, dy; /* velocity in pixels/second */
92 int radius; /* radius in pixels */
93 uint32_t prev_time;
94 } ball;
95};
96
97static int running = 1;
98
99static void
Jonas Ådahla74eff92016-08-11 23:39:31 +0800100redraw(void *data, struct wl_callback *callback, uint32_t time);
101
102static void
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500103buffer_release(void *data, struct wl_buffer *buffer)
104{
105 struct buffer *mybuf = data;
106
107 mybuf->busy = 0;
108}
109
110static const struct wl_buffer_listener buffer_listener = {
111 buffer_release
112};
113
114static int
115create_shm_buffer(struct display *display, struct buffer *buffer,
116 int width, int height, uint32_t format)
117{
118 struct wl_shm_pool *pool;
119 int fd, size, pitch;
120 void *data;
121
122 pitch = width * 4;
123 size = pitch * height;
124
125 fd = os_create_anonymous_file(size);
126 if (fd < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +0200127 fprintf(stderr, "creating a buffer file for %d B failed: %s\n",
128 size, strerror(errno));
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500129 return -1;
130 }
131
132 data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
133 if (data == MAP_FAILED) {
Antonio Borneo39578632019-04-26 23:57:31 +0200134 fprintf(stderr, "mmap failed: %s\n", strerror(errno));
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500135 close(fd);
136 return -1;
137 }
138
139 pool = wl_shm_create_pool(display->shm, fd, size);
140 buffer->buffer = wl_shm_pool_create_buffer(pool, 0,
141 width, height,
142 pitch, format);
143 wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
144 wl_shm_pool_destroy(pool);
145 close(fd);
146
147 buffer->shm_data = data;
148
149 return 0;
150}
151
152static void
ant8mef99fac22018-11-28 22:46:37 +0100153xdg_surface_handle_configure(void *data, struct xdg_surface *surface,
Jonas Ådahla74eff92016-08-11 23:39:31 +0800154 uint32_t serial)
155{
156 struct window *window = data;
157
ant8mef99fac22018-11-28 22:46:37 +0100158 xdg_surface_ack_configure(surface, serial);
Jonas Ådahla74eff92016-08-11 23:39:31 +0800159
160 if (window->wait_for_configure) {
161 redraw(window, NULL, 0);
162 window->wait_for_configure = false;
163 }
164}
165
ant8mef99fac22018-11-28 22:46:37 +0100166static const struct xdg_surface_listener xdg_surface_listener = {
Jonas Ådahla74eff92016-08-11 23:39:31 +0800167 xdg_surface_handle_configure,
168};
169
170static void
ant8mef99fac22018-11-28 22:46:37 +0100171xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *toplevel,
Jonas Ådahla74eff92016-08-11 23:39:31 +0800172 int32_t width, int32_t height,
173 struct wl_array *states)
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500174{
175}
176
177static void
ant8mef99fac22018-11-28 22:46:37 +0100178xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel)
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500179{
180 running = 0;
181}
182
ant8mef99fac22018-11-28 22:46:37 +0100183static const struct xdg_toplevel_listener xdg_toplevel_listener = {
Jonas Ådahla74eff92016-08-11 23:39:31 +0800184 xdg_toplevel_handle_configure,
185 xdg_toplevel_handle_close,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500186};
187
188static float
189bounded_randf(float a, float b)
190{
191 return a + ((float)rand() / (float)RAND_MAX) * (b - a);
192}
193
194static void
195window_init_game(struct window *window)
196{
197 int ax1, ay1, ax2, ay2; /* playable arena size */
198 struct timeval tv;
199
200 gettimeofday(&tv, NULL);
201 srand(tv.tv_usec);
202
203 window->ball.radius = 10;
204
205 ax1 = window->border + window->ball.radius;
206 ay1 = window->border + window->ball.radius;
207 ax2 = window->width - window->border - window->ball.radius;
208 ay2 = window->height - window->border - window->ball.radius;
209
210 window->ball.x = bounded_randf(ax1, ax2);
211 window->ball.y = bounded_randf(ay1, ay2);
212
213 window->ball.dx = bounded_randf(0, window->width);
214 window->ball.dy = bounded_randf(0, window->height);
215
216 window->ball.prev_time = 0;
217}
218
219static void
220window_advance_game(struct window *window, uint32_t timestamp)
221{
222 int ax1, ay1, ax2, ay2; /* Arena size */
223 float dt;
224
225 if (window->ball.prev_time == 0) {
226 /* first pass, don't do anything */
227 window->ball.prev_time = timestamp;
228 return;
229 }
230
231 /* dt in seconds */
232 dt = (float)(timestamp - window->ball.prev_time) / 1000.0f;
233
234 ax1 = window->border + window->ball.radius;
235 ay1 = window->border + window->ball.radius;
236 ax2 = window->width - window->border - window->ball.radius;
237 ay2 = window->height - window->border - window->ball.radius;
238
239 window->ball.x += window->ball.dx * dt;
240 while (window->ball.x < ax1 || ax2 < window->ball.x) {
241 if (window->ball.x < ax1)
242 window->ball.x = 2 * ax1 - window->ball.x;
243 if (ax2 <= window->ball.x)
244 window->ball.x = 2 * ax2 - window->ball.x;
245
246 window->ball.dx *= -1.0f;
247 }
248
249 window->ball.y += window->ball.dy * dt;
250 while (window->ball.y < ay1 || ay2 < window->ball.y) {
251 if (window->ball.y < ay1)
252 window->ball.y = 2 * ay1 - window->ball.y;
253 if (ay2 <= window->ball.y)
254 window->ball.y = 2 * ay2 - window->ball.y;
255
256 window->ball.dy *= -1.0f;
257 }
258
259 window->ball.prev_time = timestamp;
260}
261
262static struct window *
263create_window(struct display *display, int width, int height,
264 enum wl_output_transform transform, int scale,
265 enum window_flags flags)
266{
267 struct window *window;
268
269 if (display->compositor_version < 2 &&
270 (transform != WL_OUTPUT_TRANSFORM_NORMAL ||
271 flags & WINDOW_FLAG_ROTATING_TRANSFORM)) {
272 fprintf(stderr, "wl_surface.buffer_transform unsupported in "
273 "wl_surface version %d\n",
274 display->compositor_version);
275 exit(1);
276 }
277
278 if (display->compositor_version < 3 &&
279 (! (flags & WINDOW_FLAG_USE_VIEWPORT)) && scale != 1) {
280 fprintf(stderr, "wl_surface.buffer_scale unsupported in "
281 "wl_surface version %d\n",
282 display->compositor_version);
283 exit(1);
284 }
285
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300286 if (display->viewporter == NULL && (flags & WINDOW_FLAG_USE_VIEWPORT)) {
287 fprintf(stderr, "Compositor does not support wp_viewport");
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500288 exit(1);
289 }
290
Christopher Michaele1434d32015-12-20 07:41:52 -0500291 if (display->compositor_version <
292 WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION &&
Derek Foremanfb1e1262015-11-18 16:32:34 -0600293 (flags & WINDOW_FLAG_USE_DAMAGE_BUFFER)) {
294 fprintf(stderr, "wl_surface.damage_buffer unsupported in "
295 "wl_surface version %d\n",
296 display->compositor_version);
297 exit(1);
298 }
299
Bryce Harrington0d1a6222016-02-11 16:42:49 -0800300 window = zalloc(sizeof *window);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500301 if (!window)
302 return NULL;
303
304 window->callback = NULL;
305 window->display = display;
306 window->width = width;
307 window->height = height;
308 window->border = 10;
309 window->flags = flags;
310 window->transform = transform;
311 window->scale = scale;
312
313 window_init_game(window);
314
315 window->surface = wl_compositor_create_surface(display->compositor);
316
317 if (window->flags & WINDOW_FLAG_USE_VIEWPORT)
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300318 window->viewport = wp_viewporter_get_viewport(display->viewporter,
319 window->surface);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500320
ant8mef99fac22018-11-28 22:46:37 +0100321 if (display->wm_base) {
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500322 window->xdg_surface =
ant8mef99fac22018-11-28 22:46:37 +0100323 xdg_wm_base_get_xdg_surface(display->wm_base,
324 window->surface);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500325
326 assert(window->xdg_surface);
327
ant8mef99fac22018-11-28 22:46:37 +0100328 xdg_surface_add_listener(window->xdg_surface,
329 &xdg_surface_listener, window);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500330
Jonas Ådahla74eff92016-08-11 23:39:31 +0800331 window->xdg_toplevel =
ant8mef99fac22018-11-28 22:46:37 +0100332 xdg_surface_get_toplevel(window->xdg_surface);
Jonas Ådahla74eff92016-08-11 23:39:31 +0800333
334 assert(window->xdg_toplevel);
335
ant8mef99fac22018-11-28 22:46:37 +0100336 xdg_toplevel_add_listener(window->xdg_toplevel,
337 &xdg_toplevel_listener, window);
Jonas Ådahla74eff92016-08-11 23:39:31 +0800338
ant8mef99fac22018-11-28 22:46:37 +0100339 xdg_toplevel_set_title(window->xdg_toplevel, "simple-damage");
Marius Vlad31512202021-09-09 14:10:19 +0300340 xdg_toplevel_set_app_id(window->xdg_toplevel,
341 "org.freedesktop.weston.simple-damage");
Jonas Ådahla74eff92016-08-11 23:39:31 +0800342
343 window->wait_for_configure = true;
344 wl_surface_commit(window->surface);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500345 } else if (display->fshell) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800346 zwp_fullscreen_shell_v1_present_surface(display->fshell,
347 window->surface,
348 ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
349 NULL);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500350 } else {
351 assert(0);
352 }
353
354 /* Initialise damage to full surface, so the padding gets painted */
Derek Foremanfb1e1262015-11-18 16:32:34 -0600355 if (window->flags & WINDOW_FLAG_USE_DAMAGE_BUFFER) {
356 wl_surface_damage_buffer(window->surface, 0, 0,
357 INT32_MAX, INT32_MAX);
358 } else {
359 wl_surface_damage(window->surface, 0, 0, INT32_MAX, INT32_MAX);
360 }
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500361 return window;
362}
363
364static void
365destroy_window(struct window *window)
366{
367 if (window->callback)
368 wl_callback_destroy(window->callback);
369
370 if (window->buffers[0].buffer)
371 wl_buffer_destroy(window->buffers[0].buffer);
372 if (window->buffers[1].buffer)
373 wl_buffer_destroy(window->buffers[1].buffer);
374
Jonas Ådahla74eff92016-08-11 23:39:31 +0800375 if (window->xdg_toplevel)
ant8mef99fac22018-11-28 22:46:37 +0100376 xdg_toplevel_destroy(window->xdg_toplevel);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500377 if (window->xdg_surface)
ant8mef99fac22018-11-28 22:46:37 +0100378 xdg_surface_destroy(window->xdg_surface);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500379 if (window->viewport)
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300380 wp_viewport_destroy(window->viewport);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500381 wl_surface_destroy(window->surface);
382 free(window);
383}
384
385static struct buffer *
386window_next_buffer(struct window *window)
387{
388 struct buffer *buffer;
389 int ret = 0, bwidth, bheight;
390
391 if (!window->buffers[0].busy)
392 buffer = &window->buffers[0];
393 else if (!window->buffers[1].busy)
394 buffer = &window->buffers[1];
395 else
396 return NULL;
397
398 switch (window->transform) {
399 default:
400 case WL_OUTPUT_TRANSFORM_NORMAL:
401 case WL_OUTPUT_TRANSFORM_180:
402 case WL_OUTPUT_TRANSFORM_FLIPPED:
403 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
404 bwidth = window->width * window->scale;
405 bheight = window->height * window->scale;
406 break;
407 case WL_OUTPUT_TRANSFORM_90:
408 case WL_OUTPUT_TRANSFORM_270:
409 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
410 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
411 bwidth = window->height * window->scale;
412 bheight = window->width * window->scale;
413 break;
414 }
415
416 if (!buffer->buffer) {
417 ret = create_shm_buffer(window->display, buffer,
418 bwidth, bheight,
419 WL_SHM_FORMAT_ARGB8888);
420
421 if (ret < 0)
422 return NULL;
423 }
424
425 return buffer;
426}
427
428static void
429paint_box(uint32_t *pixels, int pitch, int x, int y, int width, int height,
430 uint32_t color)
431{
432 int i, j;
433
434 for (j = y; j < y + height; ++j)
435 for (i = x; i < x + width; ++i)
436 pixels[i + j * pitch] = color;
437}
438
439static void
440paint_circle(uint32_t *pixels, int pitch, float x, float y, int radius,
441 uint32_t color)
442{
443 int i, j;
444
445 for (j = y - radius; j <= (int)(y + radius); ++j)
446 for (i = x - radius; i <= (int)(x + radius); ++i)
447 if ((j+0.5f-y)*(j+0.5f-y) + (i+0.5f-x)*(i+0.5f-x) <= radius * radius)
448 pixels[i + j * pitch] = color;
449}
450
451static void
452window_get_transformed_ball(struct window *window, float *bx, float *by)
453{
454 float wx, wy;
455
456 wx = window->ball.x;
457 wy = window->ball.y;
458
459 switch (window->transform) {
460 default:
461 case WL_OUTPUT_TRANSFORM_NORMAL:
462 *bx = wx;
463 *by = wy;
464 break;
465 case WL_OUTPUT_TRANSFORM_90:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200466 *bx = wy;
467 *by = window->width - wx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500468 break;
469 case WL_OUTPUT_TRANSFORM_180:
470 *bx = window->width - wx;
471 *by = window->height - wy;
472 break;
473 case WL_OUTPUT_TRANSFORM_270:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200474 *bx = window->height - wy;
475 *by = wx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500476 break;
477 case WL_OUTPUT_TRANSFORM_FLIPPED:
478 *bx = window->width - wx;
479 *by = wy;
480 break;
481 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200482 *bx = wy;
483 *by = wx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500484 break;
485 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
486 *bx = wx;
487 *by = window->height - wy;
488 break;
489 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200490 *bx = window->height - wy;
491 *by = window->width - wx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500492 break;
493 }
494
495 *bx *= window->scale;
496 *by *= window->scale;
497
498 if (window->viewport) {
499 /* We're drawing half-size because of the viewport */
500 *bx /= 2;
501 *by /= 2;
502 }
503}
504
505static const struct wl_callback_listener frame_listener;
506
507static void
508redraw(void *data, struct wl_callback *callback, uint32_t time)
509{
510 struct window *window = data;
511 struct buffer *buffer;
Derek Foreman29b846e2015-11-18 16:32:33 -0600512 int off_x = 0, off_y = 0;
513 int bwidth, bheight, bborder, bpitch, bradius;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500514 float bx, by;
515
516 buffer = window_next_buffer(window);
517 if (!buffer) {
518 fprintf(stderr,
519 !callback ? "Failed to create the first buffer.\n" :
520 "Both buffers busy at redraw(). Server bug?\n");
521 abort();
522 }
523
524 /* Rotate the damage, but keep the even/odd parity so the
525 * dimensions of the buffers don't change */
526 if (window->flags & WINDOW_FLAG_ROTATING_TRANSFORM)
527 window->transform = (window->transform + 2) % 8;
528
529 switch (window->transform) {
530 default:
531 case WL_OUTPUT_TRANSFORM_NORMAL:
532 case WL_OUTPUT_TRANSFORM_180:
533 case WL_OUTPUT_TRANSFORM_FLIPPED:
534 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
535 bwidth = window->width * window->scale;
536 bheight = window->height * window->scale;
537 break;
538 case WL_OUTPUT_TRANSFORM_90:
539 case WL_OUTPUT_TRANSFORM_270:
540 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
541 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
542 bwidth = window->height * window->scale;
543 bheight = window->width * window->scale;
544 break;
545 }
546
547 bpitch = bwidth;
548
549 bborder = window->border * window->scale;
550 bradius = window->ball.radius * window->scale;
551
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500552 if (window->viewport) {
Derek Foreman29b846e2015-11-18 16:32:33 -0600553 int tx, ty;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500554 /* Fill the whole thing with red to detect viewport errors */
555 paint_box(buffer->shm_data, bpitch, 0, 0, bwidth, bheight,
556 0xffff0000);
557
558 /* The buffer is the same size. However, we crop it
559 * and scale it up by a factor of 2 */
560 bborder /= 2;
561 bradius /= 2;
562 bwidth /= 2;
563 bheight /= 2;
564
565 /* Offset the drawing region */
Derek Foreman29b846e2015-11-18 16:32:33 -0600566 tx = (window->width / 3) * window->scale;
567 ty = (window->height / 5) * window->scale;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500568 switch (window->transform) {
569 default:
570 case WL_OUTPUT_TRANSFORM_NORMAL:
Derek Foreman29b846e2015-11-18 16:32:33 -0600571 off_y = ty;
572 off_x = tx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500573 break;
574 case WL_OUTPUT_TRANSFORM_90:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200575 off_y = bheight - tx;
576 off_x = ty;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500577 break;
578 case WL_OUTPUT_TRANSFORM_180:
Derek Foreman29b846e2015-11-18 16:32:33 -0600579 off_y = bheight - ty;
580 off_x = bwidth - tx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500581 break;
582 case WL_OUTPUT_TRANSFORM_270:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200583 off_y = tx;
584 off_x = bwidth - ty;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500585 break;
586 case WL_OUTPUT_TRANSFORM_FLIPPED:
Derek Foreman29b846e2015-11-18 16:32:33 -0600587 off_y = ty;
588 off_x = bwidth - tx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500589 break;
590 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200591 off_y = tx;
592 off_x = ty;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500593 break;
594 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
Derek Foreman29b846e2015-11-18 16:32:33 -0600595 off_y = bheight - ty;
596 off_x = tx;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500597 break;
598 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200599 off_y = bheight - tx;
600 off_x = bwidth - ty;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500601 break;
602 }
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300603 wp_viewport_set_source(window->viewport,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500604 wl_fixed_from_int(window->width / 3),
605 wl_fixed_from_int(window->height / 5),
606 wl_fixed_from_int(window->width / 2),
607 wl_fixed_from_int(window->height / 2));
608 }
609
610 /* Paint the border */
Derek Foreman29b846e2015-11-18 16:32:33 -0600611 paint_box(buffer->shm_data, bpitch, off_x, off_y,
612 bwidth, bborder, 0xffffffff);
613 paint_box(buffer->shm_data, bpitch, off_x, off_y,
614 bborder, bheight, 0xffffffff);
615 paint_box(buffer->shm_data, bpitch, off_x + bwidth - bborder, off_y,
616 bborder, bheight, 0xffffffff);
617 paint_box(buffer->shm_data, bpitch, off_x, off_y + bheight - bborder,
618 bwidth, bborder, 0xffffffff);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500619
620 /* fill with translucent */
Derek Foreman29b846e2015-11-18 16:32:33 -0600621 paint_box(buffer->shm_data, bpitch, off_x + bborder, off_y + bborder,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500622 bwidth - 2 * bborder, bheight - 2 * bborder, 0x80000000);
623
624 /* Damage where the ball was */
Derek Foremanfb1e1262015-11-18 16:32:34 -0600625 if (window->flags & WINDOW_FLAG_USE_DAMAGE_BUFFER) {
626 window_get_transformed_ball(window, &bx, &by);
627 wl_surface_damage_buffer(window->surface,
628 bx - bradius + off_x,
629 by - bradius + off_y,
630 bradius * 2 + 1,
631 bradius * 2 + 1);
632 } else {
633 wl_surface_damage(window->surface,
634 window->ball.x - window->ball.radius,
635 window->ball.y - window->ball.radius,
636 window->ball.radius * 2 + 1,
637 window->ball.radius * 2 + 1);
638 }
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500639 window_advance_game(window, time);
640
641 window_get_transformed_ball(window, &bx, &by);
642
643 /* Paint the ball */
Derek Foreman29b846e2015-11-18 16:32:33 -0600644 paint_circle(buffer->shm_data, bpitch, off_x + bx, off_y + by,
645 bradius, 0xff00ff00);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500646
647 if (print_debug) {
648 printf("Ball now located at (%f, %f)\n",
649 window->ball.x, window->ball.y);
650
651 printf("Circle painted at (%f, %f), radius %d\n", bx, by,
652 bradius);
653
654 printf("Buffer damage rectangle: (%d, %d) @ %dx%d\n",
Derek Foreman29b846e2015-11-18 16:32:33 -0600655 (int)(bx - bradius) + off_x,
656 (int)(by - bradius) + off_y,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500657 bradius * 2 + 1, bradius * 2 + 1);
658 }
659
660 /* Damage where the ball is now */
Derek Foremanfb1e1262015-11-18 16:32:34 -0600661 if (window->flags & WINDOW_FLAG_USE_DAMAGE_BUFFER) {
662 wl_surface_damage_buffer(window->surface,
663 bx - bradius + off_x,
664 by - bradius + off_y,
665 bradius * 2 + 1,
666 bradius * 2 + 1);
667 } else {
668 wl_surface_damage(window->surface,
669 window->ball.x - window->ball.radius,
670 window->ball.y - window->ball.radius,
671 window->ball.radius * 2 + 1,
672 window->ball.radius * 2 + 1);
673 }
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500674 wl_surface_attach(window->surface, buffer->buffer, 0, 0);
675
676 if (window->display->compositor_version >= 2 &&
677 (window->transform != WL_OUTPUT_TRANSFORM_NORMAL ||
678 window->flags & WINDOW_FLAG_ROTATING_TRANSFORM))
679 wl_surface_set_buffer_transform(window->surface,
680 window->transform);
681
682 if (window->viewport)
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300683 wp_viewport_set_destination(window->viewport,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500684 window->width,
685 window->height);
686
687 if (window->scale != 1)
688 wl_surface_set_buffer_scale(window->surface,
689 window->scale);
690
691 if (callback)
692 wl_callback_destroy(callback);
693
694 window->callback = wl_surface_frame(window->surface);
695 wl_callback_add_listener(window->callback, &frame_listener, window);
696 wl_surface_commit(window->surface);
697 buffer->busy = 1;
698}
699
700static const struct wl_callback_listener frame_listener = {
701 redraw
702};
703
704static void
705shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
706{
707 struct display *d = data;
708
709 d->formats |= (1 << format);
710}
711
712struct wl_shm_listener shm_listener = {
713 shm_format
714};
715
716static void
ant8mef99fac22018-11-28 22:46:37 +0100717xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500718{
ant8mef99fac22018-11-28 22:46:37 +0100719 xdg_wm_base_pong(shell, serial);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500720}
721
ant8mef99fac22018-11-28 22:46:37 +0100722static const struct xdg_wm_base_listener wm_base_listener = {
723 xdg_wm_base_ping,
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500724};
725
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500726static void
727registry_handle_global(void *data, struct wl_registry *registry,
728 uint32_t id, const char *interface, uint32_t version)
729{
730 struct display *d = data;
731
732 if (strcmp(interface, "wl_compositor") == 0) {
733 if (d->compositor_version > (int)version) {
734 fprintf(stderr, "Compositor does not support "
735 "wl_surface version %d\n", d->compositor_version);
736 exit(1);
737 }
738
739 if (d->compositor_version < 0)
740 d->compositor_version = version;
741
742 d->compositor =
743 wl_registry_bind(registry,
744 id, &wl_compositor_interface,
745 d->compositor_version);
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300746 } else if (strcmp(interface, "wp_viewporter") == 0) {
747 d->viewporter = wl_registry_bind(registry, id,
748 &wp_viewporter_interface, 1);
ant8mef99fac22018-11-28 22:46:37 +0100749 } else if (strcmp(interface, "xdg_wm_base") == 0) {
750 d->wm_base = wl_registry_bind(registry,
751 id, &xdg_wm_base_interface, 1);
752 xdg_wm_base_add_listener(d->wm_base, &wm_base_listener, d);
Jonas Ådahl496adb32015-11-17 16:00:27 +0800753 } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500754 d->fshell = wl_registry_bind(registry,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800755 id, &zwp_fullscreen_shell_v1_interface, 1);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500756 } else if (strcmp(interface, "wl_shm") == 0) {
757 d->shm = wl_registry_bind(registry,
758 id, &wl_shm_interface, 1);
759 wl_shm_add_listener(d->shm, &shm_listener, d);
760 }
761}
762
763static void
764registry_handle_global_remove(void *data, struct wl_registry *registry,
765 uint32_t name)
766{
767}
768
769static const struct wl_registry_listener registry_listener = {
770 registry_handle_global,
771 registry_handle_global_remove
772};
773
774static struct display *
775create_display(int version)
776{
777 struct display *display;
778
Marius Vlad6eabd932021-12-09 18:06:03 +0200779 display = zalloc(sizeof *display);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500780 if (display == NULL) {
781 fprintf(stderr, "out of memory\n");
782 exit(1);
783 }
784 display->display = wl_display_connect(NULL);
785 assert(display->display);
786
787 display->compositor_version = version;
788 display->formats = 0;
789 display->registry = wl_display_get_registry(display->display);
790 wl_registry_add_listener(display->registry,
791 &registry_listener, display);
792 wl_display_roundtrip(display->display);
793 if (display->shm == NULL) {
794 fprintf(stderr, "No wl_shm global\n");
795 exit(1);
796 }
797
798 wl_display_roundtrip(display->display);
799
800 if (!(display->formats & (1 << WL_SHM_FORMAT_XRGB8888))) {
801 fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
802 exit(1);
803 }
804
805 return display;
806}
807
808static void
809destroy_display(struct display *display)
810{
811 if (display->shm)
812 wl_shm_destroy(display->shm);
813
ant8mef99fac22018-11-28 22:46:37 +0100814 if (display->wm_base)
815 xdg_wm_base_destroy(display->wm_base);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500816
817 if (display->fshell)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800818 zwp_fullscreen_shell_v1_release(display->fshell);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500819
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300820 if (display->viewporter)
821 wp_viewporter_destroy(display->viewporter);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500822
823 if (display->compositor)
824 wl_compositor_destroy(display->compositor);
825
826 wl_registry_destroy(display->registry);
827 wl_display_flush(display->display);
828 wl_display_disconnect(display->display);
829 free(display);
830}
831
832static void
833signal_int(int signum)
834{
835 running = 0;
836}
837
838static void
839print_usage(int retval)
840{
841 printf(
842 "usage: weston-simple-damage [options]\n\n"
843 "options:\n"
844 " -h, --help\t\tPring this help\n"
845 " --verbose\t\tPrint verbose log information\n"
846 " --version=VERSION\tVersion of wl_surface to use\n"
847 " --width=WIDTH\t\tWidth of the window\n"
848 " --height=HEIGHT\tHeight of the window\n"
849 " --scale=SCALE\t\tScale factor for the surface\n"
850 " --transform=TRANSFORM\tTransform for the surface\n"
851 " --rotating-transform\tUse a different buffer_transform for each frame\n"
Pekka Paalanen7b69d6c2016-04-15 17:00:21 +0300852 " --use-viewport\tUse wp_viewport\n"
Derek Foremanfb1e1262015-11-18 16:32:34 -0600853 " --use-damage-buffer\tUse damage_buffer to post damage\n"
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500854 );
855
856 exit(retval);
857}
858
859static int
860parse_transform(const char *str, enum wl_output_transform *transform)
861{
862 int i;
863 static const struct {
864 const char *name;
865 enum wl_output_transform transform;
866 } names[] = {
867 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
868 { "90", WL_OUTPUT_TRANSFORM_90 },
869 { "180", WL_OUTPUT_TRANSFORM_180 },
870 { "270", WL_OUTPUT_TRANSFORM_270 },
871 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
872 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
873 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
874 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
875 };
876
877 for (i = 0; i < 8; i++) {
878 if (strcmp(names[i].name, str) == 0) {
879 *transform = names[i].transform;
880 return 1;
881 }
882 }
883
884 return 0;
885}
886
887int
888main(int argc, char **argv)
889{
890 struct sigaction sigint;
891 struct display *display;
892 struct window *window;
893 int i, ret = 0;
894 int version = -1;
895 int width = 300, height = 200, scale = 1;
896 enum wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
897 enum window_flags flags = 0;
898
899 for (i = 1; i < argc; ++i) {
900 if (strcmp(argv[i], "--help") == 0 ||
901 strcmp(argv[i], "-h") == 0) {
902 print_usage(0);
903 } else if (sscanf(argv[i], "--version=%d", &version) > 0) {
Derek Foremanfb1e1262015-11-18 16:32:34 -0600904 if (version < 1 || version > 4) {
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500905 fprintf(stderr, "Unsupported wl_surface version: %d\n",
906 version);
907 return 1;
908 }
909 continue;
910 } else if (strcmp(argv[i], "--verbose") == 0) {
911 print_debug = 1;
912 continue;
913 } else if (sscanf(argv[i], "--width=%d", &width) > 0) {
914 continue;
915 } else if (sscanf(argv[i], "--height=%d", &height) > 0) {
916 continue;
917 } else if (strncmp(argv[i], "--transform=", 12) == 0 &&
918 parse_transform(argv[i] + 12, &transform) > 0) {
919 continue;
920 } else if (strcmp(argv[i], "--rotating-transform") == 0) {
921 flags |= WINDOW_FLAG_ROTATING_TRANSFORM;
922 continue;
923 } else if (sscanf(argv[i], "--scale=%d", &scale) > 0) {
924 continue;
925 } else if (strcmp(argv[i], "--use-viewport") == 0) {
926 flags |= WINDOW_FLAG_USE_VIEWPORT;
927 continue;
Derek Foremanfb1e1262015-11-18 16:32:34 -0600928 } else if (strcmp(argv[i], "--use-damage-buffer") == 0) {
929 flags |= WINDOW_FLAG_USE_DAMAGE_BUFFER;
930 continue;
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500931 } else {
932 printf("Invalid option: %s\n", argv[i]);
933 print_usage(255);
934 }
935 }
936
937 display = create_display(version);
938
939 window = create_window(display, width, height, transform, scale, flags);
940 if (!window)
941 return 1;
942
943 sigint.sa_handler = signal_int;
944 sigemptyset(&sigint.sa_mask);
945 sigint.sa_flags = SA_RESETHAND;
946 sigaction(SIGINT, &sigint, NULL);
947
Jonas Ådahla74eff92016-08-11 23:39:31 +0800948 if (!window->wait_for_configure)
949 redraw(window, NULL, 0);
Jason Ekstrand549a53f2014-04-05 09:22:15 -0500950
951 while (running && ret != -1)
952 ret = wl_display_dispatch(display->display);
953
954 fprintf(stderr, "simple-shm exiting\n");
955 destroy_window(window);
956 destroy_display(display);
957
958 return 0;
959}