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 if (view->border.outwidth == outwidth && view->border.inwidth == inwidth) {
1600 return;
1601 }
1602
1603 view->border.outwidth = outwidth;
1604 view->border.damaged_border1 = true;
1605
1606 view->border.inwidth = inwidth;
1607 view->border.damaged_border2 = true;
1608
1609 /* XXX: Damage above surface for transparent surfaces? */
1610
1611 update_extents(view);
1612 update(&view->base);
1613}
1614
1615void
1616compositor_view_set_border_color(struct compositor_view *view,
1617 uint32_t outcolor, uint32_t incolor)
1618{
1619 if (view->border.outcolor == outcolor && view->border.incolor == incolor) {
1620 return;
1621 }
1622
1623 view->border.outcolor = outcolor;
1624 view->border.damaged_border1 = true;
1625
1626 view->border.incolor = incolor;
1627 view->border.damaged_border2 = true;
1628
1629 /* XXX: Damage above surface for transparent surfaces? */
1630
1631 update(&view->base);
1632}
1633
1634void
1635compositor_view_set_decor(struct compositor_view *view,
1636 const struct swc_decor *decor)
1637{
1638 /* decor_view_set() could shrink or remove the decoration, so wedamage the old
1639 * extents before they are replaced */
1640 if (view->visible) {
1641 damage_below_view(view);
1642 }
1643
1644 decor_view_set(view, decor);
1645 update_extents(view);
1646 update(&view->base);
1647}
1648
1649void
1650compositor_view_damage_decor(struct compositor_view *view)
1651{
1652 if (!view->decor.top && !view->decor.right && !view->decor.bottom &&
1653 !view->decor.left) {
1654 return;
1655 }
1656
1657 decor_view_damage(view);
1658 update(&view->base);
1659}
1660
1661/* }}} */
1662
1663static void
1664calculate_damage(void)
1665{
1666 struct compositor_view *view;
1667 struct swc_rectangle *geom;
1668 pixman_region32_t surface_opaque, *surface_damage;
1669
1670 pixman_region32_clear(&compositor.opaque);
1671 pixman_region32_init(&surface_opaque);
1672
1673 /* Go through views top-down to calculate clipping regions. */
1674 wl_list_for_each(view, &compositor.views, link)
1675 {
1676 if (!view->visible) {
1677 continue;
1678 }
1679
1680 geom = &view->base.geometry;
1681 pixman_region32_t view_region;
1682
1683 pixman_region32_init_rect(&view_region, geom->x, geom->y, geom->width,
1684 geom->height);
1685
1686 /* Clip the surface by the opaque region covering it. */
1687 pixman_region32_copy(&view->clip, &compositor.opaque);
1688
1689 /* Translate the opaque region to global coordinates. */
1690 pixman_region32_copy(&surface_opaque, &view->surface->state.opaque);
1691 pixman_region32_translate(&surface_opaque,
1692 geom->x - view->buffer_offset_x,
1693 geom->y - view->buffer_offset_y);
1694 pixman_region32_intersect(&surface_opaque, &surface_opaque,
1695 &view_region);
1696
1697 /* Add the surface's opaque region to the accumulated opaque region. */
1698 pixman_region32_union(&compositor.opaque, &compositor.opaque,
1699 &surface_opaque);
1700
1701 surface_damage = &view->surface->state.damage;
1702
1703 if (pixman_region32_not_empty(surface_damage)) {
1704 view->buffer_opaque_valid = false;
1705 renderer_flush_view(view);
1706
1707 /* Translate surface damage to global coordinates. */
1708 pixman_region32_translate(surface_damage,
1709 geom->x - view->buffer_offset_x,
1710 geom->y - view->buffer_offset_y);
1711
1712 /* Add the surface damage to the compositor damage. */
1713 pixman_region32_union(&compositor.damage, &compositor.damage,
1714 surface_damage);
1715 pixman_region32_clear(surface_damage);
1716 }
1717
1718 /* redraw entire thingy if border or decor changed */
1719 if (view->border.damaged_border1 || view->border.damaged_border2 ||
1720 view->decor.damaged) {
1721 pixman_region32_t border_region;
1722
1723 pixman_region32_init_with_extents(&border_region, &view->extents);
1724
1725 pixman_region32_subtract(&border_region, &border_region,
1726 &view_region);
1727
1728 pixman_region32_union(&compositor.damage, &compositor.damage,
1729 &border_region);
1730
1731 pixman_region32_fini(&border_region);
1732
1733 view->border.damaged_border1 = false;
1734 view->border.damaged_border2 = false;
1735 view->decor.damaged = false;
1736 }
1737
1738 pixman_region32_fini(&view_region);
1739 }
1740
1741 pixman_region32_fini(&surface_opaque);
1742}
1743
1744static void
1745update_screen(struct screen *screen)
1746{
1747 struct target *target;
1748 const struct swc_rectangle *geom = &screen->base.geometry;
1749 pixman_region32_t damage, *total_damage;
1750
1751 if (!(compositor.scheduled_updates & screen_mask(screen))) {
1752 return;
1753 }
1754
1755 if (!(target = target_get(screen))) {
1756 return;
1757 }
1758
1759 pixman_region32_init(&damage);
1760 pixman_region32_intersect_rect(&damage, &compositor.damage, geom->x,
1761 geom->y, geom->width, geom->height);
1762 pixman_region32_translate(&damage, -geom->x, -geom->y);
1763 total_damage = wld_surface_damage(target->surface, &damage);
1764
1765 /* Don't repaint the screen if it is waiting for a page flip. */
1766 if (compositor.pending_flips & screen_mask(screen)) {
1767 pixman_region32_fini(&damage);
1768 return;
1769 }
1770
1771 /* check if zoom */
1772 if (compositor.zoom != 1.0f) {
1773 pixman_region32_fini(&damage);
1774
1775 struct wld_buffer *zoomed =
1776 render_zoomed_to_shm(screen, compositor.zoom);
1777 if (!zoomed) {
1778 return;
1779 }
1780
1781 pixman_region32_t full;
1782 pixman_region32_init_rect(&full, 0, 0, geom->width, geom->height);
1783 wld_set_target_surface(swc.backend->renderer, target->surface);
1784 wld_copy_region(swc.backend->renderer, zoomed, 0, 0, &full);
1785 wld_flush(swc.backend->renderer);
1786 pixman_region32_fini(&full);
1787
1788 wld_buffer_unreference(zoomed);
1789 } else {
1790 pixman_region32_t base_damage;
1791 pixman_region32_copy(&damage, total_damage);
1792 pixman_region32_translate(&damage, geom->x, geom->y);
1793 pixman_region32_init(&base_damage);
1794 pixman_region32_subtract(&base_damage, &damage, &compositor.opaque);
1795 renderer_repaint(target, &damage, &base_damage, &compositor.views,
1796 screen);
1797 pixman_region32_fini(&damage);
1798 pixman_region32_fini(&base_damage);
1799 }
1800
1801 switch (target_swap_buffers(target)) {
1802 case -EACCES:
1803 /* If we get an EACCES, it is because this session is being deactivated,
1804 * but we haven't yet received the deactivate signal from swc-launch. */
1805 swc_deactivate();
1806 break;
1807 case 0:
1808 compositor.pending_flips |= screen_mask(screen);
1809 break;
1810 }
1811}
1812
1813static void
1814perform_update(void *data)
1815{
1816 struct screen *screen;
1817 uint32_t updates = compositor.scheduled_updates & ~compositor.pending_flips;
1818
1819 if (!swc.active || !updates) {
1820 return;
1821 }
1822
1823 DEBUG("Performing update\n");
1824
1825 compositor.updating = true;
1826 calculate_damage();
1827
1828 wl_list_for_each(screen, &swc.screens, link) update_screen(screen);
1829
1830 /* XXX: Should assert that all damage was covered by some output */
1831 pixman_region32_clear(&compositor.damage);
1832 compositor.scheduled_updates &= ~updates;
1833 compositor.updating = false;
1834}
1835
1836bool
1837handle_motion(struct pointer_handler *handler, uint32_t time, wl_fixed_t fx,
1838 wl_fixed_t fy)
1839{
1840 int32_t x = wl_fixed_to_int(fx), y = wl_fixed_to_int(fy);
1841
1842 /* If buttons are pressed, don't change pointer focus. */
1843 if (swc.seat->pointer->buttons.size > 0) {
1844 return false;
1845 }
1846
1847 struct compositor_view *view = view_at(x, y);
1848
1849 pointer_set_focus(swc.seat->pointer, view);
1850
1851 return false;
1852}
1853
1854static bool
1855handle_button(struct pointer_handler *handler, uint32_t time,
1856 struct button *button, uint32_t state)
1857{
1858 (void)handler;
1859 (void)time;
1860 (void)button;
1861
1862 if (state != WL_POINTER_BUTTON_STATE_PRESSED) {
1863 return false;
1864 }
1865
1866 int32_t x = wl_fixed_to_int(swc.seat->pointer->x);
1867 int32_t y = wl_fixed_to_int(swc.seat->pointer->y);
1868 struct compositor_view *view = view_at(x, y);
1869
1870 pointer_set_focus(swc.seat->pointer, view);
1871 raise_window(view);
1872
1873 return false;
1874}
1875
1876static void
1877handle_terminate(void *data, uint32_t time, uint32_t value, uint32_t state)
1878{
1879 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
1880 wl_display_terminate(swc.display);
1881 }
1882}
1883
1884static void
1885handle_switch_vt(void *data, uint32_t time, uint32_t value, uint32_t state)
1886{
1887 uint8_t vt = value - XKB_KEY_XF86Switch_VT_1 + 1;
1888
1889 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
1890 launch_activate_vt(vt);
1891 }
1892}
1893
1894static void
1895handle_swc_event(struct wl_listener *listener, void *data)
1896{
1897 struct event *event = data;
1898
1899 switch (event->type) {
1900 case SWC_EVENT_ACTIVATED:
1901 schedule_updates(-1);
1902 break;
1903 case SWC_EVENT_DEACTIVATED:
1904 compositor.scheduled_updates = 0;
1905 break;
1906 }
1907}
1908
1909static void
1910create_surface(struct wl_client *client, struct wl_resource *resource,
1911 uint32_t id)
1912{
1913 struct surface *surface;
1914
1915 /* Initialize surface. */
1916 surface = surface_new(client, wl_resource_get_version(resource), id);
1917
1918 if (!surface) {
1919 wl_resource_post_no_memory(resource);
1920 return;
1921 }
1922
1923 wl_signal_emit(&swc_compositor.signal.new_surface, surface);
1924}
1925
1926static void
1927create_region(struct wl_client *client, struct wl_resource *resource,
1928 uint32_t id)
1929{
1930 if (!region_new(client, wl_resource_get_version(resource), id)) {
1931 wl_resource_post_no_memory(resource);
1932 }
1933}
1934
1935static const struct wl_compositor_interface compositor_impl = {
1936 .create_surface = create_surface,
1937 .create_region = create_region,
1938};
1939
1940static void
1941bind_compositor(struct wl_client *client, void *data, uint32_t version,
1942 uint32_t id)
1943{
1944 struct wl_resource *resource;
1945
1946 resource =
1947 wl_resource_create(client, &wl_compositor_interface, version, id);
1948 if (!resource) {
1949 wl_client_post_no_memory(client);
1950 return;
1951 }
1952 wl_resource_set_implementation(resource, &compositor_impl, NULL, NULL);
1953}
1954
1955bool
1956compositor_initialize(void)
1957{
1958 struct screen *screen;
1959 uint32_t keysym;
1960
1961 compositor.global = wl_global_create(swc.display, &wl_compositor_interface,
1962 4, NULL, &bind_compositor);
1963
1964 if (!compositor.global) {
1965 return false;
1966 }
1967
1968 compositor.scheduled_updates = 0;
1969 compositor.pending_flips = 0;
1970 compositor.updating = false;
1971 compositor.zoom = 1.0f;
1972 compositor.zoom_buffer = NULL;
1973 if (!decor_initialize()) {
1974 return false;
1975 }
1976 pixman_region32_init(&compositor.damage);
1977 pixman_region32_init(&compositor.opaque);
1978 wl_list_init(&compositor.views);
1979 wl_signal_init(&swc_compositor.signal.new_surface);
1980 compositor.swc_listener.notify = &handle_swc_event;
1981 wl_signal_add(&swc.event_signal, &compositor.swc_listener);
1982
1983 wl_list_for_each(screen, &swc.screens, link) target_new(screen);
1984 if (swc.active) {
1985 schedule_updates(-1);
1986 }
1987
1988 swc_add_binding(SWC_BINDING_KEY, SWC_MOD_CTRL | SWC_MOD_ALT,
1989 XKB_KEY_BackSpace, &handle_terminate, NULL);
1990
1991 for (keysym = XKB_KEY_XF86Switch_VT_1; keysym <= XKB_KEY_XF86Switch_VT_12;
1992 ++keysym) {
1993 swc_add_binding(SWC_BINDING_KEY, SWC_MOD_ANY, keysym, &handle_switch_vt,
1994 NULL);
1995 }
1996
1997 compositor.initialized = true;
1998
1999 return true;
2000}
2001
2002void
2003compositor_finalize(void)
2004{
2005 compositor.initialized = false;
2006
2007 if (compositor.zoom_buffer) {
2008 wld_buffer_unreference(compositor.zoom_buffer);
2009 compositor.zoom_buffer = NULL;
2010 }
2011 decor_finalize();
2012 pixman_region32_fini(&compositor.damage);
2013 pixman_region32_fini(&compositor.opaque);
2014 wl_global_destroy(compositor.global);
2015}
2016
2017struct wld_buffer *
2018compositor_get_buffer(struct screen *screen)
2019{
2020 struct target *target = target_get(screen);
2021 if (!target) {
2022 return NULL;
2023 }
2024 return target->current_buffer;
2025}
2026
2027struct wld_buffer *
2028compositor_render_to_shm(struct screen *screen)
2029{
2030 if (compositor.zoom != 1.0f) {
2031 return render_zoomed_to_shm(screen, compositor.zoom);
2032 }
2033
2034 uint32_t width = screen->base.geometry.width;
2035 uint32_t height = screen->base.geometry.height;
2036 struct wld_buffer *buffer;
2037 struct compositor_view *view;
2038 pixman_region32_t region;
2039 pixman_region32_t damage;
2040 uint32_t caps;
2041
2042 /* create shm buf */
2043 buffer = wld_create_buffer(swc.shm->context, width, height,
2044 WLD_FORMAT_ARGB8888, WLD_FLAG_MAP);
2045 if (!buffer) {
2046 return NULL;
2047 }
2048
2049 caps = wld_capabilities(swc.shm->renderer, buffer);
2050 if (!(caps & WLD_CAPABILITY_WRITE) ||
2051 !wld_set_target_buffer(swc.shm->renderer, buffer)) {
2052 wld_buffer_unreference(buffer);
2053 return NULL;
2054 }
2055
2056 /* set region */
2057 pixman_region32_init_rect(®ion, 0, 0, width, height);
2058 pixman_region32_init_rect(&damage, screen->base.geometry.x,
2059 screen->base.geometry.y, width, height);
2060
2061 /* background */
2062 wld_fill_region(swc.shm->renderer, DEFAULT_BG, ®ion);
2063
2064 wl_list_for_each_reverse(view, &compositor.views, link)
2065 {
2066 struct wld_buffer *src = view->buffer;
2067
2068 if (!view->visible) {
2069 continue;
2070 }
2071
2072 if (src &&
2073 !(wld_capabilities(swc.shm->renderer, src) & WLD_CAPABILITY_READ)) {
2074 src = view->base.buffer;
2075 }
2076
2077 if (src &&
2078 (wld_capabilities(swc.shm->renderer, src) & WLD_CAPABILITY_READ)) {
2079 const struct swc_rectangle *geom = &view->base.geometry;
2080 int32_t src_x = view->window ? view->buffer_offset_x : 0;
2081 int32_t src_y = view->window ? view->buffer_offset_y : 0;
2082 int32_t dst_x = geom->x - src_x - screen->base.geometry.x;
2083 int32_t dst_y = geom->y - src_y - screen->base.geometry.y;
2084 pixman_region32_t source_region;
2085
2086 pixman_region32_init_rect(&source_region, src_x, src_y, geom->width,
2087 geom->height);
2088 pixman_region32_intersect_rect(&source_region, &source_region, 0, 0,
2089 src->width, src->height);
2090 if (src->format == WLD_FORMAT_ARGB8888) {
2091 wld_blend_region(swc.shm->renderer, src, dst_x, dst_y,
2092 &source_region);
2093 } else {
2094 wld_copy_region(swc.shm->renderer, src, dst_x, dst_y,
2095 &source_region);
2096 }
2097 pixman_region32_fini(&source_region);
2098 }
2099
2100 if ((view->border.outwidth > 0 || view->border.inwidth > 0) &&
2101 view->base.buffer) {
2102 pixman_region32_t view_region, view_damage, border_damage;
2103 const struct swc_rectangle *geom = &view->base.geometry;
2104 const struct swc_rectangle *target_geom = &screen->base.geometry;
2105
2106 pixman_region32_init_rect(&view_region, geom->x, geom->y,
2107 geom->width, geom->height);
2108 pixman_region32_init_with_extents(&view_damage, &view->extents);
2109 pixman_region32_init(&border_damage);
2110
2111 pixman_region32_intersect(&view_damage, &view_damage, &damage);
2112 pixman_region32_subtract(&view_damage, &view_damage, &view->clip);
2113 pixman_region32_subtract(&border_damage, &view_damage,
2114 &view_region);
2115
2116 pixman_region32_t in_rect;
2117 pixman_region32_init_rect(&in_rect,
2118 geom->x - view->border.inwidth,
2119 geom->y - view->border.inwidth,
2120 geom->width + (2 * view->border.inwidth),
2121 geom->height +
2122 (2 * view->border.inwidth));
2123
2124 pixman_region32_t out_border;
2125 pixman_region32_init(&out_border);
2126 pixman_region32_subtract(&out_border, &border_damage, &in_rect);
2127
2128 pixman_region32_t in_border;
2129 pixman_region32_init(&in_border);
2130 pixman_region32_subtract(&in_border, &in_rect, &view_region);
2131 pixman_region32_intersect(&in_border, &in_border, &border_damage);
2132
2133 if (view->border.outwidth > 0 &&
2134 pixman_region32_not_empty(&out_border)) {
2135 pixman_region32_translate(&out_border, -target_geom->x,
2136 -target_geom->y);
2137 wld_fill_region(swc.shm->renderer, view->border.outcolor,
2138 &out_border);
2139 }
2140
2141 if (view->border.inwidth > 0 &&
2142 pixman_region32_not_empty(&in_border)) {
2143 pixman_region32_translate(&in_border, -target_geom->x,
2144 -target_geom->y);
2145 wld_fill_region(swc.shm->renderer, view->border.incolor,
2146 &in_border);
2147 }
2148
2149 pixman_region32_fini(&border_damage);
2150 pixman_region32_fini(&view_region);
2151 pixman_region32_fini(&view_damage);
2152 pixman_region32_fini(&in_rect);
2153 pixman_region32_fini(&out_border);
2154 pixman_region32_fini(&in_border);
2155 }
2156
2157 if (view->decor.top || view->decor.right || view->decor.bottom ||
2158 view->decor.left) {
2159 const struct swc_rectangle *target_geom = &screen->base.geometry;
2160 decor_repaint(swc.shm->renderer, target_geom, view, &damage);
2161 }
2162 }
2163
2164 draw_overlays(swc.shm->renderer, &screen->base.geometry);
2165
2166 wld_flush(swc.shm->renderer);
2167 pixman_region32_fini(®ion);
2168 pixman_region32_fini(&damage);
2169
2170 return buffer;
2171}