1/* swc: libswc/compositor.c
2 *
3 * Copyright (c) 2013-2020 Michael Forney
4 *
5 * Based in part upon compositor.c from weston, which is:
6 *
7 * Copyright © 2010-2011 Intel Corporation
8 * Copyright © 2008-2011 Kristian Høgsberg
9 * Copyright © 2012 Collabora, Ltd.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30#include "compositor.h"
31#include "backend.h"
32#include "data_device_manager.h"
33#include "decor.h"
34#ifdef ENABLE_DRM
35#include "drm.h"
36#endif
37#include "event.h"
38#include "internal.h"
39#include "launch.h"
40#include "output.h"
41#include "pointer.h"
42#include "region.h"
43#include "screen.h"
44#include "seat.h"
45#include "shm.h"
46#include "subsurface.h"
47#include "surface.h"
48#include "swc.h"
49#include "util.h"
50#include "view.h"
51#include "window.h"
52
53#include <assert.h>
54#include <errno.h>
55#include <limits.h>
56#include <stdio.h>
57#include <stdlib.h>
58#ifdef ENABLE_DRM
59#include <wld/drm.h>
60#endif
61#include <wld/wld.h>
62#include <xkbcommon/xkbcommon-keysyms.h>
63
64#define DEFAULT_BG 0xff000000u
65
66static inline int32_t
67clamp_i32(int64_t v)
68{
69 if (v > INT32_MAX) {
70 return INT32_MAX;
71 }
72 if (v < INT32_MIN) {
73 return INT32_MIN;
74 }
75 return (int32_t)v;
76}
77
78static inline uint32_t
79span_u32(int32_t a, int32_t b)
80{
81 int64_t d = (int64_t)b - (int64_t)a;
82
83 if (d <= 0) {
84 return 0;
85 }
86 if (d > UINT32_MAX) {
87 return UINT32_MAX;
88 }
89 return (uint32_t)d;
90}
91
92struct target {
93 struct wld_surface *surface;
94 struct wld_buffer *next_buffer, *current_buffer;
95 struct view *view;
96 struct view_handler view_handler;
97 uint32_t mask;
98
99 struct wl_listener screen_destroy_listener;
100};
101
102static bool
103handle_motion(struct pointer_handler *handler, uint32_t time, wl_fixed_t x,
104 wl_fixed_t y);
105static bool
106handle_button(struct pointer_handler *handler, uint32_t time,
107 struct button *button, uint32_t state);
108static void
109perform_update(void *data);
110
111static struct pointer_handler pointer_handler = {
112 .motion = handle_motion,
113 .button = handle_button,
114};
115
116static struct {
117 struct wl_list views;
118 pixman_region32_t damage, opaque;
119 struct wl_listener swc_listener;
120
121 /* A mask of screens that have been repainted but are waiting on a page
122 * flip. */
123 uint32_t pending_flips;
124
125 /* A mask of screens that are scheduled to be repainted on the next idle. */
126 uint32_t scheduled_updates;
127
128 bool updating;
129 struct wl_global *global;
130 bool initialized;
131
132 /* zoom level (1.0 = normal, >1 = zoomed in, <1 = zoomed out) */
133 float zoom;
134 struct wld_buffer *zoom_buffer;
135} compositor;
136
137static struct {
138 bool active;
139 int32_t x, y;
140 uint32_t width, height;
141 uint32_t color;
142 uint32_t border_width;
143} overlay;
144
145struct swc_compositor swc_compositor = {
146 .pointer_handler = &pointer_handler,
147};
148
149static void
150handle_screen_destroy(struct wl_listener *listener, void *data)
151{
152 struct target *target =
153 wl_container_of(listener, target, screen_destroy_listener);
154
155 wld_destroy_surface(target->surface);
156 free(target);
157}
158
159static struct target *
160target_get(struct screen *screen)
161{
162 struct wl_listener *listener =
163 wl_signal_get(&screen->destroy_signal, &handle_screen_destroy);
164 struct target *target;
165
166 return listener ? wl_container_of(listener, target, screen_destroy_listener)
167 : NULL;
168}
169
170static void
171handle_screen_frame(struct view_handler *handler, uint32_t time)
172{
173 struct target *target = wl_container_of(handler, target, view_handler);
174 struct compositor_view *view;
175
176 compositor.pending_flips &= ~target->mask;
177
178 wl_list_for_each(view, &compositor.views, link)
179 {
180 if (view->visible && view->base.screens & target->mask) {
181 view_frame(&view->base, time);
182 }
183 }
184
185 if (target->current_buffer) {
186 wld_surface_release(target->surface, target->current_buffer);
187 }
188
189 target->current_buffer = target->next_buffer;
190
191 /* If we had scheduled updates that couldn't run because we were waiting on
192 * a page flip, run them now. If the compositor is currently updating, then
193 * the frame finished immediately, and we can be sure that there are no
194 * pending updates. */
195 if (compositor.scheduled_updates && !compositor.updating) {
196 perform_update(NULL);
197 }
198}
199
200static const struct view_handler_impl screen_view_handler = {
201 .frame = handle_screen_frame,
202};
203
204static int
205target_swap_buffers(struct target *target)
206{
207 target->next_buffer = wld_surface_take(target->surface);
208 return view_attach(target->view, target->next_buffer);
209}
210
211static struct target *
212target_new(struct screen *screen)
213{
214 struct target *target;
215 struct swc_rectangle *geom = &screen->base.geometry;
216
217 if (!(target = malloc(sizeof(*target)))) {
218 goto error0;
219 }
220
221 target->surface =
222 wld_create_surface(swc.backend->context, geom->width, geom->height,
223 WLD_FORMAT_XRGB8888,
224#ifdef ENABLE_DRM
225 WLD_DRM_FLAG_SCANOUT
226#else
227 WLD_FLAG_MAP
228#endif
229 );
230
231 if (!target->surface) {
232 goto error1;
233 }
234
235 target->view = &screen->planes.primary.view;
236 target->view_handler.impl = &screen_view_handler;
237 wl_list_insert(&target->view->handlers, &target->view_handler.link);
238 target->current_buffer = NULL;
239 target->mask = screen_mask(screen);
240
241 target->screen_destroy_listener.notify = &handle_screen_destroy;
242 wl_signal_add(&screen->destroy_signal, &target->screen_destroy_listener);
243
244 return target;
245
246error1:
247 free(target);
248error0:
249 return NULL;
250}
251
252/* Rendering {{{ */
253
254/* check the client's window buffer is opaque */
255static bool
256view_buffer_is_opaque(struct compositor_view *view)
257{
258 const struct swc_rectangle *geom = &view->base.geometry;
259 struct wld_buffer *buffer = view->base.buffer;
260 uint32_t x1, y1, width, height;
261
262 if (view->buffer_opaque_valid) {
263 return view->buffer_opaque;
264 }
265
266 view->buffer_opaque_valid = true;
267 view->buffer_opaque = false;
268 if (!buffer || buffer->format != WLD_FORMAT_ARGB8888) {
269 return false;
270 }
271
272 if (view->window) {
273 if (view->buffer_offset_x < 0 || view->buffer_offset_y < 0) {
274 return false;
275 }
276 x1 = (uint32_t)view->buffer_offset_x;
277 y1 = (uint32_t)view->buffer_offset_y;
278 width = geom->width;
279 height = geom->height;
280 } else {
281 x1 = 0;
282 y1 = 0;
283 width = buffer->width;
284 height = buffer->height;
285 }
286
287 if (x1 > buffer->width || y1 > buffer->height ||
288 width > buffer->width - x1 || height > buffer->height - y1 ||
289 !wld_map(buffer)) {
290 return false;
291 }
292
293 view->buffer_opaque = true;
294 for (uint32_t y = 0; y < height && view->buffer_opaque; ++y) {
295 const uint8_t *row = (const uint8_t *)buffer->map +
296 (size_t)(y1 + y) * buffer->pitch +
297 (size_t)x1 * 4;
298
299 for (uint32_t x = 0; x < width; ++x) {
300 uint32_t pixel;
301
302 memcpy(&pixel, row + (size_t)x * 4, sizeof(pixel));
303 if ((pixel >> 24) != 0xff) {
304 view->buffer_opaque = false;
305 break;
306 }
307 }
308 }
309 wld_unmap(buffer);
310
311 return view->buffer_opaque;
312}
313
314static void
315repaint_view(struct target *target, struct compositor_view *view,
316 pixman_region32_t *damage)
317{
318 pixman_region32_t geom_region, buffer_region, border_region, view_damage,
319 buffer_damage, border_damage;
320 const struct swc_rectangle *geom = &view->base.geometry,
321 *target_geom = &target->view->geometry;
322 int32_t buf_x, buf_y;
323 uint32_t buf_w, buf_h;
324 int64_t total_border;
325
326 if (!view->base.buffer) {
327 return;
328 }
329
330 buf_w = view->base.buffer->width;
331 buf_h = view->base.buffer->height;
332 buf_x = geom->x - view->buffer_offset_x;
333 buf_y = geom->y - view->buffer_offset_y;
334
335 total_border =
336 (int64_t)view->border.outwidth + (int64_t)view->border.inwidth;
337 pixman_region32_init_rect(&geom_region, geom->x, geom->y, geom->width,
338 geom->height);
339 if (view->window) {
340 pixman_region32_init_rect(&buffer_region, geom->x, geom->y, geom->width,
341 geom->height);
342 } else {
343 pixman_region32_init_rect(&buffer_region, buf_x, buf_y, buf_w, buf_h);
344 }
345 pixman_region32_init_rect(&border_region,
346 geom->x - (int32_t)total_border,
347 geom->y - (int32_t)total_border,
348 geom->width + (uint32_t)(2 * total_border),
349 geom->height + (uint32_t)(2 * total_border));
350 pixman_region32_subtract(&border_region, &border_region, &geom_region);
351 pixman_region32_init_with_extents(&view_damage, &view->extents);
352 pixman_region32_init(&buffer_damage);
353 pixman_region32_init(&border_damage);
354
355 pixman_region32_intersect(&view_damage, &view_damage, damage);
356 pixman_region32_subtract(&view_damage, &view_damage, &view->clip);
357 pixman_region32_intersect(&border_damage, &view_damage, &border_region);
358 pixman_region32_intersect(&buffer_damage, &view_damage, &buffer_region);
359
360 if (pixman_region32_not_empty(&buffer_damage)) {
361 pixman_region32_translate(&buffer_damage,
362 -geom->x + view->buffer_offset_x,
363 -geom->y + view->buffer_offset_y);
364 if (view->buffer->format == WLD_FORMAT_ARGB8888) {
365 pixman_region32_t opaque_damage, blend_damage;
366
367 /* keep pixels that we know are opaque on the accelerated path; only
368 * pixels which might have alpha need blending. */
369 pixman_region32_init(&opaque_damage);
370 pixman_region32_intersect(&opaque_damage, &buffer_damage,
371 &view->surface->state.opaque);
372 pixman_region32_init(&blend_damage);
373 pixman_region32_subtract(&blend_damage, &buffer_damage,
374 &opaque_damage);
375
376 if (!pixman_region32_not_empty(&blend_damage) ||
377 view_buffer_is_opaque(view)) {
378 wld_copy_region(swc.backend->renderer, view->buffer,
379 buf_x - target_geom->x,
380 buf_y - target_geom->y, &buffer_damage);
381 } else {
382 wld_copy_region(swc.backend->renderer, view->buffer,
383 buf_x - target_geom->x,
384 buf_y - target_geom->y, &opaque_damage);
385 wld_blend_region(swc.backend->renderer, view->buffer,
386 buf_x - target_geom->x,
387 buf_y - target_geom->y, &blend_damage);
388 }
389
390 pixman_region32_fini(&blend_damage);
391 pixman_region32_fini(&opaque_damage);
392 } else {
393 wld_copy_region(swc.backend->renderer, view->buffer,
394 buf_x - target_geom->x, buf_y - target_geom->y,
395 &buffer_damage);
396 }
397 }
398
399 pixman_region32_fini(&view_damage);
400 pixman_region32_fini(&buffer_damage);
401
402 pixman_region32_t in_rect;
403 pixman_region32_init_rect(&in_rect,
404 geom->x - view->border.inwidth,
405 geom->y - view->border.inwidth,
406 geom->width + (2 * view->border.inwidth),
407 geom->height + (2 * view->border.inwidth));
408
409 pixman_region32_t out_border;
410 pixman_region32_init(&out_border);
411 pixman_region32_subtract(&out_border, &border_damage, &in_rect);
412
413 pixman_region32_t in_border;
414 pixman_region32_init(&in_border);
415 pixman_region32_subtract(&in_border, &in_rect, &geom_region);
416 pixman_region32_intersect(&in_border, &in_border, &border_damage);
417
418 pixman_region32_fini(&geom_region);
419 pixman_region32_fini(&buffer_region);
420 pixman_region32_fini(&border_region);
421
422 /* Draw border */
423 if (view->border.outwidth > 0 && pixman_region32_not_empty(&out_border)) {
424 pixman_region32_translate(&out_border, -target_geom->x,
425 -target_geom->y);
426 wld_fill_region(swc.backend->renderer, view->border.outcolor, &out_border);
427 }
428
429 if (view->border.inwidth > 0 && pixman_region32_not_empty(&in_border)) {
430 pixman_region32_translate(&in_border, -target_geom->x, -target_geom->y);
431 wld_fill_region(swc.backend->renderer, view->border.incolor, &in_border);
432 }
433
434 pixman_region32_fini(&border_damage);
435 pixman_region32_fini(&in_rect);
436 pixman_region32_fini(&out_border);
437 pixman_region32_fini(&in_border);
438
439 if ((view->decor.top || view->decor.right || view->decor.bottom ||
440 view->decor.left)) {
441 decor_repaint(swc.backend->renderer, target_geom, view, damage);
442 }
443}
444
445static void
446draw_overlays(struct wld_renderer *renderer, const struct swc_rectangle *target_geom)
447{
448 int32_t tx = (int32_t)target_geom->width;
449 int32_t ty = (int32_t)target_geom->height;
450
451/* draw box as 4 rectangles with wld */
452#define CLAMP_LOW(v, lo) ((v) < (lo) ? (lo) : (v))
453#define CLAMP_HIGH(v, hi) ((v) > (hi) ? (hi) : (v))
454#define DRAW_CLIPPED(rx, ry, rw, rh, clr) \
455 do { \
456 int32_t _x1 = CLAMP_LOW((rx), 0); \
457 int32_t _y1 = CLAMP_LOW((ry), 0); \
458 int32_t _x2 = CLAMP_HIGH((rx) + (int32_t)(rw), tx); \
459 int32_t _y2 = CLAMP_HIGH((ry) + (int32_t)(rh), ty); \
460 if (_x2 > _x1 && _y2 > _y1) \
461 wld_fill_rectangle(renderer, (clr), _x1, _y1, \
462 (uint32_t)(_x2 - _x1), (uint32_t)(_y2 - _y1)); \
463 } while (0)
464
465 if (overlay.active && overlay.border_width > 0) {
466 int32_t x = overlay.x - target_geom->x;
467 int32_t y = overlay.y - target_geom->y;
468 uint32_t w = overlay.width, h = overlay.height,
469 bw = overlay.border_width;
470
471 if (w > 0 && h > 0) {
472 if (bw > w) {
473 bw = w;
474 }
475 if (bw > h) {
476 bw = h;
477 }
478
479 DRAW_CLIPPED(x, y, (int32_t)w, (int32_t)bw, overlay.color);
480 DRAW_CLIPPED(x, y + (int32_t)h - (int32_t)bw, (int32_t)w,
481 (int32_t)bw, overlay.color);
482 DRAW_CLIPPED(x, y, (int32_t)bw, (int32_t)h, overlay.color);
483 DRAW_CLIPPED(x + (int32_t)w - (int32_t)bw, y, (int32_t)bw,
484 (int32_t)h, overlay.color);
485 }
486 }
487
488#undef DRAW_CLIPPED
489#undef CLAMP_HIGH
490#undef CLAMP_LOW
491}
492
493static void
494renderer_repaint(struct target *target, pixman_region32_t *damage,
495 pixman_region32_t *base_damage, struct wl_list *views,
496 struct screen *screen)
497{
498 struct compositor_view *view;
499 const struct swc_rectangle *target_geom = &target->view->geometry;
500
501 DEBUG("Rendering to target { x: %d, y: %d, w: %u, h: %u }\n",
502 target->view->geometry.x, target->view->geometry.y,
503 target->view->geometry.width, target->view->geometry.height);
504
505 wld_set_target_surface(swc.backend->renderer, target->surface);
506
507 if (pixman_region32_not_empty(base_damage)) {
508 pixman_region32_translate(base_damage, -target->view->geometry.x,
509 -target->view->geometry.y);
510 wld_fill_region(swc.backend->renderer, DEFAULT_BG,
511 base_damage);
512 }
513
514 wl_list_for_each_reverse(view, views, link)
515 {
516 if (view->visible && view->base.screens & target->mask) {
517 repaint_view(target, view, damage);
518 }
519 }
520
521 draw_overlays(swc.backend->renderer, target_geom);
522
523 wld_flush(swc.backend->renderer);
524}
525
526static int
527renderer_attach(struct compositor_view *view, struct wld_buffer *client_buffer)
528{
529 struct wld_buffer *buffer;
530 uint32_t proxy_width, proxy_height;
531 bool was_proxy = view->buffer != view->base.buffer;
532 bool needs_proxy =
533 client_buffer && !(wld_capabilities(swc.backend->renderer, client_buffer) &
534 WLD_CAPABILITY_READ);
535 bool proxy_incompatible =
536 view->buffer && client_buffer &&
537 (view->buffer->format != client_buffer->format ||
538 view->buffer->width < client_buffer->width ||
539 view->buffer->height < client_buffer->height);
540
541 if (client_buffer) {
542 /* Create a proxy buffer if necessary (for example a hardware buffer
543 * backing a SHM buffer). */
544 if (needs_proxy) {
545 if (!was_proxy || proxy_incompatible) {
546 DEBUG("Creating a proxy buffer\n");
547 proxy_width = client_buffer->width;
548 proxy_height = client_buffer->height;
549 if (proxy_width <= UINT32_MAX - 255) {
550 proxy_width = (proxy_width + 255) & ~255U;
551 }
552 if (proxy_height <= UINT32_MAX - 255) {
553 proxy_height = (proxy_height + 255) & ~255U;
554 }
555 buffer = wld_create_buffer(
556 swc.backend->context, proxy_width, proxy_height,
557 client_buffer->format, WLD_FLAG_MAP);
558
559 if (!buffer) {
560 return -ENOMEM;
561 }
562 } else {
563 /* Otherwise we can keep the original proxy buffer. */
564 buffer = view->buffer;
565 }
566 } else {
567 buffer = client_buffer;
568 }
569 } else {
570 buffer = NULL;
571 }
572
573 /* If we no longer need a proxy buffer, or the original buffer is of a
574 * different size, destroy the old proxy image. */
575 if (view->buffer &&
576 ((!needs_proxy && was_proxy) ||
577 (needs_proxy && was_proxy && proxy_incompatible))) {
578 wld_buffer_unreference(view->buffer);
579 }
580
581 view->buffer = buffer;
582 view->buffer_opaque_valid = false;
583
584 return 0;
585}
586
587static void
588renderer_flush_view(struct compositor_view *view)
589{
590 if (view->buffer == view->base.buffer) {
591 return;
592 }
593
594 wld_set_target_buffer(swc.shm->renderer, view->buffer);
595 wld_copy_region(swc.shm->renderer, view->base.buffer, 0, 0,
596 &view->surface->state.damage);
597 wld_flush(swc.shm->renderer);
598}
599
600/* }}} */
601
602/* Surface Views {{{ */
603
604/**
605 * Adds the region below a view to the compositor's damaged region.
606 */
607static void
608damage_below_view(struct compositor_view *view)
609{
610 pixman_region32_t damage_below;
611
612 pixman_region32_init_with_extents(&damage_below, &view->extents);
613 pixman_region32_union(&compositor.damage, &compositor.damage,
614 &damage_below);
615 pixman_region32_fini(&damage_below);
616}
617
618/**
619 * Completely damages the surface and its border.
620 */
621static void
622damage_view(struct compositor_view *view)
623{
624 damage_below_view(view);
625 view->border.damaged_border1 = true;
626 view->border.damaged_border2 = true;
627}
628
629static void
630update_extents(struct compositor_view *view)
631{
632 int64_t total_border =
633 (int64_t)view->border.outwidth + (int64_t)view->border.inwidth;
634 int64_t geom_x = view->base.geometry.x;
635 int64_t geom_y = view->base.geometry.y;
636 int64_t geom_w = view->base.geometry.width;
637 int64_t geom_h = view->base.geometry.height;
638
639 int64_t border_x1 = geom_x - total_border;
640 int64_t border_y1 = geom_y - total_border;
641 int64_t border_x2 = geom_x + geom_w + total_border;
642 int64_t border_y2 = geom_y + geom_h + total_border;
643 int64_t decor_x1 = geom_x - (int64_t)view->decor.left;
644 int64_t decor_y1 = geom_y - (int64_t)view->decor.top;
645 int64_t decor_x2 = geom_x + geom_w + (int64_t)view->decor.right;
646 int64_t decor_y2 = geom_y + geom_h + (int64_t)view->decor.bottom;
647
648 int64_t buffer_x1 = geom_x - view->buffer_offset_x;
649 int64_t buffer_y1 = geom_y - view->buffer_offset_y;
650 int64_t buffer_x2 =
651 buffer_x1 +
652 (view->base.buffer ? view->base.buffer->width : (uint32_t)geom_w);
653 int64_t buffer_y2 =
654 buffer_y1 +
655 (view->base.buffer ? view->base.buffer->height : (uint32_t)geom_h);
656
657 view->extents.x1 = clamp_i32(MIN(MIN(border_x1, decor_x1), buffer_x1));
658 view->extents.y1 = clamp_i32(MIN(MIN(border_y1, decor_y1), buffer_y1));
659 view->extents.x2 = clamp_i32(MAX(MAX(border_x2, decor_x2), buffer_x2));
660 view->extents.y2 = clamp_i32(MAX(MAX(border_y2, decor_y2), buffer_y2));
661
662 if (view->extents.x2 < view->extents.x1) {
663 view->extents.x2 = view->extents.x1;
664 }
665 if (view->extents.y2 < view->extents.y1) {
666 view->extents.y2 = view->extents.y1;
667 }
668
669 /* Damage border. */
670 view->border.damaged_border1 = true;
671 view->border.damaged_border2 = true;
672 view->decor.damaged = true;
673}
674
675static void
676schedule_updates(uint32_t screens)
677{
678 if (compositor.scheduled_updates == 0) {
679 wl_event_loop_add_idle(swc.event_loop, &perform_update, NULL);
680 }
681
682 if (screens == -1) {
683 struct screen *screen;
684
685 screens = 0;
686 wl_list_for_each(screen, &swc.screens, link) screens |=
687 screen_mask(screen);
688 }
689
690 /* when zoomed, force full screen damage since actual area differs from
691 * world coords */
692 if (compositor.zoom != 1.0f) {
693 struct screen *screen;
694 wl_list_for_each(screen, &swc.screens, link)
695 {
696 pixman_region32_union_rect(
697 &compositor.damage, &compositor.damage, screen->base.geometry.x,
698 screen->base.geometry.y, screen->base.geometry.width,
699 screen->base.geometry.height);
700 screens |= screen_mask(screen);
701 }
702 }
703
704 compositor.scheduled_updates |= screens;
705}
706
707void
708compositor_damage_all(void)
709{
710 struct screen *screen;
711
712 if (!compositor.initialized) {
713 return;
714 }
715
716 wl_list_for_each(screen, &swc.screens, link)
717 {
718 pixman_region32_union_rect(
719 &compositor.damage, &compositor.damage, screen->base.geometry.x,
720 screen->base.geometry.y, screen->base.geometry.width,
721 screen->base.geometry.height);
722 }
723
724 schedule_updates(-1);
725}
726
727static void
728overlay_damage_region(int32_t x, int32_t y, uint32_t width, uint32_t height,
729 uint32_t border_width)
730{
731 (void)border_width;
732 pixman_region32_union_rect(&compositor.damage, &compositor.damage, x, y,
733 width, height);
734}
735
736EXPORT void
737swc_overlay_set_box(int32_t x1, int32_t y1, int32_t x2, int32_t y2,
738 uint32_t color, uint32_t border_width)
739{
740 int32_t x = x1 < x2 ? x1 : x2;
741 int32_t y = y1 < y2 ? y1 : y2;
742 uint32_t width = (uint32_t)abs(x2 - x1);
743 uint32_t height = (uint32_t)abs(y2 - y1);
744
745 if (border_width == 0) {
746 border_width = 1;
747 }
748
749 if (overlay.active) {
750 overlay_damage_region(overlay.x, overlay.y, overlay.width,
751 overlay.height, overlay.border_width);
752 }
753
754 overlay.active = true;
755 overlay.x = x;
756 overlay.y = y;
757 overlay.width = width;
758 overlay.height = height;
759 overlay.color = color;
760 overlay.border_width = border_width;
761
762 overlay_damage_region(overlay.x, overlay.y, overlay.width, overlay.height,
763 overlay.border_width);
764 schedule_updates(-1);
765}
766
767EXPORT void
768swc_overlay_clear(void)
769{
770 if (!overlay.active) {
771 return;
772 }
773
774 overlay_damage_region(overlay.x, overlay.y, overlay.width, overlay.height,
775 overlay.border_width);
776 overlay.active = false;
777 schedule_updates(-1);
778}
779
780EXPORT void
781swc_set_zoom(float level)
782{
783 if (level < 0.1f) {
784 level = 0.1f;
785 }
786 if (level > 10.0f) {
787 level = 10.0f;
788 }
789
790 if (compositor.zoom != level) {
791 compositor.zoom = level;
792 if (level == 1.0f) {
793 if (compositor.zoom_buffer) {
794 wld_buffer_unreference(compositor.zoom_buffer);
795 compositor.zoom_buffer = NULL;
796 }
797 }
798 /* damage entire screen to force full repaint */
799 schedule_updates(-1);
800 }
801}
802
803EXPORT float
804swc_get_zoom(void)
805{
806 return compositor.zoom;
807}
808
809static pixman_format_code_t
810wld_to_pixman_format(enum wld_format format)
811{
812 switch (format) {
813 case WLD_FORMAT_XRGB8888:
814 return PIXMAN_x8r8g8b8;
815 case WLD_FORMAT_ARGB8888:
816 return PIXMAN_a8r8g8b8;
817 default:
818 return PIXMAN_x8r8g8b8;
819 }
820}
821
822static struct wld_buffer *
823zoom_buffer_for_screen(struct screen *screen)
824{
825 uint32_t width = screen->base.geometry.width;
826 uint32_t height = screen->base.geometry.height;
827
828 if (compositor.zoom_buffer &&
829 (compositor.zoom_buffer->width != width ||
830 compositor.zoom_buffer->height != height ||
831 compositor.zoom_buffer->format != WLD_FORMAT_ARGB8888)) {
832 wld_buffer_unreference(compositor.zoom_buffer);
833 compositor.zoom_buffer = NULL;
834 }
835
836 if (!compositor.zoom_buffer) {
837 compositor.zoom_buffer =
838 wld_create_buffer(swc.shm->context, width, height,
839 WLD_FORMAT_ARGB8888, WLD_FLAG_MAP);
840 if (!compositor.zoom_buffer) {
841 return NULL;
842 }
843 }
844
845 wld_buffer_reference(compositor.zoom_buffer);
846 return compositor.zoom_buffer;
847}
848
849/* render zoomed view to shm wallpaper unscaled, windows scaled */
850static struct wld_buffer *
851render_zoomed_to_shm(struct screen *screen, float zoom)
852{
853 uint32_t width = screen->base.geometry.width;
854 uint32_t height = screen->base.geometry.height;
855 int32_t screen_x = screen->base.geometry.x;
856 int32_t screen_y = screen->base.geometry.y;
857 int32_t cx = screen_x + width / 2;
858 int32_t cy = screen_y + height / 2;
859 struct compositor_view *view;
860 struct wld_buffer *buffer = zoom_buffer_for_screen(screen);
861 if (!buffer) {
862 return NULL;
863 }
864
865 if (!wld_set_target_buffer(swc.shm->renderer, buffer)) {
866 wld_buffer_unreference(buffer);
867 return NULL;
868 }
869
870 pixman_region32_t full;
871 pixman_region32_init_rect(&full, 0, 0, width, height);
872 wld_fill_region(swc.shm->renderer, DEFAULT_BG, &full);
873 pixman_region32_fini(&full);
874 wld_flush(swc.shm->renderer);
875
876 if (!wld_map(buffer)) {
877 wld_buffer_unreference(buffer);
878 return NULL;
879 }
880
881 pixman_image_t *dst_img = pixman_image_create_bits(
882 wld_to_pixman_format(buffer->format), buffer->width, buffer->height,
883 buffer->map, buffer->pitch);
884
885 if (!dst_img) {
886 wld_unmap(buffer);
887 wld_buffer_unreference(buffer);
888 return NULL;
889 }
890
891 /* render each view with scaling */
892 wl_list_for_each_reverse(view, &compositor.views, link)
893 {
894 struct wld_buffer *src = view->buffer;
895 const struct swc_rectangle *geom = &view->base.geometry;
896
897 if (!src) {
898 continue;
899 }
900
901 if (!(wld_capabilities(swc.shm->renderer, src) & WLD_CAPABILITY_READ)) {
902 src = view->base.buffer;
903 }
904 if (!src) {
905 continue;
906 }
907
908 /* maths zoom position and size */
909 float zoomed_x, zoomed_y, zoomed_w, zoomed_h;
910 float border_out, border_in, total_border;
911
912 if (view->always_top) {
913 zoomed_x = geom->x - screen_x;
914 zoomed_y = geom->y - screen_y;
915 zoomed_w = geom->width;
916 zoomed_h = geom->height;
917
918 border_out = view->border.outwidth;
919 border_in = view->border.inwidth;
920 } else {
921 zoomed_x = (geom->x - cx) * zoom + width / 2.0f;
922 zoomed_y = (geom->y - cy) * zoom + height / 2.0f;
923 zoomed_w = geom->width * zoom;
924 zoomed_h = geom->height * zoom;
925
926 border_out = view->border.outwidth * zoom;
927 border_in = view->border.inwidth * zoom;
928 }
929
930 total_border = border_out + border_in;
931
932 if (zoomed_x + zoomed_w + total_border < 0 ||
933 zoomed_x - total_border >= (int32_t)width ||
934 zoomed_y + zoomed_h + total_border < 0 ||
935 zoomed_y - total_border >= (int32_t)height) {
936 continue;
937 }
938
939 if (view->border.outwidth > 0 && border_out >= 1) {
940 int32_t bx = (int32_t)(zoomed_x - total_border);
941 int32_t by = (int32_t)(zoomed_y - total_border);
942 int32_t bw = (int32_t)(zoomed_w + 2 * total_border);
943 int32_t bh = (int32_t)(zoomed_h + 2 * total_border);
944 int32_t bo = (int32_t)border_out;
945
946 pixman_color_t color = {
947 .red = ((view->border.outcolor >> 16) & 0xff) * 257,
948 .green = ((view->border.outcolor >> 8) & 0xff) * 257,
949 .blue = (view->border.outcolor & 0xff) * 257,
950 .alpha = 0xffff};
951 pixman_image_t *fill = pixman_image_create_solid_fill(&color);
952 if (fill) {
953 pixman_image_composite32(PIXMAN_OP_OVER, fill, NULL, dst_img, 0,
954 0, 0, 0, bx, by, bw, bo);
955 pixman_image_composite32(PIXMAN_OP_OVER, fill, NULL, dst_img, 0,
956 0, 0, 0, bx, by + bh - bo, bw, bo);
957 pixman_image_composite32(PIXMAN_OP_OVER, fill, NULL, dst_img, 0,
958 0, 0, 0, bx, by + bo, bo, bh - 2 * bo);
959 pixman_image_composite32(PIXMAN_OP_OVER, fill, NULL, dst_img, 0,
960 0, 0, 0, bx + bw - bo, by + bo, bo,
961 bh - 2 * bo);
962 pixman_image_unref(fill);
963 }
964 }
965
966 if (view->border.inwidth > 0 && border_in >= 1) {
967 int32_t bx = (int32_t)(zoomed_x - border_in);
968 int32_t by = (int32_t)(zoomed_y - border_in);
969 int32_t bw = (int32_t)(zoomed_w + 2 * border_in);
970 int32_t bh = (int32_t)(zoomed_h + 2 * border_in);
971 int32_t bi = (int32_t)border_in;
972
973 pixman_color_t color = {
974 .red = ((view->border.incolor >> 16) & 0xff) * 257,
975 .green = ((view->border.incolor >> 8) & 0xff) * 257,
976 .blue = (view->border.incolor & 0xff) * 257,
977 .alpha = 0xffff};
978 pixman_image_t *fill = pixman_image_create_solid_fill(&color);
979 if (fill) {
980 pixman_image_composite32(PIXMAN_OP_OVER, fill, NULL, dst_img, 0,
981 0, 0, 0, bx, by, bw, bi);
982 pixman_image_composite32(PIXMAN_OP_OVER, fill, NULL, dst_img, 0,
983 0, 0, 0, bx, by + bh - bi, bw, bi);
984 pixman_image_composite32(PIXMAN_OP_OVER, fill, NULL, dst_img, 0,
985 0, 0, 0, bx, by + bi, bi, bh - 2 * bi);
986 pixman_image_composite32(PIXMAN_OP_OVER, fill, NULL, dst_img, 0,
987 0, 0, 0, bx + bw - bi, by + bi, bi,
988 bh - 2 * bi);
989 pixman_image_unref(fill);
990 }
991 }
992
993 if (!wld_map(src)) {
994 continue;
995 }
996
997 pixman_image_t *src_img = pixman_image_create_bits(
998 wld_to_pixman_format(src->format), src->width, src->height,
999 src->map, src->pitch);
1000
1001 if (src_img) {
1002 if (!view->always_top) {
1003 pixman_transform_t transform;
1004 pixman_transform_init_identity(&transform);
1005 pixman_fixed_t scale = pixman_double_to_fixed(1.0 / zoom);
1006 pixman_transform_scale(&transform, NULL, scale, scale);
1007 pixman_image_set_transform(src_img, &transform);
1008 pixman_image_set_filter(src_img, PIXMAN_FILTER_BILINEAR, NULL,
1009 0);
1010 }
1011
1012 pixman_image_composite32(PIXMAN_OP_OVER, src_img, NULL, dst_img, 0,
1013 0, 0, 0, (int32_t)zoomed_x,
1014 (int32_t)zoomed_y, (int32_t)(zoomed_w + 1),
1015 (int32_t)(zoomed_h + 1));
1016
1017 pixman_image_unref(src_img);
1018 }
1019
1020 wld_unmap(src);
1021 }
1022
1023 pixman_image_unref(dst_img);
1024 wld_unmap(buffer);
1025
1026 return buffer;
1027}
1028
1029static bool
1030update(struct view *base)
1031{
1032 struct compositor_view *view = (void *)base;
1033
1034 if (!swc.active || !view->visible) {
1035 return false;
1036 }
1037
1038 schedule_updates(view->base.screens);
1039
1040 return true;
1041}
1042
1043static int
1044attach(struct view *base, struct wld_buffer *buffer)
1045{
1046 struct compositor_view *view = (void *)base;
1047 struct surface *surface = view->surface;
1048 pixman_box32_t old_extents;
1049 pixman_region32_t old, new, both;
1050 uint32_t new_width = buffer ? buffer->width : 0;
1051 uint32_t new_height = buffer ? buffer->height : 0;
1052 int ret;
1053
1054 if ((ret = renderer_attach(view, buffer)) < 0) {
1055 return ret;
1056 }
1057
1058 /* Schedule updates on the screens the view was previously
1059 * visible on. */
1060 update(&view->base);
1061
1062 view->buffer_offset_x = 0;
1063 view->buffer_offset_y = 0;
1064 if (surface && surface->has_window_geometry && buffer) {
1065 if (surface->window_width > 0 && surface->window_height > 0) {
1066 new_width = (uint32_t)surface->window_width;
1067 new_height = (uint32_t)surface->window_height;
1068 view->buffer_offset_x = surface->window_x;
1069 view->buffer_offset_y = surface->window_y;
1070 }
1071 }
1072
1073 if (view_set_size(&view->base, new_width, new_height)) {
1074 /* The view was resized. */
1075 old_extents = view->extents;
1076 update_extents(view);
1077
1078 if (view->visible) {
1079 /* Damage the region that was newly uncovered or covered. */
1080 pixman_region32_init_with_extents(&old, &old_extents);
1081 pixman_region32_init_with_extents(&new, &view->extents);
1082 pixman_region32_init(&both);
1083 pixman_region32_intersect(&both, &old, &new);
1084 pixman_region32_union(&new, &old, &new);
1085 pixman_region32_subtract(&new, &new, &both);
1086 pixman_region32_union(&compositor.damage, &compositor.damage, &new);
1087 pixman_region32_fini(&old);
1088 pixman_region32_fini(&new);
1089 pixman_region32_fini(&both);
1090
1091 view_update_screens(&view->base);
1092 update(&view->base);
1093 }
1094 }
1095
1096 return 0;
1097}
1098
1099static bool
1100move(struct view *base, int32_t x, int32_t y)
1101{
1102 struct compositor_view *view = (void *)base;
1103
1104 if (view->visible) {
1105 damage_below_view(view);
1106 update(&view->base);
1107 }
1108
1109 if (view_set_position(&view->base, x, y)) {
1110 update_extents(view);
1111
1112 if (view->visible) {
1113 /* Assume worst-case no clipping until we draw the next frame (in
1114 * case the surface gets moved again before that). */
1115 pixman_region32_clear(&view->clip);
1116
1117 view_update_screens(&view->base);
1118 damage_below_view(view);
1119 update(&view->base);
1120 }
1121 }
1122
1123 return true;
1124}
1125
1126static const struct view_impl view_impl = {
1127 .update = update,
1128 .attach = attach,
1129 .move = move,
1130};
1131
1132static void
1133restack_view_for_layer(struct compositor_view *view, bool raise)
1134{
1135 struct compositor_view *other;
1136 struct wl_list *insert_after = &compositor.views;
1137 bool found_same = false;
1138
1139 wl_list_for_each(other, &compositor.views, link)
1140 {
1141 if (other == view) {
1142 continue;
1143 }
1144
1145 if (other->stack_layer > view->stack_layer) {
1146 insert_after = &other->link;
1147 continue;
1148 }
1149
1150 if (other->stack_layer == view->stack_layer) {
1151 found_same = true;
1152 if (raise) {
1153 insert_after = other->link.prev;
1154 } else {
1155 insert_after = &other->link;
1156 }
1157 break;
1158 }
1159
1160 insert_after = other->link.prev;
1161 break;
1162 }
1163
1164 if (!found_same && !raise && insert_after == &compositor.views) {
1165 insert_after = compositor.views.prev;
1166 if (insert_after == &view->link) {
1167 insert_after = insert_after->prev;
1168 }
1169 }
1170
1171 if (insert_after == &view->link) {
1172 insert_after = insert_after->prev;
1173 }
1174
1175 wl_list_remove(&view->link);
1176 wl_list_insert(insert_after, &view->link);
1177}
1178
1179static struct compositor_view *
1180view_at(int32_t x, int32_t y)
1181{
1182 struct compositor_view *view;
1183 struct swc_rectangle *geom;
1184 struct swc_rectangle buffer_geom;
1185
1186 wl_list_for_each(view, &compositor.views, link)
1187 {
1188 if (!view->visible) {
1189 continue;
1190 }
1191
1192 geom = &view->base.geometry;
1193 if (view->window) {
1194 if (!rectangle_contains_point(geom, x, y)) {
1195 continue;
1196 }
1197 } else if (view->base.buffer) {
1198 buffer_geom.x = geom->x - view->buffer_offset_x;
1199 buffer_geom.y = geom->y - view->buffer_offset_y;
1200 buffer_geom.width = view->base.buffer->width;
1201 buffer_geom.height = view->base.buffer->height;
1202 if (!rectangle_contains_point(&buffer_geom, x, y)) {
1203 continue;
1204 }
1205 } else if (!rectangle_contains_point(geom, x, y)) {
1206 continue;
1207 }
1208
1209 if (pixman_region32_contains_point(&view->surface->state.input,
1210 x - geom->x + view->buffer_offset_x,
1211 y - geom->y + view->buffer_offset_y,
1212 NULL)) {
1213 return view;
1214 }
1215 }
1216
1217 return NULL;
1218}
1219
1220static struct compositor_view *
1221window_view(struct compositor_view *view)
1222{
1223 while (view && !view->window && view->parent && view->parent != view) {
1224 view = view->parent;
1225 }
1226 return (view && view->window) ? view : NULL;
1227}
1228
1229void
1230raise_window(struct compositor_view *view)
1231{
1232 struct compositor_view *other, *top_window;
1233 struct wl_list *insert_after;
1234 uint32_t screens;
1235
1236 view = window_view(view);
1237 if (!view || !view->visible) {
1238 return;
1239 }
1240
1241 top_window = NULL;
1242 insert_after = &compositor.views;
1243 wl_list_for_each(other, &compositor.views, link)
1244 {
1245 if (other == view) {
1246 continue;
1247 }
1248
1249 if (!other->visible) {
1250 continue;
1251 }
1252
1253 if (other->stack_layer > STACK_LAYER_NORMAL ||
1254 other->always_top) {
1255 insert_after = &other->link;
1256 continue;
1257 }
1258
1259 if (other->stack_layer < STACK_LAYER_NORMAL) {
1260 break;
1261 }
1262
1263 if (other->window) {
1264 top_window = other;
1265 break;
1266 }
1267 insert_after = &other->link;
1268 }
1269
1270 if (view == top_window) {
1271 return;
1272 }
1273
1274 screens = view->base.screens;
1275
1276 wl_list_remove(&view->link);
1277 wl_list_insert(insert_after, &view->link);
1278
1279 view->border.damaged_border1 = true;
1280 pixman_region32_union_rect(&compositor.damage, &compositor.damage,
1281 view->extents.x1, view->extents.y1,
1282 span_u32(view->extents.x1, view->extents.x2),
1283 span_u32(view->extents.y1, view->extents.y2));
1284 schedule_updates(screens);
1285}
1286
1287void
1288raise_window_top(struct compositor_view *view)
1289{
1290 view->stack_layer = STACK_LAYER_OVERLAY;
1291 restack_view_for_layer(view, true);
1292 damage_view(view);
1293 schedule_updates(view->base.screens);
1294}
1295
1296void
1297compositor_view_set_stack_layer(struct compositor_view *view, uint32_t layer,
1298 bool raise)
1299{
1300 if (view->stack_layer == layer) {
1301 if (raise) {
1302 restack_view_for_layer(view, true);
1303 damage_view(view);
1304 schedule_updates(view->base.screens);
1305 }
1306 return;
1307 }
1308
1309 damage_view(view);
1310 view->stack_layer = layer;
1311 restack_view_for_layer(view, raise);
1312 damage_view(view);
1313 schedule_updates(view->base.screens);
1314}
1315
1316EXPORT struct swc_window *
1317swc_window_at(int32_t x, int32_t y)
1318{
1319 struct compositor_view *view = window_view(view_at(x, y));
1320
1321 return view ? &view->window->base : NULL;
1322}
1323
1324static struct compositor_view *
1325view_for_window(struct swc_window *base)
1326{
1327 struct window *window;
1328
1329 if (!base) {
1330 return NULL;
1331 }
1332
1333 window = (struct window *)base;
1334 return window->view;
1335}
1336
1337static struct compositor_view *
1338prev_window_view(struct compositor_view *view)
1339{
1340 struct wl_list *link;
1341 struct compositor_view *other;
1342
1343 for (link = view->link.prev; link != &compositor.views; link = link->prev) {
1344 other = wl_container_of(link, other, link);
1345
1346 if (other->visible && other->window) {
1347 return other;
1348 }
1349 }
1350
1351 return NULL;
1352}
1353
1354static struct compositor_view *
1355next_window_view(struct compositor_view *view)
1356{
1357 struct wl_list *link;
1358 struct compositor_view *other;
1359
1360 for (link = view->link.next; link != &compositor.views; link = link->next) {
1361 other = wl_container_of(link, other, link);
1362
1363 if (other->visible && other->window) {
1364 return other;
1365 }
1366 }
1367
1368 return NULL;
1369}
1370
1371static void
1372damage_views(struct compositor_view *a, struct compositor_view *b)
1373{
1374 uint32_t screens = a->base.screens | (b ? b->base.screens : 0);
1375
1376 a->border.damaged_border1 = true;
1377 a->border.damaged_border2 = true;
1378 pixman_region32_union_rect(&compositor.damage, &compositor.damage,
1379 a->extents.x1, a->extents.y1,
1380 span_u32(a->extents.x1, a->extents.x2),
1381 span_u32(a->extents.y1, a->extents.y2));
1382
1383 if (b) {
1384 b->border.damaged_border1 = true;
1385 b->border.damaged_border2 = true;
1386 pixman_region32_union_rect(&compositor.damage, &compositor.damage,
1387 b->extents.x1, b->extents.y1,
1388 span_u32(b->extents.x1, b->extents.x2),
1389 span_u32(b->extents.y1, b->extents.y2));
1390 }
1391
1392 schedule_updates(screens);
1393}
1394
1395EXPORT void
1396swc_window_stack(struct swc_window *window, int32_t direction)
1397{
1398 struct compositor_view *view = view_for_window(window);
1399 struct compositor_view *other = NULL;
1400
1401 if (!view || !view->visible || direction == 0) {
1402 return;
1403 }
1404
1405 if (direction < 0) {
1406 other = prev_window_view(view);
1407 if (!other) {
1408 return;
1409 }
1410 wl_list_remove(&view->link);
1411 wl_list_insert(other->link.prev, &view->link);
1412 } else {
1413 other = next_window_view(view);
1414 if (!other) {
1415 return;
1416 }
1417 wl_list_remove(&view->link);
1418 wl_list_insert(&other->link, &view->link);
1419 }
1420
1421 damage_views(view, other);
1422}
1423
1424struct compositor_view *
1425compositor_create_view(struct surface *surface)
1426{
1427 struct compositor_view *view;
1428
1429 view = malloc(sizeof(*view));
1430
1431 if (!view) {
1432 return NULL;
1433 }
1434
1435 view_initialize(&view->base, &view_impl);
1436 view->surface = surface;
1437 view->buffer = NULL;
1438 view->buffer_opaque_valid = false;
1439 view->buffer_opaque = false;
1440 view->window = NULL;
1441 view->parent = NULL;
1442 view->buffer_offset_x = 0;
1443 view->buffer_offset_y = 0;
1444 view->visible = false;
1445 view->always_top = false;
1446 view->stack_layer = STACK_LAYER_NORMAL;
1447 view->extents.x1 = 0;
1448 view->extents.y1 = 0;
1449 view->extents.x2 = 0;
1450 view->extents.y2 = 0;
1451 view->border.outwidth = 0;
1452 view->border.outcolor = 0x000000;
1453 view->border.damaged_border1 = false;
1454 view->border.inwidth = 0;
1455 view->border.incolor = 0x000000;
1456 view->border.damaged_border2 = false;
1457 view->decor.color = 0x000000;
1458 view->decor.top = 0;
1459 view->decor.right = 0;
1460 view->decor.bottom = 0;
1461 view->decor.left = 0;
1462 decor_view_initialize(view);
1463 view->decor.damaged = false;
1464 pixman_region32_init(&view->clip);
1465 wl_signal_init(&view->destroy_signal);
1466 surface_set_view(surface, &view->base);
1467 wl_list_insert(&compositor.views, &view->link);
1468
1469 return view;
1470}
1471
1472void
1473compositor_view_destroy(struct compositor_view *view)
1474{
1475 wl_signal_emit(&view->destroy_signal, NULL);
1476 compositor_view_hide(view);
1477 surface_set_view(view->surface, NULL);
1478 view_finalize(&view->base);
1479 decor_view_finalize(view);
1480 pixman_region32_fini(&view->clip);
1481 wl_list_remove(&view->link);
1482 free(view);
1483}
1484
1485struct compositor_view *
1486compositor_view(struct view *view)
1487{
1488 return view->impl == &view_impl ? (struct compositor_view *)view : NULL;
1489}
1490
1491void
1492compositor_view_set_parent(struct compositor_view *view,
1493 struct compositor_view *parent)
1494{
1495 view->parent = parent;
1496
1497 if (!parent) {
1498 return;
1499 }
1500
1501 if (parent->visible) {
1502 compositor_view_show(view);
1503 } else {
1504 compositor_view_hide(view);
1505 }
1506}
1507
1508void
1509compositor_view_restack(struct compositor_view *view,
1510 struct compositor_view *sibling, bool above)
1511{
1512 if (!view || !sibling || view == sibling) {
1513 return;
1514 }
1515
1516 if (above) {
1517 if (view->link.next == &sibling->link) {
1518 return;
1519 }
1520 wl_list_remove(&view->link);
1521 wl_list_insert(sibling->link.prev, &view->link);
1522 } else {
1523 if (view->link.prev == &sibling->link) {
1524 return;
1525 }
1526 wl_list_remove(&view->link);
1527 wl_list_insert(&sibling->link, &view->link);
1528 }
1529
1530 damage_views(view, sibling);
1531}
1532
1533void
1534compositor_view_show(struct compositor_view *view)
1535{
1536 struct compositor_view *other;
1537 struct subsurface *subsurface;
1538
1539 if (view->visible) {
1540 return;
1541 }
1542
1543 subsurface = view->surface ? view->surface->subsurface : NULL;
1544 if (subsurface) {
1545 if (!subsurface->added || !view->surface->state.buffer) {
1546 return;
1547 }
1548 }
1549
1550 view->visible = true;
1551 view_update_screens(&view->base);
1552
1553 if (view->window) {
1554 raise_window(view);
1555 }
1556
1557 /* Assume worst-case no clipping until we draw the next frame (in case the
1558 * surface gets moved before that. */
1559 pixman_region32_clear(&view->clip);
1560 damage_view(view);
1561 update(&view->base);
1562
1563 wl_list_for_each(other, &compositor.views, link)
1564 {
1565 if (other->parent == view) {
1566 compositor_view_show(other);
1567 }
1568 }
1569}
1570
1571void
1572compositor_view_hide(struct compositor_view *view)
1573{
1574 struct compositor_view *other;
1575
1576 if (!view->visible) {
1577 return;
1578 }
1579
1580 /* Update all the screens the view was on. */
1581 update(&view->base);
1582 damage_below_view(view);
1583
1584 view_set_screens(&view->base, 0);
1585 view->visible = false;
1586
1587 wl_list_for_each(other, &compositor.views, link)
1588 {
1589 if (other->parent == view) {
1590 compositor_view_hide(other);
1591 }
1592 }
1593}
1594
1595void
1596compositor_view_set_border_width(struct compositor_view *view,
1597 uint32_t outwidth, uint32_t inwidth)
1598{
1599 pixman_box32_t old_extents;
1600
1601 if (view->border.outwidth == outwidth && view->border.inwidth == inwidth) {
1602 return;
1603 }
1604
1605 old_extents = view->extents;
1606
1607 view->border.outwidth = outwidth;
1608 view->border.damaged_border1 = true;
1609
1610 view->border.inwidth = inwidth;
1611 view->border.damaged_border2 = true;
1612
1613 /* XXX: Damage above surface for transparent surfaces? */
1614
1615 update_extents(view);
1616
1617 /* Damage old extents to prevent leftover border artifacts */
1618 if (view->visible &&
1619 (old_extents.x1 != view->extents.x1 ||
1620 old_extents.y1 != view->extents.y1 ||
1621 old_extents.x2 != view->extents.x2 ||
1622 old_extents.y2 != view->extents.y2)) {
1623 pixman_region32_t old_region, new_region;
1624
1625 pixman_region32_init_with_extents(&old_region, &old_extents);
1626 pixman_region32_init_with_extents(&new_region, &view->extents);
1627 pixman_region32_subtract(&old_region, &old_region, &new_region);
1628 pixman_region32_union(&compositor.damage, &compositor.damage,
1629 &old_region);
1630 pixman_region32_fini(&old_region);
1631 pixman_region32_fini(&new_region);
1632 }
1633
1634 update(&view->base);
1635}
1636
1637void
1638compositor_view_set_border_color(struct compositor_view *view,
1639 uint32_t outcolor, uint32_t incolor)
1640{
1641 if (view->border.outcolor == outcolor && view->border.incolor == incolor) {
1642 return;
1643 }
1644
1645 view->border.outcolor = outcolor;
1646 view->border.damaged_border1 = true;
1647
1648 view->border.incolor = incolor;
1649 view->border.damaged_border2 = true;
1650
1651 /* XXX: Damage above surface for transparent surfaces? */
1652
1653 update(&view->base);
1654}
1655
1656void
1657compositor_view_set_decor(struct compositor_view *view,
1658 const struct swc_decor *decor)
1659{
1660 /* decor_view_set() could shrink or remove the decoration, so wedamage the old
1661 * extents before they are replaced */
1662 if (view->visible) {
1663 damage_below_view(view);
1664 }
1665
1666 decor_view_set(view, decor);
1667 update_extents(view);
1668 update(&view->base);
1669}
1670
1671void
1672compositor_view_damage_decor(struct compositor_view *view)
1673{
1674 if (!view->decor.top && !view->decor.right && !view->decor.bottom &&
1675 !view->decor.left) {
1676 return;
1677 }
1678
1679 decor_view_damage(view);
1680 update(&view->base);
1681}
1682
1683/* }}} */
1684
1685static void
1686calculate_damage(void)
1687{
1688 struct compositor_view *view;
1689 struct swc_rectangle *geom;
1690 pixman_region32_t surface_opaque, *surface_damage;
1691
1692 pixman_region32_clear(&compositor.opaque);
1693 pixman_region32_init(&surface_opaque);
1694
1695 /* Go through views top-down to calculate clipping regions. */
1696 wl_list_for_each(view, &compositor.views, link)
1697 {
1698 if (!view->visible) {
1699 continue;
1700 }
1701
1702 geom = &view->base.geometry;
1703 pixman_region32_t view_region;
1704
1705 pixman_region32_init_rect(&view_region, geom->x, geom->y, geom->width,
1706 geom->height);
1707
1708 /* Clip the surface by the opaque region covering it. */
1709 pixman_region32_copy(&view->clip, &compositor.opaque);
1710
1711 /* Translate the opaque region to global coordinates. */
1712 pixman_region32_copy(&surface_opaque, &view->surface->state.opaque);
1713 pixman_region32_translate(&surface_opaque,
1714 geom->x - view->buffer_offset_x,
1715 geom->y - view->buffer_offset_y);
1716 pixman_region32_intersect(&surface_opaque, &surface_opaque,
1717 &view_region);
1718
1719 /* Add the surface's opaque region to the accumulated opaque region. */
1720 pixman_region32_union(&compositor.opaque, &compositor.opaque,
1721 &surface_opaque);
1722
1723 surface_damage = &view->surface->state.damage;
1724
1725 if (pixman_region32_not_empty(surface_damage)) {
1726 view->buffer_opaque_valid = false;
1727 renderer_flush_view(view);
1728
1729 /* Translate surface damage to global coordinates. */
1730 pixman_region32_translate(surface_damage,
1731 geom->x - view->buffer_offset_x,
1732 geom->y - view->buffer_offset_y);
1733
1734 /* Add the surface damage to the compositor damage. */
1735 pixman_region32_union(&compositor.damage, &compositor.damage,
1736 surface_damage);
1737 pixman_region32_clear(surface_damage);
1738 }
1739
1740 /* redraw entire thingy if border or decor changed */
1741 if (view->border.damaged_border1 || view->border.damaged_border2 ||
1742 view->decor.damaged) {
1743 pixman_region32_t border_region;
1744
1745 pixman_region32_init_with_extents(&border_region, &view->extents);
1746
1747 pixman_region32_subtract(&border_region, &border_region,
1748 &view_region);
1749
1750 pixman_region32_union(&compositor.damage, &compositor.damage,
1751 &border_region);
1752
1753 pixman_region32_fini(&border_region);
1754
1755 view->border.damaged_border1 = false;
1756 view->border.damaged_border2 = false;
1757 view->decor.damaged = false;
1758 }
1759
1760 pixman_region32_fini(&view_region);
1761 }
1762
1763 pixman_region32_fini(&surface_opaque);
1764}
1765
1766static void
1767update_screen(struct screen *screen)
1768{
1769 struct target *target;
1770 const struct swc_rectangle *geom = &screen->base.geometry;
1771 pixman_region32_t damage, *total_damage;
1772
1773 if (!(compositor.scheduled_updates & screen_mask(screen))) {
1774 return;
1775 }
1776
1777 if (!(target = target_get(screen))) {
1778 return;
1779 }
1780
1781 pixman_region32_init(&damage);
1782 pixman_region32_intersect_rect(&damage, &compositor.damage, geom->x,
1783 geom->y, geom->width, geom->height);
1784 pixman_region32_translate(&damage, -geom->x, -geom->y);
1785 total_damage = wld_surface_damage(target->surface, &damage);
1786
1787 /* Don't repaint the screen if it is waiting for a page flip. */
1788 if (compositor.pending_flips & screen_mask(screen)) {
1789 pixman_region32_fini(&damage);
1790 return;
1791 }
1792
1793 /* check if zoom */
1794 if (compositor.zoom != 1.0f) {
1795 pixman_region32_fini(&damage);
1796
1797 struct wld_buffer *zoomed =
1798 render_zoomed_to_shm(screen, compositor.zoom);
1799 if (!zoomed) {
1800 return;
1801 }
1802
1803 pixman_region32_t full;
1804 pixman_region32_init_rect(&full, 0, 0, geom->width, geom->height);
1805 wld_set_target_surface(swc.backend->renderer, target->surface);
1806 wld_copy_region(swc.backend->renderer, zoomed, 0, 0, &full);
1807 wld_flush(swc.backend->renderer);
1808 pixman_region32_fini(&full);
1809
1810 wld_buffer_unreference(zoomed);
1811 } else {
1812 pixman_region32_t base_damage;
1813 pixman_region32_copy(&damage, total_damage);
1814 pixman_region32_translate(&damage, geom->x, geom->y);
1815 pixman_region32_init(&base_damage);
1816 pixman_region32_subtract(&base_damage, &damage, &compositor.opaque);
1817 renderer_repaint(target, &damage, &base_damage, &compositor.views,
1818 screen);
1819 pixman_region32_fini(&damage);
1820 pixman_region32_fini(&base_damage);
1821 }
1822
1823 switch (target_swap_buffers(target)) {
1824 case -EACCES:
1825 /* If we get an EACCES, it is because this session is being deactivated,
1826 * but we haven't yet received the deactivate signal from swc-launch. */
1827 swc_deactivate();
1828 break;
1829 case 0:
1830 compositor.pending_flips |= screen_mask(screen);
1831 break;
1832 }
1833}
1834
1835static void
1836perform_update(void *data)
1837{
1838 struct screen *screen;
1839 uint32_t updates = compositor.scheduled_updates & ~compositor.pending_flips;
1840
1841 if (!swc.active || !updates) {
1842 return;
1843 }
1844
1845 DEBUG("Performing update\n");
1846
1847 compositor.updating = true;
1848 calculate_damage();
1849
1850 wl_list_for_each(screen, &swc.screens, link) update_screen(screen);
1851
1852 /* XXX: Should assert that all damage was covered by some output */
1853 pixman_region32_clear(&compositor.damage);
1854 compositor.scheduled_updates &= ~updates;
1855 compositor.updating = false;
1856}
1857
1858bool
1859handle_motion(struct pointer_handler *handler, uint32_t time, wl_fixed_t fx,
1860 wl_fixed_t fy)
1861{
1862 int32_t x = wl_fixed_to_int(fx), y = wl_fixed_to_int(fy);
1863
1864 /* If buttons are pressed, don't change pointer focus. */
1865 if (swc.seat->pointer->buttons.size > 0) {
1866 return false;
1867 }
1868
1869 struct compositor_view *view = view_at(x, y);
1870
1871 pointer_set_focus(swc.seat->pointer, view);
1872
1873 return false;
1874}
1875
1876static bool
1877handle_button(struct pointer_handler *handler, uint32_t time,
1878 struct button *button, uint32_t state)
1879{
1880 (void)handler;
1881 (void)time;
1882 (void)button;
1883
1884 if (state != WL_POINTER_BUTTON_STATE_PRESSED) {
1885 return false;
1886 }
1887
1888 int32_t x = wl_fixed_to_int(swc.seat->pointer->x);
1889 int32_t y = wl_fixed_to_int(swc.seat->pointer->y);
1890 struct compositor_view *view = view_at(x, y);
1891
1892 pointer_set_focus(swc.seat->pointer, view);
1893 raise_window(view);
1894
1895 return false;
1896}
1897
1898static void
1899handle_terminate(void *data, uint32_t time, uint32_t value, uint32_t state)
1900{
1901 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
1902 wl_display_terminate(swc.display);
1903 }
1904}
1905
1906static void
1907handle_switch_vt(void *data, uint32_t time, uint32_t value, uint32_t state)
1908{
1909 uint8_t vt = value - XKB_KEY_XF86Switch_VT_1 + 1;
1910
1911 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
1912 launch_activate_vt(vt);
1913 }
1914}
1915
1916static void
1917handle_swc_event(struct wl_listener *listener, void *data)
1918{
1919 struct event *event = data;
1920
1921 switch (event->type) {
1922 case SWC_EVENT_ACTIVATED:
1923 schedule_updates(-1);
1924 break;
1925 case SWC_EVENT_DEACTIVATED:
1926 compositor.scheduled_updates = 0;
1927 break;
1928 }
1929}
1930
1931static void
1932create_surface(struct wl_client *client, struct wl_resource *resource,
1933 uint32_t id)
1934{
1935 struct surface *surface;
1936
1937 /* Initialize surface. */
1938 surface = surface_new(client, wl_resource_get_version(resource), id);
1939
1940 if (!surface) {
1941 wl_resource_post_no_memory(resource);
1942 return;
1943 }
1944
1945 wl_signal_emit(&swc_compositor.signal.new_surface, surface);
1946}
1947
1948static void
1949create_region(struct wl_client *client, struct wl_resource *resource,
1950 uint32_t id)
1951{
1952 if (!region_new(client, wl_resource_get_version(resource), id)) {
1953 wl_resource_post_no_memory(resource);
1954 }
1955}
1956
1957static const struct wl_compositor_interface compositor_impl = {
1958 .create_surface = create_surface,
1959 .create_region = create_region,
1960};
1961
1962static void
1963bind_compositor(struct wl_client *client, void *data, uint32_t version,
1964 uint32_t id)
1965{
1966 struct wl_resource *resource;
1967
1968 resource =
1969 wl_resource_create(client, &wl_compositor_interface, version, id);
1970 if (!resource) {
1971 wl_client_post_no_memory(client);
1972 return;
1973 }
1974 wl_resource_set_implementation(resource, &compositor_impl, NULL, NULL);
1975}
1976
1977bool
1978compositor_initialize(void)
1979{
1980 struct screen *screen;
1981 uint32_t keysym;
1982
1983 compositor.global = wl_global_create(swc.display, &wl_compositor_interface,
1984 4, NULL, &bind_compositor);
1985
1986 if (!compositor.global) {
1987 return false;
1988 }
1989
1990 compositor.scheduled_updates = 0;
1991 compositor.pending_flips = 0;
1992 compositor.updating = false;
1993 compositor.zoom = 1.0f;
1994 compositor.zoom_buffer = NULL;
1995 if (!decor_initialize()) {
1996 return false;
1997 }
1998 pixman_region32_init(&compositor.damage);
1999 pixman_region32_init(&compositor.opaque);
2000 wl_list_init(&compositor.views);
2001 wl_signal_init(&swc_compositor.signal.new_surface);
2002 compositor.swc_listener.notify = &handle_swc_event;
2003 wl_signal_add(&swc.event_signal, &compositor.swc_listener);
2004
2005 wl_list_for_each(screen, &swc.screens, link) target_new(screen);
2006 if (swc.active) {
2007 schedule_updates(-1);
2008 }
2009
2010 swc_add_binding(SWC_BINDING_KEY, SWC_MOD_CTRL | SWC_MOD_ALT,
2011 XKB_KEY_BackSpace, &handle_terminate, NULL);
2012
2013 for (keysym = XKB_KEY_XF86Switch_VT_1; keysym <= XKB_KEY_XF86Switch_VT_12;
2014 ++keysym) {
2015 swc_add_binding(SWC_BINDING_KEY, SWC_MOD_ANY, keysym, &handle_switch_vt,
2016 NULL);
2017 }
2018
2019 compositor.initialized = true;
2020
2021 return true;
2022}
2023
2024void
2025compositor_finalize(void)
2026{
2027 compositor.initialized = false;
2028
2029 if (compositor.zoom_buffer) {
2030 wld_buffer_unreference(compositor.zoom_buffer);
2031 compositor.zoom_buffer = NULL;
2032 }
2033 decor_finalize();
2034 pixman_region32_fini(&compositor.damage);
2035 pixman_region32_fini(&compositor.opaque);
2036 wl_global_destroy(compositor.global);
2037}
2038
2039struct wld_buffer *
2040compositor_get_buffer(struct screen *screen)
2041{
2042 struct target *target = target_get(screen);
2043 if (!target) {
2044 return NULL;
2045 }
2046 return target->current_buffer;
2047}
2048
2049struct wld_buffer *
2050compositor_render_to_shm(struct screen *screen)
2051{
2052 if (compositor.zoom != 1.0f) {
2053 return render_zoomed_to_shm(screen, compositor.zoom);
2054 }
2055
2056 uint32_t width = screen->base.geometry.width;
2057 uint32_t height = screen->base.geometry.height;
2058 struct wld_buffer *buffer;
2059 struct compositor_view *view;
2060 pixman_region32_t region;
2061 pixman_region32_t damage;
2062 uint32_t caps;
2063
2064 /* create shm buf */
2065 buffer = wld_create_buffer(swc.shm->context, width, height,
2066 WLD_FORMAT_ARGB8888, WLD_FLAG_MAP);
2067 if (!buffer) {
2068 return NULL;
2069 }
2070
2071 caps = wld_capabilities(swc.shm->renderer, buffer);
2072 if (!(caps & WLD_CAPABILITY_WRITE) ||
2073 !wld_set_target_buffer(swc.shm->renderer, buffer)) {
2074 wld_buffer_unreference(buffer);
2075 return NULL;
2076 }
2077
2078 /* set region */
2079 pixman_region32_init_rect(®ion, 0, 0, width, height);
2080 pixman_region32_init_rect(&damage, screen->base.geometry.x,
2081 screen->base.geometry.y, width, height);
2082
2083 /* background */
2084 wld_fill_region(swc.shm->renderer, DEFAULT_BG, ®ion);
2085
2086 wl_list_for_each_reverse(view, &compositor.views, link)
2087 {
2088 struct wld_buffer *src = view->buffer;
2089
2090 if (!view->visible) {
2091 continue;
2092 }
2093
2094 if (src &&
2095 !(wld_capabilities(swc.shm->renderer, src) & WLD_CAPABILITY_READ)) {
2096 src = view->base.buffer;
2097 }
2098
2099 if (src &&
2100 (wld_capabilities(swc.shm->renderer, src) & WLD_CAPABILITY_READ)) {
2101 const struct swc_rectangle *geom = &view->base.geometry;
2102 int32_t src_x = view->window ? view->buffer_offset_x : 0;
2103 int32_t src_y = view->window ? view->buffer_offset_y : 0;
2104 int32_t dst_x = geom->x - src_x - screen->base.geometry.x;
2105 int32_t dst_y = geom->y - src_y - screen->base.geometry.y;
2106 pixman_region32_t source_region;
2107
2108 pixman_region32_init_rect(&source_region, src_x, src_y, geom->width,
2109 geom->height);
2110 pixman_region32_intersect_rect(&source_region, &source_region, 0, 0,
2111 src->width, src->height);
2112 if (src->format == WLD_FORMAT_ARGB8888) {
2113 wld_blend_region(swc.shm->renderer, src, dst_x, dst_y,
2114 &source_region);
2115 } else {
2116 wld_copy_region(swc.shm->renderer, src, dst_x, dst_y,
2117 &source_region);
2118 }
2119 pixman_region32_fini(&source_region);
2120 }
2121
2122 if ((view->border.outwidth > 0 || view->border.inwidth > 0) &&
2123 view->base.buffer) {
2124 pixman_region32_t view_region, view_damage, border_damage;
2125 const struct swc_rectangle *geom = &view->base.geometry;
2126 const struct swc_rectangle *target_geom = &screen->base.geometry;
2127
2128 pixman_region32_init_rect(&view_region, geom->x, geom->y,
2129 geom->width, geom->height);
2130 pixman_region32_init_with_extents(&view_damage, &view->extents);
2131 pixman_region32_init(&border_damage);
2132
2133 pixman_region32_intersect(&view_damage, &view_damage, &damage);
2134 pixman_region32_subtract(&view_damage, &view_damage, &view->clip);
2135 pixman_region32_subtract(&border_damage, &view_damage,
2136 &view_region);
2137
2138 pixman_region32_t in_rect;
2139 pixman_region32_init_rect(&in_rect,
2140 geom->x - view->border.inwidth,
2141 geom->y - view->border.inwidth,
2142 geom->width + (2 * view->border.inwidth),
2143 geom->height +
2144 (2 * view->border.inwidth));
2145
2146 pixman_region32_t out_border;
2147 pixman_region32_init(&out_border);
2148 pixman_region32_subtract(&out_border, &border_damage, &in_rect);
2149
2150 pixman_region32_t in_border;
2151 pixman_region32_init(&in_border);
2152 pixman_region32_subtract(&in_border, &in_rect, &view_region);
2153 pixman_region32_intersect(&in_border, &in_border, &border_damage);
2154
2155 if (view->border.outwidth > 0 &&
2156 pixman_region32_not_empty(&out_border)) {
2157 pixman_region32_translate(&out_border, -target_geom->x,
2158 -target_geom->y);
2159 wld_fill_region(swc.shm->renderer, view->border.outcolor,
2160 &out_border);
2161 }
2162
2163 if (view->border.inwidth > 0 &&
2164 pixman_region32_not_empty(&in_border)) {
2165 pixman_region32_translate(&in_border, -target_geom->x,
2166 -target_geom->y);
2167 wld_fill_region(swc.shm->renderer, view->border.incolor,
2168 &in_border);
2169 }
2170
2171 pixman_region32_fini(&border_damage);
2172 pixman_region32_fini(&view_region);
2173 pixman_region32_fini(&view_damage);
2174 pixman_region32_fini(&in_rect);
2175 pixman_region32_fini(&out_border);
2176 pixman_region32_fini(&in_border);
2177 }
2178
2179 if (view->decor.top || view->decor.right || view->decor.bottom ||
2180 view->decor.left) {
2181 const struct swc_rectangle *target_geom = &screen->base.geometry;
2182 decor_repaint(swc.shm->renderer, target_geom, view, &damage);
2183 }
2184 }
2185
2186 draw_overlays(swc.shm->renderer, &screen->base.geometry);
2187
2188 wld_flush(swc.shm->renderer);
2189 pixman_region32_fini(®ion);
2190 pixman_region32_fini(&damage);
2191
2192 return buffer;
2193}