blob: 7992870bb7973eb14cf113585316048fffa21b5d [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 Paalanenc647ed72015-02-09 13:16:57 +02004 * Copyright © 2012-2015 Collabora, Ltd.
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05005 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07006 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
Kristian Høgsbergffd710e2008-12-02 15:15:01 -050013 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070014 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
Kristian Høgsbergffd710e2008-12-02 15:15:01 -050026 */
27
Kristian Høgsberga9410222011-01-14 17:22:35 -050028#include "config.h"
29
Daniel Stoneb7452fe2012-06-01 12:14:06 +010030#include <fcntl.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040031#include <stdio.h>
32#include <string.h>
33#include <stdlib.h>
34#include <stdint.h>
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +010035#include <limits.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050036#include <stdarg.h>
Benjamin Franzke6f5fc692011-06-21 19:34:19 +020037#include <assert.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040038#include <sys/ioctl.h>
Daniel Stoneb7452fe2012-06-01 12:14:06 +010039#include <sys/mman.h>
Kristian Høgsberg27da5382011-06-21 17:32:25 -040040#include <sys/wait.h>
Pekka Paalanen409ef0a2011-12-02 15:30:21 +020041#include <sys/socket.h>
Martin Minarikf12c2872012-06-11 00:57:39 +020042#include <sys/utsname.h>
Martin Minarik37032f82012-06-18 20:15:18 +020043#include <sys/stat.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040044#include <unistd.h>
Kristian Høgsberg54879822008-11-23 17:07:32 -050045#include <math.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040046#include <linux/input.h>
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040047#include <dlfcn.h>
Kristian Høgsberg85449032011-05-02 12:11:07 -040048#include <signal.h>
Kristian Høgsberg0690da62012-01-16 11:53:54 -050049#include <setjmp.h>
Kristian Høgsberga411c8b2012-06-08 16:16:52 -040050#include <sys/time.h>
51#include <time.h>
Pekka Paalanen23ade622014-08-27 13:31:26 +030052#include <errno.h>
Kristian Høgsberg890bc052008-12-30 14:31:33 -050053
Pekka Paalanenb5026542014-11-12 15:09:24 +020054#include "timeline.h"
55
Kristian Høgsberg82863022010-06-04 21:52:02 -040056#include "compositor.h"
Pekka Paalanene95ad5c2016-04-15 14:47:08 +030057#include "viewporter-server-protocol.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020058#include "presentation-time-server-protocol.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070059#include "shared/helpers.h"
Jon Cruz4678bab2015-06-15 15:37:07 -070060#include "shared/os-compatibility.h"
Bryce Harrington25a2bdd2016-08-03 17:40:52 -070061#include "shared/string-helpers.h"
Pekka Paalanenaa21f622015-07-03 15:44:50 +030062#include "shared/timespec-util.h"
Kristian Høgsberga411c8b2012-06-08 16:16:52 -040063#include "git-version.h"
Kristian Høgsbergaf4f2aa2013-02-15 20:53:20 -050064#include "version.h"
Pekka Paalanen827b5d22016-06-29 11:54:26 +020065#include "plugin-registry.h"
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050066
Pekka Paalanen0513a952014-05-21 16:17:27 +030067#define DEFAULT_REPAINT_WINDOW 7 /* milliseconds */
68
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -020069static void
Pekka Paalanend72bad22017-03-29 17:01:41 +030070weston_output_update_matrix(struct weston_output *output);
71
72static void
Alexander Larsson0b135062013-05-28 16:23:36 +020073weston_output_transform_scale_init(struct weston_output *output,
74 uint32_t transform, uint32_t scale);
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -020075
Rob Bradford27b17932013-06-26 18:08:46 +010076static void
Jason Ekstranda7af7042013-10-12 22:38:11 -050077weston_compositor_build_view_list(struct weston_compositor *compositor);
Rob Bradford27b17932013-06-26 18:08:46 +010078
Derek Foreman6ae7bc92014-11-04 10:47:33 -060079static void weston_mode_switch_finish(struct weston_output *output,
80 int mode_changed,
81 int scale_changed)
Alex Wu2dda6042012-04-17 17:20:47 +080082{
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -020083 struct weston_seat *seat;
Pekka Paalanen1b9bf592017-03-27 12:15:38 +030084 struct weston_head *head;
Hardening57388e42013-09-18 23:56:36 +020085 struct wl_resource *resource;
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -020086 pixman_region32_t old_output_region;
Derek Foreman41bdc272014-11-05 13:26:57 -060087 int version;
Alexander Larsson355748e2013-05-28 16:23:38 +020088
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -020089 pixman_region32_init(&old_output_region);
90 pixman_region32_copy(&old_output_region, &output->region);
91
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -020092 /* Update output region and transformation matrix */
Hardeningff39efa2013-09-18 23:56:35 +020093 weston_output_transform_scale_init(output, output->transform, output->current_scale);
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -020094
95 pixman_region32_init(&output->previous_damage);
96 pixman_region32_init_rect(&output->region, output->x, output->y,
97 output->width, output->height);
98
99 weston_output_update_matrix(output);
100
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -0200101 /* If a pointer falls outside the outputs new geometry, move it to its
102 * lower-right corner */
103 wl_list_for_each(seat, &output->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500104 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -0200105 int32_t x, y;
106
107 if (!pointer)
108 continue;
109
110 x = wl_fixed_to_int(pointer->x);
111 y = wl_fixed_to_int(pointer->y);
112
113 if (!pixman_region32_contains_point(&old_output_region,
114 x, y, NULL) ||
115 pixman_region32_contains_point(&output->region,
116 x, y, NULL))
117 continue;
118
119 if (x >= output->x + output->width)
120 x = output->x + output->width - 1;
121 if (y >= output->y + output->height)
122 y = output->y + output->height - 1;
123
124 pointer->x = wl_fixed_from_int(x);
125 pointer->y = wl_fixed_from_int(y);
126 }
127
128 pixman_region32_fini(&old_output_region);
129
Derek Foremandd4cd332014-11-10 10:29:59 -0600130 if (!mode_changed && !scale_changed)
131 return;
132
Pekka Paalanen1b9bf592017-03-27 12:15:38 +0300133 head = &output->head;
134
Hardening57388e42013-09-18 23:56:36 +0200135 /* notify clients of the changes */
Pekka Paalanen1b9bf592017-03-27 12:15:38 +0300136 wl_resource_for_each(resource, &head->resource_list) {
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600137 if (mode_changed) {
138 wl_output_send_mode(resource,
139 output->current_mode->flags,
140 output->current_mode->width,
141 output->current_mode->height,
142 output->current_mode->refresh);
143 }
Hardening57388e42013-09-18 23:56:36 +0200144
Derek Foreman41bdc272014-11-05 13:26:57 -0600145 version = wl_resource_get_version(resource);
146 if (version >= WL_OUTPUT_SCALE_SINCE_VERSION && scale_changed)
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600147 wl_output_send_scale(resource, output->current_scale);
Hardening57388e42013-09-18 23:56:36 +0200148
Derek Foreman41bdc272014-11-05 13:26:57 -0600149 if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
150 wl_output_send_done(resource);
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600151 }
152}
153
David Fort0de859e2016-05-27 23:22:57 +0200154
155static void
156weston_compositor_reflow_outputs(struct weston_compositor *compositor,
157 struct weston_output *resized_output, int delta_width);
158
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600159WL_EXPORT int
160weston_output_mode_set_native(struct weston_output *output,
161 struct weston_mode *mode,
162 int32_t scale)
163{
164 int ret;
165 int mode_changed = 0, scale_changed = 0;
David Fort0de859e2016-05-27 23:22:57 +0200166 int32_t old_width;
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600167
168 if (!output->switch_mode)
169 return -1;
170
171 if (!output->original_mode) {
172 mode_changed = 1;
173 ret = output->switch_mode(output, mode);
174 if (ret < 0)
175 return ret;
176 if (output->current_scale != scale) {
177 scale_changed = 1;
178 output->current_scale = scale;
Hardening57388e42013-09-18 23:56:36 +0200179 }
180 }
181
David Fort0de859e2016-05-27 23:22:57 +0200182 old_width = output->width;
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600183 output->native_mode = mode;
184 output->native_scale = scale;
185
186 weston_mode_switch_finish(output, mode_changed, scale_changed);
187
David Fort0de859e2016-05-27 23:22:57 +0200188 if (mode_changed || scale_changed) {
189 weston_compositor_reflow_outputs(output->compositor, output, output->width - old_width);
190
191 wl_signal_emit(&output->compositor->output_resized_signal, output);
192 }
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600193 return 0;
194}
195
196WL_EXPORT int
197weston_output_mode_switch_to_native(struct weston_output *output)
198{
199 int ret;
200 int mode_changed = 0, scale_changed = 0;
201
202 if (!output->switch_mode)
203 return -1;
204
205 if (!output->original_mode) {
206 weston_log("already in the native mode\n");
207 return -1;
208 }
209 /* the non fullscreen clients haven't seen a mode set since we
210 * switched into a temporary, so we need to notify them if the
211 * mode at that time is different from the native mode now.
212 */
213 mode_changed = (output->original_mode != output->native_mode);
214 scale_changed = (output->original_scale != output->native_scale);
215
216 ret = output->switch_mode(output, output->native_mode);
217 if (ret < 0)
218 return ret;
219
220 output->current_scale = output->native_scale;
221
222 output->original_mode = NULL;
223 output->original_scale = 0;
224
225 weston_mode_switch_finish(output, mode_changed, scale_changed);
226
227 return 0;
228}
229
230WL_EXPORT int
231weston_output_mode_switch_to_temporary(struct weston_output *output,
232 struct weston_mode *mode,
233 int32_t scale)
234{
235 int ret;
236
237 if (!output->switch_mode)
238 return -1;
239
240 /* original_mode is the last mode non full screen clients have seen,
241 * so we shouldn't change it if we already have one set.
242 */
243 if (!output->original_mode) {
244 output->original_mode = output->native_mode;
245 output->original_scale = output->native_scale;
246 }
247 ret = output->switch_mode(output, mode);
248 if (ret < 0)
249 return ret;
250
251 output->current_scale = scale;
252
253 weston_mode_switch_finish(output, 0, 0);
254
255 return 0;
Alex Wu2dda6042012-04-17 17:20:47 +0800256}
257
Benjamin Franzke06286262011-05-06 19:12:33 +0200258static void
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +0300259region_init_infinite(pixman_region32_t *region)
260{
261 pixman_region32_init_rect(region, INT32_MIN, INT32_MIN,
262 UINT32_MAX, UINT32_MAX);
263}
264
Pekka Paalanene67858b2013-04-25 13:57:42 +0300265static struct weston_subsurface *
266weston_surface_to_subsurface(struct weston_surface *surface);
267
Jason Ekstranda7af7042013-10-12 22:38:11 -0500268WL_EXPORT struct weston_view *
269weston_view_create(struct weston_surface *surface)
270{
271 struct weston_view *view;
272
Bryce Harringtonde16d892014-11-20 22:21:57 -0800273 view = zalloc(sizeof *view);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500274 if (view == NULL)
275 return NULL;
276
277 view->surface = surface;
Daniel Stonefb4869d2016-12-09 16:27:54 +0000278 view->plane = &surface->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500279
Jason Ekstranda7af7042013-10-12 22:38:11 -0500280 /* Assign to surface */
281 wl_list_insert(&surface->views, &view->surface_link);
282
283 wl_signal_init(&view->destroy_signal);
284 wl_list_init(&view->link);
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300285 wl_list_init(&view->layer_link.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500286
Jason Ekstranda7af7042013-10-12 22:38:11 -0500287 pixman_region32_init(&view->clip);
288
289 view->alpha = 1.0;
290 pixman_region32_init(&view->transform.opaque);
291
292 wl_list_init(&view->geometry.transformation_list);
293 wl_list_insert(&view->geometry.transformation_list,
294 &view->transform.position.link);
295 weston_matrix_init(&view->transform.position.matrix);
296 wl_list_init(&view->geometry.child_list);
Pekka Paalanen380adf52015-02-16 14:39:11 +0200297 pixman_region32_init(&view->geometry.scissor);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500298 pixman_region32_init(&view->transform.boundingbox);
299 view->transform.dirty = 1;
300
Jason Ekstranda7af7042013-10-12 22:38:11 -0500301 return view;
302}
303
Jason Ekstrand108865d2014-06-26 10:04:49 -0700304struct weston_frame_callback {
305 struct wl_resource *resource;
306 struct wl_list link;
307};
308
Pekka Paalanen133e4392014-09-23 22:08:46 -0400309struct weston_presentation_feedback {
310 struct wl_resource *resource;
311
312 /* XXX: could use just wl_resource_get_link() instead */
313 struct wl_list link;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +0200314
315 /* The per-surface feedback flags */
316 uint32_t psf_flags;
Pekka Paalanen133e4392014-09-23 22:08:46 -0400317};
318
319static void
320weston_presentation_feedback_discard(
321 struct weston_presentation_feedback *feedback)
322{
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200323 wp_presentation_feedback_send_discarded(feedback->resource);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400324 wl_resource_destroy(feedback->resource);
325}
326
327static void
328weston_presentation_feedback_discard_list(struct wl_list *list)
329{
330 struct weston_presentation_feedback *feedback, *tmp;
331
332 wl_list_for_each_safe(feedback, tmp, list, link)
333 weston_presentation_feedback_discard(feedback);
334}
335
336static void
337weston_presentation_feedback_present(
338 struct weston_presentation_feedback *feedback,
339 struct weston_output *output,
340 uint32_t refresh_nsec,
341 const struct timespec *ts,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200342 uint64_t seq,
343 uint32_t flags)
Pekka Paalanen133e4392014-09-23 22:08:46 -0400344{
345 struct wl_client *client = wl_resource_get_client(feedback->resource);
Pekka Paalanen1b9bf592017-03-27 12:15:38 +0300346 struct weston_head *head;
Pekka Paalanen133e4392014-09-23 22:08:46 -0400347 struct wl_resource *o;
Alexandros Frantzis10d708d2017-12-13 13:27:54 +0200348 uint32_t tv_sec_hi;
349 uint32_t tv_sec_lo;
350 uint32_t tv_nsec;
Pekka Paalanen133e4392014-09-23 22:08:46 -0400351
Pekka Paalanen1b9bf592017-03-27 12:15:38 +0300352 head = &output->head;
353 wl_resource_for_each(o, &head->resource_list) {
Pekka Paalanen133e4392014-09-23 22:08:46 -0400354 if (wl_resource_get_client(o) != client)
355 continue;
356
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200357 wp_presentation_feedback_send_sync_output(feedback->resource, o);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400358 }
359
Alexandros Frantzis10d708d2017-12-13 13:27:54 +0200360 timespec_to_proto(ts, &tv_sec_hi, &tv_sec_lo, &tv_nsec);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200361 wp_presentation_feedback_send_presented(feedback->resource,
Alexandros Frantzis10d708d2017-12-13 13:27:54 +0200362 tv_sec_hi, tv_sec_lo, tv_nsec,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200363 refresh_nsec,
364 seq >> 32, seq & 0xffffffff,
365 flags | feedback->psf_flags);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400366 wl_resource_destroy(feedback->resource);
367}
368
369static void
370weston_presentation_feedback_present_list(struct wl_list *list,
371 struct weston_output *output,
372 uint32_t refresh_nsec,
373 const struct timespec *ts,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200374 uint64_t seq,
375 uint32_t flags)
Pekka Paalanen133e4392014-09-23 22:08:46 -0400376{
377 struct weston_presentation_feedback *feedback, *tmp;
378
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200379 assert(!(flags & WP_PRESENTATION_FEEDBACK_INVALID) ||
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200380 wl_list_empty(list));
381
Pekka Paalanen133e4392014-09-23 22:08:46 -0400382 wl_list_for_each_safe(feedback, tmp, list, link)
383 weston_presentation_feedback_present(feedback, output,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200384 refresh_nsec, ts, seq,
385 flags);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400386}
387
Jason Ekstrand7b982072014-05-20 14:33:03 -0500388static void
389surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
390{
391 struct weston_surface_state *state =
392 container_of(listener, struct weston_surface_state,
393 buffer_destroy_listener);
394
395 state->buffer = NULL;
396}
397
398static void
399weston_surface_state_init(struct weston_surface_state *state)
400{
401 state->newly_attached = 0;
402 state->buffer = NULL;
403 state->buffer_destroy_listener.notify =
404 surface_state_handle_buffer_destroy;
405 state->sx = 0;
406 state->sy = 0;
407
Derek Foreman152254b2015-11-26 14:17:48 -0600408 pixman_region32_init(&state->damage_surface);
409 pixman_region32_init(&state->damage_buffer);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500410 pixman_region32_init(&state->opaque);
411 region_init_infinite(&state->input);
412
413 wl_list_init(&state->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400414 wl_list_init(&state->feedback_list);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500415
416 state->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
417 state->buffer_viewport.buffer.scale = 1;
418 state->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
419 state->buffer_viewport.surface.width = -1;
420 state->buffer_viewport.changed = 0;
421}
422
423static void
424weston_surface_state_fini(struct weston_surface_state *state)
425{
426 struct weston_frame_callback *cb, *next;
427
428 wl_list_for_each_safe(cb, next,
429 &state->frame_callback_list, link)
430 wl_resource_destroy(cb->resource);
431
Pekka Paalanen133e4392014-09-23 22:08:46 -0400432 weston_presentation_feedback_discard_list(&state->feedback_list);
433
Jason Ekstrand7b982072014-05-20 14:33:03 -0500434 pixman_region32_fini(&state->input);
435 pixman_region32_fini(&state->opaque);
Derek Foreman152254b2015-11-26 14:17:48 -0600436 pixman_region32_fini(&state->damage_surface);
437 pixman_region32_fini(&state->damage_buffer);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500438
439 if (state->buffer)
440 wl_list_remove(&state->buffer_destroy_listener.link);
441 state->buffer = NULL;
442}
443
444static void
445weston_surface_state_set_buffer(struct weston_surface_state *state,
446 struct weston_buffer *buffer)
447{
448 if (state->buffer == buffer)
449 return;
450
451 if (state->buffer)
452 wl_list_remove(&state->buffer_destroy_listener.link);
453 state->buffer = buffer;
454 if (state->buffer)
455 wl_signal_add(&state->buffer->destroy_signal,
456 &state->buffer_destroy_listener);
457}
458
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500459WL_EXPORT struct weston_surface *
Kristian Høgsberg18c93002012-01-27 11:58:31 -0500460weston_surface_create(struct weston_compositor *compositor)
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500461{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500462 struct weston_surface *surface;
Kristian Høgsberg77fb1672010-08-16 10:38:29 -0400463
Bryce Harringtonde16d892014-11-20 22:21:57 -0800464 surface = zalloc(sizeof *surface);
Kristian Høgsberg77fb1672010-08-16 10:38:29 -0400465 if (surface == NULL)
466 return NULL;
467
Jason Ekstrand26ed73c2013-06-06 22:34:41 -0500468 wl_signal_init(&surface->destroy_signal);
Jonas Ådahl5d9ca272016-07-22 17:48:03 +0800469 wl_signal_init(&surface->commit_signal);
Jason Ekstrand26ed73c2013-06-06 22:34:41 -0500470
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500471 surface->compositor = compositor;
Giulio Camuffo13b85bd2013-08-13 23:10:14 +0200472 surface->ref_count = 1;
Kristian Høgsberg27803c62010-06-06 22:23:21 -0400473
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200474 surface->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
475 surface->buffer_viewport.buffer.scale = 1;
Pekka Paalanenf0cad482014-03-14 14:38:16 +0200476 surface->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
477 surface->buffer_viewport.surface.width = -1;
Jason Ekstrand7b982072014-05-20 14:33:03 -0500478
479 weston_surface_state_init(&surface->pending);
480
Kristian Høgsberg20300ba2011-06-23 20:29:12 -0400481 pixman_region32_init(&surface->damage);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -0500482 pixman_region32_init(&surface->opaque);
Pekka Paalanen8ec4ab62012-10-10 12:49:32 +0300483 region_init_infinite(&surface->input);
Kristian Høgsberg20300ba2011-06-23 20:29:12 -0400484
Jason Ekstranda7af7042013-10-12 22:38:11 -0500485 wl_list_init(&surface->views);
486
487 wl_list_init(&surface->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400488 wl_list_init(&surface->feedback_list);
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500489
Pekka Paalanene67858b2013-04-25 13:57:42 +0300490 wl_list_init(&surface->subsurface_list);
491 wl_list_init(&surface->subsurface_list_pending);
492
Jason Ekstrand1e059042014-10-16 10:55:19 -0500493 weston_matrix_init(&surface->buffer_to_surface_matrix);
494 weston_matrix_init(&surface->surface_to_buffer_matrix);
495
Jonas Ådahld3414f22016-07-22 17:56:31 +0800496 wl_list_init(&surface->pointer_constraints);
497
Kristian Høgsberg77fb1672010-08-16 10:38:29 -0400498 return surface;
Kristian Høgsberg54879822008-11-23 17:07:32 -0500499}
500
Alex Wu8811bf92012-02-28 18:07:54 +0800501WL_EXPORT void
Kristian Høgsbergbbeefb02012-01-26 10:00:23 -0500502weston_surface_set_color(struct weston_surface *surface,
John Kåre Alsaker490d02a2012-09-30 02:57:21 +0200503 float red, float green, float blue, float alpha)
Kristian Høgsbergbbeefb02012-01-26 10:00:23 -0500504{
John Kåre Alsaker878f4492012-11-13 19:10:23 +0100505 surface->compositor->renderer->surface_set_color(surface, red, green, blue, alpha);
Kristian Høgsbergbbeefb02012-01-26 10:00:23 -0500506}
507
Kristian Høgsberge4c1a5f2012-06-18 13:17:32 -0400508WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500509weston_view_to_global_float(struct weston_view *view,
510 float sx, float sy, float *x, float *y)
Pekka Paalanenece8a012012-02-08 15:23:15 +0200511{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500512 if (view->transform.enabled) {
Pekka Paalanenece8a012012-02-08 15:23:15 +0200513 struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };
514
Jason Ekstranda7af7042013-10-12 22:38:11 -0500515 weston_matrix_transform(&view->transform.matrix, &v);
Pekka Paalanenece8a012012-02-08 15:23:15 +0200516
517 if (fabsf(v.f[3]) < 1e-6) {
Martin Minarik6d118362012-06-07 18:01:59 +0200518 weston_log("warning: numerical instability in "
Scott Moreau088c62e2013-02-11 04:45:38 -0700519 "%s(), divisor = %g\n", __func__,
Pekka Paalanenece8a012012-02-08 15:23:15 +0200520 v.f[3]);
521 *x = 0;
522 *y = 0;
523 return;
524 }
525
526 *x = v.f[0] / v.f[3];
527 *y = v.f[1] / v.f[3];
528 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500529 *x = sx + view->geometry.x;
530 *y = sy + view->geometry.y;
Pekka Paalanenece8a012012-02-08 15:23:15 +0200531 }
532}
533
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500534WL_EXPORT void
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200535weston_transformed_coord(int width, int height,
536 enum wl_output_transform transform,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200537 int32_t scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200538 float sx, float sy, float *bx, float *by)
539{
540 switch (transform) {
541 case WL_OUTPUT_TRANSFORM_NORMAL:
542 default:
543 *bx = sx;
544 *by = sy;
545 break;
546 case WL_OUTPUT_TRANSFORM_FLIPPED:
547 *bx = width - sx;
548 *by = sy;
549 break;
550 case WL_OUTPUT_TRANSFORM_90:
551 *bx = height - sy;
552 *by = sx;
553 break;
554 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
555 *bx = height - sy;
556 *by = width - sx;
557 break;
558 case WL_OUTPUT_TRANSFORM_180:
559 *bx = width - sx;
560 *by = height - sy;
561 break;
562 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
563 *bx = sx;
564 *by = height - sy;
565 break;
566 case WL_OUTPUT_TRANSFORM_270:
567 *bx = sy;
568 *by = width - sx;
569 break;
570 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
571 *bx = sy;
572 *by = sx;
573 break;
574 }
Alexander Larsson4ea95522013-05-22 14:41:37 +0200575
576 *bx *= scale;
577 *by *= scale;
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200578}
579
580WL_EXPORT pixman_box32_t
581weston_transformed_rect(int width, int height,
582 enum wl_output_transform transform,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200583 int32_t scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200584 pixman_box32_t rect)
585{
586 float x1, x2, y1, y2;
587
588 pixman_box32_t ret;
589
Alexander Larsson4ea95522013-05-22 14:41:37 +0200590 weston_transformed_coord(width, height, transform, scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200591 rect.x1, rect.y1, &x1, &y1);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200592 weston_transformed_coord(width, height, transform, scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200593 rect.x2, rect.y2, &x2, &y2);
594
595 if (x1 <= x2) {
596 ret.x1 = x1;
597 ret.x2 = x2;
598 } else {
599 ret.x1 = x2;
600 ret.x2 = x1;
601 }
602
603 if (y1 <= y2) {
604 ret.y1 = y1;
605 ret.y2 = y2;
606 } else {
607 ret.y1 = y2;
608 ret.y2 = y1;
609 }
610
611 return ret;
612}
613
Derek Foremanbc9a61c2015-11-18 16:32:30 -0600614/** Transform a region by a matrix, restricted to axis-aligned transformations
615 *
616 * Warning: This function does not work for projective, affine, or matrices
617 * that encode arbitrary rotations. Only 90-degree step rotations are
618 * supported.
619 */
620WL_EXPORT void
621weston_matrix_transform_region(pixman_region32_t *dest,
622 struct weston_matrix *matrix,
623 pixman_region32_t *src)
624{
625 pixman_box32_t *src_rects, *dest_rects;
626 int nrects, i;
627
628 src_rects = pixman_region32_rectangles(src, &nrects);
629 dest_rects = malloc(nrects * sizeof(*dest_rects));
630 if (!dest_rects)
631 return;
632
633 for (i = 0; i < nrects; i++) {
634 struct weston_vector vec1 = {{
635 src_rects[i].x1, src_rects[i].y1, 0, 1
636 }};
637 weston_matrix_transform(matrix, &vec1);
638 vec1.f[0] /= vec1.f[3];
639 vec1.f[1] /= vec1.f[3];
640
641 struct weston_vector vec2 = {{
642 src_rects[i].x2, src_rects[i].y2, 0, 1
643 }};
644 weston_matrix_transform(matrix, &vec2);
645 vec2.f[0] /= vec2.f[3];
646 vec2.f[1] /= vec2.f[3];
647
648 if (vec1.f[0] < vec2.f[0]) {
649 dest_rects[i].x1 = floor(vec1.f[0]);
650 dest_rects[i].x2 = ceil(vec2.f[0]);
651 } else {
652 dest_rects[i].x1 = floor(vec2.f[0]);
653 dest_rects[i].x2 = ceil(vec1.f[0]);
654 }
655
Derek Foremanbc9a61c2015-11-18 16:32:30 -0600656 if (vec1.f[1] < vec2.f[1]) {
657 dest_rects[i].y1 = floor(vec1.f[1]);
658 dest_rects[i].y2 = ceil(vec2.f[1]);
659 } else {
660 dest_rects[i].y1 = floor(vec2.f[1]);
661 dest_rects[i].y2 = ceil(vec1.f[1]);
662 }
663 }
664
665 pixman_region32_clear(dest);
666 pixman_region32_init_rects(dest, dest_rects, nrects);
667 free(dest_rects);
668}
669
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200670WL_EXPORT void
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500671weston_transformed_region(int width, int height,
672 enum wl_output_transform transform,
673 int32_t scale,
674 pixman_region32_t *src, pixman_region32_t *dest)
675{
676 pixman_box32_t *src_rects, *dest_rects;
677 int nrects, i;
678
679 if (transform == WL_OUTPUT_TRANSFORM_NORMAL && scale == 1) {
680 if (src != dest)
681 pixman_region32_copy(dest, src);
682 return;
683 }
684
685 src_rects = pixman_region32_rectangles(src, &nrects);
686 dest_rects = malloc(nrects * sizeof(*dest_rects));
687 if (!dest_rects)
688 return;
689
690 if (transform == WL_OUTPUT_TRANSFORM_NORMAL) {
691 memcpy(dest_rects, src_rects, nrects * sizeof(*dest_rects));
692 } else {
693 for (i = 0; i < nrects; i++) {
694 switch (transform) {
695 default:
696 case WL_OUTPUT_TRANSFORM_NORMAL:
697 dest_rects[i].x1 = src_rects[i].x1;
698 dest_rects[i].y1 = src_rects[i].y1;
699 dest_rects[i].x2 = src_rects[i].x2;
700 dest_rects[i].y2 = src_rects[i].y2;
701 break;
702 case WL_OUTPUT_TRANSFORM_90:
703 dest_rects[i].x1 = height - src_rects[i].y2;
704 dest_rects[i].y1 = src_rects[i].x1;
705 dest_rects[i].x2 = height - src_rects[i].y1;
706 dest_rects[i].y2 = src_rects[i].x2;
707 break;
708 case WL_OUTPUT_TRANSFORM_180:
709 dest_rects[i].x1 = width - src_rects[i].x2;
710 dest_rects[i].y1 = height - src_rects[i].y2;
711 dest_rects[i].x2 = width - src_rects[i].x1;
712 dest_rects[i].y2 = height - src_rects[i].y1;
713 break;
714 case WL_OUTPUT_TRANSFORM_270:
715 dest_rects[i].x1 = src_rects[i].y1;
716 dest_rects[i].y1 = width - src_rects[i].x2;
717 dest_rects[i].x2 = src_rects[i].y2;
718 dest_rects[i].y2 = width - src_rects[i].x1;
719 break;
720 case WL_OUTPUT_TRANSFORM_FLIPPED:
721 dest_rects[i].x1 = width - src_rects[i].x2;
722 dest_rects[i].y1 = src_rects[i].y1;
723 dest_rects[i].x2 = width - src_rects[i].x1;
724 dest_rects[i].y2 = src_rects[i].y2;
725 break;
726 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
727 dest_rects[i].x1 = height - src_rects[i].y2;
728 dest_rects[i].y1 = width - src_rects[i].x2;
729 dest_rects[i].x2 = height - src_rects[i].y1;
730 dest_rects[i].y2 = width - src_rects[i].x1;
731 break;
732 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
733 dest_rects[i].x1 = src_rects[i].x1;
734 dest_rects[i].y1 = height - src_rects[i].y2;
735 dest_rects[i].x2 = src_rects[i].x2;
736 dest_rects[i].y2 = height - src_rects[i].y1;
737 break;
738 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
739 dest_rects[i].x1 = src_rects[i].y1;
740 dest_rects[i].y1 = src_rects[i].x1;
741 dest_rects[i].x2 = src_rects[i].y2;
742 dest_rects[i].y2 = src_rects[i].x2;
743 break;
744 }
745 }
746 }
747
748 if (scale != 1) {
749 for (i = 0; i < nrects; i++) {
750 dest_rects[i].x1 *= scale;
751 dest_rects[i].x2 *= scale;
752 dest_rects[i].y1 *= scale;
753 dest_rects[i].y2 *= scale;
754 }
755 }
756
757 pixman_region32_clear(dest);
758 pixman_region32_init_rects(dest, dest_rects, nrects);
759 free(dest_rects);
760}
761
Jonny Lamb74130762013-11-26 18:19:46 +0100762static void
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +0300763viewport_surface_to_buffer(struct weston_surface *surface,
764 float sx, float sy, float *bx, float *by)
Jonny Lamb74130762013-11-26 18:19:46 +0100765{
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200766 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200767 double src_width, src_height;
768 double src_x, src_y;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200769
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200770 if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
771 if (vp->surface.width == -1) {
772 *bx = sx;
773 *by = sy;
774 return;
775 }
Jonny Lamb74130762013-11-26 18:19:46 +0100776
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200777 src_x = 0.0;
778 src_y = 0.0;
779 src_width = surface->width_from_buffer;
780 src_height = surface->height_from_buffer;
Jonny Lamb74130762013-11-26 18:19:46 +0100781 } else {
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200782 src_x = wl_fixed_to_double(vp->buffer.src_x);
783 src_y = wl_fixed_to_double(vp->buffer.src_y);
784 src_width = wl_fixed_to_double(vp->buffer.src_width);
785 src_height = wl_fixed_to_double(vp->buffer.src_height);
Jonny Lamb74130762013-11-26 18:19:46 +0100786 }
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200787
788 *bx = sx * src_width / surface->width + src_x;
789 *by = sy * src_height / surface->height + src_y;
Jonny Lamb74130762013-11-26 18:19:46 +0100790}
791
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500792WL_EXPORT void
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200793weston_surface_to_buffer_float(struct weston_surface *surface,
794 float sx, float sy, float *bx, float *by)
795{
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200796 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
797
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +0300798 /* first transform coordinates if the viewport is set */
799 viewport_surface_to_buffer(surface, sx, sy, bx, by);
Jonny Lamb74130762013-11-26 18:19:46 +0100800
Jason Ekstrandd0cebc32014-04-21 20:56:46 -0500801 weston_transformed_coord(surface->width_from_buffer,
802 surface->height_from_buffer,
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200803 vp->buffer.transform, vp->buffer.scale,
Jonny Lamb74130762013-11-26 18:19:46 +0100804 *bx, *by, bx, by);
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200805}
806
Derek Foreman99739672015-12-03 16:38:11 -0600807/** Transform a rectangle from surface coordinates to buffer coordinates
808 *
Pekka Paalanene95ad5c2016-04-15 14:47:08 +0300809 * \param surface The surface to fetch wp_viewport and buffer transformation
Derek Foreman99739672015-12-03 16:38:11 -0600810 * from.
811 * \param rect The rectangle to transform.
812 * \return The transformed rectangle.
813 *
814 * Viewport and buffer transformations can only do translation, scaling,
815 * and rotations in 90-degree steps. Therefore the only loss in the
816 * conversion is coordinate rounding.
817 *
818 * However, some coordinate rounding takes place as an intermediate
819 * step before the buffer scale factor is applied, so the rectangle
820 * boundary may not be exactly as expected.
821 *
822 * This is OK for damage tracking since a little extra coverage is
823 * not a problem.
824 */
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200825WL_EXPORT pixman_box32_t
826weston_surface_to_buffer_rect(struct weston_surface *surface,
827 pixman_box32_t rect)
828{
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200829 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Jonny Lamb74130762013-11-26 18:19:46 +0100830 float xf, yf;
831
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +0300832 /* first transform box coordinates if the viewport is set */
833 viewport_surface_to_buffer(surface, rect.x1, rect.y1, &xf, &yf);
Jonny Lamb74130762013-11-26 18:19:46 +0100834 rect.x1 = floorf(xf);
835 rect.y1 = floorf(yf);
836
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +0300837 viewport_surface_to_buffer(surface, rect.x2, rect.y2, &xf, &yf);
Derek Foremane2e15ac2015-12-01 13:00:43 -0600838 rect.x2 = ceilf(xf);
839 rect.y2 = ceilf(yf);
Jonny Lamb74130762013-11-26 18:19:46 +0100840
Jason Ekstrandd0cebc32014-04-21 20:56:46 -0500841 return weston_transformed_rect(surface->width_from_buffer,
842 surface->height_from_buffer,
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200843 vp->buffer.transform, vp->buffer.scale,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200844 rect);
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200845}
846
Pekka Paalanene54e31c2015-03-04 14:23:28 +0200847/** Transform a region from surface coordinates to buffer coordinates
848 *
Pekka Paalanene95ad5c2016-04-15 14:47:08 +0300849 * \param surface The surface to fetch wp_viewport and buffer transformation
Pekka Paalanene54e31c2015-03-04 14:23:28 +0200850 * from.
851 * \param surface_region[in] The region in surface coordinates.
852 * \param buffer_region[out] The region converted to buffer coordinates.
853 *
854 * Buffer_region must be init'd, but will be completely overwritten.
855 *
856 * Viewport and buffer transformations can only do translation, scaling,
857 * and rotations in 90-degree steps. Therefore the only loss in the
Derek Foreman99739672015-12-03 16:38:11 -0600858 * conversion is from the coordinate rounding that takes place in
859 * \ref weston_surface_to_buffer_rect.
Pekka Paalanene54e31c2015-03-04 14:23:28 +0200860 */
861WL_EXPORT void
862weston_surface_to_buffer_region(struct weston_surface *surface,
863 pixman_region32_t *surface_region,
864 pixman_region32_t *buffer_region)
865{
866 pixman_box32_t *src_rects, *dest_rects;
867 int nrects, i;
868
869 src_rects = pixman_region32_rectangles(surface_region, &nrects);
870 dest_rects = malloc(nrects * sizeof(*dest_rects));
871 if (!dest_rects)
872 return;
873
874 for (i = 0; i < nrects; i++) {
875 dest_rects[i] = weston_surface_to_buffer_rect(surface,
876 src_rects[i]);
877 }
878
879 pixman_region32_fini(buffer_region);
880 pixman_region32_init_rects(buffer_region, dest_rects, nrects);
881 free(dest_rects);
882}
883
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200884WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500885weston_view_move_to_plane(struct weston_view *view,
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400886 struct weston_plane *plane)
887{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500888 if (view->plane == plane)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400889 return;
890
Jason Ekstranda7af7042013-10-12 22:38:11 -0500891 weston_view_damage_below(view);
892 view->plane = plane;
893 weston_surface_damage(view->surface);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400894}
895
Pekka Paalanen51723d52015-02-17 13:10:01 +0200896/** Inflict damage on the plane where the view is visible.
897 *
898 * \param view The view that causes the damage.
899 *
900 * If the view is currently on a plane (including the primary plane),
901 * take the view's boundingbox, subtract all the opaque views that cover it,
902 * and add the remaining region as damage to the plane. This corresponds
903 * to the damage inflicted to the plane if this view disappeared.
904 *
905 * A repaint is scheduled for this view.
906 *
907 * The region of all opaque views covering this view is stored in
908 * weston_view::clip and updated by view_accumulate_damage() during
909 * weston_output_repaint(). Specifically, that region matches the
910 * scenegraph as it was last painted.
911 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400912WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500913weston_view_damage_below(struct weston_view *view)
Pekka Paalanen9abf3932012-02-08 14:49:37 +0200914{
Kristian Høgsberg1e832122012-02-28 22:47:14 -0500915 pixman_region32_t damage;
Pekka Paalanen9abf3932012-02-08 14:49:37 +0200916
Kristian Høgsberg1e832122012-02-28 22:47:14 -0500917 pixman_region32_init(&damage);
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200918 pixman_region32_subtract(&damage, &view->transform.boundingbox,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500919 &view->clip);
Xiong Zhang97116532013-10-23 13:58:31 +0800920 if (view->plane)
921 pixman_region32_union(&view->plane->damage,
922 &view->plane->damage, &damage);
Kristian Høgsberg1e832122012-02-28 22:47:14 -0500923 pixman_region32_fini(&damage);
Kristian Høgsberga3a784a2013-11-13 21:33:43 -0800924 weston_view_schedule_repaint(view);
Pekka Paalanen9abf3932012-02-08 14:49:37 +0200925}
926
Pekka Paalanen01e00682017-03-24 16:21:06 +0200927/** Send wl_surface.enter/leave events
928 *
929 * \param surface The surface.
Pekka Paalanen1b9bf592017-03-27 12:15:38 +0300930 * \param head A head of the entered/left output.
Pekka Paalanen01e00682017-03-24 16:21:06 +0200931 * \param enter True if entered.
932 * \param left True if left.
933 *
934 * Send the enter/leave events for all protocol objects bound to the given
935 * output by the client owning the surface.
936 */
937static void
938weston_surface_send_enter_leave(struct weston_surface *surface,
Pekka Paalanen1b9bf592017-03-27 12:15:38 +0300939 struct weston_head *head,
Pekka Paalanen01e00682017-03-24 16:21:06 +0200940 bool enter,
941 bool leave)
942{
943 struct wl_resource *wloutput;
944 struct wl_client *client;
945
946 assert(enter != leave);
947
948 client = wl_resource_get_client(surface->resource);
Pekka Paalanen1b9bf592017-03-27 12:15:38 +0300949 wl_resource_for_each(wloutput, &head->resource_list) {
Pekka Paalanen01e00682017-03-24 16:21:06 +0200950 if (wl_resource_get_client(wloutput) != client)
951 continue;
952
953 if (enter)
954 wl_surface_send_enter(surface->resource, wloutput);
955 if (leave)
956 wl_surface_send_leave(surface->resource, wloutput);
957 }
958}
959
Bryce Harrington3f650b82015-12-23 11:01:58 -0800960/**
961 * \param es The surface
962 * \param mask The new set of outputs for the surface
963 *
964 * Sets the surface's set of outputs to the ones specified by
965 * the new output mask provided. Identifies the outputs that
966 * have changed, the posts enter and leave events for these
967 * outputs as appropriate.
968 */
Kristian Høgsbergb9af4792012-09-25 14:48:04 -0400969static void
970weston_surface_update_output_mask(struct weston_surface *es, uint32_t mask)
971{
972 uint32_t different = es->output_mask ^ mask;
973 uint32_t entered = mask & different;
974 uint32_t left = es->output_mask & different;
Pekka Paalanen01e00682017-03-24 16:21:06 +0200975 uint32_t output_bit;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -0400976 struct weston_output *output;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -0400977
978 es->output_mask = mask;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -0500979 if (es->resource == NULL)
Kristian Høgsbergb9af4792012-09-25 14:48:04 -0400980 return;
981 if (different == 0)
982 return;
983
984 wl_list_for_each(output, &es->compositor->output_list, link) {
Pekka Paalanen01e00682017-03-24 16:21:06 +0200985 output_bit = 1u << output->id;
986 if (!(output_bit & different))
Kristian Høgsbergb9af4792012-09-25 14:48:04 -0400987 continue;
Pekka Paalanen01e00682017-03-24 16:21:06 +0200988
Pekka Paalanen1b9bf592017-03-27 12:15:38 +0300989 weston_surface_send_enter_leave(es, &output->head,
Pekka Paalanen01e00682017-03-24 16:21:06 +0200990 output_bit & entered,
991 output_bit & left);
Kristian Høgsbergb9af4792012-09-25 14:48:04 -0400992 }
993}
994
Bryce Harrington3f650b82015-12-23 11:01:58 -0800995/** Recalculate which output(s) the surface has views displayed on
996 *
997 * \param es The surface to remap to outputs
998 *
999 * Finds the output that is showing the largest amount of one
1000 * of the surface's various views. This output becomes the
Pekka Paalanen130ae6e2016-03-30 14:33:33 +03001001 * surface's primary output for vsync and frame callback purposes.
Bryce Harrington3f650b82015-12-23 11:01:58 -08001002 *
Pekka Paalanen130ae6e2016-03-30 14:33:33 +03001003 * Also notes all outputs of all of the surface's views
Bryce Harrington3f650b82015-12-23 11:01:58 -08001004 * in the output_mask for the surface.
1005 */
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001006static void
1007weston_surface_assign_output(struct weston_surface *es)
1008{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001009 struct weston_output *new_output;
1010 struct weston_view *view;
1011 pixman_region32_t region;
1012 uint32_t max, area, mask;
1013 pixman_box32_t *e;
1014
1015 new_output = NULL;
1016 max = 0;
1017 mask = 0;
1018 pixman_region32_init(&region);
1019 wl_list_for_each(view, &es->views, surface_link) {
1020 if (!view->output)
1021 continue;
1022
1023 pixman_region32_intersect(&region, &view->transform.boundingbox,
1024 &view->output->region);
1025
1026 e = pixman_region32_extents(&region);
1027 area = (e->x2 - e->x1) * (e->y2 - e->y1);
1028
1029 mask |= view->output_mask;
1030
1031 if (area >= max) {
1032 new_output = view->output;
1033 max = area;
1034 }
1035 }
1036 pixman_region32_fini(&region);
1037
1038 es->output = new_output;
1039 weston_surface_update_output_mask(es, mask);
1040}
1041
Bryce Harrington3f650b82015-12-23 11:01:58 -08001042/** Recalculate which output(s) the view is displayed on
1043 *
1044 * \param ev The view to remap to outputs
1045 *
1046 * Identifies the set of outputs that the view is visible on,
1047 * noting them into the output_mask. The output that the view
Pekka Paalanen130ae6e2016-03-30 14:33:33 +03001048 * is most visible on is set as the view's primary output.
Bryce Harrington3f650b82015-12-23 11:01:58 -08001049 *
1050 * Also does the same for the view's surface. See
1051 * weston_surface_assign_output().
1052 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001053static void
1054weston_view_assign_output(struct weston_view *ev)
1055{
1056 struct weston_compositor *ec = ev->surface->compositor;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001057 struct weston_output *output, *new_output;
1058 pixman_region32_t region;
1059 uint32_t max, area, mask;
1060 pixman_box32_t *e;
1061
1062 new_output = NULL;
1063 max = 0;
1064 mask = 0;
1065 pixman_region32_init(&region);
1066 wl_list_for_each(output, &ec->output_list, link) {
Giulio Camuffo2f2a70c2015-07-12 10:52:32 +03001067 if (output->destroying)
1068 continue;
1069
Jason Ekstranda7af7042013-10-12 22:38:11 -05001070 pixman_region32_intersect(&region, &ev->transform.boundingbox,
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001071 &output->region);
1072
1073 e = pixman_region32_extents(&region);
1074 area = (e->x2 - e->x1) * (e->y2 - e->y1);
1075
1076 if (area > 0)
Bryce Harrington89324ce2015-12-23 18:38:07 -08001077 mask |= 1u << output->id;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001078
1079 if (area >= max) {
1080 new_output = output;
1081 max = area;
1082 }
1083 }
1084 pixman_region32_fini(&region);
1085
Jason Ekstranda7af7042013-10-12 22:38:11 -05001086 ev->output = new_output;
1087 ev->output_mask = mask;
1088
1089 weston_surface_assign_output(ev->surface);
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001090}
1091
Pekka Paalanen9abf3932012-02-08 14:49:37 +02001092static void
Pekka Paalanen380adf52015-02-16 14:39:11 +02001093weston_view_to_view_map(struct weston_view *from, struct weston_view *to,
1094 int from_x, int from_y, int *to_x, int *to_y)
1095{
1096 float x, y;
1097
1098 weston_view_to_global_float(from, from_x, from_y, &x, &y);
1099 weston_view_from_global_float(to, x, y, &x, &y);
1100
1101 *to_x = round(x);
1102 *to_y = round(y);
1103}
1104
1105static void
1106weston_view_transfer_scissor(struct weston_view *from, struct weston_view *to)
1107{
1108 pixman_box32_t *a;
1109 pixman_box32_t b;
1110
1111 a = pixman_region32_extents(&from->geometry.scissor);
1112
1113 weston_view_to_view_map(from, to, a->x1, a->y1, &b.x1, &b.y1);
1114 weston_view_to_view_map(from, to, a->x2, a->y2, &b.x2, &b.y2);
1115
1116 pixman_region32_fini(&to->geometry.scissor);
1117 pixman_region32_init_with_extents(&to->geometry.scissor, &b);
1118}
1119
1120static void
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02001121view_compute_bbox(struct weston_view *view, const pixman_box32_t *inbox,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001122 pixman_region32_t *bbox)
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001123{
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001124 float min_x = HUGE_VALF, min_y = HUGE_VALF;
1125 float max_x = -HUGE_VALF, max_y = -HUGE_VALF;
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001126 int32_t s[4][2] = {
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02001127 { inbox->x1, inbox->y1 },
1128 { inbox->x1, inbox->y2 },
1129 { inbox->x2, inbox->y1 },
1130 { inbox->x2, inbox->y2 },
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001131 };
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001132 float int_x, int_y;
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001133 int i;
1134
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02001135 if (inbox->x1 == inbox->x2 || inbox->y1 == inbox->y2) {
Pekka Paalanen7c7d4642012-09-04 13:55:44 +03001136 /* avoid rounding empty bbox to 1x1 */
1137 pixman_region32_init(bbox);
1138 return;
1139 }
1140
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001141 for (i = 0; i < 4; ++i) {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001142 float x, y;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001143 weston_view_to_global_float(view, s[i][0], s[i][1], &x, &y);
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001144 if (x < min_x)
1145 min_x = x;
1146 if (x > max_x)
1147 max_x = x;
1148 if (y < min_y)
1149 min_y = y;
1150 if (y > max_y)
1151 max_y = y;
1152 }
1153
Pekka Paalanen219b9822012-02-08 15:38:37 +02001154 int_x = floorf(min_x);
1155 int_y = floorf(min_y);
1156 pixman_region32_init_rect(bbox, int_x, int_y,
1157 ceilf(max_x) - int_x, ceilf(max_y) - int_y);
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001158}
1159
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001160static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001161weston_view_update_transform_disable(struct weston_view *view)
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001162{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001163 view->transform.enabled = 0;
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001164
Pekka Paalanencc2f8682012-02-13 10:34:04 +02001165 /* round off fractions when not transformed */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001166 view->geometry.x = roundf(view->geometry.x);
1167 view->geometry.y = roundf(view->geometry.y);
Pekka Paalanencc2f8682012-02-13 10:34:04 +02001168
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001169 /* Otherwise identity matrix, but with x and y translation. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001170 view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
1171 view->transform.position.matrix.d[12] = view->geometry.x;
1172 view->transform.position.matrix.d[13] = view->geometry.y;
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001173
Jason Ekstranda7af7042013-10-12 22:38:11 -05001174 view->transform.matrix = view->transform.position.matrix;
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001175
Jason Ekstranda7af7042013-10-12 22:38:11 -05001176 view->transform.inverse = view->transform.position.matrix;
1177 view->transform.inverse.d[12] = -view->geometry.x;
1178 view->transform.inverse.d[13] = -view->geometry.y;
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001179
Jason Ekstranda7af7042013-10-12 22:38:11 -05001180 pixman_region32_init_rect(&view->transform.boundingbox,
Pekka Paalanen380adf52015-02-16 14:39:11 +02001181 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001182 view->surface->width,
1183 view->surface->height);
Pekka Paalanen380adf52015-02-16 14:39:11 +02001184 if (view->geometry.scissor_enabled)
1185 pixman_region32_intersect(&view->transform.boundingbox,
1186 &view->transform.boundingbox,
1187 &view->geometry.scissor);
1188
1189 pixman_region32_translate(&view->transform.boundingbox,
1190 view->geometry.x, view->geometry.y);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001191
Jason Ekstranda7af7042013-10-12 22:38:11 -05001192 if (view->alpha == 1.0) {
1193 pixman_region32_copy(&view->transform.opaque,
1194 &view->surface->opaque);
1195 pixman_region32_translate(&view->transform.opaque,
1196 view->geometry.x,
1197 view->geometry.y);
Kristian Høgsberg3b4af202012-02-28 09:19:39 -05001198 }
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001199}
1200
1201static int
Jason Ekstranda7af7042013-10-12 22:38:11 -05001202weston_view_update_transform_enable(struct weston_view *view)
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001203{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001204 struct weston_view *parent = view->geometry.parent;
1205 struct weston_matrix *matrix = &view->transform.matrix;
1206 struct weston_matrix *inverse = &view->transform.inverse;
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001207 struct weston_transform *tform;
Pekka Paalanen380adf52015-02-16 14:39:11 +02001208 pixman_region32_t surfregion;
1209 const pixman_box32_t *surfbox;
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001210
Jason Ekstranda7af7042013-10-12 22:38:11 -05001211 view->transform.enabled = 1;
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001212
1213 /* Otherwise identity matrix, but with x and y translation. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001214 view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
1215 view->transform.position.matrix.d[12] = view->geometry.x;
1216 view->transform.position.matrix.d[13] = view->geometry.y;
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001217
1218 weston_matrix_init(matrix);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001219 wl_list_for_each(tform, &view->geometry.transformation_list, link)
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001220 weston_matrix_multiply(matrix, &tform->matrix);
1221
Pekka Paalanen483243f2013-03-08 14:56:50 +02001222 if (parent)
1223 weston_matrix_multiply(matrix, &parent->transform.matrix);
1224
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001225 if (weston_matrix_invert(inverse, matrix) < 0) {
1226 /* Oops, bad total transformation, not invertible */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001227 weston_log("error: weston_view %p"
1228 " transformation not invertible.\n", view);
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001229 return -1;
1230 }
1231
Giulio Camuffo148c1992016-09-04 18:50:46 +03001232 if (view->alpha == 1.0 &&
1233 matrix->type == WESTON_MATRIX_TRANSFORM_TRANSLATE) {
1234 pixman_region32_copy(&view->transform.opaque,
1235 &view->surface->opaque);
1236 pixman_region32_translate(&view->transform.opaque,
1237 matrix->d[12],
1238 matrix->d[13]);
1239 }
1240
Pekka Paalanen380adf52015-02-16 14:39:11 +02001241 pixman_region32_init_rect(&surfregion, 0, 0,
1242 view->surface->width, view->surface->height);
1243 if (view->geometry.scissor_enabled)
1244 pixman_region32_intersect(&surfregion, &surfregion,
1245 &view->geometry.scissor);
1246 surfbox = pixman_region32_extents(&surfregion);
1247
1248 view_compute_bbox(view, surfbox, &view->transform.boundingbox);
1249 pixman_region32_fini(&surfregion);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001250
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001251 return 0;
1252}
1253
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001254static struct weston_layer *
1255get_view_layer(struct weston_view *view)
1256{
1257 if (view->parent_view)
1258 return get_view_layer(view->parent_view);
1259 return view->layer_link.layer;
1260}
1261
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001262WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001263weston_view_update_transform(struct weston_view *view)
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001264{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001265 struct weston_view *parent = view->geometry.parent;
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001266 struct weston_layer *layer;
1267 pixman_region32_t mask;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001268
Jason Ekstranda7af7042013-10-12 22:38:11 -05001269 if (!view->transform.dirty)
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001270 return;
1271
Pekka Paalanen483243f2013-03-08 14:56:50 +02001272 if (parent)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001273 weston_view_update_transform(parent);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001274
Jason Ekstranda7af7042013-10-12 22:38:11 -05001275 view->transform.dirty = 0;
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001276
Jason Ekstranda7af7042013-10-12 22:38:11 -05001277 weston_view_damage_below(view);
Pekka Paalanen96516782012-02-09 15:32:15 +02001278
Jason Ekstranda7af7042013-10-12 22:38:11 -05001279 pixman_region32_fini(&view->transform.boundingbox);
1280 pixman_region32_fini(&view->transform.opaque);
1281 pixman_region32_init(&view->transform.opaque);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001282
Pekka Paalanencd403622012-01-25 13:37:39 +02001283 /* transform.position is always in transformation_list */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001284 if (view->geometry.transformation_list.next ==
1285 &view->transform.position.link &&
1286 view->geometry.transformation_list.prev ==
1287 &view->transform.position.link &&
Pekka Paalanen483243f2013-03-08 14:56:50 +02001288 !parent) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001289 weston_view_update_transform_disable(view);
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001290 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001291 if (weston_view_update_transform_enable(view) < 0)
1292 weston_view_update_transform_disable(view);
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001293 }
Pekka Paalanen96516782012-02-09 15:32:15 +02001294
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001295 layer = get_view_layer(view);
1296 if (layer) {
1297 pixman_region32_init_with_extents(&mask, &layer->mask);
Pekka Paalanen25c0ca52015-02-19 11:15:33 +02001298 pixman_region32_intersect(&view->transform.boundingbox,
1299 &view->transform.boundingbox, &mask);
Pekka Paalanen8844bf22015-02-18 16:30:47 +02001300 pixman_region32_intersect(&view->transform.opaque,
1301 &view->transform.opaque, &mask);
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001302 pixman_region32_fini(&mask);
1303 }
1304
Pekka Paalanen380adf52015-02-16 14:39:11 +02001305 if (parent) {
1306 if (parent->geometry.scissor_enabled) {
1307 view->geometry.scissor_enabled = true;
1308 weston_view_transfer_scissor(parent, view);
1309 } else {
1310 view->geometry.scissor_enabled = false;
1311 }
1312 }
1313
Jason Ekstranda7af7042013-10-12 22:38:11 -05001314 weston_view_damage_below(view);
Pekka Paalanen96516782012-02-09 15:32:15 +02001315
Jason Ekstranda7af7042013-10-12 22:38:11 -05001316 weston_view_assign_output(view);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03001317
Jason Ekstranda7af7042013-10-12 22:38:11 -05001318 wl_signal_emit(&view->surface->compositor->transform_signal,
1319 view->surface);
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001320}
1321
Pekka Paalanenddae03c2012-02-06 14:54:20 +02001322WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001323weston_view_geometry_dirty(struct weston_view *view)
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02001324{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001325 struct weston_view *child;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001326
1327 /*
Jason Ekstranda7af7042013-10-12 22:38:11 -05001328 * The invariant: if view->geometry.dirty, then all views
1329 * in view->geometry.child_list have geometry.dirty too.
Pekka Paalanen483243f2013-03-08 14:56:50 +02001330 * Corollary: if not parent->geometry.dirty, then all ancestors
1331 * are not dirty.
1332 */
1333
Jason Ekstranda7af7042013-10-12 22:38:11 -05001334 if (view->transform.dirty)
Pekka Paalanen483243f2013-03-08 14:56:50 +02001335 return;
1336
Jason Ekstranda7af7042013-10-12 22:38:11 -05001337 view->transform.dirty = 1;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001338
Jason Ekstranda7af7042013-10-12 22:38:11 -05001339 wl_list_for_each(child, &view->geometry.child_list,
Pekka Paalanen483243f2013-03-08 14:56:50 +02001340 geometry.parent_link)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001341 weston_view_geometry_dirty(child);
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02001342}
1343
1344WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001345weston_view_to_global_fixed(struct weston_view *view,
1346 wl_fixed_t vx, wl_fixed_t vy,
1347 wl_fixed_t *x, wl_fixed_t *y)
Daniel Stonebd3489b2012-05-08 17:17:53 +01001348{
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001349 float xf, yf;
Daniel Stonebd3489b2012-05-08 17:17:53 +01001350
Jason Ekstranda7af7042013-10-12 22:38:11 -05001351 weston_view_to_global_float(view,
1352 wl_fixed_to_double(vx),
1353 wl_fixed_to_double(vy),
1354 &xf, &yf);
Daniel Stonebd3489b2012-05-08 17:17:53 +01001355 *x = wl_fixed_from_double(xf);
1356 *y = wl_fixed_from_double(yf);
1357}
1358
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -04001359WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001360weston_view_from_global_float(struct weston_view *view,
1361 float x, float y, float *vx, float *vy)
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001362{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001363 if (view->transform.enabled) {
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001364 struct weston_vector v = { { x, y, 0.0f, 1.0f } };
1365
Jason Ekstranda7af7042013-10-12 22:38:11 -05001366 weston_matrix_transform(&view->transform.inverse, &v);
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001367
1368 if (fabsf(v.f[3]) < 1e-6) {
Martin Minarik6d118362012-06-07 18:01:59 +02001369 weston_log("warning: numerical instability in "
Jason Ekstranda7af7042013-10-12 22:38:11 -05001370 "weston_view_from_global(), divisor = %g\n",
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001371 v.f[3]);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001372 *vx = 0;
1373 *vy = 0;
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001374 return;
1375 }
1376
Jason Ekstranda7af7042013-10-12 22:38:11 -05001377 *vx = v.f[0] / v.f[3];
1378 *vy = v.f[1] / v.f[3];
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001379 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001380 *vx = x - view->geometry.x;
1381 *vy = y - view->geometry.y;
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001382 }
1383}
1384
1385WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001386weston_view_from_global_fixed(struct weston_view *view,
1387 wl_fixed_t x, wl_fixed_t y,
1388 wl_fixed_t *vx, wl_fixed_t *vy)
Daniel Stonebd3489b2012-05-08 17:17:53 +01001389{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001390 float vxf, vyf;
Daniel Stonebd3489b2012-05-08 17:17:53 +01001391
Jason Ekstranda7af7042013-10-12 22:38:11 -05001392 weston_view_from_global_float(view,
1393 wl_fixed_to_double(x),
1394 wl_fixed_to_double(y),
1395 &vxf, &vyf);
1396 *vx = wl_fixed_from_double(vxf);
1397 *vy = wl_fixed_from_double(vyf);
Daniel Stonebd3489b2012-05-08 17:17:53 +01001398}
1399
1400WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001401weston_view_from_global(struct weston_view *view,
1402 int32_t x, int32_t y, int32_t *vx, int32_t *vy)
Pekka Paalanen0e151bb2012-01-24 14:47:37 +02001403{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001404 float vxf, vyf;
Pekka Paalanen0e151bb2012-01-24 14:47:37 +02001405
Jason Ekstranda7af7042013-10-12 22:38:11 -05001406 weston_view_from_global_float(view, x, y, &vxf, &vyf);
1407 *vx = floorf(vxf);
1408 *vy = floorf(vyf);
Pekka Paalanen0e151bb2012-01-24 14:47:37 +02001409}
1410
Bryce Harrington3f650b82015-12-23 11:01:58 -08001411/**
1412 * \param surface The surface to be repainted
1413 *
1414 * Marks the output(s) that the surface is shown on as needing to be
1415 * repainted. See weston_output_schedule_repaint().
1416 */
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001417WL_EXPORT void
Kristian Høgsberg98238702012-08-03 16:29:12 -04001418weston_surface_schedule_repaint(struct weston_surface *surface)
1419{
1420 struct weston_output *output;
1421
1422 wl_list_for_each(output, &surface->compositor->output_list, link)
Bryce Harrington89324ce2015-12-23 18:38:07 -08001423 if (surface->output_mask & (1u << output->id))
Kristian Høgsberg98238702012-08-03 16:29:12 -04001424 weston_output_schedule_repaint(output);
1425}
1426
Bryce Harrington3f650b82015-12-23 11:01:58 -08001427/**
1428 * \param view The view to be repainted
1429 *
1430 * Marks the output(s) that the view is shown on as needing to be
1431 * repainted. See weston_output_schedule_repaint().
1432 */
Kristian Høgsberg98238702012-08-03 16:29:12 -04001433WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001434weston_view_schedule_repaint(struct weston_view *view)
1435{
1436 struct weston_output *output;
1437
1438 wl_list_for_each(output, &view->surface->compositor->output_list, link)
Bryce Harrington89324ce2015-12-23 18:38:07 -08001439 if (view->output_mask & (1u << output->id))
Jason Ekstranda7af7042013-10-12 22:38:11 -05001440 weston_output_schedule_repaint(output);
1441}
1442
Pekka Paalanene508ce62015-02-19 13:59:55 +02001443/**
1444 * XXX: This function does it the wrong way.
1445 * surface->damage is the damage from the client, and causes
1446 * surface_flush_damage() to copy pixels. No window management action can
1447 * cause damage to the client-provided content, warranting re-upload!
1448 *
1449 * Instead of surface->damage, this function should record the damage
1450 * with all the views for this surface to avoid extraneous texture
1451 * uploads.
1452 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001453WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001454weston_surface_damage(struct weston_surface *surface)
Kristian Høgsberg31bd6c72011-02-13 13:00:51 -05001455{
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04001456 pixman_region32_union_rect(&surface->damage, &surface->damage,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001457 0, 0, surface->width,
1458 surface->height);
Pekka Paalanen2267d452012-01-26 13:12:45 +02001459
Kristian Høgsberg98238702012-08-03 16:29:12 -04001460 weston_surface_schedule_repaint(surface);
Kristian Høgsberg31bd6c72011-02-13 13:00:51 -05001461}
1462
Kristian Høgsberga691aee2011-06-23 21:43:50 -04001463WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001464weston_view_set_position(struct weston_view *view, float x, float y)
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001465{
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001466 if (view->geometry.x == x && view->geometry.y == y)
1467 return;
1468
Jason Ekstranda7af7042013-10-12 22:38:11 -05001469 view->geometry.x = x;
1470 view->geometry.y = y;
1471 weston_view_geometry_dirty(view);
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001472}
1473
Pekka Paalanen483243f2013-03-08 14:56:50 +02001474static void
1475transform_parent_handle_parent_destroy(struct wl_listener *listener,
1476 void *data)
1477{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001478 struct weston_view *view =
1479 container_of(listener, struct weston_view,
Pekka Paalanen483243f2013-03-08 14:56:50 +02001480 geometry.parent_destroy_listener);
1481
Jason Ekstranda7af7042013-10-12 22:38:11 -05001482 weston_view_set_transform_parent(view, NULL);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001483}
1484
1485WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001486weston_view_set_transform_parent(struct weston_view *view,
Pekka Paalanen380adf52015-02-16 14:39:11 +02001487 struct weston_view *parent)
Pekka Paalanen483243f2013-03-08 14:56:50 +02001488{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001489 if (view->geometry.parent) {
1490 wl_list_remove(&view->geometry.parent_destroy_listener.link);
1491 wl_list_remove(&view->geometry.parent_link);
Pekka Paalanen380adf52015-02-16 14:39:11 +02001492
1493 if (!parent)
1494 view->geometry.scissor_enabled = false;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001495 }
1496
Jason Ekstranda7af7042013-10-12 22:38:11 -05001497 view->geometry.parent = parent;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001498
Jason Ekstranda7af7042013-10-12 22:38:11 -05001499 view->geometry.parent_destroy_listener.notify =
Pekka Paalanen483243f2013-03-08 14:56:50 +02001500 transform_parent_handle_parent_destroy;
1501 if (parent) {
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001502 wl_signal_add(&parent->destroy_signal,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001503 &view->geometry.parent_destroy_listener);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001504 wl_list_insert(&parent->geometry.child_list,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001505 &view->geometry.parent_link);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001506 }
1507
Jason Ekstranda7af7042013-10-12 22:38:11 -05001508 weston_view_geometry_dirty(view);
1509}
1510
Pekka Paalanen380adf52015-02-16 14:39:11 +02001511/** Set a clip mask rectangle on a view
1512 *
1513 * \param view The view to set the clip mask on.
1514 * \param x Top-left corner X coordinate of the clip rectangle.
1515 * \param y Top-left corner Y coordinate of the clip rectangle.
1516 * \param width Width of the clip rectangle, non-negative.
1517 * \param height Height of the clip rectangle, non-negative.
1518 *
1519 * A shell may set a clip mask rectangle on a view. Everything outside
1520 * the rectangle is cut away for input and output purposes: it is
1521 * not drawn and cannot be hit by hit-test based input like pointer
1522 * motion or touch-downs. Everything inside the rectangle will behave
1523 * normally. Clients are unaware of clipping.
1524 *
Yong Bakos4c72e292016-04-28 11:59:10 -05001525 * The rectangle is set in surface-local coordinates. Setting a clip
Pekka Paalanen380adf52015-02-16 14:39:11 +02001526 * mask rectangle does not affect the view position, the view is positioned
1527 * as it would be without a clip. The clip also does not change
1528 * weston_surface::width,height.
1529 *
1530 * The clip mask rectangle is part of transformation inheritance
1531 * (weston_view_set_transform_parent()). A clip set in the root of the
1532 * transformation inheritance tree will affect all views in the tree.
1533 * A clip can be set only on the root view. Attempting to set a clip
1534 * on view that has a transformation parent will fail. Assigning a parent
1535 * to a view that has a clip set will cause the clip to be forgotten.
1536 *
1537 * Because the clip mask is an axis-aligned rectangle, it poses restrictions
1538 * on the additional transformations in the child views. These transformations
1539 * may not rotate the coordinate axes, i.e., only translation and scaling
1540 * are allowed. Violating this restriction causes the clipping to malfunction.
1541 * Furthermore, using scaling may cause rounding errors in child clipping.
1542 *
1543 * The clip mask rectangle is not automatically adjusted based on
1544 * wl_surface.attach dx and dy arguments.
1545 *
1546 * A clip mask rectangle can be set only if the compositor capability
1547 * WESTON_CAP_VIEW_CLIP_MASK is present.
1548 *
1549 * This function sets the clip mask rectangle and schedules a repaint for
1550 * the view.
1551 */
1552WL_EXPORT void
1553weston_view_set_mask(struct weston_view *view,
1554 int x, int y, int width, int height)
1555{
1556 struct weston_compositor *compositor = view->surface->compositor;
1557
1558 if (!(compositor->capabilities & WESTON_CAP_VIEW_CLIP_MASK)) {
1559 weston_log("%s not allowed without capability!\n", __func__);
1560 return;
1561 }
1562
1563 if (view->geometry.parent) {
1564 weston_log("view %p has a parent, clip forbidden!\n", view);
1565 return;
1566 }
1567
1568 if (width < 0 || height < 0) {
1569 weston_log("%s: illegal args %d, %d, %d, %d\n", __func__,
1570 x, y, width, height);
1571 return;
1572 }
1573
1574 pixman_region32_fini(&view->geometry.scissor);
1575 pixman_region32_init_rect(&view->geometry.scissor, x, y, width, height);
1576 view->geometry.scissor_enabled = true;
1577 weston_view_geometry_dirty(view);
1578 weston_view_schedule_repaint(view);
1579}
1580
1581/** Remove the clip mask from a view
1582 *
1583 * \param view The view to remove the clip mask from.
1584 *
1585 * Removed the clip mask rectangle and schedules a repaint.
1586 *
1587 * \sa weston_view_set_mask
1588 */
1589WL_EXPORT void
1590weston_view_set_mask_infinite(struct weston_view *view)
1591{
1592 view->geometry.scissor_enabled = false;
1593 weston_view_geometry_dirty(view);
1594 weston_view_schedule_repaint(view);
1595}
1596
Armin Krezović0da12b82016-06-30 06:04:33 +02001597/* Check if view should be displayed
1598 *
1599 * The indicator is set manually when assigning
1600 * a view to a surface.
1601 *
1602 * This needs reworking. See the thread starting at:
1603 *
1604 * https://lists.freedesktop.org/archives/wayland-devel/2016-June/029656.html
1605 */
Derek Foreman280e7dd2014-10-03 13:13:42 -05001606WL_EXPORT bool
Jason Ekstranda7af7042013-10-12 22:38:11 -05001607weston_view_is_mapped(struct weston_view *view)
1608{
Armin Krezović0da12b82016-06-30 06:04:33 +02001609 return view->is_mapped;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001610}
1611
Armin Krezović0da12b82016-06-30 06:04:33 +02001612/* Check if a surface has a view assigned to it
1613 *
1614 * The indicator is set manually when mapping
1615 * a surface and creating a view for it.
1616 *
1617 * This needs to go. See the thread starting at:
1618 *
1619 * https://lists.freedesktop.org/archives/wayland-devel/2016-June/029656.html
1620 *
1621 */
Derek Foreman280e7dd2014-10-03 13:13:42 -05001622WL_EXPORT bool
Ander Conselvan de Oliveirab8ab14f2012-03-27 17:36:36 +03001623weston_surface_is_mapped(struct weston_surface *surface)
1624{
Armin Krezović0da12b82016-06-30 06:04:33 +02001625 return surface->is_mapped;
Ander Conselvan de Oliveirab8ab14f2012-03-27 17:36:36 +03001626}
1627
Pekka Paalanenda75ee12013-11-26 18:19:43 +01001628static void
Jason Ekstrand5c11a332013-12-04 20:32:03 -06001629surface_set_size(struct weston_surface *surface, int32_t width, int32_t height)
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001630{
1631 struct weston_view *view;
1632
1633 if (surface->width == width && surface->height == height)
1634 return;
1635
1636 surface->width = width;
1637 surface->height = height;
1638
1639 wl_list_for_each(view, &surface->views, surface_link)
1640 weston_view_geometry_dirty(view);
1641}
1642
Jason Ekstrand5c11a332013-12-04 20:32:03 -06001643WL_EXPORT void
1644weston_surface_set_size(struct weston_surface *surface,
1645 int32_t width, int32_t height)
1646{
1647 assert(!surface->resource);
1648 surface_set_size(surface, width, height);
1649}
1650
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02001651static int
1652fixed_round_up_to_int(wl_fixed_t f)
1653{
1654 return wl_fixed_to_int(wl_fixed_from_int(1) - 1 + f);
1655}
1656
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001657static void
Pekka Paalanen59987fa2016-04-26 15:50:59 +03001658convert_size_by_transform_scale(int32_t *width_out, int32_t *height_out,
1659 int32_t width, int32_t height,
1660 uint32_t transform,
1661 int32_t scale)
1662{
1663 assert(scale > 0);
1664
1665 switch (transform) {
1666 case WL_OUTPUT_TRANSFORM_NORMAL:
1667 case WL_OUTPUT_TRANSFORM_180:
1668 case WL_OUTPUT_TRANSFORM_FLIPPED:
1669 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1670 *width_out = width / scale;
1671 *height_out = height / scale;
1672 break;
1673 case WL_OUTPUT_TRANSFORM_90:
1674 case WL_OUTPUT_TRANSFORM_270:
1675 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1676 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1677 *width_out = height / scale;
1678 *height_out = width / scale;
1679 break;
1680 default:
1681 assert(0 && "invalid transform");
1682 }
1683}
1684
1685static void
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02001686weston_surface_calculate_size_from_buffer(struct weston_surface *surface)
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02001687{
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001688 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Pekka Paalanenda75ee12013-11-26 18:19:43 +01001689
1690 if (!surface->buffer_ref.buffer) {
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02001691 surface->width_from_buffer = 0;
1692 surface->height_from_buffer = 0;
Jonny Lamb74130762013-11-26 18:19:46 +01001693 return;
1694 }
1695
Pekka Paalanen59987fa2016-04-26 15:50:59 +03001696 convert_size_by_transform_scale(&surface->width_from_buffer,
1697 &surface->height_from_buffer,
1698 surface->buffer_ref.buffer->width,
1699 surface->buffer_ref.buffer->height,
1700 vp->buffer.transform,
1701 vp->buffer.scale);
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02001702}
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02001703
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02001704static void
1705weston_surface_update_size(struct weston_surface *surface)
1706{
1707 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
1708 int32_t width, height;
1709
1710 width = surface->width_from_buffer;
1711 height = surface->height_from_buffer;
1712
1713 if (width != 0 && vp->surface.width != -1) {
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02001714 surface_set_size(surface,
1715 vp->surface.width, vp->surface.height);
1716 return;
1717 }
1718
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02001719 if (width != 0 && vp->buffer.src_width != wl_fixed_from_int(-1)) {
Pekka Paalanene9317212014-04-04 14:22:13 +03001720 int32_t w = fixed_round_up_to_int(vp->buffer.src_width);
1721 int32_t h = fixed_round_up_to_int(vp->buffer.src_height);
1722
1723 surface_set_size(surface, w ?: 1, h ?: 1);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02001724 return;
1725 }
1726
Jason Ekstrand5c11a332013-12-04 20:32:03 -06001727 surface_set_size(surface, width, height);
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02001728}
1729
Alexandros Frantzis409b01f2017-11-16 18:21:01 +02001730WL_EXPORT void
1731weston_compositor_get_time(struct timespec *time)
Kristian Høgsberg7132a9a2010-12-06 21:41:10 -05001732{
Alexandros Frantzis409b01f2017-11-16 18:21:01 +02001733 clock_gettime(CLOCK_REALTIME, time);
Kristian Høgsberg7132a9a2010-12-06 21:41:10 -05001734}
1735
Jason Ekstranda7af7042013-10-12 22:38:11 -05001736WL_EXPORT struct weston_view *
1737weston_compositor_pick_view(struct weston_compositor *compositor,
1738 wl_fixed_t x, wl_fixed_t y,
1739 wl_fixed_t *vx, wl_fixed_t *vy)
Tiago Vignatti9d393522012-02-10 16:26:19 +02001740{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001741 struct weston_view *view;
Pekka Paalanenfc22a522015-02-18 15:08:29 +02001742 wl_fixed_t view_x, view_y;
1743 int view_ix, view_iy;
1744 int ix = wl_fixed_to_int(x);
1745 int iy = wl_fixed_to_int(y);
Tiago Vignatti9d393522012-02-10 16:26:19 +02001746
Jason Ekstranda7af7042013-10-12 22:38:11 -05001747 wl_list_for_each(view, &compositor->view_list, link) {
Pekka Paalanenfc22a522015-02-18 15:08:29 +02001748 if (!pixman_region32_contains_point(
1749 &view->transform.boundingbox, ix, iy, NULL))
1750 continue;
1751
1752 weston_view_from_global_fixed(view, x, y, &view_x, &view_y);
1753 view_ix = wl_fixed_to_int(view_x);
1754 view_iy = wl_fixed_to_int(view_y);
1755
1756 if (!pixman_region32_contains_point(&view->surface->input,
1757 view_ix, view_iy, NULL))
1758 continue;
1759
Pekka Paalanen380adf52015-02-16 14:39:11 +02001760 if (view->geometry.scissor_enabled &&
1761 !pixman_region32_contains_point(&view->geometry.scissor,
1762 view_ix, view_iy, NULL))
1763 continue;
1764
Pekka Paalanenfc22a522015-02-18 15:08:29 +02001765 *vx = view_x;
1766 *vy = view_y;
1767 return view;
Tiago Vignatti9d393522012-02-10 16:26:19 +02001768 }
1769
Derek Foremanf9318d12015-05-11 15:40:11 -05001770 *vx = wl_fixed_from_int(-1000000);
1771 *vy = wl_fixed_from_int(-1000000);
Tiago Vignatti9d393522012-02-10 16:26:19 +02001772 return NULL;
1773}
1774
1775static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001776weston_compositor_repick(struct weston_compositor *compositor)
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04001777{
Daniel Stone37816df2012-05-16 18:45:18 +01001778 struct weston_seat *seat;
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04001779
Kristian Høgsberg10ddd972013-10-22 12:40:54 -07001780 if (!compositor->session_active)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001781 return;
1782
Daniel Stone37816df2012-05-16 18:45:18 +01001783 wl_list_for_each(seat, &compositor->seat_list, link)
Kristian Høgsberga71e8b22013-05-06 21:51:21 -04001784 weston_seat_repick(seat);
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04001785}
1786
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001787WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001788weston_view_unmap(struct weston_view *view)
Kristian Høgsberg3b5ea3b2012-02-17 12:43:56 -05001789{
Daniel Stone4dab5db2012-05-30 16:31:53 +01001790 struct weston_seat *seat;
Kristian Høgsberg867dec72012-03-01 17:09:37 -05001791
Jason Ekstranda7af7042013-10-12 22:38:11 -05001792 if (!weston_view_is_mapped(view))
1793 return;
Kristian Høgsberg867dec72012-03-01 17:09:37 -05001794
Jason Ekstranda7af7042013-10-12 22:38:11 -05001795 weston_view_damage_below(view);
1796 view->output = NULL;
Xiong Zhang97116532013-10-23 13:58:31 +08001797 view->plane = NULL;
Armin Krezovićf8486c32016-06-30 06:04:28 +02001798 view->is_mapped = false;
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001799 weston_layer_entry_remove(&view->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001800 wl_list_remove(&view->link);
1801 wl_list_init(&view->link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001802 view->output_mask = 0;
1803 weston_surface_assign_output(view->surface);
1804
1805 if (weston_surface_is_mapped(view->surface))
1806 return;
1807
1808 wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -05001809 struct weston_touch *touch = weston_seat_get_touch(seat);
1810 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
1811 struct weston_keyboard *keyboard =
1812 weston_seat_get_keyboard(seat);
1813
1814 if (keyboard && keyboard->focus == view->surface)
1815 weston_keyboard_set_focus(keyboard, NULL);
1816 if (pointer && pointer->focus == view)
Derek Foremanf9318d12015-05-11 15:40:11 -05001817 weston_pointer_clear_focus(pointer);
Derek Foreman1281a362015-07-31 16:55:32 -05001818 if (touch && touch->focus == view)
1819 weston_touch_set_focus(touch, NULL);
Daniel Stone4dab5db2012-05-30 16:31:53 +01001820 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001821}
Kristian Høgsberg867dec72012-03-01 17:09:37 -05001822
Jason Ekstranda7af7042013-10-12 22:38:11 -05001823WL_EXPORT void
1824weston_surface_unmap(struct weston_surface *surface)
1825{
1826 struct weston_view *view;
1827
Armin Krezovićf8486c32016-06-30 06:04:28 +02001828 surface->is_mapped = false;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001829 wl_list_for_each(view, &surface->views, surface_link)
1830 weston_view_unmap(view);
1831 surface->output = NULL;
Kristian Høgsberg3b5ea3b2012-02-17 12:43:56 -05001832}
1833
Pekka Paalanen3c9b8022014-03-14 14:38:13 +02001834static void
1835weston_surface_reset_pending_buffer(struct weston_surface *surface)
1836{
Jason Ekstrand7b982072014-05-20 14:33:03 -05001837 weston_surface_state_set_buffer(&surface->pending, NULL);
Pekka Paalanen3c9b8022014-03-14 14:38:13 +02001838 surface->pending.sx = 0;
1839 surface->pending.sy = 0;
1840 surface->pending.newly_attached = 0;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02001841 surface->pending.buffer_viewport.changed = 0;
Pekka Paalanen3c9b8022014-03-14 14:38:13 +02001842}
1843
Jason Ekstranda7af7042013-10-12 22:38:11 -05001844WL_EXPORT void
1845weston_view_destroy(struct weston_view *view)
1846{
1847 wl_signal_emit(&view->destroy_signal, view);
1848
1849 assert(wl_list_empty(&view->geometry.child_list));
1850
1851 if (weston_view_is_mapped(view)) {
1852 weston_view_unmap(view);
1853 weston_compositor_build_view_list(view->surface->compositor);
1854 }
1855
1856 wl_list_remove(&view->link);
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001857 weston_layer_entry_remove(&view->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001858
1859 pixman_region32_fini(&view->clip);
Pekka Paalanen380adf52015-02-16 14:39:11 +02001860 pixman_region32_fini(&view->geometry.scissor);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001861 pixman_region32_fini(&view->transform.boundingbox);
Pekka Paalanen8844bf22015-02-18 16:30:47 +02001862 pixman_region32_fini(&view->transform.opaque);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001863
1864 weston_view_set_transform_parent(view, NULL);
1865
Jason Ekstranda7af7042013-10-12 22:38:11 -05001866 wl_list_remove(&view->surface_link);
1867
1868 free(view);
1869}
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001870
1871WL_EXPORT void
1872weston_surface_destroy(struct weston_surface *surface)
Kristian Høgsberg54879822008-11-23 17:07:32 -05001873{
Kristian Høgsberg1e51fec2012-07-22 11:33:14 -04001874 struct weston_frame_callback *cb, *next;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001875 struct weston_view *ev, *nv;
Jonas Ådahld3414f22016-07-22 17:56:31 +08001876 struct weston_pointer_constraint *constraint, *next_constraint;
Kristian Høgsberg4fa48732009-03-10 23:17:00 -04001877
Giulio Camuffo13b85bd2013-08-13 23:10:14 +02001878 if (--surface->ref_count > 0)
1879 return;
1880
Pekka Paalanen08d3fb72015-04-17 14:00:24 +03001881 assert(surface->resource == NULL);
1882
Pekka Paalanenca790762015-04-17 14:23:38 +03001883 wl_signal_emit(&surface->destroy_signal, surface);
Giulio Camuffo13b85bd2013-08-13 23:10:14 +02001884
Pekka Paalanene67858b2013-04-25 13:57:42 +03001885 assert(wl_list_empty(&surface->subsurface_list_pending));
1886 assert(wl_list_empty(&surface->subsurface_list));
Pekka Paalanen483243f2013-03-08 14:56:50 +02001887
Jason Ekstranda7af7042013-10-12 22:38:11 -05001888 wl_list_for_each_safe(ev, nv, &surface->views, surface_link)
1889 weston_view_destroy(ev);
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04001890
Jason Ekstrand7b982072014-05-20 14:33:03 -05001891 weston_surface_state_fini(&surface->pending);
Pekka Paalanen5df44de2012-10-10 12:49:23 +03001892
Pekka Paalanende685b82012-12-04 15:58:12 +02001893 weston_buffer_reference(&surface->buffer_ref, NULL);
Kristian Høgsberg3f8f39c2009-09-18 17:05:13 -04001894
Pekka Paalanen402ae6d2012-01-03 10:23:24 +02001895 pixman_region32_fini(&surface->damage);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001896 pixman_region32_fini(&surface->opaque);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03001897 pixman_region32_fini(&surface->input);
Pekka Paalanen402ae6d2012-01-03 10:23:24 +02001898
Kristian Høgsberg1e51fec2012-07-22 11:33:14 -04001899 wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link)
Jason Ekstrandfbbbec82013-06-14 10:07:57 -05001900 wl_resource_destroy(cb->resource);
Kristian Høgsberg1e51fec2012-07-22 11:33:14 -04001901
Pekka Paalanen133e4392014-09-23 22:08:46 -04001902 weston_presentation_feedback_discard_list(&surface->feedback_list);
1903
Jonas Ådahld3414f22016-07-22 17:56:31 +08001904 wl_list_for_each_safe(constraint, next_constraint,
1905 &surface->pointer_constraints,
1906 link)
1907 weston_pointer_constraint_destroy(constraint);
1908
Kristian Høgsberg4fa48732009-03-10 23:17:00 -04001909 free(surface);
Kristian Høgsberg54879822008-11-23 17:07:32 -05001910}
1911
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001912static void
1913destroy_surface(struct wl_resource *resource)
Alex Wu8811bf92012-02-28 18:07:54 +08001914{
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001915 struct weston_surface *surface = wl_resource_get_user_data(resource);
Alex Wu8811bf92012-02-28 18:07:54 +08001916
Pekka Paalanen08d3fb72015-04-17 14:00:24 +03001917 assert(surface);
1918
Giulio Camuffo0d379742013-11-15 22:06:15 +01001919 /* Set the resource to NULL, since we don't want to leave a
1920 * dangling pointer if the surface was refcounted and survives
1921 * the weston_surface_destroy() call. */
1922 surface->resource = NULL;
Pekka Paalanen4826f872016-04-22 14:14:38 +03001923
1924 if (surface->viewport_resource)
1925 wl_resource_set_user_data(surface->viewport_resource, NULL);
1926
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001927 weston_surface_destroy(surface);
Alex Wu8811bf92012-02-28 18:07:54 +08001928}
1929
Benjamin Franzkefaa0a9d2011-02-21 16:24:53 +01001930static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001931weston_buffer_destroy_handler(struct wl_listener *listener, void *data)
1932{
1933 struct weston_buffer *buffer =
1934 container_of(listener, struct weston_buffer, destroy_listener);
1935
1936 wl_signal_emit(&buffer->destroy_signal, buffer);
1937 free(buffer);
1938}
1939
Giulio Camuffoe058cd12013-12-12 14:14:29 +01001940WL_EXPORT struct weston_buffer *
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001941weston_buffer_from_resource(struct wl_resource *resource)
1942{
1943 struct weston_buffer *buffer;
1944 struct wl_listener *listener;
U. Artie Eoff2e2384a2014-01-17 13:19:01 -08001945
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001946 listener = wl_resource_get_destroy_listener(resource,
1947 weston_buffer_destroy_handler);
1948
Kristian Høgsberg08b58c72013-08-15 12:26:42 -07001949 if (listener)
1950 return container_of(listener, struct weston_buffer,
1951 destroy_listener);
1952
1953 buffer = zalloc(sizeof *buffer);
1954 if (buffer == NULL)
1955 return NULL;
1956
1957 buffer->resource = resource;
1958 wl_signal_init(&buffer->destroy_signal);
1959 buffer->destroy_listener.notify = weston_buffer_destroy_handler;
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +04001960 buffer->y_inverted = 1;
Kristian Høgsberg08b58c72013-08-15 12:26:42 -07001961 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
U. Artie Eoff2e2384a2014-01-17 13:19:01 -08001962
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001963 return buffer;
1964}
1965
1966static void
Pekka Paalanende685b82012-12-04 15:58:12 +02001967weston_buffer_reference_handle_destroy(struct wl_listener *listener,
1968 void *data)
Benjamin Franzkefaa0a9d2011-02-21 16:24:53 +01001969{
Pekka Paalanende685b82012-12-04 15:58:12 +02001970 struct weston_buffer_reference *ref =
1971 container_of(listener, struct weston_buffer_reference,
1972 destroy_listener);
1973
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001974 assert((struct weston_buffer *)data == ref->buffer);
Pekka Paalanende685b82012-12-04 15:58:12 +02001975 ref->buffer = NULL;
1976}
1977
1978WL_EXPORT void
1979weston_buffer_reference(struct weston_buffer_reference *ref,
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001980 struct weston_buffer *buffer)
Pekka Paalanende685b82012-12-04 15:58:12 +02001981{
1982 if (ref->buffer && buffer != ref->buffer) {
Kristian Høgsberg20347802013-03-04 12:07:46 -05001983 ref->buffer->busy_count--;
1984 if (ref->buffer->busy_count == 0) {
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001985 assert(wl_resource_get_client(ref->buffer->resource));
Matt Hoosier3052bc72017-09-26 08:09:40 -05001986 wl_buffer_send_release(ref->buffer->resource);
Kristian Høgsberg20347802013-03-04 12:07:46 -05001987 }
Pekka Paalanende685b82012-12-04 15:58:12 +02001988 wl_list_remove(&ref->destroy_listener.link);
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03001989 }
1990
Pekka Paalanende685b82012-12-04 15:58:12 +02001991 if (buffer && buffer != ref->buffer) {
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001992 buffer->busy_count++;
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001993 wl_signal_add(&buffer->destroy_signal,
Pekka Paalanende685b82012-12-04 15:58:12 +02001994 &ref->destroy_listener);
Pekka Paalanena6421c42012-12-04 15:58:10 +02001995 }
1996
Pekka Paalanende685b82012-12-04 15:58:12 +02001997 ref->buffer = buffer;
1998 ref->destroy_listener.notify = weston_buffer_reference_handle_destroy;
1999}
2000
2001static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002002weston_surface_attach(struct weston_surface *surface,
2003 struct weston_buffer *buffer)
Pekka Paalanende685b82012-12-04 15:58:12 +02002004{
2005 weston_buffer_reference(&surface->buffer_ref, buffer);
2006
Pekka Paalanena6421c42012-12-04 15:58:10 +02002007 if (!buffer) {
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002008 if (weston_surface_is_mapped(surface))
2009 weston_surface_unmap(surface);
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002010 }
2011
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002012 surface->compositor->renderer->attach(surface, buffer);
Pekka Paalanenbb2f3f22014-03-14 14:38:11 +02002013
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002014 weston_surface_calculate_size_from_buffer(surface);
Pekka Paalanen133e4392014-09-23 22:08:46 -04002015 weston_presentation_feedback_discard_list(&surface->feedback_list);
Benjamin Franzkefaa0a9d2011-02-21 16:24:53 +01002016}
2017
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002018WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002019weston_compositor_damage_all(struct weston_compositor *compositor)
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002020{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002021 struct weston_output *output;
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002022
2023 wl_list_for_each(output, &compositor->output_list, link)
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002024 weston_output_damage(output);
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002025}
2026
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05002027WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002028weston_output_damage(struct weston_output *output)
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002029{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002030 struct weston_compositor *compositor = output->compositor;
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002031
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002032 pixman_region32_union(&compositor->primary_plane.damage,
2033 &compositor->primary_plane.damage,
2034 &output->region);
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002035 weston_output_schedule_repaint(output);
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002036}
2037
Kristian Høgsberg01f941b2009-05-27 17:47:15 -04002038static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002039surface_flush_damage(struct weston_surface *surface)
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002040{
Pekka Paalanende685b82012-12-04 15:58:12 +02002041 if (surface->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002042 wl_shm_buffer_get(surface->buffer_ref.buffer->resource))
Kristian Høgsbergfa1be022012-09-05 22:49:55 -04002043 surface->compositor->renderer->flush_damage(surface);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002044
Pekka Paalanenb5026542014-11-12 15:09:24 +02002045 if (weston_timeline_enabled_ &&
2046 pixman_region32_not_empty(&surface->damage))
2047 TL_POINT("core_flush_damage", TLP_SURFACE(surface),
2048 TLP_OUTPUT(surface->output), TLP_END);
2049
Jason Ekstrandef540082014-06-26 10:37:36 -07002050 pixman_region32_clear(&surface->damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002051}
2052
2053static void
2054view_accumulate_damage(struct weston_view *view,
2055 pixman_region32_t *opaque)
2056{
2057 pixman_region32_t damage;
2058
2059 pixman_region32_init(&damage);
2060 if (view->transform.enabled) {
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002061 pixman_box32_t *extents;
2062
Jason Ekstranda7af7042013-10-12 22:38:11 -05002063 extents = pixman_region32_extents(&view->surface->damage);
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02002064 view_compute_bbox(view, extents, &damage);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002065 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002066 pixman_region32_copy(&damage, &view->surface->damage);
2067 pixman_region32_translate(&damage,
Pekka Paalanen502f5e02015-02-23 14:08:25 +02002068 view->geometry.x, view->geometry.y);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002069 }
2070
Pekka Paalanen380adf52015-02-16 14:39:11 +02002071 pixman_region32_intersect(&damage, &damage,
2072 &view->transform.boundingbox);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002073 pixman_region32_subtract(&damage, &damage, opaque);
2074 pixman_region32_union(&view->plane->damage,
2075 &view->plane->damage, &damage);
2076 pixman_region32_fini(&damage);
2077 pixman_region32_copy(&view->clip, opaque);
Pekka Paalanen8844bf22015-02-18 16:30:47 +02002078 pixman_region32_union(opaque, opaque, &view->transform.opaque);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002079}
2080
Kristian Høgsbergcce1aec2011-04-22 15:38:14 -04002081static void
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002082compositor_accumulate_damage(struct weston_compositor *ec)
2083{
2084 struct weston_plane *plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002085 struct weston_view *ev;
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002086 pixman_region32_t opaque, clip;
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002087
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002088 pixman_region32_init(&clip);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002089
2090 wl_list_for_each(plane, &ec->plane_list, link) {
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002091 pixman_region32_copy(&plane->clip, &clip);
2092
2093 pixman_region32_init(&opaque);
2094
Jason Ekstranda7af7042013-10-12 22:38:11 -05002095 wl_list_for_each(ev, &ec->view_list, link) {
2096 if (ev->plane != plane)
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002097 continue;
2098
Jason Ekstranda7af7042013-10-12 22:38:11 -05002099 view_accumulate_damage(ev, &opaque);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002100 }
2101
2102 pixman_region32_union(&clip, &clip, &opaque);
2103 pixman_region32_fini(&opaque);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002104 }
2105
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002106 pixman_region32_fini(&clip);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002107
Jason Ekstranda7af7042013-10-12 22:38:11 -05002108 wl_list_for_each(ev, &ec->view_list, link)
Derek Foreman060cf112015-11-18 16:32:26 -06002109 ev->surface->touched = false;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002110
2111 wl_list_for_each(ev, &ec->view_list, link) {
2112 if (ev->surface->touched)
2113 continue;
Derek Foreman060cf112015-11-18 16:32:26 -06002114 ev->surface->touched = true;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002115
2116 surface_flush_damage(ev->surface);
2117
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002118 /* Both the renderer and the backend have seen the buffer
2119 * by now. If renderer needs the buffer, it has its own
2120 * reference set. If the backend wants to keep the buffer
2121 * around for migrating the surface into a non-primary plane
2122 * later, keep_buffer is true. Otherwise, drop the core
2123 * reference now, and allow early buffer release. This enables
2124 * clients to use single-buffering.
2125 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05002126 if (!ev->surface->keep_buffer)
2127 weston_buffer_reference(&ev->surface->buffer_ref, NULL);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002128 }
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002129}
2130
2131static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002132surface_stash_subsurface_views(struct weston_surface *surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03002133{
2134 struct weston_subsurface *sub;
2135
Pekka Paalanene67858b2013-04-25 13:57:42 +03002136 wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002137 if (sub->surface == surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03002138 continue;
2139
Jason Ekstranda7af7042013-10-12 22:38:11 -05002140 wl_list_insert_list(&sub->unused_views, &sub->surface->views);
2141 wl_list_init(&sub->surface->views);
2142
2143 surface_stash_subsurface_views(sub->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002144 }
2145}
2146
2147static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002148surface_free_unused_subsurface_views(struct weston_surface *surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03002149{
Jason Ekstranda7af7042013-10-12 22:38:11 -05002150 struct weston_subsurface *sub;
2151 struct weston_view *view, *nv;
Pekka Paalanene67858b2013-04-25 13:57:42 +03002152
Jason Ekstranda7af7042013-10-12 22:38:11 -05002153 wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
2154 if (sub->surface == surface)
2155 continue;
2156
George Kiagiadakised04d382014-06-13 18:10:26 +02002157 wl_list_for_each_safe(view, nv, &sub->unused_views, surface_link) {
2158 weston_view_unmap (view);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002159 weston_view_destroy(view);
George Kiagiadakised04d382014-06-13 18:10:26 +02002160 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002161
2162 surface_free_unused_subsurface_views(sub->surface);
2163 }
2164}
2165
2166static void
2167view_list_add_subsurface_view(struct weston_compositor *compositor,
2168 struct weston_subsurface *sub,
2169 struct weston_view *parent)
2170{
2171 struct weston_subsurface *child;
2172 struct weston_view *view = NULL, *iv;
2173
Pekka Paalanen661de3a2014-07-28 12:49:24 +03002174 if (!weston_surface_is_mapped(sub->surface))
2175 return;
2176
Jason Ekstranda7af7042013-10-12 22:38:11 -05002177 wl_list_for_each(iv, &sub->unused_views, surface_link) {
2178 if (iv->geometry.parent == parent) {
2179 view = iv;
2180 break;
Pekka Paalanene67858b2013-04-25 13:57:42 +03002181 }
2182 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002183
2184 if (view) {
2185 /* Put it back in the surface's list of views */
2186 wl_list_remove(&view->surface_link);
2187 wl_list_insert(&sub->surface->views, &view->surface_link);
2188 } else {
2189 view = weston_view_create(sub->surface);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002190 weston_view_set_position(view,
2191 sub->position.x,
2192 sub->position.y);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002193 weston_view_set_transform_parent(view, parent);
2194 }
2195
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03002196 view->parent_view = parent;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002197 weston_view_update_transform(view);
Armin Krezovićf8486c32016-06-30 06:04:28 +02002198 view->is_mapped = true;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002199
Pekka Paalanenb188e912013-11-19 14:03:35 +02002200 if (wl_list_empty(&sub->surface->subsurface_list)) {
2201 wl_list_insert(compositor->view_list.prev, &view->link);
2202 return;
2203 }
2204
2205 wl_list_for_each(child, &sub->surface->subsurface_list, parent_link) {
2206 if (child->surface == sub->surface)
2207 wl_list_insert(compositor->view_list.prev, &view->link);
2208 else
Jason Ekstranda7af7042013-10-12 22:38:11 -05002209 view_list_add_subsurface_view(compositor, child, view);
Pekka Paalanenb188e912013-11-19 14:03:35 +02002210 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002211}
2212
Emilio Pozuelo Monfort4f3cad72017-01-27 17:30:29 +01002213/* This recursively adds the sub-surfaces for a view, relying on the
2214 * sub-surface order. Thus, if a client restacks the sub-surfaces, that
2215 * change first happens to the sub-surface list, and then automatically
2216 * propagates here. See weston_surface_damage_subsurfaces() for how the
2217 * sub-surfaces receive damage when the client changes the state.
2218 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05002219static void
2220view_list_add(struct weston_compositor *compositor,
2221 struct weston_view *view)
2222{
2223 struct weston_subsurface *sub;
2224
2225 weston_view_update_transform(view);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002226
Pekka Paalanenb188e912013-11-19 14:03:35 +02002227 if (wl_list_empty(&view->surface->subsurface_list)) {
2228 wl_list_insert(compositor->view_list.prev, &view->link);
2229 return;
2230 }
2231
2232 wl_list_for_each(sub, &view->surface->subsurface_list, parent_link) {
2233 if (sub->surface == view->surface)
2234 wl_list_insert(compositor->view_list.prev, &view->link);
2235 else
Jason Ekstranda7af7042013-10-12 22:38:11 -05002236 view_list_add_subsurface_view(compositor, sub, view);
Pekka Paalanenb188e912013-11-19 14:03:35 +02002237 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002238}
2239
2240static void
2241weston_compositor_build_view_list(struct weston_compositor *compositor)
2242{
2243 struct weston_view *view;
2244 struct weston_layer *layer;
2245
2246 wl_list_for_each(layer, &compositor->layer_list, link)
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002247 wl_list_for_each(view, &layer->view_list.link, layer_link.link)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002248 surface_stash_subsurface_views(view->surface);
2249
2250 wl_list_init(&compositor->view_list);
2251 wl_list_for_each(layer, &compositor->layer_list, link) {
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002252 wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002253 view_list_add(compositor, view);
2254 }
2255 }
2256
2257 wl_list_for_each(layer, &compositor->layer_list, link)
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002258 wl_list_for_each(view, &layer->view_list.link, layer_link.link)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002259 surface_free_unused_subsurface_views(view->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002260}
2261
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002262static void
2263weston_output_take_feedback_list(struct weston_output *output,
2264 struct weston_surface *surface)
2265{
2266 struct weston_view *view;
2267 struct weston_presentation_feedback *feedback;
2268 uint32_t flags = 0xffffffff;
2269
2270 if (wl_list_empty(&surface->feedback_list))
2271 return;
2272
2273 /* All views must have the flag for the flag to survive. */
2274 wl_list_for_each(view, &surface->views, surface_link) {
2275 /* ignore views that are not on this output at all */
2276 if (view->output_mask & (1u << output->id))
2277 flags &= view->psf_flags;
2278 }
2279
2280 wl_list_for_each(feedback, &surface->feedback_list, link)
2281 feedback->psf_flags = flags;
2282
2283 wl_list_insert_list(&output->feedback_list, &surface->feedback_list);
2284 wl_list_init(&surface->feedback_list);
2285}
2286
David Herrmann1edf44c2013-10-22 17:11:26 +02002287static int
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002288weston_output_repaint(struct weston_output *output, void *repaint_data)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002289{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002290 struct weston_compositor *ec = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002291 struct weston_view *ev;
Kristian Høgsberg30c018b2012-01-26 08:40:37 -05002292 struct weston_animation *animation, *next;
2293 struct weston_frame_callback *cb, *cnext;
Jonas Ådahldb773762012-06-13 00:01:21 +02002294 struct wl_list frame_callback_list;
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002295 pixman_region32_t output_damage;
David Herrmann1edf44c2013-10-22 17:11:26 +02002296 int r;
Alexandros Frantzise6ac2af2017-11-16 18:20:53 +02002297 uint32_t frame_time_msec;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05002298
Ander Conselvan de Oliveirae1e23522013-12-13 22:10:55 +02002299 if (output->destroying)
2300 return 0;
2301
Pekka Paalanenb5026542014-11-12 15:09:24 +02002302 TL_POINT("core_repaint_begin", TLP_OUTPUT(output), TLP_END);
2303
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002304 /* Rebuild the surface list and update surface transforms up front. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05002305 weston_compositor_build_view_list(ec);
Pekka Paalanen15d60ef2012-01-27 14:38:33 +02002306
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002307 if (output->assign_planes && !output->disable_planes) {
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002308 output->assign_planes(output, repaint_data);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002309 } else {
2310 wl_list_for_each(ev, &ec->view_list, link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002311 weston_view_move_to_plane(ev, &ec->primary_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002312 ev->psf_flags = 0;
2313 }
2314 }
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04002315
Pekka Paalanene67858b2013-04-25 13:57:42 +03002316 wl_list_init(&frame_callback_list);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002317 wl_list_for_each(ev, &ec->view_list, link) {
2318 /* Note: This operation is safe to do multiple times on the
2319 * same surface.
2320 */
2321 if (ev->surface->output == output) {
Pekka Paalanene67858b2013-04-25 13:57:42 +03002322 wl_list_insert_list(&frame_callback_list,
Jason Ekstranda7af7042013-10-12 22:38:11 -05002323 &ev->surface->frame_callback_list);
2324 wl_list_init(&ev->surface->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -04002325
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002326 weston_output_take_feedback_list(output, ev->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002327 }
2328 }
2329
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002330 compositor_accumulate_damage(ec);
Kristian Høgsberg53df1d82011-06-23 21:11:19 -04002331
Ander Conselvan de Oliveira4f521732012-08-15 14:02:05 -04002332 pixman_region32_init(&output_damage);
Ander Conselvan de Oliveira4f521732012-08-15 14:02:05 -04002333 pixman_region32_intersect(&output_damage,
2334 &ec->primary_plane.damage, &output->region);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002335 pixman_region32_subtract(&output_damage,
2336 &output_damage, &ec->primary_plane.clip);
Ander Conselvan de Oliveira4f521732012-08-15 14:02:05 -04002337
Scott Moreauccbf29d2012-02-22 14:21:41 -07002338 if (output->dirty)
2339 weston_output_update_matrix(output);
2340
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002341 r = output->repaint(output, &output_damage, repaint_data);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002342
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -05002343 pixman_region32_fini(&output_damage);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05002344
Daniel Stone09a97e22017-03-01 11:34:06 +00002345 output->repaint_needed = false;
Daniel Stone05df8c12017-03-03 16:59:42 +00002346 if (r == 0)
2347 output->repaint_status = REPAINT_AWAITING_COMPLETION;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002348
Kristian Høgsbergaa6019e2012-03-11 16:35:16 -04002349 weston_compositor_repick(ec);
Kristian Høgsbergaa6019e2012-03-11 16:35:16 -04002350
Alexandros Frantzise6ac2af2017-11-16 18:20:53 +02002351 frame_time_msec = timespec_to_msec(&output->frame_time);
2352
Jonas Ådahldb773762012-06-13 00:01:21 +02002353 wl_list_for_each_safe(cb, cnext, &frame_callback_list, link) {
Alexandros Frantzise6ac2af2017-11-16 18:20:53 +02002354 wl_callback_send_done(cb->resource, frame_time_msec);
Jason Ekstrandfbbbec82013-06-14 10:07:57 -05002355 wl_resource_destroy(cb->resource);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05002356 }
2357
Scott Moreaud64cf212012-06-08 19:40:54 -06002358 wl_list_for_each_safe(animation, next, &output->animation_list, link) {
Scott Moreaud64cf212012-06-08 19:40:54 -06002359 animation->frame_counter++;
Alexandros Frantzise6ac2af2017-11-16 18:20:53 +02002360 animation->frame(animation, output, &output->frame_time);
Scott Moreaud64cf212012-06-08 19:40:54 -06002361 }
David Herrmann1edf44c2013-10-22 17:11:26 +02002362
Pekka Paalanenb5026542014-11-12 15:09:24 +02002363 TL_POINT("core_repaint_posted", TLP_OUTPUT(output), TLP_END);
2364
David Herrmann1edf44c2013-10-22 17:11:26 +02002365 return r;
Kristian Høgsbergef044142011-06-21 15:02:12 -04002366}
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002367
Pekka Paalanen82919792014-05-21 13:51:49 +03002368static void
2369weston_output_schedule_repaint_reset(struct weston_output *output)
2370{
Daniel Stone05df8c12017-03-03 16:59:42 +00002371 output->repaint_status = REPAINT_NOT_SCHEDULED;
Pekka Paalanen82919792014-05-21 13:51:49 +03002372 TL_POINT("core_repaint_exit_loop", TLP_OUTPUT(output), TLP_END);
Pekka Paalanen82919792014-05-21 13:51:49 +03002373}
2374
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002375static int
2376weston_output_maybe_repaint(struct weston_output *output, struct timespec *now,
2377 void *repaint_data)
Pekka Paalanen0513a952014-05-21 16:17:27 +03002378{
Pekka Paalanen0513a952014-05-21 16:17:27 +03002379 struct weston_compositor *compositor = output->compositor;
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002380 int ret = 0;
Daniel Stone6847b852017-03-01 11:34:08 +00002381 int64_t msec_to_repaint;
Pekka Paalanen0513a952014-05-21 16:17:27 +03002382
Daniel Stone6847b852017-03-01 11:34:08 +00002383 /* We're not ready yet; come back to make a decision later. */
2384 if (output->repaint_status != REPAINT_SCHEDULED)
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002385 return ret;
Daniel Stone6847b852017-03-01 11:34:08 +00002386
2387 msec_to_repaint = timespec_sub_to_msec(&output->next_repaint, now);
2388 if (msec_to_repaint > 1)
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002389 return ret;
Daniel Stone05df8c12017-03-03 16:59:42 +00002390
Daniel Stonecd1a1c32017-01-16 15:38:54 +00002391 /* If we're sleeping, drop the repaint machinery entirely; we will
2392 * explicitly repaint all outputs when we come back. */
2393 if (compositor->state == WESTON_COMPOSITOR_SLEEPING ||
2394 compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
2395 goto err;
Pekka Paalanen0513a952014-05-21 16:17:27 +03002396
Daniel Stonecd1a1c32017-01-16 15:38:54 +00002397 /* We don't actually need to repaint this output; drop it from
2398 * repaint until something causes damage. */
2399 if (!output->repaint_needed)
2400 goto err;
2401
2402 /* If repaint fails, we aren't going to get weston_output_finish_frame
2403 * to trigger a new repaint, so drop it from repaint and hope
Daniel Stone6847b852017-03-01 11:34:08 +00002404 * something schedules a successful repaint later. As repainting may
2405 * take some time, re-read our clock as a courtesy to the next
2406 * output. */
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002407 ret = weston_output_repaint(output, repaint_data);
Daniel Stone6847b852017-03-01 11:34:08 +00002408 weston_compositor_read_presentation_clock(compositor, now);
Daniel Stonecd1a1c32017-01-16 15:38:54 +00002409 if (ret != 0)
2410 goto err;
2411
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002412 return ret;
Daniel Stonecd1a1c32017-01-16 15:38:54 +00002413
2414err:
Pekka Paalanen0513a952014-05-21 16:17:27 +03002415 weston_output_schedule_repaint_reset(output);
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002416 return ret;
Daniel Stone6847b852017-03-01 11:34:08 +00002417}
2418
2419static void
2420output_repaint_timer_arm(struct weston_compositor *compositor)
2421{
2422 struct weston_output *output;
2423 bool any_should_repaint = false;
2424 struct timespec now;
Sergi Granellb4c08862017-03-18 13:01:15 +01002425 int64_t msec_to_next = INT64_MAX;
Daniel Stone6847b852017-03-01 11:34:08 +00002426
2427 weston_compositor_read_presentation_clock(compositor, &now);
2428
2429 wl_list_for_each(output, &compositor->output_list, link) {
2430 int64_t msec_to_this;
2431
2432 if (output->repaint_status != REPAINT_SCHEDULED)
2433 continue;
2434
2435 msec_to_this = timespec_sub_to_msec(&output->next_repaint,
2436 &now);
2437 if (!any_should_repaint || msec_to_this < msec_to_next)
2438 msec_to_next = msec_to_this;
2439
2440 any_should_repaint = true;
2441 }
2442
2443 if (!any_should_repaint)
2444 return;
2445
2446 /* Even if we should repaint immediately, add the minimum 1 ms delay.
2447 * This is a workaround to allow coalescing multiple output repaints
2448 * particularly from weston_output_finish_frame()
2449 * into the same call, which would not happen if we called
2450 * output_repaint_timer_handler() directly.
2451 */
2452 if (msec_to_next < 1)
2453 msec_to_next = 1;
2454
2455 wl_event_source_timer_update(compositor->repaint_timer, msec_to_next);
2456}
2457
2458static int
2459output_repaint_timer_handler(void *data)
2460{
2461 struct weston_compositor *compositor = data;
2462 struct weston_output *output;
2463 struct timespec now;
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002464 void *repaint_data = NULL;
Emre Ucane479ed82018-03-20 15:29:40 +01002465 int ret = 0;
Daniel Stone6847b852017-03-01 11:34:08 +00002466
2467 weston_compositor_read_presentation_clock(compositor, &now);
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002468
2469 if (compositor->backend->repaint_begin)
2470 repaint_data = compositor->backend->repaint_begin(compositor);
2471
2472 wl_list_for_each(output, &compositor->output_list, link) {
2473 ret = weston_output_maybe_repaint(output, &now, repaint_data);
2474 if (ret)
2475 break;
2476 }
2477
2478 if (ret == 0) {
2479 if (compositor->backend->repaint_flush)
2480 compositor->backend->repaint_flush(compositor,
2481 repaint_data);
2482 } else {
2483 if (compositor->backend->repaint_cancel)
2484 compositor->backend->repaint_cancel(compositor,
2485 repaint_data);
2486 }
Daniel Stone6847b852017-03-01 11:34:08 +00002487
2488 output_repaint_timer_arm(compositor);
2489
Pekka Paalanen0513a952014-05-21 16:17:27 +03002490 return 0;
2491}
2492
Kristian Høgsbergef044142011-06-21 15:02:12 -04002493WL_EXPORT void
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04002494weston_output_finish_frame(struct weston_output *output,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +02002495 const struct timespec *stamp,
2496 uint32_t presented_flags)
Kristian Høgsbergef044142011-06-21 15:02:12 -04002497{
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05002498 struct weston_compositor *compositor = output->compositor;
Pekka Paalanen0513a952014-05-21 16:17:27 +03002499 int32_t refresh_nsec;
2500 struct timespec now;
Daniel Stone6847b852017-03-01 11:34:08 +00002501 int64_t msec_rel;
Pekka Paalanen133e4392014-09-23 22:08:46 -04002502
Pekka Paalanenb5026542014-11-12 15:09:24 +02002503
Daniel Stone05df8c12017-03-03 16:59:42 +00002504 assert(output->repaint_status == REPAINT_AWAITING_COMPLETION);
Daniel Stone3615ce12017-03-01 11:34:05 +00002505 assert(stamp || (presented_flags & WP_PRESENTATION_FEEDBACK_INVALID));
2506
Daniel Stone6847b852017-03-01 11:34:08 +00002507 weston_compositor_read_presentation_clock(compositor, &now);
2508
Daniel Stone3615ce12017-03-01 11:34:05 +00002509 /* If we haven't been supplied any timestamp at all, we don't have a
2510 * timebase to work against, so any delay just wastes time. Push a
2511 * repaint as soon as possible so we can get on with it. */
Daniel Stone6847b852017-03-01 11:34:08 +00002512 if (!stamp) {
2513 output->next_repaint = now;
Daniel Stone3615ce12017-03-01 11:34:05 +00002514 goto out;
Daniel Stone6847b852017-03-01 11:34:08 +00002515 }
Daniel Stone3615ce12017-03-01 11:34:05 +00002516
Marius Vladdf9278a2018-03-06 18:56:23 +02002517 TL_POINT("core_repaint_finished", TLP_OUTPUT(output),
2518 TLP_VBLANK(stamp), TLP_END);
2519
Pekka Paalanend7894d02015-07-03 15:08:53 +03002520 refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
Pekka Paalanen133e4392014-09-23 22:08:46 -04002521 weston_presentation_feedback_present_list(&output->feedback_list,
2522 output, refresh_nsec, stamp,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +02002523 output->msc,
2524 presented_flags);
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05002525
Alexandros Frantzise6ac2af2017-11-16 18:20:53 +02002526 output->frame_time = *stamp;
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05002527
Daniel Stone6847b852017-03-01 11:34:08 +00002528 timespec_add_nsec(&output->next_repaint, stamp, refresh_nsec);
2529 timespec_add_msec(&output->next_repaint, &output->next_repaint,
2530 -compositor->repaint_msec);
2531 msec_rel = timespec_sub_to_msec(&output->next_repaint, &now);
Daniel Stone84aff5c2017-03-01 11:34:04 +00002532
2533 if (msec_rel < -1000 || msec_rel > 1000) {
Pekka Paalanen8fd4de42015-03-19 12:27:29 +02002534 static bool warned;
2535
2536 if (!warned)
2537 weston_log("Warning: computed repaint delay is "
Daniel Stone6847b852017-03-01 11:34:08 +00002538 "insane: %lld msec\n", (long long) msec_rel);
Pekka Paalanen8fd4de42015-03-19 12:27:29 +02002539 warned = true;
2540
Daniel Stone6847b852017-03-01 11:34:08 +00002541 output->next_repaint = now;
Pekka Paalanen8fd4de42015-03-19 12:27:29 +02002542 }
2543
Mario Kleinerb7df04e2015-06-21 21:25:15 +02002544 /* Called from restart_repaint_loop and restart happens already after
2545 * the deadline given by repaint_msec? In that case we delay until
2546 * the deadline of the next frame, to give clients a more predictable
2547 * timing of the repaint cycle to lock on. */
Daniel Stoneeca5cca2017-02-28 21:53:51 +00002548 if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID &&
2549 msec_rel < 0) {
2550 while (timespec_sub_to_nsec(&output->next_repaint, &now) < 0) {
2551 timespec_add_nsec(&output->next_repaint,
2552 &output->next_repaint,
2553 refresh_nsec);
2554 }
2555 }
Mario Kleinerb7df04e2015-06-21 21:25:15 +02002556
Daniel Stone3615ce12017-03-01 11:34:05 +00002557out:
Daniel Stone05df8c12017-03-03 16:59:42 +00002558 output->repaint_status = REPAINT_SCHEDULED;
Daniel Stone6847b852017-03-01 11:34:08 +00002559 output_repaint_timer_arm(compositor);
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05002560}
2561
2562static void
2563idle_repaint(void *data)
2564{
2565 struct weston_output *output = data;
2566
Daniel Stone05df8c12017-03-03 16:59:42 +00002567 assert(output->repaint_status == REPAINT_BEGIN_FROM_IDLE);
2568 output->repaint_status = REPAINT_AWAITING_COMPLETION;
Jonas Ådahle5a12252013-04-05 23:07:11 +02002569 output->start_repaint_loop(output);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002570}
2571
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002572WL_EXPORT void
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002573weston_layer_entry_insert(struct weston_layer_entry *list,
2574 struct weston_layer_entry *entry)
2575{
2576 wl_list_insert(&list->link, &entry->link);
2577 entry->layer = list->layer;
2578}
2579
2580WL_EXPORT void
2581weston_layer_entry_remove(struct weston_layer_entry *entry)
2582{
2583 wl_list_remove(&entry->link);
2584 wl_list_init(&entry->link);
2585 entry->layer = NULL;
2586}
2587
Quentin Glidic82681572016-12-17 13:40:51 +01002588
2589/** Initialize the weston_layer struct.
2590 *
2591 * \param compositor The compositor instance
2592 * \param layer The layer to initialize
2593 */
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002594WL_EXPORT void
Quentin Glidic82681572016-12-17 13:40:51 +01002595weston_layer_init(struct weston_layer *layer,
2596 struct weston_compositor *compositor)
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002597{
Quentin Glidic82681572016-12-17 13:40:51 +01002598 layer->compositor = compositor;
2599 wl_list_init(&layer->link);
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002600 wl_list_init(&layer->view_list.link);
2601 layer->view_list.layer = layer;
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03002602 weston_layer_set_mask_infinite(layer);
Quentin Glidic82681572016-12-17 13:40:51 +01002603}
2604
2605/** Sets the position of the layer in the layer list. The layer will be placed
2606 * below any layer with the same position value, if any.
2607 * This function is safe to call if the layer is already on the list, but the
2608 * layer may be moved below other layers at the same position, if any.
2609 *
2610 * \param layer The layer to modify
2611 * \param position The position the layer will be placed at
2612 */
2613WL_EXPORT void
2614weston_layer_set_position(struct weston_layer *layer,
2615 enum weston_layer_position position)
2616{
2617 struct weston_layer *below;
2618
2619 wl_list_remove(&layer->link);
2620
2621 /* layer_list is ordered from top to bottom, the last layer being the
2622 * background with the smallest position value */
2623
2624 layer->position = position;
2625 wl_list_for_each_reverse(below, &layer->compositor->layer_list, link) {
2626 if (below->position >= layer->position) {
2627 wl_list_insert(&below->link, &layer->link);
2628 return;
2629 }
2630 }
2631 wl_list_insert(&layer->compositor->layer_list, &layer->link);
2632}
2633
2634/** Hide a layer by taking it off the layer list.
2635 * This function is safe to call if the layer is not on the list.
2636 *
2637 * \param layer The layer to hide
2638 */
2639WL_EXPORT void
2640weston_layer_unset_position(struct weston_layer *layer)
2641{
2642 wl_list_remove(&layer->link);
2643 wl_list_init(&layer->link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002644}
2645
2646WL_EXPORT void
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03002647weston_layer_set_mask(struct weston_layer *layer,
2648 int x, int y, int width, int height)
2649{
2650 struct weston_view *view;
2651
2652 layer->mask.x1 = x;
2653 layer->mask.x2 = x + width;
2654 layer->mask.y1 = y;
2655 layer->mask.y2 = y + height;
2656
2657 wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
2658 weston_view_geometry_dirty(view);
2659 }
2660}
2661
2662WL_EXPORT void
2663weston_layer_set_mask_infinite(struct weston_layer *layer)
2664{
2665 weston_layer_set_mask(layer, INT32_MIN, INT32_MIN,
2666 UINT32_MAX, UINT32_MAX);
2667}
2668
2669WL_EXPORT void
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002670weston_output_schedule_repaint(struct weston_output *output)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002671{
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002672 struct weston_compositor *compositor = output->compositor;
Kristian Høgsbergef044142011-06-21 15:02:12 -04002673 struct wl_event_loop *loop;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002674
Bryce Harrington08976ac2016-08-30 12:05:16 -07002675 if (compositor->state == WESTON_COMPOSITOR_SLEEPING ||
2676 compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002677 return;
2678
Pekka Paalanenb5026542014-11-12 15:09:24 +02002679 if (!output->repaint_needed)
2680 TL_POINT("core_repaint_req", TLP_OUTPUT(output), TLP_END);
2681
Kristian Høgsbergef044142011-06-21 15:02:12 -04002682 loop = wl_display_get_event_loop(compositor->wl_display);
Daniel Stone09a97e22017-03-01 11:34:06 +00002683 output->repaint_needed = true;
Daniel Stone05df8c12017-03-03 16:59:42 +00002684
2685 /* If we already have a repaint scheduled for our idle handler,
2686 * no need to set it again. If the repaint has been called but
2687 * not finished, then weston_output_finish_frame() will notice
2688 * that a repaint is needed and schedule one. */
2689 if (output->repaint_status != REPAINT_NOT_SCHEDULED)
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002690 return;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002691
Daniel Stone05df8c12017-03-03 16:59:42 +00002692 output->repaint_status = REPAINT_BEGIN_FROM_IDLE;
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002693 wl_event_loop_add_idle(loop, idle_repaint, output);
Pekka Paalanenb5026542014-11-12 15:09:24 +02002694 TL_POINT("core_repaint_enter_loop", TLP_OUTPUT(output), TLP_END);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002695}
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -05002696
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002697WL_EXPORT void
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002698weston_compositor_schedule_repaint(struct weston_compositor *compositor)
2699{
2700 struct weston_output *output;
2701
2702 wl_list_for_each(output, &compositor->output_list, link)
2703 weston_output_schedule_repaint(output);
2704}
2705
Kristian Høgsberg5503bf82008-11-06 10:38:17 -05002706static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -04002707surface_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04002708{
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002709 wl_resource_destroy(resource);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04002710}
2711
Kristian Høgsberg5503bf82008-11-06 10:38:17 -05002712static void
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002713surface_attach(struct wl_client *client,
2714 struct wl_resource *resource,
2715 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
2716{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002717 struct weston_surface *surface = wl_resource_get_user_data(resource);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002718 struct weston_buffer *buffer = NULL;
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002719
Kristian Høgsbergab19f932013-08-20 11:30:54 -07002720 if (buffer_resource) {
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002721 buffer = weston_buffer_from_resource(buffer_resource);
Kristian Høgsbergab19f932013-08-20 11:30:54 -07002722 if (buffer == NULL) {
2723 wl_client_post_no_memory(client);
2724 return;
2725 }
Kristian Høgsberg08b58c72013-08-15 12:26:42 -07002726 }
Kristian Høgsberga691aee2011-06-23 21:43:50 -04002727
Pekka Paalanende685b82012-12-04 15:58:12 +02002728 /* Attach, attach, without commit in between does not send
2729 * wl_buffer.release. */
Jason Ekstrand7b982072014-05-20 14:33:03 -05002730 weston_surface_state_set_buffer(&surface->pending, buffer);
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002731
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002732 surface->pending.sx = sx;
2733 surface->pending.sy = sy;
Giulio Camuffo184df502013-02-21 11:29:21 +01002734 surface->pending.newly_attached = 1;
Kristian Høgsbergf9212892008-10-11 18:40:23 -04002735}
2736
Kristian Høgsberg5503bf82008-11-06 10:38:17 -05002737static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05002738surface_damage(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -04002739 struct wl_resource *resource,
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05002740 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -05002741{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002742 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04002743
Derek Foreman57e92ed2015-11-17 14:11:35 -06002744 if (width <= 0 || height <= 0)
2745 return;
2746
Derek Foreman152254b2015-11-26 14:17:48 -06002747 pixman_region32_union_rect(&surface->pending.damage_surface,
2748 &surface->pending.damage_surface,
2749 x, y, width, height);
2750}
2751
2752static void
2753surface_damage_buffer(struct wl_client *client,
2754 struct wl_resource *resource,
2755 int32_t x, int32_t y, int32_t width, int32_t height)
2756{
2757 struct weston_surface *surface = wl_resource_get_user_data(resource);
2758
2759 if (width <= 0 || height <= 0)
2760 return;
2761
2762 pixman_region32_union_rect(&surface->pending.damage_buffer,
2763 &surface->pending.damage_buffer,
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002764 x, y, width, height);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05002765}
2766
Kristian Høgsberg33418202011-08-16 23:01:28 -04002767static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -04002768destroy_frame_callback(struct wl_resource *resource)
Kristian Høgsberg33418202011-08-16 23:01:28 -04002769{
Jason Ekstrandfbbbec82013-06-14 10:07:57 -05002770 struct weston_frame_callback *cb = wl_resource_get_user_data(resource);
Kristian Høgsberg904055a2011-08-18 17:55:30 -04002771
2772 wl_list_remove(&cb->link);
Pekka Paalanen8c196452011-11-15 11:45:42 +02002773 free(cb);
Kristian Høgsberg33418202011-08-16 23:01:28 -04002774}
2775
2776static void
2777surface_frame(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -04002778 struct wl_resource *resource, uint32_t callback)
Kristian Høgsberg33418202011-08-16 23:01:28 -04002779{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002780 struct weston_frame_callback *cb;
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002781 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg33418202011-08-16 23:01:28 -04002782
2783 cb = malloc(sizeof *cb);
2784 if (cb == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -04002785 wl_resource_post_no_memory(resource);
Kristian Høgsberg33418202011-08-16 23:01:28 -04002786 return;
2787 }
Pekka Paalanenbc106382012-10-10 12:49:31 +03002788
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07002789 cb->resource = wl_resource_create(client, &wl_callback_interface, 1,
2790 callback);
2791 if (cb->resource == NULL) {
2792 free(cb);
2793 wl_resource_post_no_memory(resource);
2794 return;
2795 }
2796
Jason Ekstranda85118c2013-06-27 20:17:02 -05002797 wl_resource_set_implementation(cb->resource, NULL, cb,
2798 destroy_frame_callback);
Kristian Høgsberg33418202011-08-16 23:01:28 -04002799
Pekka Paalanenbc106382012-10-10 12:49:31 +03002800 wl_list_insert(surface->pending.frame_callback_list.prev, &cb->link);
Kristian Høgsberg33418202011-08-16 23:01:28 -04002801}
2802
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002803static void
2804surface_set_opaque_region(struct wl_client *client,
2805 struct wl_resource *resource,
2806 struct wl_resource *region_resource)
2807{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002808 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002809 struct weston_region *region;
2810
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002811 if (region_resource) {
Jason Ekstrand8895efc2013-06-14 10:07:56 -05002812 region = wl_resource_get_user_data(region_resource);
Pekka Paalanen512dde82012-10-10 12:49:27 +03002813 pixman_region32_copy(&surface->pending.opaque,
2814 &region->region);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002815 } else {
Jason Ekstrandef540082014-06-26 10:37:36 -07002816 pixman_region32_clear(&surface->pending.opaque);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002817 }
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002818}
2819
2820static void
2821surface_set_input_region(struct wl_client *client,
2822 struct wl_resource *resource,
2823 struct wl_resource *region_resource)
2824{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002825 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05002826 struct weston_region *region;
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002827
2828 if (region_resource) {
Jason Ekstrand8895efc2013-06-14 10:07:56 -05002829 region = wl_resource_get_user_data(region_resource);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03002830 pixman_region32_copy(&surface->pending.input,
2831 &region->region);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002832 } else {
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03002833 pixman_region32_fini(&surface->pending.input);
2834 region_init_infinite(&surface->pending.input);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002835 }
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002836}
2837
Emilio Pozuelo Monfort4f3cad72017-01-27 17:30:29 +01002838/* Cause damage to this sub-surface and all its children.
2839 *
2840 * This is useful when there are state changes that need an implicit
2841 * damage, e.g. a z-order change.
2842 */
2843static void
2844weston_surface_damage_subsurfaces(struct weston_subsurface *sub)
2845{
2846 struct weston_subsurface *child;
2847
2848 weston_surface_damage(sub->surface);
2849 sub->reordered = false;
2850
2851 wl_list_for_each(child, &sub->surface->subsurface_list, parent_link)
2852 if (child != sub)
2853 weston_surface_damage_subsurfaces(child);
2854}
2855
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002856static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03002857weston_surface_commit_subsurface_order(struct weston_surface *surface)
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002858{
Pekka Paalanene67858b2013-04-25 13:57:42 +03002859 struct weston_subsurface *sub;
2860
2861 wl_list_for_each_reverse(sub, &surface->subsurface_list_pending,
2862 parent_link_pending) {
2863 wl_list_remove(&sub->parent_link);
2864 wl_list_insert(&surface->subsurface_list, &sub->parent_link);
Emilio Pozuelo Monfort4f3cad72017-01-27 17:30:29 +01002865
2866 if (sub->reordered)
2867 weston_surface_damage_subsurfaces(sub);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002868 }
2869}
2870
2871static void
Pekka Paalanen04baea52016-04-26 15:50:58 +03002872weston_surface_build_buffer_matrix(const struct weston_surface *surface,
Jason Ekstrand1e059042014-10-16 10:55:19 -05002873 struct weston_matrix *matrix)
2874{
Pekka Paalanen04baea52016-04-26 15:50:58 +03002875 const struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Jason Ekstrand1e059042014-10-16 10:55:19 -05002876 double src_width, src_height, dest_width, dest_height;
2877
2878 weston_matrix_init(matrix);
2879
2880 if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
2881 src_width = surface->width_from_buffer;
2882 src_height = surface->height_from_buffer;
2883 } else {
2884 src_width = wl_fixed_to_double(vp->buffer.src_width);
2885 src_height = wl_fixed_to_double(vp->buffer.src_height);
2886 }
2887
2888 if (vp->surface.width == -1) {
2889 dest_width = src_width;
2890 dest_height = src_height;
2891 } else {
2892 dest_width = vp->surface.width;
2893 dest_height = vp->surface.height;
2894 }
2895
2896 if (src_width != dest_width || src_height != dest_height)
2897 weston_matrix_scale(matrix,
2898 src_width / dest_width,
2899 src_height / dest_height, 1);
2900
2901 if (vp->buffer.src_width != wl_fixed_from_int(-1))
2902 weston_matrix_translate(matrix,
2903 wl_fixed_to_double(vp->buffer.src_x),
2904 wl_fixed_to_double(vp->buffer.src_y),
2905 0);
2906
2907 switch (vp->buffer.transform) {
2908 case WL_OUTPUT_TRANSFORM_FLIPPED:
2909 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
2910 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
2911 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
2912 weston_matrix_scale(matrix, -1, 1, 1);
2913 weston_matrix_translate(matrix,
2914 surface->width_from_buffer, 0, 0);
2915 break;
2916 }
2917
2918 switch (vp->buffer.transform) {
2919 default:
2920 case WL_OUTPUT_TRANSFORM_NORMAL:
2921 case WL_OUTPUT_TRANSFORM_FLIPPED:
2922 break;
2923 case WL_OUTPUT_TRANSFORM_90:
2924 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
2925 weston_matrix_rotate_xy(matrix, 0, 1);
2926 weston_matrix_translate(matrix,
2927 surface->height_from_buffer, 0, 0);
2928 break;
2929 case WL_OUTPUT_TRANSFORM_180:
2930 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
2931 weston_matrix_rotate_xy(matrix, -1, 0);
2932 weston_matrix_translate(matrix,
2933 surface->width_from_buffer,
2934 surface->height_from_buffer, 0);
2935 break;
2936 case WL_OUTPUT_TRANSFORM_270:
2937 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
2938 weston_matrix_rotate_xy(matrix, 0, -1);
2939 weston_matrix_translate(matrix,
2940 0, surface->width_from_buffer, 0);
2941 break;
2942 }
2943
2944 weston_matrix_scale(matrix, vp->buffer.scale, vp->buffer.scale, 1);
2945}
2946
Pekka Paalanend9aae9c2016-04-26 13:46:38 +03002947/**
2948 * Compute a + b > c while being safe to overflows.
2949 */
2950static bool
2951fixed_sum_gt(wl_fixed_t a, wl_fixed_t b, wl_fixed_t c)
2952{
2953 return (int64_t)a + (int64_t)b > (int64_t)c;
2954}
2955
2956static bool
2957weston_surface_is_pending_viewport_source_valid(
2958 const struct weston_surface *surface)
2959{
2960 const struct weston_surface_state *pend = &surface->pending;
2961 const struct weston_buffer_viewport *vp = &pend->buffer_viewport;
2962 int width_from_buffer = 0;
2963 int height_from_buffer = 0;
2964 wl_fixed_t w;
2965 wl_fixed_t h;
2966
2967 /* If viewport source rect is not set, it is always ok. */
2968 if (vp->buffer.src_width == wl_fixed_from_int(-1))
2969 return true;
2970
2971 if (pend->newly_attached) {
2972 if (pend->buffer) {
2973 convert_size_by_transform_scale(&width_from_buffer,
2974 &height_from_buffer,
2975 pend->buffer->width,
2976 pend->buffer->height,
2977 vp->buffer.transform,
2978 vp->buffer.scale);
2979 } else {
2980 /* No buffer: viewport is irrelevant. */
2981 return true;
2982 }
2983 } else {
2984 width_from_buffer = surface->width_from_buffer;
2985 height_from_buffer = surface->height_from_buffer;
2986 }
2987
2988 assert((width_from_buffer == 0) == (height_from_buffer == 0));
2989 assert(width_from_buffer >= 0 && height_from_buffer >= 0);
2990
2991 /* No buffer: viewport is irrelevant. */
2992 if (width_from_buffer == 0 || height_from_buffer == 0)
2993 return true;
2994
2995 /* overflow checks for wl_fixed_from_int() */
2996 if (width_from_buffer > wl_fixed_to_int(INT32_MAX))
2997 return false;
2998 if (height_from_buffer > wl_fixed_to_int(INT32_MAX))
2999 return false;
3000
3001 w = wl_fixed_from_int(width_from_buffer);
3002 h = wl_fixed_from_int(height_from_buffer);
3003
3004 if (fixed_sum_gt(vp->buffer.src_x, vp->buffer.src_width, w))
3005 return false;
3006 if (fixed_sum_gt(vp->buffer.src_y, vp->buffer.src_height, h))
3007 return false;
3008
3009 return true;
3010}
3011
Pekka Paalanenbb32ccc2016-04-26 14:28:28 +03003012static bool
3013fixed_is_integer(wl_fixed_t v)
3014{
3015 return (v & 0xff) == 0;
3016}
3017
3018static bool
3019weston_surface_is_pending_viewport_dst_size_int(
3020 const struct weston_surface *surface)
3021{
3022 const struct weston_buffer_viewport *vp =
3023 &surface->pending.buffer_viewport;
3024
3025 if (vp->surface.width != -1) {
3026 assert(vp->surface.width > 0 && vp->surface.height > 0);
3027 return true;
3028 }
3029
3030 return fixed_is_integer(vp->buffer.src_width) &&
3031 fixed_is_integer(vp->buffer.src_height);
3032}
3033
Derek Foreman152254b2015-11-26 14:17:48 -06003034/* Translate pending damage in buffer co-ordinates to surface
3035 * co-ordinates and union it with a pixman_region32_t.
3036 * This should only be called after the buffer is attached.
3037 */
3038static void
3039apply_damage_buffer(pixman_region32_t *dest,
3040 struct weston_surface *surface,
3041 struct weston_surface_state *state)
3042{
3043 struct weston_buffer *buffer = surface->buffer_ref.buffer;
3044
3045 /* wl_surface.damage_buffer needs to be clipped to the buffer,
3046 * translated into surface co-ordinates and unioned with
3047 * any other surface damage.
3048 * None of this makes sense if there is no buffer though.
3049 */
3050 if (buffer && pixman_region32_not_empty(&state->damage_buffer)) {
3051 pixman_region32_t buffer_damage;
3052
3053 pixman_region32_intersect_rect(&state->damage_buffer,
3054 &state->damage_buffer,
3055 0, 0, buffer->width,
3056 buffer->height);
3057 pixman_region32_init(&buffer_damage);
3058 weston_matrix_transform_region(&buffer_damage,
3059 &surface->buffer_to_surface_matrix,
3060 &state->damage_buffer);
3061 pixman_region32_union(dest, dest, &buffer_damage);
3062 pixman_region32_fini(&buffer_damage);
3063 }
3064 /* We should clear this on commit even if there was no buffer */
3065 pixman_region32_clear(&state->damage_buffer);
3066}
3067
Jason Ekstrand1e059042014-10-16 10:55:19 -05003068static void
Jason Ekstrand7b982072014-05-20 14:33:03 -05003069weston_surface_commit_state(struct weston_surface *surface,
3070 struct weston_surface_state *state)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003071{
Jason Ekstranda7af7042013-10-12 22:38:11 -05003072 struct weston_view *view;
Ander Conselvan de Oliveira5df8eca2012-10-30 17:44:01 +02003073 pixman_region32_t opaque;
3074
Alexander Larsson4ea95522013-05-22 14:41:37 +02003075 /* wl_surface.set_buffer_transform */
Alexander Larsson4ea95522013-05-22 14:41:37 +02003076 /* wl_surface.set_buffer_scale */
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03003077 /* wp_viewport.set_source */
3078 /* wp_viewport.set_destination */
Jason Ekstrand7b982072014-05-20 14:33:03 -05003079 surface->buffer_viewport = state->buffer_viewport;
Alexander Larsson4ea95522013-05-22 14:41:37 +02003080
Pekka Paalanen5df44de2012-10-10 12:49:23 +03003081 /* wl_surface.attach */
Jason Ekstrand7b982072014-05-20 14:33:03 -05003082 if (state->newly_attached)
3083 weston_surface_attach(surface, state->buffer);
3084 weston_surface_state_set_buffer(state, NULL);
Giulio Camuffo184df502013-02-21 11:29:21 +01003085
Jason Ekstrand1e059042014-10-16 10:55:19 -05003086 weston_surface_build_buffer_matrix(surface,
3087 &surface->surface_to_buffer_matrix);
3088 weston_matrix_invert(&surface->buffer_to_surface_matrix,
3089 &surface->surface_to_buffer_matrix);
3090
Jason Ekstrand7b982072014-05-20 14:33:03 -05003091 if (state->newly_attached || state->buffer_viewport.changed) {
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003092 weston_surface_update_size(surface);
Quentin Glidic2edc3d52016-08-12 10:41:33 +02003093 if (surface->committed)
3094 surface->committed(surface, state->sx, state->sy);
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003095 }
Giulio Camuffo184df502013-02-21 11:29:21 +01003096
Jason Ekstrand7b982072014-05-20 14:33:03 -05003097 state->sx = 0;
3098 state->sy = 0;
3099 state->newly_attached = 0;
3100 state->buffer_viewport.changed = 0;
Pekka Paalanen8e159182012-10-10 12:49:25 +03003101
Derek Foreman152254b2015-11-26 14:17:48 -06003102 /* wl_surface.damage and wl_surface.damage_buffer */
Pekka Paalanenb5026542014-11-12 15:09:24 +02003103 if (weston_timeline_enabled_ &&
Derek Foreman152254b2015-11-26 14:17:48 -06003104 (pixman_region32_not_empty(&state->damage_surface) ||
3105 pixman_region32_not_empty(&state->damage_buffer)))
Pekka Paalanenb5026542014-11-12 15:09:24 +02003106 TL_POINT("core_commit_damage", TLP_SURFACE(surface), TLP_END);
Derek Foreman152254b2015-11-26 14:17:48 -06003107
Pekka Paalanen8e159182012-10-10 12:49:25 +03003108 pixman_region32_union(&surface->damage, &surface->damage,
Derek Foreman152254b2015-11-26 14:17:48 -06003109 &state->damage_surface);
3110
3111 apply_damage_buffer(&surface->damage, surface, state);
3112
Kristian Høgsberg4d0214c2012-11-08 11:36:02 -05003113 pixman_region32_intersect_rect(&surface->damage, &surface->damage,
Jason Ekstrandef540082014-06-26 10:37:36 -07003114 0, 0, surface->width, surface->height);
Derek Foreman152254b2015-11-26 14:17:48 -06003115 pixman_region32_clear(&state->damage_surface);
Pekka Paalanen512dde82012-10-10 12:49:27 +03003116
3117 /* wl_surface.set_opaque_region */
Jason Ekstrand7b982072014-05-20 14:33:03 -05003118 pixman_region32_init(&opaque);
3119 pixman_region32_intersect_rect(&opaque, &state->opaque,
3120 0, 0, surface->width, surface->height);
Ander Conselvan de Oliveira5df8eca2012-10-30 17:44:01 +02003121
3122 if (!pixman_region32_equal(&opaque, &surface->opaque)) {
3123 pixman_region32_copy(&surface->opaque, &opaque);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003124 wl_list_for_each(view, &surface->views, surface_link)
3125 weston_view_geometry_dirty(view);
Ander Conselvan de Oliveira5df8eca2012-10-30 17:44:01 +02003126 }
3127
3128 pixman_region32_fini(&opaque);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03003129
3130 /* wl_surface.set_input_region */
Jason Ekstrand7b982072014-05-20 14:33:03 -05003131 pixman_region32_intersect_rect(&surface->input, &state->input,
3132 0, 0, surface->width, surface->height);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03003133
Pekka Paalanenbc106382012-10-10 12:49:31 +03003134 /* wl_surface.frame */
3135 wl_list_insert_list(&surface->frame_callback_list,
Jason Ekstrand7b982072014-05-20 14:33:03 -05003136 &state->frame_callback_list);
3137 wl_list_init(&state->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -04003138
3139 /* XXX:
3140 * What should happen with a feedback request, if there
3141 * is no wl_buffer attached for this commit?
3142 */
3143
3144 /* presentation.feedback */
3145 wl_list_insert_list(&surface->feedback_list,
3146 &state->feedback_list);
3147 wl_list_init(&state->feedback_list);
Jonas Ådahl5d9ca272016-07-22 17:48:03 +08003148
3149 wl_signal_emit(&surface->commit_signal, surface);
Jason Ekstrand7b982072014-05-20 14:33:03 -05003150}
3151
3152static void
3153weston_surface_commit(struct weston_surface *surface)
3154{
3155 weston_surface_commit_state(surface, &surface->pending);
Pekka Paalanenbc106382012-10-10 12:49:31 +03003156
Pekka Paalanene67858b2013-04-25 13:57:42 +03003157 weston_surface_commit_subsurface_order(surface);
3158
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03003159 weston_surface_schedule_repaint(surface);
Pekka Paalanen5df44de2012-10-10 12:49:23 +03003160}
3161
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003162static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03003163weston_subsurface_commit(struct weston_subsurface *sub);
3164
3165static void
3166weston_subsurface_parent_commit(struct weston_subsurface *sub,
3167 int parent_is_synchronized);
3168
3169static void
3170surface_commit(struct wl_client *client, struct wl_resource *resource)
3171{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003172 struct weston_surface *surface = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003173 struct weston_subsurface *sub = weston_surface_to_subsurface(surface);
3174
Pekka Paalanend9aae9c2016-04-26 13:46:38 +03003175 if (!weston_surface_is_pending_viewport_source_valid(surface)) {
3176 assert(surface->viewport_resource);
3177
3178 wl_resource_post_error(surface->viewport_resource,
3179 WP_VIEWPORT_ERROR_OUT_OF_BUFFER,
3180 "wl_surface@%d has viewport source outside buffer",
3181 wl_resource_get_id(resource));
3182 return;
3183 }
3184
Pekka Paalanenbb32ccc2016-04-26 14:28:28 +03003185 if (!weston_surface_is_pending_viewport_dst_size_int(surface)) {
3186 assert(surface->viewport_resource);
3187
3188 wl_resource_post_error(surface->viewport_resource,
3189 WP_VIEWPORT_ERROR_BAD_SIZE,
3190 "wl_surface@%d viewport dst size not integer",
3191 wl_resource_get_id(resource));
3192 return;
3193 }
3194
Pekka Paalanene67858b2013-04-25 13:57:42 +03003195 if (sub) {
3196 weston_subsurface_commit(sub);
3197 return;
3198 }
3199
3200 weston_surface_commit(surface);
3201
3202 wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
3203 if (sub->surface != surface)
3204 weston_subsurface_parent_commit(sub, 0);
3205 }
3206}
3207
3208static void
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003209surface_set_buffer_transform(struct wl_client *client,
3210 struct wl_resource *resource, int transform)
3211{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003212 struct weston_surface *surface = wl_resource_get_user_data(resource);
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003213
Jonny Lamba55f1392014-05-30 12:07:15 +02003214 /* if wl_output.transform grows more members this will need to be updated. */
3215 if (transform < 0 ||
3216 transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) {
3217 wl_resource_post_error(resource,
3218 WL_SURFACE_ERROR_INVALID_TRANSFORM,
3219 "buffer transform must be a valid transform "
3220 "('%d' specified)", transform);
3221 return;
3222 }
3223
Pekka Paalanen952b6c82014-03-14 14:38:15 +02003224 surface->pending.buffer_viewport.buffer.transform = transform;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003225 surface->pending.buffer_viewport.changed = 1;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003226}
3227
Alexander Larsson4ea95522013-05-22 14:41:37 +02003228static void
3229surface_set_buffer_scale(struct wl_client *client,
3230 struct wl_resource *resource,
Alexander Larssonedddbd12013-05-24 13:09:43 +02003231 int32_t scale)
Alexander Larsson4ea95522013-05-22 14:41:37 +02003232{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003233 struct weston_surface *surface = wl_resource_get_user_data(resource);
Alexander Larsson4ea95522013-05-22 14:41:37 +02003234
Jonny Lamba55f1392014-05-30 12:07:15 +02003235 if (scale < 1) {
3236 wl_resource_post_error(resource,
3237 WL_SURFACE_ERROR_INVALID_SCALE,
3238 "buffer scale must be at least one "
3239 "('%d' specified)", scale);
3240 return;
3241 }
3242
Pekka Paalanen952b6c82014-03-14 14:38:15 +02003243 surface->pending.buffer_viewport.buffer.scale = scale;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003244 surface->pending.buffer_viewport.changed = 1;
Alexander Larsson4ea95522013-05-22 14:41:37 +02003245}
3246
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04003247static const struct wl_surface_interface surface_interface = {
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003248 surface_destroy,
3249 surface_attach,
Kristian Høgsberg33418202011-08-16 23:01:28 -04003250 surface_damage,
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003251 surface_frame,
3252 surface_set_opaque_region,
Pekka Paalanen5df44de2012-10-10 12:49:23 +03003253 surface_set_input_region,
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003254 surface_commit,
Alexander Larsson4ea95522013-05-22 14:41:37 +02003255 surface_set_buffer_transform,
Derek Foreman152254b2015-11-26 14:17:48 -06003256 surface_set_buffer_scale,
3257 surface_damage_buffer
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003258};
3259
3260static void
3261compositor_create_surface(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -04003262 struct wl_resource *resource, uint32_t id)
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003263{
Kristian Høgsbergc2d70422013-06-25 15:34:33 -04003264 struct weston_compositor *ec = wl_resource_get_user_data(resource);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003265 struct weston_surface *surface;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003266
Kristian Høgsberg18c93002012-01-27 11:58:31 -05003267 surface = weston_surface_create(ec);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04003268 if (surface == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -04003269 wl_resource_post_no_memory(resource);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003270 return;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04003271 }
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003272
Jason Ekstranda85118c2013-06-27 20:17:02 -05003273 surface->resource =
3274 wl_resource_create(client, &wl_surface_interface,
3275 wl_resource_get_version(resource), id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07003276 if (surface->resource == NULL) {
3277 weston_surface_destroy(surface);
3278 wl_resource_post_no_memory(resource);
3279 return;
3280 }
Jason Ekstranda85118c2013-06-27 20:17:02 -05003281 wl_resource_set_implementation(surface->resource, &surface_interface,
3282 surface, destroy_surface);
Kristian Høgsbergf03a04a2014-04-06 22:04:50 -07003283
3284 wl_signal_emit(&ec->create_surface_signal, surface);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003285}
3286
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003287static void
3288destroy_region(struct wl_resource *resource)
3289{
Jason Ekstrand8895efc2013-06-14 10:07:56 -05003290 struct weston_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003291
3292 pixman_region32_fini(&region->region);
3293 free(region);
3294}
3295
3296static void
3297region_destroy(struct wl_client *client, struct wl_resource *resource)
3298{
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003299 wl_resource_destroy(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003300}
3301
3302static void
3303region_add(struct wl_client *client, struct wl_resource *resource,
3304 int32_t x, int32_t y, int32_t width, int32_t height)
3305{
Jason Ekstrand8895efc2013-06-14 10:07:56 -05003306 struct weston_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003307
3308 pixman_region32_union_rect(&region->region, &region->region,
3309 x, y, width, height);
3310}
3311
3312static void
3313region_subtract(struct wl_client *client, struct wl_resource *resource,
3314 int32_t x, int32_t y, int32_t width, int32_t height)
3315{
Jason Ekstrand8895efc2013-06-14 10:07:56 -05003316 struct weston_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003317 pixman_region32_t rect;
3318
3319 pixman_region32_init_rect(&rect, x, y, width, height);
3320 pixman_region32_subtract(&region->region, &region->region, &rect);
3321 pixman_region32_fini(&rect);
3322}
3323
3324static const struct wl_region_interface region_interface = {
3325 region_destroy,
3326 region_add,
3327 region_subtract
3328};
3329
3330static void
3331compositor_create_region(struct wl_client *client,
3332 struct wl_resource *resource, uint32_t id)
3333{
3334 struct weston_region *region;
3335
3336 region = malloc(sizeof *region);
3337 if (region == NULL) {
3338 wl_resource_post_no_memory(resource);
3339 return;
3340 }
3341
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003342 pixman_region32_init(&region->region);
3343
Jason Ekstranda85118c2013-06-27 20:17:02 -05003344 region->resource =
3345 wl_resource_create(client, &wl_region_interface, 1, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07003346 if (region->resource == NULL) {
3347 free(region);
3348 wl_resource_post_no_memory(resource);
3349 return;
3350 }
Jason Ekstranda85118c2013-06-27 20:17:02 -05003351 wl_resource_set_implementation(region->resource, &region_interface,
3352 region, destroy_region);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003353}
3354
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04003355static const struct wl_compositor_interface compositor_interface = {
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003356 compositor_create_surface,
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003357 compositor_create_region
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003358};
3359
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003360static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03003361weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
3362{
3363 struct weston_surface *surface = sub->surface;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003364
Jason Ekstrand7b982072014-05-20 14:33:03 -05003365 weston_surface_commit_state(surface, &sub->cached);
3366 weston_buffer_reference(&sub->cached_buffer_ref, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003367
3368 weston_surface_commit_subsurface_order(surface);
3369
3370 weston_surface_schedule_repaint(surface);
3371
Jason Ekstrand7b982072014-05-20 14:33:03 -05003372 sub->has_cached_data = 0;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003373}
3374
3375static void
3376weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
3377{
3378 struct weston_surface *surface = sub->surface;
3379
3380 /*
3381 * If this commit would cause the surface to move by the
3382 * attach(dx, dy) parameters, the old damage region must be
3383 * translated to correspond to the new surface coordinate system
Chris Michael062edf22015-11-26 11:30:00 -05003384 * origin.
Pekka Paalanene67858b2013-04-25 13:57:42 +03003385 */
Derek Foreman152254b2015-11-26 14:17:48 -06003386 pixman_region32_translate(&sub->cached.damage_surface,
Pekka Paalanene67858b2013-04-25 13:57:42 +03003387 -surface->pending.sx, -surface->pending.sy);
Derek Foreman152254b2015-11-26 14:17:48 -06003388 pixman_region32_union(&sub->cached.damage_surface,
3389 &sub->cached.damage_surface,
3390 &surface->pending.damage_surface);
3391 pixman_region32_clear(&surface->pending.damage_surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003392
3393 if (surface->pending.newly_attached) {
3394 sub->cached.newly_attached = 1;
Jason Ekstrand7b982072014-05-20 14:33:03 -05003395 weston_surface_state_set_buffer(&sub->cached,
3396 surface->pending.buffer);
3397 weston_buffer_reference(&sub->cached_buffer_ref,
Pekka Paalanene67858b2013-04-25 13:57:42 +03003398 surface->pending.buffer);
Pekka Paalanen133e4392014-09-23 22:08:46 -04003399 weston_presentation_feedback_discard_list(
3400 &sub->cached.feedback_list);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003401 }
3402 sub->cached.sx += surface->pending.sx;
3403 sub->cached.sy += surface->pending.sy;
Pekka Paalanen260ba382014-03-14 14:38:12 +02003404
Derek Foreman152254b2015-11-26 14:17:48 -06003405 apply_damage_buffer(&sub->cached.damage_surface, surface, &surface->pending);
3406
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003407 sub->cached.buffer_viewport.changed |=
3408 surface->pending.buffer_viewport.changed;
3409 sub->cached.buffer_viewport.buffer =
3410 surface->pending.buffer_viewport.buffer;
3411 sub->cached.buffer_viewport.surface =
3412 surface->pending.buffer_viewport.surface;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003413
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003414 weston_surface_reset_pending_buffer(surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003415
3416 pixman_region32_copy(&sub->cached.opaque, &surface->pending.opaque);
3417
3418 pixman_region32_copy(&sub->cached.input, &surface->pending.input);
3419
3420 wl_list_insert_list(&sub->cached.frame_callback_list,
3421 &surface->pending.frame_callback_list);
3422 wl_list_init(&surface->pending.frame_callback_list);
3423
Pekka Paalanen133e4392014-09-23 22:08:46 -04003424 wl_list_insert_list(&sub->cached.feedback_list,
3425 &surface->pending.feedback_list);
3426 wl_list_init(&surface->pending.feedback_list);
3427
Jason Ekstrand7b982072014-05-20 14:33:03 -05003428 sub->has_cached_data = 1;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003429}
3430
Derek Foreman280e7dd2014-10-03 13:13:42 -05003431static bool
Pekka Paalanene67858b2013-04-25 13:57:42 +03003432weston_subsurface_is_synchronized(struct weston_subsurface *sub)
3433{
3434 while (sub) {
3435 if (sub->synchronized)
Derek Foreman280e7dd2014-10-03 13:13:42 -05003436 return true;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003437
3438 if (!sub->parent)
Derek Foreman280e7dd2014-10-03 13:13:42 -05003439 return false;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003440
3441 sub = weston_surface_to_subsurface(sub->parent);
3442 }
3443
Carlos Olmedo Escobar61a9bf52014-11-04 14:38:39 +01003444 return false;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003445}
3446
3447static void
3448weston_subsurface_commit(struct weston_subsurface *sub)
3449{
3450 struct weston_surface *surface = sub->surface;
3451 struct weston_subsurface *tmp;
3452
3453 /* Recursive check for effectively synchronized. */
3454 if (weston_subsurface_is_synchronized(sub)) {
3455 weston_subsurface_commit_to_cache(sub);
3456 } else {
Jason Ekstrand7b982072014-05-20 14:33:03 -05003457 if (sub->has_cached_data) {
Pekka Paalanene67858b2013-04-25 13:57:42 +03003458 /* flush accumulated state from cache */
3459 weston_subsurface_commit_to_cache(sub);
3460 weston_subsurface_commit_from_cache(sub);
3461 } else {
3462 weston_surface_commit(surface);
3463 }
3464
3465 wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
3466 if (tmp->surface != surface)
3467 weston_subsurface_parent_commit(tmp, 0);
3468 }
3469 }
3470}
3471
3472static void
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003473weston_subsurface_synchronized_commit(struct weston_subsurface *sub)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003474{
3475 struct weston_surface *surface = sub->surface;
3476 struct weston_subsurface *tmp;
3477
Pekka Paalanene67858b2013-04-25 13:57:42 +03003478 /* From now on, commit_from_cache the whole sub-tree, regardless of
3479 * the synchronized mode of each child. This sub-surface or some
3480 * of its ancestors were synchronized, so we are synchronized
3481 * all the way down.
3482 */
3483
Jason Ekstrand7b982072014-05-20 14:33:03 -05003484 if (sub->has_cached_data)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003485 weston_subsurface_commit_from_cache(sub);
3486
3487 wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
3488 if (tmp->surface != surface)
3489 weston_subsurface_parent_commit(tmp, 1);
3490 }
3491}
3492
3493static void
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003494weston_subsurface_parent_commit(struct weston_subsurface *sub,
3495 int parent_is_synchronized)
3496{
Jason Ekstranda7af7042013-10-12 22:38:11 -05003497 struct weston_view *view;
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003498 if (sub->position.set) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05003499 wl_list_for_each(view, &sub->surface->views, surface_link)
3500 weston_view_set_position(view,
3501 sub->position.x,
3502 sub->position.y);
3503
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003504 sub->position.set = 0;
3505 }
3506
3507 if (parent_is_synchronized || sub->synchronized)
3508 weston_subsurface_synchronized_commit(sub);
3509}
3510
Pekka Paalanen8274d902014-08-06 19:36:51 +03003511static int
3512subsurface_get_label(struct weston_surface *surface, char *buf, size_t len)
3513{
3514 return snprintf(buf, len, "sub-surface");
3515}
3516
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003517static void
Quentin Glidic2edc3d52016-08-12 10:41:33 +02003518subsurface_committed(struct weston_surface *surface, int32_t dx, int32_t dy)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003519{
Jason Ekstranda7af7042013-10-12 22:38:11 -05003520 struct weston_view *view;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003521
Jason Ekstranda7af7042013-10-12 22:38:11 -05003522 wl_list_for_each(view, &surface->views, surface_link)
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003523 weston_view_set_position(view,
3524 view->geometry.x + dx,
3525 view->geometry.y + dy);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003526
3527 /* No need to check parent mappedness, because if parent is not
3528 * mapped, parent is not in a visible layer, so this sub-surface
3529 * will not be drawn either.
3530 */
Armin Krezovićf8486c32016-06-30 06:04:28 +02003531
Pekka Paalanene67858b2013-04-25 13:57:42 +03003532 if (!weston_surface_is_mapped(surface)) {
Armin Krezovićf8486c32016-06-30 06:04:28 +02003533 surface->is_mapped = true;
Pekka Paalaneneb3cf222014-06-30 11:52:07 +03003534
Derek Foreman4b1a0a12014-09-10 15:37:33 -05003535 /* Cannot call weston_view_update_transform(),
Pekka Paalanene67858b2013-04-25 13:57:42 +03003536 * because that would call it also for the parent surface,
3537 * which might not be mapped yet. That would lead to
3538 * inconsistent state, where the window could never be
3539 * mapped.
3540 *
Armin Krezovićf8486c32016-06-30 06:04:28 +02003541 * Instead just force the is_mapped flag on, to make
Pekka Paalanene67858b2013-04-25 13:57:42 +03003542 * weston_surface_is_mapped() return true, so that when the
3543 * parent surface does get mapped, this one will get
Pekka Paalaneneb3cf222014-06-30 11:52:07 +03003544 * included, too. See view_list_add().
Pekka Paalanene67858b2013-04-25 13:57:42 +03003545 */
Pekka Paalanene67858b2013-04-25 13:57:42 +03003546 }
3547}
3548
3549static struct weston_subsurface *
3550weston_surface_to_subsurface(struct weston_surface *surface)
3551{
Quentin Glidic2edc3d52016-08-12 10:41:33 +02003552 if (surface->committed == subsurface_committed)
3553 return surface->committed_private;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003554
3555 return NULL;
3556}
3557
Pekka Paalanen01388e22013-04-25 13:57:44 +03003558WL_EXPORT struct weston_surface *
3559weston_surface_get_main_surface(struct weston_surface *surface)
3560{
3561 struct weston_subsurface *sub;
3562
3563 while (surface && (sub = weston_surface_to_subsurface(surface)))
3564 surface = sub->parent;
3565
3566 return surface;
3567}
3568
Pekka Paalanen50b67472014-10-01 15:02:41 +03003569WL_EXPORT int
3570weston_surface_set_role(struct weston_surface *surface,
3571 const char *role_name,
3572 struct wl_resource *error_resource,
3573 uint32_t error_code)
3574{
3575 assert(role_name);
3576
3577 if (surface->role_name == NULL ||
3578 surface->role_name == role_name ||
3579 strcmp(surface->role_name, role_name) == 0) {
3580 surface->role_name = role_name;
3581
3582 return 0;
3583 }
3584
3585 wl_resource_post_error(error_resource, error_code,
3586 "Cannot assign role %s to wl_surface@%d,"
3587 " already has role %s\n",
3588 role_name,
3589 wl_resource_get_id(surface->resource),
3590 surface->role_name);
3591 return -1;
3592}
3593
Quentin Glidic9c5dd7e2016-08-12 10:41:37 +02003594WL_EXPORT const char *
3595weston_surface_get_role(struct weston_surface *surface)
3596{
3597 return surface->role_name;
3598}
3599
Pekka Paalanen8274d902014-08-06 19:36:51 +03003600WL_EXPORT void
3601weston_surface_set_label_func(struct weston_surface *surface,
3602 int (*desc)(struct weston_surface *,
3603 char *, size_t))
3604{
3605 surface->get_label = desc;
Pekka Paalanenb5026542014-11-12 15:09:24 +02003606 surface->timeline.force_refresh = 1;
Pekka Paalanen8274d902014-08-06 19:36:51 +03003607}
3608
Pekka Paalanenc647ed72015-02-09 13:16:57 +02003609/** Get the size of surface contents
3610 *
3611 * \param surface The surface to query.
3612 * \param width Returns the width of raw contents.
3613 * \param height Returns the height of raw contents.
3614 *
3615 * Retrieves the raw surface content size in pixels for the given surface.
3616 * This is the whole content size in buffer pixels. If the surface
3617 * has no content or the renderer does not implement this feature,
3618 * zeroes are returned.
3619 *
3620 * This function is used to determine the buffer size needed for
3621 * a weston_surface_copy_content() call.
3622 */
3623WL_EXPORT void
3624weston_surface_get_content_size(struct weston_surface *surface,
3625 int *width, int *height)
3626{
3627 struct weston_renderer *rer = surface->compositor->renderer;
3628
3629 if (!rer->surface_get_content_size) {
3630 *width = 0;
3631 *height = 0;
3632 return;
3633 }
3634
3635 rer->surface_get_content_size(surface, width, height);
3636}
3637
Quentin Glidic248dd102016-08-12 10:41:34 +02003638/** Get the bounding box of a surface and its subsurfaces
3639 *
3640 * \param surface The surface to query.
3641 * \return The bounding box relative to the surface origin.
3642 *
3643 */
3644WL_EXPORT struct weston_geometry
3645weston_surface_get_bounding_box(struct weston_surface *surface)
3646{
3647 pixman_region32_t region;
3648 pixman_box32_t *box;
3649 struct weston_subsurface *subsurface;
3650
3651 pixman_region32_init_rect(&region,
3652 0, 0,
3653 surface->width, surface->height);
3654
3655 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link)
3656 pixman_region32_union_rect(&region, &region,
3657 subsurface->position.x,
3658 subsurface->position.y,
3659 subsurface->surface->width,
3660 subsurface->surface->height);
3661
3662 box = pixman_region32_extents(&region);
3663 struct weston_geometry geometry = {
3664 .x = box->x1,
3665 .y = box->y1,
3666 .width = box->x2 - box->x1,
3667 .height = box->y2 - box->y1,
3668 };
3669
3670 pixman_region32_fini(&region);
3671
3672 return geometry;
3673}
3674
Pekka Paalanenc647ed72015-02-09 13:16:57 +02003675/** Copy surface contents to system memory.
3676 *
3677 * \param surface The surface to copy from.
3678 * \param target Pointer to the target memory buffer.
3679 * \param size Size of the target buffer in bytes.
3680 * \param src_x X location on contents to copy from.
3681 * \param src_y Y location on contents to copy from.
3682 * \param width Width in pixels of the area to copy.
3683 * \param height Height in pixels of the area to copy.
3684 * \return 0 for success, -1 for failure.
3685 *
3686 * Surface contents are maintained by the renderer. They can be in a
3687 * reserved weston_buffer or as a copy, e.g. a GL texture, or something
3688 * else.
3689 *
3690 * Surface contents are copied into memory pointed to by target,
3691 * which has size bytes of space available. The target memory
3692 * may be larger than needed, but being smaller returns an error.
3693 * The extra bytes in target may or may not be written; their content is
3694 * unspecified. Size must be large enough to hold the image.
3695 *
3696 * The image in the target memory will be arranged in rows from
3697 * top to bottom, and pixels on a row from left to right. The pixel
3698 * format is PIXMAN_a8b8g8r8, 4 bytes per pixel, and stride is exactly
3699 * width * 4.
3700 *
3701 * Parameters src_x and src_y define the upper-left corner in buffer
3702 * coordinates (pixels) to copy from. Parameters width and height
3703 * define the size of the area to copy in pixels.
3704 *
3705 * The rectangle defined by src_x, src_y, width, height must fit in
3706 * the surface contents. Otherwise an error is returned.
3707 *
3708 * Use surface_get_data_size to determine the content size; the
3709 * needed target buffer size and rectangle limits.
3710 *
3711 * CURRENT IMPLEMENTATION RESTRICTIONS:
3712 * - the machine must be little-endian due to Pixman formats.
3713 *
3714 * NOTE: Pixman formats are premultiplied.
3715 */
3716WL_EXPORT int
3717weston_surface_copy_content(struct weston_surface *surface,
3718 void *target, size_t size,
3719 int src_x, int src_y,
3720 int width, int height)
3721{
3722 struct weston_renderer *rer = surface->compositor->renderer;
3723 int cw, ch;
3724 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
3725
3726 if (!rer->surface_copy_content)
3727 return -1;
3728
3729 weston_surface_get_content_size(surface, &cw, &ch);
3730
3731 if (src_x < 0 || src_y < 0)
3732 return -1;
3733
3734 if (width <= 0 || height <= 0)
3735 return -1;
3736
3737 if (src_x + width > cw || src_y + height > ch)
3738 return -1;
3739
3740 if (width * bytespp * height > size)
3741 return -1;
3742
3743 return rer->surface_copy_content(surface, target, size,
3744 src_x, src_y, width, height);
3745}
3746
Pekka Paalanene67858b2013-04-25 13:57:42 +03003747static void
3748subsurface_set_position(struct wl_client *client,
3749 struct wl_resource *resource, int32_t x, int32_t y)
3750{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003751 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003752
3753 if (!sub)
3754 return;
3755
3756 sub->position.x = x;
3757 sub->position.y = y;
3758 sub->position.set = 1;
3759}
3760
3761static struct weston_subsurface *
Arnaud Vracb8c16c92016-06-08 18:37:57 +02003762subsurface_find_sibling(struct weston_subsurface *sub,
3763 struct weston_surface *surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003764{
Arnaud Vracb8c16c92016-06-08 18:37:57 +02003765 struct weston_surface *parent = sub->parent;
3766 struct weston_subsurface *sibling;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003767
Arnaud Vracb8c16c92016-06-08 18:37:57 +02003768 wl_list_for_each(sibling, &parent->subsurface_list, parent_link) {
3769 if (sibling->surface == surface && sibling != sub)
3770 return sibling;
3771 }
Pekka Paalanene67858b2013-04-25 13:57:42 +03003772
3773 return NULL;
3774}
3775
3776static struct weston_subsurface *
3777subsurface_sibling_check(struct weston_subsurface *sub,
3778 struct weston_surface *surface,
3779 const char *request)
3780{
3781 struct weston_subsurface *sibling;
3782
Arnaud Vracb8c16c92016-06-08 18:37:57 +02003783 sibling = subsurface_find_sibling(sub, surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003784 if (!sibling) {
3785 wl_resource_post_error(sub->resource,
3786 WL_SUBSURFACE_ERROR_BAD_SURFACE,
3787 "%s: wl_surface@%d is not a parent or sibling",
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003788 request, wl_resource_get_id(surface->resource));
Pekka Paalanene67858b2013-04-25 13:57:42 +03003789 return NULL;
3790 }
3791
Arnaud Vracb8c16c92016-06-08 18:37:57 +02003792 assert(sibling->parent == sub->parent);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003793
3794 return sibling;
3795}
3796
3797static void
3798subsurface_place_above(struct wl_client *client,
3799 struct wl_resource *resource,
3800 struct wl_resource *sibling_resource)
3801{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003802 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003803 struct weston_surface *surface =
3804 wl_resource_get_user_data(sibling_resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003805 struct weston_subsurface *sibling;
3806
3807 if (!sub)
3808 return;
3809
3810 sibling = subsurface_sibling_check(sub, surface, "place_above");
3811 if (!sibling)
3812 return;
3813
3814 wl_list_remove(&sub->parent_link_pending);
3815 wl_list_insert(sibling->parent_link_pending.prev,
3816 &sub->parent_link_pending);
Emilio Pozuelo Monfort4f3cad72017-01-27 17:30:29 +01003817
3818 sub->reordered = true;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003819}
3820
3821static void
3822subsurface_place_below(struct wl_client *client,
3823 struct wl_resource *resource,
3824 struct wl_resource *sibling_resource)
3825{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003826 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003827 struct weston_surface *surface =
3828 wl_resource_get_user_data(sibling_resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003829 struct weston_subsurface *sibling;
3830
3831 if (!sub)
3832 return;
3833
3834 sibling = subsurface_sibling_check(sub, surface, "place_below");
3835 if (!sibling)
3836 return;
3837
3838 wl_list_remove(&sub->parent_link_pending);
3839 wl_list_insert(&sibling->parent_link_pending,
3840 &sub->parent_link_pending);
Emilio Pozuelo Monfort4f3cad72017-01-27 17:30:29 +01003841
3842 sub->reordered = true;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003843}
3844
3845static void
3846subsurface_set_sync(struct wl_client *client, struct wl_resource *resource)
3847{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003848 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003849
3850 if (sub)
3851 sub->synchronized = 1;
3852}
3853
3854static void
3855subsurface_set_desync(struct wl_client *client, struct wl_resource *resource)
3856{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003857 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003858
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003859 if (sub && sub->synchronized) {
Pekka Paalanene67858b2013-04-25 13:57:42 +03003860 sub->synchronized = 0;
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003861
3862 /* If sub became effectively desynchronized, flush. */
3863 if (!weston_subsurface_is_synchronized(sub))
3864 weston_subsurface_synchronized_commit(sub);
3865 }
Pekka Paalanene67858b2013-04-25 13:57:42 +03003866}
3867
3868static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03003869weston_subsurface_unlink_parent(struct weston_subsurface *sub)
3870{
3871 wl_list_remove(&sub->parent_link);
3872 wl_list_remove(&sub->parent_link_pending);
3873 wl_list_remove(&sub->parent_destroy_listener.link);
3874 sub->parent = NULL;
3875}
3876
3877static void
3878weston_subsurface_destroy(struct weston_subsurface *sub);
3879
3880static void
3881subsurface_handle_surface_destroy(struct wl_listener *listener, void *data)
3882{
3883 struct weston_subsurface *sub =
3884 container_of(listener, struct weston_subsurface,
3885 surface_destroy_listener);
Pekka Paalanenca790762015-04-17 14:23:38 +03003886 assert(data == sub->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003887
3888 /* The protocol object (wl_resource) is left inert. */
3889 if (sub->resource)
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003890 wl_resource_set_user_data(sub->resource, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003891
3892 weston_subsurface_destroy(sub);
3893}
3894
3895static void
3896subsurface_handle_parent_destroy(struct wl_listener *listener, void *data)
3897{
3898 struct weston_subsurface *sub =
3899 container_of(listener, struct weston_subsurface,
3900 parent_destroy_listener);
Pekka Paalanenca790762015-04-17 14:23:38 +03003901 assert(data == sub->parent);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003902 assert(sub->surface != sub->parent);
3903
3904 if (weston_surface_is_mapped(sub->surface))
3905 weston_surface_unmap(sub->surface);
3906
3907 weston_subsurface_unlink_parent(sub);
3908}
3909
3910static void
3911subsurface_resource_destroy(struct wl_resource *resource)
3912{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003913 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003914
3915 if (sub)
3916 weston_subsurface_destroy(sub);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003917}
3918
3919static void
3920subsurface_destroy(struct wl_client *client, struct wl_resource *resource)
3921{
3922 wl_resource_destroy(resource);
3923}
3924
3925static void
3926weston_subsurface_link_parent(struct weston_subsurface *sub,
3927 struct weston_surface *parent)
3928{
3929 sub->parent = parent;
3930 sub->parent_destroy_listener.notify = subsurface_handle_parent_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003931 wl_signal_add(&parent->destroy_signal,
Pekka Paalanene67858b2013-04-25 13:57:42 +03003932 &sub->parent_destroy_listener);
3933
3934 wl_list_insert(&parent->subsurface_list, &sub->parent_link);
3935 wl_list_insert(&parent->subsurface_list_pending,
3936 &sub->parent_link_pending);
3937}
3938
3939static void
3940weston_subsurface_link_surface(struct weston_subsurface *sub,
3941 struct weston_surface *surface)
3942{
3943 sub->surface = surface;
3944 sub->surface_destroy_listener.notify =
3945 subsurface_handle_surface_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003946 wl_signal_add(&surface->destroy_signal,
Pekka Paalanene67858b2013-04-25 13:57:42 +03003947 &sub->surface_destroy_listener);
3948}
3949
3950static void
3951weston_subsurface_destroy(struct weston_subsurface *sub)
3952{
Jason Ekstranda7af7042013-10-12 22:38:11 -05003953 struct weston_view *view, *next;
3954
Pekka Paalanene67858b2013-04-25 13:57:42 +03003955 assert(sub->surface);
3956
3957 if (sub->resource) {
3958 assert(weston_surface_to_subsurface(sub->surface) == sub);
3959 assert(sub->parent_destroy_listener.notify ==
3960 subsurface_handle_parent_destroy);
3961
George Kiagiadakised04d382014-06-13 18:10:26 +02003962 wl_list_for_each_safe(view, next, &sub->surface->views, surface_link) {
3963 weston_view_unmap(view);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003964 weston_view_destroy(view);
George Kiagiadakised04d382014-06-13 18:10:26 +02003965 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05003966
Pekka Paalanene67858b2013-04-25 13:57:42 +03003967 if (sub->parent)
3968 weston_subsurface_unlink_parent(sub);
3969
Jason Ekstrand7b982072014-05-20 14:33:03 -05003970 weston_surface_state_fini(&sub->cached);
3971 weston_buffer_reference(&sub->cached_buffer_ref, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003972
Quentin Glidic2edc3d52016-08-12 10:41:33 +02003973 sub->surface->committed = NULL;
3974 sub->surface->committed_private = NULL;
Pekka Paalanen8274d902014-08-06 19:36:51 +03003975 weston_surface_set_label_func(sub->surface, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003976 } else {
3977 /* the dummy weston_subsurface for the parent itself */
3978 assert(sub->parent_destroy_listener.notify == NULL);
3979 wl_list_remove(&sub->parent_link);
3980 wl_list_remove(&sub->parent_link_pending);
3981 }
3982
3983 wl_list_remove(&sub->surface_destroy_listener.link);
3984 free(sub);
3985}
3986
3987static const struct wl_subsurface_interface subsurface_implementation = {
3988 subsurface_destroy,
3989 subsurface_set_position,
3990 subsurface_place_above,
3991 subsurface_place_below,
3992 subsurface_set_sync,
3993 subsurface_set_desync
3994};
3995
3996static struct weston_subsurface *
3997weston_subsurface_create(uint32_t id, struct weston_surface *surface,
3998 struct weston_surface *parent)
3999{
4000 struct weston_subsurface *sub;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05004001 struct wl_client *client = wl_resource_get_client(surface->resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004002
Bryce Harringtonde16d892014-11-20 22:21:57 -08004003 sub = zalloc(sizeof *sub);
4004 if (sub == NULL)
Pekka Paalanene67858b2013-04-25 13:57:42 +03004005 return NULL;
4006
Jason Ekstranda7af7042013-10-12 22:38:11 -05004007 wl_list_init(&sub->unused_views);
4008
Jason Ekstranda85118c2013-06-27 20:17:02 -05004009 sub->resource =
4010 wl_resource_create(client, &wl_subsurface_interface, 1, id);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004011 if (!sub->resource) {
4012 free(sub);
4013 return NULL;
4014 }
4015
Jason Ekstranda85118c2013-06-27 20:17:02 -05004016 wl_resource_set_implementation(sub->resource,
4017 &subsurface_implementation,
4018 sub, subsurface_resource_destroy);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004019 weston_subsurface_link_surface(sub, surface);
4020 weston_subsurface_link_parent(sub, parent);
Jason Ekstrand7b982072014-05-20 14:33:03 -05004021 weston_surface_state_init(&sub->cached);
4022 sub->cached_buffer_ref.buffer = NULL;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004023 sub->synchronized = 1;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004024
4025 return sub;
4026}
4027
4028/* Create a dummy subsurface for having the parent itself in its
4029 * sub-surface lists. Makes stacking order manipulation easy.
4030 */
4031static struct weston_subsurface *
4032weston_subsurface_create_for_parent(struct weston_surface *parent)
4033{
4034 struct weston_subsurface *sub;
4035
Bryce Harringtonde16d892014-11-20 22:21:57 -08004036 sub = zalloc(sizeof *sub);
4037 if (sub == NULL)
Pekka Paalanene67858b2013-04-25 13:57:42 +03004038 return NULL;
4039
4040 weston_subsurface_link_surface(sub, parent);
4041 sub->parent = parent;
4042 wl_list_insert(&parent->subsurface_list, &sub->parent_link);
4043 wl_list_insert(&parent->subsurface_list_pending,
4044 &sub->parent_link_pending);
4045
4046 return sub;
4047}
4048
4049static void
4050subcompositor_get_subsurface(struct wl_client *client,
4051 struct wl_resource *resource,
4052 uint32_t id,
4053 struct wl_resource *surface_resource,
4054 struct wl_resource *parent_resource)
4055{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05004056 struct weston_surface *surface =
4057 wl_resource_get_user_data(surface_resource);
4058 struct weston_surface *parent =
4059 wl_resource_get_user_data(parent_resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004060 struct weston_subsurface *sub;
4061 static const char where[] = "get_subsurface: wl_subsurface@";
4062
4063 if (surface == parent) {
4064 wl_resource_post_error(resource,
4065 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
4066 "%s%d: wl_surface@%d cannot be its own parent",
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004067 where, id, wl_resource_get_id(surface_resource));
Pekka Paalanene67858b2013-04-25 13:57:42 +03004068 return;
4069 }
4070
4071 if (weston_surface_to_subsurface(surface)) {
4072 wl_resource_post_error(resource,
4073 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
4074 "%s%d: wl_surface@%d is already a sub-surface",
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004075 where, id, wl_resource_get_id(surface_resource));
Pekka Paalanene67858b2013-04-25 13:57:42 +03004076 return;
4077 }
4078
Pekka Paalanen50b67472014-10-01 15:02:41 +03004079 if (weston_surface_set_role(surface, "wl_subsurface", resource,
4080 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE) < 0)
Pekka Paalanene67858b2013-04-25 13:57:42 +03004081 return;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004082
Pekka Paalanen86c8ca02013-05-17 16:46:07 +03004083 if (weston_surface_get_main_surface(parent) == surface) {
4084 wl_resource_post_error(resource,
4085 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
4086 "%s%d: wl_surface@%d is an ancestor of parent",
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05004087 where, id, wl_resource_get_id(surface_resource));
Pekka Paalanen86c8ca02013-05-17 16:46:07 +03004088 return;
4089 }
4090
Pekka Paalanene67858b2013-04-25 13:57:42 +03004091 /* make sure the parent is in its own list */
4092 if (wl_list_empty(&parent->subsurface_list)) {
4093 if (!weston_subsurface_create_for_parent(parent)) {
4094 wl_resource_post_no_memory(resource);
4095 return;
4096 }
4097 }
4098
4099 sub = weston_subsurface_create(id, surface, parent);
4100 if (!sub) {
4101 wl_resource_post_no_memory(resource);
4102 return;
4103 }
4104
Quentin Glidic2edc3d52016-08-12 10:41:33 +02004105 surface->committed = subsurface_committed;
4106 surface->committed_private = sub;
Pekka Paalanen8274d902014-08-06 19:36:51 +03004107 weston_surface_set_label_func(surface, subsurface_get_label);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004108}
4109
4110static void
4111subcompositor_destroy(struct wl_client *client, struct wl_resource *resource)
4112{
4113 wl_resource_destroy(resource);
4114}
4115
4116static const struct wl_subcompositor_interface subcompositor_interface = {
4117 subcompositor_destroy,
4118 subcompositor_get_subsurface
4119};
4120
4121static void
4122bind_subcompositor(struct wl_client *client,
4123 void *data, uint32_t version, uint32_t id)
4124{
4125 struct weston_compositor *compositor = data;
Jason Ekstranda85118c2013-06-27 20:17:02 -05004126 struct wl_resource *resource;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004127
Jason Ekstranda85118c2013-06-27 20:17:02 -05004128 resource =
4129 wl_resource_create(client, &wl_subcompositor_interface, 1, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07004130 if (resource == NULL) {
4131 wl_client_post_no_memory(client);
4132 return;
4133 }
4134 wl_resource_set_implementation(resource, &subcompositor_interface,
4135 compositor, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03004136}
4137
Bryce Harrington0795ece2016-08-30 12:04:26 -07004138/** Set a DPMS mode on all of the compositor's outputs
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004139 *
4140 * \param compositor The compositor instance
4141 * \param state The DPMS state the outputs will be set to
4142 */
Pekka Paalanene67858b2013-04-25 13:57:42 +03004143static void
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004144weston_compositor_dpms(struct weston_compositor *compositor,
4145 enum dpms_enum state)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004146{
4147 struct weston_output *output;
4148
Bryce Harrington08976ac2016-08-30 12:05:16 -07004149 wl_list_for_each(output, &compositor->output_list, link)
4150 if (output->set_dpms)
4151 output->set_dpms(output, state);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004152}
4153
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004154/** Restores the compositor to active status
4155 *
4156 * \param compositor The compositor instance
4157 *
4158 * If the compositor was in a sleeping mode, all outputs are powered
4159 * back on via DPMS. Otherwise if the compositor was inactive
4160 * (idle/locked, offscreen, or sleeping) then the compositor's wake
4161 * signal will fire.
4162 *
4163 * Restarts the idle timer.
4164 */
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02004165WL_EXPORT void
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004166weston_compositor_wake(struct weston_compositor *compositor)
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02004167{
Neil Roberts8b62e202013-09-30 13:14:47 +01004168 uint32_t old_state = compositor->state;
4169
4170 /* The state needs to be changed before emitting the wake
4171 * signal because that may try to schedule a repaint which
4172 * will not work if the compositor is still sleeping */
4173 compositor->state = WESTON_COMPOSITOR_ACTIVE;
4174
4175 switch (old_state) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004176 case WESTON_COMPOSITOR_SLEEPING:
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004177 case WESTON_COMPOSITOR_IDLE:
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01004178 case WESTON_COMPOSITOR_OFFSCREEN:
Daniel Stone893b9362016-11-08 15:47:09 +00004179 weston_compositor_dpms(compositor, WESTON_DPMS_ON);
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004180 wl_signal_emit(&compositor->wake_signal, compositor);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004181 /* fall through */
4182 default:
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004183 wl_event_source_timer_update(compositor->idle_source,
4184 compositor->idle_time * 1000);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02004185 }
4186}
4187
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004188/** Turns off rendering and frame events for the compositor.
4189 *
4190 * \param compositor The compositor instance
4191 *
4192 * This is used for example to prevent further rendering while the
4193 * compositor is shutting down.
4194 *
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004195 * Stops the idle timer.
4196 */
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004197WL_EXPORT void
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01004198weston_compositor_offscreen(struct weston_compositor *compositor)
4199{
4200 switch (compositor->state) {
4201 case WESTON_COMPOSITOR_OFFSCREEN:
4202 return;
4203 case WESTON_COMPOSITOR_SLEEPING:
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01004204 default:
4205 compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
4206 wl_event_source_timer_update(compositor->idle_source, 0);
4207 }
4208}
4209
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004210/** Powers down all attached output devices
4211 *
4212 * \param compositor The compositor instance
4213 *
4214 * Causes rendering to the outputs to cease, and no frame events to be
4215 * sent. Only powers down the outputs if the compositor is not already
4216 * in sleep mode.
4217 *
4218 * Stops the idle timer.
4219 */
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01004220WL_EXPORT void
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004221weston_compositor_sleep(struct weston_compositor *compositor)
4222{
4223 if (compositor->state == WESTON_COMPOSITOR_SLEEPING)
4224 return;
4225
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01004226 wl_event_source_timer_update(compositor->idle_source, 0);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004227 compositor->state = WESTON_COMPOSITOR_SLEEPING;
4228 weston_compositor_dpms(compositor, WESTON_DPMS_OFF);
4229}
4230
Bryce Harringtonc9626a32015-12-11 13:11:38 -08004231/** Sets compositor to idle mode
4232 *
4233 * \param data The compositor instance
4234 *
4235 * This is called when the idle timer fires. Once the compositor is in
4236 * idle mode it requires a wake action (e.g. via
4237 * weston_compositor_wake()) to restore it. The compositor's
4238 * idle_signal will be triggered when the idle event occurs.
4239 *
4240 * Idleness can be inhibited by setting the compositor's idle_inhibit
4241 * property.
4242 */
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04004243static int
4244idle_handler(void *data)
4245{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004246 struct weston_compositor *compositor = data;
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04004247
4248 if (compositor->idle_inhibit)
4249 return 1;
4250
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004251 compositor->state = WESTON_COMPOSITOR_IDLE;
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004252 wl_signal_emit(&compositor->idle_signal, compositor);
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04004253
4254 return 1;
4255}
4256
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04004257WL_EXPORT void
Xiong Zhang97116532013-10-23 13:58:31 +08004258weston_plane_init(struct weston_plane *plane,
4259 struct weston_compositor *ec,
4260 int32_t x, int32_t y)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04004261{
4262 pixman_region32_init(&plane->damage);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02004263 pixman_region32_init(&plane->clip);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04004264 plane->x = x;
4265 plane->y = y;
Xiong Zhang97116532013-10-23 13:58:31 +08004266 plane->compositor = ec;
Ander Conselvan de Oliveira3c36bf32013-07-05 16:05:26 +03004267
4268 /* Init the link so that the call to wl_list_remove() when releasing
4269 * the plane without ever stacking doesn't lead to a crash */
4270 wl_list_init(&plane->link);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04004271}
4272
4273WL_EXPORT void
4274weston_plane_release(struct weston_plane *plane)
4275{
Xiong Zhang97116532013-10-23 13:58:31 +08004276 struct weston_view *view;
4277
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04004278 pixman_region32_fini(&plane->damage);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02004279 pixman_region32_fini(&plane->clip);
Ander Conselvan de Oliveira3c36bf32013-07-05 16:05:26 +03004280
Xiong Zhang97116532013-10-23 13:58:31 +08004281 wl_list_for_each(view, &plane->compositor->view_list, link) {
4282 if (view->plane == plane)
4283 view->plane = NULL;
4284 }
4285
Ander Conselvan de Oliveira3c36bf32013-07-05 16:05:26 +03004286 wl_list_remove(&plane->link);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04004287}
4288
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02004289WL_EXPORT void
4290weston_compositor_stack_plane(struct weston_compositor *ec,
4291 struct weston_plane *plane,
4292 struct weston_plane *above)
4293{
4294 if (above)
4295 wl_list_insert(above->link.prev, &plane->link);
4296 else
4297 wl_list_insert(&ec->plane_list, &plane->link);
4298}
4299
Quentin Glidic4ef719c2016-07-05 20:44:33 +02004300static void
4301output_release(struct wl_client *client, struct wl_resource *resource)
4302{
4303 wl_resource_destroy(resource);
4304}
4305
4306static const struct wl_output_interface output_interface = {
4307 output_release,
4308};
4309
4310
Casey Dahlin9074db52012-04-19 22:50:09 -04004311static void unbind_resource(struct wl_resource *resource)
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04004312{
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05004313 wl_list_remove(wl_resource_get_link(resource));
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04004314}
4315
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004316static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004317bind_output(struct wl_client *client,
4318 void *data, uint32_t version, uint32_t id)
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05004319{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004320 struct weston_output *output = data;
4321 struct weston_mode *mode;
Kristian Høgsbergfd07fb72011-08-29 15:03:09 -04004322 struct wl_resource *resource;
Pekka Paalanen01f60212017-03-24 15:39:24 +02004323 struct weston_head *head = &output->head;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05004324
Jason Ekstranda85118c2013-06-27 20:17:02 -05004325 resource = wl_resource_create(client, &wl_output_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06004326 version, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07004327 if (resource == NULL) {
4328 wl_client_post_no_memory(client);
4329 return;
4330 }
Kristian Høgsbergfd07fb72011-08-29 15:03:09 -04004331
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03004332 wl_list_insert(&head->resource_list, wl_resource_get_link(resource));
Quentin Glidic4ef719c2016-07-05 20:44:33 +02004333 wl_resource_set_implementation(resource, &output_interface, data, unbind_resource);
Casey Dahlin9074db52012-04-19 22:50:09 -04004334
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05004335 wl_output_send_geometry(resource,
4336 output->x,
4337 output->y,
Pekka Paalanen01f60212017-03-24 15:39:24 +02004338 head->mm_width,
4339 head->mm_height,
4340 head->subpixel,
4341 head->make, head->model,
Kristian Høgsberg05890dc2012-08-10 10:09:20 -04004342 output->transform);
Jasper St. Pierre0013a292014-08-07 16:43:11 -04004343 if (version >= WL_OUTPUT_SCALE_SINCE_VERSION)
Alexander Larsson4ea95522013-05-22 14:41:37 +02004344 wl_output_send_scale(resource,
Hardeningff39efa2013-09-18 23:56:35 +02004345 output->current_scale);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004346
4347 wl_list_for_each (mode, &output->mode_list, link) {
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05004348 wl_output_send_mode(resource,
4349 mode->flags,
4350 mode->width,
4351 mode->height,
4352 mode->refresh);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004353 }
Alexander Larsson4ea95522013-05-22 14:41:37 +02004354
Jasper St. Pierre0013a292014-08-07 16:43:11 -04004355 if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
Alexander Larsson4ea95522013-05-22 14:41:37 +02004356 wl_output_send_done(resource);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05004357}
4358
Pekka Paalanen9ffb2502017-03-27 15:14:32 +03004359/** Get the backing object of wl_output
4360 *
4361 * \param resource A wl_output protocol object.
4362 * \return The backing object (user data) of a wl_resource representing a
4363 * wl_output protocol object.
4364 */
4365WL_EXPORT struct weston_output *
4366weston_output_from_resource(struct wl_resource *resource)
4367{
4368 assert(wl_resource_instance_of(resource, &wl_output_interface,
4369 &output_interface));
4370
4371 return wl_resource_get_user_data(resource);
4372}
4373
Pekka Paalanen01f60212017-03-24 15:39:24 +02004374/** Store monitor make, model and serial number
4375 *
4376 * \param head The head to modify.
4377 * \param make The monitor make. If EDID is available, the PNP ID. Otherwise
4378 * any string, or NULL for none.
4379 * \param model The monitor model or name, or a made-up string, or NULL for
4380 * none.
4381 * \param serialno The monitor serial number, a made-up string, or NULL for
4382 * none.
4383 *
4384 * \memberof weston_head
4385 * \internal
4386 */
4387WL_EXPORT void
4388weston_head_set_monitor_strings(struct weston_head *head,
4389 const char *make,
4390 const char *model,
4391 const char *serialno)
4392{
4393 head->make = (char *)make;
4394 head->model = (char *)model;
4395 head->serial_number = (char *)serialno;
4396}
4397
4398/** Store physical image size
4399 *
4400 * \param head The head to modify.
4401 * \param mm_width Image area width in millimeters.
4402 * \param mm_height Image area height in millimeters.
4403 *
4404 * \memberof weston_head
4405 * \internal
4406 */
4407WL_EXPORT void
4408weston_head_set_physical_size(struct weston_head *head,
4409 int32_t mm_width, int32_t mm_height)
4410{
4411 head->mm_width = mm_width;
4412 head->mm_height = mm_height;
4413}
4414
4415/** Store monitor sub-pixel layout
4416 *
4417 * \param head The head to modify.
4418 * \param sp Sub-pixel layout. The possible values are:
4419 * - WL_OUTPUT_SUBPIXEL_UNKNOWN,
4420 * - WL_OUTPUT_SUBPIXEL_NONE,
4421 * - WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB,
4422 * - WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR,
4423 * - WL_OUTPUT_SUBPIXEL_VERTICAL_RGB,
4424 * - WL_OUTPUT_SUBPIXEL_VERTICAL_BGR
4425 *
4426 * \memberof weston_head
4427 * \internal
4428 */
4429WL_EXPORT void
4430weston_head_set_subpixel(struct weston_head *head,
4431 enum wl_output_subpixel sp)
4432{
4433 head->subpixel = sp;
4434}
4435
4436/** Mark the monitor as internal
4437 *
4438 * This is used for embedded screens, like laptop panels.
4439 *
4440 * \param head The head to mark as internal.
4441 *
4442 * By default a head is external. The type is often inferred from the physical
4443 * connector type.
4444 *
4445 * \memberof weston_head
4446 * \internal
4447 */
4448WL_EXPORT void
4449weston_head_set_internal(struct weston_head *head)
4450{
4451 head->connection_internal = true;
4452}
Pekka Paalanen9ffb2502017-03-27 15:14:32 +03004453
David Fort0de859e2016-05-27 23:22:57 +02004454/* Move other outputs when one is resized so the space remains contiguous. */
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02004455static void
David Fort0de859e2016-05-27 23:22:57 +02004456weston_compositor_reflow_outputs(struct weston_compositor *compositor,
4457 struct weston_output *resized_output, int delta_width)
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02004458{
4459 struct weston_output *output;
David Fort0de859e2016-05-27 23:22:57 +02004460 bool start_resizing = false;
4461
4462 if (!delta_width)
4463 return;
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02004464
4465 wl_list_for_each(output, &compositor->output_list, link) {
David Fort0de859e2016-05-27 23:22:57 +02004466 if (output == resized_output) {
4467 start_resizing = true;
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02004468 continue;
4469 }
4470
David Fort0de859e2016-05-27 23:22:57 +02004471 if (start_resizing) {
4472 weston_output_move(output, output->x + delta_width, output->y);
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02004473 output->dirty = 1;
4474 }
4475 }
4476}
4477
Pekka Paalanend72bad22017-03-29 17:01:41 +03004478static void
Scott Moreauccbf29d2012-02-22 14:21:41 -07004479weston_output_update_matrix(struct weston_output *output)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004480{
Scott Moreau850ca422012-05-21 15:21:25 -06004481 float magnification;
Kristian Høgsberg31bd6c72011-02-13 13:00:51 -05004482
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004483 weston_matrix_init(&output->matrix);
Jason Ekstrandfb23df72014-10-16 10:55:21 -05004484 weston_matrix_translate(&output->matrix, -output->x, -output->y, 0);
Scott Moreau1bad5db2012-08-18 01:04:05 -06004485
Scott Moreauccbf29d2012-02-22 14:21:41 -07004486 if (output->zoom.active) {
Scott Moreaue6603982012-06-11 13:07:51 -06004487 magnification = 1 / (1 - output->zoom.spring_z.current);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004488 weston_output_update_zoom(output);
Neil Roberts1e40a7e2014-04-25 13:19:37 +01004489 weston_matrix_translate(&output->matrix, -output->zoom.trans_x,
Jason Ekstrandfb23df72014-10-16 10:55:21 -05004490 -output->zoom.trans_y, 0);
Neil Roberts1e40a7e2014-04-25 13:19:37 +01004491 weston_matrix_scale(&output->matrix, magnification,
4492 magnification, 1.0);
Scott Moreauccbf29d2012-02-22 14:21:41 -07004493 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04004494
Jason Ekstrandfb23df72014-10-16 10:55:21 -05004495 switch (output->transform) {
4496 case WL_OUTPUT_TRANSFORM_FLIPPED:
4497 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
4498 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
4499 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
4500 weston_matrix_translate(&output->matrix, -output->width, 0, 0);
4501 weston_matrix_scale(&output->matrix, -1, 1, 1);
4502 break;
4503 }
4504
4505 switch (output->transform) {
4506 default:
4507 case WL_OUTPUT_TRANSFORM_NORMAL:
4508 case WL_OUTPUT_TRANSFORM_FLIPPED:
4509 break;
4510 case WL_OUTPUT_TRANSFORM_90:
4511 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
4512 weston_matrix_translate(&output->matrix, 0, -output->height, 0);
4513 weston_matrix_rotate_xy(&output->matrix, 0, 1);
4514 break;
4515 case WL_OUTPUT_TRANSFORM_180:
4516 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
4517 weston_matrix_translate(&output->matrix,
4518 -output->width, -output->height, 0);
4519 weston_matrix_rotate_xy(&output->matrix, -1, 0);
4520 break;
4521 case WL_OUTPUT_TRANSFORM_270:
4522 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
4523 weston_matrix_translate(&output->matrix, -output->width, 0, 0);
4524 weston_matrix_rotate_xy(&output->matrix, 0, -1);
4525 break;
4526 }
4527
4528 if (output->current_scale != 1)
4529 weston_matrix_scale(&output->matrix,
4530 output->current_scale,
4531 output->current_scale, 1);
Neil Roberts6c3b01f2014-05-06 19:04:15 +01004532
Scott Moreauccbf29d2012-02-22 14:21:41 -07004533 output->dirty = 0;
Derek Foremanc0023212015-03-24 11:36:13 -05004534
4535 weston_matrix_invert(&output->inverse_matrix, &output->matrix);
Scott Moreauccbf29d2012-02-22 14:21:41 -07004536}
4537
Scott Moreau1bad5db2012-08-18 01:04:05 -06004538static void
Alexander Larsson0b135062013-05-28 16:23:36 +02004539weston_output_transform_scale_init(struct weston_output *output, uint32_t transform, uint32_t scale)
Scott Moreau1bad5db2012-08-18 01:04:05 -06004540{
4541 output->transform = transform;
Pekka Paalanen59987fa2016-04-26 15:50:59 +03004542 output->native_scale = scale;
4543 output->current_scale = scale;
Scott Moreau1bad5db2012-08-18 01:04:05 -06004544
Pekka Paalanen59987fa2016-04-26 15:50:59 +03004545 convert_size_by_transform_scale(&output->width, &output->height,
4546 output->current_mode->width,
4547 output->current_mode->height,
4548 transform, scale);
Alexander Larsson4ea95522013-05-22 14:41:37 +02004549}
4550
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004551static void
4552weston_output_init_geometry(struct weston_output *output, int x, int y)
Scott Moreauccbf29d2012-02-22 14:21:41 -07004553{
4554 output->x = x;
4555 output->y = y;
4556
Pekka Paalanen4b582c72017-03-30 16:04:58 +03004557 pixman_region32_fini(&output->previous_damage);
Ander Conselvan de Oliveirab8fcca92012-11-16 17:23:52 +02004558 pixman_region32_init(&output->previous_damage);
Pekka Paalanen4b582c72017-03-30 16:04:58 +03004559
4560 pixman_region32_fini(&output->region);
Scott Moreauccbf29d2012-02-22 14:21:41 -07004561 pixman_region32_init_rect(&output->region, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06004562 output->width,
4563 output->height);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004564}
4565
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004566WL_EXPORT void
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004567weston_output_move(struct weston_output *output, int x, int y)
4568{
Pekka Paalanen01f60212017-03-24 15:39:24 +02004569 struct weston_head *head = &output->head;
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004570 struct wl_resource *resource;
4571
4572 output->move_x = x - output->x;
4573 output->move_y = y - output->y;
4574
4575 if (output->move_x == 0 && output->move_y == 0)
4576 return;
4577
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004578 weston_output_init_geometry(output, x, y);
4579
4580 output->dirty = 1;
4581
4582 /* Move views on this output. */
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02004583 wl_signal_emit(&output->compositor->output_moved_signal, output);
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004584
4585 /* Notify clients of the change for output position. */
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03004586 wl_resource_for_each(resource, &head->resource_list) {
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004587 wl_output_send_geometry(resource,
4588 output->x,
4589 output->y,
Pekka Paalanen01f60212017-03-24 15:39:24 +02004590 head->mm_width,
4591 head->mm_height,
4592 head->subpixel,
4593 head->make,
4594 head->model,
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004595 output->transform);
Quanxian Wangb2c86362014-03-14 09:16:25 +08004596
FORT David8a120692016-04-26 23:34:06 +02004597 if (wl_resource_get_version(resource) >= WL_OUTPUT_DONE_SINCE_VERSION)
Quanxian Wangb2c86362014-03-14 09:16:25 +08004598 wl_output_send_done(resource);
4599 }
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004600}
4601
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03004602/** Signal that a pending output is taken into use.
4603 *
4604 * Removes the output from the pending list and adds it to the compositor's
4605 * list of enabled outputs. The output created signal is emitted.
Giulio Camuffob1147152015-05-06 21:41:57 +03004606 *
Pekka Paalanen2210ad02017-03-30 15:48:06 +03004607 * The output gets an internal ID assigned, and the wl_output global is
4608 * created.
Pekka Paalanen3d2d4972017-03-30 15:19:45 +03004609 *
Giulio Camuffob1147152015-05-06 21:41:57 +03004610 * \param compositor The compositor instance.
4611 * \param output The output to be added.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03004612 *
4613 * \internal
Giulio Camuffob1147152015-05-06 21:41:57 +03004614 */
Pekka Paalanenf9681b52017-03-29 16:58:48 +03004615static void
Giulio Camuffob1147152015-05-06 21:41:57 +03004616weston_compositor_add_output(struct weston_compositor *compositor,
4617 struct weston_output *output)
4618{
Armin Krezoviće5403842016-08-05 15:28:29 +02004619 struct weston_view *view, *next;
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03004620 struct weston_head *head;
Armin Krezoviće5403842016-08-05 15:28:29 +02004621
Pekka Paalanen7f340ff2017-03-30 14:56:22 +03004622 assert(!output->enabled);
Pekka Paalanen3d2d4972017-03-30 15:19:45 +03004623
4624 /* Verify we haven't reached the limit of 32 available output IDs */
4625 assert(ffs(~compositor->output_id_pool) > 0);
4626
4627 /* Invert the output id pool and look for the lowest numbered
4628 * switch (the least significant bit). Take that bit's position
4629 * as our ID, and mark it used in the compositor's output_id_pool.
4630 */
4631 output->id = ffs(~compositor->output_id_pool) - 1;
4632 compositor->output_id_pool |= 1u << output->id;
4633
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03004634 wl_list_remove(&output->link);
Giulio Camuffob1147152015-05-06 21:41:57 +03004635 wl_list_insert(compositor->output_list.prev, &output->link);
Pekka Paalanen7f340ff2017-03-30 14:56:22 +03004636 output->enabled = true;
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03004637
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03004638 head = &output->head;
4639 head->global = wl_global_create(compositor->wl_display,
4640 &wl_output_interface, 3,
4641 output, bind_output);
Pekka Paalanen2210ad02017-03-30 15:48:06 +03004642
Giulio Camuffob1147152015-05-06 21:41:57 +03004643 wl_signal_emit(&compositor->output_created_signal, output);
Armin Krezoviće5403842016-08-05 15:28:29 +02004644
4645 wl_list_for_each_safe(view, next, &compositor->view_list, link)
4646 weston_view_geometry_dirty(view);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04004647}
4648
Pekka Paalanenee16ea92017-03-29 16:53:50 +03004649/** Transform device coordinates into global coordinates
4650 *
4651 * \param device_x[in] X coordinate in device units.
4652 * \param device_y[in] Y coordinate in device units.
4653 * \param x[out] X coordinate in the global space.
4654 * \param y[out] Y coordinate in the global space.
4655 *
4656 * Transforms coordinates from the device coordinate space
4657 * (physical pixel units) to the global coordinate space (logical pixel units).
4658 * This takes into account output transform and scale.
4659 *
4660 * \memberof weston_output
4661 * \internal
4662 */
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07004663WL_EXPORT void
4664weston_output_transform_coordinate(struct weston_output *output,
Giulio Camuffo90a6fc62016-03-22 17:44:54 +02004665 double device_x, double device_y,
4666 double *x, double *y)
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07004667{
Derek Foreman0f679412014-10-02 13:41:17 -05004668 struct weston_vector p = { {
Giulio Camuffo90a6fc62016-03-22 17:44:54 +02004669 device_x,
4670 device_y,
Derek Foreman0f679412014-10-02 13:41:17 -05004671 0.0,
4672 1.0 } };
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07004673
Derek Foreman67a18b92015-03-24 11:36:14 -05004674 weston_matrix_transform(&output->inverse_matrix, &p);
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07004675
Giulio Camuffo90a6fc62016-03-22 17:44:54 +02004676 *x = p.f[0] / p.f[3];
4677 *y = p.f[1] / p.f[3];
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07004678}
4679
Pekka Paalanene6ac4fc2017-03-29 16:07:34 +03004680/** Removes output from compositor's list of enabled outputs
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004681 *
4682 * \param output The weston_output object that is being removed.
4683 *
Pekka Paalanene6ac4fc2017-03-29 16:07:34 +03004684 * The following happens:
4685 *
4686 * - The output assignments of all views in the current scenegraph are
4687 * recomputed.
4688 *
4689 * - Presentation feedback is discarded.
4690 *
4691 * - Compositor is notified that outputs were changed and
4692 * applies the necessary changes to re-layout outputs.
4693 *
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03004694 * - The output is put back in the pending outputs list.
4695 *
Pekka Paalanene6ac4fc2017-03-29 16:07:34 +03004696 * - Signal is emitted to notify all users of the weston_output
4697 * object that the output is being destroyed.
4698 *
4699 * - wl_output protocol objects referencing this weston_output
Pekka Paalanen2210ad02017-03-30 15:48:06 +03004700 * are made inert, and the wl_output global is removed.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03004701 *
Pekka Paalanen3d2d4972017-03-30 15:19:45 +03004702 * - The output's internal ID is released.
4703 *
Pekka Paalanenee16ea92017-03-29 16:53:50 +03004704 * \memberof weston_output
4705 * \internal
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004706 */
4707static void
4708weston_compositor_remove_output(struct weston_output *output)
4709{
Pekka Paalanenbccda712017-03-29 16:16:04 +03004710 struct weston_compositor *compositor = output->compositor;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004711 struct wl_resource *resource;
4712 struct weston_view *view;
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03004713 struct weston_head *head;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004714
4715 assert(output->destroying);
Pekka Paalanen7f340ff2017-03-30 14:56:22 +03004716 assert(output->enabled);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004717
Pekka Paalanenbccda712017-03-29 16:16:04 +03004718 wl_list_for_each(view, &compositor->view_list, link) {
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004719 if (view->output_mask & (1u << output->id))
4720 weston_view_assign_output(view);
4721 }
4722
4723 weston_presentation_feedback_discard_list(&output->feedback_list);
4724
Pekka Paalanenbccda712017-03-29 16:16:04 +03004725 weston_compositor_reflow_outputs(compositor, output, output->width);
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03004726
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004727 wl_list_remove(&output->link);
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03004728 wl_list_insert(compositor->pending_output_list.prev, &output->link);
Pekka Paalanen7f340ff2017-03-30 14:56:22 +03004729 output->enabled = false;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004730
Pekka Paalanenbccda712017-03-29 16:16:04 +03004731 wl_signal_emit(&compositor->output_destroyed_signal, output);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004732 wl_signal_emit(&output->destroy_signal, output);
4733
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03004734 head = &output->head;
4735 wl_global_destroy(head->global);
4736 head->global = NULL;
4737 wl_resource_for_each(resource, &head->resource_list) {
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004738 wl_resource_set_destructor(resource, NULL);
4739 }
Pekka Paalanen3d2d4972017-03-30 15:19:45 +03004740
4741 compositor->output_id_pool &= ~(1u << output->id);
4742 output->id = 0xffffffff; /* invalid */
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004743}
4744
4745/** Sets the output scale for a given output.
4746 *
4747 * \param output The weston_output object that the scale is set for.
4748 * \param scale Scale factor for the given output.
4749 *
4750 * It only supports setting scale for an output that
4751 * is not enabled and it can only be ran once.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03004752 *
4753 * \memberof weston_output
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004754 */
4755WL_EXPORT void
4756weston_output_set_scale(struct weston_output *output,
4757 int32_t scale)
4758{
4759 /* We can only set scale on a disabled output */
4760 assert(!output->enabled);
4761
4762 /* We only want to set scale once */
4763 assert(!output->scale);
4764
4765 output->scale = scale;
4766}
4767
4768/** Sets the output transform for a given output.
4769 *
4770 * \param output The weston_output object that the transform is set for.
4771 * \param transform Transform value for the given output.
4772 *
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004773 * Refer to wl_output::transform section located at
4774 * https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_output
4775 * for list of values that can be passed to this function.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03004776 *
4777 * \memberof weston_output
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004778 */
4779WL_EXPORT void
4780weston_output_set_transform(struct weston_output *output,
4781 uint32_t transform)
4782{
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00004783 struct weston_pointer_motion_event ev;
4784 struct wl_resource *resource;
4785 struct weston_seat *seat;
4786 pixman_region32_t old_region;
4787 int mid_x, mid_y;
Pekka Paalanen01f60212017-03-24 15:39:24 +02004788 struct weston_head *head = &output->head;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004789
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00004790 if (!output->enabled && output->transform == UINT32_MAX) {
4791 output->transform = transform;
4792 return;
4793 }
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004794
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00004795 weston_output_transform_scale_init(output, transform, output->scale);
4796
4797 pixman_region32_init(&old_region);
4798 pixman_region32_copy(&old_region, &output->region);
4799
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00004800 weston_output_init_geometry(output, output->x, output->y);
4801
4802 output->dirty = 1;
4803
4804 /* Notify clients of the change for output transform. */
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03004805 wl_resource_for_each(resource, &head->resource_list) {
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00004806 wl_output_send_geometry(resource,
4807 output->x,
4808 output->y,
Pekka Paalanen01f60212017-03-24 15:39:24 +02004809 head->mm_width,
4810 head->mm_height,
4811 head->subpixel,
4812 head->make,
4813 head->model,
Ilia Bozhinov8564a0d2017-06-25 12:21:39 +00004814 output->transform);
4815
4816 if (wl_resource_get_version(resource) >= WL_OUTPUT_DONE_SINCE_VERSION)
4817 wl_output_send_done(resource);
4818 }
4819
4820 /* we must ensure that pointers are inside output, otherwise they disappear */
4821 mid_x = output->x + output->width / 2;
4822 mid_y = output->y + output->height / 2;
4823
4824 ev.mask = WESTON_POINTER_MOTION_ABS;
4825 ev.x = wl_fixed_to_double(wl_fixed_from_int(mid_x));
4826 ev.y = wl_fixed_to_double(wl_fixed_from_int(mid_y));
4827
4828 wl_list_for_each(seat, &output->compositor->seat_list, link) {
4829 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
4830
4831 if (pointer && pixman_region32_contains_point(&old_region,
4832 wl_fixed_to_int(pointer->x),
4833 wl_fixed_to_int(pointer->y),
4834 NULL))
4835 weston_pointer_move(pointer, &ev);
4836 }
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004837}
4838
4839/** Initializes a weston_output object with enough data so
4840 ** an output can be configured.
4841 *
4842 * \param output The weston_output object to initialize
4843 * \param compositor The compositor instance.
Pekka Paalanen26ac2e12017-04-03 13:18:13 +03004844 * \param name Name for the output (the string is copied).
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004845 *
4846 * Sets initial values for fields that are expected to be
4847 * configured either by compositors or backends.
Pekka Paalanenee16ea92017-03-29 16:53:50 +03004848 *
Pekka Paalanen26ac2e12017-04-03 13:18:13 +03004849 * The name is used in logs, and can be used by compositors as a configuration
4850 * identifier.
4851 *
Pekka Paalanenee16ea92017-03-29 16:53:50 +03004852 * \memberof weston_output
4853 * \internal
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004854 */
4855WL_EXPORT void
Armin Krezović40087402016-09-30 14:11:12 +02004856weston_output_init(struct weston_output *output,
Pekka Paalanen26ac2e12017-04-03 13:18:13 +03004857 struct weston_compositor *compositor,
4858 const char *name)
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004859{
Pekka Paalanen01f60212017-03-24 15:39:24 +02004860 struct weston_head *head = &output->head;
4861
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004862 output->compositor = compositor;
4863 output->destroying = 0;
Pekka Paalanen26ac2e12017-04-03 13:18:13 +03004864 output->name = strdup(name);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004865 wl_list_init(&output->link);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004866 output->enabled = false;
4867
4868 /* Add some (in)sane defaults which can be used
4869 * for checking if an output was properly configured
4870 */
Pekka Paalanen01f60212017-03-24 15:39:24 +02004871 head->mm_width = 0;
4872 head->mm_height = 0;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004873 output->scale = 0;
4874 /* Can't use -1 on uint32_t and 0 is valid enum value */
4875 output->transform = UINT32_MAX;
Pekka Paalanen4b582c72017-03-30 16:04:58 +03004876
4877 pixman_region32_init(&output->previous_damage);
4878 pixman_region32_init(&output->region);
Pekka Paalanen42704142017-09-06 16:47:52 +03004879 wl_list_init(&output->mode_list);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004880}
4881
4882/** Adds weston_output object to pending output list.
4883 *
4884 * \param output The weston_output object to add
4885 * \param compositor The compositor instance.
4886 *
4887 * Also notifies the compositor that an output is pending for
4888 * configuration.
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03004889 *
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03004890 * The opposite of this operation is built into weston_output_release().
Pekka Paalanenee16ea92017-03-29 16:53:50 +03004891 *
4892 * \memberof weston_output
4893 * \internal
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004894 */
4895WL_EXPORT void
4896weston_compositor_add_pending_output(struct weston_output *output,
4897 struct weston_compositor *compositor)
4898{
Pekka Paalanene952a012017-03-29 17:14:00 +03004899 assert(output->disable);
4900 assert(output->enable);
4901
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03004902 wl_list_remove(&output->link);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004903 wl_list_insert(compositor->pending_output_list.prev, &output->link);
4904 wl_signal_emit(&compositor->output_pending_signal, output);
4905}
4906
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004907/** Constructs a weston_output object that can be used by the compositor.
4908 *
Pekka Paalanencc201e42017-03-30 15:11:25 +03004909 * \param output The weston_output object that needs to be enabled. Must not
4910 * be enabled already.
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004911 *
4912 * Output coordinates are calculated and each new output is by default
4913 * assigned to the right of previous one.
4914 *
4915 * Sets up the transformation, zoom, and geometry of the output using
4916 * the properties that need to be configured by the compositor.
4917 *
4918 * Establishes a repaint timer for the output with the relevant display
4919 * object's event loop. See output_repaint_timer_handler().
4920 *
4921 * The output is assigned an ID. Weston can support up to 32 distinct
4922 * outputs, with IDs numbered from 0-31; the compositor's output_id_pool
4923 * is referred to and used to find the first available ID number, and
4924 * then this ID is marked as used in output_id_pool.
4925 *
4926 * The output is also assigned a Wayland global with the wl_output
4927 * external interface.
4928 *
4929 * Backend specific function is called to set up the output output.
4930 *
4931 * Output is added to the compositor's output list
4932 *
4933 * If the backend specific function fails, the weston_output object
4934 * is returned to a state it was before calling this function and
4935 * is added to the compositor's pending_output_list in case it needs
4936 * to be reconfigured or just so it can be destroyed at shutdown.
4937 *
4938 * 0 is returned on success, -1 on failure.
4939 */
4940WL_EXPORT int
4941weston_output_enable(struct weston_output *output)
4942{
Armin Krezović782f5df2016-09-30 14:11:11 +02004943 struct weston_compositor *c = output->compositor;
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004944 struct weston_output *iterator;
4945 int x = 0, y = 0;
4946
Pekka Paalanencc201e42017-03-30 15:11:25 +03004947 if (output->enabled) {
4948 weston_log("Error: attempt to enable an enabled output '%s'\n",
4949 output->name);
4950 return -1;
4951 }
4952
Armin Krezović782f5df2016-09-30 14:11:11 +02004953 iterator = container_of(c->output_list.prev,
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004954 struct weston_output, link);
4955
Armin Krezović782f5df2016-09-30 14:11:11 +02004956 if (!wl_list_empty(&c->output_list))
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004957 x = iterator->x + iterator->width;
4958
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004959 /* Make sure the scale is set up */
4960 assert(output->scale);
4961
4962 /* Make sure we have a transform set */
4963 assert(output->transform != UINT32_MAX);
4964
Armin Krezović782f5df2016-09-30 14:11:11 +02004965 output->x = x;
4966 output->y = y;
4967 output->dirty = 1;
4968 output->original_scale = output->scale;
4969
4970 weston_output_transform_scale_init(output, output->transform, output->scale);
4971 weston_output_init_zoom(output);
4972
4973 weston_output_init_geometry(output, x, y);
4974 weston_output_damage(output);
4975
4976 wl_signal_init(&output->frame_signal);
4977 wl_signal_init(&output->destroy_signal);
4978 wl_list_init(&output->animation_list);
Pekka Paalanen1b9bf592017-03-27 12:15:38 +03004979 wl_list_init(&output->head.resource_list);
Armin Krezović782f5df2016-09-30 14:11:11 +02004980 wl_list_init(&output->feedback_list);
Armin Krezović782f5df2016-09-30 14:11:11 +02004981
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004982 /* Enable the output (set up the crtc or create a
4983 * window representing the output, set up the
4984 * renderer, etc)
4985 */
4986 if (output->enable(output) < 0) {
4987 weston_log("Enabling output \"%s\" failed.\n", output->name);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02004988 return -1;
4989 }
4990
4991 weston_compositor_add_output(output->compositor, output);
4992
4993 return 0;
4994}
4995
4996/** Converts a weston_output object to a pending output state, so it
4997 ** can be configured again or destroyed.
4998 *
4999 * \param output The weston_output object that needs to be disabled.
5000 *
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005001 * Calls a backend specific function to disable an output, in case
5002 * such function exists.
5003 *
Pekka Paalanenc65df642017-03-29 15:45:46 +03005004 * The backend specific disable function may choose to postpone the disabling
5005 * by returning a negative value, in which case this function returns early.
5006 * In that case the backend will guarantee the output will be disabled soon
5007 * by the backend calling this function again. One must not attempt to re-enable
5008 * the output until that happens.
5009 *
5010 * Otherwise, if the output is being used by the compositor, it is removed
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005011 * from weston's output_list (see weston_compositor_remove_output())
5012 * and is returned to a state it was before weston_output_enable()
5013 * was ran (see weston_output_enable_undo()).
5014 *
Pekka Paalanenc65df642017-03-29 15:45:46 +03005015 * See weston_output_init() for more information on the
5016 * state output is returned to.
Pekka Paalanencc201e42017-03-30 15:11:25 +03005017 *
5018 * If the output has never been enabled yet, this function can still be
5019 * called to ensure that the output is actually turned off rather than left
5020 * in the state it was discovered in.
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005021 */
5022WL_EXPORT void
5023weston_output_disable(struct weston_output *output)
5024{
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005025 /* Should we rename this? */
5026 output->destroying = 1;
5027
Pekka Paalanenc65df642017-03-29 15:45:46 +03005028 /* Disable is called unconditionally also for not-enabled outputs,
5029 * because at compositor start-up, if there is an output that is
5030 * already on but the compositor wants to turn it off, we have to
5031 * forward the turn-off to the backend so it knows to do it.
5032 * The backend cannot initially turn off everything, because it
5033 * would cause unnecessary mode-sets for all outputs the compositor
5034 * wants to be on.
5035 */
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005036 if (output->disable(output) < 0)
5037 return;
5038
Pekka Paalanen4b582c72017-03-30 16:04:58 +03005039 if (output->enabled)
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005040 weston_compositor_remove_output(output);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005041
5042 output->destroying = 0;
5043}
5044
5045/** Emits a signal to indicate that there are outputs waiting to be configured.
5046 *
5047 * \param compositor The compositor instance
5048 */
5049WL_EXPORT void
5050weston_pending_output_coldplug(struct weston_compositor *compositor)
5051{
5052 struct weston_output *output, *next;
5053
5054 wl_list_for_each_safe(output, next, &compositor->pending_output_list, link)
5055 wl_signal_emit(&compositor->output_pending_signal, output);
5056}
5057
Pekka Paalanenee16ea92017-03-29 16:53:50 +03005058/** Uninitialize an output
5059 *
5060 * Removes the output from the list of enabled outputs if necessary, but
5061 * does not call the backend's output disable function. The output will no
5062 * longer be in the list of pending outputs either.
5063 *
5064 * All fields of weston_output become uninitialized, i.e. should not be used
5065 * anymore. The caller can free the memory after this.
5066 *
5067 * \memberof weston_output
5068 * \internal
5069 */
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005070WL_EXPORT void
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03005071weston_output_release(struct weston_output *output)
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005072{
5073 output->destroying = 1;
5074
Pekka Paalanen4b582c72017-03-30 16:04:58 +03005075 if (output->enabled)
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005076 weston_compositor_remove_output(output);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005077
Pekka Paalanen4b582c72017-03-30 16:04:58 +03005078 pixman_region32_fini(&output->region);
5079 pixman_region32_fini(&output->previous_damage);
Pekka Paalanenf0ca7962017-03-29 16:20:19 +03005080 wl_list_remove(&output->link);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005081 free(output->name);
5082}
5083
Benjamin Franzke315b3dc2011-03-08 11:32:57 +01005084static void
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02005085destroy_viewport(struct wl_resource *resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01005086{
Jonny Lamb74130762013-11-26 18:19:46 +01005087 struct weston_surface *surface =
5088 wl_resource_get_user_data(resource);
5089
Pekka Paalanen4826f872016-04-22 14:14:38 +03005090 if (!surface)
5091 return;
5092
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02005093 surface->viewport_resource = NULL;
Pekka Paalanenf0cad482014-03-14 14:38:16 +02005094 surface->pending.buffer_viewport.buffer.src_width =
5095 wl_fixed_from_int(-1);
5096 surface->pending.buffer_viewport.surface.width = -1;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02005097 surface->pending.buffer_viewport.changed = 1;
Jonny Lamb8ae35902013-11-26 18:19:45 +01005098}
5099
5100static void
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02005101viewport_destroy(struct wl_client *client,
5102 struct wl_resource *resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01005103{
5104 wl_resource_destroy(resource);
5105}
5106
5107static void
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005108viewport_set_source(struct wl_client *client,
5109 struct wl_resource *resource,
5110 wl_fixed_t src_x,
5111 wl_fixed_t src_y,
5112 wl_fixed_t src_width,
5113 wl_fixed_t src_height)
5114{
5115 struct weston_surface *surface =
5116 wl_resource_get_user_data(resource);
5117
Pekka Paalanen4826f872016-04-22 14:14:38 +03005118 if (!surface) {
5119 wl_resource_post_error(resource,
5120 WP_VIEWPORT_ERROR_NO_SURFACE,
5121 "wl_surface for this viewport is no longer exists");
5122 return;
5123 }
5124
5125 assert(surface->viewport_resource == resource);
Pekka Paalanen201769a2016-04-26 14:42:11 +03005126 assert(surface->resource);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005127
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03005128 if (src_width == wl_fixed_from_int(-1) &&
Pekka Paalanen201769a2016-04-26 14:42:11 +03005129 src_height == wl_fixed_from_int(-1) &&
5130 src_x == wl_fixed_from_int(-1) &&
5131 src_y == wl_fixed_from_int(-1)) {
5132 /* unset source rect */
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005133 surface->pending.buffer_viewport.buffer.src_width =
5134 wl_fixed_from_int(-1);
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02005135 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03005136 return;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005137 }
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03005138
Pekka Paalanen201769a2016-04-26 14:42:11 +03005139 if (src_width <= 0 || src_height <= 0 || src_x < 0 || src_y < 0) {
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03005140 wl_resource_post_error(resource,
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03005141 WP_VIEWPORT_ERROR_BAD_VALUE,
Pekka Paalanen201769a2016-04-26 14:42:11 +03005142 "wl_surface@%d viewport source "
5143 "w=%f <= 0, h=%f <= 0, x=%f < 0, or y=%f < 0",
5144 wl_resource_get_id(surface->resource),
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03005145 wl_fixed_to_double(src_width),
Pekka Paalanen201769a2016-04-26 14:42:11 +03005146 wl_fixed_to_double(src_height),
5147 wl_fixed_to_double(src_x),
5148 wl_fixed_to_double(src_y));
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03005149 return;
5150 }
5151
5152 surface->pending.buffer_viewport.buffer.src_x = src_x;
5153 surface->pending.buffer_viewport.buffer.src_y = src_y;
5154 surface->pending.buffer_viewport.buffer.src_width = src_width;
5155 surface->pending.buffer_viewport.buffer.src_height = src_height;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02005156 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005157}
5158
5159static void
5160viewport_set_destination(struct wl_client *client,
5161 struct wl_resource *resource,
5162 int32_t dst_width,
5163 int32_t dst_height)
5164{
5165 struct weston_surface *surface =
5166 wl_resource_get_user_data(resource);
5167
Pekka Paalanen4826f872016-04-22 14:14:38 +03005168 if (!surface) {
5169 wl_resource_post_error(resource,
5170 WP_VIEWPORT_ERROR_NO_SURFACE,
5171 "wl_surface for this viewport no longer exists");
5172 return;
5173 }
5174
5175 assert(surface->viewport_resource == resource);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005176
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03005177 if (dst_width == -1 && dst_height == -1) {
5178 /* unset destination size */
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005179 surface->pending.buffer_viewport.surface.width = -1;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02005180 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03005181 return;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005182 }
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03005183
5184 if (dst_width <= 0 || dst_height <= 0) {
5185 wl_resource_post_error(resource,
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03005186 WP_VIEWPORT_ERROR_BAD_VALUE,
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03005187 "destination size must be positive (%dx%d)",
5188 dst_width, dst_height);
5189 return;
5190 }
5191
5192 surface->pending.buffer_viewport.surface.width = dst_width;
5193 surface->pending.buffer_viewport.surface.height = dst_height;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02005194 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005195}
5196
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03005197static const struct wp_viewport_interface viewport_interface = {
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02005198 viewport_destroy,
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005199 viewport_set_source,
5200 viewport_set_destination
Jonny Lamb8ae35902013-11-26 18:19:45 +01005201};
5202
5203static void
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03005204viewporter_destroy(struct wl_client *client,
5205 struct wl_resource *resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01005206{
5207 wl_resource_destroy(resource);
5208}
5209
5210static void
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03005211viewporter_get_viewport(struct wl_client *client,
5212 struct wl_resource *viewporter,
5213 uint32_t id,
5214 struct wl_resource *surface_resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01005215{
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03005216 int version = wl_resource_get_version(viewporter);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005217 struct weston_surface *surface =
5218 wl_resource_get_user_data(surface_resource);
Jonny Lamb8ae35902013-11-26 18:19:45 +01005219 struct wl_resource *resource;
5220
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02005221 if (surface->viewport_resource) {
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03005222 wl_resource_post_error(viewporter,
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03005223 WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS,
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02005224 "a viewport for that surface already exists");
Jonny Lamb74130762013-11-26 18:19:46 +01005225 return;
5226 }
5227
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03005228 resource = wl_resource_create(client, &wp_viewport_interface,
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02005229 version, id);
Jonny Lamb8ae35902013-11-26 18:19:45 +01005230 if (resource == NULL) {
5231 wl_client_post_no_memory(client);
5232 return;
5233 }
5234
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02005235 wl_resource_set_implementation(resource, &viewport_interface,
5236 surface, destroy_viewport);
Jonny Lamb74130762013-11-26 18:19:46 +01005237
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02005238 surface->viewport_resource = resource;
Jonny Lamb8ae35902013-11-26 18:19:45 +01005239}
5240
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03005241static const struct wp_viewporter_interface viewporter_interface = {
5242 viewporter_destroy,
5243 viewporter_get_viewport
Jonny Lamb8ae35902013-11-26 18:19:45 +01005244};
5245
5246static void
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03005247bind_viewporter(struct wl_client *client,
5248 void *data, uint32_t version, uint32_t id)
Jonny Lamb8ae35902013-11-26 18:19:45 +01005249{
5250 struct wl_resource *resource;
5251
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03005252 resource = wl_resource_create(client, &wp_viewporter_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06005253 version, id);
Jonny Lamb8ae35902013-11-26 18:19:45 +01005254 if (resource == NULL) {
5255 wl_client_post_no_memory(client);
5256 return;
5257 }
5258
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03005259 wl_resource_set_implementation(resource, &viewporter_interface,
Jonny Lamb8ae35902013-11-26 18:19:45 +01005260 NULL, NULL);
5261}
5262
5263static void
Pekka Paalanen133e4392014-09-23 22:08:46 -04005264destroy_presentation_feedback(struct wl_resource *feedback_resource)
5265{
5266 struct weston_presentation_feedback *feedback;
5267
5268 feedback = wl_resource_get_user_data(feedback_resource);
5269
5270 wl_list_remove(&feedback->link);
5271 free(feedback);
5272}
5273
5274static void
Pekka Paalanen31f7d782014-09-23 22:08:43 -04005275presentation_destroy(struct wl_client *client, struct wl_resource *resource)
5276{
5277 wl_resource_destroy(resource);
5278}
5279
5280static void
5281presentation_feedback(struct wl_client *client,
Pekka Paalanen133e4392014-09-23 22:08:46 -04005282 struct wl_resource *presentation_resource,
5283 struct wl_resource *surface_resource,
Pekka Paalanen31f7d782014-09-23 22:08:43 -04005284 uint32_t callback)
5285{
Pekka Paalanen133e4392014-09-23 22:08:46 -04005286 struct weston_surface *surface;
5287 struct weston_presentation_feedback *feedback;
5288
5289 surface = wl_resource_get_user_data(surface_resource);
5290
Bryce Harringtonde16d892014-11-20 22:21:57 -08005291 feedback = zalloc(sizeof *feedback);
5292 if (feedback == NULL)
Pekka Paalanen133e4392014-09-23 22:08:46 -04005293 goto err_calloc;
5294
5295 feedback->resource = wl_resource_create(client,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02005296 &wp_presentation_feedback_interface,
Pekka Paalanen133e4392014-09-23 22:08:46 -04005297 1, callback);
5298 if (!feedback->resource)
5299 goto err_create;
5300
5301 wl_resource_set_implementation(feedback->resource, NULL, feedback,
5302 destroy_presentation_feedback);
5303
5304 wl_list_insert(&surface->pending.feedback_list, &feedback->link);
5305
5306 return;
5307
5308err_create:
5309 free(feedback);
5310
5311err_calloc:
5312 wl_client_post_no_memory(client);
Pekka Paalanen31f7d782014-09-23 22:08:43 -04005313}
5314
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02005315static const struct wp_presentation_interface presentation_implementation = {
Pekka Paalanen31f7d782014-09-23 22:08:43 -04005316 presentation_destroy,
5317 presentation_feedback
5318};
5319
5320static void
5321bind_presentation(struct wl_client *client,
5322 void *data, uint32_t version, uint32_t id)
5323{
5324 struct weston_compositor *compositor = data;
5325 struct wl_resource *resource;
5326
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02005327 resource = wl_resource_create(client, &wp_presentation_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06005328 version, id);
Pekka Paalanen31f7d782014-09-23 22:08:43 -04005329 if (resource == NULL) {
5330 wl_client_post_no_memory(client);
5331 return;
5332 }
5333
5334 wl_resource_set_implementation(resource, &presentation_implementation,
5335 compositor, NULL);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02005336 wp_presentation_send_clock_id(resource, compositor->presentation_clock);
Pekka Paalanen31f7d782014-09-23 22:08:43 -04005337}
5338
5339static void
Kristian Høgsberga8873122011-11-23 10:39:34 -05005340compositor_bind(struct wl_client *client,
5341 void *data, uint32_t version, uint32_t id)
5342{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005343 struct weston_compositor *compositor = data;
Jason Ekstranda85118c2013-06-27 20:17:02 -05005344 struct wl_resource *resource;
Kristian Høgsberga8873122011-11-23 10:39:34 -05005345
Jason Ekstranda85118c2013-06-27 20:17:02 -05005346 resource = wl_resource_create(client, &wl_compositor_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06005347 version, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07005348 if (resource == NULL) {
5349 wl_client_post_no_memory(client);
5350 return;
5351 }
5352
5353 wl_resource_set_implementation(resource, &compositor_interface,
5354 compositor, NULL);
Kristian Høgsberga8873122011-11-23 10:39:34 -05005355}
5356
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005357WL_EXPORT int
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +02005358weston_environment_get_fd(const char *env)
5359{
Bryce Harrington25a2bdd2016-08-03 17:40:52 -07005360 char *e;
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +02005361 int fd, flags;
5362
5363 e = getenv(env);
Bryce Harrington25a2bdd2016-08-03 17:40:52 -07005364 if (!e || !safe_strtoint(e, &fd))
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +02005365 return -1;
5366
5367 flags = fcntl(fd, F_GETFD);
5368 if (flags == -1)
5369 return -1;
5370
5371 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
5372 unsetenv(env);
5373
5374 return fd;
5375}
5376
Pekka Paalanenb5026542014-11-12 15:09:24 +02005377static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02005378timeline_key_binding_handler(struct weston_keyboard *keyboard,
5379 const struct timespec *time, uint32_t key,
5380 void *data)
Pekka Paalanenb5026542014-11-12 15:09:24 +02005381{
5382 struct weston_compositor *compositor = data;
5383
5384 if (weston_timeline_enabled_)
5385 weston_timeline_close();
5386 else
5387 weston_timeline_open(compositor);
5388}
5389
Giulio Camuffo459137b2014-10-11 23:56:24 +03005390/** Create the compositor.
5391 *
5392 * This functions creates and initializes a compositor instance.
5393 *
5394 * \param display The Wayland display to be used.
5395 * \param user_data A pointer to an object that can later be retrieved
5396 * using the \ref weston_compositor_get_user_data function.
5397 * \return The compositor instance on success or NULL on failure.
5398 */
5399WL_EXPORT struct weston_compositor *
5400weston_compositor_create(struct wl_display *display, void *user_data)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04005401{
Giulio Camuffo459137b2014-10-11 23:56:24 +03005402 struct weston_compositor *ec;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05005403 struct wl_event_loop *loop;
Ossama Othmana50e6e42013-05-14 09:48:26 -07005404
Giulio Camuffo459137b2014-10-11 23:56:24 +03005405 ec = zalloc(sizeof *ec);
5406 if (!ec)
5407 return NULL;
5408
5409 ec->wl_display = display;
5410 ec->user_data = user_data;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005411 wl_signal_init(&ec->destroy_signal);
Kristian Høgsbergf03a04a2014-04-06 22:04:50 -07005412 wl_signal_init(&ec->create_surface_signal);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005413 wl_signal_init(&ec->activate_signal);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03005414 wl_signal_init(&ec->transform_signal);
Tiago Vignatti1d01b012012-09-27 17:48:36 +03005415 wl_signal_init(&ec->kill_signal);
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005416 wl_signal_init(&ec->idle_signal);
5417 wl_signal_init(&ec->wake_signal);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02005418 wl_signal_init(&ec->show_input_panel_signal);
5419 wl_signal_init(&ec->hide_input_panel_signal);
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02005420 wl_signal_init(&ec->update_input_panel_signal);
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +01005421 wl_signal_init(&ec->seat_created_signal);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005422 wl_signal_init(&ec->output_pending_signal);
Richard Hughes59d5da72013-05-01 21:52:11 +01005423 wl_signal_init(&ec->output_created_signal);
Ander Conselvan de Oliveiraf84327a2014-01-29 18:47:51 +02005424 wl_signal_init(&ec->output_destroyed_signal);
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02005425 wl_signal_init(&ec->output_moved_signal);
David Fort0de859e2016-05-27 23:22:57 +02005426 wl_signal_init(&ec->output_resized_signal);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005427 wl_signal_init(&ec->session_signal);
5428 ec->session_active = 1;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04005429
Casey Dahlin58ba1372012-04-19 22:50:08 -04005430 ec->output_id_pool = 0;
Giulio Camuffobab996e2014-10-12 00:24:25 +03005431 ec->repaint_msec = DEFAULT_REPAINT_WINDOW;
Casey Dahlin58ba1372012-04-19 22:50:08 -04005432
Jonas Ådahl94e2e2d2014-10-18 18:42:19 +02005433 ec->activate_serial = 1;
5434
Derek Foreman152254b2015-11-26 14:17:48 -06005435 if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 4,
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005436 ec, compositor_bind))
Giulio Camuffo459137b2014-10-11 23:56:24 +03005437 goto fail;
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05005438
Giulio Camuffo954f1832014-10-11 18:27:30 +03005439 if (!wl_global_create(ec->wl_display, &wl_subcompositor_interface, 1,
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005440 ec, bind_subcompositor))
Giulio Camuffo459137b2014-10-11 23:56:24 +03005441 goto fail;
Pekka Paalanene67858b2013-04-25 13:57:42 +03005442
Pekka Paalanene95ad5c2016-04-15 14:47:08 +03005443 if (!wl_global_create(ec->wl_display, &wp_viewporter_interface, 1,
Pekka Paalanen9c5a0d92016-04-15 16:42:49 +03005444 ec, bind_viewporter))
Giulio Camuffo459137b2014-10-11 23:56:24 +03005445 goto fail;
Jonny Lamb8ae35902013-11-26 18:19:45 +01005446
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02005447 if (!wl_global_create(ec->wl_display, &wp_presentation_interface, 1,
Pekka Paalanen31f7d782014-09-23 22:08:43 -04005448 ec, bind_presentation))
Giulio Camuffo459137b2014-10-11 23:56:24 +03005449 goto fail;
Pekka Paalanen31f7d782014-09-23 22:08:43 -04005450
Jonas Ådahl30d61d82014-10-22 21:21:17 +02005451 if (weston_input_init(ec) != 0)
5452 goto fail;
5453
Jason Ekstranda7af7042013-10-12 22:38:11 -05005454 wl_list_init(&ec->view_list);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02005455 wl_list_init(&ec->plane_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01005456 wl_list_init(&ec->layer_list);
5457 wl_list_init(&ec->seat_list);
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005458 wl_list_init(&ec->pending_output_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01005459 wl_list_init(&ec->output_list);
5460 wl_list_init(&ec->key_binding_list);
Daniel Stone96d47c02013-11-19 11:37:12 +01005461 wl_list_init(&ec->modifier_binding_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01005462 wl_list_init(&ec->button_binding_list);
Neil Robertsa28c6932013-10-03 16:43:04 +01005463 wl_list_init(&ec->touch_binding_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01005464 wl_list_init(&ec->axis_binding_list);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005465 wl_list_init(&ec->debug_binding_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01005466
Pekka Paalanen827b5d22016-06-29 11:54:26 +02005467 wl_list_init(&ec->plugin_api_list);
5468
Xiong Zhang97116532013-10-23 13:58:31 +08005469 weston_plane_init(&ec->primary_plane, ec, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02005470 weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04005471
Giulio Camuffo459137b2014-10-11 23:56:24 +03005472 wl_data_device_manager_init(ec->wl_display);
5473
5474 wl_display_init_shm(ec->wl_display);
5475
5476 loop = wl_display_get_event_loop(ec->wl_display);
5477 ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
Daniel Stone6847b852017-03-01 11:34:08 +00005478 ec->repaint_timer =
5479 wl_event_loop_add_timer(loop, output_repaint_timer_handler,
5480 ec);
Giulio Camuffo459137b2014-10-11 23:56:24 +03005481
Quentin Glidic82681572016-12-17 13:40:51 +01005482 weston_layer_init(&ec->fade_layer, ec);
5483 weston_layer_init(&ec->cursor_layer, ec);
5484
5485 weston_layer_set_position(&ec->fade_layer, WESTON_LAYER_POSITION_FADE);
5486 weston_layer_set_position(&ec->cursor_layer,
5487 WESTON_LAYER_POSITION_CURSOR);
Giulio Camuffo459137b2014-10-11 23:56:24 +03005488
5489 weston_compositor_add_debug_binding(ec, KEY_T,
5490 timeline_key_binding_handler, ec);
5491
Giulio Camuffo459137b2014-10-11 23:56:24 +03005492 return ec;
5493
5494fail:
5495 free(ec);
5496 return NULL;
5497}
5498
Benjamin Franzkeb8263022011-08-30 11:32:47 +02005499WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005500weston_compositor_shutdown(struct weston_compositor *ec)
Matt Roper361d2ad2011-08-29 13:52:23 -07005501{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005502 struct weston_output *output, *next;
Matt Roper361d2ad2011-08-29 13:52:23 -07005503
Pekka Paalanend1591ae2012-01-02 16:06:56 +02005504 wl_event_source_remove(ec->idle_source);
5505
Matt Roper361d2ad2011-08-29 13:52:23 -07005506 /* Destroy all outputs associated with this compositor */
Tiago Vignattib303a1d2011-12-18 22:27:40 +02005507 wl_list_for_each_safe(output, next, &ec->output_list, link)
Matt Roper361d2ad2011-08-29 13:52:23 -07005508 output->destroy(output);
Pekka Paalanen4738f3b2012-01-02 15:47:07 +02005509
Armin Krezovića01ab6d2016-09-30 14:11:02 +02005510 /* Destroy all pending outputs associated with this compositor */
5511 wl_list_for_each_safe(output, next, &ec->pending_output_list, link)
5512 output->destroy(output);
5513
Ander Conselvan de Oliveira18536762013-12-20 21:07:00 +02005514 if (ec->renderer)
5515 ec->renderer->destroy(ec);
5516
Daniel Stone325fc2d2012-05-30 16:31:58 +01005517 weston_binding_list_destroy_all(&ec->key_binding_list);
Ryo Munakata27135af2015-07-17 13:07:42 +09005518 weston_binding_list_destroy_all(&ec->modifier_binding_list);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005519 weston_binding_list_destroy_all(&ec->button_binding_list);
Neil Robertsa28c6932013-10-03 16:43:04 +01005520 weston_binding_list_destroy_all(&ec->touch_binding_list);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005521 weston_binding_list_destroy_all(&ec->axis_binding_list);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005522 weston_binding_list_destroy_all(&ec->debug_binding_list);
Pekka Paalanend1591ae2012-01-02 16:06:56 +02005523
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04005524 weston_plane_release(&ec->primary_plane);
Matt Roper361d2ad2011-08-29 13:52:23 -07005525}
5526
Kristian Høgsbergaf4f2aa2013-02-15 20:53:20 -05005527WL_EXPORT void
Frederic Plourdec336f062014-10-29 14:44:33 -04005528weston_compositor_exit_with_code(struct weston_compositor *compositor,
5529 int exit_code)
5530{
Pekka Paalanenf5ef88f2014-11-18 15:57:04 +02005531 if (compositor->exit_code == EXIT_SUCCESS)
5532 compositor->exit_code = exit_code;
5533
Giulio Camuffo459137b2014-10-11 23:56:24 +03005534 weston_compositor_exit(compositor);
Frederic Plourdec336f062014-10-29 14:44:33 -04005535}
5536
5537WL_EXPORT void
Giulio Camuffocdb4d292013-11-14 23:42:53 +01005538weston_compositor_set_default_pointer_grab(struct weston_compositor *ec,
5539 const struct weston_pointer_grab_interface *interface)
5540{
5541 struct weston_seat *seat;
5542
5543 ec->default_pointer_grab = interface;
5544 wl_list_for_each(seat, &ec->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -05005545 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
5546
5547 if (pointer)
5548 weston_pointer_set_default_grab(pointer, interface);
Giulio Camuffocdb4d292013-11-14 23:42:53 +01005549 }
5550}
5551
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04005552WL_EXPORT int
5553weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
5554 clockid_t clk_id)
5555{
5556 struct timespec ts;
5557
5558 if (clock_gettime(clk_id, &ts) < 0)
5559 return -1;
5560
5561 compositor->presentation_clock = clk_id;
5562
5563 return 0;
5564}
5565
5566/*
5567 * For choosing the software clock, when the display hardware or API
5568 * does not expose a compatible presentation timestamp.
5569 */
5570WL_EXPORT int
5571weston_compositor_set_presentation_clock_software(
5572 struct weston_compositor *compositor)
5573{
5574 /* In order of preference */
5575 static const clockid_t clocks[] = {
5576 CLOCK_MONOTONIC_RAW, /* no jumps, no crawling */
5577 CLOCK_MONOTONIC_COARSE, /* no jumps, may crawl, fast & coarse */
5578 CLOCK_MONOTONIC, /* no jumps, may crawl */
5579 CLOCK_REALTIME_COARSE, /* may jump and crawl, fast & coarse */
5580 CLOCK_REALTIME /* may jump and crawl */
5581 };
5582 unsigned i;
5583
5584 for (i = 0; i < ARRAY_LENGTH(clocks); i++)
5585 if (weston_compositor_set_presentation_clock(compositor,
5586 clocks[i]) == 0)
5587 return 0;
5588
5589 weston_log("Error: no suitable presentation clock available.\n");
5590
5591 return -1;
5592}
5593
Pekka Paalanen662f3842015-03-18 12:17:26 +02005594/** Read the current time from the Presentation clock
5595 *
5596 * \param compositor
5597 * \param ts[out] The current time.
5598 *
5599 * \note Reading the current time in user space is always imprecise to some
5600 * degree.
5601 *
5602 * This function is never meant to fail. If reading the clock does fail,
5603 * an error message is logged and a zero time is returned. Callers are not
5604 * supposed to detect or react to failures.
5605 */
5606WL_EXPORT void
5607weston_compositor_read_presentation_clock(
5608 const struct weston_compositor *compositor,
5609 struct timespec *ts)
5610{
5611 static bool warned;
5612 int ret;
5613
5614 ret = clock_gettime(compositor->presentation_clock, ts);
5615 if (ret < 0) {
5616 ts->tv_sec = 0;
5617 ts->tv_nsec = 0;
5618
5619 if (!warned)
5620 weston_log("Error: failure to read "
5621 "the presentation clock %#x: '%m' (%d)\n",
5622 compositor->presentation_clock, errno);
5623 warned = true;
5624 }
5625}
5626
Pekka Paalanen230f3b12014-09-29 14:18:40 -04005627/** Import dmabuf buffer into current renderer
5628 *
5629 * \param compositor
5630 * \param buffer the dmabuf buffer to import
5631 * \return true on usable buffers, false otherwise
5632 *
5633 * This function tests that the linux_dmabuf_buffer is usable
5634 * for the current renderer. Returns false on unusable buffers. Usually
5635 * usability is tested by importing the dmabufs for composition.
5636 *
5637 * This hook is also used for detecting if the renderer supports
5638 * dmabufs at all. If the renderer hook is NULL, dmabufs are not
5639 * supported.
5640 * */
5641WL_EXPORT bool
5642weston_compositor_import_dmabuf(struct weston_compositor *compositor,
5643 struct linux_dmabuf_buffer *buffer)
5644{
5645 struct weston_renderer *renderer;
5646
5647 renderer = compositor->renderer;
5648
5649 if (renderer->import_dmabuf == NULL)
5650 return false;
5651
5652 return renderer->import_dmabuf(compositor, buffer);
5653}
5654
Giulio Camuffocdb4d292013-11-14 23:42:53 +01005655WL_EXPORT void
Kristian Høgsbergaf4f2aa2013-02-15 20:53:20 -05005656weston_version(int *major, int *minor, int *micro)
5657{
5658 *major = WESTON_VERSION_MAJOR;
5659 *minor = WESTON_VERSION_MINOR;
5660 *micro = WESTON_VERSION_MICRO;
5661}
5662
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03005663WL_EXPORT void *
5664weston_load_module(const char *name, const char *entrypoint)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005665{
Derek Foreman3f86e502015-06-08 11:46:54 -05005666 const char *builddir = getenv("WESTON_BUILD_DIR");
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005667 char path[PATH_MAX];
5668 void *module, *init;
Daniel Stonebeb97e52016-11-28 12:13:54 +00005669 size_t len;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005670
U. Artie Eoff2e2384a2014-01-17 13:19:01 -08005671 if (name == NULL)
5672 return NULL;
5673
Derek Foreman3f86e502015-06-08 11:46:54 -05005674 if (name[0] != '/') {
5675 if (builddir)
Daniel Stonebeb97e52016-11-28 12:13:54 +00005676 len = snprintf(path, sizeof path, "%s/.libs/%s",
5677 builddir, name);
Derek Foreman3f86e502015-06-08 11:46:54 -05005678 else
Daniel Stonebeb97e52016-11-28 12:13:54 +00005679 len = snprintf(path, sizeof path, "%s/%s",
5680 LIBWESTON_MODULEDIR, name);
Derek Foreman3f86e502015-06-08 11:46:54 -05005681 } else {
Daniel Stonebeb97e52016-11-28 12:13:54 +00005682 len = snprintf(path, sizeof path, "%s", name);
Derek Foreman3f86e502015-06-08 11:46:54 -05005683 }
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005684
Daniel Stonebeb97e52016-11-28 12:13:54 +00005685 /* snprintf returns the length of the string it would've written,
5686 * _excluding_ the NUL byte. So even being equal to the size of
5687 * our buffer is an error here. */
5688 if (len >= sizeof path)
5689 return NULL;
5690
Kristian Høgsberga6813d22012-09-12 12:21:01 -04005691 module = dlopen(path, RTLD_NOW | RTLD_NOLOAD);
5692 if (module) {
5693 weston_log("Module '%s' already loaded\n", path);
5694 dlclose(module);
5695 return NULL;
5696 }
5697
Pekka Paalanen1b3c1ea2012-06-11 14:06:04 +03005698 weston_log("Loading module '%s'\n", path);
Kristian Høgsberg1acd9f82012-07-26 11:39:26 -04005699 module = dlopen(path, RTLD_NOW);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005700 if (!module) {
Pekka Paalanen1b3c1ea2012-06-11 14:06:04 +03005701 weston_log("Failed to load module: %s\n", dlerror());
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005702 return NULL;
5703 }
5704
5705 init = dlsym(module, entrypoint);
5706 if (!init) {
Pekka Paalanen1b3c1ea2012-06-11 14:06:04 +03005707 weston_log("Failed to lookup init function: %s\n", dlerror());
Rob Bradfordc9e64ab2012-12-05 18:47:10 +00005708 dlclose(module);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005709 return NULL;
5710 }
5711
5712 return init;
5713}
5714
Giulio Camuffo459137b2014-10-11 23:56:24 +03005715
5716/** Destroys the compositor.
5717 *
5718 * This function cleans up the compositor state and destroys it.
5719 *
5720 * \param compositor The compositor to be destroyed.
5721 */
5722WL_EXPORT void
5723weston_compositor_destroy(struct weston_compositor *compositor)
5724{
5725 /* prevent further rendering while shutting down */
5726 compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
5727
5728 wl_signal_emit(&compositor->destroy_signal, compositor);
5729
5730 weston_compositor_xkb_destroy(compositor);
5731
Giulio Camuffo2d24e642015-10-03 16:25:15 +03005732 if (compositor->backend)
5733 compositor->backend->destroy(compositor);
Pekka Paalanen827b5d22016-06-29 11:54:26 +02005734
5735 weston_plugin_api_destroy_list(compositor);
5736
Giulio Camuffo459137b2014-10-11 23:56:24 +03005737 free(compositor);
5738}
5739
5740/** Instruct the compositor to exit.
5741 *
5742 * This functions does not directly destroy the compositor object, it merely
5743 * command it to start the tear down process. It is not guaranteed that the
5744 * tear down will happen immediately.
5745 *
5746 * \param compositor The compositor to tear down.
5747 */
5748WL_EXPORT void
5749weston_compositor_exit(struct weston_compositor *compositor)
5750{
5751 compositor->exit(compositor);
5752}
5753
5754/** Return the user data stored in the compositor.
5755 *
5756 * This function returns the user data pointer set with user_data parameter
5757 * to the \ref weston_compositor_create function.
5758 */
5759WL_EXPORT void *
5760weston_compositor_get_user_data(struct weston_compositor *compositor)
5761{
5762 return compositor->user_data;
5763}
Pekka Paalanendd186732016-06-03 14:49:54 +03005764
Pekka Paalanen50dbf382016-06-03 15:23:46 +03005765static const char * const backend_map[] = {
5766 [WESTON_BACKEND_DRM] = "drm-backend.so",
5767 [WESTON_BACKEND_FBDEV] = "fbdev-backend.so",
5768 [WESTON_BACKEND_HEADLESS] = "headless-backend.so",
5769 [WESTON_BACKEND_RDP] = "rdp-backend.so",
5770 [WESTON_BACKEND_WAYLAND] = "wayland-backend.so",
5771 [WESTON_BACKEND_X11] = "x11-backend.so",
5772};
5773
Pekka Paalanendd186732016-06-03 14:49:54 +03005774/** Load a backend into a weston_compositor
5775 *
5776 * A backend must be loaded to make a weston_compositor work. A backend
5777 * provides input and output capabilities, and determines the renderer to use.
5778 *
5779 * \param compositor A compositor that has not had a backend loaded yet.
5780 * \param backend Name of the backend file.
5781 * \param config_base A pointer to a backend-specific configuration
5782 * structure's 'base' member.
5783 *
5784 * \return 0 on success, or -1 on error.
5785 */
5786WL_EXPORT int
5787weston_compositor_load_backend(struct weston_compositor *compositor,
Pekka Paalanen50dbf382016-06-03 15:23:46 +03005788 enum weston_compositor_backend backend,
Pekka Paalanendd186732016-06-03 14:49:54 +03005789 struct weston_backend_config *config_base)
5790{
5791 int (*backend_init)(struct weston_compositor *c,
Pekka Paalanendd186732016-06-03 14:49:54 +03005792 struct weston_backend_config *config_base);
5793
Pekka Paalanend7e35112017-08-29 17:04:12 +03005794 if (compositor->backend) {
5795 weston_log("Error: attempt to load a backend when one is already loaded\n");
5796 return -1;
5797 }
5798
Quentin Glidic887c0182016-07-10 11:00:53 +02005799 if (backend >= ARRAY_LENGTH(backend_map))
Pekka Paalanen50dbf382016-06-03 15:23:46 +03005800 return -1;
5801
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01005802 backend_init = weston_load_module(backend_map[backend], "weston_backend_init");
Pekka Paalanendd186732016-06-03 14:49:54 +03005803 if (!backend_init)
5804 return -1;
5805
Pekka Paalanend7e35112017-08-29 17:04:12 +03005806 if (backend_init(compositor, config_base) < 0) {
5807 compositor->backend = NULL;
5808 return -1;
5809 }
5810
5811 return 0;
Pekka Paalanendd186732016-06-03 14:49:54 +03005812}
Giulio Camuffo9c764df2016-06-29 11:54:27 +02005813
5814WL_EXPORT int
5815weston_compositor_load_xwayland(struct weston_compositor *compositor)
5816{
Quentin Glidic3d7ca3b2016-12-02 14:20:35 +01005817 int (*module_init)(struct weston_compositor *ec);
Giulio Camuffo9c764df2016-06-29 11:54:27 +02005818
Quentin Glidic3d7ca3b2016-12-02 14:20:35 +01005819 module_init = weston_load_module("xwayland.so", "weston_module_init");
Giulio Camuffo9c764df2016-06-29 11:54:27 +02005820 if (!module_init)
5821 return -1;
Quentin Glidic3d7ca3b2016-12-02 14:20:35 +01005822 if (module_init(compositor) < 0)
Giulio Camuffo9c764df2016-06-29 11:54:27 +02005823 return -1;
5824 return 0;
5825}