blob: 3fa1b8d0bc4e984e1e1d0c376ca4d2bf7ee083d3 [file] [log] [blame]
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2010-2011 Intel Corporation
3 * Copyright © 2008-2011 Kristian Høgsberg
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03004 * Copyright © 2012-2018, 2021 Collabora, Ltd.
Pekka Paalanen925788f2018-04-19 14:20:01 +03005 * Copyright © 2017, 2018 General Electric Company
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05006 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07007 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
Kristian Høgsbergffd710e2008-12-02 15:15:01 -050014 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070015 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
Kristian Høgsbergffd710e2008-12-02 15:15:01 -050027 */
28
Kristian Høgsberga9410222011-01-14 17:22:35 -050029#include "config.h"
30
Daniel Stoneb7452fe2012-06-01 12:14:06 +010031#include <fcntl.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040032#include <stdio.h>
33#include <string.h>
34#include <stdlib.h>
35#include <stdint.h>
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +010036#include <limits.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050037#include <stdarg.h>
Benjamin Franzke6f5fc692011-06-21 19:34:19 +020038#include <assert.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040039#include <sys/ioctl.h>
Daniel Stoneb7452fe2012-06-01 12:14:06 +010040#include <sys/mman.h>
Kristian Høgsberg27da5382011-06-21 17:32:25 -040041#include <sys/wait.h>
Pekka Paalanen409ef0a2011-12-02 15:30:21 +020042#include <sys/socket.h>
Martin Minarikf12c2872012-06-11 00:57:39 +020043#include <sys/utsname.h>
Martin Minarik37032f82012-06-18 20:15:18 +020044#include <sys/stat.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040045#include <unistd.h>
Kristian Høgsberg54879822008-11-23 17:07:32 -050046#include <math.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include <linux/input.h>
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040048#include <dlfcn.h>
Kristian Høgsberg85449032011-05-02 12:11:07 -040049#include <signal.h>
Kristian Høgsberg0690da62012-01-16 11:53:54 -050050#include <setjmp.h>
Kristian Høgsberga411c8b2012-06-08 16:16:52 -040051#include <sys/time.h>
52#include <time.h>
Pekka Paalanen23ade622014-08-27 13:31:26 +030053#include <errno.h>
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030054#include <inttypes.h>
Kristian Høgsberg890bc052008-12-30 14:31:33 -050055
Pekka Paalanenb5026542014-11-12 15:09:24 +020056#include "timeline.h"
57
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020058#include <libweston/libweston.h>
Marius Vladc901e892019-06-21 22:49:18 +030059#include <libweston/weston-log.h>
Daniel Stonece62cb32018-07-20 09:46:24 +010060#include "linux-dmabuf.h"
Pekka Paalanene95ad5c2016-04-15 14:47:08 +030061#include "viewporter-server-protocol.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020062#include "presentation-time-server-protocol.h"
Roman Gilge97391c2019-03-29 13:01:06 +010063#include "xdg-output-unstable-v1-server-protocol.h"
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030064#include "linux-explicit-synchronization-unstable-v1-server-protocol.h"
Alexandros Frantzis67629672018-10-19 12:14:11 +030065#include "linux-explicit-synchronization.h"
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030066#include "shared/fd-util.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070067#include "shared/helpers.h"
Jon Cruz4678bab2015-06-15 15:37:07 -070068#include "shared/os-compatibility.h"
Bryce Harrington25a2bdd2016-08-03 17:40:52 -070069#include "shared/string-helpers.h"
Pekka Paalanenaa21f622015-07-03 15:44:50 +030070#include "shared/timespec-util.h"
Kristian Høgsberga411c8b2012-06-08 16:16:52 -040071#include "git-version.h"
Pekka Paalanencda14882019-04-04 15:41:02 +030072#include <libweston/version.h>
Pekka Paalanen27b377f2019-03-29 17:07:34 +020073#include <libweston/plugin-registry.h>
Marius Vlad00a6e012018-11-20 17:52:31 +020074#include "pixel-formats.h"
Marius Vlad63ef0782019-07-16 23:34:14 +030075#include "backend.h"
Marius Vlada72e3712019-07-10 13:46:39 +030076#include "libweston-internal.h"
Pekka Paalanen90a5ffa2021-02-25 12:03:28 +020077#include "color.h"
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050078
Marius Vlad4e036292019-07-09 00:36:20 +030079#include "weston-log-internal.h"
80
Marius Vlad78984ee2019-06-11 00:05:08 +030081/**
82 * \defgroup head Head
83 * \defgroup output Output
84 * \defgroup compositor Compositor
85 */
86
Pekka Paalanen0513a952014-05-21 16:17:27 +030087#define DEFAULT_REPAINT_WINDOW 7 /* milliseconds */
88
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -020089static void
Pekka Paalanend72bad22017-03-29 17:01:41 +030090weston_output_update_matrix(struct weston_output *output);
91
92static void
Alexander Larsson0b135062013-05-28 16:23:36 +020093weston_output_transform_scale_init(struct weston_output *output,
94 uint32_t transform, uint32_t scale);
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -020095
Rob Bradford27b17932013-06-26 18:08:46 +010096static void
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +030097weston_compositor_build_view_list(struct weston_compositor *compositor,
98 struct weston_output *output);
Rob Bradford27b17932013-06-26 18:08:46 +010099
Pekka Paalanendcac3512017-12-08 14:13:34 +0200100static char *
101weston_output_create_heads_string(struct weston_output *output);
102
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +0300103static struct weston_paint_node *
104weston_paint_node_create(struct weston_surface *surface,
105 struct weston_view *view,
106 struct weston_output *output)
107{
108 struct weston_paint_node *pnode;
Pekka Paalanen90a5ffa2021-02-25 12:03:28 +0200109 struct weston_paint_node *existing_node;
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +0300110
111 assert(view->surface == surface);
112
113 pnode = zalloc(sizeof *pnode);
114 if (!pnode)
115 return NULL;
116
Pekka Paalanen90a5ffa2021-02-25 12:03:28 +0200117 /*
118 * Invariant: all paint nodes with the same surface+output have the
119 * same surf_xform state.
120 */
121 wl_list_for_each(existing_node, &view->paint_node_list, view_link) {
122 assert(existing_node->surface == surface);
123 if (existing_node->output != output)
124 continue;
125
126 weston_surface_color_transform_copy(&pnode->surf_xform,
127 &existing_node->surf_xform);
128 pnode->surf_xform_valid = existing_node->surf_xform_valid;
129 break;
130 }
131
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +0300132 pnode->surface = surface;
133 wl_list_insert(&surface->paint_node_list, &pnode->surface_link);
134
135 pnode->view = view;
136 wl_list_insert(&view->paint_node_list, &pnode->view_link);
137
138 pnode->output = output;
139 wl_list_insert(&output->paint_node_list, &pnode->output_link);
140
Pekka Paalanen2fddc532021-04-30 17:41:29 +0300141 wl_list_init(&pnode->z_order_link);
142
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +0300143 return pnode;
144}
145
146static void
147weston_paint_node_destroy(struct weston_paint_node *pnode)
148{
149 assert(pnode->view->surface == pnode->surface);
150 wl_list_remove(&pnode->surface_link);
151 wl_list_remove(&pnode->view_link);
152 wl_list_remove(&pnode->output_link);
Pekka Paalanen2fddc532021-04-30 17:41:29 +0300153 wl_list_remove(&pnode->z_order_link);
Pekka Paalanen90a5ffa2021-02-25 12:03:28 +0200154 assert(pnode->surf_xform_valid || !pnode->surf_xform.transform);
155 weston_surface_color_transform_fini(&pnode->surf_xform);
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +0300156 free(pnode);
157}
158
Pekka Paalanen6528c032017-03-28 15:27:10 +0300159/** Send wl_output events for mode and scale changes
160 *
161 * \param head Send on all resources bound to this head.
162 * \param mode_changed If true, send the current mode.
163 * \param scale_changed If true, send the current scale.
164 */
165static void
166weston_mode_switch_send_events(struct weston_head *head,
167 bool mode_changed, bool scale_changed)
168{
169 struct weston_output *output = head->output;
170 struct wl_resource *resource;
171 int version;
172
173 wl_resource_for_each(resource, &head->resource_list) {
174 if (mode_changed) {
175 wl_output_send_mode(resource,
176 output->current_mode->flags,
177 output->current_mode->width,
178 output->current_mode->height,
179 output->current_mode->refresh);
180 }
181
182 version = wl_resource_get_version(resource);
183 if (version >= WL_OUTPUT_SCALE_SINCE_VERSION && scale_changed)
184 wl_output_send_scale(resource, output->current_scale);
185
186 if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
187 wl_output_send_done(resource);
188 }
Roman Gilge97391c2019-03-29 13:01:06 +0100189 wl_resource_for_each(resource, &head->xdg_output_resource_list) {
190 zxdg_output_v1_send_logical_position(resource,
191 output->x,
192 output->y);
193 zxdg_output_v1_send_logical_size(resource,
194 output->width,
195 output->height);
196 zxdg_output_v1_send_done(resource);
197 }
Pekka Paalanen6528c032017-03-28 15:27:10 +0300198}
199
200static void
201weston_mode_switch_finish(struct weston_output *output,
202 int mode_changed, int scale_changed)
Alex Wu2dda6042012-04-17 17:20:47 +0800203{
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -0200204 struct weston_seat *seat;
Pekka Paalanen1b9bf592017-03-27 12:15:38 +0300205 struct weston_head *head;
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -0200206 pixman_region32_t old_output_region;
Alexander Larsson355748e2013-05-28 16:23:38 +0200207
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -0200208 pixman_region32_init(&old_output_region);
209 pixman_region32_copy(&old_output_region, &output->region);
210
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -0200211 /* Update output region and transformation matrix */
Hardeningff39efa2013-09-18 23:56:35 +0200212 weston_output_transform_scale_init(output, output->transform, output->current_scale);
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -0200213
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -0200214 pixman_region32_init_rect(&output->region, output->x, output->y,
215 output->width, output->height);
216
217 weston_output_update_matrix(output);
218
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -0200219 /* If a pointer falls outside the outputs new geometry, move it to its
220 * lower-right corner */
221 wl_list_for_each(seat, &output->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500222 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -0200223 int32_t x, y;
224
225 if (!pointer)
226 continue;
227
228 x = wl_fixed_to_int(pointer->x);
229 y = wl_fixed_to_int(pointer->y);
230
231 if (!pixman_region32_contains_point(&old_output_region,
232 x, y, NULL) ||
233 pixman_region32_contains_point(&output->region,
234 x, y, NULL))
235 continue;
236
237 if (x >= output->x + output->width)
238 x = output->x + output->width - 1;
239 if (y >= output->y + output->height)
240 y = output->y + output->height - 1;
241
242 pointer->x = wl_fixed_from_int(x);
243 pointer->y = wl_fixed_from_int(y);
244 }
245
246 pixman_region32_fini(&old_output_region);
247
Derek Foremandd4cd332014-11-10 10:29:59 -0600248 if (!mode_changed && !scale_changed)
249 return;
250
Hardening57388e42013-09-18 23:56:36 +0200251 /* notify clients of the changes */
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +0300252 wl_list_for_each(head, &output->head_list, output_link)
253 weston_mode_switch_send_events(head,
254 mode_changed, scale_changed);
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600255}
256
David Fort0de859e2016-05-27 23:22:57 +0200257static void
258weston_compositor_reflow_outputs(struct weston_compositor *compositor,
259 struct weston_output *resized_output, int delta_width);
260
Marius Vlad55d87362019-06-11 01:15:35 +0300261/**
262 * \ingroup output
263 */
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600264WL_EXPORT int
265weston_output_mode_set_native(struct weston_output *output,
266 struct weston_mode *mode,
267 int32_t scale)
268{
269 int ret;
270 int mode_changed = 0, scale_changed = 0;
David Fort0de859e2016-05-27 23:22:57 +0200271 int32_t old_width;
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600272
273 if (!output->switch_mode)
274 return -1;
275
276 if (!output->original_mode) {
277 mode_changed = 1;
278 ret = output->switch_mode(output, mode);
279 if (ret < 0)
280 return ret;
281 if (output->current_scale != scale) {
282 scale_changed = 1;
283 output->current_scale = scale;
Hardening57388e42013-09-18 23:56:36 +0200284 }
285 }
286
David Fort0de859e2016-05-27 23:22:57 +0200287 old_width = output->width;
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600288 output->native_mode = mode;
289 output->native_scale = scale;
290
291 weston_mode_switch_finish(output, mode_changed, scale_changed);
292
David Fort0de859e2016-05-27 23:22:57 +0200293 if (mode_changed || scale_changed) {
294 weston_compositor_reflow_outputs(output->compositor, output, output->width - old_width);
295
296 wl_signal_emit(&output->compositor->output_resized_signal, output);
297 }
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600298 return 0;
299}
300
Marius Vlad55d87362019-06-11 01:15:35 +0300301/**
302 * \ingroup output
303 */
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600304WL_EXPORT int
305weston_output_mode_switch_to_native(struct weston_output *output)
306{
307 int ret;
308 int mode_changed = 0, scale_changed = 0;
309
310 if (!output->switch_mode)
311 return -1;
312
313 if (!output->original_mode) {
314 weston_log("already in the native mode\n");
315 return -1;
316 }
317 /* the non fullscreen clients haven't seen a mode set since we
318 * switched into a temporary, so we need to notify them if the
319 * mode at that time is different from the native mode now.
320 */
321 mode_changed = (output->original_mode != output->native_mode);
322 scale_changed = (output->original_scale != output->native_scale);
323
324 ret = output->switch_mode(output, output->native_mode);
325 if (ret < 0)
326 return ret;
327
328 output->current_scale = output->native_scale;
329
330 output->original_mode = NULL;
331 output->original_scale = 0;
332
333 weston_mode_switch_finish(output, mode_changed, scale_changed);
334
335 return 0;
336}
337
Marius Vlad55d87362019-06-11 01:15:35 +0300338/**
339 * \ingroup output
340 */
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600341WL_EXPORT int
342weston_output_mode_switch_to_temporary(struct weston_output *output,
343 struct weston_mode *mode,
344 int32_t scale)
345{
346 int ret;
347
348 if (!output->switch_mode)
349 return -1;
350
351 /* original_mode is the last mode non full screen clients have seen,
352 * so we shouldn't change it if we already have one set.
353 */
354 if (!output->original_mode) {
355 output->original_mode = output->native_mode;
356 output->original_scale = output->native_scale;
357 }
358 ret = output->switch_mode(output, mode);
359 if (ret < 0)
360 return ret;
361
362 output->current_scale = scale;
363
364 weston_mode_switch_finish(output, 0, 0);
365
366 return 0;
Alex Wu2dda6042012-04-17 17:20:47 +0800367}
368
Benjamin Franzke06286262011-05-06 19:12:33 +0200369static void
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +0300370region_init_infinite(pixman_region32_t *region)
371{
372 pixman_region32_init_rect(region, INT32_MIN, INT32_MIN,
373 UINT32_MAX, UINT32_MAX);
374}
375
Pekka Paalanene67858b2013-04-25 13:57:42 +0300376static struct weston_subsurface *
377weston_surface_to_subsurface(struct weston_surface *surface);
378
Jason Ekstranda7af7042013-10-12 22:38:11 -0500379WL_EXPORT struct weston_view *
380weston_view_create(struct weston_surface *surface)
381{
382 struct weston_view *view;
383
Bryce Harringtonde16d892014-11-20 22:21:57 -0800384 view = zalloc(sizeof *view);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500385 if (view == NULL)
386 return NULL;
387
388 view->surface = surface;
Daniel Stonefb4869d2016-12-09 16:27:54 +0000389 view->plane = &surface->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500390
Jason Ekstranda7af7042013-10-12 22:38:11 -0500391 /* Assign to surface */
392 wl_list_insert(&surface->views, &view->surface_link);
393
394 wl_signal_init(&view->destroy_signal);
395 wl_list_init(&view->link);
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300396 wl_list_init(&view->layer_link.link);
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +0300397 wl_list_init(&view->paint_node_list);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500398
Jason Ekstranda7af7042013-10-12 22:38:11 -0500399 pixman_region32_init(&view->clip);
400
401 view->alpha = 1.0;
402 pixman_region32_init(&view->transform.opaque);
403
404 wl_list_init(&view->geometry.transformation_list);
405 wl_list_insert(&view->geometry.transformation_list,
406 &view->transform.position.link);
407 weston_matrix_init(&view->transform.position.matrix);
408 wl_list_init(&view->geometry.child_list);
Pekka Paalanen380adf52015-02-16 14:39:11 +0200409 pixman_region32_init(&view->geometry.scissor);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500410 pixman_region32_init(&view->transform.boundingbox);
411 view->transform.dirty = 1;
412
Jason Ekstranda7af7042013-10-12 22:38:11 -0500413 return view;
414}
415
Pekka Paalanen133e4392014-09-23 22:08:46 -0400416struct weston_presentation_feedback {
417 struct wl_resource *resource;
418
419 /* XXX: could use just wl_resource_get_link() instead */
420 struct wl_list link;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +0200421
422 /* The per-surface feedback flags */
423 uint32_t psf_flags;
Pekka Paalanen133e4392014-09-23 22:08:46 -0400424};
425
426static void
427weston_presentation_feedback_discard(
428 struct weston_presentation_feedback *feedback)
429{
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200430 wp_presentation_feedback_send_discarded(feedback->resource);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400431 wl_resource_destroy(feedback->resource);
432}
433
434static void
435weston_presentation_feedback_discard_list(struct wl_list *list)
436{
437 struct weston_presentation_feedback *feedback, *tmp;
438
439 wl_list_for_each_safe(feedback, tmp, list, link)
440 weston_presentation_feedback_discard(feedback);
441}
442
443static void
444weston_presentation_feedback_present(
445 struct weston_presentation_feedback *feedback,
446 struct weston_output *output,
447 uint32_t refresh_nsec,
448 const struct timespec *ts,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200449 uint64_t seq,
450 uint32_t flags)
Pekka Paalanen133e4392014-09-23 22:08:46 -0400451{
452 struct wl_client *client = wl_resource_get_client(feedback->resource);
Pekka Paalanen1b9bf592017-03-27 12:15:38 +0300453 struct weston_head *head;
Pekka Paalanen133e4392014-09-23 22:08:46 -0400454 struct wl_resource *o;
Alexandros Frantzis10d708d2017-12-13 13:27:54 +0200455 uint32_t tv_sec_hi;
456 uint32_t tv_sec_lo;
457 uint32_t tv_nsec;
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +0300458 bool done = false;
Pekka Paalanen133e4392014-09-23 22:08:46 -0400459
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +0300460 wl_list_for_each(head, &output->head_list, output_link) {
461 wl_resource_for_each(o, &head->resource_list) {
462 if (wl_resource_get_client(o) != client)
463 continue;
Pekka Paalanen133e4392014-09-23 22:08:46 -0400464
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +0300465 wp_presentation_feedback_send_sync_output(feedback->resource, o);
466 done = true;
467 }
468
469 /* For clone mode, send it for just one wl_output global,
470 * they are all equivalent anyway.
471 */
472 if (done)
473 break;
Pekka Paalanen133e4392014-09-23 22:08:46 -0400474 }
475
Alexandros Frantzis10d708d2017-12-13 13:27:54 +0200476 timespec_to_proto(ts, &tv_sec_hi, &tv_sec_lo, &tv_nsec);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200477 wp_presentation_feedback_send_presented(feedback->resource,
Alexandros Frantzis10d708d2017-12-13 13:27:54 +0200478 tv_sec_hi, tv_sec_lo, tv_nsec,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200479 refresh_nsec,
480 seq >> 32, seq & 0xffffffff,
481 flags | feedback->psf_flags);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400482 wl_resource_destroy(feedback->resource);
483}
484
485static void
486weston_presentation_feedback_present_list(struct wl_list *list,
487 struct weston_output *output,
488 uint32_t refresh_nsec,
489 const struct timespec *ts,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200490 uint64_t seq,
491 uint32_t flags)
Pekka Paalanen133e4392014-09-23 22:08:46 -0400492{
493 struct weston_presentation_feedback *feedback, *tmp;
494
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200495 assert(!(flags & WP_PRESENTATION_FEEDBACK_INVALID) ||
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200496 wl_list_empty(list));
497
Pekka Paalanen133e4392014-09-23 22:08:46 -0400498 wl_list_for_each_safe(feedback, tmp, list, link)
499 weston_presentation_feedback_present(feedback, output,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200500 refresh_nsec, ts, seq,
501 flags);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400502}
503
Jason Ekstrand7b982072014-05-20 14:33:03 -0500504static void
505surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
506{
507 struct weston_surface_state *state =
508 container_of(listener, struct weston_surface_state,
509 buffer_destroy_listener);
510
511 state->buffer = NULL;
512}
513
514static void
515weston_surface_state_init(struct weston_surface_state *state)
516{
517 state->newly_attached = 0;
518 state->buffer = NULL;
519 state->buffer_destroy_listener.notify =
520 surface_state_handle_buffer_destroy;
521 state->sx = 0;
522 state->sy = 0;
523
Derek Foreman152254b2015-11-26 14:17:48 -0600524 pixman_region32_init(&state->damage_surface);
525 pixman_region32_init(&state->damage_buffer);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500526 pixman_region32_init(&state->opaque);
527 region_init_infinite(&state->input);
528
529 wl_list_init(&state->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400530 wl_list_init(&state->feedback_list);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500531
532 state->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
533 state->buffer_viewport.buffer.scale = 1;
534 state->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
535 state->buffer_viewport.surface.width = -1;
536 state->buffer_viewport.changed = 0;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +0300537
538 state->acquire_fence_fd = -1;
Ankit Nautiyal4b6e73d2019-03-26 13:37:12 +0530539
540 state->desired_protection = WESTON_HDCP_DISABLE;
Ankit Nautiyal5cfe03c2019-03-28 15:05:42 +0530541 state->protection_mode = WESTON_SURFACE_PROTECTION_MODE_RELAXED;
Jason Ekstrand7b982072014-05-20 14:33:03 -0500542}
543
544static void
545weston_surface_state_fini(struct weston_surface_state *state)
546{
Vlad Zahorodniic2b97472021-07-29 11:16:51 +0300547 struct wl_resource *cb, *next;
Jason Ekstrand7b982072014-05-20 14:33:03 -0500548
Vlad Zahorodniic2b97472021-07-29 11:16:51 +0300549 wl_resource_for_each_safe(cb, next, &state->frame_callback_list)
550 wl_resource_destroy(cb);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500551
Pekka Paalanen133e4392014-09-23 22:08:46 -0400552 weston_presentation_feedback_discard_list(&state->feedback_list);
553
Jason Ekstrand7b982072014-05-20 14:33:03 -0500554 pixman_region32_fini(&state->input);
555 pixman_region32_fini(&state->opaque);
Derek Foreman152254b2015-11-26 14:17:48 -0600556 pixman_region32_fini(&state->damage_surface);
557 pixman_region32_fini(&state->damage_buffer);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500558
559 if (state->buffer)
560 wl_list_remove(&state->buffer_destroy_listener.link);
561 state->buffer = NULL;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +0300562
563 fd_clear(&state->acquire_fence_fd);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300564 weston_buffer_release_reference(&state->buffer_release_ref, NULL);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500565}
566
567static void
568weston_surface_state_set_buffer(struct weston_surface_state *state,
569 struct weston_buffer *buffer)
570{
571 if (state->buffer == buffer)
572 return;
573
574 if (state->buffer)
575 wl_list_remove(&state->buffer_destroy_listener.link);
576 state->buffer = buffer;
577 if (state->buffer)
578 wl_signal_add(&state->buffer->destroy_signal,
579 &state->buffer_destroy_listener);
580}
581
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500582WL_EXPORT struct weston_surface *
Kristian Høgsberg18c93002012-01-27 11:58:31 -0500583weston_surface_create(struct weston_compositor *compositor)
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500584{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500585 struct weston_surface *surface;
Kristian Høgsberg77fb1672010-08-16 10:38:29 -0400586
Bryce Harringtonde16d892014-11-20 22:21:57 -0800587 surface = zalloc(sizeof *surface);
Kristian Høgsberg77fb1672010-08-16 10:38:29 -0400588 if (surface == NULL)
589 return NULL;
590
Jason Ekstrand26ed73c2013-06-06 22:34:41 -0500591 wl_signal_init(&surface->destroy_signal);
Jonas Ådahl5d9ca272016-07-22 17:48:03 +0800592 wl_signal_init(&surface->commit_signal);
Jason Ekstrand26ed73c2013-06-06 22:34:41 -0500593
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500594 surface->compositor = compositor;
Giulio Camuffo13b85bd2013-08-13 23:10:14 +0200595 surface->ref_count = 1;
Kristian Høgsberg27803c62010-06-06 22:23:21 -0400596
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200597 surface->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
598 surface->buffer_viewport.buffer.scale = 1;
Pekka Paalanenf0cad482014-03-14 14:38:16 +0200599 surface->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
600 surface->buffer_viewport.surface.width = -1;
Jason Ekstrand7b982072014-05-20 14:33:03 -0500601
602 weston_surface_state_init(&surface->pending);
603
Kristian Høgsberg20300ba2011-06-23 20:29:12 -0400604 pixman_region32_init(&surface->damage);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -0500605 pixman_region32_init(&surface->opaque);
Pekka Paalanen8ec4ab62012-10-10 12:49:32 +0300606 region_init_infinite(&surface->input);
Kristian Høgsberg20300ba2011-06-23 20:29:12 -0400607
Jason Ekstranda7af7042013-10-12 22:38:11 -0500608 wl_list_init(&surface->views);
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +0300609 wl_list_init(&surface->paint_node_list);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500610
611 wl_list_init(&surface->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400612 wl_list_init(&surface->feedback_list);
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500613
Pekka Paalanene67858b2013-04-25 13:57:42 +0300614 wl_list_init(&surface->subsurface_list);
615 wl_list_init(&surface->subsurface_list_pending);
616
Jason Ekstrand1e059042014-10-16 10:55:19 -0500617 weston_matrix_init(&surface->buffer_to_surface_matrix);
618 weston_matrix_init(&surface->surface_to_buffer_matrix);
619
Jonas Ådahld3414f22016-07-22 17:56:31 +0800620 wl_list_init(&surface->pointer_constraints);
621
Alexandros Frantzisacff29b2018-10-19 12:14:11 +0300622 surface->acquire_fence_fd = -1;
623
Ankit Nautiyal4b6e73d2019-03-26 13:37:12 +0530624 surface->desired_protection = WESTON_HDCP_DISABLE;
Ankit Nautiyal5cfe03c2019-03-28 15:05:42 +0530625 surface->current_protection = WESTON_HDCP_DISABLE;
626 surface->protection_mode = WESTON_SURFACE_PROTECTION_MODE_RELAXED;
Ankit Nautiyal4b6e73d2019-03-26 13:37:12 +0530627
Kristian Høgsberg77fb1672010-08-16 10:38:29 -0400628 return surface;
Kristian Høgsberg54879822008-11-23 17:07:32 -0500629}
630
Alex Wu8811bf92012-02-28 18:07:54 +0800631WL_EXPORT void
Kristian Høgsbergbbeefb02012-01-26 10:00:23 -0500632weston_surface_set_color(struct weston_surface *surface,
John Kåre Alsaker490d02a2012-09-30 02:57:21 +0200633 float red, float green, float blue, float alpha)
Kristian Høgsbergbbeefb02012-01-26 10:00:23 -0500634{
John Kåre Alsaker878f4492012-11-13 19:10:23 +0100635 surface->compositor->renderer->surface_set_color(surface, red, green, blue, alpha);
Philipp Zabel195dade2018-09-03 19:44:59 +0200636 surface->is_opaque = !(alpha < 1.0);
Kristian Høgsbergbbeefb02012-01-26 10:00:23 -0500637}
638
Kristian Høgsberge4c1a5f2012-06-18 13:17:32 -0400639WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500640weston_view_to_global_float(struct weston_view *view,
641 float sx, float sy, float *x, float *y)
Pekka Paalanenece8a012012-02-08 15:23:15 +0200642{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500643 if (view->transform.enabled) {
Pekka Paalanenece8a012012-02-08 15:23:15 +0200644 struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };
645
Jason Ekstranda7af7042013-10-12 22:38:11 -0500646 weston_matrix_transform(&view->transform.matrix, &v);
Pekka Paalanenece8a012012-02-08 15:23:15 +0200647
648 if (fabsf(v.f[3]) < 1e-6) {
Martin Minarik6d118362012-06-07 18:01:59 +0200649 weston_log("warning: numerical instability in "
Scott Moreau088c62e2013-02-11 04:45:38 -0700650 "%s(), divisor = %g\n", __func__,
Pekka Paalanenece8a012012-02-08 15:23:15 +0200651 v.f[3]);
652 *x = 0;
653 *y = 0;
654 return;
655 }
656
657 *x = v.f[0] / v.f[3];
658 *y = v.f[1] / v.f[3];
659 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500660 *x = sx + view->geometry.x;
661 *y = sy + view->geometry.y;
Pekka Paalanenece8a012012-02-08 15:23:15 +0200662 }
663}
664
Pekka Paalanen0df44772020-02-14 14:50:03 +0200665/** Transform a point to buffer coordinates
666 *
667 * \param width Surface width.
668 * \param height Surface height.
669 * \param transform Buffer transform.
670 * \param scale Buffer scale.
671 * \param sx Surface x coordinate of a point.
672 * \param sy Surface y coordinate of a point.
673 * \param[out] bx Buffer x coordinate of the point.
674 * \param[out] by Buffer Y coordinate of the point.
675 *
676 * Converts the given surface-local coordinates to buffer coordinates
677 * according to the given buffer transform and scale.
678 * This ignores wp_viewport.
679 *
680 * The given width and height must be the result of inverse scaled and
681 * inverse transformed buffer size.
682 */
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500683WL_EXPORT void
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200684weston_transformed_coord(int width, int height,
685 enum wl_output_transform transform,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200686 int32_t scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200687 float sx, float sy, float *bx, float *by)
688{
689 switch (transform) {
690 case WL_OUTPUT_TRANSFORM_NORMAL:
691 default:
692 *bx = sx;
693 *by = sy;
694 break;
695 case WL_OUTPUT_TRANSFORM_FLIPPED:
696 *bx = width - sx;
697 *by = sy;
698 break;
699 case WL_OUTPUT_TRANSFORM_90:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200700 *bx = sy;
701 *by = width - sx;
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200702 break;
703 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200704 *bx = sy;
705 *by = sx;
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200706 break;
707 case WL_OUTPUT_TRANSFORM_180:
708 *bx = width - sx;
709 *by = height - sy;
710 break;
711 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
712 *bx = sx;
713 *by = height - sy;
714 break;
715 case WL_OUTPUT_TRANSFORM_270:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200716 *bx = height - sy;
717 *by = sx;
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200718 break;
719 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200720 *bx = height - sy;
721 *by = width - sx;
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200722 break;
723 }
Alexander Larsson4ea95522013-05-22 14:41:37 +0200724
725 *bx *= scale;
726 *by *= scale;
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200727}
728
Pekka Paalanen0df44772020-02-14 14:50:03 +0200729/** Transform a rectangle to buffer coordinates
730 *
731 * \param width Surface width.
732 * \param height Surface height.
733 * \param transform Buffer transform.
734 * \param scale Buffer scale.
735 * \param rect Rectangle in surface coordinates.
736 * \return Rectangle in buffer coordinates.
737 *
738 * Converts the given surface-local rectangle to buffer coordinates
739 * according to the given buffer transform and scale. The resulting
740 * rectangle is guaranteed to be well-formed.
741 * This ignores wp_viewport.
742 *
743 * The given width and height must be the result of inverse scaled and
744 * inverse transformed buffer size.
745 */
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200746WL_EXPORT pixman_box32_t
747weston_transformed_rect(int width, int height,
748 enum wl_output_transform transform,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200749 int32_t scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200750 pixman_box32_t rect)
751{
752 float x1, x2, y1, y2;
753
754 pixman_box32_t ret;
755
Alexander Larsson4ea95522013-05-22 14:41:37 +0200756 weston_transformed_coord(width, height, transform, scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200757 rect.x1, rect.y1, &x1, &y1);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200758 weston_transformed_coord(width, height, transform, scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200759 rect.x2, rect.y2, &x2, &y2);
760
761 if (x1 <= x2) {
762 ret.x1 = x1;
763 ret.x2 = x2;
764 } else {
765 ret.x1 = x2;
766 ret.x2 = x1;
767 }
768
769 if (y1 <= y2) {
770 ret.y1 = y1;
771 ret.y2 = y2;
772 } else {
773 ret.y1 = y2;
774 ret.y2 = y1;
775 }
776
777 return ret;
778}
779
Derek Foremanbc9a61c2015-11-18 16:32:30 -0600780/** Transform a region by a matrix, restricted to axis-aligned transformations
781 *
782 * Warning: This function does not work for projective, affine, or matrices
783 * that encode arbitrary rotations. Only 90-degree step rotations are
784 * supported.
785 */
786WL_EXPORT void
787weston_matrix_transform_region(pixman_region32_t *dest,
788 struct weston_matrix *matrix,
789 pixman_region32_t *src)
790{
791 pixman_box32_t *src_rects, *dest_rects;
792 int nrects, i;
793
794 src_rects = pixman_region32_rectangles(src, &nrects);
795 dest_rects = malloc(nrects * sizeof(*dest_rects));
796 if (!dest_rects)
797 return;
798
799 for (i = 0; i < nrects; i++) {
800 struct weston_vector vec1 = {{
801 src_rects[i].x1, src_rects[i].y1, 0, 1
802 }};
803 weston_matrix_transform(matrix, &vec1);
804 vec1.f[0] /= vec1.f[3];
805 vec1.f[1] /= vec1.f[3];
806
807 struct weston_vector vec2 = {{
808 src_rects[i].x2, src_rects[i].y2, 0, 1
809 }};
810 weston_matrix_transform(matrix, &vec2);
811 vec2.f[0] /= vec2.f[3];
812 vec2.f[1] /= vec2.f[3];
813
814 if (vec1.f[0] < vec2.f[0]) {
815 dest_rects[i].x1 = floor(vec1.f[0]);
816 dest_rects[i].x2 = ceil(vec2.f[0]);
817 } else {
818 dest_rects[i].x1 = floor(vec2.f[0]);
819 dest_rects[i].x2 = ceil(vec1.f[0]);
820 }
821
Derek Foremanbc9a61c2015-11-18 16:32:30 -0600822 if (vec1.f[1] < vec2.f[1]) {
823 dest_rects[i].y1 = floor(vec1.f[1]);
824 dest_rects[i].y2 = ceil(vec2.f[1]);
825 } else {
826 dest_rects[i].y1 = floor(vec2.f[1]);
827 dest_rects[i].y2 = ceil(vec1.f[1]);
828 }
829 }
830
831 pixman_region32_clear(dest);
832 pixman_region32_init_rects(dest, dest_rects, nrects);
833 free(dest_rects);
834}
835
Pekka Paalanen0df44772020-02-14 14:50:03 +0200836/** Transform a region to buffer coordinates
837 *
838 * \param width Surface width.
839 * \param height Surface height.
840 * \param transform Buffer transform.
841 * \param scale Buffer scale.
842 * \param[in] src Region in surface coordinates.
843 * \param[out] dest Resulting region in buffer coordinates.
844 *
845 * Converts the given surface-local region to buffer coordinates
846 * according to the given buffer transform and scale.
847 * This ignores wp_viewport.
848 *
849 * The given width and height must be the result of inverse scaled and
850 * inverse transformed buffer size.
851 *
852 * src and dest are allowed to point to the same memory for in-place conversion.
853 */
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200854WL_EXPORT void
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500855weston_transformed_region(int width, int height,
856 enum wl_output_transform transform,
857 int32_t scale,
858 pixman_region32_t *src, pixman_region32_t *dest)
859{
860 pixman_box32_t *src_rects, *dest_rects;
861 int nrects, i;
862
863 if (transform == WL_OUTPUT_TRANSFORM_NORMAL && scale == 1) {
864 if (src != dest)
865 pixman_region32_copy(dest, src);
866 return;
867 }
868
869 src_rects = pixman_region32_rectangles(src, &nrects);
870 dest_rects = malloc(nrects * sizeof(*dest_rects));
871 if (!dest_rects)
872 return;
873
874 if (transform == WL_OUTPUT_TRANSFORM_NORMAL) {
875 memcpy(dest_rects, src_rects, nrects * sizeof(*dest_rects));
876 } else {
877 for (i = 0; i < nrects; i++) {
878 switch (transform) {
879 default:
880 case WL_OUTPUT_TRANSFORM_NORMAL:
881 dest_rects[i].x1 = src_rects[i].x1;
882 dest_rects[i].y1 = src_rects[i].y1;
883 dest_rects[i].x2 = src_rects[i].x2;
884 dest_rects[i].y2 = src_rects[i].y2;
885 break;
886 case WL_OUTPUT_TRANSFORM_90:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200887 dest_rects[i].x1 = src_rects[i].y1;
888 dest_rects[i].y1 = width - src_rects[i].x2;
889 dest_rects[i].x2 = src_rects[i].y2;
890 dest_rects[i].y2 = width - src_rects[i].x1;
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500891 break;
892 case WL_OUTPUT_TRANSFORM_180:
893 dest_rects[i].x1 = width - src_rects[i].x2;
894 dest_rects[i].y1 = height - src_rects[i].y2;
895 dest_rects[i].x2 = width - src_rects[i].x1;
896 dest_rects[i].y2 = height - src_rects[i].y1;
897 break;
898 case WL_OUTPUT_TRANSFORM_270:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200899 dest_rects[i].x1 = height - src_rects[i].y2;
900 dest_rects[i].y1 = src_rects[i].x1;
901 dest_rects[i].x2 = height - src_rects[i].y1;
902 dest_rects[i].y2 = src_rects[i].x2;
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500903 break;
904 case WL_OUTPUT_TRANSFORM_FLIPPED:
905 dest_rects[i].x1 = width - src_rects[i].x2;
906 dest_rects[i].y1 = src_rects[i].y1;
907 dest_rects[i].x2 = width - src_rects[i].x1;
908 dest_rects[i].y2 = src_rects[i].y2;
909 break;
910 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200911 dest_rects[i].x1 = src_rects[i].y1;
912 dest_rects[i].y1 = src_rects[i].x1;
913 dest_rects[i].x2 = src_rects[i].y2;
914 dest_rects[i].y2 = src_rects[i].x2;
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500915 break;
916 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
917 dest_rects[i].x1 = src_rects[i].x1;
918 dest_rects[i].y1 = height - src_rects[i].y2;
919 dest_rects[i].x2 = src_rects[i].x2;
920 dest_rects[i].y2 = height - src_rects[i].y1;
921 break;
922 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
Pekka Paalanen8060d822020-02-06 15:27:54 +0200923 dest_rects[i].x1 = height - src_rects[i].y2;
924 dest_rects[i].y1 = width - src_rects[i].x2;
925 dest_rects[i].x2 = height - src_rects[i].y1;
926 dest_rects[i].y2 = width - src_rects[i].x1;
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500927 break;
928 }
929 }
930 }
931
932 if (scale != 1) {
933 for (i = 0; i < nrects; i++) {
934 dest_rects[i].x1 *= scale;
935 dest_rects[i].x2 *= scale;
936 dest_rects[i].y1 *= scale;
937 dest_rects[i].y2 *= scale;
938 }
939 }
940
941 pixman_region32_clear(dest);
942 pixman_region32_init_rects(dest, dest_rects, nrects);
943 free(dest_rects);
944}
945
Jonny Lamb74130762013-11-26 18:19:46 +0100946static void
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +0300947viewport_surface_to_buffer(struct weston_surface *surface,
948 float sx, float sy, float *bx, float *by)
Jonny Lamb74130762013-11-26 18:19:46 +0100949{
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200950 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200951 double src_width, src_height;
952 double src_x, src_y;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200953
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200954 if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
955 if (vp->surface.width == -1) {
956 *bx = sx;
957 *by = sy;
958 return;
959 }
Jonny Lamb74130762013-11-26 18:19:46 +0100960
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200961 src_x = 0.0;
962 src_y = 0.0;
963 src_width = surface->width_from_buffer;
964 src_height = surface->height_from_buffer;
Jonny Lamb74130762013-11-26 18:19:46 +0100965 } else {
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200966 src_x = wl_fixed_to_double(vp->buffer.src_x);
967 src_y = wl_fixed_to_double(vp->buffer.src_y);
968 src_width = wl_fixed_to_double(vp->buffer.src_width);
969 src_height = wl_fixed_to_double(vp->buffer.src_height);
Jonny Lamb74130762013-11-26 18:19:46 +0100970 }
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200971
972 *bx = sx * src_width / surface->width + src_x;
973 *by = sy * src_height / surface->height + src_y;
Jonny Lamb74130762013-11-26 18:19:46 +0100974}
975
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500976WL_EXPORT void
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200977weston_surface_to_buffer_float(struct weston_surface *surface,
978 float sx, float sy, float *bx, float *by)
979{
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200980 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
981
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +0300982 /* first transform coordinates if the viewport is set */
983 viewport_surface_to_buffer(surface, sx, sy, bx, by);
Jonny Lamb74130762013-11-26 18:19:46 +0100984
Jason Ekstrandd0cebc32014-04-21 20:56:46 -0500985 weston_transformed_coord(surface->width_from_buffer,
986 surface->height_from_buffer,
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200987 vp->buffer.transform, vp->buffer.scale,
Jonny Lamb74130762013-11-26 18:19:46 +0100988 *bx, *by, bx, by);
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200989}
990
Derek Foreman99739672015-12-03 16:38:11 -0600991/** Transform a rectangle from surface coordinates to buffer coordinates
992 *
Pekka Paalanene95ad5c2016-04-15 14:47:08 +0300993 * \param surface The surface to fetch wp_viewport and buffer transformation
Derek Foreman99739672015-12-03 16:38:11 -0600994 * from.
995 * \param rect The rectangle to transform.
996 * \return The transformed rectangle.
997 *
998 * Viewport and buffer transformations can only do translation, scaling,
999 * and rotations in 90-degree steps. Therefore the only loss in the
1000 * conversion is coordinate rounding.
1001 *
1002 * However, some coordinate rounding takes place as an intermediate
1003 * step before the buffer scale factor is applied, so the rectangle
1004 * boundary may not be exactly as expected.
1005 *
1006 * This is OK for damage tracking since a little extra coverage is
1007 * not a problem.
1008 */
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +02001009WL_EXPORT pixman_box32_t
1010weston_surface_to_buffer_rect(struct weston_surface *surface,
1011 pixman_box32_t rect)
1012{
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001013 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Jonny Lamb74130762013-11-26 18:19:46 +01001014 float xf, yf;
1015
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03001016 /* first transform box coordinates if the viewport is set */
1017 viewport_surface_to_buffer(surface, rect.x1, rect.y1, &xf, &yf);
Jonny Lamb74130762013-11-26 18:19:46 +01001018 rect.x1 = floorf(xf);
1019 rect.y1 = floorf(yf);
1020
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03001021 viewport_surface_to_buffer(surface, rect.x2, rect.y2, &xf, &yf);
Derek Foremane2e15ac2015-12-01 13:00:43 -06001022 rect.x2 = ceilf(xf);
1023 rect.y2 = ceilf(yf);
Jonny Lamb74130762013-11-26 18:19:46 +01001024
Jason Ekstrandd0cebc32014-04-21 20:56:46 -05001025 return weston_transformed_rect(surface->width_from_buffer,
1026 surface->height_from_buffer,
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001027 vp->buffer.transform, vp->buffer.scale,
Alexander Larsson4ea95522013-05-22 14:41:37 +02001028 rect);
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +02001029}
1030
Pekka Paalanene54e31c2015-03-04 14:23:28 +02001031/** Transform a region from surface coordinates to buffer coordinates
1032 *
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03001033 * \param surface The surface to fetch wp_viewport and buffer transformation
Pekka Paalanene54e31c2015-03-04 14:23:28 +02001034 * from.
Marius Vlada2dace22019-06-12 16:05:44 +03001035 * \param[in] surface_region The region in surface coordinates.
1036 * \param[out] buffer_region The region converted to buffer coordinates.
Pekka Paalanene54e31c2015-03-04 14:23:28 +02001037 *
1038 * Buffer_region must be init'd, but will be completely overwritten.
1039 *
1040 * Viewport and buffer transformations can only do translation, scaling,
1041 * and rotations in 90-degree steps. Therefore the only loss in the
Derek Foreman99739672015-12-03 16:38:11 -06001042 * conversion is from the coordinate rounding that takes place in
1043 * \ref weston_surface_to_buffer_rect.
Marius Vlada2dace22019-06-12 16:05:44 +03001044 *
Pekka Paalanene54e31c2015-03-04 14:23:28 +02001045 */
1046WL_EXPORT void
1047weston_surface_to_buffer_region(struct weston_surface *surface,
1048 pixman_region32_t *surface_region,
1049 pixman_region32_t *buffer_region)
1050{
1051 pixman_box32_t *src_rects, *dest_rects;
1052 int nrects, i;
1053
1054 src_rects = pixman_region32_rectangles(surface_region, &nrects);
1055 dest_rects = malloc(nrects * sizeof(*dest_rects));
1056 if (!dest_rects)
1057 return;
1058
1059 for (i = 0; i < nrects; i++) {
1060 dest_rects[i] = weston_surface_to_buffer_rect(surface,
1061 src_rects[i]);
1062 }
1063
1064 pixman_region32_fini(buffer_region);
1065 pixman_region32_init_rects(buffer_region, dest_rects, nrects);
1066 free(dest_rects);
1067}
1068
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +02001069WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001070weston_view_move_to_plane(struct weston_view *view,
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001071 struct weston_plane *plane)
1072{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001073 if (view->plane == plane)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001074 return;
1075
Jason Ekstranda7af7042013-10-12 22:38:11 -05001076 weston_view_damage_below(view);
1077 view->plane = plane;
1078 weston_surface_damage(view->surface);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001079}
1080
Pekka Paalanen51723d52015-02-17 13:10:01 +02001081/** Inflict damage on the plane where the view is visible.
1082 *
1083 * \param view The view that causes the damage.
1084 *
1085 * If the view is currently on a plane (including the primary plane),
1086 * take the view's boundingbox, subtract all the opaque views that cover it,
1087 * and add the remaining region as damage to the plane. This corresponds
1088 * to the damage inflicted to the plane if this view disappeared.
1089 *
1090 * A repaint is scheduled for this view.
1091 *
1092 * The region of all opaque views covering this view is stored in
1093 * weston_view::clip and updated by view_accumulate_damage() during
1094 * weston_output_repaint(). Specifically, that region matches the
1095 * scenegraph as it was last painted.
1096 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001097WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001098weston_view_damage_below(struct weston_view *view)
Pekka Paalanen9abf3932012-02-08 14:49:37 +02001099{
Kristian Høgsberg1e832122012-02-28 22:47:14 -05001100 pixman_region32_t damage;
Pekka Paalanen9abf3932012-02-08 14:49:37 +02001101
Kristian Høgsberg1e832122012-02-28 22:47:14 -05001102 pixman_region32_init(&damage);
Pekka Paalanen25c0ca52015-02-19 11:15:33 +02001103 pixman_region32_subtract(&damage, &view->transform.boundingbox,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001104 &view->clip);
Xiong Zhang97116532013-10-23 13:58:31 +08001105 if (view->plane)
1106 pixman_region32_union(&view->plane->damage,
1107 &view->plane->damage, &damage);
Kristian Høgsberg1e832122012-02-28 22:47:14 -05001108 pixman_region32_fini(&damage);
Kristian Høgsberga3a784a2013-11-13 21:33:43 -08001109 weston_view_schedule_repaint(view);
Pekka Paalanen9abf3932012-02-08 14:49:37 +02001110}
1111
Pekka Paalanen01e00682017-03-24 16:21:06 +02001112/** Send wl_surface.enter/leave events
1113 *
1114 * \param surface The surface.
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03001115 * \param head A head of the entered/left output.
Pekka Paalanen01e00682017-03-24 16:21:06 +02001116 * \param enter True if entered.
Marius Vlada2dace22019-06-12 16:05:44 +03001117 * \param leave True if left.
Pekka Paalanen01e00682017-03-24 16:21:06 +02001118 *
1119 * Send the enter/leave events for all protocol objects bound to the given
1120 * output by the client owning the surface.
1121 */
1122static void
1123weston_surface_send_enter_leave(struct weston_surface *surface,
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03001124 struct weston_head *head,
Pekka Paalanen01e00682017-03-24 16:21:06 +02001125 bool enter,
1126 bool leave)
1127{
1128 struct wl_resource *wloutput;
1129 struct wl_client *client;
1130
1131 assert(enter != leave);
1132
1133 client = wl_resource_get_client(surface->resource);
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03001134 wl_resource_for_each(wloutput, &head->resource_list) {
Pekka Paalanen01e00682017-03-24 16:21:06 +02001135 if (wl_resource_get_client(wloutput) != client)
1136 continue;
1137
1138 if (enter)
1139 wl_surface_send_enter(surface->resource, wloutput);
1140 if (leave)
1141 wl_surface_send_leave(surface->resource, wloutput);
1142 }
1143}
1144
Ankit Nautiyalf74c35b2019-04-03 19:21:58 +05301145static void
1146weston_surface_compute_protection(struct protected_surface *psurface)
1147{
1148 enum weston_hdcp_protection min_protection;
1149 bool min_protection_valid = false;
1150 struct weston_surface *surface = psurface->surface;
1151 struct weston_output *output;
1152
1153 wl_list_for_each(output, &surface->compositor->output_list, link)
1154 if (surface->output_mask & (1u << output->id)) {
Ankit Nautiyal4fd38132019-07-08 15:12:19 +05301155 /*
1156 * If the content-protection is enabled with protection
1157 * mode as RELAXED for a surface, and if
1158 * content-recording features like: screen-shooter,
1159 * recorder, screen-sharing, etc are on, then notify the
1160 * client, that the protection is disabled.
1161 *
1162 * Note: If the protection mode is ENFORCED then there
1163 * is no need to bother the client as the renderer takes
1164 * care of censoring the visibility of the protected
1165 * content.
1166 */
1167
1168 if (output->disable_planes > 0 &&
1169 surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_RELAXED) {
1170 min_protection = WESTON_HDCP_DISABLE;
1171 min_protection_valid = true;
1172 break;
1173 }
Ankit Nautiyalf74c35b2019-04-03 19:21:58 +05301174 if (!min_protection_valid) {
1175 min_protection = output->current_protection;
1176 min_protection_valid = true;
1177 }
1178 if (output->current_protection < min_protection)
1179 min_protection = output->current_protection;
1180 }
1181 if (!min_protection_valid)
1182 min_protection = WESTON_HDCP_DISABLE;
1183
1184 surface->current_protection = min_protection;
Ankit Nautiyal4fd38132019-07-08 15:12:19 +05301185
1186 weston_protected_surface_send_event(psurface, surface->current_protection);
Ankit Nautiyalf74c35b2019-04-03 19:21:58 +05301187}
1188
1189static void
1190notify_surface_protection_change(void *data)
1191{
1192 struct weston_compositor *compositor = data;
1193 struct content_protection *cp;
1194 struct protected_surface *psurface;
1195
1196 cp = compositor->content_protection;
1197 cp->surface_protection_update = NULL;
1198
1199 /* Notify the clients, whose surfaces are changed */
1200 wl_list_for_each(psurface, &cp->protected_list, link)
1201 if (psurface && psurface->surface)
1202 weston_surface_compute_protection(psurface);
1203}
1204
Bryce Harrington3f650b82015-12-23 11:01:58 -08001205/**
Ankit Nautiyalfaa5ab42019-07-08 13:23:24 +05301206 * \param compositor weston_compositor
1207 *
1208 * Schedule an idle task to notify surface about the update in protection,
1209 * if not already scheduled.
1210 */
1211static void
1212weston_schedule_surface_protection_update(struct weston_compositor *compositor)
1213{
1214 struct content_protection *cp = compositor->content_protection;
1215 struct wl_event_loop *loop;
1216
1217 if (!cp || cp->surface_protection_update)
1218 return;
1219 loop = wl_display_get_event_loop(compositor->wl_display);
1220 cp->surface_protection_update = wl_event_loop_add_idle(loop,
1221 notify_surface_protection_change,
1222 compositor);
1223}
1224
1225/**
Bryce Harrington3f650b82015-12-23 11:01:58 -08001226 * \param es The surface
1227 * \param mask The new set of outputs for the surface
1228 *
1229 * Sets the surface's set of outputs to the ones specified by
1230 * the new output mask provided. Identifies the outputs that
1231 * have changed, the posts enter and leave events for these
1232 * outputs as appropriate.
1233 */
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001234static void
1235weston_surface_update_output_mask(struct weston_surface *es, uint32_t mask)
1236{
1237 uint32_t different = es->output_mask ^ mask;
1238 uint32_t entered = mask & different;
1239 uint32_t left = es->output_mask & different;
Pekka Paalanen01e00682017-03-24 16:21:06 +02001240 uint32_t output_bit;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001241 struct weston_output *output;
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03001242 struct weston_head *head;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001243
1244 es->output_mask = mask;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001245 if (es->resource == NULL)
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001246 return;
1247 if (different == 0)
1248 return;
1249
1250 wl_list_for_each(output, &es->compositor->output_list, link) {
Pekka Paalanen01e00682017-03-24 16:21:06 +02001251 output_bit = 1u << output->id;
1252 if (!(output_bit & different))
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001253 continue;
Pekka Paalanen01e00682017-03-24 16:21:06 +02001254
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03001255 wl_list_for_each(head, &output->head_list, output_link) {
1256 weston_surface_send_enter_leave(es, head,
1257 output_bit & entered,
1258 output_bit & left);
1259 }
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001260 }
Ankit Nautiyalf74c35b2019-04-03 19:21:58 +05301261 /*
1262 * Change in surfaces' output mask might trigger a change in its
1263 * protection.
1264 */
Ankit Nautiyalfaa5ab42019-07-08 13:23:24 +05301265 weston_schedule_surface_protection_update(es->compositor);
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001266}
1267
Semi Malinene7a52fb2018-04-26 11:08:10 +02001268static void
1269notify_view_output_destroy(struct wl_listener *listener, void *data)
1270{
1271 struct weston_view *view =
1272 container_of(listener,
1273 struct weston_view, output_destroy_listener);
1274
1275 view->output = NULL;
1276 view->output_destroy_listener.notify = NULL;
1277}
1278
1279/** Set the primary output of the view
1280 *
1281 * \param view The view whose primary output to set
1282 * \param output The new primary output for the view
1283 *
1284 * Set \a output to be the primary output of the \a view.
1285 *
1286 * Notice that the assignment may be temporary; the primary output could be
1287 * automatically changed. Hence, one cannot rely on the value persisting.
1288 *
1289 * Passing NULL as /a output will set the primary output to NULL.
1290 */
1291WL_EXPORT void
1292weston_view_set_output(struct weston_view *view, struct weston_output *output)
1293{
1294 if (view->output_destroy_listener.notify) {
1295 wl_list_remove(&view->output_destroy_listener.link);
1296 view->output_destroy_listener.notify = NULL;
1297 }
1298 view->output = output;
1299 if (output) {
1300 view->output_destroy_listener.notify =
1301 notify_view_output_destroy;
1302 wl_signal_add(&output->destroy_signal,
1303 &view->output_destroy_listener);
1304 }
1305}
1306
Bryce Harrington3f650b82015-12-23 11:01:58 -08001307/** Recalculate which output(s) the surface has views displayed on
1308 *
1309 * \param es The surface to remap to outputs
1310 *
1311 * Finds the output that is showing the largest amount of one
1312 * of the surface's various views. This output becomes the
Pekka Paalanen130ae6e2016-03-30 14:33:33 +03001313 * surface's primary output for vsync and frame callback purposes.
Bryce Harrington3f650b82015-12-23 11:01:58 -08001314 *
Pekka Paalanen130ae6e2016-03-30 14:33:33 +03001315 * Also notes all outputs of all of the surface's views
Bryce Harrington3f650b82015-12-23 11:01:58 -08001316 * in the output_mask for the surface.
1317 */
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001318static void
1319weston_surface_assign_output(struct weston_surface *es)
1320{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001321 struct weston_output *new_output;
1322 struct weston_view *view;
1323 pixman_region32_t region;
1324 uint32_t max, area, mask;
1325 pixman_box32_t *e;
1326
1327 new_output = NULL;
1328 max = 0;
1329 mask = 0;
1330 pixman_region32_init(&region);
1331 wl_list_for_each(view, &es->views, surface_link) {
1332 if (!view->output)
1333 continue;
1334
1335 pixman_region32_intersect(&region, &view->transform.boundingbox,
1336 &view->output->region);
1337
1338 e = pixman_region32_extents(&region);
1339 area = (e->x2 - e->x1) * (e->y2 - e->y1);
1340
1341 mask |= view->output_mask;
1342
1343 if (area >= max) {
1344 new_output = view->output;
1345 max = area;
1346 }
1347 }
1348 pixman_region32_fini(&region);
1349
1350 es->output = new_output;
1351 weston_surface_update_output_mask(es, mask);
1352}
1353
Bryce Harrington3f650b82015-12-23 11:01:58 -08001354/** Recalculate which output(s) the view is displayed on
1355 *
1356 * \param ev The view to remap to outputs
1357 *
1358 * Identifies the set of outputs that the view is visible on,
1359 * noting them into the output_mask. The output that the view
Pekka Paalanen130ae6e2016-03-30 14:33:33 +03001360 * is most visible on is set as the view's primary output.
Bryce Harrington3f650b82015-12-23 11:01:58 -08001361 *
1362 * Also does the same for the view's surface. See
1363 * weston_surface_assign_output().
1364 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001365static void
1366weston_view_assign_output(struct weston_view *ev)
1367{
1368 struct weston_compositor *ec = ev->surface->compositor;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001369 struct weston_output *output, *new_output;
1370 pixman_region32_t region;
1371 uint32_t max, area, mask;
1372 pixman_box32_t *e;
1373
1374 new_output = NULL;
1375 max = 0;
1376 mask = 0;
1377 pixman_region32_init(&region);
1378 wl_list_for_each(output, &ec->output_list, link) {
Giulio Camuffo2f2a70c2015-07-12 10:52:32 +03001379 if (output->destroying)
1380 continue;
1381
Jason Ekstranda7af7042013-10-12 22:38:11 -05001382 pixman_region32_intersect(&region, &ev->transform.boundingbox,
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001383 &output->region);
1384
1385 e = pixman_region32_extents(&region);
1386 area = (e->x2 - e->x1) * (e->y2 - e->y1);
1387
1388 if (area > 0)
Bryce Harrington89324ce2015-12-23 18:38:07 -08001389 mask |= 1u << output->id;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001390
1391 if (area >= max) {
1392 new_output = output;
1393 max = area;
1394 }
1395 }
1396 pixman_region32_fini(&region);
1397
Semi Malinene7a52fb2018-04-26 11:08:10 +02001398 weston_view_set_output(ev, new_output);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001399 ev->output_mask = mask;
1400
1401 weston_surface_assign_output(ev->surface);
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001402}
1403
Pekka Paalanen9abf3932012-02-08 14:49:37 +02001404static void
Pekka Paalanen380adf52015-02-16 14:39:11 +02001405weston_view_to_view_map(struct weston_view *from, struct weston_view *to,
1406 int from_x, int from_y, int *to_x, int *to_y)
1407{
1408 float x, y;
1409
1410 weston_view_to_global_float(from, from_x, from_y, &x, &y);
1411 weston_view_from_global_float(to, x, y, &x, &y);
1412
1413 *to_x = round(x);
1414 *to_y = round(y);
1415}
1416
1417static void
1418weston_view_transfer_scissor(struct weston_view *from, struct weston_view *to)
1419{
1420 pixman_box32_t *a;
1421 pixman_box32_t b;
1422
1423 a = pixman_region32_extents(&from->geometry.scissor);
1424
1425 weston_view_to_view_map(from, to, a->x1, a->y1, &b.x1, &b.y1);
1426 weston_view_to_view_map(from, to, a->x2, a->y2, &b.x2, &b.y2);
1427
1428 pixman_region32_fini(&to->geometry.scissor);
1429 pixman_region32_init_with_extents(&to->geometry.scissor, &b);
1430}
1431
1432static void
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02001433view_compute_bbox(struct weston_view *view, const pixman_box32_t *inbox,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001434 pixman_region32_t *bbox)
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001435{
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001436 float min_x = HUGE_VALF, min_y = HUGE_VALF;
1437 float max_x = -HUGE_VALF, max_y = -HUGE_VALF;
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001438 int32_t s[4][2] = {
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02001439 { inbox->x1, inbox->y1 },
1440 { inbox->x1, inbox->y2 },
1441 { inbox->x2, inbox->y1 },
1442 { inbox->x2, inbox->y2 },
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001443 };
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001444 float int_x, int_y;
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001445 int i;
1446
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02001447 if (inbox->x1 == inbox->x2 || inbox->y1 == inbox->y2) {
Pekka Paalanen7c7d4642012-09-04 13:55:44 +03001448 /* avoid rounding empty bbox to 1x1 */
1449 pixman_region32_init(bbox);
1450 return;
1451 }
1452
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001453 for (i = 0; i < 4; ++i) {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001454 float x, y;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001455 weston_view_to_global_float(view, s[i][0], s[i][1], &x, &y);
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001456 if (x < min_x)
1457 min_x = x;
1458 if (x > max_x)
1459 max_x = x;
1460 if (y < min_y)
1461 min_y = y;
1462 if (y > max_y)
1463 max_y = y;
1464 }
1465
Pekka Paalanen219b9822012-02-08 15:38:37 +02001466 int_x = floorf(min_x);
1467 int_y = floorf(min_y);
1468 pixman_region32_init_rect(bbox, int_x, int_y,
1469 ceilf(max_x) - int_x, ceilf(max_y) - int_y);
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001470}
1471
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001472static void
Michael Olbrichcb04f982020-06-08 10:22:32 +02001473weston_view_update_transform_scissor(struct weston_view *view,
1474 pixman_region32_t *region)
1475{
1476 struct weston_view *parent = view->geometry.parent;
1477
1478 if (parent) {
1479 if (parent->geometry.scissor_enabled) {
1480 view->geometry.scissor_enabled = true;
1481 weston_view_transfer_scissor(parent, view);
1482 } else {
1483 view->geometry.scissor_enabled = false;
1484 }
1485 }
1486
1487 if (view->geometry.scissor_enabled)
1488 pixman_region32_intersect(region, region,
1489 &view->geometry.scissor);
1490}
1491static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001492weston_view_update_transform_disable(struct weston_view *view)
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001493{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001494 view->transform.enabled = 0;
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001495
Pekka Paalanencc2f8682012-02-13 10:34:04 +02001496 /* round off fractions when not transformed */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001497 view->geometry.x = roundf(view->geometry.x);
1498 view->geometry.y = roundf(view->geometry.y);
Pekka Paalanencc2f8682012-02-13 10:34:04 +02001499
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001500 /* Otherwise identity matrix, but with x and y translation. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001501 view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
1502 view->transform.position.matrix.d[12] = view->geometry.x;
1503 view->transform.position.matrix.d[13] = view->geometry.y;
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001504
Jason Ekstranda7af7042013-10-12 22:38:11 -05001505 view->transform.matrix = view->transform.position.matrix;
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001506
Jason Ekstranda7af7042013-10-12 22:38:11 -05001507 view->transform.inverse = view->transform.position.matrix;
1508 view->transform.inverse.d[12] = -view->geometry.x;
1509 view->transform.inverse.d[13] = -view->geometry.y;
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001510
Jason Ekstranda7af7042013-10-12 22:38:11 -05001511 pixman_region32_init_rect(&view->transform.boundingbox,
Pekka Paalanen380adf52015-02-16 14:39:11 +02001512 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001513 view->surface->width,
1514 view->surface->height);
Michael Olbrichcb04f982020-06-08 10:22:32 +02001515
1516 weston_view_update_transform_scissor(view, &view->transform.boundingbox);
Pekka Paalanen380adf52015-02-16 14:39:11 +02001517
1518 pixman_region32_translate(&view->transform.boundingbox,
1519 view->geometry.x, view->geometry.y);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001520
Jason Ekstranda7af7042013-10-12 22:38:11 -05001521 if (view->alpha == 1.0) {
1522 pixman_region32_copy(&view->transform.opaque,
1523 &view->surface->opaque);
Michael Olbrich0e4f0972020-08-19 11:31:03 +02001524 pixman_region32_intersect(&view->transform.opaque,
1525 &view->transform.opaque,
1526 &view->geometry.scissor);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001527 pixman_region32_translate(&view->transform.opaque,
1528 view->geometry.x,
1529 view->geometry.y);
Kristian Høgsberg3b4af202012-02-28 09:19:39 -05001530 }
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001531}
1532
1533static int
Jason Ekstranda7af7042013-10-12 22:38:11 -05001534weston_view_update_transform_enable(struct weston_view *view)
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001535{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001536 struct weston_view *parent = view->geometry.parent;
1537 struct weston_matrix *matrix = &view->transform.matrix;
1538 struct weston_matrix *inverse = &view->transform.inverse;
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001539 struct weston_transform *tform;
Pekka Paalanen380adf52015-02-16 14:39:11 +02001540 pixman_region32_t surfregion;
1541 const pixman_box32_t *surfbox;
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001542
Jason Ekstranda7af7042013-10-12 22:38:11 -05001543 view->transform.enabled = 1;
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001544
1545 /* Otherwise identity matrix, but with x and y translation. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001546 view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
1547 view->transform.position.matrix.d[12] = view->geometry.x;
1548 view->transform.position.matrix.d[13] = view->geometry.y;
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001549
1550 weston_matrix_init(matrix);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001551 wl_list_for_each(tform, &view->geometry.transformation_list, link)
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001552 weston_matrix_multiply(matrix, &tform->matrix);
1553
Pekka Paalanen483243f2013-03-08 14:56:50 +02001554 if (parent)
1555 weston_matrix_multiply(matrix, &parent->transform.matrix);
1556
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001557 if (weston_matrix_invert(inverse, matrix) < 0) {
1558 /* Oops, bad total transformation, not invertible */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001559 weston_log("error: weston_view %p"
1560 " transformation not invertible.\n", view);
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001561 return -1;
1562 }
1563
Pekka Paalanen380adf52015-02-16 14:39:11 +02001564 pixman_region32_init_rect(&surfregion, 0, 0,
1565 view->surface->width, view->surface->height);
Michael Olbrichcb04f982020-06-08 10:22:32 +02001566
1567 weston_view_update_transform_scissor(view, &surfregion);
1568
Pekka Paalanen380adf52015-02-16 14:39:11 +02001569 surfbox = pixman_region32_extents(&surfregion);
1570
1571 view_compute_bbox(view, surfbox, &view->transform.boundingbox);
1572 pixman_region32_fini(&surfregion);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001573
Michael Olbrich0e4f0972020-08-19 11:31:03 +02001574 if (view->alpha == 1.0 &&
1575 matrix->type == WESTON_MATRIX_TRANSFORM_TRANSLATE) {
1576 pixman_region32_copy(&view->transform.opaque,
1577 &view->surface->opaque);
1578 pixman_region32_intersect(&view->transform.opaque,
1579 &view->transform.opaque,
1580 &view->geometry.scissor);
1581 pixman_region32_translate(&view->transform.opaque,
1582 matrix->d[12],
1583 matrix->d[13]);
1584 }
1585
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001586 return 0;
1587}
1588
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001589static struct weston_layer *
1590get_view_layer(struct weston_view *view)
1591{
1592 if (view->parent_view)
1593 return get_view_layer(view->parent_view);
1594 return view->layer_link.layer;
1595}
1596
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001597WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001598weston_view_update_transform(struct weston_view *view)
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001599{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001600 struct weston_view *parent = view->geometry.parent;
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001601 struct weston_layer *layer;
1602 pixman_region32_t mask;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001603
Jason Ekstranda7af7042013-10-12 22:38:11 -05001604 if (!view->transform.dirty)
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001605 return;
1606
Pekka Paalanen483243f2013-03-08 14:56:50 +02001607 if (parent)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001608 weston_view_update_transform(parent);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001609
Jason Ekstranda7af7042013-10-12 22:38:11 -05001610 view->transform.dirty = 0;
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001611
Jason Ekstranda7af7042013-10-12 22:38:11 -05001612 weston_view_damage_below(view);
Pekka Paalanen96516782012-02-09 15:32:15 +02001613
Jason Ekstranda7af7042013-10-12 22:38:11 -05001614 pixman_region32_fini(&view->transform.boundingbox);
1615 pixman_region32_fini(&view->transform.opaque);
1616 pixman_region32_init(&view->transform.opaque);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001617
Pekka Paalanencd403622012-01-25 13:37:39 +02001618 /* transform.position is always in transformation_list */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001619 if (view->geometry.transformation_list.next ==
1620 &view->transform.position.link &&
1621 view->geometry.transformation_list.prev ==
1622 &view->transform.position.link &&
Pekka Paalanen483243f2013-03-08 14:56:50 +02001623 !parent) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001624 weston_view_update_transform_disable(view);
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001625 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001626 if (weston_view_update_transform_enable(view) < 0)
1627 weston_view_update_transform_disable(view);
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001628 }
Pekka Paalanen96516782012-02-09 15:32:15 +02001629
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001630 layer = get_view_layer(view);
1631 if (layer) {
1632 pixman_region32_init_with_extents(&mask, &layer->mask);
Pekka Paalanen25c0ca52015-02-19 11:15:33 +02001633 pixman_region32_intersect(&view->transform.boundingbox,
1634 &view->transform.boundingbox, &mask);
Pekka Paalanen8844bf22015-02-18 16:30:47 +02001635 pixman_region32_intersect(&view->transform.opaque,
1636 &view->transform.opaque, &mask);
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001637 pixman_region32_fini(&mask);
1638 }
1639
Jason Ekstranda7af7042013-10-12 22:38:11 -05001640 weston_view_damage_below(view);
Pekka Paalanen96516782012-02-09 15:32:15 +02001641
Jason Ekstranda7af7042013-10-12 22:38:11 -05001642 weston_view_assign_output(view);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03001643
Jason Ekstranda7af7042013-10-12 22:38:11 -05001644 wl_signal_emit(&view->surface->compositor->transform_signal,
1645 view->surface);
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001646}
1647
Pekka Paalanenddae03c2012-02-06 14:54:20 +02001648WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001649weston_view_geometry_dirty(struct weston_view *view)
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02001650{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001651 struct weston_view *child;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001652
1653 /*
Jason Ekstranda7af7042013-10-12 22:38:11 -05001654 * The invariant: if view->geometry.dirty, then all views
1655 * in view->geometry.child_list have geometry.dirty too.
Pekka Paalanen483243f2013-03-08 14:56:50 +02001656 * Corollary: if not parent->geometry.dirty, then all ancestors
1657 * are not dirty.
1658 */
1659
Jason Ekstranda7af7042013-10-12 22:38:11 -05001660 if (view->transform.dirty)
Pekka Paalanen483243f2013-03-08 14:56:50 +02001661 return;
1662
Jason Ekstranda7af7042013-10-12 22:38:11 -05001663 view->transform.dirty = 1;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001664
Jason Ekstranda7af7042013-10-12 22:38:11 -05001665 wl_list_for_each(child, &view->geometry.child_list,
Pekka Paalanen483243f2013-03-08 14:56:50 +02001666 geometry.parent_link)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001667 weston_view_geometry_dirty(child);
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02001668}
1669
1670WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001671weston_view_to_global_fixed(struct weston_view *view,
1672 wl_fixed_t vx, wl_fixed_t vy,
1673 wl_fixed_t *x, wl_fixed_t *y)
Daniel Stonebd3489b2012-05-08 17:17:53 +01001674{
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001675 float xf, yf;
Daniel Stonebd3489b2012-05-08 17:17:53 +01001676
Jason Ekstranda7af7042013-10-12 22:38:11 -05001677 weston_view_to_global_float(view,
1678 wl_fixed_to_double(vx),
1679 wl_fixed_to_double(vy),
1680 &xf, &yf);
Daniel Stonebd3489b2012-05-08 17:17:53 +01001681 *x = wl_fixed_from_double(xf);
1682 *y = wl_fixed_from_double(yf);
1683}
1684
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -04001685WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001686weston_view_from_global_float(struct weston_view *view,
1687 float x, float y, float *vx, float *vy)
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001688{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001689 if (view->transform.enabled) {
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001690 struct weston_vector v = { { x, y, 0.0f, 1.0f } };
1691
Jason Ekstranda7af7042013-10-12 22:38:11 -05001692 weston_matrix_transform(&view->transform.inverse, &v);
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001693
1694 if (fabsf(v.f[3]) < 1e-6) {
Martin Minarik6d118362012-06-07 18:01:59 +02001695 weston_log("warning: numerical instability in "
Jason Ekstranda7af7042013-10-12 22:38:11 -05001696 "weston_view_from_global(), divisor = %g\n",
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001697 v.f[3]);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001698 *vx = 0;
1699 *vy = 0;
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001700 return;
1701 }
1702
Jason Ekstranda7af7042013-10-12 22:38:11 -05001703 *vx = v.f[0] / v.f[3];
1704 *vy = v.f[1] / v.f[3];
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001705 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001706 *vx = x - view->geometry.x;
1707 *vy = y - view->geometry.y;
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001708 }
1709}
1710
1711WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001712weston_view_from_global_fixed(struct weston_view *view,
1713 wl_fixed_t x, wl_fixed_t y,
1714 wl_fixed_t *vx, wl_fixed_t *vy)
Daniel Stonebd3489b2012-05-08 17:17:53 +01001715{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001716 float vxf, vyf;
Daniel Stonebd3489b2012-05-08 17:17:53 +01001717
Jason Ekstranda7af7042013-10-12 22:38:11 -05001718 weston_view_from_global_float(view,
1719 wl_fixed_to_double(x),
1720 wl_fixed_to_double(y),
1721 &vxf, &vyf);
1722 *vx = wl_fixed_from_double(vxf);
1723 *vy = wl_fixed_from_double(vyf);
Daniel Stonebd3489b2012-05-08 17:17:53 +01001724}
1725
1726WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001727weston_view_from_global(struct weston_view *view,
1728 int32_t x, int32_t y, int32_t *vx, int32_t *vy)
Pekka Paalanen0e151bb2012-01-24 14:47:37 +02001729{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001730 float vxf, vyf;
Pekka Paalanen0e151bb2012-01-24 14:47:37 +02001731
Jason Ekstranda7af7042013-10-12 22:38:11 -05001732 weston_view_from_global_float(view, x, y, &vxf, &vyf);
1733 *vx = floorf(vxf);
1734 *vy = floorf(vyf);
Pekka Paalanen0e151bb2012-01-24 14:47:37 +02001735}
1736
Bryce Harrington3f650b82015-12-23 11:01:58 -08001737/**
1738 * \param surface The surface to be repainted
1739 *
1740 * Marks the output(s) that the surface is shown on as needing to be
1741 * repainted. See weston_output_schedule_repaint().
1742 */
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001743WL_EXPORT void
Kristian Høgsberg98238702012-08-03 16:29:12 -04001744weston_surface_schedule_repaint(struct weston_surface *surface)
1745{
1746 struct weston_output *output;
1747
1748 wl_list_for_each(output, &surface->compositor->output_list, link)
Bryce Harrington89324ce2015-12-23 18:38:07 -08001749 if (surface->output_mask & (1u << output->id))
Kristian Høgsberg98238702012-08-03 16:29:12 -04001750 weston_output_schedule_repaint(output);
1751}
1752
Bryce Harrington3f650b82015-12-23 11:01:58 -08001753/**
1754 * \param view The view to be repainted
1755 *
1756 * Marks the output(s) that the view is shown on as needing to be
1757 * repainted. See weston_output_schedule_repaint().
1758 */
Kristian Høgsberg98238702012-08-03 16:29:12 -04001759WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001760weston_view_schedule_repaint(struct weston_view *view)
1761{
1762 struct weston_output *output;
1763
1764 wl_list_for_each(output, &view->surface->compositor->output_list, link)
Bryce Harrington89324ce2015-12-23 18:38:07 -08001765 if (view->output_mask & (1u << output->id))
Jason Ekstranda7af7042013-10-12 22:38:11 -05001766 weston_output_schedule_repaint(output);
1767}
1768
Pekka Paalanene508ce62015-02-19 13:59:55 +02001769/**
1770 * XXX: This function does it the wrong way.
1771 * surface->damage is the damage from the client, and causes
1772 * surface_flush_damage() to copy pixels. No window management action can
1773 * cause damage to the client-provided content, warranting re-upload!
1774 *
1775 * Instead of surface->damage, this function should record the damage
1776 * with all the views for this surface to avoid extraneous texture
1777 * uploads.
1778 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001779WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001780weston_surface_damage(struct weston_surface *surface)
Kristian Høgsberg31bd6c72011-02-13 13:00:51 -05001781{
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04001782 pixman_region32_union_rect(&surface->damage, &surface->damage,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001783 0, 0, surface->width,
1784 surface->height);
Pekka Paalanen2267d452012-01-26 13:12:45 +02001785
Kristian Høgsberg98238702012-08-03 16:29:12 -04001786 weston_surface_schedule_repaint(surface);
Kristian Høgsberg31bd6c72011-02-13 13:00:51 -05001787}
1788
Kristian Høgsberga691aee2011-06-23 21:43:50 -04001789WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001790weston_view_set_position(struct weston_view *view, float x, float y)
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001791{
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001792 if (view->geometry.x == x && view->geometry.y == y)
1793 return;
1794
Jason Ekstranda7af7042013-10-12 22:38:11 -05001795 view->geometry.x = x;
1796 view->geometry.y = y;
1797 weston_view_geometry_dirty(view);
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001798}
1799
Pekka Paalanen483243f2013-03-08 14:56:50 +02001800static void
1801transform_parent_handle_parent_destroy(struct wl_listener *listener,
1802 void *data)
1803{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001804 struct weston_view *view =
1805 container_of(listener, struct weston_view,
Pekka Paalanen483243f2013-03-08 14:56:50 +02001806 geometry.parent_destroy_listener);
1807
Jason Ekstranda7af7042013-10-12 22:38:11 -05001808 weston_view_set_transform_parent(view, NULL);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001809}
1810
1811WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001812weston_view_set_transform_parent(struct weston_view *view,
Pekka Paalanen380adf52015-02-16 14:39:11 +02001813 struct weston_view *parent)
Pekka Paalanen483243f2013-03-08 14:56:50 +02001814{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001815 if (view->geometry.parent) {
1816 wl_list_remove(&view->geometry.parent_destroy_listener.link);
1817 wl_list_remove(&view->geometry.parent_link);
Pekka Paalanen380adf52015-02-16 14:39:11 +02001818
1819 if (!parent)
1820 view->geometry.scissor_enabled = false;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001821 }
1822
Jason Ekstranda7af7042013-10-12 22:38:11 -05001823 view->geometry.parent = parent;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001824
Jason Ekstranda7af7042013-10-12 22:38:11 -05001825 view->geometry.parent_destroy_listener.notify =
Pekka Paalanen483243f2013-03-08 14:56:50 +02001826 transform_parent_handle_parent_destroy;
1827 if (parent) {
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001828 wl_signal_add(&parent->destroy_signal,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001829 &view->geometry.parent_destroy_listener);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001830 wl_list_insert(&parent->geometry.child_list,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001831 &view->geometry.parent_link);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001832 }
1833
Jason Ekstranda7af7042013-10-12 22:38:11 -05001834 weston_view_geometry_dirty(view);
1835}
1836
Pekka Paalanen380adf52015-02-16 14:39:11 +02001837/** Set a clip mask rectangle on a view
1838 *
1839 * \param view The view to set the clip mask on.
1840 * \param x Top-left corner X coordinate of the clip rectangle.
1841 * \param y Top-left corner Y coordinate of the clip rectangle.
1842 * \param width Width of the clip rectangle, non-negative.
1843 * \param height Height of the clip rectangle, non-negative.
1844 *
1845 * A shell may set a clip mask rectangle on a view. Everything outside
1846 * the rectangle is cut away for input and output purposes: it is
1847 * not drawn and cannot be hit by hit-test based input like pointer
1848 * motion or touch-downs. Everything inside the rectangle will behave
1849 * normally. Clients are unaware of clipping.
1850 *
Yong Bakos4c72e292016-04-28 11:59:10 -05001851 * The rectangle is set in surface-local coordinates. Setting a clip
Pekka Paalanen380adf52015-02-16 14:39:11 +02001852 * mask rectangle does not affect the view position, the view is positioned
1853 * as it would be without a clip. The clip also does not change
1854 * weston_surface::width,height.
1855 *
1856 * The clip mask rectangle is part of transformation inheritance
1857 * (weston_view_set_transform_parent()). A clip set in the root of the
1858 * transformation inheritance tree will affect all views in the tree.
1859 * A clip can be set only on the root view. Attempting to set a clip
1860 * on view that has a transformation parent will fail. Assigning a parent
1861 * to a view that has a clip set will cause the clip to be forgotten.
1862 *
1863 * Because the clip mask is an axis-aligned rectangle, it poses restrictions
1864 * on the additional transformations in the child views. These transformations
1865 * may not rotate the coordinate axes, i.e., only translation and scaling
1866 * are allowed. Violating this restriction causes the clipping to malfunction.
1867 * Furthermore, using scaling may cause rounding errors in child clipping.
1868 *
1869 * The clip mask rectangle is not automatically adjusted based on
1870 * wl_surface.attach dx and dy arguments.
1871 *
1872 * A clip mask rectangle can be set only if the compositor capability
1873 * WESTON_CAP_VIEW_CLIP_MASK is present.
1874 *
1875 * This function sets the clip mask rectangle and schedules a repaint for
1876 * the view.
1877 */
1878WL_EXPORT void
1879weston_view_set_mask(struct weston_view *view,
1880 int x, int y, int width, int height)
1881{
1882 struct weston_compositor *compositor = view->surface->compositor;
1883
1884 if (!(compositor->capabilities & WESTON_CAP_VIEW_CLIP_MASK)) {
1885 weston_log("%s not allowed without capability!\n", __func__);
1886 return;
1887 }
1888
1889 if (view->geometry.parent) {
1890 weston_log("view %p has a parent, clip forbidden!\n", view);
1891 return;
1892 }
1893
1894 if (width < 0 || height < 0) {
1895 weston_log("%s: illegal args %d, %d, %d, %d\n", __func__,
1896 x, y, width, height);
1897 return;
1898 }
1899
1900 pixman_region32_fini(&view->geometry.scissor);
1901 pixman_region32_init_rect(&view->geometry.scissor, x, y, width, height);
1902 view->geometry.scissor_enabled = true;
1903 weston_view_geometry_dirty(view);
1904 weston_view_schedule_repaint(view);
1905}
1906
1907/** Remove the clip mask from a view
1908 *
1909 * \param view The view to remove the clip mask from.
1910 *
1911 * Removed the clip mask rectangle and schedules a repaint.
1912 *
1913 * \sa weston_view_set_mask
1914 */
1915WL_EXPORT void
1916weston_view_set_mask_infinite(struct weston_view *view)
1917{
1918 view->geometry.scissor_enabled = false;
1919 weston_view_geometry_dirty(view);
1920 weston_view_schedule_repaint(view);
1921}
1922
Armin Krezović0da12b82016-06-30 06:04:33 +02001923/* Check if view should be displayed
1924 *
1925 * The indicator is set manually when assigning
1926 * a view to a surface.
1927 *
1928 * This needs reworking. See the thread starting at:
1929 *
1930 * https://lists.freedesktop.org/archives/wayland-devel/2016-June/029656.html
1931 */
Derek Foreman280e7dd2014-10-03 13:13:42 -05001932WL_EXPORT bool
Jason Ekstranda7af7042013-10-12 22:38:11 -05001933weston_view_is_mapped(struct weston_view *view)
1934{
Armin Krezović0da12b82016-06-30 06:04:33 +02001935 return view->is_mapped;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001936}
1937
Philipp Zabel70decd52018-09-03 20:11:15 +02001938/* Check if view is opaque in specified region
1939 *
1940 * \param view The view to check for opacity.
1941 * \param region The region to check for opacity, in view coordinates.
1942 *
1943 * Returns true if the view is opaque in the specified region, because view
1944 * alpha is 1.0 and either the opaque region set by the client contains the
1945 * specified region, or the buffer pixel format or solid color is opaque.
1946 */
1947WL_EXPORT bool
1948weston_view_is_opaque(struct weston_view *ev, pixman_region32_t *region)
1949{
1950 pixman_region32_t r;
1951 bool ret = false;
1952
1953 if (ev->alpha < 1.0)
1954 return false;
1955
1956 if (ev->surface->is_opaque)
1957 return true;
1958
Marius Vlad67b382c2020-08-21 13:57:54 +03001959 if (ev->transform.dirty)
Philipp Zabel70decd52018-09-03 20:11:15 +02001960 return false;
Philipp Zabel70decd52018-09-03 20:11:15 +02001961
1962 pixman_region32_init(&r);
1963 pixman_region32_subtract(&r, region, &ev->transform.opaque);
1964
1965 if (!pixman_region32_not_empty(&r))
1966 ret = true;
1967
1968 pixman_region32_fini(&r);
1969
1970 return ret;
1971}
1972
Marius Vlad5f6bee42019-09-11 16:41:04 +03001973/** Check if the view has a valid buffer available
1974 *
1975 * @param ev The view to check if it has a valid buffer.
1976 *
1977 * Returns true if the view has a valid buffer or false otherwise.
1978 */
1979WL_EXPORT bool
1980weston_view_has_valid_buffer(struct weston_view *ev)
1981{
1982 return ev->surface->buffer_ref.buffer != NULL;
1983}
1984
Marius Vlad47e3d1e2019-09-11 16:53:08 +03001985/** Check if the view matches the entire output
1986 *
1987 * @param ev The view to check.
1988 * @param output The output to check against.
1989 *
1990 * Returns true if the view does indeed matches the entire output.
1991 */
1992WL_EXPORT bool
1993weston_view_matches_output_entirely(struct weston_view *ev,
1994 struct weston_output *output)
1995{
1996 pixman_box32_t *extents =
1997 pixman_region32_extents(&ev->transform.boundingbox);
1998
1999 if (extents->x1 != output->x ||
2000 extents->y1 != output->y ||
2001 extents->x2 != output->x + output->width ||
2002 extents->y2 != output->y + output->height)
2003 return false;
2004
2005 return true;
2006}
2007
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002008/** Find paint node for the given view and output
2009 */
2010WL_EXPORT struct weston_paint_node *
2011weston_view_find_paint_node(struct weston_view *view,
2012 struct weston_output *output)
2013{
2014 struct weston_paint_node *pnode;
2015
2016 wl_list_for_each(pnode, &view->paint_node_list, view_link) {
2017 assert(pnode->surface == view->surface);
2018 if (pnode->output == output)
2019 return pnode;
2020 }
2021
2022 return NULL;
2023}
2024
Armin Krezović0da12b82016-06-30 06:04:33 +02002025/* Check if a surface has a view assigned to it
2026 *
2027 * The indicator is set manually when mapping
2028 * a surface and creating a view for it.
2029 *
2030 * This needs to go. See the thread starting at:
2031 *
2032 * https://lists.freedesktop.org/archives/wayland-devel/2016-June/029656.html
2033 *
2034 */
Derek Foreman280e7dd2014-10-03 13:13:42 -05002035WL_EXPORT bool
Ander Conselvan de Oliveirab8ab14f2012-03-27 17:36:36 +03002036weston_surface_is_mapped(struct weston_surface *surface)
2037{
Armin Krezović0da12b82016-06-30 06:04:33 +02002038 return surface->is_mapped;
Ander Conselvan de Oliveirab8ab14f2012-03-27 17:36:36 +03002039}
2040
Pekka Paalanenda75ee12013-11-26 18:19:43 +01002041static void
Jason Ekstrand5c11a332013-12-04 20:32:03 -06002042surface_set_size(struct weston_surface *surface, int32_t width, int32_t height)
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002043{
2044 struct weston_view *view;
2045
2046 if (surface->width == width && surface->height == height)
2047 return;
2048
2049 surface->width = width;
2050 surface->height = height;
2051
2052 wl_list_for_each(view, &surface->views, surface_link)
2053 weston_view_geometry_dirty(view);
2054}
2055
Jason Ekstrand5c11a332013-12-04 20:32:03 -06002056WL_EXPORT void
2057weston_surface_set_size(struct weston_surface *surface,
2058 int32_t width, int32_t height)
2059{
2060 assert(!surface->resource);
2061 surface_set_size(surface, width, height);
2062}
2063
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02002064static int
2065fixed_round_up_to_int(wl_fixed_t f)
2066{
2067 return wl_fixed_to_int(wl_fixed_from_int(1) - 1 + f);
2068}
2069
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002070static void
Pekka Paalanen59987fa2016-04-26 15:50:59 +03002071convert_size_by_transform_scale(int32_t *width_out, int32_t *height_out,
2072 int32_t width, int32_t height,
2073 uint32_t transform,
2074 int32_t scale)
2075{
2076 assert(scale > 0);
2077
2078 switch (transform) {
2079 case WL_OUTPUT_TRANSFORM_NORMAL:
2080 case WL_OUTPUT_TRANSFORM_180:
2081 case WL_OUTPUT_TRANSFORM_FLIPPED:
2082 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
2083 *width_out = width / scale;
2084 *height_out = height / scale;
2085 break;
2086 case WL_OUTPUT_TRANSFORM_90:
2087 case WL_OUTPUT_TRANSFORM_270:
2088 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
2089 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
2090 *width_out = height / scale;
2091 *height_out = width / scale;
2092 break;
2093 default:
2094 assert(0 && "invalid transform");
2095 }
2096}
2097
2098static void
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002099weston_surface_calculate_size_from_buffer(struct weston_surface *surface)
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02002100{
Pekka Paalanen952b6c82014-03-14 14:38:15 +02002101 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Pekka Paalanenda75ee12013-11-26 18:19:43 +01002102
2103 if (!surface->buffer_ref.buffer) {
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02002104 surface->width_from_buffer = 0;
2105 surface->height_from_buffer = 0;
Jonny Lamb74130762013-11-26 18:19:46 +01002106 return;
2107 }
2108
Pekka Paalanen59987fa2016-04-26 15:50:59 +03002109 convert_size_by_transform_scale(&surface->width_from_buffer,
2110 &surface->height_from_buffer,
2111 surface->buffer_ref.buffer->width,
2112 surface->buffer_ref.buffer->height,
2113 vp->buffer.transform,
2114 vp->buffer.scale);
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002115}
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02002116
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002117static void
2118weston_surface_update_size(struct weston_surface *surface)
2119{
2120 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
2121 int32_t width, height;
2122
2123 width = surface->width_from_buffer;
2124 height = surface->height_from_buffer;
2125
2126 if (width != 0 && vp->surface.width != -1) {
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02002127 surface_set_size(surface,
2128 vp->surface.width, vp->surface.height);
2129 return;
2130 }
2131
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002132 if (width != 0 && vp->buffer.src_width != wl_fixed_from_int(-1)) {
Pekka Paalanene9317212014-04-04 14:22:13 +03002133 int32_t w = fixed_round_up_to_int(vp->buffer.src_width);
2134 int32_t h = fixed_round_up_to_int(vp->buffer.src_height);
2135
2136 surface_set_size(surface, w ?: 1, h ?: 1);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02002137 return;
2138 }
2139
Jason Ekstrand5c11a332013-12-04 20:32:03 -06002140 surface_set_size(surface, width, height);
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02002141}
2142
Marius Vlad9fdda7f2019-06-11 16:08:55 +03002143/** weston_compositor_get_time
2144 * \ingroup compositor
2145 */
Alexandros Frantzis409b01f2017-11-16 18:21:01 +02002146WL_EXPORT void
2147weston_compositor_get_time(struct timespec *time)
Kristian Høgsberg7132a9a2010-12-06 21:41:10 -05002148{
Alexandros Frantzis409b01f2017-11-16 18:21:01 +02002149 clock_gettime(CLOCK_REALTIME, time);
Kristian Høgsberg7132a9a2010-12-06 21:41:10 -05002150}
2151
Marius Vlad9fdda7f2019-06-11 16:08:55 +03002152/** weston_compositor_pick_view
2153 * \ingroup compositor
2154 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05002155WL_EXPORT struct weston_view *
2156weston_compositor_pick_view(struct weston_compositor *compositor,
2157 wl_fixed_t x, wl_fixed_t y,
2158 wl_fixed_t *vx, wl_fixed_t *vy)
Tiago Vignatti9d393522012-02-10 16:26:19 +02002159{
Jason Ekstranda7af7042013-10-12 22:38:11 -05002160 struct weston_view *view;
Pekka Paalanenfc22a522015-02-18 15:08:29 +02002161 wl_fixed_t view_x, view_y;
2162 int view_ix, view_iy;
2163 int ix = wl_fixed_to_int(x);
2164 int iy = wl_fixed_to_int(y);
Tiago Vignatti9d393522012-02-10 16:26:19 +02002165
Pekka Paalanen6551c092021-05-03 16:09:45 +03002166 /* Can't use paint node list: occlusion by input regions, not opaque. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05002167 wl_list_for_each(view, &compositor->view_list, link) {
Pekka Paalanenfc22a522015-02-18 15:08:29 +02002168 if (!pixman_region32_contains_point(
2169 &view->transform.boundingbox, ix, iy, NULL))
2170 continue;
2171
2172 weston_view_from_global_fixed(view, x, y, &view_x, &view_y);
2173 view_ix = wl_fixed_to_int(view_x);
2174 view_iy = wl_fixed_to_int(view_y);
2175
2176 if (!pixman_region32_contains_point(&view->surface->input,
2177 view_ix, view_iy, NULL))
2178 continue;
2179
Pekka Paalanen380adf52015-02-16 14:39:11 +02002180 if (view->geometry.scissor_enabled &&
2181 !pixman_region32_contains_point(&view->geometry.scissor,
2182 view_ix, view_iy, NULL))
2183 continue;
2184
Pekka Paalanenfc22a522015-02-18 15:08:29 +02002185 *vx = view_x;
2186 *vy = view_y;
2187 return view;
Tiago Vignatti9d393522012-02-10 16:26:19 +02002188 }
2189
Derek Foremanf9318d12015-05-11 15:40:11 -05002190 *vx = wl_fixed_from_int(-1000000);
2191 *vy = wl_fixed_from_int(-1000000);
Tiago Vignatti9d393522012-02-10 16:26:19 +02002192 return NULL;
2193}
2194
2195static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002196weston_compositor_repick(struct weston_compositor *compositor)
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04002197{
Daniel Stone37816df2012-05-16 18:45:18 +01002198 struct weston_seat *seat;
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04002199
Kristian Høgsberg10ddd972013-10-22 12:40:54 -07002200 if (!compositor->session_active)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002201 return;
2202
Daniel Stone37816df2012-05-16 18:45:18 +01002203 wl_list_for_each(seat, &compositor->seat_list, link)
Kristian Høgsberga71e8b22013-05-06 21:51:21 -04002204 weston_seat_repick(seat);
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04002205}
2206
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002207WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002208weston_view_unmap(struct weston_view *view)
Kristian Høgsberg3b5ea3b2012-02-17 12:43:56 -05002209{
Daniel Stone4dab5db2012-05-30 16:31:53 +01002210 struct weston_seat *seat;
Kristian Høgsberg867dec72012-03-01 17:09:37 -05002211
Jason Ekstranda7af7042013-10-12 22:38:11 -05002212 if (!weston_view_is_mapped(view))
2213 return;
Kristian Høgsberg867dec72012-03-01 17:09:37 -05002214
Jason Ekstranda7af7042013-10-12 22:38:11 -05002215 weston_view_damage_below(view);
Semi Malinene7a52fb2018-04-26 11:08:10 +02002216 weston_view_set_output(view, NULL);
Xiong Zhang97116532013-10-23 13:58:31 +08002217 view->plane = NULL;
Armin Krezovićf8486c32016-06-30 06:04:28 +02002218 view->is_mapped = false;
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002219 weston_layer_entry_remove(&view->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002220 wl_list_remove(&view->link);
2221 wl_list_init(&view->link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002222 view->output_mask = 0;
2223 weston_surface_assign_output(view->surface);
2224
2225 if (weston_surface_is_mapped(view->surface))
2226 return;
2227
2228 wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -05002229 struct weston_touch *touch = weston_seat_get_touch(seat);
2230 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
2231 struct weston_keyboard *keyboard =
2232 weston_seat_get_keyboard(seat);
2233
2234 if (keyboard && keyboard->focus == view->surface)
2235 weston_keyboard_set_focus(keyboard, NULL);
2236 if (pointer && pointer->focus == view)
Derek Foremanf9318d12015-05-11 15:40:11 -05002237 weston_pointer_clear_focus(pointer);
Derek Foreman1281a362015-07-31 16:55:32 -05002238 if (touch && touch->focus == view)
2239 weston_touch_set_focus(touch, NULL);
Daniel Stone4dab5db2012-05-30 16:31:53 +01002240 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002241}
Kristian Høgsberg867dec72012-03-01 17:09:37 -05002242
Jason Ekstranda7af7042013-10-12 22:38:11 -05002243WL_EXPORT void
2244weston_surface_unmap(struct weston_surface *surface)
2245{
2246 struct weston_view *view;
2247
Armin Krezovićf8486c32016-06-30 06:04:28 +02002248 surface->is_mapped = false;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002249 wl_list_for_each(view, &surface->views, surface_link)
2250 weston_view_unmap(view);
2251 surface->output = NULL;
Kristian Høgsberg3b5ea3b2012-02-17 12:43:56 -05002252}
2253
Pekka Paalanen3c9b8022014-03-14 14:38:13 +02002254static void
2255weston_surface_reset_pending_buffer(struct weston_surface *surface)
2256{
Jason Ekstrand7b982072014-05-20 14:33:03 -05002257 weston_surface_state_set_buffer(&surface->pending, NULL);
Pekka Paalanen3c9b8022014-03-14 14:38:13 +02002258 surface->pending.sx = 0;
2259 surface->pending.sy = 0;
2260 surface->pending.newly_attached = 0;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002261 surface->pending.buffer_viewport.changed = 0;
Pekka Paalanen3c9b8022014-03-14 14:38:13 +02002262}
2263
Jason Ekstranda7af7042013-10-12 22:38:11 -05002264WL_EXPORT void
2265weston_view_destroy(struct weston_view *view)
2266{
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002267 struct weston_paint_node *pnode, *pntmp;
2268
Jason Ekstranda7af7042013-10-12 22:38:11 -05002269 wl_signal_emit(&view->destroy_signal, view);
2270
2271 assert(wl_list_empty(&view->geometry.child_list));
2272
2273 if (weston_view_is_mapped(view)) {
2274 weston_view_unmap(view);
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002275 weston_compositor_build_view_list(view->surface->compositor,
2276 NULL);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002277 }
2278
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002279 wl_list_for_each_safe(pnode, pntmp, &view->paint_node_list, view_link)
2280 weston_paint_node_destroy(pnode);
2281
Jason Ekstranda7af7042013-10-12 22:38:11 -05002282 wl_list_remove(&view->link);
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002283 weston_layer_entry_remove(&view->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002284
2285 pixman_region32_fini(&view->clip);
Pekka Paalanen380adf52015-02-16 14:39:11 +02002286 pixman_region32_fini(&view->geometry.scissor);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002287 pixman_region32_fini(&view->transform.boundingbox);
Pekka Paalanen8844bf22015-02-18 16:30:47 +02002288 pixman_region32_fini(&view->transform.opaque);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002289
2290 weston_view_set_transform_parent(view, NULL);
Pekka Paalanen944fae82018-05-22 13:15:58 +03002291 weston_view_set_output(view, NULL);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002292
Jason Ekstranda7af7042013-10-12 22:38:11 -05002293 wl_list_remove(&view->surface_link);
2294
2295 free(view);
2296}
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05002297
2298WL_EXPORT void
2299weston_surface_destroy(struct weston_surface *surface)
Kristian Høgsberg54879822008-11-23 17:07:32 -05002300{
Vlad Zahorodniic2b97472021-07-29 11:16:51 +03002301 struct wl_resource *cb, *next;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002302 struct weston_view *ev, *nv;
Jonas Ådahld3414f22016-07-22 17:56:31 +08002303 struct weston_pointer_constraint *constraint, *next_constraint;
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002304 struct weston_paint_node *pnode, *pntmp;
Kristian Høgsberg4fa48732009-03-10 23:17:00 -04002305
Giulio Camuffo13b85bd2013-08-13 23:10:14 +02002306 if (--surface->ref_count > 0)
2307 return;
2308
Pekka Paalanen08d3fb72015-04-17 14:00:24 +03002309 assert(surface->resource == NULL);
2310
Pekka Paalanenca790762015-04-17 14:23:38 +03002311 wl_signal_emit(&surface->destroy_signal, surface);
Giulio Camuffo13b85bd2013-08-13 23:10:14 +02002312
Pekka Paalanene67858b2013-04-25 13:57:42 +03002313 assert(wl_list_empty(&surface->subsurface_list_pending));
2314 assert(wl_list_empty(&surface->subsurface_list));
Pekka Paalanen483243f2013-03-08 14:56:50 +02002315
Jason Ekstranda7af7042013-10-12 22:38:11 -05002316 wl_list_for_each_safe(ev, nv, &surface->views, surface_link)
2317 weston_view_destroy(ev);
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04002318
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002319 wl_list_for_each_safe(pnode, pntmp,
2320 &surface->paint_node_list, surface_link) {
2321 weston_paint_node_destroy(pnode);
2322 }
2323
Jason Ekstrand7b982072014-05-20 14:33:03 -05002324 weston_surface_state_fini(&surface->pending);
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002325
Pekka Paalanende685b82012-12-04 15:58:12 +02002326 weston_buffer_reference(&surface->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +03002327 weston_buffer_release_reference(&surface->buffer_release_ref, NULL);
Kristian Høgsberg3f8f39c2009-09-18 17:05:13 -04002328
Pekka Paalanen402ae6d2012-01-03 10:23:24 +02002329 pixman_region32_fini(&surface->damage);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002330 pixman_region32_fini(&surface->opaque);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03002331 pixman_region32_fini(&surface->input);
Pekka Paalanen402ae6d2012-01-03 10:23:24 +02002332
Vlad Zahorodniic2b97472021-07-29 11:16:51 +03002333 wl_resource_for_each_safe(cb, next, &surface->frame_callback_list)
2334 wl_resource_destroy(cb);
Kristian Høgsberg1e51fec2012-07-22 11:33:14 -04002335
Pekka Paalanen133e4392014-09-23 22:08:46 -04002336 weston_presentation_feedback_discard_list(&surface->feedback_list);
2337
Jonas Ådahld3414f22016-07-22 17:56:31 +08002338 wl_list_for_each_safe(constraint, next_constraint,
2339 &surface->pointer_constraints,
2340 link)
2341 weston_pointer_constraint_destroy(constraint);
2342
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002343 fd_clear(&surface->acquire_fence_fd);
2344
Kristian Høgsberg4fa48732009-03-10 23:17:00 -04002345 free(surface);
Kristian Høgsberg54879822008-11-23 17:07:32 -05002346}
2347
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05002348static void
2349destroy_surface(struct wl_resource *resource)
Alex Wu8811bf92012-02-28 18:07:54 +08002350{
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05002351 struct weston_surface *surface = wl_resource_get_user_data(resource);
Alex Wu8811bf92012-02-28 18:07:54 +08002352
Pekka Paalanen08d3fb72015-04-17 14:00:24 +03002353 assert(surface);
2354
Giulio Camuffo0d379742013-11-15 22:06:15 +01002355 /* Set the resource to NULL, since we don't want to leave a
2356 * dangling pointer if the surface was refcounted and survives
2357 * the weston_surface_destroy() call. */
2358 surface->resource = NULL;
Pekka Paalanen4826f872016-04-22 14:14:38 +03002359
2360 if (surface->viewport_resource)
2361 wl_resource_set_user_data(surface->viewport_resource, NULL);
2362
Alexandros Frantzis27d7c392018-10-19 12:14:11 +03002363 if (surface->synchronization_resource) {
2364 wl_resource_set_user_data(surface->synchronization_resource,
2365 NULL);
2366 }
2367
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05002368 weston_surface_destroy(surface);
Alex Wu8811bf92012-02-28 18:07:54 +08002369}
2370
Benjamin Franzkefaa0a9d2011-02-21 16:24:53 +01002371static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002372weston_buffer_destroy_handler(struct wl_listener *listener, void *data)
2373{
2374 struct weston_buffer *buffer =
2375 container_of(listener, struct weston_buffer, destroy_listener);
2376
2377 wl_signal_emit(&buffer->destroy_signal, buffer);
2378 free(buffer);
2379}
2380
Giulio Camuffoe058cd12013-12-12 14:14:29 +01002381WL_EXPORT struct weston_buffer *
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002382weston_buffer_from_resource(struct wl_resource *resource)
2383{
2384 struct weston_buffer *buffer;
2385 struct wl_listener *listener;
U. Artie Eoff2e2384a2014-01-17 13:19:01 -08002386
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002387 listener = wl_resource_get_destroy_listener(resource,
2388 weston_buffer_destroy_handler);
2389
Kristian Høgsberg08b58c72013-08-15 12:26:42 -07002390 if (listener)
2391 return container_of(listener, struct weston_buffer,
2392 destroy_listener);
2393
2394 buffer = zalloc(sizeof *buffer);
2395 if (buffer == NULL)
2396 return NULL;
2397
2398 buffer->resource = resource;
2399 wl_signal_init(&buffer->destroy_signal);
2400 buffer->destroy_listener.notify = weston_buffer_destroy_handler;
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +04002401 buffer->y_inverted = 1;
Kristian Høgsberg08b58c72013-08-15 12:26:42 -07002402 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
U. Artie Eoff2e2384a2014-01-17 13:19:01 -08002403
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002404 return buffer;
2405}
2406
2407static void
Pekka Paalanende685b82012-12-04 15:58:12 +02002408weston_buffer_reference_handle_destroy(struct wl_listener *listener,
2409 void *data)
Benjamin Franzkefaa0a9d2011-02-21 16:24:53 +01002410{
Pekka Paalanende685b82012-12-04 15:58:12 +02002411 struct weston_buffer_reference *ref =
2412 container_of(listener, struct weston_buffer_reference,
2413 destroy_listener);
2414
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002415 assert((struct weston_buffer *)data == ref->buffer);
Pekka Paalanende685b82012-12-04 15:58:12 +02002416 ref->buffer = NULL;
2417}
2418
2419WL_EXPORT void
2420weston_buffer_reference(struct weston_buffer_reference *ref,
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002421 struct weston_buffer *buffer)
Pekka Paalanende685b82012-12-04 15:58:12 +02002422{
2423 if (ref->buffer && buffer != ref->buffer) {
Kristian Høgsberg20347802013-03-04 12:07:46 -05002424 ref->buffer->busy_count--;
2425 if (ref->buffer->busy_count == 0) {
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002426 assert(wl_resource_get_client(ref->buffer->resource));
Matt Hoosier3052bc72017-09-26 08:09:40 -05002427 wl_buffer_send_release(ref->buffer->resource);
Kristian Høgsberg20347802013-03-04 12:07:46 -05002428 }
Pekka Paalanende685b82012-12-04 15:58:12 +02002429 wl_list_remove(&ref->destroy_listener.link);
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002430 }
2431
Pekka Paalanende685b82012-12-04 15:58:12 +02002432 if (buffer && buffer != ref->buffer) {
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04002433 buffer->busy_count++;
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002434 wl_signal_add(&buffer->destroy_signal,
Pekka Paalanende685b82012-12-04 15:58:12 +02002435 &ref->destroy_listener);
Pekka Paalanena6421c42012-12-04 15:58:10 +02002436 }
2437
Pekka Paalanende685b82012-12-04 15:58:12 +02002438 ref->buffer = buffer;
2439 ref->destroy_listener.notify = weston_buffer_reference_handle_destroy;
2440}
2441
2442static void
Alexandros Frantzis67629672018-10-19 12:14:11 +03002443weston_buffer_release_reference_handle_destroy(struct wl_listener *listener,
2444 void *data)
2445{
2446 struct weston_buffer_release_reference *ref =
2447 container_of(listener, struct weston_buffer_release_reference,
2448 destroy_listener);
2449
2450 assert((struct wl_resource *)data == ref->buffer_release->resource);
2451 ref->buffer_release = NULL;
2452}
2453
2454static void
2455weston_buffer_release_destroy(struct weston_buffer_release *buffer_release)
2456{
2457 struct wl_resource *resource = buffer_release->resource;
2458 int release_fence_fd = buffer_release->fence_fd;
2459
2460 if (release_fence_fd >= 0) {
2461 zwp_linux_buffer_release_v1_send_fenced_release(
2462 resource, release_fence_fd);
2463 } else {
2464 zwp_linux_buffer_release_v1_send_immediate_release(
2465 resource);
2466 }
2467
2468 wl_resource_destroy(resource);
2469}
2470
2471WL_EXPORT void
2472weston_buffer_release_reference(struct weston_buffer_release_reference *ref,
2473 struct weston_buffer_release *buffer_release)
2474{
2475 if (buffer_release == ref->buffer_release)
2476 return;
2477
2478 if (ref->buffer_release) {
2479 ref->buffer_release->ref_count--;
2480 wl_list_remove(&ref->destroy_listener.link);
2481 if (ref->buffer_release->ref_count == 0)
2482 weston_buffer_release_destroy(ref->buffer_release);
2483 }
2484
2485 if (buffer_release) {
2486 buffer_release->ref_count++;
2487 wl_resource_add_destroy_listener(buffer_release->resource,
2488 &ref->destroy_listener);
2489 }
2490
2491 ref->buffer_release = buffer_release;
2492 ref->destroy_listener.notify =
2493 weston_buffer_release_reference_handle_destroy;
2494}
2495
2496WL_EXPORT void
2497weston_buffer_release_move(struct weston_buffer_release_reference *dest,
2498 struct weston_buffer_release_reference *src)
2499{
2500 weston_buffer_release_reference(dest, src->buffer_release);
2501 weston_buffer_release_reference(src, NULL);
2502}
2503
2504static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002505weston_surface_attach(struct weston_surface *surface,
2506 struct weston_buffer *buffer)
Pekka Paalanende685b82012-12-04 15:58:12 +02002507{
2508 weston_buffer_reference(&surface->buffer_ref, buffer);
2509
Pekka Paalanena6421c42012-12-04 15:58:10 +02002510 if (!buffer) {
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002511 if (weston_surface_is_mapped(surface))
2512 weston_surface_unmap(surface);
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002513 }
2514
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002515 surface->compositor->renderer->attach(surface, buffer);
Pekka Paalanenbb2f3f22014-03-14 14:38:11 +02002516
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002517 weston_surface_calculate_size_from_buffer(surface);
Pekka Paalanen133e4392014-09-23 22:08:46 -04002518 weston_presentation_feedback_discard_list(&surface->feedback_list);
Benjamin Franzkefaa0a9d2011-02-21 16:24:53 +01002519}
2520
Marius Vlad9fdda7f2019-06-11 16:08:55 +03002521/** weston_compositor_damage_all
2522 * \ingroup compositor
2523 */
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002524WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002525weston_compositor_damage_all(struct weston_compositor *compositor)
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002526{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002527 struct weston_output *output;
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002528
2529 wl_list_for_each(output, &compositor->output_list, link)
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002530 weston_output_damage(output);
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002531}
2532
Marius Vlad55d87362019-06-11 01:15:35 +03002533/**
2534 * \ingroup output
2535 */
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05002536WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002537weston_output_damage(struct weston_output *output)
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002538{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002539 struct weston_compositor *compositor = output->compositor;
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002540
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002541 pixman_region32_union(&compositor->primary_plane.damage,
2542 &compositor->primary_plane.damage,
2543 &output->region);
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002544 weston_output_schedule_repaint(output);
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002545}
2546
Kristian Høgsberg01f941b2009-05-27 17:47:15 -04002547static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002548surface_flush_damage(struct weston_surface *surface)
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002549{
Pekka Paalanende685b82012-12-04 15:58:12 +02002550 if (surface->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002551 wl_shm_buffer_get(surface->buffer_ref.buffer->resource))
Kristian Høgsbergfa1be022012-09-05 22:49:55 -04002552 surface->compositor->renderer->flush_damage(surface);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002553
Marius Vlad2a1b7862019-09-05 13:12:18 +03002554 if (pixman_region32_not_empty(&surface->damage))
Marius Vlad3203ff62019-09-05 14:56:12 +03002555 TL_POINT(surface->compositor, "core_flush_damage", TLP_SURFACE(surface),
Pekka Paalanenb5026542014-11-12 15:09:24 +02002556 TLP_OUTPUT(surface->output), TLP_END);
2557
Jason Ekstrandef540082014-06-26 10:37:36 -07002558 pixman_region32_clear(&surface->damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002559}
2560
2561static void
2562view_accumulate_damage(struct weston_view *view,
2563 pixman_region32_t *opaque)
2564{
2565 pixman_region32_t damage;
2566
2567 pixman_region32_init(&damage);
2568 if (view->transform.enabled) {
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002569 pixman_box32_t *extents;
2570
Jason Ekstranda7af7042013-10-12 22:38:11 -05002571 extents = pixman_region32_extents(&view->surface->damage);
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02002572 view_compute_bbox(view, extents, &damage);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002573 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002574 pixman_region32_copy(&damage, &view->surface->damage);
2575 pixman_region32_translate(&damage,
Pekka Paalanen502f5e02015-02-23 14:08:25 +02002576 view->geometry.x, view->geometry.y);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002577 }
2578
Pekka Paalanen380adf52015-02-16 14:39:11 +02002579 pixman_region32_intersect(&damage, &damage,
2580 &view->transform.boundingbox);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002581 pixman_region32_subtract(&damage, &damage, opaque);
2582 pixman_region32_union(&view->plane->damage,
2583 &view->plane->damage, &damage);
2584 pixman_region32_fini(&damage);
2585 pixman_region32_copy(&view->clip, opaque);
Pekka Paalanen8844bf22015-02-18 16:30:47 +02002586 pixman_region32_union(opaque, opaque, &view->transform.opaque);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002587}
2588
Kristian Høgsbergcce1aec2011-04-22 15:38:14 -04002589static void
Michael Olbrichc5ea4952020-08-11 12:42:35 +02002590output_accumulate_damage(struct weston_output *output)
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002591{
Michael Olbrichc5ea4952020-08-11 12:42:35 +02002592 struct weston_compositor *ec = output->compositor;
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002593 struct weston_plane *plane;
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002594 struct weston_paint_node *pnode;
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002595 pixman_region32_t opaque, clip;
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002596
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002597 pixman_region32_init(&clip);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002598
2599 wl_list_for_each(plane, &ec->plane_list, link) {
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002600 pixman_region32_copy(&plane->clip, &clip);
2601
2602 pixman_region32_init(&opaque);
2603
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002604 wl_list_for_each(pnode, &output->paint_node_z_order_list,
2605 z_order_link) {
2606 if (pnode->view->plane != plane)
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002607 continue;
2608
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002609 view_accumulate_damage(pnode->view, &opaque);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002610 }
2611
2612 pixman_region32_union(&clip, &clip, &opaque);
2613 pixman_region32_fini(&opaque);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002614 }
2615
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002616 pixman_region32_fini(&clip);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002617
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002618 wl_list_for_each(pnode, &output->paint_node_z_order_list,
2619 z_order_link) {
2620 pnode->surface->touched = false;
2621 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002622
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002623 wl_list_for_each(pnode, &output->paint_node_z_order_list,
2624 z_order_link) {
Michael Olbrichc5ea4952020-08-11 12:42:35 +02002625 /* Ignore views not visible on the current output */
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002626 /* TODO: turn this into assert once z_order_list is pruned. */
2627 if (!(pnode->view->output_mask & (1u << output->id)))
Michael Olbrichc5ea4952020-08-11 12:42:35 +02002628 continue;
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002629 if (pnode->surface->touched)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002630 continue;
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002631 pnode->surface->touched = true;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002632
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002633 surface_flush_damage(pnode->surface);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002634
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002635 /* Both the renderer and the backend have seen the buffer
2636 * by now. If renderer needs the buffer, it has its own
2637 * reference set. If the backend wants to keep the buffer
2638 * around for migrating the surface into a non-primary plane
2639 * later, keep_buffer is true. Otherwise, drop the core
2640 * reference now, and allow early buffer release. This enables
2641 * clients to use single-buffering.
2642 */
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002643 if (!pnode->surface->keep_buffer) {
2644 weston_buffer_reference(&pnode->surface->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +03002645 weston_buffer_release_reference(
Pekka Paalanen20ab6f82021-05-03 14:06:55 +03002646 &pnode->surface->buffer_release_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +03002647 }
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002648 }
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002649}
2650
2651static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002652surface_stash_subsurface_views(struct weston_surface *surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03002653{
2654 struct weston_subsurface *sub;
2655
Pekka Paalanene67858b2013-04-25 13:57:42 +03002656 wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002657 if (sub->surface == surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03002658 continue;
2659
Jason Ekstranda7af7042013-10-12 22:38:11 -05002660 wl_list_insert_list(&sub->unused_views, &sub->surface->views);
2661 wl_list_init(&sub->surface->views);
2662
2663 surface_stash_subsurface_views(sub->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002664 }
2665}
2666
2667static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002668surface_free_unused_subsurface_views(struct weston_surface *surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03002669{
Jason Ekstranda7af7042013-10-12 22:38:11 -05002670 struct weston_subsurface *sub;
2671 struct weston_view *view, *nv;
Pekka Paalanene67858b2013-04-25 13:57:42 +03002672
Jason Ekstranda7af7042013-10-12 22:38:11 -05002673 wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
2674 if (sub->surface == surface)
2675 continue;
2676
George Kiagiadakised04d382014-06-13 18:10:26 +02002677 wl_list_for_each_safe(view, nv, &sub->unused_views, surface_link) {
2678 weston_view_unmap (view);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002679 weston_view_destroy(view);
George Kiagiadakised04d382014-06-13 18:10:26 +02002680 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002681
2682 surface_free_unused_subsurface_views(sub->surface);
2683 }
2684}
2685
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002686static struct weston_paint_node *
2687view_ensure_paint_node(struct weston_view *view, struct weston_output *output)
2688{
2689 struct weston_paint_node *pnode;
2690
2691 if (!output)
2692 return NULL;
2693
2694 pnode = weston_view_find_paint_node(view, output);
2695 if (pnode)
2696 return pnode;
2697
2698 return weston_paint_node_create(view->surface, view, output);
2699}
2700
Jason Ekstranda7af7042013-10-12 22:38:11 -05002701static void
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002702add_to_z_order_list(struct weston_output *output,
2703 struct weston_paint_node *pnode)
2704{
2705 if (!pnode)
2706 return;
2707
2708 wl_list_remove(&pnode->z_order_link);
2709 wl_list_insert(output->paint_node_z_order_list.prev,
2710 &pnode->z_order_link);
Pekka Paalanen90a5ffa2021-02-25 12:03:28 +02002711
2712 /*
2713 * Building weston_output::paint_node_z_order_list ensures all
2714 * necessary color transform objects are installed.
2715 */
2716 weston_paint_node_ensure_color_transform(pnode);
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002717}
2718
2719static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002720view_list_add_subsurface_view(struct weston_compositor *compositor,
2721 struct weston_subsurface *sub,
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002722 struct weston_view *parent,
2723 struct weston_output *output)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002724{
2725 struct weston_subsurface *child;
2726 struct weston_view *view = NULL, *iv;
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002727 struct weston_paint_node *pnode;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002728
Pekka Paalanen661de3a2014-07-28 12:49:24 +03002729 if (!weston_surface_is_mapped(sub->surface))
2730 return;
2731
Jason Ekstranda7af7042013-10-12 22:38:11 -05002732 wl_list_for_each(iv, &sub->unused_views, surface_link) {
2733 if (iv->geometry.parent == parent) {
2734 view = iv;
2735 break;
Pekka Paalanene67858b2013-04-25 13:57:42 +03002736 }
2737 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002738
2739 if (view) {
2740 /* Put it back in the surface's list of views */
2741 wl_list_remove(&view->surface_link);
2742 wl_list_insert(&sub->surface->views, &view->surface_link);
2743 } else {
2744 view = weston_view_create(sub->surface);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002745 weston_view_set_position(view,
2746 sub->position.x,
2747 sub->position.y);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002748 weston_view_set_transform_parent(view, parent);
2749 }
2750
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03002751 view->parent_view = parent;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002752 weston_view_update_transform(view);
Armin Krezovićf8486c32016-06-30 06:04:28 +02002753 view->is_mapped = true;
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002754 pnode = view_ensure_paint_node(view, output);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002755
Pekka Paalanenb188e912013-11-19 14:03:35 +02002756 if (wl_list_empty(&sub->surface->subsurface_list)) {
2757 wl_list_insert(compositor->view_list.prev, &view->link);
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002758 add_to_z_order_list(output, pnode);
Pekka Paalanenb188e912013-11-19 14:03:35 +02002759 return;
2760 }
2761
2762 wl_list_for_each(child, &sub->surface->subsurface_list, parent_link) {
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002763 if (child->surface == sub->surface) {
Pekka Paalanenb188e912013-11-19 14:03:35 +02002764 wl_list_insert(compositor->view_list.prev, &view->link);
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002765 add_to_z_order_list(output, pnode);
2766 } else {
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002767 view_list_add_subsurface_view(compositor, child, view, output);
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002768 }
Pekka Paalanenb188e912013-11-19 14:03:35 +02002769 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002770}
2771
Emilio Pozuelo Monfort4f3cad72017-01-27 17:30:29 +01002772/* This recursively adds the sub-surfaces for a view, relying on the
2773 * sub-surface order. Thus, if a client restacks the sub-surfaces, that
2774 * change first happens to the sub-surface list, and then automatically
2775 * propagates here. See weston_surface_damage_subsurfaces() for how the
2776 * sub-surfaces receive damage when the client changes the state.
2777 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05002778static void
2779view_list_add(struct weston_compositor *compositor,
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002780 struct weston_view *view,
2781 struct weston_output *output)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002782{
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002783 struct weston_paint_node *pnode;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002784 struct weston_subsurface *sub;
2785
2786 weston_view_update_transform(view);
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002787 pnode = view_ensure_paint_node(view, output);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002788
Pekka Paalanenb188e912013-11-19 14:03:35 +02002789 if (wl_list_empty(&view->surface->subsurface_list)) {
2790 wl_list_insert(compositor->view_list.prev, &view->link);
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002791 add_to_z_order_list(output, pnode);
Pekka Paalanenb188e912013-11-19 14:03:35 +02002792 return;
2793 }
2794
2795 wl_list_for_each(sub, &view->surface->subsurface_list, parent_link) {
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002796 if (sub->surface == view->surface) {
Pekka Paalanenb188e912013-11-19 14:03:35 +02002797 wl_list_insert(compositor->view_list.prev, &view->link);
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002798 add_to_z_order_list(output, pnode);
2799 } else {
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002800 view_list_add_subsurface_view(compositor, sub, view, output);
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002801 }
Pekka Paalanenb188e912013-11-19 14:03:35 +02002802 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002803}
2804
2805static void
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002806weston_compositor_build_view_list(struct weston_compositor *compositor,
2807 struct weston_output *output)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002808{
Loïc Yhuel267b16e2019-09-17 20:14:56 +02002809 struct weston_view *view, *tmp;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002810 struct weston_layer *layer;
2811
Pekka Paalanen2fddc532021-04-30 17:41:29 +03002812 if (output) {
2813 wl_list_remove(&output->paint_node_z_order_list);
2814 wl_list_init(&output->paint_node_z_order_list);
2815 }
2816
Jason Ekstranda7af7042013-10-12 22:38:11 -05002817 wl_list_for_each(layer, &compositor->layer_list, link)
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002818 wl_list_for_each(view, &layer->view_list.link, layer_link.link)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002819 surface_stash_subsurface_views(view->surface);
2820
Loïc Yhuel267b16e2019-09-17 20:14:56 +02002821 wl_list_for_each_safe(view, tmp, &compositor->view_list, link)
2822 wl_list_init(&view->link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002823 wl_list_init(&compositor->view_list);
Loïc Yhuel267b16e2019-09-17 20:14:56 +02002824
Jason Ekstranda7af7042013-10-12 22:38:11 -05002825 wl_list_for_each(layer, &compositor->layer_list, link) {
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002826 wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002827 view_list_add(compositor, view, output);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002828 }
2829 }
2830
2831 wl_list_for_each(layer, &compositor->layer_list, link)
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002832 wl_list_for_each(view, &layer->view_list.link, layer_link.link)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002833 surface_free_unused_subsurface_views(view->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002834}
2835
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002836static void
2837weston_output_take_feedback_list(struct weston_output *output,
2838 struct weston_surface *surface)
2839{
2840 struct weston_view *view;
2841 struct weston_presentation_feedback *feedback;
2842 uint32_t flags = 0xffffffff;
2843
2844 if (wl_list_empty(&surface->feedback_list))
2845 return;
2846
2847 /* All views must have the flag for the flag to survive. */
2848 wl_list_for_each(view, &surface->views, surface_link) {
2849 /* ignore views that are not on this output at all */
2850 if (view->output_mask & (1u << output->id))
2851 flags &= view->psf_flags;
2852 }
2853
2854 wl_list_for_each(feedback, &surface->feedback_list, link)
2855 feedback->psf_flags = flags;
2856
2857 wl_list_insert_list(&output->feedback_list, &surface->feedback_list);
2858 wl_list_init(&surface->feedback_list);
2859}
2860
David Herrmann1edf44c2013-10-22 17:11:26 +02002861static int
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002862weston_output_repaint(struct weston_output *output, void *repaint_data)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002863{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002864 struct weston_compositor *ec = output->compositor;
Pekka Paalanen6d6b3672021-05-03 14:06:55 +03002865 struct weston_paint_node *pnode;
Kristian Høgsberg30c018b2012-01-26 08:40:37 -05002866 struct weston_animation *animation, *next;
Vlad Zahorodniic2b97472021-07-29 11:16:51 +03002867 struct wl_resource *cb, *cnext;
Jonas Ådahldb773762012-06-13 00:01:21 +02002868 struct wl_list frame_callback_list;
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002869 pixman_region32_t output_damage;
David Herrmann1edf44c2013-10-22 17:11:26 +02002870 int r;
Alexandros Frantzise6ac2af2017-11-16 18:20:53 +02002871 uint32_t frame_time_msec;
Ankit Nautiyal4b6e73d2019-03-26 13:37:12 +05302872 enum weston_hdcp_protection highest_requested = WESTON_HDCP_DISABLE;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05002873
Ander Conselvan de Oliveirae1e23522013-12-13 22:10:55 +02002874 if (output->destroying)
2875 return 0;
2876
Marius Vlad3203ff62019-09-05 14:56:12 +03002877 TL_POINT(ec, "core_repaint_begin", TLP_OUTPUT(output), TLP_END);
Pekka Paalanenb5026542014-11-12 15:09:24 +02002878
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002879 /* Rebuild the surface list and update surface transforms up front. */
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03002880 weston_compositor_build_view_list(ec, output);
Pekka Paalanen15d60ef2012-01-27 14:38:33 +02002881
Ankit Nautiyal4b6e73d2019-03-26 13:37:12 +05302882 /* Find the highest protection desired for an output */
Pekka Paalanen6d6b3672021-05-03 14:06:55 +03002883 wl_list_for_each(pnode, &output->paint_node_z_order_list,
2884 z_order_link) {
2885 /* TODO: turn this into assert once z_order_list is pruned. */
2886 if ((pnode->surface->output_mask & (1u << output->id)) == 0)
2887 continue;
2888
2889 /*
2890 * The desired_protection of the output should be the
2891 * maximum of the desired_protection of the surfaces,
2892 * that are displayed on that output, to avoid
2893 * reducing the protection for existing surfaces.
2894 */
2895 if (pnode->surface->desired_protection > highest_requested)
2896 highest_requested = pnode->surface->desired_protection;
Ankit Nautiyal4b6e73d2019-03-26 13:37:12 +05302897 }
2898
2899 output->desired_protection = highest_requested;
2900
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002901 if (output->assign_planes && !output->disable_planes) {
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002902 output->assign_planes(output, repaint_data);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002903 } else {
Pekka Paalanen6d6b3672021-05-03 14:06:55 +03002904 wl_list_for_each(pnode, &output->paint_node_z_order_list,
2905 z_order_link) {
2906 weston_view_move_to_plane(pnode->view, &ec->primary_plane);
2907 pnode->view->psf_flags = 0;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002908 }
2909 }
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04002910
Pekka Paalanene67858b2013-04-25 13:57:42 +03002911 wl_list_init(&frame_callback_list);
Pekka Paalanen6d6b3672021-05-03 14:06:55 +03002912 wl_list_for_each(pnode, &output->paint_node_z_order_list,
2913 z_order_link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002914 /* Note: This operation is safe to do multiple times on the
2915 * same surface.
2916 */
Pekka Paalanen6d6b3672021-05-03 14:06:55 +03002917 if (pnode->surface->output == output) {
Pekka Paalanene67858b2013-04-25 13:57:42 +03002918 wl_list_insert_list(&frame_callback_list,
Pekka Paalanen6d6b3672021-05-03 14:06:55 +03002919 &pnode->surface->frame_callback_list);
2920 wl_list_init(&pnode->surface->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -04002921
Pekka Paalanen6d6b3672021-05-03 14:06:55 +03002922 weston_output_take_feedback_list(output, pnode->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002923 }
2924 }
2925
Michael Olbrichc5ea4952020-08-11 12:42:35 +02002926 output_accumulate_damage(output);
Kristian Høgsberg53df1d82011-06-23 21:11:19 -04002927
Ander Conselvan de Oliveira4f521732012-08-15 14:02:05 -04002928 pixman_region32_init(&output_damage);
Ander Conselvan de Oliveira4f521732012-08-15 14:02:05 -04002929 pixman_region32_intersect(&output_damage,
2930 &ec->primary_plane.damage, &output->region);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002931 pixman_region32_subtract(&output_damage,
2932 &output_damage, &ec->primary_plane.clip);
Ander Conselvan de Oliveira4f521732012-08-15 14:02:05 -04002933
Scott Moreauccbf29d2012-02-22 14:21:41 -07002934 if (output->dirty)
2935 weston_output_update_matrix(output);
2936
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002937 r = output->repaint(output, &output_damage, repaint_data);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002938
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -05002939 pixman_region32_fini(&output_damage);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05002940
Daniel Stone09a97e22017-03-01 11:34:06 +00002941 output->repaint_needed = false;
Daniel Stone05df8c12017-03-03 16:59:42 +00002942 if (r == 0)
2943 output->repaint_status = REPAINT_AWAITING_COMPLETION;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002944
Kristian Høgsbergaa6019e2012-03-11 16:35:16 -04002945 weston_compositor_repick(ec);
Kristian Høgsbergaa6019e2012-03-11 16:35:16 -04002946
Alexandros Frantzise6ac2af2017-11-16 18:20:53 +02002947 frame_time_msec = timespec_to_msec(&output->frame_time);
2948
Vlad Zahorodniic2b97472021-07-29 11:16:51 +03002949 wl_resource_for_each_safe(cb, cnext, &frame_callback_list) {
2950 wl_callback_send_done(cb, frame_time_msec);
2951 wl_resource_destroy(cb);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05002952 }
2953
Scott Moreaud64cf212012-06-08 19:40:54 -06002954 wl_list_for_each_safe(animation, next, &output->animation_list, link) {
Scott Moreaud64cf212012-06-08 19:40:54 -06002955 animation->frame_counter++;
Alexandros Frantzise6ac2af2017-11-16 18:20:53 +02002956 animation->frame(animation, output, &output->frame_time);
Scott Moreaud64cf212012-06-08 19:40:54 -06002957 }
David Herrmann1edf44c2013-10-22 17:11:26 +02002958
Marius Vlad3203ff62019-09-05 14:56:12 +03002959 TL_POINT(ec, "core_repaint_posted", TLP_OUTPUT(output), TLP_END);
Pekka Paalanenb5026542014-11-12 15:09:24 +02002960
David Herrmann1edf44c2013-10-22 17:11:26 +02002961 return r;
Kristian Høgsbergef044142011-06-21 15:02:12 -04002962}
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002963
Pekka Paalanen82919792014-05-21 13:51:49 +03002964static void
2965weston_output_schedule_repaint_reset(struct weston_output *output)
2966{
Daniel Stone05df8c12017-03-03 16:59:42 +00002967 output->repaint_status = REPAINT_NOT_SCHEDULED;
Marius Vlad3203ff62019-09-05 14:56:12 +03002968 TL_POINT(output->compositor, "core_repaint_exit_loop",
2969 TLP_OUTPUT(output), TLP_END);
Pekka Paalanen82919792014-05-21 13:51:49 +03002970}
2971
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002972static int
2973weston_output_maybe_repaint(struct weston_output *output, struct timespec *now,
2974 void *repaint_data)
Pekka Paalanen0513a952014-05-21 16:17:27 +03002975{
Pekka Paalanen0513a952014-05-21 16:17:27 +03002976 struct weston_compositor *compositor = output->compositor;
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002977 int ret = 0;
Daniel Stone6847b852017-03-01 11:34:08 +00002978 int64_t msec_to_repaint;
Pekka Paalanen0513a952014-05-21 16:17:27 +03002979
Daniel Stone6847b852017-03-01 11:34:08 +00002980 /* We're not ready yet; come back to make a decision later. */
2981 if (output->repaint_status != REPAINT_SCHEDULED)
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002982 return ret;
Daniel Stone6847b852017-03-01 11:34:08 +00002983
2984 msec_to_repaint = timespec_sub_to_msec(&output->next_repaint, now);
2985 if (msec_to_repaint > 1)
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002986 return ret;
Daniel Stone05df8c12017-03-03 16:59:42 +00002987
Daniel Stonecd1a1c32017-01-16 15:38:54 +00002988 /* If we're sleeping, drop the repaint machinery entirely; we will
2989 * explicitly repaint all outputs when we come back. */
2990 if (compositor->state == WESTON_COMPOSITOR_SLEEPING ||
2991 compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
2992 goto err;
Pekka Paalanen0513a952014-05-21 16:17:27 +03002993
Daniel Stonecd1a1c32017-01-16 15:38:54 +00002994 /* We don't actually need to repaint this output; drop it from
2995 * repaint until something causes damage. */
2996 if (!output->repaint_needed)
2997 goto err;
2998
2999 /* If repaint fails, we aren't going to get weston_output_finish_frame
3000 * to trigger a new repaint, so drop it from repaint and hope
Daniel Stone6847b852017-03-01 11:34:08 +00003001 * something schedules a successful repaint later. As repainting may
3002 * take some time, re-read our clock as a courtesy to the next
3003 * output. */
Daniel Stoneb1f166d2017-03-01 11:34:10 +00003004 ret = weston_output_repaint(output, repaint_data);
Daniel Stone6847b852017-03-01 11:34:08 +00003005 weston_compositor_read_presentation_clock(compositor, now);
Daniel Stonecd1a1c32017-01-16 15:38:54 +00003006 if (ret != 0)
3007 goto err;
3008
Tomohito Esaki7f4d9ff2018-06-05 10:37:06 +09003009 output->repainted = true;
Daniel Stoneb1f166d2017-03-01 11:34:10 +00003010 return ret;
Daniel Stonecd1a1c32017-01-16 15:38:54 +00003011
3012err:
Pekka Paalanen0513a952014-05-21 16:17:27 +03003013 weston_output_schedule_repaint_reset(output);
Daniel Stoneb1f166d2017-03-01 11:34:10 +00003014 return ret;
Daniel Stone6847b852017-03-01 11:34:08 +00003015}
3016
3017static void
3018output_repaint_timer_arm(struct weston_compositor *compositor)
3019{
3020 struct weston_output *output;
3021 bool any_should_repaint = false;
3022 struct timespec now;
Sergi Granellb4c08862017-03-18 13:01:15 +01003023 int64_t msec_to_next = INT64_MAX;
Daniel Stone6847b852017-03-01 11:34:08 +00003024
3025 weston_compositor_read_presentation_clock(compositor, &now);
3026
3027 wl_list_for_each(output, &compositor->output_list, link) {
3028 int64_t msec_to_this;
3029
3030 if (output->repaint_status != REPAINT_SCHEDULED)
3031 continue;
3032
3033 msec_to_this = timespec_sub_to_msec(&output->next_repaint,
3034 &now);
3035 if (!any_should_repaint || msec_to_this < msec_to_next)
3036 msec_to_next = msec_to_this;
3037
3038 any_should_repaint = true;
3039 }
3040
3041 if (!any_should_repaint)
3042 return;
3043
3044 /* Even if we should repaint immediately, add the minimum 1 ms delay.
3045 * This is a workaround to allow coalescing multiple output repaints
3046 * particularly from weston_output_finish_frame()
3047 * into the same call, which would not happen if we called
3048 * output_repaint_timer_handler() directly.
3049 */
3050 if (msec_to_next < 1)
3051 msec_to_next = 1;
3052
3053 wl_event_source_timer_update(compositor->repaint_timer, msec_to_next);
3054}
3055
3056static int
3057output_repaint_timer_handler(void *data)
3058{
3059 struct weston_compositor *compositor = data;
3060 struct weston_output *output;
3061 struct timespec now;
Daniel Stoneb1f166d2017-03-01 11:34:10 +00003062 void *repaint_data = NULL;
Emre Ucane479ed82018-03-20 15:29:40 +01003063 int ret = 0;
Daniel Stone6847b852017-03-01 11:34:08 +00003064
3065 weston_compositor_read_presentation_clock(compositor, &now);
Pekka Paalanen1ed2cad2021-02-10 12:33:03 +02003066 compositor->last_repaint_start = now;
Daniel Stoneb1f166d2017-03-01 11:34:10 +00003067
3068 if (compositor->backend->repaint_begin)
3069 repaint_data = compositor->backend->repaint_begin(compositor);
3070
3071 wl_list_for_each(output, &compositor->output_list, link) {
3072 ret = weston_output_maybe_repaint(output, &now, repaint_data);
3073 if (ret)
3074 break;
3075 }
3076
3077 if (ret == 0) {
Tomohito Esaki09bfcd62018-06-05 10:37:05 +09003078 if (compositor->backend->repaint_flush)
Antonio Borneoc90fccc2019-06-30 15:51:10 +02003079 ret = compositor->backend->repaint_flush(compositor,
3080 repaint_data);
Daniel Stoneb1f166d2017-03-01 11:34:10 +00003081 } else {
Antonio Borneoc90fccc2019-06-30 15:51:10 +02003082 if (compositor->backend->repaint_cancel)
3083 compositor->backend->repaint_cancel(compositor,
3084 repaint_data);
3085 }
3086
3087 if (ret != 0) {
Tomohito Esaki7f4d9ff2018-06-05 10:37:06 +09003088 wl_list_for_each(output, &compositor->output_list, link) {
3089 if (output->repainted)
3090 weston_output_schedule_repaint_reset(output);
3091 }
Daniel Stoneb1f166d2017-03-01 11:34:10 +00003092 }
Daniel Stone6847b852017-03-01 11:34:08 +00003093
Tomohito Esakiddaf95c2018-07-10 11:47:15 +09003094 wl_list_for_each(output, &compositor->output_list, link)
3095 output->repainted = false;
3096
Daniel Stone6847b852017-03-01 11:34:08 +00003097 output_repaint_timer_arm(compositor);
3098
Pekka Paalanen0513a952014-05-21 16:17:27 +03003099 return 0;
3100}
3101
Pekka Paalanen50aa3a72020-05-28 11:34:04 +03003102/** Convert a presentation timestamp to another clock domain
3103 *
3104 * \param compositor The compositor defines the presentation clock domain.
3105 * \param presentation_stamp The timestamp in presentation clock domain.
3106 * \param presentation_now Current time in presentation clock domain.
3107 * \param target_clock Defines the target clock domain.
3108 *
3109 * This approximation relies on presentation_stamp to be close to current time.
3110 * The further it is from current time and the bigger the speed difference
3111 * between the two clock domains, the bigger the conversion error.
3112 *
3113 * Conversion error due to system load is biased and unbounded.
3114 */
3115static struct timespec
3116convert_presentation_time_now(struct weston_compositor *compositor,
3117 const struct timespec *presentation_stamp,
3118 const struct timespec *presentation_now,
3119 clockid_t target_clock)
3120{
3121 struct timespec target_now = {};
3122 struct timespec target_stamp;
3123 int64_t delta_ns;
3124
3125 if (compositor->presentation_clock == target_clock)
3126 return *presentation_stamp;
3127
3128 clock_gettime(target_clock, &target_now);
3129 delta_ns = timespec_sub_to_nsec(presentation_stamp, presentation_now);
3130 timespec_add_nsec(&target_stamp, &target_now, delta_ns);
3131
3132 return target_stamp;
3133}
3134
Marius Vlad55d87362019-06-11 01:15:35 +03003135/**
3136 * \ingroup output
3137 */
Kristian Høgsbergef044142011-06-21 15:02:12 -04003138WL_EXPORT void
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003139weston_output_finish_frame(struct weston_output *output,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +02003140 const struct timespec *stamp,
3141 uint32_t presented_flags)
Kristian Høgsbergef044142011-06-21 15:02:12 -04003142{
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05003143 struct weston_compositor *compositor = output->compositor;
Pekka Paalanen0513a952014-05-21 16:17:27 +03003144 int32_t refresh_nsec;
3145 struct timespec now;
Pekka Paalanen50aa3a72020-05-28 11:34:04 +03003146 struct timespec vblank_monotonic;
Daniel Stone6847b852017-03-01 11:34:08 +00003147 int64_t msec_rel;
Pekka Paalanen133e4392014-09-23 22:08:46 -04003148
Daniel Stone05df8c12017-03-03 16:59:42 +00003149 assert(output->repaint_status == REPAINT_AWAITING_COMPLETION);
Pekka Paalanen98b4e202021-05-10 11:33:23 +03003150
3151 /*
3152 * If timestamp of latest vblank is given, it must always go forwards.
3153 * If not given, INVALID flag must be set.
3154 */
3155 if (stamp)
3156 assert(timespec_sub_to_nsec(stamp, &output->frame_time) >= 0);
3157 else
3158 assert(presented_flags & WP_PRESENTATION_FEEDBACK_INVALID);
Daniel Stone3615ce12017-03-01 11:34:05 +00003159
Daniel Stone6847b852017-03-01 11:34:08 +00003160 weston_compositor_read_presentation_clock(compositor, &now);
3161
Daniel Stone3615ce12017-03-01 11:34:05 +00003162 /* If we haven't been supplied any timestamp at all, we don't have a
3163 * timebase to work against, so any delay just wastes time. Push a
3164 * repaint as soon as possible so we can get on with it. */
Daniel Stone6847b852017-03-01 11:34:08 +00003165 if (!stamp) {
3166 output->next_repaint = now;
Daniel Stone3615ce12017-03-01 11:34:05 +00003167 goto out;
Daniel Stone6847b852017-03-01 11:34:08 +00003168 }
Daniel Stone3615ce12017-03-01 11:34:05 +00003169
Pekka Paalanen50aa3a72020-05-28 11:34:04 +03003170 vblank_monotonic = convert_presentation_time_now(compositor,
3171 stamp, &now,
3172 CLOCK_MONOTONIC);
Marius Vlad3203ff62019-09-05 14:56:12 +03003173 TL_POINT(compositor, "core_repaint_finished", TLP_OUTPUT(output),
Pekka Paalanen50aa3a72020-05-28 11:34:04 +03003174 TLP_VBLANK(&vblank_monotonic), TLP_END);
Marius Vladdf9278a2018-03-06 18:56:23 +02003175
Pekka Paalanend7894d02015-07-03 15:08:53 +03003176 refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
Pekka Paalanen133e4392014-09-23 22:08:46 -04003177 weston_presentation_feedback_present_list(&output->feedback_list,
3178 output, refresh_nsec, stamp,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +02003179 output->msc,
3180 presented_flags);
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05003181
Alexandros Frantzise6ac2af2017-11-16 18:20:53 +02003182 output->frame_time = *stamp;
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05003183
Daniel Stone6847b852017-03-01 11:34:08 +00003184 timespec_add_nsec(&output->next_repaint, stamp, refresh_nsec);
3185 timespec_add_msec(&output->next_repaint, &output->next_repaint,
3186 -compositor->repaint_msec);
3187 msec_rel = timespec_sub_to_msec(&output->next_repaint, &now);
Daniel Stone84aff5c2017-03-01 11:34:04 +00003188
3189 if (msec_rel < -1000 || msec_rel > 1000) {
Pekka Paalanen8fd4de42015-03-19 12:27:29 +02003190 static bool warned;
3191
3192 if (!warned)
3193 weston_log("Warning: computed repaint delay is "
Daniel Stone6847b852017-03-01 11:34:08 +00003194 "insane: %lld msec\n", (long long) msec_rel);
Pekka Paalanen8fd4de42015-03-19 12:27:29 +02003195 warned = true;
3196
Daniel Stone6847b852017-03-01 11:34:08 +00003197 output->next_repaint = now;
Pekka Paalanen8fd4de42015-03-19 12:27:29 +02003198 }
3199
Mario Kleinerb7df04e2015-06-21 21:25:15 +02003200 /* Called from restart_repaint_loop and restart happens already after
3201 * the deadline given by repaint_msec? In that case we delay until
3202 * the deadline of the next frame, to give clients a more predictable
3203 * timing of the repaint cycle to lock on. */
Daniel Stoneeca5cca2017-02-28 21:53:51 +00003204 if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID &&
3205 msec_rel < 0) {
3206 while (timespec_sub_to_nsec(&output->next_repaint, &now) < 0) {
3207 timespec_add_nsec(&output->next_repaint,
3208 &output->next_repaint,
3209 refresh_nsec);
3210 }
3211 }
Mario Kleinerb7df04e2015-06-21 21:25:15 +02003212
Daniel Stone3615ce12017-03-01 11:34:05 +00003213out:
Daniel Stone05df8c12017-03-03 16:59:42 +00003214 output->repaint_status = REPAINT_SCHEDULED;
Daniel Stone6847b852017-03-01 11:34:08 +00003215 output_repaint_timer_arm(compositor);
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05003216}
3217
3218static void
3219idle_repaint(void *data)
3220{
3221 struct weston_output *output = data;
Antonio Borneoc90fccc2019-06-30 15:51:10 +02003222 int ret;
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05003223
Daniel Stone05df8c12017-03-03 16:59:42 +00003224 assert(output->repaint_status == REPAINT_BEGIN_FROM_IDLE);
3225 output->repaint_status = REPAINT_AWAITING_COMPLETION;
Pekka Paalanendcbcfc72017-10-26 14:33:59 +03003226 output->idle_repaint_source = NULL;
Antonio Borneoc90fccc2019-06-30 15:51:10 +02003227 ret = output->start_repaint_loop(output);
3228 if (ret != 0)
3229 weston_output_schedule_repaint_reset(output);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04003230}
3231
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04003232WL_EXPORT void
Giulio Camuffo412e6a52014-07-09 22:12:56 +03003233weston_layer_entry_insert(struct weston_layer_entry *list,
3234 struct weston_layer_entry *entry)
3235{
3236 wl_list_insert(&list->link, &entry->link);
3237 entry->layer = list->layer;
3238}
3239
3240WL_EXPORT void
3241weston_layer_entry_remove(struct weston_layer_entry *entry)
3242{
3243 wl_list_remove(&entry->link);
3244 wl_list_init(&entry->link);
3245 entry->layer = NULL;
3246}
3247
Quentin Glidic82681572016-12-17 13:40:51 +01003248
3249/** Initialize the weston_layer struct.
3250 *
3251 * \param compositor The compositor instance
3252 * \param layer The layer to initialize
3253 */
Giulio Camuffo412e6a52014-07-09 22:12:56 +03003254WL_EXPORT void
Quentin Glidic82681572016-12-17 13:40:51 +01003255weston_layer_init(struct weston_layer *layer,
3256 struct weston_compositor *compositor)
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003257{
Quentin Glidic82681572016-12-17 13:40:51 +01003258 layer->compositor = compositor;
3259 wl_list_init(&layer->link);
Giulio Camuffo412e6a52014-07-09 22:12:56 +03003260 wl_list_init(&layer->view_list.link);
3261 layer->view_list.layer = layer;
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03003262 weston_layer_set_mask_infinite(layer);
Quentin Glidic82681572016-12-17 13:40:51 +01003263}
3264
Pekka Paalanen87400372021-05-14 14:29:40 +03003265/** Finalize the weston_layer struct.
3266 *
3267 * \param layer The layer to finalize.
3268 */
3269WL_EXPORT void
3270weston_layer_fini(struct weston_layer *layer)
3271{
3272 wl_list_remove(&layer->link);
3273
3274 if (!wl_list_empty(&layer->view_list.link))
3275 weston_log("BUG: finalizing a layer with views still on it.\n");
3276
3277 wl_list_remove(&layer->view_list.link);
3278}
3279
Quentin Glidic82681572016-12-17 13:40:51 +01003280/** Sets the position of the layer in the layer list. The layer will be placed
3281 * below any layer with the same position value, if any.
3282 * This function is safe to call if the layer is already on the list, but the
3283 * layer may be moved below other layers at the same position, if any.
3284 *
3285 * \param layer The layer to modify
3286 * \param position The position the layer will be placed at
3287 */
3288WL_EXPORT void
3289weston_layer_set_position(struct weston_layer *layer,
3290 enum weston_layer_position position)
3291{
3292 struct weston_layer *below;
3293
3294 wl_list_remove(&layer->link);
3295
3296 /* layer_list is ordered from top to bottom, the last layer being the
3297 * background with the smallest position value */
3298
3299 layer->position = position;
3300 wl_list_for_each_reverse(below, &layer->compositor->layer_list, link) {
3301 if (below->position >= layer->position) {
3302 wl_list_insert(&below->link, &layer->link);
3303 return;
3304 }
3305 }
3306 wl_list_insert(&layer->compositor->layer_list, &layer->link);
3307}
3308
3309/** Hide a layer by taking it off the layer list.
3310 * This function is safe to call if the layer is not on the list.
3311 *
3312 * \param layer The layer to hide
3313 */
3314WL_EXPORT void
3315weston_layer_unset_position(struct weston_layer *layer)
3316{
3317 wl_list_remove(&layer->link);
3318 wl_list_init(&layer->link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003319}
3320
3321WL_EXPORT void
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03003322weston_layer_set_mask(struct weston_layer *layer,
3323 int x, int y, int width, int height)
3324{
3325 struct weston_view *view;
3326
3327 layer->mask.x1 = x;
3328 layer->mask.x2 = x + width;
3329 layer->mask.y1 = y;
3330 layer->mask.y2 = y + height;
3331
3332 wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
3333 weston_view_geometry_dirty(view);
3334 }
3335}
3336
3337WL_EXPORT void
3338weston_layer_set_mask_infinite(struct weston_layer *layer)
3339{
Adam Jackson3c3f3b12019-10-16 16:02:59 -04003340 struct weston_view *view;
3341
3342 layer->mask.x1 = INT32_MIN;
3343 layer->mask.x2 = INT32_MAX;
3344 layer->mask.y1 = INT32_MIN;
3345 layer->mask.y2 = INT32_MAX;
3346
3347 wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
3348 weston_view_geometry_dirty(view);
3349 }
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03003350}
3351
Daniel Stone3b775632018-07-20 08:38:25 +01003352WL_EXPORT bool
3353weston_layer_mask_is_infinite(struct weston_layer *layer)
3354{
3355 return layer->mask.x1 == INT32_MIN &&
3356 layer->mask.y1 == INT32_MIN &&
Adam Jackson3c3f3b12019-10-16 16:02:59 -04003357 layer->mask.x2 == INT32_MAX &&
3358 layer->mask.y2 == INT32_MAX;
Daniel Stone3b775632018-07-20 08:38:25 +01003359}
3360
Marius Vlad55d87362019-06-11 01:15:35 +03003361/**
3362 * \ingroup output
3363 */
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03003364WL_EXPORT void
Kristian Høgsberg49952d12012-06-20 00:35:59 -04003365weston_output_schedule_repaint(struct weston_output *output)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04003366{
Kristian Høgsberg49952d12012-06-20 00:35:59 -04003367 struct weston_compositor *compositor = output->compositor;
Kristian Høgsbergef044142011-06-21 15:02:12 -04003368 struct wl_event_loop *loop;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01003369
Bryce Harrington08976ac2016-08-30 12:05:16 -07003370 if (compositor->state == WESTON_COMPOSITOR_SLEEPING ||
3371 compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04003372 return;
3373
Pekka Paalanenb5026542014-11-12 15:09:24 +02003374 if (!output->repaint_needed)
Marius Vlad3203ff62019-09-05 14:56:12 +03003375 TL_POINT(compositor, "core_repaint_req", TLP_OUTPUT(output), TLP_END);
Pekka Paalanenb5026542014-11-12 15:09:24 +02003376
Kristian Høgsbergef044142011-06-21 15:02:12 -04003377 loop = wl_display_get_event_loop(compositor->wl_display);
Daniel Stone09a97e22017-03-01 11:34:06 +00003378 output->repaint_needed = true;
Daniel Stone05df8c12017-03-03 16:59:42 +00003379
3380 /* If we already have a repaint scheduled for our idle handler,
3381 * no need to set it again. If the repaint has been called but
3382 * not finished, then weston_output_finish_frame() will notice
3383 * that a repaint is needed and schedule one. */
3384 if (output->repaint_status != REPAINT_NOT_SCHEDULED)
Kristian Høgsberg49952d12012-06-20 00:35:59 -04003385 return;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01003386
Daniel Stone05df8c12017-03-03 16:59:42 +00003387 output->repaint_status = REPAINT_BEGIN_FROM_IDLE;
Pekka Paalanendcbcfc72017-10-26 14:33:59 +03003388 assert(!output->idle_repaint_source);
3389 output->idle_repaint_source = wl_event_loop_add_idle(loop, idle_repaint,
3390 output);
Marius Vlad3203ff62019-09-05 14:56:12 +03003391 TL_POINT(compositor, "core_repaint_enter_loop", TLP_OUTPUT(output), TLP_END);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04003392}
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -05003393
Marius Vlad9fdda7f2019-06-11 16:08:55 +03003394/** weston_compositor_schedule_repaint
3395 * \ingroup compositor
3396 */
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04003397WL_EXPORT void
Kristian Høgsberg49952d12012-06-20 00:35:59 -04003398weston_compositor_schedule_repaint(struct weston_compositor *compositor)
3399{
3400 struct weston_output *output;
3401
3402 wl_list_for_each(output, &compositor->output_list, link)
3403 weston_output_schedule_repaint(output);
3404}
3405
Kristian Høgsberg5503bf82008-11-06 10:38:17 -05003406static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -04003407surface_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04003408{
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003409 wl_resource_destroy(resource);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04003410}
3411
Kristian Høgsberg5503bf82008-11-06 10:38:17 -05003412static void
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03003413surface_attach(struct wl_client *client,
3414 struct wl_resource *resource,
3415 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
3416{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003417 struct weston_surface *surface = wl_resource_get_user_data(resource);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05003418 struct weston_buffer *buffer = NULL;
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03003419
Kristian Høgsbergab19f932013-08-20 11:30:54 -07003420 if (buffer_resource) {
Jason Ekstrand6bd62942013-06-20 20:38:23 -05003421 buffer = weston_buffer_from_resource(buffer_resource);
Kristian Høgsbergab19f932013-08-20 11:30:54 -07003422 if (buffer == NULL) {
3423 wl_client_post_no_memory(client);
3424 return;
3425 }
Kristian Høgsberg08b58c72013-08-15 12:26:42 -07003426 }
Kristian Høgsberga691aee2011-06-23 21:43:50 -04003427
Pekka Paalanende685b82012-12-04 15:58:12 +02003428 /* Attach, attach, without commit in between does not send
3429 * wl_buffer.release. */
Jason Ekstrand7b982072014-05-20 14:33:03 -05003430 weston_surface_state_set_buffer(&surface->pending, buffer);
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03003431
Pekka Paalanen5df44de2012-10-10 12:49:23 +03003432 surface->pending.sx = sx;
3433 surface->pending.sy = sy;
Giulio Camuffo184df502013-02-21 11:29:21 +01003434 surface->pending.newly_attached = 1;
Kristian Høgsbergf9212892008-10-11 18:40:23 -04003435}
3436
Kristian Høgsberg5503bf82008-11-06 10:38:17 -05003437static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003438surface_damage(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -04003439 struct wl_resource *resource,
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003440 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -05003441{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003442 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04003443
Derek Foreman57e92ed2015-11-17 14:11:35 -06003444 if (width <= 0 || height <= 0)
3445 return;
3446
Derek Foreman152254b2015-11-26 14:17:48 -06003447 pixman_region32_union_rect(&surface->pending.damage_surface,
3448 &surface->pending.damage_surface,
3449 x, y, width, height);
3450}
3451
3452static void
3453surface_damage_buffer(struct wl_client *client,
3454 struct wl_resource *resource,
3455 int32_t x, int32_t y, int32_t width, int32_t height)
3456{
3457 struct weston_surface *surface = wl_resource_get_user_data(resource);
3458
3459 if (width <= 0 || height <= 0)
3460 return;
3461
3462 pixman_region32_union_rect(&surface->pending.damage_buffer,
3463 &surface->pending.damage_buffer,
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04003464 x, y, width, height);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05003465}
3466
Kristian Høgsberg33418202011-08-16 23:01:28 -04003467static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -04003468destroy_frame_callback(struct wl_resource *resource)
Kristian Høgsberg33418202011-08-16 23:01:28 -04003469{
Vlad Zahorodniic2b97472021-07-29 11:16:51 +03003470 wl_list_remove(wl_resource_get_link(resource));
Kristian Høgsberg33418202011-08-16 23:01:28 -04003471}
3472
3473static void
3474surface_frame(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -04003475 struct wl_resource *resource, uint32_t callback)
Kristian Høgsberg33418202011-08-16 23:01:28 -04003476{
Vlad Zahorodniic2b97472021-07-29 11:16:51 +03003477 struct wl_resource *cb;
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003478 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg33418202011-08-16 23:01:28 -04003479
Vlad Zahorodniic2b97472021-07-29 11:16:51 +03003480 cb = wl_resource_create(client, &wl_callback_interface, 1, callback);
Kristian Høgsberg33418202011-08-16 23:01:28 -04003481 if (cb == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -04003482 wl_resource_post_no_memory(resource);
Kristian Høgsberg33418202011-08-16 23:01:28 -04003483 return;
3484 }
Pekka Paalanenbc106382012-10-10 12:49:31 +03003485
Vlad Zahorodniic2b97472021-07-29 11:16:51 +03003486 wl_resource_set_implementation(cb, NULL, NULL,
Jason Ekstranda85118c2013-06-27 20:17:02 -05003487 destroy_frame_callback);
Kristian Høgsberg33418202011-08-16 23:01:28 -04003488
Vlad Zahorodniic2b97472021-07-29 11:16:51 +03003489 wl_list_insert(surface->pending.frame_callback_list.prev,
3490 wl_resource_get_link(cb));
Kristian Høgsberg33418202011-08-16 23:01:28 -04003491}
3492
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003493static void
3494surface_set_opaque_region(struct wl_client *client,
3495 struct wl_resource *resource,
3496 struct wl_resource *region_resource)
3497{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003498 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003499 struct weston_region *region;
3500
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003501 if (region_resource) {
Jason Ekstrand8895efc2013-06-14 10:07:56 -05003502 region = wl_resource_get_user_data(region_resource);
Pekka Paalanen512dde82012-10-10 12:49:27 +03003503 pixman_region32_copy(&surface->pending.opaque,
3504 &region->region);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003505 } else {
Jason Ekstrandef540082014-06-26 10:37:36 -07003506 pixman_region32_clear(&surface->pending.opaque);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003507 }
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003508}
3509
3510static void
3511surface_set_input_region(struct wl_client *client,
3512 struct wl_resource *resource,
3513 struct wl_resource *region_resource)
3514{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003515 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05003516 struct weston_region *region;
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003517
3518 if (region_resource) {
Jason Ekstrand8895efc2013-06-14 10:07:56 -05003519 region = wl_resource_get_user_data(region_resource);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03003520 pixman_region32_copy(&surface->pending.input,
3521 &region->region);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003522 } else {
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03003523 pixman_region32_fini(&surface->pending.input);
3524 region_init_infinite(&surface->pending.input);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003525 }
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003526}
3527
Emilio Pozuelo Monfort4f3cad72017-01-27 17:30:29 +01003528/* Cause damage to this sub-surface and all its children.
3529 *
3530 * This is useful when there are state changes that need an implicit
3531 * damage, e.g. a z-order change.
3532 */
3533static void
3534weston_surface_damage_subsurfaces(struct weston_subsurface *sub)
3535{
3536 struct weston_subsurface *child;
3537
3538 weston_surface_damage(sub->surface);
3539 sub->reordered = false;
3540
3541 wl_list_for_each(child, &sub->surface->subsurface_list, parent_link)
3542 if (child != sub)
3543 weston_surface_damage_subsurfaces(child);
3544}
3545
Pekka Paalanen5df44de2012-10-10 12:49:23 +03003546static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03003547weston_surface_commit_subsurface_order(struct weston_surface *surface)
Pekka Paalanen5df44de2012-10-10 12:49:23 +03003548{
Pekka Paalanene67858b2013-04-25 13:57:42 +03003549 struct weston_subsurface *sub;
3550
3551 wl_list_for_each_reverse(sub, &surface->subsurface_list_pending,
3552 parent_link_pending) {
3553 wl_list_remove(&sub->parent_link);
3554 wl_list_insert(&surface->subsurface_list, &sub->parent_link);
Emilio Pozuelo Monfort4f3cad72017-01-27 17:30:29 +01003555
3556 if (sub->reordered)
3557 weston_surface_damage_subsurfaces(sub);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003558 }
3559}
3560
3561static void
Pekka Paalanen04baea52016-04-26 15:50:58 +03003562weston_surface_build_buffer_matrix(const struct weston_surface *surface,
Jason Ekstrand1e059042014-10-16 10:55:19 -05003563 struct weston_matrix *matrix)
3564{
Pekka Paalanen04baea52016-04-26 15:50:58 +03003565 const struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Jason Ekstrand1e059042014-10-16 10:55:19 -05003566 double src_width, src_height, dest_width, dest_height;
3567
3568 weston_matrix_init(matrix);
3569
3570 if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
3571 src_width = surface->width_from_buffer;
3572 src_height = surface->height_from_buffer;
3573 } else {
3574 src_width = wl_fixed_to_double(vp->buffer.src_width);
3575 src_height = wl_fixed_to_double(vp->buffer.src_height);
3576 }
3577
3578 if (vp->surface.width == -1) {
3579 dest_width = src_width;
3580 dest_height = src_height;
3581 } else {
3582 dest_width = vp->surface.width;
3583 dest_height = vp->surface.height;
3584 }
3585
3586 if (src_width != dest_width || src_height != dest_height)
3587 weston_matrix_scale(matrix,
3588 src_width / dest_width,
3589 src_height / dest_height, 1);
3590
3591 if (vp->buffer.src_width != wl_fixed_from_int(-1))
3592 weston_matrix_translate(matrix,
3593 wl_fixed_to_double(vp->buffer.src_x),
3594 wl_fixed_to_double(vp->buffer.src_y),
3595 0);
3596
3597 switch (vp->buffer.transform) {
3598 case WL_OUTPUT_TRANSFORM_FLIPPED:
3599 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
3600 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
3601 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
3602 weston_matrix_scale(matrix, -1, 1, 1);
3603 weston_matrix_translate(matrix,
3604 surface->width_from_buffer, 0, 0);
3605 break;
3606 }
3607
3608 switch (vp->buffer.transform) {
3609 default:
3610 case WL_OUTPUT_TRANSFORM_NORMAL:
3611 case WL_OUTPUT_TRANSFORM_FLIPPED:
3612 break;
3613 case WL_OUTPUT_TRANSFORM_90:
3614 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
Pekka Paalanen8060d822020-02-06 15:27:54 +02003615 weston_matrix_rotate_xy(matrix, 0, -1);
Jason Ekstrand1e059042014-10-16 10:55:19 -05003616 weston_matrix_translate(matrix,
Pekka Paalanen8060d822020-02-06 15:27:54 +02003617 0, surface->width_from_buffer, 0);
Jason Ekstrand1e059042014-10-16 10:55:19 -05003618 break;
3619 case WL_OUTPUT_TRANSFORM_180:
3620 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
3621 weston_matrix_rotate_xy(matrix, -1, 0);
3622 weston_matrix_translate(matrix,
3623 surface->width_from_buffer,
3624 surface->height_from_buffer, 0);
3625 break;
3626 case WL_OUTPUT_TRANSFORM_270:
3627 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
Pekka Paalanen8060d822020-02-06 15:27:54 +02003628 weston_matrix_rotate_xy(matrix, 0, 1);
Jason Ekstrand1e059042014-10-16 10:55:19 -05003629 weston_matrix_translate(matrix,
Pekka Paalanen8060d822020-02-06 15:27:54 +02003630 surface->height_from_buffer, 0, 0);
Jason Ekstrand1e059042014-10-16 10:55:19 -05003631 break;
3632 }
3633
3634 weston_matrix_scale(matrix, vp->buffer.scale, vp->buffer.scale, 1);
3635}
3636
Pekka Paalanend9aae9c2016-04-26 13:46:38 +03003637/**
3638 * Compute a + b > c while being safe to overflows.
3639 */
3640static bool
3641fixed_sum_gt(wl_fixed_t a, wl_fixed_t b, wl_fixed_t c)
3642{
3643 return (int64_t)a + (int64_t)b > (int64_t)c;
3644}
3645
3646static bool
3647weston_surface_is_pending_viewport_source_valid(
3648 const struct weston_surface *surface)
3649{
3650 const struct weston_surface_state *pend = &surface->pending;
3651 const struct weston_buffer_viewport *vp = &pend->buffer_viewport;
3652 int width_from_buffer = 0;
3653 int height_from_buffer = 0;
3654 wl_fixed_t w;
3655 wl_fixed_t h;
3656
3657 /* If viewport source rect is not set, it is always ok. */
3658 if (vp->buffer.src_width == wl_fixed_from_int(-1))
3659 return true;
3660
3661 if (pend->newly_attached) {
3662 if (pend->buffer) {
3663 convert_size_by_transform_scale(&width_from_buffer,
3664 &height_from_buffer,
3665 pend->buffer->width,
3666 pend->buffer->height,
3667 vp->buffer.transform,
3668 vp->buffer.scale);
3669 } else {
3670 /* No buffer: viewport is irrelevant. */
3671 return true;
3672 }
3673 } else {
3674 width_from_buffer = surface->width_from_buffer;
3675 height_from_buffer = surface->height_from_buffer;
3676 }
3677
3678 assert((width_from_buffer == 0) == (height_from_buffer == 0));
3679 assert(width_from_buffer >= 0 && height_from_buffer >= 0);
3680
3681 /* No buffer: viewport is irrelevant. */
3682 if (width_from_buffer == 0 || height_from_buffer == 0)
3683 return true;
3684
3685 /* overflow checks for wl_fixed_from_int() */
3686 if (width_from_buffer > wl_fixed_to_int(INT32_MAX))
3687 return false;
3688 if (height_from_buffer > wl_fixed_to_int(INT32_MAX))
3689 return false;
3690
3691 w = wl_fixed_from_int(width_from_buffer);
3692 h = wl_fixed_from_int(height_from_buffer);
3693
3694 if (fixed_sum_gt(vp->buffer.src_x, vp->buffer.src_width, w))
3695 return false;
3696 if (fixed_sum_gt(vp->buffer.src_y, vp->buffer.src_height, h))
3697 return false;
3698
3699 return true;
3700}
3701
Pekka Paalanenbb32ccc2016-04-26 14:28:28 +03003702static bool
3703fixed_is_integer(wl_fixed_t v)
3704{
3705 return (v & 0xff) == 0;
3706}
3707
3708static bool
3709weston_surface_is_pending_viewport_dst_size_int(
3710 const struct weston_surface *surface)
3711{
3712 const struct weston_buffer_viewport *vp =
3713 &surface->pending.buffer_viewport;
3714
3715 if (vp->surface.width != -1) {
3716 assert(vp->surface.width > 0 && vp->surface.height > 0);
3717 return true;
3718 }
3719
3720 return fixed_is_integer(vp->buffer.src_width) &&
3721 fixed_is_integer(vp->buffer.src_height);
3722}
3723
Derek Foreman152254b2015-11-26 14:17:48 -06003724/* Translate pending damage in buffer co-ordinates to surface
3725 * co-ordinates and union it with a pixman_region32_t.
3726 * This should only be called after the buffer is attached.
3727 */
3728static void
3729apply_damage_buffer(pixman_region32_t *dest,
3730 struct weston_surface *surface,
3731 struct weston_surface_state *state)
3732{
3733 struct weston_buffer *buffer = surface->buffer_ref.buffer;
3734
3735 /* wl_surface.damage_buffer needs to be clipped to the buffer,
3736 * translated into surface co-ordinates and unioned with
3737 * any other surface damage.
3738 * None of this makes sense if there is no buffer though.
3739 */
3740 if (buffer && pixman_region32_not_empty(&state->damage_buffer)) {
3741 pixman_region32_t buffer_damage;
3742
3743 pixman_region32_intersect_rect(&state->damage_buffer,
3744 &state->damage_buffer,
3745 0, 0, buffer->width,
3746 buffer->height);
3747 pixman_region32_init(&buffer_damage);
3748 weston_matrix_transform_region(&buffer_damage,
3749 &surface->buffer_to_surface_matrix,
3750 &state->damage_buffer);
3751 pixman_region32_union(dest, dest, &buffer_damage);
3752 pixman_region32_fini(&buffer_damage);
3753 }
3754 /* We should clear this on commit even if there was no buffer */
3755 pixman_region32_clear(&state->damage_buffer);
3756}
3757
Jason Ekstrand1e059042014-10-16 10:55:19 -05003758static void
Ankit Nautiyal4b6e73d2019-03-26 13:37:12 +05303759weston_surface_set_desired_protection(struct weston_surface *surface,
3760 enum weston_hdcp_protection protection)
3761{
3762 if (surface->desired_protection == protection)
3763 return;
3764 surface->desired_protection = protection;
3765 weston_surface_damage(surface);
3766}
3767
3768static void
Ankit Nautiyal5cfe03c2019-03-28 15:05:42 +05303769weston_surface_set_protection_mode(struct weston_surface *surface,
3770 enum weston_surface_protection_mode p_mode)
3771{
3772 struct content_protection *cp = surface->compositor->content_protection;
3773 struct protected_surface *psurface;
3774
3775 surface->protection_mode = p_mode;
3776 wl_list_for_each(psurface, &cp->protected_list, link) {
3777 if (!psurface || psurface->surface != surface)
3778 continue;
3779 weston_protected_surface_send_event(psurface,
3780 surface->current_protection);
3781 }
3782}
3783
3784static void
Jason Ekstrand7b982072014-05-20 14:33:03 -05003785weston_surface_commit_state(struct weston_surface *surface,
3786 struct weston_surface_state *state)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003787{
Jason Ekstranda7af7042013-10-12 22:38:11 -05003788 struct weston_view *view;
Ander Conselvan de Oliveira5df8eca2012-10-30 17:44:01 +02003789 pixman_region32_t opaque;
3790
Alexander Larsson4ea95522013-05-22 14:41:37 +02003791 /* wl_surface.set_buffer_transform */
Alexander Larsson4ea95522013-05-22 14:41:37 +02003792 /* wl_surface.set_buffer_scale */
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03003793 /* wp_viewport.set_source */
3794 /* wp_viewport.set_destination */
Jason Ekstrand7b982072014-05-20 14:33:03 -05003795 surface->buffer_viewport = state->buffer_viewport;
Alexander Larsson4ea95522013-05-22 14:41:37 +02003796
Pekka Paalanen5df44de2012-10-10 12:49:23 +03003797 /* wl_surface.attach */
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003798 if (state->newly_attached) {
3799 /* zwp_surface_synchronization_v1.set_acquire_fence */
3800 fd_move(&surface->acquire_fence_fd,
3801 &state->acquire_fence_fd);
Alexandros Frantzis67629672018-10-19 12:14:11 +03003802 /* zwp_surface_synchronization_v1.get_release */
3803 weston_buffer_release_move(&surface->buffer_release_ref,
3804 &state->buffer_release_ref);
Jason Ekstrand7b982072014-05-20 14:33:03 -05003805 weston_surface_attach(surface, state->buffer);
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003806 }
Jason Ekstrand7b982072014-05-20 14:33:03 -05003807 weston_surface_state_set_buffer(state, NULL);
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003808 assert(state->acquire_fence_fd == -1);
Alexandros Frantzis67629672018-10-19 12:14:11 +03003809 assert(state->buffer_release_ref.buffer_release == NULL);
Giulio Camuffo184df502013-02-21 11:29:21 +01003810
Jason Ekstrand1e059042014-10-16 10:55:19 -05003811 weston_surface_build_buffer_matrix(surface,
3812 &surface->surface_to_buffer_matrix);
3813 weston_matrix_invert(&surface->buffer_to_surface_matrix,
3814 &surface->surface_to_buffer_matrix);
3815
Jason Ekstrand7b982072014-05-20 14:33:03 -05003816 if (state->newly_attached || state->buffer_viewport.changed) {
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003817 weston_surface_update_size(surface);
Quentin Glidic2edc3d52016-08-12 10:41:33 +02003818 if (surface->committed)
3819 surface->committed(surface, state->sx, state->sy);
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003820 }
Giulio Camuffo184df502013-02-21 11:29:21 +01003821
Jason Ekstrand7b982072014-05-20 14:33:03 -05003822 state->sx = 0;
3823 state->sy = 0;
3824 state->newly_attached = 0;
3825 state->buffer_viewport.changed = 0;
Pekka Paalanen8e159182012-10-10 12:49:25 +03003826
Derek Foreman152254b2015-11-26 14:17:48 -06003827 /* wl_surface.damage and wl_surface.damage_buffer */
Marius Vlad2a1b7862019-09-05 13:12:18 +03003828 if (pixman_region32_not_empty(&state->damage_surface) ||
3829 pixman_region32_not_empty(&state->damage_buffer))
Marius Vlad3203ff62019-09-05 14:56:12 +03003830 TL_POINT(surface->compositor, "core_commit_damage", TLP_SURFACE(surface), TLP_END);
Derek Foreman152254b2015-11-26 14:17:48 -06003831
Pekka Paalanen8e159182012-10-10 12:49:25 +03003832 pixman_region32_union(&surface->damage, &surface->damage,
Derek Foreman152254b2015-11-26 14:17:48 -06003833 &state->damage_surface);
3834
3835 apply_damage_buffer(&surface->damage, surface, state);
3836
Kristian Høgsberg4d0214c2012-11-08 11:36:02 -05003837 pixman_region32_intersect_rect(&surface->damage, &surface->damage,
Jason Ekstrandef540082014-06-26 10:37:36 -07003838 0, 0, surface->width, surface->height);
Derek Foreman152254b2015-11-26 14:17:48 -06003839 pixman_region32_clear(&state->damage_surface);
Pekka Paalanen512dde82012-10-10 12:49:27 +03003840
3841 /* wl_surface.set_opaque_region */
Jason Ekstrand7b982072014-05-20 14:33:03 -05003842 pixman_region32_init(&opaque);
3843 pixman_region32_intersect_rect(&opaque, &state->opaque,
3844 0, 0, surface->width, surface->height);
Ander Conselvan de Oliveira5df8eca2012-10-30 17:44:01 +02003845
3846 if (!pixman_region32_equal(&opaque, &surface->opaque)) {
3847 pixman_region32_copy(&surface->opaque, &opaque);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003848 wl_list_for_each(view, &surface->views, surface_link)
3849 weston_view_geometry_dirty(view);
Ander Conselvan de Oliveira5df8eca2012-10-30 17:44:01 +02003850 }
3851
3852 pixman_region32_fini(&opaque);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03003853
3854 /* wl_surface.set_input_region */
Jason Ekstrand7b982072014-05-20 14:33:03 -05003855 pixman_region32_intersect_rect(&surface->input, &state->input,
3856 0, 0, surface->width, surface->height);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03003857
Pekka Paalanenbc106382012-10-10 12:49:31 +03003858 /* wl_surface.frame */
3859 wl_list_insert_list(&surface->frame_callback_list,
Jason Ekstrand7b982072014-05-20 14:33:03 -05003860 &state->frame_callback_list);
3861 wl_list_init(&state->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -04003862
3863 /* XXX:
3864 * What should happen with a feedback request, if there
3865 * is no wl_buffer attached for this commit?
3866 */
3867
3868 /* presentation.feedback */
3869 wl_list_insert_list(&surface->feedback_list,
3870 &state->feedback_list);
3871 wl_list_init(&state->feedback_list);
Jonas Ådahl5d9ca272016-07-22 17:48:03 +08003872
Ankit Nautiyal5cfe03c2019-03-28 15:05:42 +05303873 /* weston_protected_surface.enforced/relaxed */
3874 if (surface->protection_mode != state->protection_mode)
3875 weston_surface_set_protection_mode(surface,
3876 state->protection_mode);
3877
Ankit Nautiyal4b6e73d2019-03-26 13:37:12 +05303878 /* weston_protected_surface.set_type */
3879 weston_surface_set_desired_protection(surface, state->desired_protection);
3880
Jonas Ådahl5d9ca272016-07-22 17:48:03 +08003881 wl_signal_emit(&surface->commit_signal, surface);
Jason Ekstrand7b982072014-05-20 14:33:03 -05003882}
3883
3884static void
3885weston_surface_commit(struct weston_surface *surface)
3886{
3887 weston_surface_commit_state(surface, &surface->pending);
Pekka Paalanenbc106382012-10-10 12:49:31 +03003888
Pekka Paalanene67858b2013-04-25 13:57:42 +03003889 weston_surface_commit_subsurface_order(surface);
3890
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03003891 weston_surface_schedule_repaint(surface);
Pekka Paalanen5df44de2012-10-10 12:49:23 +03003892}
3893
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003894static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03003895weston_subsurface_commit(struct weston_subsurface *sub);
3896
3897static void
3898weston_subsurface_parent_commit(struct weston_subsurface *sub,
3899 int parent_is_synchronized);
3900
3901static void
3902surface_commit(struct wl_client *client, struct wl_resource *resource)
3903{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003904 struct weston_surface *surface = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003905 struct weston_subsurface *sub = weston_surface_to_subsurface(surface);
3906
Pekka Paalanend9aae9c2016-04-26 13:46:38 +03003907 if (!weston_surface_is_pending_viewport_source_valid(surface)) {
3908 assert(surface->viewport_resource);
3909
3910 wl_resource_post_error(surface->viewport_resource,
3911 WP_VIEWPORT_ERROR_OUT_OF_BUFFER,
3912 "wl_surface@%d has viewport source outside buffer",
3913 wl_resource_get_id(resource));
3914 return;
3915 }
3916
Pekka Paalanenbb32ccc2016-04-26 14:28:28 +03003917 if (!weston_surface_is_pending_viewport_dst_size_int(surface)) {
3918 assert(surface->viewport_resource);
3919
3920 wl_resource_post_error(surface->viewport_resource,
3921 WP_VIEWPORT_ERROR_BAD_SIZE,
3922 "wl_surface@%d viewport dst size not integer",
3923 wl_resource_get_id(resource));
3924 return;
3925 }
3926
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003927 if (surface->pending.acquire_fence_fd >= 0) {
3928 assert(surface->synchronization_resource);
3929
3930 if (!surface->pending.buffer) {
3931 fd_clear(&surface->pending.acquire_fence_fd);
3932 wl_resource_post_error(surface->synchronization_resource,
3933 ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_NO_BUFFER,
3934 "wl_surface@%"PRIu32" no buffer for synchronization",
3935 wl_resource_get_id(resource));
3936 return;
3937 }
3938
3939 /* We support fences for both wp_linux_dmabuf and opaque EGL
3940 * buffers, as mandated by minor version 2 of the
3941 * zwp_linux_explicit_synchronization_v1 protocol. Since
3942 * renderers that support fences currently only support these
3943 * two buffer types plus SHM buffers, we can just check for the
3944 * SHM buffer case here.
3945 */
3946 if (wl_shm_buffer_get(surface->pending.buffer->resource)) {
3947 fd_clear(&surface->pending.acquire_fence_fd);
3948 wl_resource_post_error(surface->synchronization_resource,
3949 ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_UNSUPPORTED_BUFFER,
3950 "wl_surface@%"PRIu32" unsupported buffer for synchronization",
3951 wl_resource_get_id(resource));
3952 return;
3953 }
3954 }
3955
Alexandros Frantzis67629672018-10-19 12:14:11 +03003956 if (surface->pending.buffer_release_ref.buffer_release &&
3957 !surface->pending.buffer) {
3958 assert(surface->synchronization_resource);
3959
3960 wl_resource_post_error(surface->synchronization_resource,
3961 ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_NO_BUFFER,
3962 "wl_surface@%"PRIu32" no buffer for synchronization",
3963 wl_resource_get_id(resource));
3964 return;
3965 }
3966
Pekka Paalanene67858b2013-04-25 13:57:42 +03003967 if (sub) {
3968 weston_subsurface_commit(sub);
3969 return;
3970 }
3971
3972 weston_surface_commit(surface);
3973
3974 wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
3975 if (sub->surface != surface)
3976 weston_subsurface_parent_commit(sub, 0);
3977 }
3978}
3979
3980static void
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003981surface_set_buffer_transform(struct wl_client *client,
3982 struct wl_resource *resource, int transform)
3983{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003984 struct weston_surface *surface = wl_resource_get_user_data(resource);
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003985
Jonny Lamba55f1392014-05-30 12:07:15 +02003986 /* if wl_output.transform grows more members this will need to be updated. */
3987 if (transform < 0 ||
3988 transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) {
3989 wl_resource_post_error(resource,
3990 WL_SURFACE_ERROR_INVALID_TRANSFORM,
3991 "buffer transform must be a valid transform "
3992 "('%d' specified)", transform);
3993 return;
3994 }
3995
Pekka Paalanen952b6c82014-03-14 14:38:15 +02003996 surface->pending.buffer_viewport.buffer.transform = transform;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003997 surface->pending.buffer_viewport.changed = 1;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003998}
3999
Alexander Larsson4ea95522013-05-22 14:41:37 +02004000static void
4001surface_set_buffer_scale(struct wl_client *client,
4002 struct wl_resource *resource,
Alexander Larssonedddbd12013-05-24 13:09:43 +02004003 int32_t scale)
Alexander Larsson4ea95522013-05-22 14:41:37 +02004004{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05004005 struct weston_surface *surface = wl_resource_get_user_data(resource);
Alexander Larsson4ea95522013-05-22 14:41:37 +02004006
Jonny Lamba55f1392014-05-30 12:07:15 +02004007 if (scale < 1) {
4008 wl_resource_post_error(resource,
4009 WL_SURFACE_ERROR_INVALID_SCALE,
4010 "buffer scale must be at least one "
4011 "('%d' specified)", scale);
4012 return;
4013 }
4014
Pekka Paalanen952b6c82014-03-14 14:38:15 +02004015 surface->pending.buffer_viewport.buffer.scale = scale;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02004016 surface->pending.buffer_viewport.changed = 1;
Alexander Larsson4ea95522013-05-22 14:41:37 +02004017}
4018
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04004019static const struct wl_surface_interface surface_interface = {
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05004020 surface_destroy,
4021 surface_attach,
Kristian Høgsberg33418202011-08-16 23:01:28 -04004022 surface_damage,
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05004023 surface_frame,
4024 surface_set_opaque_region,
Pekka Paalanen5df44de2012-10-10 12:49:23 +03004025 surface_set_input_region,
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02004026 surface_commit,
Alexander Larsson4ea95522013-05-22 14:41:37 +02004027 surface_set_buffer_transform,
Derek Foreman152254b2015-11-26 14:17:48 -06004028 surface_set_buffer_scale,
4029 surface_damage_buffer
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05004030};
4031
4032static void
4033compositor_create_surface(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -04004034 struct wl_resource *resource, uint32_t id)
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05004035{
Kristian Høgsbergc2d70422013-06-25 15:34:33 -04004036 struct weston_compositor *ec = wl_resource_get_user_data(resource);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004037 struct weston_surface *surface;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05004038
Kristian Høgsberg18c93002012-01-27 11:58:31 -05004039 surface = weston_surface_create(ec);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04004040 if (surface == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -04004041 wl_resource_post_no_memory(resource);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05004042 return;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04004043 }
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05004044
Jason Ekstranda85118c2013-06-27 20:17:02 -05004045 surface->resource =
4046 wl_resource_create(client, &wl_surface_interface,
4047 wl_resource_get_version(resource), id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07004048 if (surface->resource == NULL) {
4049 weston_surface_destroy(surface);
4050 wl_resource_post_no_memory(resource);
4051 return;
4052 }
Jason Ekstranda85118c2013-06-27 20:17:02 -05004053 wl_resource_set_implementation(surface->resource, &surface_interface,
4054 surface, destroy_surface);
Kristian Høgsbergf03a04a2014-04-06 22:04:50 -07004055
4056 wl_signal_emit(&ec->create_surface_signal, surface);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05004057}
4058
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05004059static void
4060destroy_region(struct wl_resource *resource)
4061{
Jason Ekstrand8895efc2013-06-14 10:07:56 -05004062 struct weston_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05004063
4064 pixman_region32_fini(&region->region);
4065 free(region);
4066}
4067
4068static void
4069region_destroy(struct wl_client *client, struct wl_resource *resource)
4070{
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04004071 wl_resource_destroy(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05004072}
4073
4074static void
4075region_add(struct wl_client *client, struct wl_resource *resource,
4076 int32_t x, int32_t y, int32_t width, int32_t height)
4077{
Jason Ekstrand8895efc2013-06-14 10:07:56 -05004078 struct weston_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05004079
4080 pixman_region32_union_rect(&region->region, &region->region,
4081 x, y, width, height);
4082}
4083
4084static void
4085region_subtract(struct wl_client *client, struct wl_resource *resource,
4086 int32_t x, int32_t y, int32_t width, int32_t height)
4087{
Jason Ekstrand8895efc2013-06-14 10:07:56 -05004088 struct weston_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05004089 pixman_region32_t rect;
4090
4091 pixman_region32_init_rect(&rect, x, y, width, height);
4092 pixman_region32_subtract(&region->region, &region->region, &rect);
4093 pixman_region32_fini(&rect);
4094}
4095
4096static const struct wl_region_interface region_interface = {
4097 region_destroy,
4098 region_add,
4099 region_subtract
4100};
4101
4102static void
4103compositor_create_region(struct wl_client *client,
4104 struct wl_resource *resource, uint32_t id)
4105{
4106 struct weston_region *region;
4107
4108 region = malloc(sizeof *region);
4109 if (region == NULL) {
4110 wl_resource_post_no_memory(resource);
4111 return;
4112 }
4113
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05004114 pixman_region32_init(&region->region);
4115
Jason Ekstranda85118c2013-06-27 20:17:02 -05004116 region->resource =
4117 wl_resource_create(client, &wl_region_interface, 1, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07004118 if (region->resource == NULL) {
4119 free(region);
4120 wl_resource_post_no_memory(resource);
4121 return;
4122 }
Jason Ekstranda85118c2013-06-27 20:17:02 -05004123 wl_resource_set_implementation(region->resource, &region_interface,
4124 region, destroy_region);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05004125}
4126
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04004127static const struct wl_compositor_interface compositor_interface = {
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05004128 compositor_create_surface,
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05004129 compositor_create_region
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05004130};
4131
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004132static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03004133weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
4134{
4135 struct weston_surface *surface = sub->surface;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004136
Jason Ekstrand7b982072014-05-20 14:33:03 -05004137 weston_surface_commit_state(surface, &sub->cached);
4138 weston_buffer_reference(&sub->cached_buffer_ref, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004139
4140 weston_surface_commit_subsurface_order(surface);
4141
4142 weston_surface_schedule_repaint(surface);
4143
Jason Ekstrand7b982072014-05-20 14:33:03 -05004144 sub->has_cached_data = 0;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004145}
4146
4147static void
4148weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
4149{
4150 struct weston_surface *surface = sub->surface;
4151
4152 /*
4153 * If this commit would cause the surface to move by the
4154 * attach(dx, dy) parameters, the old damage region must be
4155 * translated to correspond to the new surface coordinate system
Chris Michael062edf22015-11-26 11:30:00 -05004156 * origin.
Pekka Paalanene67858b2013-04-25 13:57:42 +03004157 */
Derek Foreman152254b2015-11-26 14:17:48 -06004158 pixman_region32_translate(&sub->cached.damage_surface,
Pekka Paalanene67858b2013-04-25 13:57:42 +03004159 -surface->pending.sx, -surface->pending.sy);
Derek Foreman152254b2015-11-26 14:17:48 -06004160 pixman_region32_union(&sub->cached.damage_surface,
4161 &sub->cached.damage_surface,
4162 &surface->pending.damage_surface);
4163 pixman_region32_clear(&surface->pending.damage_surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004164
4165 if (surface->pending.newly_attached) {
4166 sub->cached.newly_attached = 1;
Jason Ekstrand7b982072014-05-20 14:33:03 -05004167 weston_surface_state_set_buffer(&sub->cached,
4168 surface->pending.buffer);
4169 weston_buffer_reference(&sub->cached_buffer_ref,
Pekka Paalanene67858b2013-04-25 13:57:42 +03004170 surface->pending.buffer);
Pekka Paalanen133e4392014-09-23 22:08:46 -04004171 weston_presentation_feedback_discard_list(
4172 &sub->cached.feedback_list);
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03004173 /* zwp_surface_synchronization_v1.set_acquire_fence */
4174 fd_move(&sub->cached.acquire_fence_fd,
4175 &surface->pending.acquire_fence_fd);
Alexandros Frantzis67629672018-10-19 12:14:11 +03004176 /* zwp_surface_synchronization_v1.get_release */
4177 weston_buffer_release_move(&sub->cached.buffer_release_ref,
4178 &surface->pending.buffer_release_ref);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004179 }
Ankit Nautiyal4b6e73d2019-03-26 13:37:12 +05304180 sub->cached.desired_protection = surface->pending.desired_protection;
Ankit Nautiyal5cfe03c2019-03-28 15:05:42 +05304181 sub->cached.protection_mode = surface->pending.protection_mode;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03004182 assert(surface->pending.acquire_fence_fd == -1);
Alexandros Frantzis67629672018-10-19 12:14:11 +03004183 assert(surface->pending.buffer_release_ref.buffer_release == NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004184 sub->cached.sx += surface->pending.sx;
4185 sub->cached.sy += surface->pending.sy;
Pekka Paalanen260ba382014-03-14 14:38:12 +02004186
Derek Foreman152254b2015-11-26 14:17:48 -06004187 apply_damage_buffer(&sub->cached.damage_surface, surface, &surface->pending);
4188
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02004189 sub->cached.buffer_viewport.changed |=
4190 surface->pending.buffer_viewport.changed;
4191 sub->cached.buffer_viewport.buffer =
4192 surface->pending.buffer_viewport.buffer;
4193 sub->cached.buffer_viewport.surface =
4194 surface->pending.buffer_viewport.surface;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004195
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02004196 weston_surface_reset_pending_buffer(surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004197
4198 pixman_region32_copy(&sub->cached.opaque, &surface->pending.opaque);
4199
4200 pixman_region32_copy(&sub->cached.input, &surface->pending.input);
4201
4202 wl_list_insert_list(&sub->cached.frame_callback_list,
4203 &surface->pending.frame_callback_list);
4204 wl_list_init(&surface->pending.frame_callback_list);
4205
Pekka Paalanen133e4392014-09-23 22:08:46 -04004206 wl_list_insert_list(&sub->cached.feedback_list,
4207 &surface->pending.feedback_list);
4208 wl_list_init(&surface->pending.feedback_list);
4209
Jason Ekstrand7b982072014-05-20 14:33:03 -05004210 sub->has_cached_data = 1;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004211}
4212
Derek Foreman280e7dd2014-10-03 13:13:42 -05004213static bool
Pekka Paalanene67858b2013-04-25 13:57:42 +03004214weston_subsurface_is_synchronized(struct weston_subsurface *sub)
4215{
4216 while (sub) {
4217 if (sub->synchronized)
Derek Foreman280e7dd2014-10-03 13:13:42 -05004218 return true;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004219
4220 if (!sub->parent)
Derek Foreman280e7dd2014-10-03 13:13:42 -05004221 return false;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004222
4223 sub = weston_surface_to_subsurface(sub->parent);
4224 }
4225
Carlos Olmedo Escobar61a9bf52014-11-04 14:38:39 +01004226 return false;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004227}
4228
4229static void
4230weston_subsurface_commit(struct weston_subsurface *sub)
4231{
4232 struct weston_surface *surface = sub->surface;
4233 struct weston_subsurface *tmp;
4234
4235 /* Recursive check for effectively synchronized. */
4236 if (weston_subsurface_is_synchronized(sub)) {
4237 weston_subsurface_commit_to_cache(sub);
4238 } else {
Jason Ekstrand7b982072014-05-20 14:33:03 -05004239 if (sub->has_cached_data) {
Pekka Paalanene67858b2013-04-25 13:57:42 +03004240 /* flush accumulated state from cache */
4241 weston_subsurface_commit_to_cache(sub);
4242 weston_subsurface_commit_from_cache(sub);
4243 } else {
4244 weston_surface_commit(surface);
4245 }
4246
4247 wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
4248 if (tmp->surface != surface)
4249 weston_subsurface_parent_commit(tmp, 0);
4250 }
4251 }
4252}
4253
4254static void
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03004255weston_subsurface_synchronized_commit(struct weston_subsurface *sub)
Pekka Paalanene67858b2013-04-25 13:57:42 +03004256{
4257 struct weston_surface *surface = sub->surface;
4258 struct weston_subsurface *tmp;
4259
Pekka Paalanene67858b2013-04-25 13:57:42 +03004260 /* From now on, commit_from_cache the whole sub-tree, regardless of
4261 * the synchronized mode of each child. This sub-surface or some
4262 * of its ancestors were synchronized, so we are synchronized
4263 * all the way down.
4264 */
4265
Jason Ekstrand7b982072014-05-20 14:33:03 -05004266 if (sub->has_cached_data)
Pekka Paalanene67858b2013-04-25 13:57:42 +03004267 weston_subsurface_commit_from_cache(sub);
4268
4269 wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
4270 if (tmp->surface != surface)
4271 weston_subsurface_parent_commit(tmp, 1);
4272 }
4273}
4274
4275static void
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03004276weston_subsurface_parent_commit(struct weston_subsurface *sub,
4277 int parent_is_synchronized)
4278{
Jason Ekstranda7af7042013-10-12 22:38:11 -05004279 struct weston_view *view;
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03004280 if (sub->position.set) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004281 wl_list_for_each(view, &sub->surface->views, surface_link)
4282 weston_view_set_position(view,
4283 sub->position.x,
4284 sub->position.y);
4285
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03004286 sub->position.set = 0;
4287 }
4288
4289 if (parent_is_synchronized || sub->synchronized)
4290 weston_subsurface_synchronized_commit(sub);
4291}
4292
Pekka Paalanen8274d902014-08-06 19:36:51 +03004293static int
4294subsurface_get_label(struct weston_surface *surface, char *buf, size_t len)
4295{
4296 return snprintf(buf, len, "sub-surface");
4297}
4298
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03004299static void
Quentin Glidic2edc3d52016-08-12 10:41:33 +02004300subsurface_committed(struct weston_surface *surface, int32_t dx, int32_t dy)
Pekka Paalanene67858b2013-04-25 13:57:42 +03004301{
Jason Ekstranda7af7042013-10-12 22:38:11 -05004302 struct weston_view *view;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004303
Jason Ekstranda7af7042013-10-12 22:38:11 -05004304 wl_list_for_each(view, &surface->views, surface_link)
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004305 weston_view_set_position(view,
4306 view->geometry.x + dx,
4307 view->geometry.y + dy);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004308
4309 /* No need to check parent mappedness, because if parent is not
4310 * mapped, parent is not in a visible layer, so this sub-surface
4311 * will not be drawn either.
4312 */
Armin Krezovićf8486c32016-06-30 06:04:28 +02004313
Pekka Paalanene67858b2013-04-25 13:57:42 +03004314 if (!weston_surface_is_mapped(surface)) {
Armin Krezovićf8486c32016-06-30 06:04:28 +02004315 surface->is_mapped = true;
Pekka Paalaneneb3cf222014-06-30 11:52:07 +03004316
Derek Foreman4b1a0a12014-09-10 15:37:33 -05004317 /* Cannot call weston_view_update_transform(),
Pekka Paalanene67858b2013-04-25 13:57:42 +03004318 * because that would call it also for the parent surface,
4319 * which might not be mapped yet. That would lead to
4320 * inconsistent state, where the window could never be
4321 * mapped.
4322 *
Armin Krezovićf8486c32016-06-30 06:04:28 +02004323 * Instead just force the is_mapped flag on, to make
Pekka Paalanene67858b2013-04-25 13:57:42 +03004324 * weston_surface_is_mapped() return true, so that when the
4325 * parent surface does get mapped, this one will get
Pekka Paalaneneb3cf222014-06-30 11:52:07 +03004326 * included, too. See view_list_add().
Pekka Paalanene67858b2013-04-25 13:57:42 +03004327 */
Pekka Paalanene67858b2013-04-25 13:57:42 +03004328 }
4329}
4330
4331static struct weston_subsurface *
4332weston_surface_to_subsurface(struct weston_surface *surface)
4333{
Quentin Glidic2edc3d52016-08-12 10:41:33 +02004334 if (surface->committed == subsurface_committed)
4335 return surface->committed_private;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004336
4337 return NULL;
4338}
4339
Pekka Paalanen01388e22013-04-25 13:57:44 +03004340WL_EXPORT struct weston_surface *
4341weston_surface_get_main_surface(struct weston_surface *surface)
4342{
4343 struct weston_subsurface *sub;
4344
4345 while (surface && (sub = weston_surface_to_subsurface(surface)))
4346 surface = sub->parent;
4347
4348 return surface;
4349}
4350
Pekka Paalanen50b67472014-10-01 15:02:41 +03004351WL_EXPORT int
4352weston_surface_set_role(struct weston_surface *surface,
4353 const char *role_name,
4354 struct wl_resource *error_resource,
4355 uint32_t error_code)
4356{
4357 assert(role_name);
4358
4359 if (surface->role_name == NULL ||
4360 surface->role_name == role_name ||
4361 strcmp(surface->role_name, role_name) == 0) {
4362 surface->role_name = role_name;
4363
4364 return 0;
4365 }
4366
4367 wl_resource_post_error(error_resource, error_code,
4368 "Cannot assign role %s to wl_surface@%d,"
4369 " already has role %s\n",
4370 role_name,
4371 wl_resource_get_id(surface->resource),
4372 surface->role_name);
4373 return -1;
4374}
4375
Quentin Glidic9c5dd7e2016-08-12 10:41:37 +02004376WL_EXPORT const char *
4377weston_surface_get_role(struct weston_surface *surface)
4378{
4379 return surface->role_name;
4380}
4381
Pekka Paalanen8274d902014-08-06 19:36:51 +03004382WL_EXPORT void
4383weston_surface_set_label_func(struct weston_surface *surface,
4384 int (*desc)(struct weston_surface *,
4385 char *, size_t))
4386{
4387 surface->get_label = desc;
Marius Vlad5de92972019-10-15 13:25:41 +03004388 weston_timeline_refresh_subscription_objects(surface->compositor,
4389 surface);
Pekka Paalanen8274d902014-08-06 19:36:51 +03004390}
4391
Pekka Paalanenc647ed72015-02-09 13:16:57 +02004392/** Get the size of surface contents
4393 *
4394 * \param surface The surface to query.
4395 * \param width Returns the width of raw contents.
4396 * \param height Returns the height of raw contents.
4397 *
4398 * Retrieves the raw surface content size in pixels for the given surface.
4399 * This is the whole content size in buffer pixels. If the surface
4400 * has no content or the renderer does not implement this feature,
4401 * zeroes are returned.
4402 *
4403 * This function is used to determine the buffer size needed for
4404 * a weston_surface_copy_content() call.
4405 */
4406WL_EXPORT void
4407weston_surface_get_content_size(struct weston_surface *surface,
4408 int *width, int *height)
4409{
4410 struct weston_renderer *rer = surface->compositor->renderer;
4411
4412 if (!rer->surface_get_content_size) {
4413 *width = 0;
4414 *height = 0;
4415 return;
4416 }
4417
4418 rer->surface_get_content_size(surface, width, height);
4419}
4420
Quentin Glidic248dd102016-08-12 10:41:34 +02004421/** Get the bounding box of a surface and its subsurfaces
4422 *
4423 * \param surface The surface to query.
4424 * \return The bounding box relative to the surface origin.
4425 *
4426 */
4427WL_EXPORT struct weston_geometry
4428weston_surface_get_bounding_box(struct weston_surface *surface)
4429{
4430 pixman_region32_t region;
4431 pixman_box32_t *box;
4432 struct weston_subsurface *subsurface;
4433
4434 pixman_region32_init_rect(&region,
4435 0, 0,
4436 surface->width, surface->height);
4437
4438 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link)
4439 pixman_region32_union_rect(&region, &region,
4440 subsurface->position.x,
4441 subsurface->position.y,
4442 subsurface->surface->width,
4443 subsurface->surface->height);
4444
4445 box = pixman_region32_extents(&region);
4446 struct weston_geometry geometry = {
4447 .x = box->x1,
4448 .y = box->y1,
4449 .width = box->x2 - box->x1,
4450 .height = box->y2 - box->y1,
4451 };
4452
4453 pixman_region32_fini(&region);
4454
4455 return geometry;
4456}
4457
Pekka Paalanenc647ed72015-02-09 13:16:57 +02004458/** Copy surface contents to system memory.
4459 *
4460 * \param surface The surface to copy from.
4461 * \param target Pointer to the target memory buffer.
4462 * \param size Size of the target buffer in bytes.
4463 * \param src_x X location on contents to copy from.
4464 * \param src_y Y location on contents to copy from.
4465 * \param width Width in pixels of the area to copy.
4466 * \param height Height in pixels of the area to copy.
4467 * \return 0 for success, -1 for failure.
4468 *
4469 * Surface contents are maintained by the renderer. They can be in a
4470 * reserved weston_buffer or as a copy, e.g. a GL texture, or something
4471 * else.
4472 *
4473 * Surface contents are copied into memory pointed to by target,
4474 * which has size bytes of space available. The target memory
4475 * may be larger than needed, but being smaller returns an error.
4476 * The extra bytes in target may or may not be written; their content is
4477 * unspecified. Size must be large enough to hold the image.
4478 *
4479 * The image in the target memory will be arranged in rows from
4480 * top to bottom, and pixels on a row from left to right. The pixel
4481 * format is PIXMAN_a8b8g8r8, 4 bytes per pixel, and stride is exactly
4482 * width * 4.
4483 *
4484 * Parameters src_x and src_y define the upper-left corner in buffer
4485 * coordinates (pixels) to copy from. Parameters width and height
4486 * define the size of the area to copy in pixels.
4487 *
4488 * The rectangle defined by src_x, src_y, width, height must fit in
4489 * the surface contents. Otherwise an error is returned.
4490 *
Changwoo Chof97d2502017-08-05 00:30:47 +09004491 * Use weston_surface_get_content_size to determine the content size; the
Pekka Paalanenc647ed72015-02-09 13:16:57 +02004492 * needed target buffer size and rectangle limits.
4493 *
4494 * CURRENT IMPLEMENTATION RESTRICTIONS:
4495 * - the machine must be little-endian due to Pixman formats.
4496 *
4497 * NOTE: Pixman formats are premultiplied.
4498 */
4499WL_EXPORT int
4500weston_surface_copy_content(struct weston_surface *surface,
4501 void *target, size_t size,
4502 int src_x, int src_y,
4503 int width, int height)
4504{
4505 struct weston_renderer *rer = surface->compositor->renderer;
4506 int cw, ch;
4507 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
4508
4509 if (!rer->surface_copy_content)
4510 return -1;
4511
4512 weston_surface_get_content_size(surface, &cw, &ch);
4513
4514 if (src_x < 0 || src_y < 0)
4515 return -1;
4516
4517 if (width <= 0 || height <= 0)
4518 return -1;
4519
4520 if (src_x + width > cw || src_y + height > ch)
4521 return -1;
4522
4523 if (width * bytespp * height > size)
4524 return -1;
4525
4526 return rer->surface_copy_content(surface, target, size,
4527 src_x, src_y, width, height);
4528}
4529
Pekka Paalanene67858b2013-04-25 13:57:42 +03004530static void
4531subsurface_set_position(struct wl_client *client,
4532 struct wl_resource *resource, int32_t x, int32_t y)
4533{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004534 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004535
4536 if (!sub)
4537 return;
4538
4539 sub->position.x = x;
4540 sub->position.y = y;
4541 sub->position.set = 1;
4542}
4543
4544static struct weston_subsurface *
Arnaud Vracb8c16c92016-06-08 18:37:57 +02004545subsurface_find_sibling(struct weston_subsurface *sub,
4546 struct weston_surface *surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03004547{
Arnaud Vracb8c16c92016-06-08 18:37:57 +02004548 struct weston_surface *parent = sub->parent;
4549 struct weston_subsurface *sibling;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004550
Arnaud Vracb8c16c92016-06-08 18:37:57 +02004551 wl_list_for_each(sibling, &parent->subsurface_list, parent_link) {
4552 if (sibling->surface == surface && sibling != sub)
4553 return sibling;
4554 }
Pekka Paalanene67858b2013-04-25 13:57:42 +03004555
4556 return NULL;
4557}
4558
4559static struct weston_subsurface *
4560subsurface_sibling_check(struct weston_subsurface *sub,
4561 struct weston_surface *surface,
4562 const char *request)
4563{
4564 struct weston_subsurface *sibling;
4565
Arnaud Vracb8c16c92016-06-08 18:37:57 +02004566 sibling = subsurface_find_sibling(sub, surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004567 if (!sibling) {
4568 wl_resource_post_error(sub->resource,
4569 WL_SUBSURFACE_ERROR_BAD_SURFACE,
4570 "%s: wl_surface@%d is not a parent or sibling",
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05004571 request, wl_resource_get_id(surface->resource));
Pekka Paalanene67858b2013-04-25 13:57:42 +03004572 return NULL;
4573 }
4574
Arnaud Vracb8c16c92016-06-08 18:37:57 +02004575 assert(sibling->parent == sub->parent);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004576
4577 return sibling;
4578}
4579
4580static void
4581subsurface_place_above(struct wl_client *client,
4582 struct wl_resource *resource,
4583 struct wl_resource *sibling_resource)
4584{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004585 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05004586 struct weston_surface *surface =
4587 wl_resource_get_user_data(sibling_resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004588 struct weston_subsurface *sibling;
4589
4590 if (!sub)
4591 return;
4592
4593 sibling = subsurface_sibling_check(sub, surface, "place_above");
4594 if (!sibling)
4595 return;
4596
4597 wl_list_remove(&sub->parent_link_pending);
4598 wl_list_insert(sibling->parent_link_pending.prev,
4599 &sub->parent_link_pending);
Emilio Pozuelo Monfort4f3cad72017-01-27 17:30:29 +01004600
4601 sub->reordered = true;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004602}
4603
4604static void
4605subsurface_place_below(struct wl_client *client,
4606 struct wl_resource *resource,
4607 struct wl_resource *sibling_resource)
4608{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004609 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05004610 struct weston_surface *surface =
4611 wl_resource_get_user_data(sibling_resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004612 struct weston_subsurface *sibling;
4613
4614 if (!sub)
4615 return;
4616
4617 sibling = subsurface_sibling_check(sub, surface, "place_below");
4618 if (!sibling)
4619 return;
4620
4621 wl_list_remove(&sub->parent_link_pending);
4622 wl_list_insert(&sibling->parent_link_pending,
4623 &sub->parent_link_pending);
Emilio Pozuelo Monfort4f3cad72017-01-27 17:30:29 +01004624
4625 sub->reordered = true;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004626}
4627
4628static void
4629subsurface_set_sync(struct wl_client *client, struct wl_resource *resource)
4630{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004631 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004632
4633 if (sub)
4634 sub->synchronized = 1;
4635}
4636
4637static void
4638subsurface_set_desync(struct wl_client *client, struct wl_resource *resource)
4639{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004640 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004641
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03004642 if (sub && sub->synchronized) {
Pekka Paalanene67858b2013-04-25 13:57:42 +03004643 sub->synchronized = 0;
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03004644
4645 /* If sub became effectively desynchronized, flush. */
4646 if (!weston_subsurface_is_synchronized(sub))
4647 weston_subsurface_synchronized_commit(sub);
4648 }
Pekka Paalanene67858b2013-04-25 13:57:42 +03004649}
4650
4651static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03004652weston_subsurface_unlink_parent(struct weston_subsurface *sub)
4653{
4654 wl_list_remove(&sub->parent_link);
4655 wl_list_remove(&sub->parent_link_pending);
4656 wl_list_remove(&sub->parent_destroy_listener.link);
4657 sub->parent = NULL;
4658}
4659
4660static void
4661weston_subsurface_destroy(struct weston_subsurface *sub);
4662
4663static void
4664subsurface_handle_surface_destroy(struct wl_listener *listener, void *data)
4665{
4666 struct weston_subsurface *sub =
4667 container_of(listener, struct weston_subsurface,
4668 surface_destroy_listener);
Pekka Paalanenca790762015-04-17 14:23:38 +03004669 assert(data == sub->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004670
4671 /* The protocol object (wl_resource) is left inert. */
4672 if (sub->resource)
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004673 wl_resource_set_user_data(sub->resource, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004674
4675 weston_subsurface_destroy(sub);
4676}
4677
4678static void
4679subsurface_handle_parent_destroy(struct wl_listener *listener, void *data)
4680{
4681 struct weston_subsurface *sub =
4682 container_of(listener, struct weston_subsurface,
4683 parent_destroy_listener);
Pekka Paalanenca790762015-04-17 14:23:38 +03004684 assert(data == sub->parent);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004685 assert(sub->surface != sub->parent);
4686
4687 if (weston_surface_is_mapped(sub->surface))
4688 weston_surface_unmap(sub->surface);
4689
4690 weston_subsurface_unlink_parent(sub);
4691}
4692
4693static void
4694subsurface_resource_destroy(struct wl_resource *resource)
4695{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004696 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004697
4698 if (sub)
4699 weston_subsurface_destroy(sub);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004700}
4701
4702static void
4703subsurface_destroy(struct wl_client *client, struct wl_resource *resource)
4704{
4705 wl_resource_destroy(resource);
4706}
4707
4708static void
4709weston_subsurface_link_parent(struct weston_subsurface *sub,
4710 struct weston_surface *parent)
4711{
4712 sub->parent = parent;
4713 sub->parent_destroy_listener.notify = subsurface_handle_parent_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05004714 wl_signal_add(&parent->destroy_signal,
Pekka Paalanene67858b2013-04-25 13:57:42 +03004715 &sub->parent_destroy_listener);
4716
4717 wl_list_insert(&parent->subsurface_list, &sub->parent_link);
4718 wl_list_insert(&parent->subsurface_list_pending,
4719 &sub->parent_link_pending);
4720}
4721
4722static void
4723weston_subsurface_link_surface(struct weston_subsurface *sub,
4724 struct weston_surface *surface)
4725{
4726 sub->surface = surface;
4727 sub->surface_destroy_listener.notify =
4728 subsurface_handle_surface_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05004729 wl_signal_add(&surface->destroy_signal,
Pekka Paalanene67858b2013-04-25 13:57:42 +03004730 &sub->surface_destroy_listener);
4731}
4732
4733static void
4734weston_subsurface_destroy(struct weston_subsurface *sub)
4735{
Jason Ekstranda7af7042013-10-12 22:38:11 -05004736 struct weston_view *view, *next;
4737
Pekka Paalanene67858b2013-04-25 13:57:42 +03004738 assert(sub->surface);
4739
4740 if (sub->resource) {
4741 assert(weston_surface_to_subsurface(sub->surface) == sub);
4742 assert(sub->parent_destroy_listener.notify ==
4743 subsurface_handle_parent_destroy);
4744
George Kiagiadakised04d382014-06-13 18:10:26 +02004745 wl_list_for_each_safe(view, next, &sub->surface->views, surface_link) {
4746 weston_view_unmap(view);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004747 weston_view_destroy(view);
George Kiagiadakised04d382014-06-13 18:10:26 +02004748 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05004749
Pekka Paalanene67858b2013-04-25 13:57:42 +03004750 if (sub->parent)
4751 weston_subsurface_unlink_parent(sub);
4752
Jason Ekstrand7b982072014-05-20 14:33:03 -05004753 weston_surface_state_fini(&sub->cached);
4754 weston_buffer_reference(&sub->cached_buffer_ref, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004755
Quentin Glidic2edc3d52016-08-12 10:41:33 +02004756 sub->surface->committed = NULL;
4757 sub->surface->committed_private = NULL;
Pekka Paalanen8274d902014-08-06 19:36:51 +03004758 weston_surface_set_label_func(sub->surface, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004759 } else {
4760 /* the dummy weston_subsurface for the parent itself */
4761 assert(sub->parent_destroy_listener.notify == NULL);
4762 wl_list_remove(&sub->parent_link);
4763 wl_list_remove(&sub->parent_link_pending);
4764 }
4765
4766 wl_list_remove(&sub->surface_destroy_listener.link);
4767 free(sub);
4768}
4769
4770static const struct wl_subsurface_interface subsurface_implementation = {
4771 subsurface_destroy,
4772 subsurface_set_position,
4773 subsurface_place_above,
4774 subsurface_place_below,
4775 subsurface_set_sync,
4776 subsurface_set_desync
4777};
4778
4779static struct weston_subsurface *
4780weston_subsurface_create(uint32_t id, struct weston_surface *surface,
4781 struct weston_surface *parent)
4782{
4783 struct weston_subsurface *sub;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05004784 struct wl_client *client = wl_resource_get_client(surface->resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004785
Bryce Harringtonde16d892014-11-20 22:21:57 -08004786 sub = zalloc(sizeof *sub);
4787 if (sub == NULL)
Pekka Paalanene67858b2013-04-25 13:57:42 +03004788 return NULL;
4789
Jason Ekstranda7af7042013-10-12 22:38:11 -05004790 wl_list_init(&sub->unused_views);
4791
Jason Ekstranda85118c2013-06-27 20:17:02 -05004792 sub->resource =
4793 wl_resource_create(client, &wl_subsurface_interface, 1, id);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004794 if (!sub->resource) {
4795 free(sub);
4796 return NULL;
4797 }
4798
Jason Ekstranda85118c2013-06-27 20:17:02 -05004799 wl_resource_set_implementation(sub->resource,
4800 &subsurface_implementation,
4801 sub, subsurface_resource_destroy);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004802 weston_subsurface_link_surface(sub, surface);
4803 weston_subsurface_link_parent(sub, parent);
Jason Ekstrand7b982072014-05-20 14:33:03 -05004804 weston_surface_state_init(&sub->cached);
4805 sub->cached_buffer_ref.buffer = NULL;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004806 sub->synchronized = 1;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004807
4808 return sub;
4809}
4810
4811/* Create a dummy subsurface for having the parent itself in its
4812 * sub-surface lists. Makes stacking order manipulation easy.
4813 */
4814static struct weston_subsurface *
4815weston_subsurface_create_for_parent(struct weston_surface *parent)
4816{
4817 struct weston_subsurface *sub;
4818
Bryce Harringtonde16d892014-11-20 22:21:57 -08004819 sub = zalloc(sizeof *sub);
4820 if (sub == NULL)
Pekka Paalanene67858b2013-04-25 13:57:42 +03004821 return NULL;
4822
4823 weston_subsurface_link_surface(sub, parent);
4824 sub->parent = parent;
4825 wl_list_insert(&parent->subsurface_list, &sub->parent_link);
4826 wl_list_insert(&parent->subsurface_list_pending,
4827 &sub->parent_link_pending);
4828
4829 return sub;
4830}
4831
4832static void
4833subcompositor_get_subsurface(struct wl_client *client,
4834 struct wl_resource *resource,
4835 uint32_t id,
4836 struct wl_resource *surface_resource,
4837 struct wl_resource *parent_resource)
4838{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05004839 struct weston_surface *surface =
4840 wl_resource_get_user_data(surface_resource);
4841 struct weston_surface *parent =
4842 wl_resource_get_user_data(parent_resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004843 struct weston_subsurface *sub;
4844 static const char where[] = "get_subsurface: wl_subsurface@";
4845
4846 if (surface == parent) {
4847 wl_resource_post_error(resource,
4848 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
4849 "%s%d: wl_surface@%d cannot be its own parent",
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004850 where, id, wl_resource_get_id(surface_resource));
Pekka Paalanene67858b2013-04-25 13:57:42 +03004851 return;
4852 }
4853
4854 if (weston_surface_to_subsurface(surface)) {
4855 wl_resource_post_error(resource,
4856 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
4857 "%s%d: wl_surface@%d is already a sub-surface",
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004858 where, id, wl_resource_get_id(surface_resource));
Pekka Paalanene67858b2013-04-25 13:57:42 +03004859 return;
4860 }
4861
Pekka Paalanen50b67472014-10-01 15:02:41 +03004862 if (weston_surface_set_role(surface, "wl_subsurface", resource,
4863 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE) < 0)
Pekka Paalanene67858b2013-04-25 13:57:42 +03004864 return;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004865
Pekka Paalanen86c8ca02013-05-17 16:46:07 +03004866 if (weston_surface_get_main_surface(parent) == surface) {
4867 wl_resource_post_error(resource,
4868 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
4869 "%s%d: wl_surface@%d is an ancestor of parent",
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004870 where, id, wl_resource_get_id(surface_resource));
Pekka Paalanen86c8ca02013-05-17 16:46:07 +03004871 return;
4872 }
4873
Pekka Paalanene67858b2013-04-25 13:57:42 +03004874 /* make sure the parent is in its own list */
4875 if (wl_list_empty(&parent->subsurface_list)) {
4876 if (!weston_subsurface_create_for_parent(parent)) {
4877 wl_resource_post_no_memory(resource);
4878 return;
4879 }
4880 }
4881
4882 sub = weston_subsurface_create(id, surface, parent);
4883 if (!sub) {
4884 wl_resource_post_no_memory(resource);
4885 return;
4886 }
4887
Quentin Glidic2edc3d52016-08-12 10:41:33 +02004888 surface->committed = subsurface_committed;
4889 surface->committed_private = sub;
Pekka Paalanen8274d902014-08-06 19:36:51 +03004890 weston_surface_set_label_func(surface, subsurface_get_label);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004891}
4892
4893static void
4894subcompositor_destroy(struct wl_client *client, struct wl_resource *resource)
4895{
4896 wl_resource_destroy(resource);
4897}
4898
4899static const struct wl_subcompositor_interface subcompositor_interface = {
4900 subcompositor_destroy,
4901 subcompositor_get_subsurface
4902};
4903
4904static void
4905bind_subcompositor(struct wl_client *client,
4906 void *data, uint32_t version, uint32_t id)
4907{
4908 struct weston_compositor *compositor = data;
Jason Ekstranda85118c2013-06-27 20:17:02 -05004909 struct wl_resource *resource;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004910
Jason Ekstranda85118c2013-06-27 20:17:02 -05004911 resource =
4912 wl_resource_create(client, &wl_subcompositor_interface, 1, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07004913 if (resource == NULL) {
4914 wl_client_post_no_memory(client);
4915 return;
4916 }
4917 wl_resource_set_implementation(resource, &subcompositor_interface,
4918 compositor, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004919}
4920
Bryce Harrington0795ece2016-08-30 12:04:26 -07004921/** Set a DPMS mode on all of the compositor's outputs
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004922 *
4923 * \param compositor The compositor instance
4924 * \param state The DPMS state the outputs will be set to
4925 */
Pekka Paalanene67858b2013-04-25 13:57:42 +03004926static void
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004927weston_compositor_dpms(struct weston_compositor *compositor,
4928 enum dpms_enum state)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004929{
Emmanuel Gil Peyroteff793a2021-07-31 17:25:41 +02004930 struct weston_output *output;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004931
Emmanuel Gil Peyroteff793a2021-07-31 17:25:41 +02004932 wl_list_for_each(output, &compositor->output_list, link)
Bryce Harrington08976ac2016-08-30 12:05:16 -07004933 if (output->set_dpms)
4934 output->set_dpms(output, state);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004935}
4936
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004937/** Restores the compositor to active status
4938 *
4939 * \param compositor The compositor instance
4940 *
4941 * If the compositor was in a sleeping mode, all outputs are powered
4942 * back on via DPMS. Otherwise if the compositor was inactive
4943 * (idle/locked, offscreen, or sleeping) then the compositor's wake
4944 * signal will fire.
4945 *
4946 * Restarts the idle timer.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03004947 * \ingroup compositor
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004948 */
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02004949WL_EXPORT void
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004950weston_compositor_wake(struct weston_compositor *compositor)
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02004951{
Neil Roberts8b62e202013-09-30 13:14:47 +01004952 uint32_t old_state = compositor->state;
4953
4954 /* The state needs to be changed before emitting the wake
4955 * signal because that may try to schedule a repaint which
4956 * will not work if the compositor is still sleeping */
4957 compositor->state = WESTON_COMPOSITOR_ACTIVE;
4958
4959 switch (old_state) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004960 case WESTON_COMPOSITOR_SLEEPING:
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004961 case WESTON_COMPOSITOR_IDLE:
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01004962 case WESTON_COMPOSITOR_OFFSCREEN:
Daniel Stone893b9362016-11-08 15:47:09 +00004963 weston_compositor_dpms(compositor, WESTON_DPMS_ON);
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004964 wl_signal_emit(&compositor->wake_signal, compositor);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004965 /* fall through */
4966 default:
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004967 wl_event_source_timer_update(compositor->idle_source,
4968 compositor->idle_time * 1000);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02004969 }
4970}
4971
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004972/** Turns off rendering and frame events for the compositor.
4973 *
4974 * \param compositor The compositor instance
4975 *
4976 * This is used for example to prevent further rendering while the
4977 * compositor is shutting down.
4978 *
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004979 * Stops the idle timer.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03004980 *
4981 * \ingroup compositor
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004982 */
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004983WL_EXPORT void
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01004984weston_compositor_offscreen(struct weston_compositor *compositor)
4985{
4986 switch (compositor->state) {
4987 case WESTON_COMPOSITOR_OFFSCREEN:
4988 return;
4989 case WESTON_COMPOSITOR_SLEEPING:
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01004990 default:
4991 compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
4992 wl_event_source_timer_update(compositor->idle_source, 0);
4993 }
4994}
4995
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004996/** Powers down all attached output devices
4997 *
4998 * \param compositor The compositor instance
4999 *
5000 * Causes rendering to the outputs to cease, and no frame events to be
5001 * sent. Only powers down the outputs if the compositor is not already
5002 * in sleep mode.
5003 *
5004 * Stops the idle timer.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03005005 *
5006 * \ingroup compositor
Bryce Harringtonc9626a32015-12-11 13:11:38 -08005007 */
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01005008WL_EXPORT void
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02005009weston_compositor_sleep(struct weston_compositor *compositor)
5010{
5011 if (compositor->state == WESTON_COMPOSITOR_SLEEPING)
5012 return;
5013
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01005014 wl_event_source_timer_update(compositor->idle_source, 0);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02005015 compositor->state = WESTON_COMPOSITOR_SLEEPING;
5016 weston_compositor_dpms(compositor, WESTON_DPMS_OFF);
5017}
5018
Bryce Harringtonc9626a32015-12-11 13:11:38 -08005019/** Sets compositor to idle mode
5020 *
5021 * \param data The compositor instance
5022 *
5023 * This is called when the idle timer fires. Once the compositor is in
5024 * idle mode it requires a wake action (e.g. via
5025 * weston_compositor_wake()) to restore it. The compositor's
5026 * idle_signal will be triggered when the idle event occurs.
5027 *
5028 * Idleness can be inhibited by setting the compositor's idle_inhibit
5029 * property.
5030 */
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04005031static int
5032idle_handler(void *data)
5033{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005034 struct weston_compositor *compositor = data;
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04005035
5036 if (compositor->idle_inhibit)
5037 return 1;
5038
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005039 compositor->state = WESTON_COMPOSITOR_IDLE;
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005040 wl_signal_emit(&compositor->idle_signal, compositor);
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04005041
5042 return 1;
5043}
5044
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04005045WL_EXPORT void
Xiong Zhang97116532013-10-23 13:58:31 +08005046weston_plane_init(struct weston_plane *plane,
5047 struct weston_compositor *ec,
5048 int32_t x, int32_t y)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04005049{
5050 pixman_region32_init(&plane->damage);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02005051 pixman_region32_init(&plane->clip);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04005052 plane->x = x;
5053 plane->y = y;
Xiong Zhang97116532013-10-23 13:58:31 +08005054 plane->compositor = ec;
Ander Conselvan de Oliveira3c36bf32013-07-05 16:05:26 +03005055
5056 /* Init the link so that the call to wl_list_remove() when releasing
5057 * the plane without ever stacking doesn't lead to a crash */
5058 wl_list_init(&plane->link);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04005059}
5060
5061WL_EXPORT void
5062weston_plane_release(struct weston_plane *plane)
5063{
Xiong Zhang97116532013-10-23 13:58:31 +08005064 struct weston_view *view;
5065
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04005066 pixman_region32_fini(&plane->damage);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02005067 pixman_region32_fini(&plane->clip);
Ander Conselvan de Oliveira3c36bf32013-07-05 16:05:26 +03005068
Pekka Paalanen6551c092021-05-03 16:09:45 +03005069 /*
5070 * Can't use paint node list here, weston_plane is not specific to an
5071 * output.
5072 */
Xiong Zhang97116532013-10-23 13:58:31 +08005073 wl_list_for_each(view, &plane->compositor->view_list, link) {
5074 if (view->plane == plane)
5075 view->plane = NULL;
5076 }
5077
Ander Conselvan de Oliveira3c36bf32013-07-05 16:05:26 +03005078 wl_list_remove(&plane->link);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04005079}
5080
Marius Vlad9fdda7f2019-06-11 16:08:55 +03005081/** weston_compositor_stack_plane
5082 * \ingroup compositor
5083 */
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02005084WL_EXPORT void
5085weston_compositor_stack_plane(struct weston_compositor *ec,
5086 struct weston_plane *plane,
5087 struct weston_plane *above)
5088{
5089 if (above)
5090 wl_list_insert(above->link.prev, &plane->link);
5091 else
5092 wl_list_insert(&ec->plane_list, &plane->link);
5093}
5094
Quentin Glidic4ef719c2016-07-05 20:44:33 +02005095static void
5096output_release(struct wl_client *client, struct wl_resource *resource)
5097{
5098 wl_resource_destroy(resource);
5099}
5100
5101static const struct wl_output_interface output_interface = {
5102 output_release,
5103};
5104
5105
Casey Dahlin9074db52012-04-19 22:50:09 -04005106static void unbind_resource(struct wl_resource *resource)
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04005107{
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05005108 wl_list_remove(wl_resource_get_link(resource));
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04005109}
5110
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04005111static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04005112bind_output(struct wl_client *client,
5113 void *data, uint32_t version, uint32_t id)
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05005114{
Pekka Paalanen05347622017-03-27 12:24:34 +03005115 struct weston_head *head = data;
5116 struct weston_output *output = head->output;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005117 struct weston_mode *mode;
Kristian Høgsbergfd07fb72011-08-29 15:03:09 -04005118 struct wl_resource *resource;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05005119
Jason Ekstranda85118c2013-06-27 20:17:02 -05005120 resource = wl_resource_create(client, &wl_output_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06005121 version, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07005122 if (resource == NULL) {
5123 wl_client_post_no_memory(client);
5124 return;
5125 }
Kristian Høgsbergfd07fb72011-08-29 15:03:09 -04005126
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03005127 wl_list_insert(&head->resource_list, wl_resource_get_link(resource));
Pekka Paalanen055c1132017-03-27 16:31:25 +03005128 wl_resource_set_implementation(resource, &output_interface, head,
Pekka Paalanen05347622017-03-27 12:24:34 +03005129 unbind_resource);
Casey Dahlin9074db52012-04-19 22:50:09 -04005130
Pekka Paalanen05347622017-03-27 12:24:34 +03005131 assert(output);
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05005132 wl_output_send_geometry(resource,
5133 output->x,
5134 output->y,
Pekka Paalanen01f60212017-03-24 15:39:24 +02005135 head->mm_width,
5136 head->mm_height,
5137 head->subpixel,
5138 head->make, head->model,
Kristian Høgsberg05890dc2012-08-10 10:09:20 -04005139 output->transform);
Jasper St. Pierre0013a292014-08-07 16:43:11 -04005140 if (version >= WL_OUTPUT_SCALE_SINCE_VERSION)
Alexander Larsson4ea95522013-05-22 14:41:37 +02005141 wl_output_send_scale(resource,
Hardeningff39efa2013-09-18 23:56:35 +02005142 output->current_scale);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04005143
5144 wl_list_for_each (mode, &output->mode_list, link) {
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05005145 wl_output_send_mode(resource,
5146 mode->flags,
5147 mode->width,
5148 mode->height,
5149 mode->refresh);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04005150 }
Alexander Larsson4ea95522013-05-22 14:41:37 +02005151
Jasper St. Pierre0013a292014-08-07 16:43:11 -04005152 if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
Alexander Larsson4ea95522013-05-22 14:41:37 +02005153 wl_output_send_done(resource);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05005154}
5155
Pekka Paalanendcac3512017-12-08 14:13:34 +02005156static void
5157weston_head_add_global(struct weston_head *head)
5158{
5159 head->global = wl_global_create(head->compositor->wl_display,
5160 &wl_output_interface, 3,
5161 head, bind_output);
5162}
5163
Pekka Paalanend9dcc6d2017-12-04 15:28:13 +02005164/** Remove the global wl_output protocol object
5165 *
5166 * \param head The head whose global to remove.
5167 *
5168 * Also orphans the wl_resources for this head (wl_output).
5169 */
5170static void
5171weston_head_remove_global(struct weston_head *head)
5172{
5173 struct wl_resource *resource, *tmp;
5174
5175 if (head->global)
5176 wl_global_destroy(head->global);
5177 head->global = NULL;
5178
5179 wl_resource_for_each_safe(resource, tmp, &head->resource_list) {
5180 unbind_resource(resource);
5181 wl_resource_set_destructor(resource, NULL);
5182 wl_resource_set_user_data(resource, NULL);
5183 }
Roman Gilge97391c2019-03-29 13:01:06 +01005184
5185 wl_resource_for_each(resource, &head->xdg_output_resource_list) {
5186 /* It's sufficient to unset the destructor, then the list elements
5187 * won't be accessed.
5188 */
5189 wl_resource_set_destructor(resource, NULL);
5190 }
5191 wl_list_init(&head->xdg_output_resource_list);
Pekka Paalanend9dcc6d2017-12-04 15:28:13 +02005192}
5193
Pekka Paalanen9ffb2502017-03-27 15:14:32 +03005194/** Get the backing object of wl_output
5195 *
5196 * \param resource A wl_output protocol object.
5197 * \return The backing object (user data) of a wl_resource representing a
5198 * wl_output protocol object.
Marius Vlad78984ee2019-06-11 00:05:08 +03005199 *
5200 * \ingroup head
Pekka Paalanen9ffb2502017-03-27 15:14:32 +03005201 */
Pekka Paalanen055c1132017-03-27 16:31:25 +03005202WL_EXPORT struct weston_head *
5203weston_head_from_resource(struct wl_resource *resource)
Pekka Paalanen9ffb2502017-03-27 15:14:32 +03005204{
5205 assert(wl_resource_instance_of(resource, &wl_output_interface,
5206 &output_interface));
5207
5208 return wl_resource_get_user_data(resource);
5209}
5210
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005211/** Initialize a pre-allocated weston_head
5212 *
5213 * \param head The head to initialize.
Pekka Paalanen9b02e472017-08-14 14:43:13 +03005214 * \param name The head name, e.g. the connector name or equivalent.
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005215 *
5216 * The head will be safe to attach, detach and release.
5217 *
Pekka Paalanen9b02e472017-08-14 14:43:13 +03005218 * The name is used in logs, and can be used by compositors as a configuration
5219 * identifier.
5220 *
Marius Vlad78984ee2019-06-11 00:05:08 +03005221 * \ingroup head
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005222 * \internal
5223 */
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005224WL_EXPORT void
Pekka Paalanen9b02e472017-08-14 14:43:13 +03005225weston_head_init(struct weston_head *head, const char *name)
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005226{
5227 /* Add some (in)sane defaults which can be used
5228 * for checking if an output was properly configured
5229 */
5230 memset(head, 0, sizeof *head);
5231
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03005232 wl_list_init(&head->compositor_link);
Pekka Paalanen2e1bedb2017-10-10 11:21:58 +03005233 wl_signal_init(&head->destroy_signal);
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005234 wl_list_init(&head->output_link);
5235 wl_list_init(&head->resource_list);
Roman Gilge97391c2019-03-29 13:01:06 +01005236 wl_list_init(&head->xdg_output_resource_list);
Pekka Paalanen9b02e472017-08-14 14:43:13 +03005237 head->name = strdup(name);
Ankit Nautiyal4f64ff82019-04-03 18:44:35 +05305238 head->current_protection = WESTON_HDCP_DISABLE;
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005239}
5240
Pekka Paalanen8dc6db82018-03-20 13:29:40 +02005241/** Send output heads changed signal
5242 *
5243 * \param output The output that changed.
5244 *
5245 * Notify that the enabled output gained and/or lost heads, or that the
5246 * associated heads may have changed their connection status. This does not
5247 * include cases where the output becomes enabled or disabled. The registered
5248 * callbacks are called after the change has successfully happened.
5249 *
5250 * If connection status change causes the compositor to attach or detach a head
5251 * to an enabled output, the registered callbacks may be called multiple times.
Marius Vlad55d87362019-06-11 01:15:35 +03005252 *
5253 * \ingroup output
Pekka Paalanen8dc6db82018-03-20 13:29:40 +02005254 */
5255static void
5256weston_output_emit_heads_changed(struct weston_output *output)
5257{
5258 wl_signal_emit(&output->compositor->output_heads_changed_signal,
5259 output);
5260}
5261
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005262/** Idle task for emitting heads_changed_signal */
5263static void
5264weston_compositor_call_heads_changed(void *data)
5265{
5266 struct weston_compositor *compositor = data;
Pekka Paalanen8dc6db82018-03-20 13:29:40 +02005267 struct weston_head *head;
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005268
5269 compositor->heads_changed_source = NULL;
5270
5271 wl_signal_emit(&compositor->heads_changed_signal, compositor);
Pekka Paalanen8dc6db82018-03-20 13:29:40 +02005272
5273 wl_list_for_each(head, &compositor->head_list, compositor_link) {
5274 if (head->output && head->output->enabled)
5275 weston_output_emit_heads_changed(head->output);
5276 }
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005277}
5278
5279/** Schedule a call on idle to heads_changed callback
5280 *
5281 * \param compositor The Compositor.
5282 *
Marius Vlad9fdda7f2019-06-11 16:08:55 +03005283 * \ingroup compositor
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005284 * \internal
5285 */
5286static void
5287weston_compositor_schedule_heads_changed(struct weston_compositor *compositor)
5288{
5289 struct wl_event_loop *loop;
5290
5291 if (compositor->heads_changed_source)
5292 return;
5293
5294 loop = wl_display_get_event_loop(compositor->wl_display);
5295 compositor->heads_changed_source = wl_event_loop_add_idle(loop,
5296 weston_compositor_call_heads_changed, compositor);
5297}
5298
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03005299/** Register a new head
5300 *
5301 * \param compositor The compositor.
5302 * \param head The head to register, must not be already registered.
5303 *
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005304 * This signals the core that a new head has become available, leading to
5305 * heads_changed hook being called later.
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03005306 *
Marius Vlad9fdda7f2019-06-11 16:08:55 +03005307 * \ingroup compositor
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03005308 * \internal
5309 */
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005310WL_EXPORT void
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03005311weston_compositor_add_head(struct weston_compositor *compositor,
5312 struct weston_head *head)
5313{
5314 assert(wl_list_empty(&head->compositor_link));
5315 assert(head->name);
5316
5317 wl_list_insert(compositor->head_list.prev, &head->compositor_link);
5318 head->compositor = compositor;
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005319 weston_compositor_schedule_heads_changed(compositor);
5320}
5321
5322/** Adds a listener to be called when heads change
5323 *
5324 * \param compositor The compositor.
5325 * \param listener The listener to add.
5326 *
Marius Vlada2dace22019-06-12 16:05:44 +03005327 * The listener notify function argument is weston_compositor.
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005328 *
5329 * The listener function will be called after heads are added or their
5330 * connection status has changed. Several changes may be accumulated into a
5331 * single call. The user is expected to iterate over the existing heads and
5332 * check their statuses to find out what changed.
5333 *
5334 * \sa weston_compositor_iterate_heads, weston_head_is_connected,
5335 * weston_head_is_enabled
Marius Vlad9fdda7f2019-06-11 16:08:55 +03005336 * \ingroup compositor
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005337 */
5338WL_EXPORT void
5339weston_compositor_add_heads_changed_listener(struct weston_compositor *compositor,
5340 struct wl_listener *listener)
5341{
5342 wl_signal_add(&compositor->heads_changed_signal, listener);
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03005343}
5344
5345/** Iterate over available heads
5346 *
5347 * \param compositor The compositor.
Marius Vlada2dace22019-06-12 16:05:44 +03005348 * \param iter The iterator, or NULL for start.
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03005349 * \return The next available head in the list.
5350 *
5351 * Returns all available heads, regardless of being connected or enabled.
5352 *
5353 * You can iterate over all heads as follows:
5354 * \code
5355 * struct weston_head *head = NULL;
5356 *
5357 * while ((head = weston_compositor_iterate_heads(compositor, head))) {
5358 * ...
5359 * }
5360 * \endcode
5361 *
5362 * If you cause \c iter to be removed from the list, you cannot use it to
5363 * continue iterating. Removing any other item is safe.
5364 *
Marius Vlad9fdda7f2019-06-11 16:08:55 +03005365 * \ingroup compositor
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03005366 */
5367WL_EXPORT struct weston_head *
5368weston_compositor_iterate_heads(struct weston_compositor *compositor,
5369 struct weston_head *iter)
5370{
5371 struct wl_list *list = &compositor->head_list;
5372 struct wl_list *node;
5373
5374 assert(compositor);
5375 assert(!iter || iter->compositor == compositor);
5376
5377 if (iter)
5378 node = iter->compositor_link.next;
5379 else
5380 node = list->next;
5381
5382 assert(node);
5383 assert(!iter || node != &iter->compositor_link);
5384
5385 if (node == list)
5386 return NULL;
5387
5388 return container_of(node, struct weston_head, compositor_link);
5389}
5390
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005391/** Iterate over attached heads
5392 *
5393 * \param output The output whose heads to iterate.
Marius Vlada2dace22019-06-12 16:05:44 +03005394 * \param iter The iterator, or NULL for start.
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005395 * \return The next attached head in the list.
5396 *
5397 * Returns all heads currently attached to the output.
5398 *
5399 * You can iterate over all heads as follows:
5400 * \code
5401 * struct weston_head *head = NULL;
5402 *
5403 * while ((head = weston_output_iterate_heads(output, head))) {
5404 * ...
5405 * }
5406 * \endcode
5407 *
5408 * If you cause \c iter to be removed from the list, you cannot use it to
5409 * continue iterating. Removing any other item is safe.
5410 *
Maxime Roussin-Bélanger1d009c22020-12-17 17:10:13 -05005411 * \ingroup output
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005412 */
5413WL_EXPORT struct weston_head *
5414weston_output_iterate_heads(struct weston_output *output,
5415 struct weston_head *iter)
5416{
5417 struct wl_list *list = &output->head_list;
5418 struct wl_list *node;
5419
5420 assert(output);
5421 assert(!iter || iter->output == output);
5422
5423 if (iter)
5424 node = iter->output_link.next;
5425 else
5426 node = list->next;
5427
5428 assert(node);
5429 assert(!iter || node != &iter->output_link);
5430
5431 if (node == list)
5432 return NULL;
5433
5434 return container_of(node, struct weston_head, output_link);
5435}
5436
Pekka Paalanendcac3512017-12-08 14:13:34 +02005437/** Attach a head to an output
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005438 *
5439 * \param output The output to attach to.
5440 * \param head The head that is not yet attached.
5441 * \return 0 on success, -1 on failure.
5442 *
5443 * Attaches the given head to the output. All heads of an output are clones
5444 * and share the resolution and timings.
5445 *
5446 * Cloning heads this way uses less resources than creating an output for
5447 * each head, but is not always possible due to environment, driver and hardware
5448 * limitations.
5449 *
5450 * On failure, the head remains unattached. Success of this function does not
5451 * guarantee the output configuration is actually valid. The final checks are
Pekka Paalanendcac3512017-12-08 14:13:34 +02005452 * made on weston_output_enable() unless the output was already enabled.
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005453 *
Marius Vlad55d87362019-06-11 01:15:35 +03005454 * \ingroup output
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005455 */
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005456WL_EXPORT int
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005457weston_output_attach_head(struct weston_output *output,
5458 struct weston_head *head)
5459{
Pekka Paalanendcac3512017-12-08 14:13:34 +02005460 char *head_names;
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005461
5462 if (!wl_list_empty(&head->output_link))
5463 return -1;
5464
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005465 if (output->attach_head) {
5466 if (output->attach_head(output, head) < 0)
5467 return -1;
5468 } else if (!wl_list_empty(&output->head_list)) {
5469 /* No support for clones in the legacy path. */
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005470 return -1;
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005471 }
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005472
5473 head->output = output;
5474 wl_list_insert(output->head_list.prev, &head->output_link);
5475
Pekka Paalanendcac3512017-12-08 14:13:34 +02005476 if (output->enabled) {
5477 weston_head_add_global(head);
5478
5479 head_names = weston_output_create_heads_string(output);
5480 weston_log("Output '%s' updated to have head(s) %s\n",
5481 output->name, head_names);
5482 free(head_names);
Pekka Paalanen8dc6db82018-03-20 13:29:40 +02005483
5484 weston_output_emit_heads_changed(output);
Pekka Paalanendcac3512017-12-08 14:13:34 +02005485 }
5486
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005487 return 0;
5488}
5489
5490/** Detach a head from its output
5491 *
5492 * \param head The head to detach.
5493 *
5494 * It is safe to detach a non-attached head.
5495 *
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005496 * If the head is attached to an enabled output and the output will be left
5497 * with no heads, the output will be disabled.
5498 *
Marius Vlad78984ee2019-06-11 00:05:08 +03005499 * \ingroup head
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005500 * \sa weston_output_disable
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005501 */
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005502WL_EXPORT void
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005503weston_head_detach(struct weston_head *head)
5504{
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005505 struct weston_output *output = head->output;
Pekka Paalanena0106992017-12-08 16:11:17 +02005506 char *head_names;
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005507
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005508 wl_list_remove(&head->output_link);
5509 wl_list_init(&head->output_link);
5510 head->output = NULL;
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005511
5512 if (!output)
5513 return;
5514
5515 if (output->detach_head)
5516 output->detach_head(output, head);
5517
5518 if (output->enabled) {
5519 weston_head_remove_global(head);
5520
Pekka Paalanena0106992017-12-08 16:11:17 +02005521 if (wl_list_empty(&output->head_list)) {
5522 weston_log("Output '%s' no heads left, disabling.\n",
5523 output->name);
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005524 weston_output_disable(output);
Pekka Paalanena0106992017-12-08 16:11:17 +02005525 } else {
5526 head_names = weston_output_create_heads_string(output);
5527 weston_log("Output '%s' updated to have head(s) %s\n",
5528 output->name, head_names);
5529 free(head_names);
Pekka Paalanen8dc6db82018-03-20 13:29:40 +02005530
5531 weston_output_emit_heads_changed(output);
Pekka Paalanena0106992017-12-08 16:11:17 +02005532 }
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005533 }
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005534}
5535
5536/** Destroy a head
5537 *
5538 * \param head The head to be released.
5539 *
5540 * Destroys the head. The caller is responsible for freeing the memory pointed
5541 * to by \c head.
5542 *
Marius Vlad78984ee2019-06-11 00:05:08 +03005543 * \ingroup head
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005544 * \internal
5545 */
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005546WL_EXPORT void
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005547weston_head_release(struct weston_head *head)
5548{
Pekka Paalanen2e1bedb2017-10-10 11:21:58 +03005549 wl_signal_emit(&head->destroy_signal, head);
5550
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005551 weston_head_detach(head);
Pekka Paalanen06f99ef2017-04-04 16:26:23 +03005552
5553 free(head->make);
5554 free(head->model);
5555 free(head->serial_number);
Pekka Paalanen9b02e472017-08-14 14:43:13 +03005556 free(head->name);
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03005557
5558 wl_list_remove(&head->compositor_link);
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03005559}
5560
Pekka Paalanene19970f2017-08-28 14:11:02 +03005561static void
5562weston_head_set_device_changed(struct weston_head *head)
5563{
5564 head->device_changed = true;
5565
5566 if (head->compositor)
5567 weston_compositor_schedule_heads_changed(head->compositor);
5568}
5569
5570/** String equal comparison with NULLs being equal */
5571static bool
5572str_null_eq(const char *a, const char *b)
5573{
5574 if (!a && !b)
5575 return true;
5576
5577 if (!!a != !!b)
5578 return false;
5579
5580 return strcmp(a, b) == 0;
5581}
5582
Pekka Paalanen01f60212017-03-24 15:39:24 +02005583/** Store monitor make, model and serial number
5584 *
5585 * \param head The head to modify.
5586 * \param make The monitor make. If EDID is available, the PNP ID. Otherwise
5587 * any string, or NULL for none.
5588 * \param model The monitor model or name, or a made-up string, or NULL for
5589 * none.
5590 * \param serialno The monitor serial number, a made-up string, or NULL for
5591 * none.
5592 *
Pekka Paalanene19970f2017-08-28 14:11:02 +03005593 * This may set the device_changed flag.
5594 *
Marius Vlad78984ee2019-06-11 00:05:08 +03005595 * \ingroup head
Pekka Paalanen01f60212017-03-24 15:39:24 +02005596 * \internal
5597 */
5598WL_EXPORT void
5599weston_head_set_monitor_strings(struct weston_head *head,
5600 const char *make,
5601 const char *model,
5602 const char *serialno)
5603{
Pekka Paalanene19970f2017-08-28 14:11:02 +03005604 if (str_null_eq(head->make, make) &&
5605 str_null_eq(head->model, model) &&
5606 str_null_eq(head->serial_number, serialno))
5607 return;
5608
Pekka Paalanen06f99ef2017-04-04 16:26:23 +03005609 free(head->make);
5610 free(head->model);
5611 free(head->serial_number);
5612
5613 head->make = make ? strdup(make) : NULL;
5614 head->model = model ? strdup(model) : NULL;
5615 head->serial_number = serialno ? strdup(serialno) : NULL;
Pekka Paalanene19970f2017-08-28 14:11:02 +03005616
5617 weston_head_set_device_changed(head);
Pekka Paalanen01f60212017-03-24 15:39:24 +02005618}
5619
Philipp Zabelc18ffd32018-08-30 17:38:03 +02005620/** Store display non-desktop status
5621 *
5622 * \param head The head to modify.
5623 * \param non_desktop Whether the head connects to a non-desktop display.
5624 *
Marius Vlad78984ee2019-06-11 00:05:08 +03005625 * \ingroup head
Philipp Zabelc18ffd32018-08-30 17:38:03 +02005626 * \internal
5627 */
5628WL_EXPORT void
5629weston_head_set_non_desktop(struct weston_head *head, bool non_desktop)
5630{
5631 if (head->non_desktop == non_desktop)
5632 return;
5633
5634 head->non_desktop = non_desktop;
5635
5636 weston_head_set_device_changed(head);
5637}
5638
Lucas Stacha69cb712019-11-25 23:29:31 +00005639/** Store display transformation
5640 *
5641 * \param head The head to modify.
5642 * \param transform The transformation to apply for this head
5643 *
5644 * This may set the device_changed flag.
5645 *
5646 * \ingroup head
5647 * \internal
5648 */
5649WL_EXPORT void
5650weston_head_set_transform(struct weston_head *head, uint32_t transform)
5651{
5652 if (head->transform == transform)
5653 return;
5654
5655 head->transform = transform;
5656
5657 weston_head_set_device_changed(head);
5658}
5659
5660
Pekka Paalanen01f60212017-03-24 15:39:24 +02005661/** Store physical image size
5662 *
5663 * \param head The head to modify.
5664 * \param mm_width Image area width in millimeters.
5665 * \param mm_height Image area height in millimeters.
5666 *
Pekka Paalanene19970f2017-08-28 14:11:02 +03005667 * This may set the device_changed flag.
5668 *
Marius Vlad78984ee2019-06-11 00:05:08 +03005669 * \ingroup head
Pekka Paalanen01f60212017-03-24 15:39:24 +02005670 * \internal
5671 */
5672WL_EXPORT void
5673weston_head_set_physical_size(struct weston_head *head,
5674 int32_t mm_width, int32_t mm_height)
5675{
Pekka Paalanene19970f2017-08-28 14:11:02 +03005676 if (head->mm_width == mm_width &&
5677 head->mm_height == mm_height)
5678 return;
5679
Pekka Paalanen01f60212017-03-24 15:39:24 +02005680 head->mm_width = mm_width;
5681 head->mm_height = mm_height;
Pekka Paalanene19970f2017-08-28 14:11:02 +03005682
5683 weston_head_set_device_changed(head);
Pekka Paalanen01f60212017-03-24 15:39:24 +02005684}
5685
5686/** Store monitor sub-pixel layout
5687 *
5688 * \param head The head to modify.
5689 * \param sp Sub-pixel layout. The possible values are:
5690 * - WL_OUTPUT_SUBPIXEL_UNKNOWN,
5691 * - WL_OUTPUT_SUBPIXEL_NONE,
5692 * - WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB,
5693 * - WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR,
5694 * - WL_OUTPUT_SUBPIXEL_VERTICAL_RGB,
5695 * - WL_OUTPUT_SUBPIXEL_VERTICAL_BGR
5696 *
Pekka Paalanene19970f2017-08-28 14:11:02 +03005697 * This may set the device_changed flag.
5698 *
Marius Vlad78984ee2019-06-11 00:05:08 +03005699 * \ingroup head
Pekka Paalanen01f60212017-03-24 15:39:24 +02005700 * \internal
5701 */
5702WL_EXPORT void
5703weston_head_set_subpixel(struct weston_head *head,
5704 enum wl_output_subpixel sp)
5705{
Pekka Paalanene19970f2017-08-28 14:11:02 +03005706 if (head->subpixel == sp)
5707 return;
5708
Pekka Paalanen01f60212017-03-24 15:39:24 +02005709 head->subpixel = sp;
Pekka Paalanene19970f2017-08-28 14:11:02 +03005710
5711 weston_head_set_device_changed(head);
Pekka Paalanen01f60212017-03-24 15:39:24 +02005712}
5713
5714/** Mark the monitor as internal
5715 *
5716 * This is used for embedded screens, like laptop panels.
5717 *
5718 * \param head The head to mark as internal.
5719 *
5720 * By default a head is external. The type is often inferred from the physical
5721 * connector type.
5722 *
Marius Vlad78984ee2019-06-11 00:05:08 +03005723 * \ingroup head
Pekka Paalanen01f60212017-03-24 15:39:24 +02005724 * \internal
5725 */
5726WL_EXPORT void
5727weston_head_set_internal(struct weston_head *head)
5728{
5729 head->connection_internal = true;
5730}
Pekka Paalanen9ffb2502017-03-27 15:14:32 +03005731
Pekka Paalanen7fe858b2017-08-14 15:45:14 +03005732/** Store connector status
5733 *
5734 * \param head The head to modify.
5735 * \param connected Whether the head is connected.
5736 *
5737 * Connectors are created as disconnected. This function can be used to
5738 * set the connector status.
5739 *
5740 * The status should be set to true when a physical connector is connected to
5741 * a video sink device like a monitor and to false when the connector is
5742 * disconnected. For nested backends, the connection status should reflect the
5743 * connection to the parent display server.
5744 *
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005745 * When the connection status changes, it schedules a call to the heads_changed
Pekka Paalanene19970f2017-08-28 14:11:02 +03005746 * hook and sets the device_changed flag.
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005747 *
5748 * \sa weston_compositor_set_heads_changed_cb
Marius Vlad78984ee2019-06-11 00:05:08 +03005749 * \ingroup head
Pekka Paalanen7fe858b2017-08-14 15:45:14 +03005750 * \internal
5751 */
5752WL_EXPORT void
5753weston_head_set_connection_status(struct weston_head *head, bool connected)
5754{
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005755 if (head->connected == connected)
5756 return;
5757
Pekka Paalanen7fe858b2017-08-14 15:45:14 +03005758 head->connected = connected;
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03005759
Pekka Paalanene19970f2017-08-28 14:11:02 +03005760 weston_head_set_device_changed(head);
Pekka Paalanen7fe858b2017-08-14 15:45:14 +03005761}
5762
Ankit Nautiyal4f64ff82019-04-03 18:44:35 +05305763static void
5764weston_output_compute_protection(struct weston_output *output)
5765{
5766 struct weston_head *head;
5767 enum weston_hdcp_protection op_protection;
5768 bool op_protection_valid = false;
Ankit Nautiyalf74c35b2019-04-03 19:21:58 +05305769 struct weston_compositor *wc = output->compositor;
Ankit Nautiyal4f64ff82019-04-03 18:44:35 +05305770
5771 wl_list_for_each(head, &output->head_list, output_link) {
5772 if (!op_protection_valid) {
5773 op_protection = head->current_protection;
5774 op_protection_valid = true;
5775 }
5776 if (head->current_protection < op_protection)
5777 op_protection = head->current_protection;
5778 }
5779
5780 if (!op_protection_valid)
5781 op_protection = WESTON_HDCP_DISABLE;
5782
Ankit Nautiyalf74c35b2019-04-03 19:21:58 +05305783 if (output->current_protection != op_protection) {
Ankit Nautiyal4f64ff82019-04-03 18:44:35 +05305784 output->current_protection = op_protection;
Ankit Nautiyalf74c35b2019-04-03 19:21:58 +05305785 weston_output_damage(output);
Ankit Nautiyalfaa5ab42019-07-08 13:23:24 +05305786 weston_schedule_surface_protection_update(wc);
Ankit Nautiyalf74c35b2019-04-03 19:21:58 +05305787 }
Ankit Nautiyal4f64ff82019-04-03 18:44:35 +05305788}
5789
5790WL_EXPORT void
5791weston_head_set_content_protection_status(struct weston_head *head,
5792 enum weston_hdcp_protection status)
5793{
5794 head->current_protection = status;
5795 if (head->output)
5796 weston_output_compute_protection(head->output);
5797}
5798
Pekka Paalanen7fe858b2017-08-14 15:45:14 +03005799/** Is the head currently connected?
5800 *
5801 * \param head The head to query.
5802 * \return Connection status.
5803 *
5804 * Returns true if the head is physically connected to a monitor, or in
5805 * case of a nested backend returns true when there is a connection to the
5806 * parent display server.
5807 *
5808 * This is independent from the head being enabled.
5809 *
5810 * \sa weston_head_is_enabled
Marius Vlad78984ee2019-06-11 00:05:08 +03005811 * \ingroup head
Pekka Paalanen7fe858b2017-08-14 15:45:14 +03005812 */
5813WL_EXPORT bool
5814weston_head_is_connected(struct weston_head *head)
5815{
5816 return head->connected;
5817}
5818
Pekka Paalanen8e552fd2018-02-15 15:18:20 +02005819/** Is the head currently enabled?
5820 *
5821 * \param head The head to query.
5822 * \return Video status.
5823 *
5824 * Returns true if the head is currently transmitting a video stream.
5825 *
5826 * This is independent of the head being connected.
5827 *
5828 * \sa weston_head_is_connected
Marius Vlad78984ee2019-06-11 00:05:08 +03005829 * \ingroup head
Pekka Paalanen8e552fd2018-02-15 15:18:20 +02005830 */
5831WL_EXPORT bool
5832weston_head_is_enabled(struct weston_head *head)
5833{
5834 if (!head->output)
5835 return false;
5836
5837 return head->output->enabled;
5838}
5839
Pekka Paalanene19970f2017-08-28 14:11:02 +03005840/** Has the device information changed?
5841 *
5842 * \param head The head to query.
5843 * \return True if the device information has changed since last reset.
5844 *
5845 * The information about the connected display device, e.g. a monitor, may
5846 * change without being disconnected in between. Changing information
5847 * causes a call to the heads_changed hook.
5848 *
5849 * The information includes make, model, serial number, physical size,
5850 * and sub-pixel type. The connection status is also included.
5851 *
5852 * \sa weston_head_reset_device_changed, weston_compositor_set_heads_changed_cb
Marius Vlad78984ee2019-06-11 00:05:08 +03005853 * \ingroup head
Pekka Paalanene19970f2017-08-28 14:11:02 +03005854 */
5855WL_EXPORT bool
5856weston_head_is_device_changed(struct weston_head *head)
5857{
5858 return head->device_changed;
5859}
5860
Philipp Zabelc18ffd32018-08-30 17:38:03 +02005861/** Does the head represent a non-desktop display?
5862 *
5863 * \param head The head to query.
5864 * \return True if the device is a non-desktop display.
5865 *
5866 * Non-desktop heads are not attached to outputs by default.
5867 * This stops weston from extending the desktop onto head mounted displays.
5868 *
Marius Vlad78984ee2019-06-11 00:05:08 +03005869 * \ingroup head
Philipp Zabelc18ffd32018-08-30 17:38:03 +02005870 */
5871WL_EXPORT bool
5872weston_head_is_non_desktop(struct weston_head *head)
5873{
5874 return head->non_desktop;
5875}
5876
Pekka Paalanene19970f2017-08-28 14:11:02 +03005877/** Acknowledge device information change
5878 *
5879 * \param head The head to acknowledge.
5880 *
5881 * Clears the device changed flag on this head. When a compositor has processed
5882 * device information, it should call this to be able to notice further
5883 * changes.
5884 *
5885 * \sa weston_head_is_device_changed
Marius Vlad78984ee2019-06-11 00:05:08 +03005886 * \ingroup head
Pekka Paalanene19970f2017-08-28 14:11:02 +03005887 */
5888WL_EXPORT void
5889weston_head_reset_device_changed(struct weston_head *head)
5890{
5891 head->device_changed = false;
5892}
5893
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005894/** Get the name of a head
5895 *
5896 * \param head The head to query.
5897 * \return The head's name, not NULL.
5898 *
5899 * The name depends on the backend. The DRM backend uses connector names,
5900 * other backends may use hardcoded names or user-given names.
Marius Vlad78984ee2019-06-11 00:05:08 +03005901 *
5902 * \ingroup head
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005903 */
5904WL_EXPORT const char *
5905weston_head_get_name(struct weston_head *head)
5906{
5907 return head->name;
5908}
5909
5910/** Get the output the head is attached to
5911 *
5912 * \param head The head to query.
5913 * \return The output the head is attached to, or NULL if detached.
Marius Vlad78984ee2019-06-11 00:05:08 +03005914 * \ingroup head
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03005915 */
5916WL_EXPORT struct weston_output *
5917weston_head_get_output(struct weston_head *head)
5918{
5919 return head->output;
5920}
5921
Lucas Stacha69cb712019-11-25 23:29:31 +00005922/** Get the head's native transformation
5923 *
5924 * \param head The head to query.
5925 * \return The head's native transform, as a WL_OUTPUT_TRANSFORM_* value
5926 *
5927 * A weston_head may have a 'native' transform provided by the backend.
5928 * Examples include panels which are physically rotated, where the rotation
5929 * is recorded and described as part of the system configuration. This call
5930 * will return any known native transform for the head.
5931 *
5932 * \ingroup head
5933 */
5934WL_EXPORT uint32_t
5935weston_head_get_transform(struct weston_head *head)
5936{
5937 return head->transform;
5938}
5939
Pekka Paalanen2e1bedb2017-10-10 11:21:58 +03005940/** Add destroy callback for a head
5941 *
5942 * \param head The head to watch for.
5943 * \param listener The listener to add. The \c notify member must be set.
5944 *
5945 * Heads may get destroyed for various reasons by the backends. If a head is
5946 * attached to an output, the compositor should listen for head destruction
5947 * and reconfigure or destroy the output if necessary.
5948 *
5949 * The destroy callbacks will be called on weston_head destruction before any
5950 * automatic detaching from an associated weston_output and before any
5951 * weston_head information is lost.
5952 *
5953 * The \c data argument to the notify callback is the weston_head being
5954 * destroyed.
Marius Vlad78984ee2019-06-11 00:05:08 +03005955 *
5956 * \ingroup head
Pekka Paalanen2e1bedb2017-10-10 11:21:58 +03005957 */
5958WL_EXPORT void
5959weston_head_add_destroy_listener(struct weston_head *head,
5960 struct wl_listener *listener)
5961{
5962 wl_signal_add(&head->destroy_signal, listener);
5963}
5964
5965/** Look up destroy listener for a head
5966 *
5967 * \param head The head to query.
5968 * \param notify The notify function used used for the added destroy listener.
5969 * \return The listener, or NULL if not found.
5970 *
5971 * This looks up the previously added destroy listener struct based on the
5972 * notify function it has. The listener can be used to access user data
5973 * through \c container_of().
5974 *
5975 * \sa wl_signal_get()
Marius Vlad78984ee2019-06-11 00:05:08 +03005976 * \ingroup head
Pekka Paalanen2e1bedb2017-10-10 11:21:58 +03005977 */
5978WL_EXPORT struct wl_listener *
5979weston_head_get_destroy_listener(struct weston_head *head,
5980 wl_notify_func_t notify)
5981{
5982 return wl_signal_get(&head->destroy_signal, notify);
5983}
5984
David Fort0de859e2016-05-27 23:22:57 +02005985/* Move other outputs when one is resized so the space remains contiguous. */
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02005986static void
David Fort0de859e2016-05-27 23:22:57 +02005987weston_compositor_reflow_outputs(struct weston_compositor *compositor,
5988 struct weston_output *resized_output, int delta_width)
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02005989{
5990 struct weston_output *output;
David Fort0de859e2016-05-27 23:22:57 +02005991 bool start_resizing = false;
5992
5993 if (!delta_width)
5994 return;
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02005995
5996 wl_list_for_each(output, &compositor->output_list, link) {
David Fort0de859e2016-05-27 23:22:57 +02005997 if (output == resized_output) {
5998 start_resizing = true;
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02005999 continue;
6000 }
6001
David Fort0de859e2016-05-27 23:22:57 +02006002 if (start_resizing) {
6003 weston_output_move(output, output->x + delta_width, output->y);
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02006004 output->dirty = 1;
6005 }
6006 }
6007}
6008
Pekka Paalanen06920792020-12-08 15:22:36 +02006009/** Transform a region in-place from global to output coordinates
6010 *
6011 * \param output The output that defines the transformation.
6012 * \param region The region to be transformed in-place.
6013 *
6014 * This takes a region in the global coordinate system, and takes into account
6015 * output position, transform and scale, and the zoom, and converts the region
6016 * into output pixel coordinates in the framebuffer.
6017 *
6018 * Uses floating-point operations if zoom is active, which may round to expand
6019 * the region.
6020 *
6021 * \internal
6022 * \ingroup output
6023 */
6024WL_EXPORT void
6025weston_output_region_from_global(struct weston_output *output,
6026 pixman_region32_t *region)
6027{
6028 if (output->zoom.active) {
6029 weston_matrix_transform_region(region, &output->matrix, region);
6030 } else {
6031 pixman_region32_translate(region, -output->x, -output->y);
6032 weston_transformed_region(output->width, output->height,
6033 output->transform,
6034 output->current_scale,
6035 region, region);
6036 }
6037}
6038
Pekka Paalanend72bad22017-03-29 17:01:41 +03006039static void
Scott Moreauccbf29d2012-02-22 14:21:41 -07006040weston_output_update_matrix(struct weston_output *output)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006041{
Scott Moreau850ca422012-05-21 15:21:25 -06006042 float magnification;
Kristian Høgsberg31bd6c72011-02-13 13:00:51 -05006043
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05006044 weston_matrix_init(&output->matrix);
Jason Ekstrandfb23df72014-10-16 10:55:21 -05006045 weston_matrix_translate(&output->matrix, -output->x, -output->y, 0);
Scott Moreau1bad5db2012-08-18 01:04:05 -06006046
Scott Moreauccbf29d2012-02-22 14:21:41 -07006047 if (output->zoom.active) {
Scott Moreaue6603982012-06-11 13:07:51 -06006048 magnification = 1 / (1 - output->zoom.spring_z.current);
Jason Ekstranda7af7042013-10-12 22:38:11 -05006049 weston_output_update_zoom(output);
Neil Roberts1e40a7e2014-04-25 13:19:37 +01006050 weston_matrix_translate(&output->matrix, -output->zoom.trans_x,
Jason Ekstrandfb23df72014-10-16 10:55:21 -05006051 -output->zoom.trans_y, 0);
Neil Roberts1e40a7e2014-04-25 13:19:37 +01006052 weston_matrix_scale(&output->matrix, magnification,
6053 magnification, 1.0);
Scott Moreauccbf29d2012-02-22 14:21:41 -07006054 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006055
Jason Ekstrandfb23df72014-10-16 10:55:21 -05006056 switch (output->transform) {
6057 case WL_OUTPUT_TRANSFORM_FLIPPED:
6058 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
6059 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
6060 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
6061 weston_matrix_translate(&output->matrix, -output->width, 0, 0);
6062 weston_matrix_scale(&output->matrix, -1, 1, 1);
6063 break;
6064 }
6065
6066 switch (output->transform) {
6067 default:
6068 case WL_OUTPUT_TRANSFORM_NORMAL:
6069 case WL_OUTPUT_TRANSFORM_FLIPPED:
6070 break;
6071 case WL_OUTPUT_TRANSFORM_90:
6072 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
Pekka Paalanen8060d822020-02-06 15:27:54 +02006073 weston_matrix_translate(&output->matrix, -output->width, 0, 0);
6074 weston_matrix_rotate_xy(&output->matrix, 0, -1);
Jason Ekstrandfb23df72014-10-16 10:55:21 -05006075 break;
6076 case WL_OUTPUT_TRANSFORM_180:
6077 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
6078 weston_matrix_translate(&output->matrix,
6079 -output->width, -output->height, 0);
6080 weston_matrix_rotate_xy(&output->matrix, -1, 0);
6081 break;
6082 case WL_OUTPUT_TRANSFORM_270:
6083 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
Pekka Paalanen8060d822020-02-06 15:27:54 +02006084 weston_matrix_translate(&output->matrix, 0, -output->height, 0);
6085 weston_matrix_rotate_xy(&output->matrix, 0, 1);
Jason Ekstrandfb23df72014-10-16 10:55:21 -05006086 break;
6087 }
6088
6089 if (output->current_scale != 1)
6090 weston_matrix_scale(&output->matrix,
6091 output->current_scale,
6092 output->current_scale, 1);
Neil Roberts6c3b01f2014-05-06 19:04:15 +01006093
Scott Moreauccbf29d2012-02-22 14:21:41 -07006094 output->dirty = 0;
Derek Foremanc0023212015-03-24 11:36:13 -05006095
6096 weston_matrix_invert(&output->inverse_matrix, &output->matrix);
Scott Moreauccbf29d2012-02-22 14:21:41 -07006097}
6098
Scott Moreau1bad5db2012-08-18 01:04:05 -06006099static void
Alexander Larsson0b135062013-05-28 16:23:36 +02006100weston_output_transform_scale_init(struct weston_output *output, uint32_t transform, uint32_t scale)
Scott Moreau1bad5db2012-08-18 01:04:05 -06006101{
6102 output->transform = transform;
Pekka Paalanen59987fa2016-04-26 15:50:59 +03006103 output->native_scale = scale;
6104 output->current_scale = scale;
Scott Moreau1bad5db2012-08-18 01:04:05 -06006105
Pekka Paalanen59987fa2016-04-26 15:50:59 +03006106 convert_size_by_transform_scale(&output->width, &output->height,
6107 output->current_mode->width,
6108 output->current_mode->height,
6109 transform, scale);
Alexander Larsson4ea95522013-05-22 14:41:37 +02006110}
6111
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02006112static void
6113weston_output_init_geometry(struct weston_output *output, int x, int y)
Scott Moreauccbf29d2012-02-22 14:21:41 -07006114{
6115 output->x = x;
6116 output->y = y;
6117
Pekka Paalanen4b582c72017-03-30 16:04:58 +03006118 pixman_region32_fini(&output->region);
Scott Moreauccbf29d2012-02-22 14:21:41 -07006119 pixman_region32_init_rect(&output->region, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06006120 output->width,
6121 output->height);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006122}
6123
Marius Vlad55d87362019-06-11 01:15:35 +03006124/**
6125 * \ingroup output
6126 */
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006127WL_EXPORT void
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02006128weston_output_move(struct weston_output *output, int x, int y)
6129{
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03006130 struct weston_head *head;
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02006131 struct wl_resource *resource;
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03006132 int ver;
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02006133
6134 output->move_x = x - output->x;
6135 output->move_y = y - output->y;
6136
6137 if (output->move_x == 0 && output->move_y == 0)
6138 return;
6139
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02006140 weston_output_init_geometry(output, x, y);
6141
6142 output->dirty = 1;
6143
6144 /* Move views on this output. */
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02006145 wl_signal_emit(&output->compositor->output_moved_signal, output);
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02006146
6147 /* Notify clients of the change for output position. */
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03006148 wl_list_for_each(head, &output->head_list, output_link) {
6149 wl_resource_for_each(resource, &head->resource_list) {
6150 wl_output_send_geometry(resource,
6151 output->x,
6152 output->y,
6153 head->mm_width,
6154 head->mm_height,
6155 head->subpixel,
6156 head->make,
6157 head->model,
6158 output->transform);
Quanxian Wangb2c86362014-03-14 09:16:25 +08006159
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03006160 ver = wl_resource_get_version(resource);
6161 if (ver >= WL_OUTPUT_DONE_SINCE_VERSION)
6162 wl_output_send_done(resource);
6163 }
Roman Gilge97391c2019-03-29 13:01:06 +01006164
6165 wl_resource_for_each(resource, &head->xdg_output_resource_list) {
6166 zxdg_output_v1_send_logical_position(resource,
6167 output->x,
6168 output->y);
6169 zxdg_output_v1_send_done(resource);
6170 }
Quanxian Wangb2c86362014-03-14 09:16:25 +08006171 }
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02006172}
6173
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03006174/** Signal that a pending output is taken into use.
6175 *
6176 * Removes the output from the pending list and adds it to the compositor's
6177 * list of enabled outputs. The output created signal is emitted.
Giulio Camuffob1147152015-05-06 21:41:57 +03006178 *
Pekka Paalanen2210ad02017-03-30 15:48:06 +03006179 * The output gets an internal ID assigned, and the wl_output global is
6180 * created.
Pekka Paalanen3d2d4972017-03-30 15:19:45 +03006181 *
Giulio Camuffob1147152015-05-06 21:41:57 +03006182 * \param compositor The compositor instance.
6183 * \param output The output to be added.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006184 *
6185 * \internal
Marius Vlad9fdda7f2019-06-11 16:08:55 +03006186 * \ingroup compositor
Giulio Camuffob1147152015-05-06 21:41:57 +03006187 */
Pekka Paalanenf9681b52017-03-29 16:58:48 +03006188static void
Giulio Camuffob1147152015-05-06 21:41:57 +03006189weston_compositor_add_output(struct weston_compositor *compositor,
6190 struct weston_output *output)
6191{
Armin Krezoviće5403842016-08-05 15:28:29 +02006192 struct weston_view *view, *next;
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03006193 struct weston_head *head;
Armin Krezoviće5403842016-08-05 15:28:29 +02006194
Pekka Paalanen7f340ff2017-03-30 14:56:22 +03006195 assert(!output->enabled);
Pekka Paalanen3d2d4972017-03-30 15:19:45 +03006196
6197 /* Verify we haven't reached the limit of 32 available output IDs */
6198 assert(ffs(~compositor->output_id_pool) > 0);
6199
6200 /* Invert the output id pool and look for the lowest numbered
6201 * switch (the least significant bit). Take that bit's position
6202 * as our ID, and mark it used in the compositor's output_id_pool.
6203 */
6204 output->id = ffs(~compositor->output_id_pool) - 1;
6205 compositor->output_id_pool |= 1u << output->id;
6206
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03006207 wl_list_remove(&output->link);
Giulio Camuffob1147152015-05-06 21:41:57 +03006208 wl_list_insert(compositor->output_list.prev, &output->link);
Pekka Paalanen7f340ff2017-03-30 14:56:22 +03006209 output->enabled = true;
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03006210
Pekka Paalanendcac3512017-12-08 14:13:34 +02006211 wl_list_for_each(head, &output->head_list, output_link)
6212 weston_head_add_global(head);
Pekka Paalanen2210ad02017-03-30 15:48:06 +03006213
Giulio Camuffob1147152015-05-06 21:41:57 +03006214 wl_signal_emit(&compositor->output_created_signal, output);
Armin Krezoviće5403842016-08-05 15:28:29 +02006215
Pekka Paalanen6551c092021-05-03 16:09:45 +03006216 /*
6217 * Use view_list, as paint nodes have not been created for this
6218 * output yet. Any existing view might touch this new output.
6219 */
Armin Krezoviće5403842016-08-05 15:28:29 +02006220 wl_list_for_each_safe(view, next, &compositor->view_list, link)
6221 weston_view_geometry_dirty(view);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006222}
6223
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006224/** Transform device coordinates into global coordinates
6225 *
Marius Vlada2dace22019-06-12 16:05:44 +03006226 * \param output the weston_output object
6227 * \param[in] device_x X coordinate in device units.
6228 * \param[in] device_y Y coordinate in device units.
6229 * \param[out] x X coordinate in the global space.
6230 * \param[out] y Y coordinate in the global space.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006231 *
Marius Vlada2dace22019-06-12 16:05:44 +03006232 * Transforms coordinates from the device coordinate space (physical pixel
6233 * units) to the global coordinate space (logical pixel units). This takes
6234 * into account output transform and scale.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006235 *
Marius Vlad55d87362019-06-11 01:15:35 +03006236 * \ingroup output
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006237 * \internal
6238 */
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07006239WL_EXPORT void
6240weston_output_transform_coordinate(struct weston_output *output,
Giulio Camuffo90a6fc62016-03-22 17:44:54 +02006241 double device_x, double device_y,
6242 double *x, double *y)
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07006243{
Derek Foreman0f679412014-10-02 13:41:17 -05006244 struct weston_vector p = { {
Giulio Camuffo90a6fc62016-03-22 17:44:54 +02006245 device_x,
6246 device_y,
Derek Foreman0f679412014-10-02 13:41:17 -05006247 0.0,
6248 1.0 } };
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07006249
Derek Foreman67a18b92015-03-24 11:36:14 -05006250 weston_matrix_transform(&output->inverse_matrix, &p);
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07006251
Giulio Camuffo90a6fc62016-03-22 17:44:54 +02006252 *x = p.f[0] / p.f[3];
6253 *y = p.f[1] / p.f[3];
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07006254}
6255
Pekka Paalanen1d2eee22021-02-25 12:03:28 +02006256static void
6257weston_output_reset_color_transforms(struct weston_output *output)
6258{
Pekka Paalanencda39512021-03-22 17:32:07 +02006259 weston_color_transform_unref(output->from_sRGB_to_output);
6260 output->from_sRGB_to_output = NULL;
Pekka Paalanen8fb23ed2021-03-23 13:40:43 +02006261 weston_color_transform_unref(output->from_sRGB_to_blend);
6262 output->from_sRGB_to_blend = NULL;
Pekka Paalanen1d2eee22021-02-25 12:03:28 +02006263 weston_color_transform_unref(output->from_blend_to_output);
6264 output->from_blend_to_output = NULL;
6265}
6266
Pekka Paalanene6ac4fc2017-03-29 16:07:34 +03006267/** Removes output from compositor's list of enabled outputs
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006268 *
6269 * \param output The weston_output object that is being removed.
6270 *
Pekka Paalanene6ac4fc2017-03-29 16:07:34 +03006271 * The following happens:
6272 *
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03006273 * - Destroys all paint nodes related to the output.
6274 *
Pekka Paalanene6ac4fc2017-03-29 16:07:34 +03006275 * - The output assignments of all views in the current scenegraph are
6276 * recomputed.
6277 *
Pekka Paalanen1d2eee22021-02-25 12:03:28 +02006278 * - Destroys output's color transforms.
6279 *
Pekka Paalanene6ac4fc2017-03-29 16:07:34 +03006280 * - Presentation feedback is discarded.
6281 *
6282 * - Compositor is notified that outputs were changed and
6283 * applies the necessary changes to re-layout outputs.
6284 *
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03006285 * - The output is put back in the pending outputs list.
6286 *
Pekka Paalanene6ac4fc2017-03-29 16:07:34 +03006287 * - Signal is emitted to notify all users of the weston_output
6288 * object that the output is being destroyed.
6289 *
6290 * - wl_output protocol objects referencing this weston_output
Pekka Paalanen2210ad02017-03-30 15:48:06 +03006291 * are made inert, and the wl_output global is removed.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006292 *
Pekka Paalanen3d2d4972017-03-30 15:19:45 +03006293 * - The output's internal ID is released.
6294 *
Marius Vlad9fdda7f2019-06-11 16:08:55 +03006295 * \ingroup compositor
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006296 * \internal
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006297 */
6298static void
6299weston_compositor_remove_output(struct weston_output *output)
6300{
Pekka Paalanenbccda712017-03-29 16:16:04 +03006301 struct weston_compositor *compositor = output->compositor;
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03006302 struct weston_paint_node *pnode, *pntmp;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006303 struct weston_view *view;
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03006304 struct weston_head *head;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006305
6306 assert(output->destroying);
Pekka Paalanen7f340ff2017-03-30 14:56:22 +03006307 assert(output->enabled);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006308
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03006309 wl_list_for_each_safe(pnode, pntmp,
6310 &output->paint_node_list, output_link) {
6311 weston_paint_node_destroy(pnode);
6312 }
Pekka Paalanen2fddc532021-04-30 17:41:29 +03006313 assert(wl_list_empty(&output->paint_node_z_order_list));
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03006314
Pekka Paalanen6551c092021-05-03 16:09:45 +03006315 /*
6316 * Use view_list in case the output did not go through repaint
6317 * after a view came on it, lacking a paint node. Just to be sure.
6318 */
Pekka Paalanenbccda712017-03-29 16:16:04 +03006319 wl_list_for_each(view, &compositor->view_list, link) {
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006320 if (view->output_mask & (1u << output->id))
6321 weston_view_assign_output(view);
6322 }
6323
Pekka Paalanen1d2eee22021-02-25 12:03:28 +02006324 weston_output_reset_color_transforms(output);
6325
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006326 weston_presentation_feedback_discard_list(&output->feedback_list);
6327
Pekka Paalanen9711fd92018-06-21 14:26:18 +03006328 weston_compositor_reflow_outputs(compositor, output, -output->width);
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03006329
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006330 wl_list_remove(&output->link);
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03006331 wl_list_insert(compositor->pending_output_list.prev, &output->link);
Pekka Paalanen7f340ff2017-03-30 14:56:22 +03006332 output->enabled = false;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006333
Pekka Paalanenbccda712017-03-29 16:16:04 +03006334 wl_signal_emit(&compositor->output_destroyed_signal, output);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006335 wl_signal_emit(&output->destroy_signal, output);
6336
Pekka Paalanend9dcc6d2017-12-04 15:28:13 +02006337 wl_list_for_each(head, &output->head_list, output_link)
6338 weston_head_remove_global(head);
Pekka Paalanen3d2d4972017-03-30 15:19:45 +03006339
6340 compositor->output_id_pool &= ~(1u << output->id);
6341 output->id = 0xffffffff; /* invalid */
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006342}
6343
6344/** Sets the output scale for a given output.
6345 *
6346 * \param output The weston_output object that the scale is set for.
6347 * \param scale Scale factor for the given output.
6348 *
6349 * It only supports setting scale for an output that
6350 * is not enabled and it can only be ran once.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006351 *
Maxime Roussin-Bélanger1d009c22020-12-17 17:10:13 -05006352 * \ingroup output
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006353 */
6354WL_EXPORT void
6355weston_output_set_scale(struct weston_output *output,
6356 int32_t scale)
6357{
6358 /* We can only set scale on a disabled output */
6359 assert(!output->enabled);
6360
6361 /* We only want to set scale once */
6362 assert(!output->scale);
6363
6364 output->scale = scale;
6365}
6366
6367/** Sets the output transform for a given output.
6368 *
6369 * \param output The weston_output object that the transform is set for.
6370 * \param transform Transform value for the given output.
6371 *
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006372 * Refer to wl_output::transform section located at
6373 * https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_output
6374 * for list of values that can be passed to this function.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006375 *
Marius Vlad55d87362019-06-11 01:15:35 +03006376 * \ingroup output
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006377 */
6378WL_EXPORT void
6379weston_output_set_transform(struct weston_output *output,
6380 uint32_t transform)
6381{
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00006382 struct weston_pointer_motion_event ev;
6383 struct wl_resource *resource;
6384 struct weston_seat *seat;
6385 pixman_region32_t old_region;
6386 int mid_x, mid_y;
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03006387 struct weston_head *head;
6388 int ver;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006389
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00006390 if (!output->enabled && output->transform == UINT32_MAX) {
6391 output->transform = transform;
6392 return;
6393 }
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006394
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00006395 weston_output_transform_scale_init(output, transform, output->scale);
6396
6397 pixman_region32_init(&old_region);
6398 pixman_region32_copy(&old_region, &output->region);
6399
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00006400 weston_output_init_geometry(output, output->x, output->y);
6401
6402 output->dirty = 1;
6403
6404 /* Notify clients of the change for output transform. */
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03006405 wl_list_for_each(head, &output->head_list, output_link) {
6406 wl_resource_for_each(resource, &head->resource_list) {
6407 wl_output_send_geometry(resource,
6408 output->x,
6409 output->y,
6410 head->mm_width,
6411 head->mm_height,
6412 head->subpixel,
6413 head->make,
6414 head->model,
6415 output->transform);
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00006416
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03006417 ver = wl_resource_get_version(resource);
6418 if (ver >= WL_OUTPUT_DONE_SINCE_VERSION)
6419 wl_output_send_done(resource);
6420 }
Roman Gilge97391c2019-03-29 13:01:06 +01006421 wl_resource_for_each(resource, &head->xdg_output_resource_list) {
6422 zxdg_output_v1_send_logical_position(resource,
6423 output->x,
6424 output->y);
6425 zxdg_output_v1_send_logical_size(resource,
6426 output->width,
6427 output->height);
6428 zxdg_output_v1_send_done(resource);
6429 }
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00006430 }
6431
6432 /* we must ensure that pointers are inside output, otherwise they disappear */
6433 mid_x = output->x + output->width / 2;
6434 mid_y = output->y + output->height / 2;
6435
6436 ev.mask = WESTON_POINTER_MOTION_ABS;
6437 ev.x = wl_fixed_to_double(wl_fixed_from_int(mid_x));
6438 ev.y = wl_fixed_to_double(wl_fixed_from_int(mid_y));
6439
6440 wl_list_for_each(seat, &output->compositor->seat_list, link) {
6441 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
6442
6443 if (pointer && pixman_region32_contains_point(&old_region,
6444 wl_fixed_to_int(pointer->x),
6445 wl_fixed_to_int(pointer->y),
6446 NULL))
6447 weston_pointer_move(pointer, &ev);
6448 }
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006449}
6450
6451/** Initializes a weston_output object with enough data so
6452 ** an output can be configured.
6453 *
6454 * \param output The weston_output object to initialize
6455 * \param compositor The compositor instance.
Pekka Paalanen26ac2e12017-04-03 13:18:13 +03006456 * \param name Name for the output (the string is copied).
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006457 *
6458 * Sets initial values for fields that are expected to be
6459 * configured either by compositors or backends.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006460 *
Pekka Paalanen26ac2e12017-04-03 13:18:13 +03006461 * The name is used in logs, and can be used by compositors as a configuration
6462 * identifier.
6463 *
Marius Vlad55d87362019-06-11 01:15:35 +03006464 * \ingroup output
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006465 * \internal
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006466 */
6467WL_EXPORT void
Armin Krezović40087402016-09-30 14:11:12 +02006468weston_output_init(struct weston_output *output,
Pekka Paalanen26ac2e12017-04-03 13:18:13 +03006469 struct weston_compositor *compositor,
6470 const char *name)
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006471{
6472 output->compositor = compositor;
6473 output->destroying = 0;
Pekka Paalanen26ac2e12017-04-03 13:18:13 +03006474 output->name = strdup(name);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006475 wl_list_init(&output->link);
Pekka Paalanen37b7c6e2017-11-07 10:15:01 +02006476 wl_signal_init(&output->user_destroy_signal);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006477 output->enabled = false;
Ankit Nautiyal2690a772019-03-25 17:57:59 +05306478 output->desired_protection = WESTON_HDCP_DISABLE;
Ankit Nautiyal2844f8e2019-04-03 10:14:59 +05306479 output->allow_protection = true;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006480
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03006481 wl_list_init(&output->head_list);
6482
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006483 /* Add some (in)sane defaults which can be used
6484 * for checking if an output was properly configured
6485 */
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006486 output->scale = 0;
6487 /* Can't use -1 on uint32_t and 0 is valid enum value */
6488 output->transform = UINT32_MAX;
Pekka Paalanen4b582c72017-03-30 16:04:58 +03006489
Pekka Paalanen4b582c72017-03-30 16:04:58 +03006490 pixman_region32_init(&output->region);
Pekka Paalanen42704142017-09-06 16:47:52 +03006491 wl_list_init(&output->mode_list);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006492}
6493
6494/** Adds weston_output object to pending output list.
6495 *
6496 * \param output The weston_output object to add
6497 * \param compositor The compositor instance.
6498 *
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03006499 * The opposite of this operation is built into weston_output_release().
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006500 *
Marius Vlad9fdda7f2019-06-11 16:08:55 +03006501 * \ingroup compositor
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006502 * \internal
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006503 */
6504WL_EXPORT void
6505weston_compositor_add_pending_output(struct weston_output *output,
6506 struct weston_compositor *compositor)
6507{
Pekka Paalanene952a012017-03-29 17:14:00 +03006508 assert(output->disable);
6509 assert(output->enable);
6510
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03006511 wl_list_remove(&output->link);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006512 wl_list_insert(compositor->pending_output_list.prev, &output->link);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006513}
6514
Pekka Paalanen3e8f2012017-11-02 14:03:11 +02006515/** Create a string with the attached heads' names.
6516 *
6517 * The string must be free()'d.
Marius Vlad55d87362019-06-11 01:15:35 +03006518 *
6519 * \ingroup output
Pekka Paalanen3e8f2012017-11-02 14:03:11 +02006520 */
6521static char *
6522weston_output_create_heads_string(struct weston_output *output)
6523{
6524 FILE *fp;
6525 char *str = NULL;
6526 size_t size = 0;
6527 struct weston_head *head;
6528 const char *sep = "";
6529
6530 fp = open_memstream(&str, &size);
6531 if (!fp)
6532 return NULL;
6533
6534 wl_list_for_each(head, &output->head_list, output_link) {
6535 fprintf(fp, "%s%s", sep, head->name);
6536 sep = ", ";
6537 }
6538 fclose(fp);
6539
6540 return str;
6541}
6542
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006543/** Constructs a weston_output object that can be used by the compositor.
6544 *
Pekka Paalanencc201e42017-03-30 15:11:25 +03006545 * \param output The weston_output object that needs to be enabled. Must not
Pekka Paalanenddce54d2017-08-23 16:00:21 +03006546 * be enabled already. Must have at least one head attached.
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006547 *
6548 * Output coordinates are calculated and each new output is by default
6549 * assigned to the right of previous one.
6550 *
6551 * Sets up the transformation, zoom, and geometry of the output using
6552 * the properties that need to be configured by the compositor.
6553 *
6554 * Establishes a repaint timer for the output with the relevant display
6555 * object's event loop. See output_repaint_timer_handler().
6556 *
6557 * The output is assigned an ID. Weston can support up to 32 distinct
6558 * outputs, with IDs numbered from 0-31; the compositor's output_id_pool
6559 * is referred to and used to find the first available ID number, and
6560 * then this ID is marked as used in output_id_pool.
6561 *
6562 * The output is also assigned a Wayland global with the wl_output
6563 * external interface.
6564 *
6565 * Backend specific function is called to set up the output output.
6566 *
6567 * Output is added to the compositor's output list
6568 *
6569 * If the backend specific function fails, the weston_output object
6570 * is returned to a state it was before calling this function and
6571 * is added to the compositor's pending_output_list in case it needs
6572 * to be reconfigured or just so it can be destroyed at shutdown.
6573 *
6574 * 0 is returned on success, -1 on failure.
Marius Vlad55d87362019-06-11 01:15:35 +03006575 *
6576 * \ingroup output
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006577 */
6578WL_EXPORT int
6579weston_output_enable(struct weston_output *output)
6580{
Armin Krezović782f5df2016-09-30 14:11:11 +02006581 struct weston_compositor *c = output->compositor;
Pekka Paalanen1d2eee22021-02-25 12:03:28 +02006582 struct weston_color_manager *cm = c->color_manager;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006583 struct weston_output *iterator;
Pekka Paalanenec25b0a2017-08-24 16:08:49 +03006584 struct weston_head *head;
Pekka Paalanen3e8f2012017-11-02 14:03:11 +02006585 char *head_names;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006586 int x = 0, y = 0;
Pekka Paalanen1d2eee22021-02-25 12:03:28 +02006587 bool ok;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006588
Pekka Paalanencc201e42017-03-30 15:11:25 +03006589 if (output->enabled) {
6590 weston_log("Error: attempt to enable an enabled output '%s'\n",
6591 output->name);
6592 return -1;
6593 }
6594
Pekka Paalanenddce54d2017-08-23 16:00:21 +03006595 if (wl_list_empty(&output->head_list)) {
6596 weston_log("Error: cannot enable output '%s' without heads.\n",
6597 output->name);
6598 return -1;
6599 }
6600
Pekka Paalanen586e1ac2017-09-14 16:17:59 +03006601 if (wl_list_empty(&output->mode_list) || !output->current_mode) {
6602 weston_log("Error: no video mode for output '%s'.\n",
6603 output->name);
6604 return -1;
6605 }
6606
Pekka Paalanenec25b0a2017-08-24 16:08:49 +03006607 wl_list_for_each(head, &output->head_list, output_link) {
6608 assert(head->make);
6609 assert(head->model);
6610 }
6611
Armin Krezović782f5df2016-09-30 14:11:11 +02006612 iterator = container_of(c->output_list.prev,
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006613 struct weston_output, link);
6614
Armin Krezović782f5df2016-09-30 14:11:11 +02006615 if (!wl_list_empty(&c->output_list))
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006616 x = iterator->x + iterator->width;
6617
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006618 /* Make sure the scale is set up */
6619 assert(output->scale);
6620
6621 /* Make sure we have a transform set */
6622 assert(output->transform != UINT32_MAX);
6623
Armin Krezović782f5df2016-09-30 14:11:11 +02006624 output->x = x;
6625 output->y = y;
6626 output->dirty = 1;
6627 output->original_scale = output->scale;
6628
Marius Vlad3a2f8292019-11-04 17:53:46 +02006629 wl_signal_init(&output->frame_signal);
6630 wl_signal_init(&output->destroy_signal);
6631
Armin Krezović782f5df2016-09-30 14:11:11 +02006632 weston_output_transform_scale_init(output, output->transform, output->scale);
6633 weston_output_init_zoom(output);
6634
6635 weston_output_init_geometry(output, x, y);
6636 weston_output_damage(output);
6637
Armin Krezović782f5df2016-09-30 14:11:11 +02006638 wl_list_init(&output->animation_list);
Armin Krezović782f5df2016-09-30 14:11:11 +02006639 wl_list_init(&output->feedback_list);
Pekka Paalanen1a4f87d2021-04-30 14:48:52 +03006640 wl_list_init(&output->paint_node_list);
Pekka Paalanen2fddc532021-04-30 17:41:29 +03006641 wl_list_init(&output->paint_node_z_order_list);
Armin Krezović782f5df2016-09-30 14:11:11 +02006642
Pekka Paalanen1d2eee22021-02-25 12:03:28 +02006643 ok = cm->get_output_color_transform(cm, output,
6644 &output->from_blend_to_output);
Pekka Paalanencda39512021-03-22 17:32:07 +02006645 ok = ok && cm->get_sRGB_to_output_color_transform(cm, output,
6646 &output->from_sRGB_to_output);
Pekka Paalanen8fb23ed2021-03-23 13:40:43 +02006647 ok = ok && cm->get_sRGB_to_blend_color_transform(cm, output,
6648 &output->from_sRGB_to_blend);
Pekka Paalanen1d2eee22021-02-25 12:03:28 +02006649 if (!ok) {
6650 weston_log("Creating color transformation for output \"%s\" failed.\n",
6651 output->name);
6652 weston_output_reset_color_transforms(output);
6653 return -1;
6654 }
6655 output->from_blend_to_output_by_backend = false;
6656
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006657 /* Enable the output (set up the crtc or create a
6658 * window representing the output, set up the
6659 * renderer, etc)
6660 */
6661 if (output->enable(output) < 0) {
6662 weston_log("Enabling output \"%s\" failed.\n", output->name);
Pekka Paalanen1d2eee22021-02-25 12:03:28 +02006663 weston_output_reset_color_transforms(output);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006664 return -1;
6665 }
6666
6667 weston_compositor_add_output(output->compositor, output);
6668
Pekka Paalanen3e8f2012017-11-02 14:03:11 +02006669 head_names = weston_output_create_heads_string(output);
6670 weston_log("Output '%s' enabled with head(s) %s\n",
6671 output->name, head_names);
6672 free(head_names);
6673
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006674 return 0;
6675}
6676
6677/** Converts a weston_output object to a pending output state, so it
6678 ** can be configured again or destroyed.
6679 *
6680 * \param output The weston_output object that needs to be disabled.
6681 *
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006682 * Calls a backend specific function to disable an output, in case
6683 * such function exists.
6684 *
Pekka Paalanenc65df642017-03-29 15:45:46 +03006685 * The backend specific disable function may choose to postpone the disabling
6686 * by returning a negative value, in which case this function returns early.
6687 * In that case the backend will guarantee the output will be disabled soon
6688 * by the backend calling this function again. One must not attempt to re-enable
6689 * the output until that happens.
6690 *
6691 * Otherwise, if the output is being used by the compositor, it is removed
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006692 * from weston's output_list (see weston_compositor_remove_output())
6693 * and is returned to a state it was before weston_output_enable()
6694 * was ran (see weston_output_enable_undo()).
6695 *
Pekka Paalanenc65df642017-03-29 15:45:46 +03006696 * See weston_output_init() for more information on the
6697 * state output is returned to.
Pekka Paalanencc201e42017-03-30 15:11:25 +03006698 *
6699 * If the output has never been enabled yet, this function can still be
6700 * called to ensure that the output is actually turned off rather than left
6701 * in the state it was discovered in.
Marius Vlad55d87362019-06-11 01:15:35 +03006702 *
6703 * \ingroup output
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006704 */
6705WL_EXPORT void
6706weston_output_disable(struct weston_output *output)
6707{
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006708 /* Should we rename this? */
6709 output->destroying = 1;
6710
Pekka Paalanenc65df642017-03-29 15:45:46 +03006711 /* Disable is called unconditionally also for not-enabled outputs,
6712 * because at compositor start-up, if there is an output that is
6713 * already on but the compositor wants to turn it off, we have to
6714 * forward the turn-off to the backend so it knows to do it.
6715 * The backend cannot initially turn off everything, because it
6716 * would cause unnecessary mode-sets for all outputs the compositor
6717 * wants to be on.
6718 */
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006719 if (output->disable(output) < 0)
6720 return;
6721
Pekka Paalanen2ec15eb2021-06-09 16:14:45 +03006722 if (output->enabled) {
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006723 weston_compositor_remove_output(output);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006724
Pekka Paalanen2ec15eb2021-06-09 16:14:45 +03006725 assert(wl_list_empty(&output->paint_node_list));
6726 }
6727
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006728 output->destroying = 0;
6729}
6730
Pekka Paalanen8a8dcac2017-08-17 17:29:36 +03006731/** Forces a synchronous call to heads_changed hook
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006732 *
6733 * \param compositor The compositor instance
Pekka Paalanen8a8dcac2017-08-17 17:29:36 +03006734 *
6735 * If there are new or changed heads, calls the heads_changed hook and
6736 * returns after the hook returns.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03006737 *
6738 * \ingroup compositor
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006739 */
6740WL_EXPORT void
Pekka Paalanen8a8dcac2017-08-17 17:29:36 +03006741weston_compositor_flush_heads_changed(struct weston_compositor *compositor)
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006742{
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03006743 if (compositor->heads_changed_source) {
6744 wl_event_source_remove(compositor->heads_changed_source);
6745 weston_compositor_call_heads_changed(compositor);
6746 }
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006747}
6748
Pekka Paalanen37b7c6e2017-11-07 10:15:01 +02006749/** Add destroy callback for an output
6750 *
6751 * \param output The output to watch.
6752 * \param listener The listener to add. The \c notify member must be set.
6753 *
6754 * The listener callback will be called when user destroys an output. This
6755 * may be delayed by a backend in some cases. The main purpose of the
6756 * listener is to allow hooking up custom data to the output. The custom data
6757 * can be fetched via weston_output_get_destroy_listener() followed by
6758 * container_of().
6759 *
6760 * The \c data argument to the notify callback is the weston_output being
6761 * destroyed.
6762 *
6763 * @note This is for the final destruction of an output, not when it gets
6764 * disabled. If you want to keep track of enabled outputs, this is not it.
Marius Vlad55d87362019-06-11 01:15:35 +03006765 *
Maxime Roussin-Bélanger1d009c22020-12-17 17:10:13 -05006766 * \ingroup output
Pekka Paalanen37b7c6e2017-11-07 10:15:01 +02006767 */
6768WL_EXPORT void
6769weston_output_add_destroy_listener(struct weston_output *output,
6770 struct wl_listener *listener)
6771{
6772 wl_signal_add(&output->user_destroy_signal, listener);
6773}
6774
6775/** Look up destroy listener for an output
6776 *
6777 * \param output The output to query.
6778 * \param notify The notify function used used for the added destroy listener.
6779 * \return The listener, or NULL if not found.
6780 *
6781 * This looks up the previously added destroy listener struct based on the
6782 * notify function it has. The listener can be used to access user data
6783 * through \c container_of().
6784 *
6785 * \sa wl_signal_get() weston_output_add_destroy_listener()
Marius Vlad55d87362019-06-11 01:15:35 +03006786 * \ingroup output
Pekka Paalanen37b7c6e2017-11-07 10:15:01 +02006787 */
6788WL_EXPORT struct wl_listener *
6789weston_output_get_destroy_listener(struct weston_output *output,
6790 wl_notify_func_t notify)
6791{
6792 return wl_signal_get(&output->user_destroy_signal, notify);
6793}
6794
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006795/** Uninitialize an output
6796 *
6797 * Removes the output from the list of enabled outputs if necessary, but
6798 * does not call the backend's output disable function. The output will no
6799 * longer be in the list of pending outputs either.
6800 *
6801 * All fields of weston_output become uninitialized, i.e. should not be used
6802 * anymore. The caller can free the memory after this.
6803 *
Maxime Roussin-Bélanger1d009c22020-12-17 17:10:13 -05006804 * \ingroup output
Pekka Paalanenee16ea92017-03-29 16:53:50 +03006805 * \internal
6806 */
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006807WL_EXPORT void
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03006808weston_output_release(struct weston_output *output)
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006809{
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03006810 struct weston_head *head, *tmp;
6811
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006812 output->destroying = 1;
6813
Pekka Paalanen37b7c6e2017-11-07 10:15:01 +02006814 wl_signal_emit(&output->user_destroy_signal, output);
6815
Pekka Paalanendcbcfc72017-10-26 14:33:59 +03006816 if (output->idle_repaint_source)
6817 wl_event_source_remove(output->idle_repaint_source);
6818
Pekka Paalanen4b582c72017-03-30 16:04:58 +03006819 if (output->enabled)
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006820 weston_compositor_remove_output(output);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006821
Pekka Paalanen4b582c72017-03-30 16:04:58 +03006822 pixman_region32_fini(&output->region);
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03006823 wl_list_remove(&output->link);
Pekka Paalanen7cdbabe2017-03-28 16:27:25 +03006824
6825 wl_list_for_each_safe(head, tmp, &output->head_list, output_link)
6826 weston_head_detach(head);
6827
Armin Krezovića01ab6d2016-09-30 14:11:02 +02006828 free(output->name);
6829}
6830
Pekka Paalanen1ae9d082017-11-02 14:11:53 +02006831/** Find an output by its given name
6832 *
6833 * \param compositor The compositor to search in.
6834 * \param name The output name to search for.
6835 * \return An existing output with the given name, or NULL if not found.
6836 *
Marius Vlad9fdda7f2019-06-11 16:08:55 +03006837 * \ingroup compositor
Pekka Paalanen1ae9d082017-11-02 14:11:53 +02006838 */
6839WL_EXPORT struct weston_output *
6840weston_compositor_find_output_by_name(struct weston_compositor *compositor,
6841 const char *name)
6842{
6843 struct weston_output *output;
6844
6845 wl_list_for_each(output, &compositor->output_list, link)
6846 if (strcmp(output->name, name) == 0)
6847 return output;
6848
6849 wl_list_for_each(output, &compositor->pending_output_list, link)
6850 if (strcmp(output->name, name) == 0)
6851 return output;
6852
6853 return NULL;
6854}
6855
6856/** Create a named output
6857 *
6858 * \param compositor The compositor.
6859 * \param name The name for the output.
6860 * \return A new \c weston_output, or NULL on failure.
6861 *
6862 * This creates a new weston_output that starts with no heads attached.
6863 *
6864 * An output must be configured and it must have at least one head before
6865 * it can be enabled.
6866 *
Marius Vlad9fdda7f2019-06-11 16:08:55 +03006867 * \ingroup compositor
Pekka Paalanen1ae9d082017-11-02 14:11:53 +02006868 */
6869WL_EXPORT struct weston_output *
6870weston_compositor_create_output(struct weston_compositor *compositor,
6871 const char *name)
6872{
6873 assert(compositor->backend->create_output);
6874
6875 if (weston_compositor_find_output_by_name(compositor, name)) {
6876 weston_log("Warning: attempted to create an output with a "
6877 "duplicate name '%s'.\n", name);
6878 return NULL;
6879 }
6880
6881 return compositor->backend->create_output(compositor, name);
6882}
6883
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03006884/** Create an output for an unused head
6885 *
6886 * \param compositor The compositor.
6887 * \param head The head to attach to the output.
6888 * \return A new \c weston_output, or NULL on failure.
6889 *
6890 * This creates a new weston_output that starts with the given head attached.
6891 * The output inherits the name of the head. The head must not be already
6892 * attached to another output.
6893 *
6894 * An output must be configured before it can be enabled.
6895 *
Marius Vlad9fdda7f2019-06-11 16:08:55 +03006896 * \ingroup compositor
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03006897 */
6898WL_EXPORT struct weston_output *
6899weston_compositor_create_output_with_head(struct weston_compositor *compositor,
6900 struct weston_head *head)
6901{
6902 struct weston_output *output;
6903
Pekka Paalanen1ae9d082017-11-02 14:11:53 +02006904 output = weston_compositor_create_output(compositor, head->name);
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03006905 if (!output)
6906 return NULL;
6907
6908 if (weston_output_attach_head(output, head) < 0) {
Pekka Paalanen42c0e142017-10-27 12:07:49 +03006909 weston_output_destroy(output);
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03006910 return NULL;
6911 }
6912
6913 return output;
6914}
6915
6916/** Destroy an output
6917 *
6918 * \param output The output to destroy.
6919 *
6920 * The heads attached to the given output are detached and become unused again.
6921 *
6922 * It is not necessary to explicitly destroy all outputs at compositor exit.
Leandro Ribeiroca640d52020-01-27 19:12:01 -03006923 * weston_compositor_destroy() will automatically destroy any remaining
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03006924 * outputs.
6925 *
Maxime Roussin-Bélanger1d009c22020-12-17 17:10:13 -05006926 * \ingroup output
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03006927 */
6928WL_EXPORT void
6929weston_output_destroy(struct weston_output *output)
6930{
Pekka Paalanen992a8cb2017-08-16 10:39:17 +03006931 output->destroy(output);
6932}
6933
Pekka Paalanencf0a4762017-04-04 16:36:07 +03006934/** When you need a head...
6935 *
6936 * This function is a hack, used until all code has been converted to become
6937 * multi-head aware.
6938 *
6939 * \param output The weston_output whose head to get.
6940 * \return The first head in the output's list.
Marius Vlad55d87362019-06-11 01:15:35 +03006941 *
Maxime Roussin-Bélanger1d009c22020-12-17 17:10:13 -05006942 * \ingroup output
Pekka Paalanencf0a4762017-04-04 16:36:07 +03006943 */
6944WL_EXPORT struct weston_head *
6945weston_output_get_first_head(struct weston_output *output)
6946{
6947 if (wl_list_empty(&output->head_list))
6948 return NULL;
6949
6950 return container_of(output->head_list.next,
6951 struct weston_head, output_link);
6952}
6953
Ankit Nautiyal2844f8e2019-04-03 10:14:59 +05306954/** Allow/Disallow content-protection support for an output
6955 *
6956 * This function sets the allow_protection member for an output. Setting of
6957 * this field will allow the compositor to attempt content-protection for this
6958 * output, for a backend that supports the content-protection protocol.
6959 *
6960 * \param output The weston_output for whom the content-protection is to be
6961 * allowed.
6962 * \param allow_protection The bool value which is to be set.
6963 */
6964WL_EXPORT void
6965weston_output_allow_protection(struct weston_output *output,
6966 bool allow_protection)
6967{
6968 output->allow_protection = allow_protection;
6969}
6970
Benjamin Franzke315b3dc2011-03-08 11:32:57 +01006971static void
Roman Gilge97391c2019-03-29 13:01:06 +01006972xdg_output_unlist(struct wl_resource *resource)
6973{
6974 wl_list_remove(wl_resource_get_link(resource));
6975}
6976
6977static void
6978xdg_output_destroy(struct wl_client *client, struct wl_resource *resource)
6979{
6980 wl_resource_destroy(resource);
6981}
6982
6983static const struct zxdg_output_v1_interface xdg_output_interface = {
6984 xdg_output_destroy
6985};
6986
6987static void
6988xdg_output_manager_destroy(struct wl_client *client,
6989 struct wl_resource *resource)
6990{
6991 wl_resource_destroy(resource);
6992}
6993
6994static void
6995xdg_output_manager_get_xdg_output(struct wl_client *client,
6996 struct wl_resource *manager,
6997 uint32_t id,
6998 struct wl_resource *output_resource)
6999{
7000 int version = wl_resource_get_version(manager);
7001 struct weston_head *head = wl_resource_get_user_data(output_resource);
7002 struct weston_output *output = head->output;
7003 struct wl_resource *resource;
7004
7005 resource = wl_resource_create(client, &zxdg_output_v1_interface,
7006 version, id);
7007 if (resource == NULL) {
7008 wl_client_post_no_memory(client);
7009 return;
7010 }
7011
7012 wl_list_insert(&head->xdg_output_resource_list,
7013 wl_resource_get_link(resource));
7014
7015 wl_resource_set_implementation(resource, &xdg_output_interface,
7016 NULL, xdg_output_unlist);
7017
7018 zxdg_output_v1_send_logical_position(resource, output->x, output->y);
7019 zxdg_output_v1_send_logical_size(resource,
7020 output->width,
7021 output->height);
7022 if (version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION)
7023 zxdg_output_v1_send_name(resource, head->name);
7024
7025 zxdg_output_v1_send_done(resource);
7026}
7027
7028static const struct zxdg_output_manager_v1_interface xdg_output_manager_interface = {
7029 xdg_output_manager_destroy,
7030 xdg_output_manager_get_xdg_output
7031};
7032
7033static void
7034bind_xdg_output_manager(struct wl_client *client,
7035 void *data, uint32_t version, uint32_t id)
7036{
7037 struct wl_resource *resource;
7038
7039 resource = wl_resource_create(client, &zxdg_output_manager_v1_interface,
7040 version, id);
7041 if (resource == NULL) {
7042 wl_client_post_no_memory(client);
7043 return;
7044 }
7045
7046 wl_resource_set_implementation(resource, &xdg_output_manager_interface,
7047 NULL, NULL);
7048}
7049
7050static void
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02007051destroy_viewport(struct wl_resource *resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01007052{
Jonny Lamb74130762013-11-26 18:19:46 +01007053 struct weston_surface *surface =
7054 wl_resource_get_user_data(resource);
7055
Pekka Paalanen4826f872016-04-22 14:14:38 +03007056 if (!surface)
7057 return;
7058
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02007059 surface->viewport_resource = NULL;
Pekka Paalanenf0cad482014-03-14 14:38:16 +02007060 surface->pending.buffer_viewport.buffer.src_width =
7061 wl_fixed_from_int(-1);
7062 surface->pending.buffer_viewport.surface.width = -1;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02007063 surface->pending.buffer_viewport.changed = 1;
Jonny Lamb8ae35902013-11-26 18:19:45 +01007064}
7065
7066static void
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02007067viewport_destroy(struct wl_client *client,
7068 struct wl_resource *resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01007069{
7070 wl_resource_destroy(resource);
7071}
7072
7073static void
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007074viewport_set_source(struct wl_client *client,
7075 struct wl_resource *resource,
7076 wl_fixed_t src_x,
7077 wl_fixed_t src_y,
7078 wl_fixed_t src_width,
7079 wl_fixed_t src_height)
7080{
7081 struct weston_surface *surface =
7082 wl_resource_get_user_data(resource);
7083
Pekka Paalanen4826f872016-04-22 14:14:38 +03007084 if (!surface) {
7085 wl_resource_post_error(resource,
7086 WP_VIEWPORT_ERROR_NO_SURFACE,
7087 "wl_surface for this viewport is no longer exists");
7088 return;
7089 }
7090
7091 assert(surface->viewport_resource == resource);
Pekka Paalanen201769a2016-04-26 14:42:11 +03007092 assert(surface->resource);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007093
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03007094 if (src_width == wl_fixed_from_int(-1) &&
Pekka Paalanen201769a2016-04-26 14:42:11 +03007095 src_height == wl_fixed_from_int(-1) &&
7096 src_x == wl_fixed_from_int(-1) &&
7097 src_y == wl_fixed_from_int(-1)) {
7098 /* unset source rect */
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007099 surface->pending.buffer_viewport.buffer.src_width =
7100 wl_fixed_from_int(-1);
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02007101 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03007102 return;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007103 }
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03007104
Pekka Paalanen201769a2016-04-26 14:42:11 +03007105 if (src_width <= 0 || src_height <= 0 || src_x < 0 || src_y < 0) {
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03007106 wl_resource_post_error(resource,
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03007107 WP_VIEWPORT_ERROR_BAD_VALUE,
Pekka Paalanen201769a2016-04-26 14:42:11 +03007108 "wl_surface@%d viewport source "
7109 "w=%f <= 0, h=%f <= 0, x=%f < 0, or y=%f < 0",
7110 wl_resource_get_id(surface->resource),
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03007111 wl_fixed_to_double(src_width),
Pekka Paalanen201769a2016-04-26 14:42:11 +03007112 wl_fixed_to_double(src_height),
7113 wl_fixed_to_double(src_x),
7114 wl_fixed_to_double(src_y));
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03007115 return;
7116 }
7117
7118 surface->pending.buffer_viewport.buffer.src_x = src_x;
7119 surface->pending.buffer_viewport.buffer.src_y = src_y;
7120 surface->pending.buffer_viewport.buffer.src_width = src_width;
7121 surface->pending.buffer_viewport.buffer.src_height = src_height;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02007122 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007123}
7124
7125static void
7126viewport_set_destination(struct wl_client *client,
7127 struct wl_resource *resource,
7128 int32_t dst_width,
7129 int32_t dst_height)
7130{
7131 struct weston_surface *surface =
7132 wl_resource_get_user_data(resource);
7133
Pekka Paalanen4826f872016-04-22 14:14:38 +03007134 if (!surface) {
7135 wl_resource_post_error(resource,
7136 WP_VIEWPORT_ERROR_NO_SURFACE,
7137 "wl_surface for this viewport no longer exists");
7138 return;
7139 }
7140
7141 assert(surface->viewport_resource == resource);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007142
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03007143 if (dst_width == -1 && dst_height == -1) {
7144 /* unset destination size */
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007145 surface->pending.buffer_viewport.surface.width = -1;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02007146 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03007147 return;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007148 }
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03007149
7150 if (dst_width <= 0 || dst_height <= 0) {
7151 wl_resource_post_error(resource,
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03007152 WP_VIEWPORT_ERROR_BAD_VALUE,
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03007153 "destination size must be positive (%dx%d)",
7154 dst_width, dst_height);
7155 return;
7156 }
7157
7158 surface->pending.buffer_viewport.surface.width = dst_width;
7159 surface->pending.buffer_viewport.surface.height = dst_height;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02007160 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007161}
7162
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03007163static const struct wp_viewport_interface viewport_interface = {
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02007164 viewport_destroy,
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007165 viewport_set_source,
7166 viewport_set_destination
Jonny Lamb8ae35902013-11-26 18:19:45 +01007167};
7168
7169static void
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03007170viewporter_destroy(struct wl_client *client,
7171 struct wl_resource *resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01007172{
7173 wl_resource_destroy(resource);
7174}
7175
7176static void
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03007177viewporter_get_viewport(struct wl_client *client,
7178 struct wl_resource *viewporter,
7179 uint32_t id,
7180 struct wl_resource *surface_resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01007181{
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03007182 int version = wl_resource_get_version(viewporter);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007183 struct weston_surface *surface =
7184 wl_resource_get_user_data(surface_resource);
Jonny Lamb8ae35902013-11-26 18:19:45 +01007185 struct wl_resource *resource;
7186
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02007187 if (surface->viewport_resource) {
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03007188 wl_resource_post_error(viewporter,
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03007189 WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS,
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02007190 "a viewport for that surface already exists");
Jonny Lamb74130762013-11-26 18:19:46 +01007191 return;
7192 }
7193
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03007194 resource = wl_resource_create(client, &wp_viewport_interface,
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02007195 version, id);
Jonny Lamb8ae35902013-11-26 18:19:45 +01007196 if (resource == NULL) {
7197 wl_client_post_no_memory(client);
7198 return;
7199 }
7200
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02007201 wl_resource_set_implementation(resource, &viewport_interface,
7202 surface, destroy_viewport);
Jonny Lamb74130762013-11-26 18:19:46 +01007203
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02007204 surface->viewport_resource = resource;
Jonny Lamb8ae35902013-11-26 18:19:45 +01007205}
7206
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03007207static const struct wp_viewporter_interface viewporter_interface = {
7208 viewporter_destroy,
7209 viewporter_get_viewport
Jonny Lamb8ae35902013-11-26 18:19:45 +01007210};
7211
7212static void
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03007213bind_viewporter(struct wl_client *client,
7214 void *data, uint32_t version, uint32_t id)
Jonny Lamb8ae35902013-11-26 18:19:45 +01007215{
7216 struct wl_resource *resource;
7217
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03007218 resource = wl_resource_create(client, &wp_viewporter_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06007219 version, id);
Jonny Lamb8ae35902013-11-26 18:19:45 +01007220 if (resource == NULL) {
7221 wl_client_post_no_memory(client);
7222 return;
7223 }
7224
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03007225 wl_resource_set_implementation(resource, &viewporter_interface,
Jonny Lamb8ae35902013-11-26 18:19:45 +01007226 NULL, NULL);
7227}
7228
7229static void
Pekka Paalanen133e4392014-09-23 22:08:46 -04007230destroy_presentation_feedback(struct wl_resource *feedback_resource)
7231{
7232 struct weston_presentation_feedback *feedback;
7233
7234 feedback = wl_resource_get_user_data(feedback_resource);
7235
7236 wl_list_remove(&feedback->link);
7237 free(feedback);
7238}
7239
7240static void
Pekka Paalanen31f7d782014-09-23 22:08:43 -04007241presentation_destroy(struct wl_client *client, struct wl_resource *resource)
7242{
7243 wl_resource_destroy(resource);
7244}
7245
7246static void
7247presentation_feedback(struct wl_client *client,
Pekka Paalanen133e4392014-09-23 22:08:46 -04007248 struct wl_resource *presentation_resource,
7249 struct wl_resource *surface_resource,
Pekka Paalanen31f7d782014-09-23 22:08:43 -04007250 uint32_t callback)
7251{
Pekka Paalanen133e4392014-09-23 22:08:46 -04007252 struct weston_surface *surface;
7253 struct weston_presentation_feedback *feedback;
7254
7255 surface = wl_resource_get_user_data(surface_resource);
7256
Bryce Harringtonde16d892014-11-20 22:21:57 -08007257 feedback = zalloc(sizeof *feedback);
7258 if (feedback == NULL)
Pekka Paalanen133e4392014-09-23 22:08:46 -04007259 goto err_calloc;
7260
7261 feedback->resource = wl_resource_create(client,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02007262 &wp_presentation_feedback_interface,
Pekka Paalanen133e4392014-09-23 22:08:46 -04007263 1, callback);
7264 if (!feedback->resource)
7265 goto err_create;
7266
7267 wl_resource_set_implementation(feedback->resource, NULL, feedback,
7268 destroy_presentation_feedback);
7269
7270 wl_list_insert(&surface->pending.feedback_list, &feedback->link);
7271
7272 return;
7273
7274err_create:
7275 free(feedback);
7276
7277err_calloc:
7278 wl_client_post_no_memory(client);
Pekka Paalanen31f7d782014-09-23 22:08:43 -04007279}
7280
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02007281static const struct wp_presentation_interface presentation_implementation = {
Pekka Paalanen31f7d782014-09-23 22:08:43 -04007282 presentation_destroy,
7283 presentation_feedback
7284};
7285
7286static void
7287bind_presentation(struct wl_client *client,
7288 void *data, uint32_t version, uint32_t id)
7289{
7290 struct weston_compositor *compositor = data;
7291 struct wl_resource *resource;
7292
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02007293 resource = wl_resource_create(client, &wp_presentation_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06007294 version, id);
Pekka Paalanen31f7d782014-09-23 22:08:43 -04007295 if (resource == NULL) {
7296 wl_client_post_no_memory(client);
7297 return;
7298 }
7299
7300 wl_resource_set_implementation(resource, &presentation_implementation,
7301 compositor, NULL);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02007302 wp_presentation_send_clock_id(resource, compositor->presentation_clock);
Pekka Paalanen31f7d782014-09-23 22:08:43 -04007303}
7304
7305static void
Kristian Høgsberga8873122011-11-23 10:39:34 -05007306compositor_bind(struct wl_client *client,
7307 void *data, uint32_t version, uint32_t id)
7308{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05007309 struct weston_compositor *compositor = data;
Jason Ekstranda85118c2013-06-27 20:17:02 -05007310 struct wl_resource *resource;
Kristian Høgsberga8873122011-11-23 10:39:34 -05007311
Jason Ekstranda85118c2013-06-27 20:17:02 -05007312 resource = wl_resource_create(client, &wl_compositor_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06007313 version, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07007314 if (resource == NULL) {
7315 wl_client_post_no_memory(client);
7316 return;
7317 }
7318
7319 wl_resource_set_implementation(resource, &compositor_interface,
7320 compositor, NULL);
Kristian Høgsberga8873122011-11-23 10:39:34 -05007321}
7322
Daniel Stonece62cb32018-07-20 09:46:24 +01007323static const char *
7324output_repaint_status_text(struct weston_output *output)
7325{
7326 switch (output->repaint_status) {
7327 case REPAINT_NOT_SCHEDULED:
7328 return "no repaint";
7329 case REPAINT_BEGIN_FROM_IDLE:
7330 return "start_repaint_loop scheduled";
7331 case REPAINT_SCHEDULED:
7332 return "repaint scheduled";
7333 case REPAINT_AWAITING_COMPLETION:
7334 return "awaiting completion";
7335 }
7336
7337 assert(!"output_repaint_status_text missing enum");
7338 return NULL;
7339}
7340
7341static void
7342debug_scene_view_print_buffer(FILE *fp, struct weston_view *view)
7343{
7344 struct weston_buffer *buffer = view->surface->buffer_ref.buffer;
7345 struct wl_shm_buffer *shm;
7346 struct linux_dmabuf_buffer *dmabuf;
Marius Vlad00a6e012018-11-20 17:52:31 +02007347 const struct pixel_format_info *pixel_info = NULL;
Daniel Stonece62cb32018-07-20 09:46:24 +01007348
7349 if (!buffer) {
7350 fprintf(fp, "\t\t[buffer not available]\n");
7351 return;
7352 }
7353
7354 shm = wl_shm_buffer_get(buffer->resource);
7355 if (shm) {
Marius Vlad00a6e012018-11-20 17:52:31 +02007356 uint32_t _format = wl_shm_buffer_get_format(shm);
7357 pixel_info = pixel_format_get_info_shm(_format);
Daniel Stonece62cb32018-07-20 09:46:24 +01007358 fprintf(fp, "\t\tSHM buffer\n");
Marius Vlad00a6e012018-11-20 17:52:31 +02007359 fprintf(fp, "\t\t\tformat: 0x%lx %s\n",
7360 (unsigned long) _format,
7361 pixel_info ? pixel_info->drm_format_name : "UNKNOWN");
Daniel Stonece62cb32018-07-20 09:46:24 +01007362 return;
7363 }
7364
7365 dmabuf = linux_dmabuf_buffer_get(buffer->resource);
7366 if (dmabuf) {
Marius Vlad6f6fd262021-07-12 12:58:34 +03007367 uint64_t modifier = dmabuf->attributes.modifier[0];
7368 char *modifier_name = pixel_format_get_modifier(modifier);
Marius Vlad00a6e012018-11-20 17:52:31 +02007369 pixel_info = pixel_format_get_info(dmabuf->attributes.format);
Daniel Stonece62cb32018-07-20 09:46:24 +01007370 fprintf(fp, "\t\tdmabuf buffer\n");
Marius Vlad00a6e012018-11-20 17:52:31 +02007371 fprintf(fp, "\t\t\tformat: 0x%lx %s\n",
7372 (unsigned long) dmabuf->attributes.format,
7373 pixel_info ? pixel_info->drm_format_name : "UNKNOWN");
Marius Vlad6f6fd262021-07-12 12:58:34 +03007374
7375 fprintf(fp, "\t\t\tmodifier: %s\n", modifier_name ? modifier_name :
7376 "Failed to convert to a modifier name");
7377 free(modifier_name);
Daniel Stonece62cb32018-07-20 09:46:24 +01007378 return;
7379 }
7380
Marius Vlad253ba9a2019-03-17 18:22:21 +02007381 fprintf(fp, "\t\tEGL buffer\n");
Daniel Stonece62cb32018-07-20 09:46:24 +01007382}
7383
7384static void
7385debug_scene_view_print(FILE *fp, struct weston_view *view, int view_idx)
7386{
7387 struct weston_compositor *ec = view->surface->compositor;
7388 struct weston_output *output;
7389 char desc[512];
7390 pixman_box32_t *box;
7391 uint32_t surface_id = 0;
7392 pid_t pid = 0;
7393
7394 if (view->surface->resource) {
7395 struct wl_resource *resource = view->surface->resource;
7396 wl_client_get_credentials(wl_resource_get_client(resource),
7397 &pid, NULL, NULL);
7398 surface_id = wl_resource_get_id(view->surface->resource);
7399 }
7400
7401 if (!view->surface->get_label ||
7402 view->surface->get_label(view->surface, desc, sizeof(desc)) < 0) {
7403 strcpy(desc, "[no description available]");
7404 }
7405 fprintf(fp, "\tView %d (role %s, PID %d, surface ID %u, %s, %p):\n",
7406 view_idx, view->surface->role_name, pid, surface_id,
7407 desc, view);
7408
7409 box = pixman_region32_extents(&view->transform.boundingbox);
7410 fprintf(fp, "\t\tposition: (%d, %d) -> (%d, %d)\n",
7411 box->x1, box->y1, box->x2, box->y2);
7412 box = pixman_region32_extents(&view->transform.opaque);
7413
Michael Olbrichb7e5f102020-08-11 16:33:35 +02007414 if (weston_view_is_opaque(view, &view->transform.boundingbox)) {
Daniel Stonece62cb32018-07-20 09:46:24 +01007415 fprintf(fp, "\t\t[fully opaque]\n");
7416 } else if (!pixman_region32_not_empty(&view->transform.opaque)) {
7417 fprintf(fp, "\t\t[not opaque]\n");
7418 } else {
7419 fprintf(fp, "\t\t[opaque: (%d, %d) -> (%d, %d)]\n",
7420 box->x1, box->y1, box->x2, box->y2);
7421 }
7422
7423 if (view->alpha < 1.0)
7424 fprintf(fp, "\t\talpha: %f\n", view->alpha);
7425
7426 if (view->output_mask != 0) {
7427 bool first_output = true;
7428 fprintf(fp, "\t\toutputs: ");
7429 wl_list_for_each(output, &ec->output_list, link) {
7430 if (!(view->output_mask & (1 << output->id)))
7431 continue;
7432 fprintf(fp, "%s%d (%s)%s",
7433 (first_output) ? "" : ", ",
7434 output->id, output->name,
7435 (view->output == output) ? " (primary)" : "");
7436 first_output = false;
7437 }
7438 } else {
7439 fprintf(fp, "\t\t[no outputs]");
7440 }
7441
7442 fprintf(fp, "\n");
7443
7444 debug_scene_view_print_buffer(fp, view);
7445}
7446
Marius Vlad433f4e72019-02-17 22:14:23 +02007447static void
7448debug_scene_view_print_tree(struct weston_view *view,
Marius Vlada6acfa82019-03-17 18:10:09 +02007449 FILE *fp, int *view_idx)
Marius Vlad433f4e72019-02-17 22:14:23 +02007450{
7451 struct weston_subsurface *sub;
7452 struct weston_view *ev;
7453
7454 /*
7455 * print the view first, then we recursively go on printing
7456 * sub-surfaces. We bail out once no more sub-surfaces are available.
7457 */
Marius Vlada6acfa82019-03-17 18:10:09 +02007458 debug_scene_view_print(fp, view, *view_idx);
Marius Vlad433f4e72019-02-17 22:14:23 +02007459
7460 /* no more sub-surfaces */
7461 if (wl_list_empty(&view->surface->subsurface_list))
7462 return;
7463
7464 wl_list_for_each(sub, &view->surface->subsurface_list, parent_link) {
7465 wl_list_for_each(ev, &sub->surface->views, surface_link) {
Michael Olbrichef5f3232020-04-29 09:03:15 +02007466 /* only print the child views of the current view */
7467 if (ev->parent_view != view)
Marius Vlad433f4e72019-02-17 22:14:23 +02007468 continue;
Marius Vlada6acfa82019-03-17 18:10:09 +02007469
7470 (*view_idx)++;
Marius Vlad433f4e72019-02-17 22:14:23 +02007471 debug_scene_view_print_tree(ev, fp, view_idx);
7472 }
7473 }
7474}
7475
Daniel Stonece62cb32018-07-20 09:46:24 +01007476/**
7477 * Output information on how libweston is currently composing the scene
7478 * graph.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03007479 *
7480 * \ingroup compositor
Daniel Stonece62cb32018-07-20 09:46:24 +01007481 */
7482WL_EXPORT char *
7483weston_compositor_print_scene_graph(struct weston_compositor *ec)
7484{
7485 struct weston_output *output;
7486 struct weston_layer *layer;
7487 struct timespec now;
7488 int layer_idx = 0;
7489 FILE *fp;
7490 char *ret;
7491 size_t len;
7492 int err;
7493
7494 fp = open_memstream(&ret, &len);
7495 assert(fp);
7496
7497 weston_compositor_read_presentation_clock(ec, &now);
7498 fprintf(fp, "Weston scene graph at %ld.%09ld:\n\n",
7499 now.tv_sec, now.tv_nsec);
7500
7501 wl_list_for_each(output, &ec->output_list, link) {
7502 struct weston_head *head;
7503 int head_idx = 0;
7504
7505 fprintf(fp, "Output %d (%s):\n", output->id, output->name);
7506 assert(output->enabled);
7507
7508 fprintf(fp, "\tposition: (%d, %d) -> (%d, %d)\n",
7509 output->x, output->y,
7510 output->x + output->width,
7511 output->y + output->height);
7512 fprintf(fp, "\tmode: %dx%d@%.3fHz\n",
7513 output->current_mode->width,
7514 output->current_mode->height,
7515 output->current_mode->refresh / 1000.0);
7516 fprintf(fp, "\tscale: %d\n", output->scale);
7517
7518 fprintf(fp, "\trepaint status: %s\n",
7519 output_repaint_status_text(output));
7520 if (output->repaint_status == REPAINT_SCHEDULED)
7521 fprintf(fp, "\tnext repaint: %ld.%09ld\n",
7522 output->next_repaint.tv_sec,
7523 output->next_repaint.tv_nsec);
7524
7525 wl_list_for_each(head, &output->head_list, output_link) {
7526 fprintf(fp, "\tHead %d (%s): %sconnected\n",
7527 head_idx++, head->name,
7528 (head->connected) ? "" : "not ");
7529 }
7530 }
7531
7532 fprintf(fp, "\n");
7533
7534 wl_list_for_each(layer, &ec->layer_list, link) {
7535 struct weston_view *view;
7536 int view_idx = 0;
7537
7538 fprintf(fp, "Layer %d (pos 0x%lx):\n", layer_idx++,
7539 (unsigned long) layer->position);
7540
7541 if (!weston_layer_mask_is_infinite(layer)) {
7542 fprintf(fp, "\t[mask: (%d, %d) -> (%d,%d)]\n\n",
7543 layer->mask.x1, layer->mask.y1,
7544 layer->mask.x2, layer->mask.y2);
7545 }
7546
Marius Vlada6acfa82019-03-17 18:10:09 +02007547 wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
7548 debug_scene_view_print_tree(view, fp, &view_idx);
7549 view_idx++;
7550 }
Daniel Stonece62cb32018-07-20 09:46:24 +01007551
7552 if (wl_list_empty(&layer->view_list.link))
7553 fprintf(fp, "\t[no views]\n");
7554
7555 fprintf(fp, "\n");
7556 }
7557
7558 err = fclose(fp);
7559 assert(err == 0);
7560
7561 return ret;
7562}
7563
7564/**
7565 * Called when the 'scene-graph' debug scope is bound by a client. This
7566 * one-shot weston-debug scope prints the current scene graph when bound,
7567 * and then terminates the stream.
7568 */
7569static void
Marius Vladdad882a2019-07-17 15:43:53 +03007570debug_scene_graph_cb(struct weston_log_subscription *sub, void *data)
Daniel Stonece62cb32018-07-20 09:46:24 +01007571{
7572 struct weston_compositor *ec = data;
7573 char *str = weston_compositor_print_scene_graph(ec);
7574
Marius Vladdad882a2019-07-17 15:43:53 +03007575 weston_log_subscription_printf(sub, "%s", str);
Daniel Stonece62cb32018-07-20 09:46:24 +01007576 free(str);
Marius Vladdad882a2019-07-17 15:43:53 +03007577 weston_log_subscription_complete(sub);
Daniel Stonece62cb32018-07-20 09:46:24 +01007578}
7579
Leandro Ribeiro32a5acd2020-10-19 16:06:22 -03007580/** Retrieve testsuite data from compositor
7581 *
7582 * The testsuite data can be defined by the test suite of projects that uses
7583 * libweston and given to the compositor at the moment of its creation. This
7584 * function should be used when we need to retrieve the testsuite private data
7585 * from the compositor.
7586 *
7587 * \param ec The weston compositor.
7588 * \return The testsuite data.
7589 *
7590 * \ingroup compositor
7591 * \sa weston_compositor_test_data_init
7592 */
7593WL_EXPORT void *
7594weston_compositor_get_test_data(struct weston_compositor *ec)
7595{
7596 return ec->test_data.test_private_data;
7597}
7598
Giulio Camuffo459137b2014-10-11 23:56:24 +03007599/** Create the compositor.
7600 *
7601 * This functions creates and initializes a compositor instance.
7602 *
7603 * \param display The Wayland display to be used.
7604 * \param user_data A pointer to an object that can later be retrieved
Marius Vlada2dace22019-06-12 16:05:44 +03007605 * \param log_ctx A pointer to weston_debug_compositor
Leandro Ribeirocdb72182020-11-06 11:24:22 -03007606 * \param test_data Optional testsuite data, or NULL.
Giulio Camuffo459137b2014-10-11 23:56:24 +03007607 * using the \ref weston_compositor_get_user_data function.
7608 * \return The compositor instance on success or NULL on failure.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03007609 *
7610 * \ingroup compositor
Giulio Camuffo459137b2014-10-11 23:56:24 +03007611 */
7612WL_EXPORT struct weston_compositor *
Marius Vlad880b4852019-04-07 17:07:58 +03007613weston_compositor_create(struct wl_display *display,
Leandro Ribeirocdb72182020-11-06 11:24:22 -03007614 struct weston_log_context *log_ctx, void *user_data,
7615 const struct weston_testsuite_data *test_data)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04007616{
Giulio Camuffo459137b2014-10-11 23:56:24 +03007617 struct weston_compositor *ec;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05007618 struct wl_event_loop *loop;
Ossama Othmana50e6e42013-05-14 09:48:26 -07007619
Leandro Ribeirobd9c0a62020-01-17 10:47:49 -03007620 if (!log_ctx)
7621 return NULL;
7622
Giulio Camuffo459137b2014-10-11 23:56:24 +03007623 ec = zalloc(sizeof *ec);
7624 if (!ec)
7625 return NULL;
7626
Leandro Ribeirocdb72182020-11-06 11:24:22 -03007627 if (test_data)
7628 ec->test_data = *test_data;
7629
Leandro Ribeirobd9c0a62020-01-17 10:47:49 -03007630 ec->weston_log_ctx = log_ctx;
Giulio Camuffo459137b2014-10-11 23:56:24 +03007631 ec->wl_display = display;
7632 ec->user_data = user_data;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04007633 wl_signal_init(&ec->destroy_signal);
Kristian Høgsbergf03a04a2014-04-06 22:04:50 -07007634 wl_signal_init(&ec->create_surface_signal);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04007635 wl_signal_init(&ec->activate_signal);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03007636 wl_signal_init(&ec->transform_signal);
Tiago Vignatti1d01b012012-09-27 17:48:36 +03007637 wl_signal_init(&ec->kill_signal);
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02007638 wl_signal_init(&ec->idle_signal);
7639 wl_signal_init(&ec->wake_signal);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02007640 wl_signal_init(&ec->show_input_panel_signal);
7641 wl_signal_init(&ec->hide_input_panel_signal);
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02007642 wl_signal_init(&ec->update_input_panel_signal);
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +01007643 wl_signal_init(&ec->seat_created_signal);
Richard Hughes59d5da72013-05-01 21:52:11 +01007644 wl_signal_init(&ec->output_created_signal);
Ander Conselvan de Oliveiraf84327a2014-01-29 18:47:51 +02007645 wl_signal_init(&ec->output_destroyed_signal);
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02007646 wl_signal_init(&ec->output_moved_signal);
David Fort0de859e2016-05-27 23:22:57 +02007647 wl_signal_init(&ec->output_resized_signal);
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03007648 wl_signal_init(&ec->heads_changed_signal);
Pekka Paalanen8dc6db82018-03-20 13:29:40 +02007649 wl_signal_init(&ec->output_heads_changed_signal);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07007650 wl_signal_init(&ec->session_signal);
Robert Beckettc569bdc2019-07-10 16:40:12 +01007651 ec->session_active = true;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04007652
Casey Dahlin58ba1372012-04-19 22:50:08 -04007653 ec->output_id_pool = 0;
Giulio Camuffobab996e2014-10-12 00:24:25 +03007654 ec->repaint_msec = DEFAULT_REPAINT_WINDOW;
Casey Dahlin58ba1372012-04-19 22:50:08 -04007655
Jonas Ådahl94e2e2d2014-10-18 18:42:19 +02007656 ec->activate_serial = 1;
7657
Louis-Francis Ratté-Bouliannec4689ff2017-11-28 20:42:47 -05007658 ec->touch_mode = WESTON_TOUCH_MODE_NORMAL;
7659
Ankit Nautiyal5cfe03c2019-03-28 15:05:42 +05307660 ec->content_protection = NULL;
7661
Derek Foreman152254b2015-11-26 14:17:48 -06007662 if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 4,
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04007663 ec, compositor_bind))
Giulio Camuffo459137b2014-10-11 23:56:24 +03007664 goto fail;
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05007665
Giulio Camuffo954f1832014-10-11 18:27:30 +03007666 if (!wl_global_create(ec->wl_display, &wl_subcompositor_interface, 1,
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04007667 ec, bind_subcompositor))
Giulio Camuffo459137b2014-10-11 23:56:24 +03007668 goto fail;
Pekka Paalanene67858b2013-04-25 13:57:42 +03007669
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03007670 if (!wl_global_create(ec->wl_display, &wp_viewporter_interface, 1,
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03007671 ec, bind_viewporter))
Giulio Camuffo459137b2014-10-11 23:56:24 +03007672 goto fail;
Jonny Lamb8ae35902013-11-26 18:19:45 +01007673
Roman Gilge97391c2019-03-29 13:01:06 +01007674 if (!wl_global_create(ec->wl_display, &zxdg_output_manager_v1_interface, 2,
7675 ec, bind_xdg_output_manager))
7676 goto fail;
7677
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02007678 if (!wl_global_create(ec->wl_display, &wp_presentation_interface, 1,
Pekka Paalanen31f7d782014-09-23 22:08:43 -04007679 ec, bind_presentation))
Giulio Camuffo459137b2014-10-11 23:56:24 +03007680 goto fail;
Pekka Paalanen31f7d782014-09-23 22:08:43 -04007681
Jonas Ådahl30d61d82014-10-22 21:21:17 +02007682 if (weston_input_init(ec) != 0)
7683 goto fail;
7684
Jason Ekstranda7af7042013-10-12 22:38:11 -05007685 wl_list_init(&ec->view_list);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02007686 wl_list_init(&ec->plane_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01007687 wl_list_init(&ec->layer_list);
7688 wl_list_init(&ec->seat_list);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02007689 wl_list_init(&ec->pending_output_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01007690 wl_list_init(&ec->output_list);
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03007691 wl_list_init(&ec->head_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01007692 wl_list_init(&ec->key_binding_list);
Daniel Stone96d47c02013-11-19 11:37:12 +01007693 wl_list_init(&ec->modifier_binding_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01007694 wl_list_init(&ec->button_binding_list);
Neil Robertsa28c6932013-10-03 16:43:04 +01007695 wl_list_init(&ec->touch_binding_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01007696 wl_list_init(&ec->axis_binding_list);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02007697 wl_list_init(&ec->debug_binding_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01007698
Pekka Paalanen827b5d22016-06-29 11:54:26 +02007699 wl_list_init(&ec->plugin_api_list);
7700
Xiong Zhang97116532013-10-23 13:58:31 +08007701 weston_plane_init(&ec->primary_plane, ec, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02007702 weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04007703
Giulio Camuffo459137b2014-10-11 23:56:24 +03007704 wl_data_device_manager_init(ec->wl_display);
7705
7706 wl_display_init_shm(ec->wl_display);
7707
7708 loop = wl_display_get_event_loop(ec->wl_display);
7709 ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
Daniel Stone6847b852017-03-01 11:34:08 +00007710 ec->repaint_timer =
7711 wl_event_loop_add_timer(loop, output_repaint_timer_handler,
7712 ec);
Giulio Camuffo459137b2014-10-11 23:56:24 +03007713
Quentin Glidic82681572016-12-17 13:40:51 +01007714 weston_layer_init(&ec->fade_layer, ec);
7715 weston_layer_init(&ec->cursor_layer, ec);
7716
7717 weston_layer_set_position(&ec->fade_layer, WESTON_LAYER_POSITION_FADE);
7718 weston_layer_set_position(&ec->cursor_layer,
7719 WESTON_LAYER_POSITION_CURSOR);
Giulio Camuffo459137b2014-10-11 23:56:24 +03007720
Daniel Stonece62cb32018-07-20 09:46:24 +01007721 ec->debug_scene =
Leandro Ribeiroce100192019-12-26 16:35:49 -03007722 weston_compositor_add_log_scope(ec, "scene-graph",
7723 "Scene graph details\n",
7724 debug_scene_graph_cb, NULL,
7725 ec);
Daniel Stonece62cb32018-07-20 09:46:24 +01007726
Marius Vladda104eb2019-09-05 14:31:01 +03007727 ec->timeline =
Leandro Ribeiroce100192019-12-26 16:35:49 -03007728 weston_compositor_add_log_scope(ec, "timeline",
7729 "Timeline event points\n",
7730 weston_timeline_create_subscription,
7731 weston_timeline_destroy_subscription,
7732 ec);
Giulio Camuffo459137b2014-10-11 23:56:24 +03007733 return ec;
7734
7735fail:
7736 free(ec);
7737 return NULL;
7738}
7739
Marius Vlad9fdda7f2019-06-11 16:08:55 +03007740/** weston_compositor_shutdown
7741 * \ingroup compositor
7742 */
Benjamin Franzkeb8263022011-08-30 11:32:47 +02007743WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05007744weston_compositor_shutdown(struct weston_compositor *ec)
Matt Roper361d2ad2011-08-29 13:52:23 -07007745{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05007746 struct weston_output *output, *next;
Matt Roper361d2ad2011-08-29 13:52:23 -07007747
Pekka Paalanend1591ae2012-01-02 16:06:56 +02007748 wl_event_source_remove(ec->idle_source);
Lujin Wangd4b46cd2019-08-12 12:03:29 -07007749 wl_event_source_remove(ec->repaint_timer);
Pekka Paalanend1591ae2012-01-02 16:06:56 +02007750
Matt Roper361d2ad2011-08-29 13:52:23 -07007751 /* Destroy all outputs associated with this compositor */
Tiago Vignattib303a1d2011-12-18 22:27:40 +02007752 wl_list_for_each_safe(output, next, &ec->output_list, link)
Matt Roper361d2ad2011-08-29 13:52:23 -07007753 output->destroy(output);
Pekka Paalanen4738f3b2012-01-02 15:47:07 +02007754
Armin Krezovića01ab6d2016-09-30 14:11:02 +02007755 /* Destroy all pending outputs associated with this compositor */
7756 wl_list_for_each_safe(output, next, &ec->pending_output_list, link)
7757 output->destroy(output);
7758
Pekka Paalanen90a5ffa2021-02-25 12:03:28 +02007759 /* Color manager objects may have renderer hooks */
7760 if (ec->color_manager) {
7761 ec->color_manager->destroy(ec->color_manager);
7762 ec->color_manager = NULL;
7763 }
7764
Ander Conselvan de Oliveira18536762013-12-20 21:07:00 +02007765 if (ec->renderer)
7766 ec->renderer->destroy(ec);
7767
Daniel Stone325fc2d2012-05-30 16:31:58 +01007768 weston_binding_list_destroy_all(&ec->key_binding_list);
Ryo Munakata27135af2015-07-17 13:07:42 +09007769 weston_binding_list_destroy_all(&ec->modifier_binding_list);
Daniel Stone325fc2d2012-05-30 16:31:58 +01007770 weston_binding_list_destroy_all(&ec->button_binding_list);
Neil Robertsa28c6932013-10-03 16:43:04 +01007771 weston_binding_list_destroy_all(&ec->touch_binding_list);
Daniel Stone325fc2d2012-05-30 16:31:58 +01007772 weston_binding_list_destroy_all(&ec->axis_binding_list);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02007773 weston_binding_list_destroy_all(&ec->debug_binding_list);
Pekka Paalanend1591ae2012-01-02 16:06:56 +02007774
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04007775 weston_plane_release(&ec->primary_plane);
Pekka Paalanen87400372021-05-14 14:29:40 +03007776
7777 weston_layer_fini(&ec->fade_layer);
7778 weston_layer_fini(&ec->cursor_layer);
7779
7780 if (!wl_list_empty(&ec->layer_list))
7781 weston_log("BUG: layer_list is not empty after shutdown. Calls to weston_layer_fini() are missing somwhere.\n");
Matt Roper361d2ad2011-08-29 13:52:23 -07007782}
7783
Marius Vlad9fdda7f2019-06-11 16:08:55 +03007784/** weston_compositor_exit_with_code
7785 * \ingroup compositor
7786 */
Kristian Høgsbergaf4f2aa2013-02-15 20:53:20 -05007787WL_EXPORT void
Adam Jackson3c3f3b12019-10-16 16:02:59 -04007788weston_compositor_exit_with_code(struct weston_compositor *compositor,
Frederic Plourdec336f062014-10-29 14:44:33 -04007789 int exit_code)
7790{
Pekka Paalanenf5ef88f2014-11-18 15:57:04 +02007791 if (compositor->exit_code == EXIT_SUCCESS)
7792 compositor->exit_code = exit_code;
7793
Giulio Camuffo459137b2014-10-11 23:56:24 +03007794 weston_compositor_exit(compositor);
Frederic Plourdec336f062014-10-29 14:44:33 -04007795}
7796
Marius Vlad9fdda7f2019-06-11 16:08:55 +03007797/** weston_compositor_set_default_pointer_grab
7798 * \ingroup compositor
7799 */
Frederic Plourdec336f062014-10-29 14:44:33 -04007800WL_EXPORT void
Giulio Camuffocdb4d292013-11-14 23:42:53 +01007801weston_compositor_set_default_pointer_grab(struct weston_compositor *ec,
7802 const struct weston_pointer_grab_interface *interface)
7803{
7804 struct weston_seat *seat;
7805
7806 ec->default_pointer_grab = interface;
7807 wl_list_for_each(seat, &ec->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -05007808 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
7809
7810 if (pointer)
7811 weston_pointer_set_default_grab(pointer, interface);
Giulio Camuffocdb4d292013-11-14 23:42:53 +01007812 }
7813}
7814
Marius Vlad9fdda7f2019-06-11 16:08:55 +03007815/** weston_compositor_set_presentation_clock
7816 * \ingroup compositor
7817 */
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04007818WL_EXPORT int
7819weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
7820 clockid_t clk_id)
7821{
7822 struct timespec ts;
7823
7824 if (clock_gettime(clk_id, &ts) < 0)
7825 return -1;
7826
7827 compositor->presentation_clock = clk_id;
7828
7829 return 0;
7830}
7831
Marius Vlad9fdda7f2019-06-11 16:08:55 +03007832/** For choosing the software clock, when the display hardware or API
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04007833 * does not expose a compatible presentation timestamp.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03007834 *
7835 * \ingroup compositor
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04007836 */
7837WL_EXPORT int
7838weston_compositor_set_presentation_clock_software(
7839 struct weston_compositor *compositor)
7840{
7841 /* In order of preference */
7842 static const clockid_t clocks[] = {
7843 CLOCK_MONOTONIC_RAW, /* no jumps, no crawling */
7844 CLOCK_MONOTONIC_COARSE, /* no jumps, may crawl, fast & coarse */
7845 CLOCK_MONOTONIC, /* no jumps, may crawl */
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04007846 };
7847 unsigned i;
7848
7849 for (i = 0; i < ARRAY_LENGTH(clocks); i++)
7850 if (weston_compositor_set_presentation_clock(compositor,
7851 clocks[i]) == 0)
7852 return 0;
7853
7854 weston_log("Error: no suitable presentation clock available.\n");
7855
7856 return -1;
7857}
7858
Pekka Paalanen662f3842015-03-18 12:17:26 +02007859/** Read the current time from the Presentation clock
7860 *
7861 * \param compositor
Marius Vlada2dace22019-06-12 16:05:44 +03007862 * \param[out] ts The current time.
Pekka Paalanen662f3842015-03-18 12:17:26 +02007863 *
7864 * \note Reading the current time in user space is always imprecise to some
7865 * degree.
7866 *
7867 * This function is never meant to fail. If reading the clock does fail,
7868 * an error message is logged and a zero time is returned. Callers are not
7869 * supposed to detect or react to failures.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03007870 *
7871 * \ingroup compositor
Pekka Paalanen662f3842015-03-18 12:17:26 +02007872 */
7873WL_EXPORT void
7874weston_compositor_read_presentation_clock(
7875 const struct weston_compositor *compositor,
7876 struct timespec *ts)
7877{
7878 static bool warned;
7879 int ret;
7880
7881 ret = clock_gettime(compositor->presentation_clock, ts);
7882 if (ret < 0) {
7883 ts->tv_sec = 0;
7884 ts->tv_nsec = 0;
7885
7886 if (!warned)
7887 weston_log("Error: failure to read "
Antonio Borneo39578632019-04-26 23:57:31 +02007888 "the presentation clock %#x: '%s' (%d)\n",
7889 compositor->presentation_clock,
7890 strerror(errno), errno);
Pekka Paalanen662f3842015-03-18 12:17:26 +02007891 warned = true;
7892 }
7893}
7894
Pekka Paalanen230f3b12014-09-29 14:18:40 -04007895/** Import dmabuf buffer into current renderer
7896 *
7897 * \param compositor
7898 * \param buffer the dmabuf buffer to import
7899 * \return true on usable buffers, false otherwise
7900 *
7901 * This function tests that the linux_dmabuf_buffer is usable
7902 * for the current renderer. Returns false on unusable buffers. Usually
7903 * usability is tested by importing the dmabufs for composition.
7904 *
7905 * This hook is also used for detecting if the renderer supports
7906 * dmabufs at all. If the renderer hook is NULL, dmabufs are not
7907 * supported.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03007908 *
7909 * \ingroup compositor
7910 */
Pekka Paalanen230f3b12014-09-29 14:18:40 -04007911WL_EXPORT bool
7912weston_compositor_import_dmabuf(struct weston_compositor *compositor,
7913 struct linux_dmabuf_buffer *buffer)
7914{
7915 struct weston_renderer *renderer;
7916
7917 renderer = compositor->renderer;
7918
7919 if (renderer->import_dmabuf == NULL)
7920 return false;
7921
7922 return renderer->import_dmabuf(compositor, buffer);
7923}
7924
Marius Vlad5a701542019-11-16 20:26:52 +02007925WL_EXPORT bool
7926weston_compositor_dmabuf_can_scanout(struct weston_compositor *compositor,
7927 struct linux_dmabuf_buffer *buffer)
7928{
7929 struct weston_backend *backend = compositor->backend;
7930
7931 if (backend->can_scanout_dmabuf == NULL)
7932 return false;
7933
7934 return backend->can_scanout_dmabuf(compositor, buffer);
7935}
7936
Giulio Camuffocdb4d292013-11-14 23:42:53 +01007937WL_EXPORT void
Kristian Høgsbergaf4f2aa2013-02-15 20:53:20 -05007938weston_version(int *major, int *minor, int *micro)
7939{
7940 *major = WESTON_VERSION_MAJOR;
7941 *minor = WESTON_VERSION_MINOR;
7942 *micro = WESTON_VERSION_MICRO;
7943}
7944
Daniel Stonee03c1112016-11-24 20:45:45 +00007945/**
7946 * Attempts to find a module path from the module map specified in the
7947 * environment. If found, writes the full path into the path variable.
7948 *
7949 * The module map is a string in environment variable WESTON_MODULE_MAP, where
7950 * each entry is of the form "name=path" and entries are separated by
7951 * semicolons. Whitespace is significant.
7952 *
7953 * \param name The name to search for.
7954 * \param path Where the path is written to if found.
7955 * \param path_len Allocated bytes at \c path .
7956 * \returns The length of the string written to path on success, or 0 if the
7957 * module was not specified in the environment map or path_len was too small.
7958 */
7959WL_EXPORT size_t
7960weston_module_path_from_env(const char *name, char *path, size_t path_len)
7961{
7962 const char *mapping = getenv("WESTON_MODULE_MAP");
7963 const char *end;
7964 const int name_len = strlen(name);
7965
7966 if (!mapping)
7967 return 0;
7968
7969 end = mapping + strlen(mapping);
7970 while (mapping < end && *mapping) {
7971 const char *filename, *next;
7972
7973 /* early out: impossibly short string */
7974 if (end - mapping < name_len + 1)
7975 return 0;
7976
7977 filename = &mapping[name_len + 1];
7978 next = strchrnul(mapping, ';');
7979
7980 if (strncmp(mapping, name, name_len) == 0 &&
7981 mapping[name_len] == '=') {
7982 size_t file_len = next - filename; /* no trailing NUL */
7983 if (file_len >= path_len)
7984 return 0;
7985 strncpy(path, filename, file_len);
7986 path[file_len] = '\0';
7987 return file_len;
7988 }
7989
7990 mapping = next + 1;
7991 }
7992
7993 return 0;
7994}
7995
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03007996WL_EXPORT void *
7997weston_load_module(const char *name, const char *entrypoint)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04007998{
7999 char path[PATH_MAX];
8000 void *module, *init;
Daniel Stonebeb97e52016-11-28 12:13:54 +00008001 size_t len;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04008002
U. Artie Eoff2e2384a2014-01-17 13:19:01 -08008003 if (name == NULL)
8004 return NULL;
8005
Derek Foreman3f86e502015-06-08 11:46:54 -05008006 if (name[0] != '/') {
Daniel Stonee03c1112016-11-24 20:45:45 +00008007 len = weston_module_path_from_env(name, path, sizeof path);
8008 if (len == 0)
Daniel Stonebeb97e52016-11-28 12:13:54 +00008009 len = snprintf(path, sizeof path, "%s/%s",
8010 LIBWESTON_MODULEDIR, name);
Derek Foreman3f86e502015-06-08 11:46:54 -05008011 } else {
Daniel Stonebeb97e52016-11-28 12:13:54 +00008012 len = snprintf(path, sizeof path, "%s", name);
Derek Foreman3f86e502015-06-08 11:46:54 -05008013 }
Kristian Høgsberg1c562182011-05-02 22:09:20 -04008014
Daniel Stonebeb97e52016-11-28 12:13:54 +00008015 /* snprintf returns the length of the string it would've written,
8016 * _excluding_ the NUL byte. So even being equal to the size of
8017 * our buffer is an error here. */
8018 if (len >= sizeof path)
8019 return NULL;
8020
Kristian Høgsberga6813d22012-09-12 12:21:01 -04008021 module = dlopen(path, RTLD_NOW | RTLD_NOLOAD);
8022 if (module) {
8023 weston_log("Module '%s' already loaded\n", path);
Pekka Paalanenf696ee92019-11-04 14:07:51 +02008024 } else {
8025 weston_log("Loading module '%s'\n", path);
8026 module = dlopen(path, RTLD_NOW);
8027 if (!module) {
8028 weston_log("Failed to load module: %s\n", dlerror());
8029 return NULL;
8030 }
Kristian Høgsberg1c562182011-05-02 22:09:20 -04008031 }
8032
8033 init = dlsym(module, entrypoint);
8034 if (!init) {
Pekka Paalanen1b3c1ea2012-06-11 14:06:04 +03008035 weston_log("Failed to lookup init function: %s\n", dlerror());
Rob Bradfordc9e64ab2012-12-05 18:47:10 +00008036 dlclose(module);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04008037 return NULL;
8038 }
8039
8040 return init;
8041}
8042
Pekka Paalanen6ffbba32019-11-06 12:59:32 +02008043/** Add a compositor destroy listener only once
8044 *
8045 * \param compositor The compositor whose destroy to watch for.
8046 * \param listener The listener struct to initialize.
8047 * \param destroy_handler The callback when compositor is destroyed.
8048 * \return True if listener is added, or false if there already is a listener
8049 * with the given \c destroy_handler.
8050 *
8051 * This function does nothing and returns false if the given callback function
8052 * is already present in the weston_compositor destroy callbacks list.
8053 * Otherwise, this function initializes the given listener with the given
8054 * callback pointer and adds it to the compositor's destroy callbacks list.
8055 *
8056 * This can be used to ensure that plugin initialization is done only once
8057 * in case the same plugin is loaded multiple times. If this function returns
8058 * false, the plugin should be already initialized successfully.
8059 *
8060 * All plugins should register a destroy listener for cleaning up. Note, that
8061 * the plugin destruction order is not guaranteed: plugins that depend on other
8062 * plugins must be able to be torn down in arbitrary order.
8063 *
Leandro Ribeiroca640d52020-01-27 19:12:01 -03008064 * \sa weston_compositor_destroy
Pekka Paalanen6ffbba32019-11-06 12:59:32 +02008065 */
8066WL_EXPORT bool
8067weston_compositor_add_destroy_listener_once(struct weston_compositor *compositor,
8068 struct wl_listener *listener,
8069 wl_notify_func_t destroy_handler)
8070{
8071 if (wl_signal_get(&compositor->destroy_signal, destroy_handler))
8072 return false;
8073
8074 listener->notify = destroy_handler;
8075 wl_signal_add(&compositor->destroy_signal, listener);
8076 return true;
8077}
Giulio Camuffo459137b2014-10-11 23:56:24 +03008078
Leandro Ribeiroca640d52020-01-27 19:12:01 -03008079/** Destroys the compositor.
Giulio Camuffo459137b2014-10-11 23:56:24 +03008080 *
Leandro Ribeiroca640d52020-01-27 19:12:01 -03008081 * This function cleans up the compositor state and then destroys it.
Giulio Camuffo459137b2014-10-11 23:56:24 +03008082 *
Leandro Ribeiroca640d52020-01-27 19:12:01 -03008083 * @param compositor The compositor to be destroyed.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03008084 *
Marius Vlad284d5342019-06-24 12:00:47 +03008085 * @ingroup compositor
Giulio Camuffo459137b2014-10-11 23:56:24 +03008086 */
8087WL_EXPORT void
Leandro Ribeiroca640d52020-01-27 19:12:01 -03008088weston_compositor_destroy(struct weston_compositor *compositor)
Giulio Camuffo459137b2014-10-11 23:56:24 +03008089{
8090 /* prevent further rendering while shutting down */
8091 compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
8092
8093 wl_signal_emit(&compositor->destroy_signal, compositor);
8094
8095 weston_compositor_xkb_destroy(compositor);
8096
Giulio Camuffo2d24e642015-10-03 16:25:15 +03008097 if (compositor->backend)
8098 compositor->backend->destroy(compositor);
Pekka Paalanen827b5d22016-06-29 11:54:26 +02008099
Pekka Paalanen1adcbac2017-08-14 16:05:35 +03008100 /* The backend is responsible for destroying the heads. */
8101 assert(wl_list_empty(&compositor->head_list));
8102
Pekka Paalanen827b5d22016-06-29 11:54:26 +02008103 weston_plugin_api_destroy_list(compositor);
8104
Pekka Paalanen37e6c9e2017-08-15 13:00:02 +03008105 if (compositor->heads_changed_source)
8106 wl_event_source_remove(compositor->heads_changed_source);
8107
Leandro Ribeirof0149642019-12-18 15:52:18 -03008108 weston_log_scope_destroy(compositor->debug_scene);
Daniel Stonece62cb32018-07-20 09:46:24 +01008109 compositor->debug_scene = NULL;
Marius Vladda104eb2019-09-05 14:31:01 +03008110
Leandro Ribeirof0149642019-12-18 15:52:18 -03008111 weston_log_scope_destroy(compositor->timeline);
Marius Vladda104eb2019-09-05 14:31:01 +03008112 compositor->timeline = NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +02008113
Giulio Camuffo459137b2014-10-11 23:56:24 +03008114 free(compositor);
8115}
8116
8117/** Instruct the compositor to exit.
8118 *
8119 * This functions does not directly destroy the compositor object, it merely
8120 * command it to start the tear down process. It is not guaranteed that the
8121 * tear down will happen immediately.
8122 *
8123 * \param compositor The compositor to tear down.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03008124 *
8125 * \ingroup compositor
Giulio Camuffo459137b2014-10-11 23:56:24 +03008126 */
8127WL_EXPORT void
8128weston_compositor_exit(struct weston_compositor *compositor)
8129{
8130 compositor->exit(compositor);
8131}
8132
8133/** Return the user data stored in the compositor.
8134 *
8135 * This function returns the user data pointer set with user_data parameter
8136 * to the \ref weston_compositor_create function.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03008137 *
8138 * \ingroup compositor
Giulio Camuffo459137b2014-10-11 23:56:24 +03008139 */
8140WL_EXPORT void *
8141weston_compositor_get_user_data(struct weston_compositor *compositor)
8142{
8143 return compositor->user_data;
8144}
Pekka Paalanendd186732016-06-03 14:49:54 +03008145
Pekka Paalanen50dbf382016-06-03 15:23:46 +03008146static const char * const backend_map[] = {
8147 [WESTON_BACKEND_DRM] = "drm-backend.so",
8148 [WESTON_BACKEND_FBDEV] = "fbdev-backend.so",
8149 [WESTON_BACKEND_HEADLESS] = "headless-backend.so",
8150 [WESTON_BACKEND_RDP] = "rdp-backend.so",
8151 [WESTON_BACKEND_WAYLAND] = "wayland-backend.so",
8152 [WESTON_BACKEND_X11] = "x11-backend.so",
8153};
8154
Pekka Paalanendd186732016-06-03 14:49:54 +03008155/** Load a backend into a weston_compositor
8156 *
8157 * A backend must be loaded to make a weston_compositor work. A backend
8158 * provides input and output capabilities, and determines the renderer to use.
8159 *
8160 * \param compositor A compositor that has not had a backend loaded yet.
8161 * \param backend Name of the backend file.
8162 * \param config_base A pointer to a backend-specific configuration
8163 * structure's 'base' member.
8164 *
8165 * \return 0 on success, or -1 on error.
Marius Vlad9fdda7f2019-06-11 16:08:55 +03008166 *
8167 * \ingroup compositor
Pekka Paalanendd186732016-06-03 14:49:54 +03008168 */
8169WL_EXPORT int
8170weston_compositor_load_backend(struct weston_compositor *compositor,
Pekka Paalanen50dbf382016-06-03 15:23:46 +03008171 enum weston_compositor_backend backend,
Pekka Paalanendd186732016-06-03 14:49:54 +03008172 struct weston_backend_config *config_base)
8173{
8174 int (*backend_init)(struct weston_compositor *c,
Pekka Paalanendd186732016-06-03 14:49:54 +03008175 struct weston_backend_config *config_base);
8176
Pekka Paalanend7e35112017-08-29 17:04:12 +03008177 if (compositor->backend) {
8178 weston_log("Error: attempt to load a backend when one is already loaded\n");
8179 return -1;
8180 }
8181
Quentin Glidic887c0182016-07-10 11:00:53 +02008182 if (backend >= ARRAY_LENGTH(backend_map))
Pekka Paalanen50dbf382016-06-03 15:23:46 +03008183 return -1;
8184
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01008185 backend_init = weston_load_module(backend_map[backend], "weston_backend_init");
Pekka Paalanendd186732016-06-03 14:49:54 +03008186 if (!backend_init)
8187 return -1;
8188
Pekka Paalanend7e35112017-08-29 17:04:12 +03008189 if (backend_init(compositor, config_base) < 0) {
8190 compositor->backend = NULL;
8191 return -1;
8192 }
8193
Pekka Paalanen90a5ffa2021-02-25 12:03:28 +02008194 if (!compositor->color_manager) {
8195 compositor->color_manager =
8196 weston_color_manager_noop_create(compositor);
8197 }
8198
8199 if (!compositor->color_manager)
8200 return -1;
8201
8202 if (!compositor->color_manager->init(compositor->color_manager))
8203 return -1;
8204
8205 weston_log("Color manager: %s\n", compositor->color_manager->name);
8206
Pekka Paalanend7e35112017-08-29 17:04:12 +03008207 return 0;
Pekka Paalanendd186732016-06-03 14:49:54 +03008208}
Giulio Camuffo9c764df2016-06-29 11:54:27 +02008209
Marius Vlad9fdda7f2019-06-11 16:08:55 +03008210/** weston_compositor_load_xwayland
8211 * \ingroup compositor
8212 */
Giulio Camuffo9c764df2016-06-29 11:54:27 +02008213WL_EXPORT int
8214weston_compositor_load_xwayland(struct weston_compositor *compositor)
8215{
Quentin Glidic3d7ca3b2016-12-02 14:20:35 +01008216 int (*module_init)(struct weston_compositor *ec);
Giulio Camuffo9c764df2016-06-29 11:54:27 +02008217
Quentin Glidic3d7ca3b2016-12-02 14:20:35 +01008218 module_init = weston_load_module("xwayland.so", "weston_module_init");
Giulio Camuffo9c764df2016-06-29 11:54:27 +02008219 if (!module_init)
8220 return -1;
Quentin Glidic3d7ca3b2016-12-02 14:20:35 +01008221 if (module_init(compositor) < 0)
Giulio Camuffo9c764df2016-06-29 11:54:27 +02008222 return -1;
8223 return 0;
8224}
Vasilis Liaskovitis486b4632018-10-10 16:14:55 +02008225
Pekka Paalanen5e79dd42021-03-29 14:11:49 +03008226/** Load Little CMS color manager plugin
8227 *
8228 * Calling this function before loading any backend sets Little CMS
8229 * as the active color matching module (CMM) instead of the default no-op
8230 * color manager.
8231 *
8232 * \ingroup compositor
8233 */
8234WL_EXPORT int
8235weston_compositor_load_color_manager(struct weston_compositor *compositor)
8236{
8237 struct weston_color_manager *
8238 (*cm_create)(struct weston_compositor *compositor);
8239
8240 if (compositor->color_manager) {
8241 weston_log("Error: Color manager '%s' is loaded, cannot load another.\n",
8242 compositor->color_manager->name);
8243 return -1;
8244 }
8245
8246 cm_create = weston_load_module("color-lcms.so", "weston_color_manager_create");
8247 if (!cm_create) {
8248 weston_log("Error: Could not load color-lcms.so.\n");
8249 return -1;
8250 }
8251
8252 compositor->color_manager = cm_create(compositor);
8253 if (!compositor->color_manager) {
8254 weston_log("Error: loading color-lcms.so failed.\n");
8255 return -1;
8256 }
8257
8258 return 0;
8259}
8260
Vasilis Liaskovitis486b4632018-10-10 16:14:55 +02008261/** Resolve an internal compositor error by disconnecting the client.
8262 *
8263 * This function is used in cases when the wl_buffer turns out
8264 * unusable and there is no fallback path.
8265 *
8266 * It is possible the fault is caused by a compositor bug, the underlying
8267 * graphics stack bug or normal behaviour, or perhaps a client mistake.
8268 * In any case, the options are to either composite garbage or nothing,
8269 * or disconnect the client. This is a helper function for the latter.
8270 *
8271 * The error is sent as an INVALID_OBJECT error on the client's wl_display.
8272 *
8273 * \param buffer The weston buffer that is unusable.
8274 * \param msg A custom error message attached to the protocol error.
8275 */
8276WL_EXPORT void
8277weston_buffer_send_server_error(struct weston_buffer *buffer,
8278 const char *msg)
8279{
8280 struct wl_client *client;
8281 struct wl_resource *display_resource;
8282 uint32_t id;
8283
8284 assert(buffer->resource);
8285 id = wl_resource_get_id(buffer->resource);
8286 client = wl_resource_get_client(buffer->resource);
8287 display_resource = wl_client_get_object(client, 1);
8288
8289 assert(display_resource);
8290 wl_resource_post_error(display_resource,
8291 WL_DISPLAY_ERROR_INVALID_OBJECT,
8292 "server error with "
8293 "wl_buffer@%u: %s", id, msg);
8294}
Ankit Nautiyal93dde242019-07-08 11:46:42 +05308295
8296WL_EXPORT void
8297weston_output_disable_planes_incr(struct weston_output *output)
8298{
8299 output->disable_planes++;
Ankit Nautiyal4fd38132019-07-08 15:12:19 +05308300 /*
8301 * If disable_planes changes from 0 to non-zero, it means some type of
8302 * recording of content has started, and therefore protection level of
8303 * the protected surfaces must be updated to avoid the recording of
8304 * the protected content.
8305 */
8306 if (output->disable_planes == 1)
8307 weston_schedule_surface_protection_update(output->compositor);
Ankit Nautiyal93dde242019-07-08 11:46:42 +05308308}
8309
8310WL_EXPORT void
8311weston_output_disable_planes_decr(struct weston_output *output)
8312{
8313 output->disable_planes--;
Ankit Nautiyal4fd38132019-07-08 15:12:19 +05308314 /*
8315 * If disable_planes changes from non-zero to 0, it means no content
8316 * recording is going on any more, and the protected and surfaces can be
8317 * shown without any apprehensions about content being recorded.
8318 */
8319 if (output->disable_planes == 0)
8320 weston_schedule_surface_protection_update(output->compositor);
8321
Ankit Nautiyal93dde242019-07-08 11:46:42 +05308322}