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