blob: 40d8bafd948fd71bd49348989d4255bec9ed9fcb [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"
Jonny Lamb8ae35902013-11-26 18:19:45 +010057#include "scaler-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"
Pekka Paalanenaa21f622015-07-03 15:44:50 +030061#include "shared/timespec-util.h"
Kristian Høgsberga411c8b2012-06-08 16:16:52 -040062#include "git-version.h"
Kristian Høgsbergaf4f2aa2013-02-15 20:53:20 -050063#include "version.h"
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050064
Pekka Paalanen0513a952014-05-21 16:17:27 +030065#define DEFAULT_REPAINT_WINDOW 7 /* milliseconds */
66
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -020067static void
Alexander Larsson0b135062013-05-28 16:23:36 +020068weston_output_transform_scale_init(struct weston_output *output,
69 uint32_t transform, uint32_t scale);
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -020070
Rob Bradford27b17932013-06-26 18:08:46 +010071static void
Jason Ekstranda7af7042013-10-12 22:38:11 -050072weston_compositor_build_view_list(struct weston_compositor *compositor);
Rob Bradford27b17932013-06-26 18:08:46 +010073
Derek Foreman6ae7bc92014-11-04 10:47:33 -060074static void weston_mode_switch_finish(struct weston_output *output,
75 int mode_changed,
76 int scale_changed)
Alex Wu2dda6042012-04-17 17:20:47 +080077{
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -020078 struct weston_seat *seat;
Hardening57388e42013-09-18 23:56:36 +020079 struct wl_resource *resource;
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -020080 pixman_region32_t old_output_region;
Derek Foreman41bdc272014-11-05 13:26:57 -060081 int version;
Alexander Larsson355748e2013-05-28 16:23:38 +020082
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -020083 pixman_region32_init(&old_output_region);
84 pixman_region32_copy(&old_output_region, &output->region);
85
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -020086 /* Update output region and transformation matrix */
Hardeningff39efa2013-09-18 23:56:35 +020087 weston_output_transform_scale_init(output, output->transform, output->current_scale);
Ander Conselvan de Oliveira5c38ef42012-12-14 13:37:25 -020088
89 pixman_region32_init(&output->previous_damage);
90 pixman_region32_init_rect(&output->region, output->x, output->y,
91 output->width, output->height);
92
93 weston_output_update_matrix(output);
94
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -020095 /* If a pointer falls outside the outputs new geometry, move it to its
96 * lower-right corner */
97 wl_list_for_each(seat, &output->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -050098 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
Ander Conselvan de Oliveira2bbb2b82012-12-14 13:37:26 -020099 int32_t x, y;
100
101 if (!pointer)
102 continue;
103
104 x = wl_fixed_to_int(pointer->x);
105 y = wl_fixed_to_int(pointer->y);
106
107 if (!pixman_region32_contains_point(&old_output_region,
108 x, y, NULL) ||
109 pixman_region32_contains_point(&output->region,
110 x, y, NULL))
111 continue;
112
113 if (x >= output->x + output->width)
114 x = output->x + output->width - 1;
115 if (y >= output->y + output->height)
116 y = output->y + output->height - 1;
117
118 pointer->x = wl_fixed_from_int(x);
119 pointer->y = wl_fixed_from_int(y);
120 }
121
122 pixman_region32_fini(&old_output_region);
123
Derek Foremandd4cd332014-11-10 10:29:59 -0600124 if (!mode_changed && !scale_changed)
125 return;
126
Hardening57388e42013-09-18 23:56:36 +0200127 /* notify clients of the changes */
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600128 wl_resource_for_each(resource, &output->resource_list) {
129 if (mode_changed) {
130 wl_output_send_mode(resource,
131 output->current_mode->flags,
132 output->current_mode->width,
133 output->current_mode->height,
134 output->current_mode->refresh);
135 }
Hardening57388e42013-09-18 23:56:36 +0200136
Derek Foreman41bdc272014-11-05 13:26:57 -0600137 version = wl_resource_get_version(resource);
138 if (version >= WL_OUTPUT_SCALE_SINCE_VERSION && scale_changed)
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600139 wl_output_send_scale(resource, output->current_scale);
Hardening57388e42013-09-18 23:56:36 +0200140
Derek Foreman41bdc272014-11-05 13:26:57 -0600141 if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
142 wl_output_send_done(resource);
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600143 }
144}
145
146WL_EXPORT int
147weston_output_mode_set_native(struct weston_output *output,
148 struct weston_mode *mode,
149 int32_t scale)
150{
151 int ret;
152 int mode_changed = 0, scale_changed = 0;
153
154 if (!output->switch_mode)
155 return -1;
156
157 if (!output->original_mode) {
158 mode_changed = 1;
159 ret = output->switch_mode(output, mode);
160 if (ret < 0)
161 return ret;
162 if (output->current_scale != scale) {
163 scale_changed = 1;
164 output->current_scale = scale;
Hardening57388e42013-09-18 23:56:36 +0200165 }
166 }
167
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600168 output->native_mode = mode;
169 output->native_scale = scale;
170
171 weston_mode_switch_finish(output, mode_changed, scale_changed);
172
173 return 0;
174}
175
176WL_EXPORT int
177weston_output_mode_switch_to_native(struct weston_output *output)
178{
179 int ret;
180 int mode_changed = 0, scale_changed = 0;
181
182 if (!output->switch_mode)
183 return -1;
184
185 if (!output->original_mode) {
186 weston_log("already in the native mode\n");
187 return -1;
188 }
189 /* the non fullscreen clients haven't seen a mode set since we
190 * switched into a temporary, so we need to notify them if the
191 * mode at that time is different from the native mode now.
192 */
193 mode_changed = (output->original_mode != output->native_mode);
194 scale_changed = (output->original_scale != output->native_scale);
195
196 ret = output->switch_mode(output, output->native_mode);
197 if (ret < 0)
198 return ret;
199
200 output->current_scale = output->native_scale;
201
202 output->original_mode = NULL;
203 output->original_scale = 0;
204
205 weston_mode_switch_finish(output, mode_changed, scale_changed);
206
207 return 0;
208}
209
210WL_EXPORT int
211weston_output_mode_switch_to_temporary(struct weston_output *output,
212 struct weston_mode *mode,
213 int32_t scale)
214{
215 int ret;
216
217 if (!output->switch_mode)
218 return -1;
219
220 /* original_mode is the last mode non full screen clients have seen,
221 * so we shouldn't change it if we already have one set.
222 */
223 if (!output->original_mode) {
224 output->original_mode = output->native_mode;
225 output->original_scale = output->native_scale;
226 }
227 ret = output->switch_mode(output, mode);
228 if (ret < 0)
229 return ret;
230
231 output->current_scale = scale;
232
233 weston_mode_switch_finish(output, 0, 0);
234
235 return 0;
Alex Wu2dda6042012-04-17 17:20:47 +0800236}
237
Benjamin Franzke06286262011-05-06 19:12:33 +0200238static void
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200239child_client_exec(int sockfd, const char *path)
240{
Kristian Høgsbergd42b0c92011-12-08 10:19:40 -0500241 int clientfd;
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200242 char s[32];
Pekka Paalanenc47ddfd2011-12-08 10:44:56 +0200243 sigset_t allsigs;
244
245 /* do not give our signal mask to the new process */
246 sigfillset(&allsigs);
247 sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200248
Alexandru DAMIAN840a4212013-09-25 14:47:47 +0100249 /* Launch clients as the user. Do not lauch clients with wrong euid.*/
250 if (seteuid(getuid()) == -1) {
251 weston_log("compositor: failed seteuid\n");
252 return;
253 }
Kristian Høgsbergeb764842012-01-31 22:17:25 -0500254
Kristian Høgsbergd42b0c92011-12-08 10:19:40 -0500255 /* SOCK_CLOEXEC closes both ends, so we dup the fd to get a
256 * non-CLOEXEC fd to pass through exec. */
257 clientfd = dup(sockfd);
258 if (clientfd == -1) {
Martin Minarik6d118362012-06-07 18:01:59 +0200259 weston_log("compositor: dup failed: %m\n");
Kristian Høgsbergd42b0c92011-12-08 10:19:40 -0500260 return;
261 }
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200262
Kristian Høgsbergd42b0c92011-12-08 10:19:40 -0500263 snprintf(s, sizeof s, "%d", clientfd);
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200264 setenv("WAYLAND_SOCKET", s, 1);
265
266 if (execl(path, path, NULL) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +0200267 weston_log("compositor: executing '%s' failed: %m\n",
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200268 path);
269}
270
271WL_EXPORT struct wl_client *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500272weston_client_launch(struct weston_compositor *compositor,
273 struct weston_process *proc,
274 const char *path,
275 weston_process_cleanup_func_t cleanup)
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200276{
277 int sv[2];
278 pid_t pid;
279 struct wl_client *client;
280
Pekka Paalanendf1fd362012-08-06 14:57:03 +0300281 weston_log("launching '%s'\n", path);
282
Pekka Paalanen51aaf642012-05-30 15:53:41 +0300283 if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200284 weston_log("weston_client_launch: "
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200285 "socketpair failed while launching '%s': %m\n",
286 path);
287 return NULL;
288 }
289
290 pid = fork();
291 if (pid == -1) {
292 close(sv[0]);
293 close(sv[1]);
Martin Minarik6d118362012-06-07 18:01:59 +0200294 weston_log("weston_client_launch: "
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200295 "fork failed while launching '%s': %m\n", path);
296 return NULL;
297 }
298
299 if (pid == 0) {
300 child_client_exec(sv[1], path);
U. Artie Eoff3b64d622013-06-03 16:22:31 -0700301 _exit(-1);
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200302 }
303
304 close(sv[1]);
305
306 client = wl_client_create(compositor->wl_display, sv[0]);
307 if (!client) {
308 close(sv[0]);
Martin Minarik6d118362012-06-07 18:01:59 +0200309 weston_log("weston_client_launch: "
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200310 "wl_client_create failed while launching '%s'.\n",
311 path);
312 return NULL;
313 }
314
315 proc->pid = pid;
316 proc->cleanup = cleanup;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500317 weston_watch_process(proc);
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200318
319 return client;
320}
321
Pekka Paalanen9c1ac7b2014-08-27 12:03:38 +0300322struct process_info {
323 struct weston_process proc;
324 char *path;
325};
326
327static void
328process_handle_sigchld(struct weston_process *process, int status)
329{
330 struct process_info *pinfo =
331 container_of(process, struct process_info, proc);
332
333 /*
334 * There are no guarantees whether this runs before or after
335 * the wl_client destructor.
336 */
337
338 if (WIFEXITED(status)) {
339 weston_log("%s exited with status %d\n", pinfo->path,
340 WEXITSTATUS(status));
341 } else if (WIFSIGNALED(status)) {
342 weston_log("%s died on signal %d\n", pinfo->path,
343 WTERMSIG(status));
344 } else {
345 weston_log("%s disappeared\n", pinfo->path);
346 }
347
348 free(pinfo->path);
349 free(pinfo);
350}
351
352WL_EXPORT struct wl_client *
353weston_client_start(struct weston_compositor *compositor, const char *path)
354{
355 struct process_info *pinfo;
356 struct wl_client *client;
357
358 pinfo = zalloc(sizeof *pinfo);
359 if (!pinfo)
360 return NULL;
361
362 pinfo->path = strdup(path);
363 if (!pinfo->path)
364 goto out_free;
365
366 client = weston_client_launch(compositor, &pinfo->proc, path,
367 process_handle_sigchld);
368 if (!client)
369 goto out_str;
370
371 return client;
372
373out_str:
374 free(pinfo->path);
375
376out_free:
377 free(pinfo);
378
379 return NULL;
380}
381
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200382static void
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +0300383region_init_infinite(pixman_region32_t *region)
384{
385 pixman_region32_init_rect(region, INT32_MIN, INT32_MIN,
386 UINT32_MAX, UINT32_MAX);
387}
388
Pekka Paalanene67858b2013-04-25 13:57:42 +0300389static struct weston_subsurface *
390weston_surface_to_subsurface(struct weston_surface *surface);
391
Jason Ekstranda7af7042013-10-12 22:38:11 -0500392WL_EXPORT struct weston_view *
393weston_view_create(struct weston_surface *surface)
394{
395 struct weston_view *view;
396
Bryce Harringtonde16d892014-11-20 22:21:57 -0800397 view = zalloc(sizeof *view);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500398 if (view == NULL)
399 return NULL;
400
401 view->surface = surface;
402
Jason Ekstranda7af7042013-10-12 22:38:11 -0500403 /* Assign to surface */
404 wl_list_insert(&surface->views, &view->surface_link);
405
406 wl_signal_init(&view->destroy_signal);
407 wl_list_init(&view->link);
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300408 wl_list_init(&view->layer_link.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500409
Jason Ekstranda7af7042013-10-12 22:38:11 -0500410 pixman_region32_init(&view->clip);
411
412 view->alpha = 1.0;
413 pixman_region32_init(&view->transform.opaque);
414
415 wl_list_init(&view->geometry.transformation_list);
416 wl_list_insert(&view->geometry.transformation_list,
417 &view->transform.position.link);
418 weston_matrix_init(&view->transform.position.matrix);
419 wl_list_init(&view->geometry.child_list);
Pekka Paalanen380adf52015-02-16 14:39:11 +0200420 pixman_region32_init(&view->geometry.scissor);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500421 pixman_region32_init(&view->transform.boundingbox);
422 view->transform.dirty = 1;
423
Jason Ekstranda7af7042013-10-12 22:38:11 -0500424 return view;
425}
426
Jason Ekstrand108865d2014-06-26 10:04:49 -0700427struct weston_frame_callback {
428 struct wl_resource *resource;
429 struct wl_list link;
430};
431
Pekka Paalanen133e4392014-09-23 22:08:46 -0400432struct weston_presentation_feedback {
433 struct wl_resource *resource;
434
435 /* XXX: could use just wl_resource_get_link() instead */
436 struct wl_list link;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +0200437
438 /* The per-surface feedback flags */
439 uint32_t psf_flags;
Pekka Paalanen133e4392014-09-23 22:08:46 -0400440};
441
442static void
443weston_presentation_feedback_discard(
444 struct weston_presentation_feedback *feedback)
445{
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200446 wp_presentation_feedback_send_discarded(feedback->resource);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400447 wl_resource_destroy(feedback->resource);
448}
449
450static void
451weston_presentation_feedback_discard_list(struct wl_list *list)
452{
453 struct weston_presentation_feedback *feedback, *tmp;
454
455 wl_list_for_each_safe(feedback, tmp, list, link)
456 weston_presentation_feedback_discard(feedback);
457}
458
459static void
460weston_presentation_feedback_present(
461 struct weston_presentation_feedback *feedback,
462 struct weston_output *output,
463 uint32_t refresh_nsec,
464 const struct timespec *ts,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200465 uint64_t seq,
466 uint32_t flags)
Pekka Paalanen133e4392014-09-23 22:08:46 -0400467{
468 struct wl_client *client = wl_resource_get_client(feedback->resource);
469 struct wl_resource *o;
470 uint64_t secs;
Pekka Paalanen133e4392014-09-23 22:08:46 -0400471
472 wl_resource_for_each(o, &output->resource_list) {
473 if (wl_resource_get_client(o) != client)
474 continue;
475
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200476 wp_presentation_feedback_send_sync_output(feedback->resource, o);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400477 }
478
479 secs = ts->tv_sec;
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200480 wp_presentation_feedback_send_presented(feedback->resource,
481 secs >> 32, secs & 0xffffffff,
482 ts->tv_nsec,
483 refresh_nsec,
484 seq >> 32, seq & 0xffffffff,
485 flags | feedback->psf_flags);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400486 wl_resource_destroy(feedback->resource);
487}
488
489static void
490weston_presentation_feedback_present_list(struct wl_list *list,
491 struct weston_output *output,
492 uint32_t refresh_nsec,
493 const struct timespec *ts,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200494 uint64_t seq,
495 uint32_t flags)
Pekka Paalanen133e4392014-09-23 22:08:46 -0400496{
497 struct weston_presentation_feedback *feedback, *tmp;
498
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200499 assert(!(flags & WP_PRESENTATION_FEEDBACK_INVALID) ||
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200500 wl_list_empty(list));
501
Pekka Paalanen133e4392014-09-23 22:08:46 -0400502 wl_list_for_each_safe(feedback, tmp, list, link)
503 weston_presentation_feedback_present(feedback, output,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200504 refresh_nsec, ts, seq,
505 flags);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400506}
507
Jason Ekstrand7b982072014-05-20 14:33:03 -0500508static void
509surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
510{
511 struct weston_surface_state *state =
512 container_of(listener, struct weston_surface_state,
513 buffer_destroy_listener);
514
515 state->buffer = NULL;
516}
517
518static void
519weston_surface_state_init(struct weston_surface_state *state)
520{
521 state->newly_attached = 0;
522 state->buffer = NULL;
523 state->buffer_destroy_listener.notify =
524 surface_state_handle_buffer_destroy;
525 state->sx = 0;
526 state->sy = 0;
527
Derek Foreman152254b2015-11-26 14:17:48 -0600528 pixman_region32_init(&state->damage_surface);
529 pixman_region32_init(&state->damage_buffer);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500530 pixman_region32_init(&state->opaque);
531 region_init_infinite(&state->input);
532
533 wl_list_init(&state->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400534 wl_list_init(&state->feedback_list);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500535
536 state->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
537 state->buffer_viewport.buffer.scale = 1;
538 state->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
539 state->buffer_viewport.surface.width = -1;
540 state->buffer_viewport.changed = 0;
541}
542
543static void
544weston_surface_state_fini(struct weston_surface_state *state)
545{
546 struct weston_frame_callback *cb, *next;
547
548 wl_list_for_each_safe(cb, next,
549 &state->frame_callback_list, link)
550 wl_resource_destroy(cb->resource);
551
Pekka Paalanen133e4392014-09-23 22:08:46 -0400552 weston_presentation_feedback_discard_list(&state->feedback_list);
553
Jason Ekstrand7b982072014-05-20 14:33:03 -0500554 pixman_region32_fini(&state->input);
555 pixman_region32_fini(&state->opaque);
Derek Foreman152254b2015-11-26 14:17:48 -0600556 pixman_region32_fini(&state->damage_surface);
557 pixman_region32_fini(&state->damage_buffer);
Jason Ekstrand7b982072014-05-20 14:33:03 -0500558
559 if (state->buffer)
560 wl_list_remove(&state->buffer_destroy_listener.link);
561 state->buffer = NULL;
562}
563
564static void
565weston_surface_state_set_buffer(struct weston_surface_state *state,
566 struct weston_buffer *buffer)
567{
568 if (state->buffer == buffer)
569 return;
570
571 if (state->buffer)
572 wl_list_remove(&state->buffer_destroy_listener.link);
573 state->buffer = buffer;
574 if (state->buffer)
575 wl_signal_add(&state->buffer->destroy_signal,
576 &state->buffer_destroy_listener);
577}
578
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500579WL_EXPORT struct weston_surface *
Kristian Høgsberg18c93002012-01-27 11:58:31 -0500580weston_surface_create(struct weston_compositor *compositor)
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500581{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500582 struct weston_surface *surface;
Kristian Høgsberg77fb1672010-08-16 10:38:29 -0400583
Bryce Harringtonde16d892014-11-20 22:21:57 -0800584 surface = zalloc(sizeof *surface);
Kristian Høgsberg77fb1672010-08-16 10:38:29 -0400585 if (surface == NULL)
586 return NULL;
587
Jason Ekstrand26ed73c2013-06-06 22:34:41 -0500588 wl_signal_init(&surface->destroy_signal);
589
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500590 surface->compositor = compositor;
Giulio Camuffo13b85bd2013-08-13 23:10:14 +0200591 surface->ref_count = 1;
Kristian Høgsberg27803c62010-06-06 22:23:21 -0400592
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200593 surface->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
594 surface->buffer_viewport.buffer.scale = 1;
Pekka Paalanenf0cad482014-03-14 14:38:16 +0200595 surface->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
596 surface->buffer_viewport.surface.width = -1;
Jason Ekstrand7b982072014-05-20 14:33:03 -0500597
598 weston_surface_state_init(&surface->pending);
599
Kristian Høgsberg20300ba2011-06-23 20:29:12 -0400600 pixman_region32_init(&surface->damage);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -0500601 pixman_region32_init(&surface->opaque);
Pekka Paalanen8ec4ab62012-10-10 12:49:32 +0300602 region_init_infinite(&surface->input);
Kristian Høgsberg20300ba2011-06-23 20:29:12 -0400603
Jason Ekstranda7af7042013-10-12 22:38:11 -0500604 wl_list_init(&surface->views);
605
606 wl_list_init(&surface->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -0400607 wl_list_init(&surface->feedback_list);
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500608
Pekka Paalanene67858b2013-04-25 13:57:42 +0300609 wl_list_init(&surface->subsurface_list);
610 wl_list_init(&surface->subsurface_list_pending);
611
Jason Ekstrand1e059042014-10-16 10:55:19 -0500612 weston_matrix_init(&surface->buffer_to_surface_matrix);
613 weston_matrix_init(&surface->surface_to_buffer_matrix);
614
Kristian Høgsberg77fb1672010-08-16 10:38:29 -0400615 return surface;
Kristian Høgsberg54879822008-11-23 17:07:32 -0500616}
617
Alex Wu8811bf92012-02-28 18:07:54 +0800618WL_EXPORT void
Kristian Høgsbergbbeefb02012-01-26 10:00:23 -0500619weston_surface_set_color(struct weston_surface *surface,
John Kåre Alsaker490d02a2012-09-30 02:57:21 +0200620 float red, float green, float blue, float alpha)
Kristian Høgsbergbbeefb02012-01-26 10:00:23 -0500621{
John Kåre Alsaker878f4492012-11-13 19:10:23 +0100622 surface->compositor->renderer->surface_set_color(surface, red, green, blue, alpha);
Kristian Høgsbergbbeefb02012-01-26 10:00:23 -0500623}
624
Kristian Høgsberge4c1a5f2012-06-18 13:17:32 -0400625WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500626weston_view_to_global_float(struct weston_view *view,
627 float sx, float sy, float *x, float *y)
Pekka Paalanenece8a012012-02-08 15:23:15 +0200628{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500629 if (view->transform.enabled) {
Pekka Paalanenece8a012012-02-08 15:23:15 +0200630 struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };
631
Jason Ekstranda7af7042013-10-12 22:38:11 -0500632 weston_matrix_transform(&view->transform.matrix, &v);
Pekka Paalanenece8a012012-02-08 15:23:15 +0200633
634 if (fabsf(v.f[3]) < 1e-6) {
Martin Minarik6d118362012-06-07 18:01:59 +0200635 weston_log("warning: numerical instability in "
Scott Moreau088c62e2013-02-11 04:45:38 -0700636 "%s(), divisor = %g\n", __func__,
Pekka Paalanenece8a012012-02-08 15:23:15 +0200637 v.f[3]);
638 *x = 0;
639 *y = 0;
640 return;
641 }
642
643 *x = v.f[0] / v.f[3];
644 *y = v.f[1] / v.f[3];
645 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500646 *x = sx + view->geometry.x;
647 *y = sy + view->geometry.y;
Pekka Paalanenece8a012012-02-08 15:23:15 +0200648 }
649}
650
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500651WL_EXPORT void
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200652weston_transformed_coord(int width, int height,
653 enum wl_output_transform transform,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200654 int32_t scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200655 float sx, float sy, float *bx, float *by)
656{
657 switch (transform) {
658 case WL_OUTPUT_TRANSFORM_NORMAL:
659 default:
660 *bx = sx;
661 *by = sy;
662 break;
663 case WL_OUTPUT_TRANSFORM_FLIPPED:
664 *bx = width - sx;
665 *by = sy;
666 break;
667 case WL_OUTPUT_TRANSFORM_90:
668 *bx = height - sy;
669 *by = sx;
670 break;
671 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
672 *bx = height - sy;
673 *by = width - sx;
674 break;
675 case WL_OUTPUT_TRANSFORM_180:
676 *bx = width - sx;
677 *by = height - sy;
678 break;
679 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
680 *bx = sx;
681 *by = height - sy;
682 break;
683 case WL_OUTPUT_TRANSFORM_270:
684 *bx = sy;
685 *by = width - sx;
686 break;
687 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
688 *bx = sy;
689 *by = sx;
690 break;
691 }
Alexander Larsson4ea95522013-05-22 14:41:37 +0200692
693 *bx *= scale;
694 *by *= scale;
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200695}
696
697WL_EXPORT pixman_box32_t
698weston_transformed_rect(int width, int height,
699 enum wl_output_transform transform,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200700 int32_t scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200701 pixman_box32_t rect)
702{
703 float x1, x2, y1, y2;
704
705 pixman_box32_t ret;
706
Alexander Larsson4ea95522013-05-22 14:41:37 +0200707 weston_transformed_coord(width, height, transform, scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200708 rect.x1, rect.y1, &x1, &y1);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200709 weston_transformed_coord(width, height, transform, scale,
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200710 rect.x2, rect.y2, &x2, &y2);
711
712 if (x1 <= x2) {
713 ret.x1 = x1;
714 ret.x2 = x2;
715 } else {
716 ret.x1 = x2;
717 ret.x2 = x1;
718 }
719
720 if (y1 <= y2) {
721 ret.y1 = y1;
722 ret.y2 = y2;
723 } else {
724 ret.y1 = y2;
725 ret.y2 = y1;
726 }
727
728 return ret;
729}
730
Derek Foremanbc9a61c2015-11-18 16:32:30 -0600731/** Transform a region by a matrix, restricted to axis-aligned transformations
732 *
733 * Warning: This function does not work for projective, affine, or matrices
734 * that encode arbitrary rotations. Only 90-degree step rotations are
735 * supported.
736 */
737WL_EXPORT void
738weston_matrix_transform_region(pixman_region32_t *dest,
739 struct weston_matrix *matrix,
740 pixman_region32_t *src)
741{
742 pixman_box32_t *src_rects, *dest_rects;
743 int nrects, i;
744
745 src_rects = pixman_region32_rectangles(src, &nrects);
746 dest_rects = malloc(nrects * sizeof(*dest_rects));
747 if (!dest_rects)
748 return;
749
750 for (i = 0; i < nrects; i++) {
751 struct weston_vector vec1 = {{
752 src_rects[i].x1, src_rects[i].y1, 0, 1
753 }};
754 weston_matrix_transform(matrix, &vec1);
755 vec1.f[0] /= vec1.f[3];
756 vec1.f[1] /= vec1.f[3];
757
758 struct weston_vector vec2 = {{
759 src_rects[i].x2, src_rects[i].y2, 0, 1
760 }};
761 weston_matrix_transform(matrix, &vec2);
762 vec2.f[0] /= vec2.f[3];
763 vec2.f[1] /= vec2.f[3];
764
765 if (vec1.f[0] < vec2.f[0]) {
766 dest_rects[i].x1 = floor(vec1.f[0]);
767 dest_rects[i].x2 = ceil(vec2.f[0]);
768 } else {
769 dest_rects[i].x1 = floor(vec2.f[0]);
770 dest_rects[i].x2 = ceil(vec1.f[0]);
771 }
772
Derek Foremanbc9a61c2015-11-18 16:32:30 -0600773 if (vec1.f[1] < vec2.f[1]) {
774 dest_rects[i].y1 = floor(vec1.f[1]);
775 dest_rects[i].y2 = ceil(vec2.f[1]);
776 } else {
777 dest_rects[i].y1 = floor(vec2.f[1]);
778 dest_rects[i].y2 = ceil(vec1.f[1]);
779 }
780 }
781
782 pixman_region32_clear(dest);
783 pixman_region32_init_rects(dest, dest_rects, nrects);
784 free(dest_rects);
785}
786
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +0200787WL_EXPORT void
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500788weston_transformed_region(int width, int height,
789 enum wl_output_transform transform,
790 int32_t scale,
791 pixman_region32_t *src, pixman_region32_t *dest)
792{
793 pixman_box32_t *src_rects, *dest_rects;
794 int nrects, i;
795
796 if (transform == WL_OUTPUT_TRANSFORM_NORMAL && scale == 1) {
797 if (src != dest)
798 pixman_region32_copy(dest, src);
799 return;
800 }
801
802 src_rects = pixman_region32_rectangles(src, &nrects);
803 dest_rects = malloc(nrects * sizeof(*dest_rects));
804 if (!dest_rects)
805 return;
806
807 if (transform == WL_OUTPUT_TRANSFORM_NORMAL) {
808 memcpy(dest_rects, src_rects, nrects * sizeof(*dest_rects));
809 } else {
810 for (i = 0; i < nrects; i++) {
811 switch (transform) {
812 default:
813 case WL_OUTPUT_TRANSFORM_NORMAL:
814 dest_rects[i].x1 = src_rects[i].x1;
815 dest_rects[i].y1 = src_rects[i].y1;
816 dest_rects[i].x2 = src_rects[i].x2;
817 dest_rects[i].y2 = src_rects[i].y2;
818 break;
819 case WL_OUTPUT_TRANSFORM_90:
820 dest_rects[i].x1 = height - src_rects[i].y2;
821 dest_rects[i].y1 = src_rects[i].x1;
822 dest_rects[i].x2 = height - src_rects[i].y1;
823 dest_rects[i].y2 = src_rects[i].x2;
824 break;
825 case WL_OUTPUT_TRANSFORM_180:
826 dest_rects[i].x1 = width - src_rects[i].x2;
827 dest_rects[i].y1 = height - src_rects[i].y2;
828 dest_rects[i].x2 = width - src_rects[i].x1;
829 dest_rects[i].y2 = height - src_rects[i].y1;
830 break;
831 case WL_OUTPUT_TRANSFORM_270:
832 dest_rects[i].x1 = src_rects[i].y1;
833 dest_rects[i].y1 = width - src_rects[i].x2;
834 dest_rects[i].x2 = src_rects[i].y2;
835 dest_rects[i].y2 = width - src_rects[i].x1;
836 break;
837 case WL_OUTPUT_TRANSFORM_FLIPPED:
838 dest_rects[i].x1 = width - src_rects[i].x2;
839 dest_rects[i].y1 = src_rects[i].y1;
840 dest_rects[i].x2 = width - src_rects[i].x1;
841 dest_rects[i].y2 = src_rects[i].y2;
842 break;
843 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
844 dest_rects[i].x1 = height - src_rects[i].y2;
845 dest_rects[i].y1 = width - src_rects[i].x2;
846 dest_rects[i].x2 = height - src_rects[i].y1;
847 dest_rects[i].y2 = width - src_rects[i].x1;
848 break;
849 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
850 dest_rects[i].x1 = src_rects[i].x1;
851 dest_rects[i].y1 = height - src_rects[i].y2;
852 dest_rects[i].x2 = src_rects[i].x2;
853 dest_rects[i].y2 = height - src_rects[i].y1;
854 break;
855 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
856 dest_rects[i].x1 = src_rects[i].y1;
857 dest_rects[i].y1 = src_rects[i].x1;
858 dest_rects[i].x2 = src_rects[i].y2;
859 dest_rects[i].y2 = src_rects[i].x2;
860 break;
861 }
862 }
863 }
864
865 if (scale != 1) {
866 for (i = 0; i < nrects; i++) {
867 dest_rects[i].x1 *= scale;
868 dest_rects[i].x2 *= scale;
869 dest_rects[i].y1 *= scale;
870 dest_rects[i].y2 *= scale;
871 }
872 }
873
874 pixman_region32_clear(dest);
875 pixman_region32_init_rects(dest, dest_rects, nrects);
876 free(dest_rects);
877}
878
Jonny Lamb74130762013-11-26 18:19:46 +0100879static void
880scaler_surface_to_buffer(struct weston_surface *surface,
881 float sx, float sy, float *bx, float *by)
882{
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200883 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200884 double src_width, src_height;
885 double src_x, src_y;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200886
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200887 if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
888 if (vp->surface.width == -1) {
889 *bx = sx;
890 *by = sy;
891 return;
892 }
Jonny Lamb74130762013-11-26 18:19:46 +0100893
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200894 src_x = 0.0;
895 src_y = 0.0;
896 src_width = surface->width_from_buffer;
897 src_height = surface->height_from_buffer;
Jonny Lamb74130762013-11-26 18:19:46 +0100898 } else {
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200899 src_x = wl_fixed_to_double(vp->buffer.src_x);
900 src_y = wl_fixed_to_double(vp->buffer.src_y);
901 src_width = wl_fixed_to_double(vp->buffer.src_width);
902 src_height = wl_fixed_to_double(vp->buffer.src_height);
Jonny Lamb74130762013-11-26 18:19:46 +0100903 }
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200904
905 *bx = sx * src_width / surface->width + src_x;
906 *by = sy * src_height / surface->height + src_y;
Jonny Lamb74130762013-11-26 18:19:46 +0100907}
908
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500909WL_EXPORT void
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200910weston_surface_to_buffer_float(struct weston_surface *surface,
911 float sx, float sy, float *bx, float *by)
912{
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200913 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
914
Jonny Lamb74130762013-11-26 18:19:46 +0100915 /* first transform coordinates if the scaler is set */
916 scaler_surface_to_buffer(surface, sx, sy, bx, by);
917
Jason Ekstrandd0cebc32014-04-21 20:56:46 -0500918 weston_transformed_coord(surface->width_from_buffer,
919 surface->height_from_buffer,
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200920 vp->buffer.transform, vp->buffer.scale,
Jonny Lamb74130762013-11-26 18:19:46 +0100921 *bx, *by, bx, by);
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200922}
923
Derek Foreman99739672015-12-03 16:38:11 -0600924/** Transform a rectangle from surface coordinates to buffer coordinates
925 *
926 * \param surface The surface to fetch wl_viewport and buffer transformation
927 * from.
928 * \param rect The rectangle to transform.
929 * \return The transformed rectangle.
930 *
931 * Viewport and buffer transformations can only do translation, scaling,
932 * and rotations in 90-degree steps. Therefore the only loss in the
933 * conversion is coordinate rounding.
934 *
935 * However, some coordinate rounding takes place as an intermediate
936 * step before the buffer scale factor is applied, so the rectangle
937 * boundary may not be exactly as expected.
938 *
939 * This is OK for damage tracking since a little extra coverage is
940 * not a problem.
941 */
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200942WL_EXPORT pixman_box32_t
943weston_surface_to_buffer_rect(struct weston_surface *surface,
944 pixman_box32_t rect)
945{
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200946 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Jonny Lamb74130762013-11-26 18:19:46 +0100947 float xf, yf;
948
949 /* first transform box coordinates if the scaler is set */
950 scaler_surface_to_buffer(surface, rect.x1, rect.y1, &xf, &yf);
951 rect.x1 = floorf(xf);
952 rect.y1 = floorf(yf);
953
954 scaler_surface_to_buffer(surface, rect.x2, rect.y2, &xf, &yf);
Derek Foremane2e15ac2015-12-01 13:00:43 -0600955 rect.x2 = ceilf(xf);
956 rect.y2 = ceilf(yf);
Jonny Lamb74130762013-11-26 18:19:46 +0100957
Jason Ekstrandd0cebc32014-04-21 20:56:46 -0500958 return weston_transformed_rect(surface->width_from_buffer,
959 surface->height_from_buffer,
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200960 vp->buffer.transform, vp->buffer.scale,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200961 rect);
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200962}
963
Pekka Paalanene54e31c2015-03-04 14:23:28 +0200964/** Transform a region from surface coordinates to buffer coordinates
965 *
966 * \param surface The surface to fetch wl_viewport and buffer transformation
967 * from.
968 * \param surface_region[in] The region in surface coordinates.
969 * \param buffer_region[out] The region converted to buffer coordinates.
970 *
971 * Buffer_region must be init'd, but will be completely overwritten.
972 *
973 * Viewport and buffer transformations can only do translation, scaling,
974 * and rotations in 90-degree steps. Therefore the only loss in the
Derek Foreman99739672015-12-03 16:38:11 -0600975 * conversion is from the coordinate rounding that takes place in
976 * \ref weston_surface_to_buffer_rect.
Pekka Paalanene54e31c2015-03-04 14:23:28 +0200977 */
978WL_EXPORT void
979weston_surface_to_buffer_region(struct weston_surface *surface,
980 pixman_region32_t *surface_region,
981 pixman_region32_t *buffer_region)
982{
983 pixman_box32_t *src_rects, *dest_rects;
984 int nrects, i;
985
986 src_rects = pixman_region32_rectangles(surface_region, &nrects);
987 dest_rects = malloc(nrects * sizeof(*dest_rects));
988 if (!dest_rects)
989 return;
990
991 for (i = 0; i < nrects; i++) {
992 dest_rects[i] = weston_surface_to_buffer_rect(surface,
993 src_rects[i]);
994 }
995
996 pixman_region32_fini(buffer_region);
997 pixman_region32_init_rects(buffer_region, dest_rects, nrects);
998 free(dest_rects);
999}
1000
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +02001001WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001002weston_view_move_to_plane(struct weston_view *view,
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001003 struct weston_plane *plane)
1004{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001005 if (view->plane == plane)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001006 return;
1007
Jason Ekstranda7af7042013-10-12 22:38:11 -05001008 weston_view_damage_below(view);
1009 view->plane = plane;
1010 weston_surface_damage(view->surface);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001011}
1012
Pekka Paalanen51723d52015-02-17 13:10:01 +02001013/** Inflict damage on the plane where the view is visible.
1014 *
1015 * \param view The view that causes the damage.
1016 *
1017 * If the view is currently on a plane (including the primary plane),
1018 * take the view's boundingbox, subtract all the opaque views that cover it,
1019 * and add the remaining region as damage to the plane. This corresponds
1020 * to the damage inflicted to the plane if this view disappeared.
1021 *
1022 * A repaint is scheduled for this view.
1023 *
1024 * The region of all opaque views covering this view is stored in
1025 * weston_view::clip and updated by view_accumulate_damage() during
1026 * weston_output_repaint(). Specifically, that region matches the
1027 * scenegraph as it was last painted.
1028 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001029WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001030weston_view_damage_below(struct weston_view *view)
Pekka Paalanen9abf3932012-02-08 14:49:37 +02001031{
Kristian Høgsberg1e832122012-02-28 22:47:14 -05001032 pixman_region32_t damage;
Pekka Paalanen9abf3932012-02-08 14:49:37 +02001033
Kristian Høgsberg1e832122012-02-28 22:47:14 -05001034 pixman_region32_init(&damage);
Pekka Paalanen25c0ca52015-02-19 11:15:33 +02001035 pixman_region32_subtract(&damage, &view->transform.boundingbox,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001036 &view->clip);
Xiong Zhang97116532013-10-23 13:58:31 +08001037 if (view->plane)
1038 pixman_region32_union(&view->plane->damage,
1039 &view->plane->damage, &damage);
Kristian Høgsberg1e832122012-02-28 22:47:14 -05001040 pixman_region32_fini(&damage);
Kristian Høgsberga3a784a2013-11-13 21:33:43 -08001041 weston_view_schedule_repaint(view);
Pekka Paalanen9abf3932012-02-08 14:49:37 +02001042}
1043
Bryce Harrington3f650b82015-12-23 11:01:58 -08001044/**
1045 * \param es The surface
1046 * \param mask The new set of outputs for the surface
1047 *
1048 * Sets the surface's set of outputs to the ones specified by
1049 * the new output mask provided. Identifies the outputs that
1050 * have changed, the posts enter and leave events for these
1051 * outputs as appropriate.
1052 */
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001053static void
1054weston_surface_update_output_mask(struct weston_surface *es, uint32_t mask)
1055{
1056 uint32_t different = es->output_mask ^ mask;
1057 uint32_t entered = mask & different;
1058 uint32_t left = es->output_mask & different;
1059 struct weston_output *output;
1060 struct wl_resource *resource = NULL;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001061 struct wl_client *client;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001062
1063 es->output_mask = mask;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001064 if (es->resource == NULL)
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001065 return;
1066 if (different == 0)
1067 return;
1068
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001069 client = wl_resource_get_client(es->resource);
1070
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001071 wl_list_for_each(output, &es->compositor->output_list, link) {
Bryce Harrington89324ce2015-12-23 18:38:07 -08001072 if (1u << output->id & different)
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001073 resource =
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05001074 wl_resource_find_for_client(&output->resource_list,
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001075 client);
1076 if (resource == NULL)
1077 continue;
Bryce Harrington89324ce2015-12-23 18:38:07 -08001078 if (1u << output->id & entered)
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001079 wl_surface_send_enter(es->resource, resource);
Bryce Harrington89324ce2015-12-23 18:38:07 -08001080 if (1u << output->id & left)
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001081 wl_surface_send_leave(es->resource, resource);
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001082 }
1083}
1084
Bryce Harrington3f650b82015-12-23 11:01:58 -08001085/** Recalculate which output(s) the surface has views displayed on
1086 *
1087 * \param es The surface to remap to outputs
1088 *
1089 * Finds the output that is showing the largest amount of one
1090 * of the surface's various views. This output becomes the
Pekka Paalanen130ae6e2016-03-30 14:33:33 +03001091 * surface's primary output for vsync and frame callback purposes.
Bryce Harrington3f650b82015-12-23 11:01:58 -08001092 *
Pekka Paalanen130ae6e2016-03-30 14:33:33 +03001093 * Also notes all outputs of all of the surface's views
Bryce Harrington3f650b82015-12-23 11:01:58 -08001094 * in the output_mask for the surface.
1095 */
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001096static void
1097weston_surface_assign_output(struct weston_surface *es)
1098{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001099 struct weston_output *new_output;
1100 struct weston_view *view;
1101 pixman_region32_t region;
1102 uint32_t max, area, mask;
1103 pixman_box32_t *e;
1104
1105 new_output = NULL;
1106 max = 0;
1107 mask = 0;
1108 pixman_region32_init(&region);
1109 wl_list_for_each(view, &es->views, surface_link) {
1110 if (!view->output)
1111 continue;
1112
1113 pixman_region32_intersect(&region, &view->transform.boundingbox,
1114 &view->output->region);
1115
1116 e = pixman_region32_extents(&region);
1117 area = (e->x2 - e->x1) * (e->y2 - e->y1);
1118
1119 mask |= view->output_mask;
1120
1121 if (area >= max) {
1122 new_output = view->output;
1123 max = area;
1124 }
1125 }
1126 pixman_region32_fini(&region);
1127
1128 es->output = new_output;
1129 weston_surface_update_output_mask(es, mask);
1130}
1131
Bryce Harrington3f650b82015-12-23 11:01:58 -08001132/** Recalculate which output(s) the view is displayed on
1133 *
1134 * \param ev The view to remap to outputs
1135 *
1136 * Identifies the set of outputs that the view is visible on,
1137 * noting them into the output_mask. The output that the view
Pekka Paalanen130ae6e2016-03-30 14:33:33 +03001138 * is most visible on is set as the view's primary output.
Bryce Harrington3f650b82015-12-23 11:01:58 -08001139 *
1140 * Also does the same for the view's surface. See
1141 * weston_surface_assign_output().
1142 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001143static void
1144weston_view_assign_output(struct weston_view *ev)
1145{
1146 struct weston_compositor *ec = ev->surface->compositor;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001147 struct weston_output *output, *new_output;
1148 pixman_region32_t region;
1149 uint32_t max, area, mask;
1150 pixman_box32_t *e;
1151
1152 new_output = NULL;
1153 max = 0;
1154 mask = 0;
1155 pixman_region32_init(&region);
1156 wl_list_for_each(output, &ec->output_list, link) {
Giulio Camuffo2f2a70c2015-07-12 10:52:32 +03001157 if (output->destroying)
1158 continue;
1159
Jason Ekstranda7af7042013-10-12 22:38:11 -05001160 pixman_region32_intersect(&region, &ev->transform.boundingbox,
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001161 &output->region);
1162
1163 e = pixman_region32_extents(&region);
1164 area = (e->x2 - e->x1) * (e->y2 - e->y1);
1165
1166 if (area > 0)
Bryce Harrington89324ce2015-12-23 18:38:07 -08001167 mask |= 1u << output->id;
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001168
1169 if (area >= max) {
1170 new_output = output;
1171 max = area;
1172 }
1173 }
1174 pixman_region32_fini(&region);
1175
Jason Ekstranda7af7042013-10-12 22:38:11 -05001176 ev->output = new_output;
1177 ev->output_mask = mask;
1178
1179 weston_surface_assign_output(ev->surface);
Kristian Høgsbergb9af4792012-09-25 14:48:04 -04001180}
1181
Pekka Paalanen9abf3932012-02-08 14:49:37 +02001182static void
Pekka Paalanen380adf52015-02-16 14:39:11 +02001183weston_view_to_view_map(struct weston_view *from, struct weston_view *to,
1184 int from_x, int from_y, int *to_x, int *to_y)
1185{
1186 float x, y;
1187
1188 weston_view_to_global_float(from, from_x, from_y, &x, &y);
1189 weston_view_from_global_float(to, x, y, &x, &y);
1190
1191 *to_x = round(x);
1192 *to_y = round(y);
1193}
1194
1195static void
1196weston_view_transfer_scissor(struct weston_view *from, struct weston_view *to)
1197{
1198 pixman_box32_t *a;
1199 pixman_box32_t b;
1200
1201 a = pixman_region32_extents(&from->geometry.scissor);
1202
1203 weston_view_to_view_map(from, to, a->x1, a->y1, &b.x1, &b.y1);
1204 weston_view_to_view_map(from, to, a->x2, a->y2, &b.x2, &b.y2);
1205
1206 pixman_region32_fini(&to->geometry.scissor);
1207 pixman_region32_init_with_extents(&to->geometry.scissor, &b);
1208}
1209
1210static void
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02001211view_compute_bbox(struct weston_view *view, const pixman_box32_t *inbox,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001212 pixman_region32_t *bbox)
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001213{
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001214 float min_x = HUGE_VALF, min_y = HUGE_VALF;
1215 float max_x = -HUGE_VALF, max_y = -HUGE_VALF;
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001216 int32_t s[4][2] = {
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02001217 { inbox->x1, inbox->y1 },
1218 { inbox->x1, inbox->y2 },
1219 { inbox->x2, inbox->y1 },
1220 { inbox->x2, inbox->y2 },
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001221 };
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001222 float int_x, int_y;
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001223 int i;
1224
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02001225 if (inbox->x1 == inbox->x2 || inbox->y1 == inbox->y2) {
Pekka Paalanen7c7d4642012-09-04 13:55:44 +03001226 /* avoid rounding empty bbox to 1x1 */
1227 pixman_region32_init(bbox);
1228 return;
1229 }
1230
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001231 for (i = 0; i < 4; ++i) {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001232 float x, y;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001233 weston_view_to_global_float(view, s[i][0], s[i][1], &x, &y);
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001234 if (x < min_x)
1235 min_x = x;
1236 if (x > max_x)
1237 max_x = x;
1238 if (y < min_y)
1239 min_y = y;
1240 if (y > max_y)
1241 max_y = y;
1242 }
1243
Pekka Paalanen219b9822012-02-08 15:38:37 +02001244 int_x = floorf(min_x);
1245 int_y = floorf(min_y);
1246 pixman_region32_init_rect(bbox, int_x, int_y,
1247 ceilf(max_x) - int_x, ceilf(max_y) - int_y);
Pekka Paalanen6720d8f2012-01-25 15:17:40 +02001248}
1249
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001250static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001251weston_view_update_transform_disable(struct weston_view *view)
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001252{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001253 view->transform.enabled = 0;
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001254
Pekka Paalanencc2f8682012-02-13 10:34:04 +02001255 /* round off fractions when not transformed */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001256 view->geometry.x = roundf(view->geometry.x);
1257 view->geometry.y = roundf(view->geometry.y);
Pekka Paalanencc2f8682012-02-13 10:34:04 +02001258
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001259 /* Otherwise identity matrix, but with x and y translation. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001260 view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
1261 view->transform.position.matrix.d[12] = view->geometry.x;
1262 view->transform.position.matrix.d[13] = view->geometry.y;
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001263
Jason Ekstranda7af7042013-10-12 22:38:11 -05001264 view->transform.matrix = view->transform.position.matrix;
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001265
Jason Ekstranda7af7042013-10-12 22:38:11 -05001266 view->transform.inverse = view->transform.position.matrix;
1267 view->transform.inverse.d[12] = -view->geometry.x;
1268 view->transform.inverse.d[13] = -view->geometry.y;
Kristian Høgsbergc1e6c8a2013-02-19 17:04:50 -05001269
Jason Ekstranda7af7042013-10-12 22:38:11 -05001270 pixman_region32_init_rect(&view->transform.boundingbox,
Pekka Paalanen380adf52015-02-16 14:39:11 +02001271 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001272 view->surface->width,
1273 view->surface->height);
Pekka Paalanen380adf52015-02-16 14:39:11 +02001274 if (view->geometry.scissor_enabled)
1275 pixman_region32_intersect(&view->transform.boundingbox,
1276 &view->transform.boundingbox,
1277 &view->geometry.scissor);
1278
1279 pixman_region32_translate(&view->transform.boundingbox,
1280 view->geometry.x, view->geometry.y);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001281
Jason Ekstranda7af7042013-10-12 22:38:11 -05001282 if (view->alpha == 1.0) {
1283 pixman_region32_copy(&view->transform.opaque,
1284 &view->surface->opaque);
1285 pixman_region32_translate(&view->transform.opaque,
1286 view->geometry.x,
1287 view->geometry.y);
Kristian Høgsberg3b4af202012-02-28 09:19:39 -05001288 }
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001289}
1290
1291static int
Jason Ekstranda7af7042013-10-12 22:38:11 -05001292weston_view_update_transform_enable(struct weston_view *view)
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001293{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001294 struct weston_view *parent = view->geometry.parent;
1295 struct weston_matrix *matrix = &view->transform.matrix;
1296 struct weston_matrix *inverse = &view->transform.inverse;
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001297 struct weston_transform *tform;
Pekka Paalanen380adf52015-02-16 14:39:11 +02001298 pixman_region32_t surfregion;
1299 const pixman_box32_t *surfbox;
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001300
Jason Ekstranda7af7042013-10-12 22:38:11 -05001301 view->transform.enabled = 1;
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001302
1303 /* Otherwise identity matrix, but with x and y translation. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001304 view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
1305 view->transform.position.matrix.d[12] = view->geometry.x;
1306 view->transform.position.matrix.d[13] = view->geometry.y;
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001307
1308 weston_matrix_init(matrix);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001309 wl_list_for_each(tform, &view->geometry.transformation_list, link)
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001310 weston_matrix_multiply(matrix, &tform->matrix);
1311
Pekka Paalanen483243f2013-03-08 14:56:50 +02001312 if (parent)
1313 weston_matrix_multiply(matrix, &parent->transform.matrix);
1314
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001315 if (weston_matrix_invert(inverse, matrix) < 0) {
1316 /* Oops, bad total transformation, not invertible */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001317 weston_log("error: weston_view %p"
1318 " transformation not invertible.\n", view);
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001319 return -1;
1320 }
1321
Pekka Paalanen380adf52015-02-16 14:39:11 +02001322 pixman_region32_init_rect(&surfregion, 0, 0,
1323 view->surface->width, view->surface->height);
1324 if (view->geometry.scissor_enabled)
1325 pixman_region32_intersect(&surfregion, &surfregion,
1326 &view->geometry.scissor);
1327 surfbox = pixman_region32_extents(&surfregion);
1328
1329 view_compute_bbox(view, surfbox, &view->transform.boundingbox);
1330 pixman_region32_fini(&surfregion);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001331
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001332 return 0;
1333}
1334
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001335static struct weston_layer *
1336get_view_layer(struct weston_view *view)
1337{
1338 if (view->parent_view)
1339 return get_view_layer(view->parent_view);
1340 return view->layer_link.layer;
1341}
1342
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001343WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001344weston_view_update_transform(struct weston_view *view)
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001345{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001346 struct weston_view *parent = view->geometry.parent;
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001347 struct weston_layer *layer;
1348 pixman_region32_t mask;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001349
Jason Ekstranda7af7042013-10-12 22:38:11 -05001350 if (!view->transform.dirty)
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001351 return;
1352
Pekka Paalanen483243f2013-03-08 14:56:50 +02001353 if (parent)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001354 weston_view_update_transform(parent);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001355
Jason Ekstranda7af7042013-10-12 22:38:11 -05001356 view->transform.dirty = 0;
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001357
Jason Ekstranda7af7042013-10-12 22:38:11 -05001358 weston_view_damage_below(view);
Pekka Paalanen96516782012-02-09 15:32:15 +02001359
Jason Ekstranda7af7042013-10-12 22:38:11 -05001360 pixman_region32_fini(&view->transform.boundingbox);
1361 pixman_region32_fini(&view->transform.opaque);
1362 pixman_region32_init(&view->transform.opaque);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001363
Pekka Paalanencd403622012-01-25 13:37:39 +02001364 /* transform.position is always in transformation_list */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001365 if (view->geometry.transformation_list.next ==
1366 &view->transform.position.link &&
1367 view->geometry.transformation_list.prev ==
1368 &view->transform.position.link &&
Pekka Paalanen483243f2013-03-08 14:56:50 +02001369 !parent) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001370 weston_view_update_transform_disable(view);
Pekka Paalanen80fb08d2012-02-08 15:14:17 +02001371 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001372 if (weston_view_update_transform_enable(view) < 0)
1373 weston_view_update_transform_disable(view);
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001374 }
Pekka Paalanen96516782012-02-09 15:32:15 +02001375
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001376 layer = get_view_layer(view);
1377 if (layer) {
1378 pixman_region32_init_with_extents(&mask, &layer->mask);
Pekka Paalanen25c0ca52015-02-19 11:15:33 +02001379 pixman_region32_intersect(&view->transform.boundingbox,
1380 &view->transform.boundingbox, &mask);
Pekka Paalanen8844bf22015-02-18 16:30:47 +02001381 pixman_region32_intersect(&view->transform.opaque,
1382 &view->transform.opaque, &mask);
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03001383 pixman_region32_fini(&mask);
1384 }
1385
Pekka Paalanen380adf52015-02-16 14:39:11 +02001386 if (parent) {
1387 if (parent->geometry.scissor_enabled) {
1388 view->geometry.scissor_enabled = true;
1389 weston_view_transfer_scissor(parent, view);
1390 } else {
1391 view->geometry.scissor_enabled = false;
1392 }
1393 }
1394
Jason Ekstranda7af7042013-10-12 22:38:11 -05001395 weston_view_damage_below(view);
Pekka Paalanen96516782012-02-09 15:32:15 +02001396
Jason Ekstranda7af7042013-10-12 22:38:11 -05001397 weston_view_assign_output(view);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03001398
Jason Ekstranda7af7042013-10-12 22:38:11 -05001399 wl_signal_emit(&view->surface->compositor->transform_signal,
1400 view->surface);
Pekka Paalanen2a5cecc2012-01-20 14:24:25 +02001401}
1402
Pekka Paalanenddae03c2012-02-06 14:54:20 +02001403WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001404weston_view_geometry_dirty(struct weston_view *view)
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02001405{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001406 struct weston_view *child;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001407
1408 /*
Jason Ekstranda7af7042013-10-12 22:38:11 -05001409 * The invariant: if view->geometry.dirty, then all views
1410 * in view->geometry.child_list have geometry.dirty too.
Pekka Paalanen483243f2013-03-08 14:56:50 +02001411 * Corollary: if not parent->geometry.dirty, then all ancestors
1412 * are not dirty.
1413 */
1414
Jason Ekstranda7af7042013-10-12 22:38:11 -05001415 if (view->transform.dirty)
Pekka Paalanen483243f2013-03-08 14:56:50 +02001416 return;
1417
Jason Ekstranda7af7042013-10-12 22:38:11 -05001418 view->transform.dirty = 1;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001419
Jason Ekstranda7af7042013-10-12 22:38:11 -05001420 wl_list_for_each(child, &view->geometry.child_list,
Pekka Paalanen483243f2013-03-08 14:56:50 +02001421 geometry.parent_link)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001422 weston_view_geometry_dirty(child);
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02001423}
1424
1425WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001426weston_view_to_global_fixed(struct weston_view *view,
1427 wl_fixed_t vx, wl_fixed_t vy,
1428 wl_fixed_t *x, wl_fixed_t *y)
Daniel Stonebd3489b2012-05-08 17:17:53 +01001429{
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001430 float xf, yf;
Daniel Stonebd3489b2012-05-08 17:17:53 +01001431
Jason Ekstranda7af7042013-10-12 22:38:11 -05001432 weston_view_to_global_float(view,
1433 wl_fixed_to_double(vx),
1434 wl_fixed_to_double(vy),
1435 &xf, &yf);
Daniel Stonebd3489b2012-05-08 17:17:53 +01001436 *x = wl_fixed_from_double(xf);
1437 *y = wl_fixed_from_double(yf);
1438}
1439
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -04001440WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001441weston_view_from_global_float(struct weston_view *view,
1442 float x, float y, float *vx, float *vy)
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001443{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001444 if (view->transform.enabled) {
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001445 struct weston_vector v = { { x, y, 0.0f, 1.0f } };
1446
Jason Ekstranda7af7042013-10-12 22:38:11 -05001447 weston_matrix_transform(&view->transform.inverse, &v);
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001448
1449 if (fabsf(v.f[3]) < 1e-6) {
Martin Minarik6d118362012-06-07 18:01:59 +02001450 weston_log("warning: numerical instability in "
Jason Ekstranda7af7042013-10-12 22:38:11 -05001451 "weston_view_from_global(), divisor = %g\n",
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001452 v.f[3]);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001453 *vx = 0;
1454 *vy = 0;
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001455 return;
1456 }
1457
Jason Ekstranda7af7042013-10-12 22:38:11 -05001458 *vx = v.f[0] / v.f[3];
1459 *vy = v.f[1] / v.f[3];
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001460 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001461 *vx = x - view->geometry.x;
1462 *vy = y - view->geometry.y;
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02001463 }
1464}
1465
1466WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001467weston_view_from_global_fixed(struct weston_view *view,
1468 wl_fixed_t x, wl_fixed_t y,
1469 wl_fixed_t *vx, wl_fixed_t *vy)
Daniel Stonebd3489b2012-05-08 17:17:53 +01001470{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001471 float vxf, vyf;
Daniel Stonebd3489b2012-05-08 17:17:53 +01001472
Jason Ekstranda7af7042013-10-12 22:38:11 -05001473 weston_view_from_global_float(view,
1474 wl_fixed_to_double(x),
1475 wl_fixed_to_double(y),
1476 &vxf, &vyf);
1477 *vx = wl_fixed_from_double(vxf);
1478 *vy = wl_fixed_from_double(vyf);
Daniel Stonebd3489b2012-05-08 17:17:53 +01001479}
1480
1481WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001482weston_view_from_global(struct weston_view *view,
1483 int32_t x, int32_t y, int32_t *vx, int32_t *vy)
Pekka Paalanen0e151bb2012-01-24 14:47:37 +02001484{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001485 float vxf, vyf;
Pekka Paalanen0e151bb2012-01-24 14:47:37 +02001486
Jason Ekstranda7af7042013-10-12 22:38:11 -05001487 weston_view_from_global_float(view, x, y, &vxf, &vyf);
1488 *vx = floorf(vxf);
1489 *vy = floorf(vyf);
Pekka Paalanen0e151bb2012-01-24 14:47:37 +02001490}
1491
Bryce Harrington3f650b82015-12-23 11:01:58 -08001492/**
1493 * \param surface The surface to be repainted
1494 *
1495 * Marks the output(s) that the surface is shown on as needing to be
1496 * repainted. See weston_output_schedule_repaint().
1497 */
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001498WL_EXPORT void
Kristian Høgsberg98238702012-08-03 16:29:12 -04001499weston_surface_schedule_repaint(struct weston_surface *surface)
1500{
1501 struct weston_output *output;
1502
1503 wl_list_for_each(output, &surface->compositor->output_list, link)
Bryce Harrington89324ce2015-12-23 18:38:07 -08001504 if (surface->output_mask & (1u << output->id))
Kristian Høgsberg98238702012-08-03 16:29:12 -04001505 weston_output_schedule_repaint(output);
1506}
1507
Bryce Harrington3f650b82015-12-23 11:01:58 -08001508/**
1509 * \param view The view to be repainted
1510 *
1511 * Marks the output(s) that the view is shown on as needing to be
1512 * repainted. See weston_output_schedule_repaint().
1513 */
Kristian Høgsberg98238702012-08-03 16:29:12 -04001514WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001515weston_view_schedule_repaint(struct weston_view *view)
1516{
1517 struct weston_output *output;
1518
1519 wl_list_for_each(output, &view->surface->compositor->output_list, link)
Bryce Harrington89324ce2015-12-23 18:38:07 -08001520 if (view->output_mask & (1u << output->id))
Jason Ekstranda7af7042013-10-12 22:38:11 -05001521 weston_output_schedule_repaint(output);
1522}
1523
Pekka Paalanene508ce62015-02-19 13:59:55 +02001524/**
1525 * XXX: This function does it the wrong way.
1526 * surface->damage is the damage from the client, and causes
1527 * surface_flush_damage() to copy pixels. No window management action can
1528 * cause damage to the client-provided content, warranting re-upload!
1529 *
1530 * Instead of surface->damage, this function should record the damage
1531 * with all the views for this surface to avoid extraneous texture
1532 * uploads.
1533 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001534WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001535weston_surface_damage(struct weston_surface *surface)
Kristian Høgsberg31bd6c72011-02-13 13:00:51 -05001536{
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04001537 pixman_region32_union_rect(&surface->damage, &surface->damage,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001538 0, 0, surface->width,
1539 surface->height);
Pekka Paalanen2267d452012-01-26 13:12:45 +02001540
Kristian Høgsberg98238702012-08-03 16:29:12 -04001541 weston_surface_schedule_repaint(surface);
Kristian Høgsberg31bd6c72011-02-13 13:00:51 -05001542}
1543
Kristian Høgsberga691aee2011-06-23 21:43:50 -04001544WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001545weston_view_set_position(struct weston_view *view, float x, float y)
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001546{
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001547 if (view->geometry.x == x && view->geometry.y == y)
1548 return;
1549
Jason Ekstranda7af7042013-10-12 22:38:11 -05001550 view->geometry.x = x;
1551 view->geometry.y = y;
1552 weston_view_geometry_dirty(view);
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001553}
1554
Pekka Paalanen483243f2013-03-08 14:56:50 +02001555static void
1556transform_parent_handle_parent_destroy(struct wl_listener *listener,
1557 void *data)
1558{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001559 struct weston_view *view =
1560 container_of(listener, struct weston_view,
Pekka Paalanen483243f2013-03-08 14:56:50 +02001561 geometry.parent_destroy_listener);
1562
Jason Ekstranda7af7042013-10-12 22:38:11 -05001563 weston_view_set_transform_parent(view, NULL);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001564}
1565
1566WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001567weston_view_set_transform_parent(struct weston_view *view,
Pekka Paalanen380adf52015-02-16 14:39:11 +02001568 struct weston_view *parent)
Pekka Paalanen483243f2013-03-08 14:56:50 +02001569{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001570 if (view->geometry.parent) {
1571 wl_list_remove(&view->geometry.parent_destroy_listener.link);
1572 wl_list_remove(&view->geometry.parent_link);
Pekka Paalanen380adf52015-02-16 14:39:11 +02001573
1574 if (!parent)
1575 view->geometry.scissor_enabled = false;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001576 }
1577
Jason Ekstranda7af7042013-10-12 22:38:11 -05001578 view->geometry.parent = parent;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001579
Jason Ekstranda7af7042013-10-12 22:38:11 -05001580 view->geometry.parent_destroy_listener.notify =
Pekka Paalanen483243f2013-03-08 14:56:50 +02001581 transform_parent_handle_parent_destroy;
1582 if (parent) {
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001583 wl_signal_add(&parent->destroy_signal,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001584 &view->geometry.parent_destroy_listener);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001585 wl_list_insert(&parent->geometry.child_list,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001586 &view->geometry.parent_link);
Pekka Paalanen483243f2013-03-08 14:56:50 +02001587 }
1588
Jason Ekstranda7af7042013-10-12 22:38:11 -05001589 weston_view_geometry_dirty(view);
1590}
1591
Pekka Paalanen380adf52015-02-16 14:39:11 +02001592/** Set a clip mask rectangle on a view
1593 *
1594 * \param view The view to set the clip mask on.
1595 * \param x Top-left corner X coordinate of the clip rectangle.
1596 * \param y Top-left corner Y coordinate of the clip rectangle.
1597 * \param width Width of the clip rectangle, non-negative.
1598 * \param height Height of the clip rectangle, non-negative.
1599 *
1600 * A shell may set a clip mask rectangle on a view. Everything outside
1601 * the rectangle is cut away for input and output purposes: it is
1602 * not drawn and cannot be hit by hit-test based input like pointer
1603 * motion or touch-downs. Everything inside the rectangle will behave
1604 * normally. Clients are unaware of clipping.
1605 *
Yong Bakos4c72e292016-04-28 11:59:10 -05001606 * The rectangle is set in surface-local coordinates. Setting a clip
Pekka Paalanen380adf52015-02-16 14:39:11 +02001607 * mask rectangle does not affect the view position, the view is positioned
1608 * as it would be without a clip. The clip also does not change
1609 * weston_surface::width,height.
1610 *
1611 * The clip mask rectangle is part of transformation inheritance
1612 * (weston_view_set_transform_parent()). A clip set in the root of the
1613 * transformation inheritance tree will affect all views in the tree.
1614 * A clip can be set only on the root view. Attempting to set a clip
1615 * on view that has a transformation parent will fail. Assigning a parent
1616 * to a view that has a clip set will cause the clip to be forgotten.
1617 *
1618 * Because the clip mask is an axis-aligned rectangle, it poses restrictions
1619 * on the additional transformations in the child views. These transformations
1620 * may not rotate the coordinate axes, i.e., only translation and scaling
1621 * are allowed. Violating this restriction causes the clipping to malfunction.
1622 * Furthermore, using scaling may cause rounding errors in child clipping.
1623 *
1624 * The clip mask rectangle is not automatically adjusted based on
1625 * wl_surface.attach dx and dy arguments.
1626 *
1627 * A clip mask rectangle can be set only if the compositor capability
1628 * WESTON_CAP_VIEW_CLIP_MASK is present.
1629 *
1630 * This function sets the clip mask rectangle and schedules a repaint for
1631 * the view.
1632 */
1633WL_EXPORT void
1634weston_view_set_mask(struct weston_view *view,
1635 int x, int y, int width, int height)
1636{
1637 struct weston_compositor *compositor = view->surface->compositor;
1638
1639 if (!(compositor->capabilities & WESTON_CAP_VIEW_CLIP_MASK)) {
1640 weston_log("%s not allowed without capability!\n", __func__);
1641 return;
1642 }
1643
1644 if (view->geometry.parent) {
1645 weston_log("view %p has a parent, clip forbidden!\n", view);
1646 return;
1647 }
1648
1649 if (width < 0 || height < 0) {
1650 weston_log("%s: illegal args %d, %d, %d, %d\n", __func__,
1651 x, y, width, height);
1652 return;
1653 }
1654
1655 pixman_region32_fini(&view->geometry.scissor);
1656 pixman_region32_init_rect(&view->geometry.scissor, x, y, width, height);
1657 view->geometry.scissor_enabled = true;
1658 weston_view_geometry_dirty(view);
1659 weston_view_schedule_repaint(view);
1660}
1661
1662/** Remove the clip mask from a view
1663 *
1664 * \param view The view to remove the clip mask from.
1665 *
1666 * Removed the clip mask rectangle and schedules a repaint.
1667 *
1668 * \sa weston_view_set_mask
1669 */
1670WL_EXPORT void
1671weston_view_set_mask_infinite(struct weston_view *view)
1672{
1673 view->geometry.scissor_enabled = false;
1674 weston_view_geometry_dirty(view);
1675 weston_view_schedule_repaint(view);
1676}
1677
Derek Foreman280e7dd2014-10-03 13:13:42 -05001678WL_EXPORT bool
Jason Ekstranda7af7042013-10-12 22:38:11 -05001679weston_view_is_mapped(struct weston_view *view)
1680{
1681 if (view->output)
Derek Foreman280e7dd2014-10-03 13:13:42 -05001682 return true;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001683 else
Derek Foreman280e7dd2014-10-03 13:13:42 -05001684 return false;
Pekka Paalanen483243f2013-03-08 14:56:50 +02001685}
1686
Derek Foreman280e7dd2014-10-03 13:13:42 -05001687WL_EXPORT bool
Ander Conselvan de Oliveirab8ab14f2012-03-27 17:36:36 +03001688weston_surface_is_mapped(struct weston_surface *surface)
1689{
1690 if (surface->output)
Derek Foreman280e7dd2014-10-03 13:13:42 -05001691 return true;
Ander Conselvan de Oliveirab8ab14f2012-03-27 17:36:36 +03001692 else
Derek Foreman280e7dd2014-10-03 13:13:42 -05001693 return false;
Ander Conselvan de Oliveirab8ab14f2012-03-27 17:36:36 +03001694}
1695
Pekka Paalanenda75ee12013-11-26 18:19:43 +01001696static void
Jason Ekstrand5c11a332013-12-04 20:32:03 -06001697surface_set_size(struct weston_surface *surface, int32_t width, int32_t height)
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001698{
1699 struct weston_view *view;
1700
1701 if (surface->width == width && surface->height == height)
1702 return;
1703
1704 surface->width = width;
1705 surface->height = height;
1706
1707 wl_list_for_each(view, &surface->views, surface_link)
1708 weston_view_geometry_dirty(view);
1709}
1710
Jason Ekstrand5c11a332013-12-04 20:32:03 -06001711WL_EXPORT void
1712weston_surface_set_size(struct weston_surface *surface,
1713 int32_t width, int32_t height)
1714{
1715 assert(!surface->resource);
1716 surface_set_size(surface, width, height);
1717}
1718
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02001719static int
1720fixed_round_up_to_int(wl_fixed_t f)
1721{
1722 return wl_fixed_to_int(wl_fixed_from_int(1) - 1 + f);
1723}
1724
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001725static void
Pekka Paalanen59987fa2016-04-26 15:50:59 +03001726convert_size_by_transform_scale(int32_t *width_out, int32_t *height_out,
1727 int32_t width, int32_t height,
1728 uint32_t transform,
1729 int32_t scale)
1730{
1731 assert(scale > 0);
1732
1733 switch (transform) {
1734 case WL_OUTPUT_TRANSFORM_NORMAL:
1735 case WL_OUTPUT_TRANSFORM_180:
1736 case WL_OUTPUT_TRANSFORM_FLIPPED:
1737 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1738 *width_out = width / scale;
1739 *height_out = height / scale;
1740 break;
1741 case WL_OUTPUT_TRANSFORM_90:
1742 case WL_OUTPUT_TRANSFORM_270:
1743 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1744 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1745 *width_out = height / scale;
1746 *height_out = width / scale;
1747 break;
1748 default:
1749 assert(0 && "invalid transform");
1750 }
1751}
1752
1753static void
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02001754weston_surface_calculate_size_from_buffer(struct weston_surface *surface)
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02001755{
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001756 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Pekka Paalanenda75ee12013-11-26 18:19:43 +01001757
1758 if (!surface->buffer_ref.buffer) {
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02001759 surface->width_from_buffer = 0;
1760 surface->height_from_buffer = 0;
Jonny Lamb74130762013-11-26 18:19:46 +01001761 return;
1762 }
1763
Pekka Paalanen59987fa2016-04-26 15:50:59 +03001764 convert_size_by_transform_scale(&surface->width_from_buffer,
1765 &surface->height_from_buffer,
1766 surface->buffer_ref.buffer->width,
1767 surface->buffer_ref.buffer->height,
1768 vp->buffer.transform,
1769 vp->buffer.scale);
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02001770}
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02001771
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02001772static void
1773weston_surface_update_size(struct weston_surface *surface)
1774{
1775 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
1776 int32_t width, height;
1777
1778 width = surface->width_from_buffer;
1779 height = surface->height_from_buffer;
1780
1781 if (width != 0 && vp->surface.width != -1) {
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02001782 surface_set_size(surface,
1783 vp->surface.width, vp->surface.height);
1784 return;
1785 }
1786
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02001787 if (width != 0 && vp->buffer.src_width != wl_fixed_from_int(-1)) {
Pekka Paalanene9317212014-04-04 14:22:13 +03001788 int32_t w = fixed_round_up_to_int(vp->buffer.src_width);
1789 int32_t h = fixed_round_up_to_int(vp->buffer.src_height);
1790
1791 surface_set_size(surface, w ?: 1, h ?: 1);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02001792 return;
1793 }
1794
Jason Ekstrand5c11a332013-12-04 20:32:03 -06001795 surface_set_size(surface, width, height);
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02001796}
1797
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001798WL_EXPORT uint32_t
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001799weston_compositor_get_time(void)
Kristian Høgsberg7132a9a2010-12-06 21:41:10 -05001800{
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001801 struct timeval tv;
Kristian Høgsberg7132a9a2010-12-06 21:41:10 -05001802
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001803 gettimeofday(&tv, NULL);
Kristian Høgsberg7132a9a2010-12-06 21:41:10 -05001804
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001805 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
Kristian Høgsberg7132a9a2010-12-06 21:41:10 -05001806}
1807
Jason Ekstranda7af7042013-10-12 22:38:11 -05001808WL_EXPORT struct weston_view *
1809weston_compositor_pick_view(struct weston_compositor *compositor,
1810 wl_fixed_t x, wl_fixed_t y,
1811 wl_fixed_t *vx, wl_fixed_t *vy)
Tiago Vignatti9d393522012-02-10 16:26:19 +02001812{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001813 struct weston_view *view;
Pekka Paalanenfc22a522015-02-18 15:08:29 +02001814 wl_fixed_t view_x, view_y;
1815 int view_ix, view_iy;
1816 int ix = wl_fixed_to_int(x);
1817 int iy = wl_fixed_to_int(y);
Tiago Vignatti9d393522012-02-10 16:26:19 +02001818
Jason Ekstranda7af7042013-10-12 22:38:11 -05001819 wl_list_for_each(view, &compositor->view_list, link) {
Pekka Paalanenfc22a522015-02-18 15:08:29 +02001820 if (!pixman_region32_contains_point(
1821 &view->transform.boundingbox, ix, iy, NULL))
1822 continue;
1823
1824 weston_view_from_global_fixed(view, x, y, &view_x, &view_y);
1825 view_ix = wl_fixed_to_int(view_x);
1826 view_iy = wl_fixed_to_int(view_y);
1827
1828 if (!pixman_region32_contains_point(&view->surface->input,
1829 view_ix, view_iy, NULL))
1830 continue;
1831
Pekka Paalanen380adf52015-02-16 14:39:11 +02001832 if (view->geometry.scissor_enabled &&
1833 !pixman_region32_contains_point(&view->geometry.scissor,
1834 view_ix, view_iy, NULL))
1835 continue;
1836
Pekka Paalanenfc22a522015-02-18 15:08:29 +02001837 *vx = view_x;
1838 *vy = view_y;
1839 return view;
Tiago Vignatti9d393522012-02-10 16:26:19 +02001840 }
1841
Derek Foremanf9318d12015-05-11 15:40:11 -05001842 *vx = wl_fixed_from_int(-1000000);
1843 *vy = wl_fixed_from_int(-1000000);
Tiago Vignatti9d393522012-02-10 16:26:19 +02001844 return NULL;
1845}
1846
1847static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001848weston_compositor_repick(struct weston_compositor *compositor)
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04001849{
Daniel Stone37816df2012-05-16 18:45:18 +01001850 struct weston_seat *seat;
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04001851
Kristian Høgsberg10ddd972013-10-22 12:40:54 -07001852 if (!compositor->session_active)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001853 return;
1854
Daniel Stone37816df2012-05-16 18:45:18 +01001855 wl_list_for_each(seat, &compositor->seat_list, link)
Kristian Høgsberga71e8b22013-05-06 21:51:21 -04001856 weston_seat_repick(seat);
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04001857}
1858
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001859WL_EXPORT void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001860weston_view_unmap(struct weston_view *view)
Kristian Høgsberg3b5ea3b2012-02-17 12:43:56 -05001861{
Daniel Stone4dab5db2012-05-30 16:31:53 +01001862 struct weston_seat *seat;
Kristian Høgsberg867dec72012-03-01 17:09:37 -05001863
Jason Ekstranda7af7042013-10-12 22:38:11 -05001864 if (!weston_view_is_mapped(view))
1865 return;
Kristian Høgsberg867dec72012-03-01 17:09:37 -05001866
Jason Ekstranda7af7042013-10-12 22:38:11 -05001867 weston_view_damage_below(view);
1868 view->output = NULL;
Xiong Zhang97116532013-10-23 13:58:31 +08001869 view->plane = NULL;
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001870 weston_layer_entry_remove(&view->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001871 wl_list_remove(&view->link);
1872 wl_list_init(&view->link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001873 view->output_mask = 0;
1874 weston_surface_assign_output(view->surface);
1875
1876 if (weston_surface_is_mapped(view->surface))
1877 return;
1878
1879 wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -05001880 struct weston_touch *touch = weston_seat_get_touch(seat);
1881 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
1882 struct weston_keyboard *keyboard =
1883 weston_seat_get_keyboard(seat);
1884
1885 if (keyboard && keyboard->focus == view->surface)
1886 weston_keyboard_set_focus(keyboard, NULL);
1887 if (pointer && pointer->focus == view)
Derek Foremanf9318d12015-05-11 15:40:11 -05001888 weston_pointer_clear_focus(pointer);
Derek Foreman1281a362015-07-31 16:55:32 -05001889 if (touch && touch->focus == view)
1890 weston_touch_set_focus(touch, NULL);
Daniel Stone4dab5db2012-05-30 16:31:53 +01001891 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001892}
Kristian Høgsberg867dec72012-03-01 17:09:37 -05001893
Jason Ekstranda7af7042013-10-12 22:38:11 -05001894WL_EXPORT void
1895weston_surface_unmap(struct weston_surface *surface)
1896{
1897 struct weston_view *view;
1898
1899 wl_list_for_each(view, &surface->views, surface_link)
1900 weston_view_unmap(view);
1901 surface->output = NULL;
Kristian Høgsberg3b5ea3b2012-02-17 12:43:56 -05001902}
1903
Pekka Paalanen3c9b8022014-03-14 14:38:13 +02001904static void
1905weston_surface_reset_pending_buffer(struct weston_surface *surface)
1906{
Jason Ekstrand7b982072014-05-20 14:33:03 -05001907 weston_surface_state_set_buffer(&surface->pending, NULL);
Pekka Paalanen3c9b8022014-03-14 14:38:13 +02001908 surface->pending.sx = 0;
1909 surface->pending.sy = 0;
1910 surface->pending.newly_attached = 0;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02001911 surface->pending.buffer_viewport.changed = 0;
Pekka Paalanen3c9b8022014-03-14 14:38:13 +02001912}
1913
Jason Ekstranda7af7042013-10-12 22:38:11 -05001914WL_EXPORT void
1915weston_view_destroy(struct weston_view *view)
1916{
1917 wl_signal_emit(&view->destroy_signal, view);
1918
1919 assert(wl_list_empty(&view->geometry.child_list));
1920
1921 if (weston_view_is_mapped(view)) {
1922 weston_view_unmap(view);
1923 weston_compositor_build_view_list(view->surface->compositor);
1924 }
1925
1926 wl_list_remove(&view->link);
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001927 weston_layer_entry_remove(&view->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001928
1929 pixman_region32_fini(&view->clip);
Pekka Paalanen380adf52015-02-16 14:39:11 +02001930 pixman_region32_fini(&view->geometry.scissor);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001931 pixman_region32_fini(&view->transform.boundingbox);
Pekka Paalanen8844bf22015-02-18 16:30:47 +02001932 pixman_region32_fini(&view->transform.opaque);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001933
1934 weston_view_set_transform_parent(view, NULL);
1935
Jason Ekstranda7af7042013-10-12 22:38:11 -05001936 wl_list_remove(&view->surface_link);
1937
1938 free(view);
1939}
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001940
1941WL_EXPORT void
1942weston_surface_destroy(struct weston_surface *surface)
Kristian Høgsberg54879822008-11-23 17:07:32 -05001943{
Kristian Høgsberg1e51fec2012-07-22 11:33:14 -04001944 struct weston_frame_callback *cb, *next;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001945 struct weston_view *ev, *nv;
Kristian Høgsberg4fa48732009-03-10 23:17:00 -04001946
Giulio Camuffo13b85bd2013-08-13 23:10:14 +02001947 if (--surface->ref_count > 0)
1948 return;
1949
Pekka Paalanen08d3fb72015-04-17 14:00:24 +03001950 assert(surface->resource == NULL);
1951
Pekka Paalanenca790762015-04-17 14:23:38 +03001952 wl_signal_emit(&surface->destroy_signal, surface);
Giulio Camuffo13b85bd2013-08-13 23:10:14 +02001953
Pekka Paalanene67858b2013-04-25 13:57:42 +03001954 assert(wl_list_empty(&surface->subsurface_list_pending));
1955 assert(wl_list_empty(&surface->subsurface_list));
Pekka Paalanen483243f2013-03-08 14:56:50 +02001956
Jason Ekstranda7af7042013-10-12 22:38:11 -05001957 wl_list_for_each_safe(ev, nv, &surface->views, surface_link)
1958 weston_view_destroy(ev);
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04001959
Jason Ekstrand7b982072014-05-20 14:33:03 -05001960 weston_surface_state_fini(&surface->pending);
Pekka Paalanen5df44de2012-10-10 12:49:23 +03001961
Pekka Paalanende685b82012-12-04 15:58:12 +02001962 weston_buffer_reference(&surface->buffer_ref, NULL);
Kristian Høgsberg3f8f39c2009-09-18 17:05:13 -04001963
Pekka Paalanen402ae6d2012-01-03 10:23:24 +02001964 pixman_region32_fini(&surface->damage);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05001965 pixman_region32_fini(&surface->opaque);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03001966 pixman_region32_fini(&surface->input);
Pekka Paalanen402ae6d2012-01-03 10:23:24 +02001967
Kristian Høgsberg1e51fec2012-07-22 11:33:14 -04001968 wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link)
Jason Ekstrandfbbbec82013-06-14 10:07:57 -05001969 wl_resource_destroy(cb->resource);
Kristian Høgsberg1e51fec2012-07-22 11:33:14 -04001970
Pekka Paalanen133e4392014-09-23 22:08:46 -04001971 weston_presentation_feedback_discard_list(&surface->feedback_list);
1972
Kristian Høgsberg4fa48732009-03-10 23:17:00 -04001973 free(surface);
Kristian Høgsberg54879822008-11-23 17:07:32 -05001974}
1975
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001976static void
1977destroy_surface(struct wl_resource *resource)
Alex Wu8811bf92012-02-28 18:07:54 +08001978{
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001979 struct weston_surface *surface = wl_resource_get_user_data(resource);
Alex Wu8811bf92012-02-28 18:07:54 +08001980
Pekka Paalanen08d3fb72015-04-17 14:00:24 +03001981 assert(surface);
1982
Giulio Camuffo0d379742013-11-15 22:06:15 +01001983 /* Set the resource to NULL, since we don't want to leave a
1984 * dangling pointer if the surface was refcounted and survives
1985 * the weston_surface_destroy() call. */
1986 surface->resource = NULL;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05001987 weston_surface_destroy(surface);
Alex Wu8811bf92012-02-28 18:07:54 +08001988}
1989
Benjamin Franzkefaa0a9d2011-02-21 16:24:53 +01001990static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001991weston_buffer_destroy_handler(struct wl_listener *listener, void *data)
1992{
1993 struct weston_buffer *buffer =
1994 container_of(listener, struct weston_buffer, destroy_listener);
1995
1996 wl_signal_emit(&buffer->destroy_signal, buffer);
1997 free(buffer);
1998}
1999
Giulio Camuffoe058cd12013-12-12 14:14:29 +01002000WL_EXPORT struct weston_buffer *
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002001weston_buffer_from_resource(struct wl_resource *resource)
2002{
2003 struct weston_buffer *buffer;
2004 struct wl_listener *listener;
U. Artie Eoff2e2384a2014-01-17 13:19:01 -08002005
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002006 listener = wl_resource_get_destroy_listener(resource,
2007 weston_buffer_destroy_handler);
2008
Kristian Høgsberg08b58c72013-08-15 12:26:42 -07002009 if (listener)
2010 return container_of(listener, struct weston_buffer,
2011 destroy_listener);
2012
2013 buffer = zalloc(sizeof *buffer);
2014 if (buffer == NULL)
2015 return NULL;
2016
2017 buffer->resource = resource;
2018 wl_signal_init(&buffer->destroy_signal);
2019 buffer->destroy_listener.notify = weston_buffer_destroy_handler;
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +04002020 buffer->y_inverted = 1;
Kristian Høgsberg08b58c72013-08-15 12:26:42 -07002021 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
U. Artie Eoff2e2384a2014-01-17 13:19:01 -08002022
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002023 return buffer;
2024}
2025
2026static void
Pekka Paalanende685b82012-12-04 15:58:12 +02002027weston_buffer_reference_handle_destroy(struct wl_listener *listener,
2028 void *data)
Benjamin Franzkefaa0a9d2011-02-21 16:24:53 +01002029{
Pekka Paalanende685b82012-12-04 15:58:12 +02002030 struct weston_buffer_reference *ref =
2031 container_of(listener, struct weston_buffer_reference,
2032 destroy_listener);
2033
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002034 assert((struct weston_buffer *)data == ref->buffer);
Pekka Paalanende685b82012-12-04 15:58:12 +02002035 ref->buffer = NULL;
2036}
2037
2038WL_EXPORT void
2039weston_buffer_reference(struct weston_buffer_reference *ref,
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002040 struct weston_buffer *buffer)
Pekka Paalanende685b82012-12-04 15:58:12 +02002041{
2042 if (ref->buffer && buffer != ref->buffer) {
Kristian Høgsberg20347802013-03-04 12:07:46 -05002043 ref->buffer->busy_count--;
2044 if (ref->buffer->busy_count == 0) {
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002045 assert(wl_resource_get_client(ref->buffer->resource));
2046 wl_resource_queue_event(ref->buffer->resource,
Kristian Høgsberg20347802013-03-04 12:07:46 -05002047 WL_BUFFER_RELEASE);
2048 }
Pekka Paalanende685b82012-12-04 15:58:12 +02002049 wl_list_remove(&ref->destroy_listener.link);
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002050 }
2051
Pekka Paalanende685b82012-12-04 15:58:12 +02002052 if (buffer && buffer != ref->buffer) {
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04002053 buffer->busy_count++;
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002054 wl_signal_add(&buffer->destroy_signal,
Pekka Paalanende685b82012-12-04 15:58:12 +02002055 &ref->destroy_listener);
Pekka Paalanena6421c42012-12-04 15:58:10 +02002056 }
2057
Pekka Paalanende685b82012-12-04 15:58:12 +02002058 ref->buffer = buffer;
2059 ref->destroy_listener.notify = weston_buffer_reference_handle_destroy;
2060}
2061
2062static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002063weston_surface_attach(struct weston_surface *surface,
2064 struct weston_buffer *buffer)
Pekka Paalanende685b82012-12-04 15:58:12 +02002065{
2066 weston_buffer_reference(&surface->buffer_ref, buffer);
2067
Pekka Paalanena6421c42012-12-04 15:58:10 +02002068 if (!buffer) {
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002069 if (weston_surface_is_mapped(surface))
2070 weston_surface_unmap(surface);
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002071 }
2072
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002073 surface->compositor->renderer->attach(surface, buffer);
Pekka Paalanenbb2f3f22014-03-14 14:38:11 +02002074
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002075 weston_surface_calculate_size_from_buffer(surface);
Pekka Paalanen133e4392014-09-23 22:08:46 -04002076 weston_presentation_feedback_discard_list(&surface->feedback_list);
Benjamin Franzkefaa0a9d2011-02-21 16:24:53 +01002077}
2078
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002079WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002080weston_compositor_damage_all(struct weston_compositor *compositor)
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002081{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002082 struct weston_output *output;
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002083
2084 wl_list_for_each(output, &compositor->output_list, link)
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002085 weston_output_damage(output);
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002086}
2087
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05002088WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002089weston_output_damage(struct weston_output *output)
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002090{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002091 struct weston_compositor *compositor = output->compositor;
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002092
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002093 pixman_region32_union(&compositor->primary_plane.damage,
2094 &compositor->primary_plane.damage,
2095 &output->region);
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002096 weston_output_schedule_repaint(output);
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002097}
2098
Kristian Høgsberg01f941b2009-05-27 17:47:15 -04002099static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002100surface_flush_damage(struct weston_surface *surface)
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002101{
Pekka Paalanende685b82012-12-04 15:58:12 +02002102 if (surface->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002103 wl_shm_buffer_get(surface->buffer_ref.buffer->resource))
Kristian Høgsbergfa1be022012-09-05 22:49:55 -04002104 surface->compositor->renderer->flush_damage(surface);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002105
Pekka Paalanenb5026542014-11-12 15:09:24 +02002106 if (weston_timeline_enabled_ &&
2107 pixman_region32_not_empty(&surface->damage))
2108 TL_POINT("core_flush_damage", TLP_SURFACE(surface),
2109 TLP_OUTPUT(surface->output), TLP_END);
2110
Jason Ekstrandef540082014-06-26 10:37:36 -07002111 pixman_region32_clear(&surface->damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002112}
2113
2114static void
2115view_accumulate_damage(struct weston_view *view,
2116 pixman_region32_t *opaque)
2117{
2118 pixman_region32_t damage;
2119
2120 pixman_region32_init(&damage);
2121 if (view->transform.enabled) {
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002122 pixman_box32_t *extents;
2123
Jason Ekstranda7af7042013-10-12 22:38:11 -05002124 extents = pixman_region32_extents(&view->surface->damage);
Pekka Paalanenc7d7fdf2015-02-23 12:27:00 +02002125 view_compute_bbox(view, extents, &damage);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002126 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002127 pixman_region32_copy(&damage, &view->surface->damage);
2128 pixman_region32_translate(&damage,
Pekka Paalanen502f5e02015-02-23 14:08:25 +02002129 view->geometry.x, view->geometry.y);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002130 }
2131
Pekka Paalanen380adf52015-02-16 14:39:11 +02002132 pixman_region32_intersect(&damage, &damage,
2133 &view->transform.boundingbox);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002134 pixman_region32_subtract(&damage, &damage, opaque);
2135 pixman_region32_union(&view->plane->damage,
2136 &view->plane->damage, &damage);
2137 pixman_region32_fini(&damage);
2138 pixman_region32_copy(&view->clip, opaque);
Pekka Paalanen8844bf22015-02-18 16:30:47 +02002139 pixman_region32_union(opaque, opaque, &view->transform.opaque);
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002140}
2141
Kristian Høgsbergcce1aec2011-04-22 15:38:14 -04002142static void
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002143compositor_accumulate_damage(struct weston_compositor *ec)
2144{
2145 struct weston_plane *plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002146 struct weston_view *ev;
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002147 pixman_region32_t opaque, clip;
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002148
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002149 pixman_region32_init(&clip);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002150
2151 wl_list_for_each(plane, &ec->plane_list, link) {
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002152 pixman_region32_copy(&plane->clip, &clip);
2153
2154 pixman_region32_init(&opaque);
2155
Jason Ekstranda7af7042013-10-12 22:38:11 -05002156 wl_list_for_each(ev, &ec->view_list, link) {
2157 if (ev->plane != plane)
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002158 continue;
2159
Jason Ekstranda7af7042013-10-12 22:38:11 -05002160 view_accumulate_damage(ev, &opaque);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002161 }
2162
2163 pixman_region32_union(&clip, &clip, &opaque);
2164 pixman_region32_fini(&opaque);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002165 }
2166
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002167 pixman_region32_fini(&clip);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002168
Jason Ekstranda7af7042013-10-12 22:38:11 -05002169 wl_list_for_each(ev, &ec->view_list, link)
Derek Foreman060cf112015-11-18 16:32:26 -06002170 ev->surface->touched = false;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002171
2172 wl_list_for_each(ev, &ec->view_list, link) {
2173 if (ev->surface->touched)
2174 continue;
Derek Foreman060cf112015-11-18 16:32:26 -06002175 ev->surface->touched = true;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002176
2177 surface_flush_damage(ev->surface);
2178
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002179 /* Both the renderer and the backend have seen the buffer
2180 * by now. If renderer needs the buffer, it has its own
2181 * reference set. If the backend wants to keep the buffer
2182 * around for migrating the surface into a non-primary plane
2183 * later, keep_buffer is true. Otherwise, drop the core
2184 * reference now, and allow early buffer release. This enables
2185 * clients to use single-buffering.
2186 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05002187 if (!ev->surface->keep_buffer)
2188 weston_buffer_reference(&ev->surface->buffer_ref, NULL);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002189 }
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002190}
2191
2192static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002193surface_stash_subsurface_views(struct weston_surface *surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03002194{
2195 struct weston_subsurface *sub;
2196
Pekka Paalanene67858b2013-04-25 13:57:42 +03002197 wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002198 if (sub->surface == surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03002199 continue;
2200
Jason Ekstranda7af7042013-10-12 22:38:11 -05002201 wl_list_insert_list(&sub->unused_views, &sub->surface->views);
2202 wl_list_init(&sub->surface->views);
2203
2204 surface_stash_subsurface_views(sub->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002205 }
2206}
2207
2208static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05002209surface_free_unused_subsurface_views(struct weston_surface *surface)
Pekka Paalanene67858b2013-04-25 13:57:42 +03002210{
Jason Ekstranda7af7042013-10-12 22:38:11 -05002211 struct weston_subsurface *sub;
2212 struct weston_view *view, *nv;
Pekka Paalanene67858b2013-04-25 13:57:42 +03002213
Jason Ekstranda7af7042013-10-12 22:38:11 -05002214 wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
2215 if (sub->surface == surface)
2216 continue;
2217
George Kiagiadakised04d382014-06-13 18:10:26 +02002218 wl_list_for_each_safe(view, nv, &sub->unused_views, surface_link) {
2219 weston_view_unmap (view);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002220 weston_view_destroy(view);
George Kiagiadakised04d382014-06-13 18:10:26 +02002221 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002222
2223 surface_free_unused_subsurface_views(sub->surface);
2224 }
2225}
2226
2227static void
2228view_list_add_subsurface_view(struct weston_compositor *compositor,
2229 struct weston_subsurface *sub,
2230 struct weston_view *parent)
2231{
2232 struct weston_subsurface *child;
2233 struct weston_view *view = NULL, *iv;
2234
Pekka Paalanen661de3a2014-07-28 12:49:24 +03002235 if (!weston_surface_is_mapped(sub->surface))
2236 return;
2237
Jason Ekstranda7af7042013-10-12 22:38:11 -05002238 wl_list_for_each(iv, &sub->unused_views, surface_link) {
2239 if (iv->geometry.parent == parent) {
2240 view = iv;
2241 break;
Pekka Paalanene67858b2013-04-25 13:57:42 +03002242 }
2243 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002244
2245 if (view) {
2246 /* Put it back in the surface's list of views */
2247 wl_list_remove(&view->surface_link);
2248 wl_list_insert(&sub->surface->views, &view->surface_link);
2249 } else {
2250 view = weston_view_create(sub->surface);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002251 weston_view_set_position(view,
2252 sub->position.x,
2253 sub->position.y);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002254 weston_view_set_transform_parent(view, parent);
2255 }
2256
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03002257 view->parent_view = parent;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002258 weston_view_update_transform(view);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002259
Pekka Paalanenb188e912013-11-19 14:03:35 +02002260 if (wl_list_empty(&sub->surface->subsurface_list)) {
2261 wl_list_insert(compositor->view_list.prev, &view->link);
2262 return;
2263 }
2264
2265 wl_list_for_each(child, &sub->surface->subsurface_list, parent_link) {
2266 if (child->surface == sub->surface)
2267 wl_list_insert(compositor->view_list.prev, &view->link);
2268 else
Jason Ekstranda7af7042013-10-12 22:38:11 -05002269 view_list_add_subsurface_view(compositor, child, view);
Pekka Paalanenb188e912013-11-19 14:03:35 +02002270 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002271}
2272
2273static void
2274view_list_add(struct weston_compositor *compositor,
2275 struct weston_view *view)
2276{
2277 struct weston_subsurface *sub;
2278
2279 weston_view_update_transform(view);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002280
Pekka Paalanenb188e912013-11-19 14:03:35 +02002281 if (wl_list_empty(&view->surface->subsurface_list)) {
2282 wl_list_insert(compositor->view_list.prev, &view->link);
2283 return;
2284 }
2285
2286 wl_list_for_each(sub, &view->surface->subsurface_list, parent_link) {
2287 if (sub->surface == view->surface)
2288 wl_list_insert(compositor->view_list.prev, &view->link);
2289 else
Jason Ekstranda7af7042013-10-12 22:38:11 -05002290 view_list_add_subsurface_view(compositor, sub, view);
Pekka Paalanenb188e912013-11-19 14:03:35 +02002291 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002292}
2293
2294static void
2295weston_compositor_build_view_list(struct weston_compositor *compositor)
2296{
2297 struct weston_view *view;
2298 struct weston_layer *layer;
2299
2300 wl_list_for_each(layer, &compositor->layer_list, link)
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002301 wl_list_for_each(view, &layer->view_list.link, layer_link.link)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002302 surface_stash_subsurface_views(view->surface);
2303
2304 wl_list_init(&compositor->view_list);
2305 wl_list_for_each(layer, &compositor->layer_list, link) {
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002306 wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002307 view_list_add(compositor, view);
2308 }
2309 }
2310
2311 wl_list_for_each(layer, &compositor->layer_list, link)
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002312 wl_list_for_each(view, &layer->view_list.link, layer_link.link)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002313 surface_free_unused_subsurface_views(view->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002314}
2315
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002316static void
2317weston_output_take_feedback_list(struct weston_output *output,
2318 struct weston_surface *surface)
2319{
2320 struct weston_view *view;
2321 struct weston_presentation_feedback *feedback;
2322 uint32_t flags = 0xffffffff;
2323
2324 if (wl_list_empty(&surface->feedback_list))
2325 return;
2326
2327 /* All views must have the flag for the flag to survive. */
2328 wl_list_for_each(view, &surface->views, surface_link) {
2329 /* ignore views that are not on this output at all */
2330 if (view->output_mask & (1u << output->id))
2331 flags &= view->psf_flags;
2332 }
2333
2334 wl_list_for_each(feedback, &surface->feedback_list, link)
2335 feedback->psf_flags = flags;
2336
2337 wl_list_insert_list(&output->feedback_list, &surface->feedback_list);
2338 wl_list_init(&surface->feedback_list);
2339}
2340
David Herrmann1edf44c2013-10-22 17:11:26 +02002341static int
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04002342weston_output_repaint(struct weston_output *output)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002343{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002344 struct weston_compositor *ec = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002345 struct weston_view *ev;
Kristian Høgsberg30c018b2012-01-26 08:40:37 -05002346 struct weston_animation *animation, *next;
2347 struct weston_frame_callback *cb, *cnext;
Jonas Ådahldb773762012-06-13 00:01:21 +02002348 struct wl_list frame_callback_list;
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002349 pixman_region32_t output_damage;
David Herrmann1edf44c2013-10-22 17:11:26 +02002350 int r;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05002351
Ander Conselvan de Oliveirae1e23522013-12-13 22:10:55 +02002352 if (output->destroying)
2353 return 0;
2354
Pekka Paalanenb5026542014-11-12 15:09:24 +02002355 TL_POINT("core_repaint_begin", TLP_OUTPUT(output), TLP_END);
2356
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002357 /* Rebuild the surface list and update surface transforms up front. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05002358 weston_compositor_build_view_list(ec);
Pekka Paalanen15d60ef2012-01-27 14:38:33 +02002359
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002360 if (output->assign_planes && !output->disable_planes) {
Jesse Barnes5308a5e2012-02-09 13:12:57 -08002361 output->assign_planes(output);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002362 } else {
2363 wl_list_for_each(ev, &ec->view_list, link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002364 weston_view_move_to_plane(ev, &ec->primary_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002365 ev->psf_flags = 0;
2366 }
2367 }
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04002368
Pekka Paalanene67858b2013-04-25 13:57:42 +03002369 wl_list_init(&frame_callback_list);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002370 wl_list_for_each(ev, &ec->view_list, link) {
2371 /* Note: This operation is safe to do multiple times on the
2372 * same surface.
2373 */
2374 if (ev->surface->output == output) {
Pekka Paalanene67858b2013-04-25 13:57:42 +03002375 wl_list_insert_list(&frame_callback_list,
Jason Ekstranda7af7042013-10-12 22:38:11 -05002376 &ev->surface->frame_callback_list);
2377 wl_list_init(&ev->surface->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -04002378
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002379 weston_output_take_feedback_list(output, ev->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002380 }
2381 }
2382
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002383 compositor_accumulate_damage(ec);
Kristian Høgsberg53df1d82011-06-23 21:11:19 -04002384
Ander Conselvan de Oliveira4f521732012-08-15 14:02:05 -04002385 pixman_region32_init(&output_damage);
Ander Conselvan de Oliveira4f521732012-08-15 14:02:05 -04002386 pixman_region32_intersect(&output_damage,
2387 &ec->primary_plane.damage, &output->region);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02002388 pixman_region32_subtract(&output_damage,
2389 &output_damage, &ec->primary_plane.clip);
Ander Conselvan de Oliveira4f521732012-08-15 14:02:05 -04002390
Scott Moreauccbf29d2012-02-22 14:21:41 -07002391 if (output->dirty)
2392 weston_output_update_matrix(output);
2393
David Herrmann1edf44c2013-10-22 17:11:26 +02002394 r = output->repaint(output, &output_damage);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002395
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -05002396 pixman_region32_fini(&output_damage);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05002397
Kristian Høgsbergef044142011-06-21 15:02:12 -04002398 output->repaint_needed = 0;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002399
Kristian Høgsbergaa6019e2012-03-11 16:35:16 -04002400 weston_compositor_repick(ec);
Kristian Høgsbergaa6019e2012-03-11 16:35:16 -04002401
Jonas Ådahldb773762012-06-13 00:01:21 +02002402 wl_list_for_each_safe(cb, cnext, &frame_callback_list, link) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04002403 wl_callback_send_done(cb->resource, output->frame_time);
Jason Ekstrandfbbbec82013-06-14 10:07:57 -05002404 wl_resource_destroy(cb->resource);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05002405 }
2406
Scott Moreaud64cf212012-06-08 19:40:54 -06002407 wl_list_for_each_safe(animation, next, &output->animation_list, link) {
Scott Moreaud64cf212012-06-08 19:40:54 -06002408 animation->frame_counter++;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04002409 animation->frame(animation, output, output->frame_time);
Scott Moreaud64cf212012-06-08 19:40:54 -06002410 }
David Herrmann1edf44c2013-10-22 17:11:26 +02002411
Pekka Paalanenb5026542014-11-12 15:09:24 +02002412 TL_POINT("core_repaint_posted", TLP_OUTPUT(output), TLP_END);
2413
David Herrmann1edf44c2013-10-22 17:11:26 +02002414 return r;
Kristian Høgsbergef044142011-06-21 15:02:12 -04002415}
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002416
Pekka Paalanen82919792014-05-21 13:51:49 +03002417static void
2418weston_output_schedule_repaint_reset(struct weston_output *output)
2419{
Pekka Paalanen82919792014-05-21 13:51:49 +03002420 output->repaint_scheduled = 0;
2421 TL_POINT("core_repaint_exit_loop", TLP_OUTPUT(output), TLP_END);
Pekka Paalanen82919792014-05-21 13:51:49 +03002422}
2423
Pekka Paalanen0513a952014-05-21 16:17:27 +03002424static int
2425output_repaint_timer_handler(void *data)
2426{
2427 struct weston_output *output = data;
2428 struct weston_compositor *compositor = output->compositor;
2429
2430 if (output->repaint_needed &&
2431 compositor->state != WESTON_COMPOSITOR_SLEEPING &&
2432 compositor->state != WESTON_COMPOSITOR_OFFSCREEN &&
2433 weston_output_repaint(output) == 0)
2434 return 0;
2435
2436 weston_output_schedule_repaint_reset(output);
2437
2438 return 0;
2439}
2440
Kristian Høgsbergef044142011-06-21 15:02:12 -04002441WL_EXPORT void
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04002442weston_output_finish_frame(struct weston_output *output,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +02002443 const struct timespec *stamp,
2444 uint32_t presented_flags)
Kristian Høgsbergef044142011-06-21 15:02:12 -04002445{
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05002446 struct weston_compositor *compositor = output->compositor;
Pekka Paalanen0513a952014-05-21 16:17:27 +03002447 int32_t refresh_nsec;
2448 struct timespec now;
2449 struct timespec gone;
2450 int msec;
Pekka Paalanen133e4392014-09-23 22:08:46 -04002451
Pekka Paalanenb5026542014-11-12 15:09:24 +02002452 TL_POINT("core_repaint_finished", TLP_OUTPUT(output),
2453 TLP_VBLANK(stamp), TLP_END);
2454
Pekka Paalanend7894d02015-07-03 15:08:53 +03002455 refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
Pekka Paalanen133e4392014-09-23 22:08:46 -04002456 weston_presentation_feedback_present_list(&output->feedback_list,
2457 output, refresh_nsec, stamp,
Pekka Paalanen363aa7b2014-12-17 16:20:40 +02002458 output->msc,
2459 presented_flags);
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05002460
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04002461 output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 1000000;
Kristian Høgsberg991810c2013-10-16 11:10:12 -07002462
Pekka Paalanen0513a952014-05-21 16:17:27 +03002463 weston_compositor_read_presentation_clock(compositor, &now);
2464 timespec_sub(&gone, &now, stamp);
2465 msec = (refresh_nsec - timespec_to_nsec(&gone)) / 1000000; /* floor */
2466 msec -= compositor->repaint_msec;
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05002467
Pekka Paalanen8fd4de42015-03-19 12:27:29 +02002468 if (msec < -1000 || msec > 1000) {
2469 static bool warned;
2470
2471 if (!warned)
2472 weston_log("Warning: computed repaint delay is "
2473 "insane: %d msec\n", msec);
2474 warned = true;
2475
2476 msec = 0;
2477 }
2478
Mario Kleinerb7df04e2015-06-21 21:25:15 +02002479 /* Called from restart_repaint_loop and restart happens already after
2480 * the deadline given by repaint_msec? In that case we delay until
2481 * the deadline of the next frame, to give clients a more predictable
2482 * timing of the repaint cycle to lock on. */
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002483 if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID && msec < 0)
Mario Kleinerb7df04e2015-06-21 21:25:15 +02002484 msec += refresh_nsec / 1000000;
2485
Pekka Paalanen8fd4de42015-03-19 12:27:29 +02002486 if (msec < 1)
Pekka Paalanen0513a952014-05-21 16:17:27 +03002487 output_repaint_timer_handler(output);
2488 else
2489 wl_event_source_timer_update(output->repaint_timer, msec);
Kristian Høgsberg7dbf5e22012-03-05 19:50:08 -05002490}
2491
2492static void
2493idle_repaint(void *data)
2494{
2495 struct weston_output *output = data;
2496
Jonas Ådahle5a12252013-04-05 23:07:11 +02002497 output->start_repaint_loop(output);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002498}
2499
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002500WL_EXPORT void
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002501weston_layer_entry_insert(struct weston_layer_entry *list,
2502 struct weston_layer_entry *entry)
2503{
2504 wl_list_insert(&list->link, &entry->link);
2505 entry->layer = list->layer;
2506}
2507
2508WL_EXPORT void
2509weston_layer_entry_remove(struct weston_layer_entry *entry)
2510{
2511 wl_list_remove(&entry->link);
2512 wl_list_init(&entry->link);
2513 entry->layer = NULL;
2514}
2515
2516WL_EXPORT void
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002517weston_layer_init(struct weston_layer *layer, struct wl_list *below)
2518{
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002519 wl_list_init(&layer->view_list.link);
2520 layer->view_list.layer = layer;
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03002521 weston_layer_set_mask_infinite(layer);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002522 if (below != NULL)
2523 wl_list_insert(below, &layer->link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002524}
2525
2526WL_EXPORT void
Giulio Camuffo95ec0f92014-07-09 22:12:57 +03002527weston_layer_set_mask(struct weston_layer *layer,
2528 int x, int y, int width, int height)
2529{
2530 struct weston_view *view;
2531
2532 layer->mask.x1 = x;
2533 layer->mask.x2 = x + width;
2534 layer->mask.y1 = y;
2535 layer->mask.y2 = y + height;
2536
2537 wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
2538 weston_view_geometry_dirty(view);
2539 }
2540}
2541
2542WL_EXPORT void
2543weston_layer_set_mask_infinite(struct weston_layer *layer)
2544{
2545 weston_layer_set_mask(layer, INT32_MIN, INT32_MIN,
2546 UINT32_MAX, UINT32_MAX);
2547}
2548
2549WL_EXPORT void
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002550weston_output_schedule_repaint(struct weston_output *output)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002551{
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002552 struct weston_compositor *compositor = output->compositor;
Kristian Høgsbergef044142011-06-21 15:02:12 -04002553 struct wl_event_loop *loop;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002554
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002555 if (compositor->state == WESTON_COMPOSITOR_SLEEPING ||
2556 compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04002557 return;
2558
Pekka Paalanenb5026542014-11-12 15:09:24 +02002559 if (!output->repaint_needed)
2560 TL_POINT("core_repaint_req", TLP_OUTPUT(output), TLP_END);
2561
Kristian Høgsbergef044142011-06-21 15:02:12 -04002562 loop = wl_display_get_event_loop(compositor->wl_display);
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002563 output->repaint_needed = 1;
2564 if (output->repaint_scheduled)
2565 return;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002566
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002567 wl_event_loop_add_idle(loop, idle_repaint, output);
2568 output->repaint_scheduled = 1;
Pekka Paalanenb5026542014-11-12 15:09:24 +02002569 TL_POINT("core_repaint_enter_loop", TLP_OUTPUT(output), TLP_END);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04002570}
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -05002571
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002572WL_EXPORT void
Kristian Høgsberg49952d12012-06-20 00:35:59 -04002573weston_compositor_schedule_repaint(struct weston_compositor *compositor)
2574{
2575 struct weston_output *output;
2576
2577 wl_list_for_each(output, &compositor->output_list, link)
2578 weston_output_schedule_repaint(output);
2579}
2580
Kristian Høgsberg5503bf82008-11-06 10:38:17 -05002581static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -04002582surface_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04002583{
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002584 wl_resource_destroy(resource);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04002585}
2586
Kristian Høgsberg5503bf82008-11-06 10:38:17 -05002587static void
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002588surface_attach(struct wl_client *client,
2589 struct wl_resource *resource,
2590 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
2591{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002592 struct weston_surface *surface = wl_resource_get_user_data(resource);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002593 struct weston_buffer *buffer = NULL;
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002594
Kristian Høgsbergab19f932013-08-20 11:30:54 -07002595 if (buffer_resource) {
Jason Ekstrand6bd62942013-06-20 20:38:23 -05002596 buffer = weston_buffer_from_resource(buffer_resource);
Kristian Høgsbergab19f932013-08-20 11:30:54 -07002597 if (buffer == NULL) {
2598 wl_client_post_no_memory(client);
2599 return;
2600 }
Kristian Høgsberg08b58c72013-08-15 12:26:42 -07002601 }
Kristian Høgsberga691aee2011-06-23 21:43:50 -04002602
Pekka Paalanende685b82012-12-04 15:58:12 +02002603 /* Attach, attach, without commit in between does not send
2604 * wl_buffer.release. */
Jason Ekstrand7b982072014-05-20 14:33:03 -05002605 weston_surface_state_set_buffer(&surface->pending, buffer);
Ander Conselvan de Oliveirae11683a2012-03-27 17:36:40 +03002606
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002607 surface->pending.sx = sx;
2608 surface->pending.sy = sy;
Giulio Camuffo184df502013-02-21 11:29:21 +01002609 surface->pending.newly_attached = 1;
Kristian Høgsbergf9212892008-10-11 18:40:23 -04002610}
2611
Kristian Høgsberg5503bf82008-11-06 10:38:17 -05002612static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05002613surface_damage(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -04002614 struct wl_resource *resource,
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05002615 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -05002616{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002617 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04002618
Derek Foreman57e92ed2015-11-17 14:11:35 -06002619 if (width <= 0 || height <= 0)
2620 return;
2621
Derek Foreman152254b2015-11-26 14:17:48 -06002622 pixman_region32_union_rect(&surface->pending.damage_surface,
2623 &surface->pending.damage_surface,
2624 x, y, width, height);
2625}
2626
2627static void
2628surface_damage_buffer(struct wl_client *client,
2629 struct wl_resource *resource,
2630 int32_t x, int32_t y, int32_t width, int32_t height)
2631{
2632 struct weston_surface *surface = wl_resource_get_user_data(resource);
2633
2634 if (width <= 0 || height <= 0)
2635 return;
2636
2637 pixman_region32_union_rect(&surface->pending.damage_buffer,
2638 &surface->pending.damage_buffer,
Kristian Høgsberg460a79b2012-06-18 15:09:11 -04002639 x, y, width, height);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05002640}
2641
Kristian Høgsberg33418202011-08-16 23:01:28 -04002642static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -04002643destroy_frame_callback(struct wl_resource *resource)
Kristian Høgsberg33418202011-08-16 23:01:28 -04002644{
Jason Ekstrandfbbbec82013-06-14 10:07:57 -05002645 struct weston_frame_callback *cb = wl_resource_get_user_data(resource);
Kristian Høgsberg904055a2011-08-18 17:55:30 -04002646
2647 wl_list_remove(&cb->link);
Pekka Paalanen8c196452011-11-15 11:45:42 +02002648 free(cb);
Kristian Høgsberg33418202011-08-16 23:01:28 -04002649}
2650
2651static void
2652surface_frame(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -04002653 struct wl_resource *resource, uint32_t callback)
Kristian Høgsberg33418202011-08-16 23:01:28 -04002654{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002655 struct weston_frame_callback *cb;
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002656 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg33418202011-08-16 23:01:28 -04002657
2658 cb = malloc(sizeof *cb);
2659 if (cb == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -04002660 wl_resource_post_no_memory(resource);
Kristian Høgsberg33418202011-08-16 23:01:28 -04002661 return;
2662 }
Pekka Paalanenbc106382012-10-10 12:49:31 +03002663
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07002664 cb->resource = wl_resource_create(client, &wl_callback_interface, 1,
2665 callback);
2666 if (cb->resource == NULL) {
2667 free(cb);
2668 wl_resource_post_no_memory(resource);
2669 return;
2670 }
2671
Jason Ekstranda85118c2013-06-27 20:17:02 -05002672 wl_resource_set_implementation(cb->resource, NULL, cb,
2673 destroy_frame_callback);
Kristian Høgsberg33418202011-08-16 23:01:28 -04002674
Pekka Paalanenbc106382012-10-10 12:49:31 +03002675 wl_list_insert(surface->pending.frame_callback_list.prev, &cb->link);
Kristian Høgsberg33418202011-08-16 23:01:28 -04002676}
2677
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002678static void
2679surface_set_opaque_region(struct wl_client *client,
2680 struct wl_resource *resource,
2681 struct wl_resource *region_resource)
2682{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002683 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002684 struct weston_region *region;
2685
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002686 if (region_resource) {
Jason Ekstrand8895efc2013-06-14 10:07:56 -05002687 region = wl_resource_get_user_data(region_resource);
Pekka Paalanen512dde82012-10-10 12:49:27 +03002688 pixman_region32_copy(&surface->pending.opaque,
2689 &region->region);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002690 } else {
Jason Ekstrandef540082014-06-26 10:37:36 -07002691 pixman_region32_clear(&surface->pending.opaque);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002692 }
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002693}
2694
2695static void
2696surface_set_input_region(struct wl_client *client,
2697 struct wl_resource *resource,
2698 struct wl_resource *region_resource)
2699{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002700 struct weston_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05002701 struct weston_region *region;
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002702
2703 if (region_resource) {
Jason Ekstrand8895efc2013-06-14 10:07:56 -05002704 region = wl_resource_get_user_data(region_resource);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03002705 pixman_region32_copy(&surface->pending.input,
2706 &region->region);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002707 } else {
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03002708 pixman_region32_fini(&surface->pending.input);
2709 region_init_infinite(&surface->pending.input);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002710 }
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002711}
2712
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002713static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03002714weston_surface_commit_subsurface_order(struct weston_surface *surface)
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002715{
Pekka Paalanene67858b2013-04-25 13:57:42 +03002716 struct weston_subsurface *sub;
2717
2718 wl_list_for_each_reverse(sub, &surface->subsurface_list_pending,
2719 parent_link_pending) {
2720 wl_list_remove(&sub->parent_link);
2721 wl_list_insert(&surface->subsurface_list, &sub->parent_link);
2722 }
2723}
2724
2725static void
Pekka Paalanen04baea52016-04-26 15:50:58 +03002726weston_surface_build_buffer_matrix(const struct weston_surface *surface,
Jason Ekstrand1e059042014-10-16 10:55:19 -05002727 struct weston_matrix *matrix)
2728{
Pekka Paalanen04baea52016-04-26 15:50:58 +03002729 const struct weston_buffer_viewport *vp = &surface->buffer_viewport;
Jason Ekstrand1e059042014-10-16 10:55:19 -05002730 double src_width, src_height, dest_width, dest_height;
2731
2732 weston_matrix_init(matrix);
2733
2734 if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
2735 src_width = surface->width_from_buffer;
2736 src_height = surface->height_from_buffer;
2737 } else {
2738 src_width = wl_fixed_to_double(vp->buffer.src_width);
2739 src_height = wl_fixed_to_double(vp->buffer.src_height);
2740 }
2741
2742 if (vp->surface.width == -1) {
2743 dest_width = src_width;
2744 dest_height = src_height;
2745 } else {
2746 dest_width = vp->surface.width;
2747 dest_height = vp->surface.height;
2748 }
2749
2750 if (src_width != dest_width || src_height != dest_height)
2751 weston_matrix_scale(matrix,
2752 src_width / dest_width,
2753 src_height / dest_height, 1);
2754
2755 if (vp->buffer.src_width != wl_fixed_from_int(-1))
2756 weston_matrix_translate(matrix,
2757 wl_fixed_to_double(vp->buffer.src_x),
2758 wl_fixed_to_double(vp->buffer.src_y),
2759 0);
2760
2761 switch (vp->buffer.transform) {
2762 case WL_OUTPUT_TRANSFORM_FLIPPED:
2763 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
2764 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
2765 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
2766 weston_matrix_scale(matrix, -1, 1, 1);
2767 weston_matrix_translate(matrix,
2768 surface->width_from_buffer, 0, 0);
2769 break;
2770 }
2771
2772 switch (vp->buffer.transform) {
2773 default:
2774 case WL_OUTPUT_TRANSFORM_NORMAL:
2775 case WL_OUTPUT_TRANSFORM_FLIPPED:
2776 break;
2777 case WL_OUTPUT_TRANSFORM_90:
2778 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
2779 weston_matrix_rotate_xy(matrix, 0, 1);
2780 weston_matrix_translate(matrix,
2781 surface->height_from_buffer, 0, 0);
2782 break;
2783 case WL_OUTPUT_TRANSFORM_180:
2784 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
2785 weston_matrix_rotate_xy(matrix, -1, 0);
2786 weston_matrix_translate(matrix,
2787 surface->width_from_buffer,
2788 surface->height_from_buffer, 0);
2789 break;
2790 case WL_OUTPUT_TRANSFORM_270:
2791 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
2792 weston_matrix_rotate_xy(matrix, 0, -1);
2793 weston_matrix_translate(matrix,
2794 0, surface->width_from_buffer, 0);
2795 break;
2796 }
2797
2798 weston_matrix_scale(matrix, vp->buffer.scale, vp->buffer.scale, 1);
2799}
2800
Derek Foreman152254b2015-11-26 14:17:48 -06002801/* Translate pending damage in buffer co-ordinates to surface
2802 * co-ordinates and union it with a pixman_region32_t.
2803 * This should only be called after the buffer is attached.
2804 */
2805static void
2806apply_damage_buffer(pixman_region32_t *dest,
2807 struct weston_surface *surface,
2808 struct weston_surface_state *state)
2809{
2810 struct weston_buffer *buffer = surface->buffer_ref.buffer;
2811
2812 /* wl_surface.damage_buffer needs to be clipped to the buffer,
2813 * translated into surface co-ordinates and unioned with
2814 * any other surface damage.
2815 * None of this makes sense if there is no buffer though.
2816 */
2817 if (buffer && pixman_region32_not_empty(&state->damage_buffer)) {
2818 pixman_region32_t buffer_damage;
2819
2820 pixman_region32_intersect_rect(&state->damage_buffer,
2821 &state->damage_buffer,
2822 0, 0, buffer->width,
2823 buffer->height);
2824 pixman_region32_init(&buffer_damage);
2825 weston_matrix_transform_region(&buffer_damage,
2826 &surface->buffer_to_surface_matrix,
2827 &state->damage_buffer);
2828 pixman_region32_union(dest, dest, &buffer_damage);
2829 pixman_region32_fini(&buffer_damage);
2830 }
2831 /* We should clear this on commit even if there was no buffer */
2832 pixman_region32_clear(&state->damage_buffer);
2833}
2834
Jason Ekstrand1e059042014-10-16 10:55:19 -05002835static void
Jason Ekstrand7b982072014-05-20 14:33:03 -05002836weston_surface_commit_state(struct weston_surface *surface,
2837 struct weston_surface_state *state)
Pekka Paalanene67858b2013-04-25 13:57:42 +03002838{
Jason Ekstranda7af7042013-10-12 22:38:11 -05002839 struct weston_view *view;
Ander Conselvan de Oliveira5df8eca2012-10-30 17:44:01 +02002840 pixman_region32_t opaque;
2841
Alexander Larsson4ea95522013-05-22 14:41:37 +02002842 /* wl_surface.set_buffer_transform */
Alexander Larsson4ea95522013-05-22 14:41:37 +02002843 /* wl_surface.set_buffer_scale */
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02002844 /* wl_viewport.set */
Jason Ekstrand7b982072014-05-20 14:33:03 -05002845 surface->buffer_viewport = state->buffer_viewport;
Alexander Larsson4ea95522013-05-22 14:41:37 +02002846
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002847 /* wl_surface.attach */
Jason Ekstrand7b982072014-05-20 14:33:03 -05002848 if (state->newly_attached)
2849 weston_surface_attach(surface, state->buffer);
2850 weston_surface_state_set_buffer(state, NULL);
Giulio Camuffo184df502013-02-21 11:29:21 +01002851
Jason Ekstrand1e059042014-10-16 10:55:19 -05002852 weston_surface_build_buffer_matrix(surface,
2853 &surface->surface_to_buffer_matrix);
2854 weston_matrix_invert(&surface->buffer_to_surface_matrix,
2855 &surface->surface_to_buffer_matrix);
2856
Jason Ekstrand7b982072014-05-20 14:33:03 -05002857 if (state->newly_attached || state->buffer_viewport.changed) {
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002858 weston_surface_update_size(surface);
2859 if (surface->configure)
Jason Ekstrand7b982072014-05-20 14:33:03 -05002860 surface->configure(surface, state->sx, state->sy);
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002861 }
Giulio Camuffo184df502013-02-21 11:29:21 +01002862
Jason Ekstrand7b982072014-05-20 14:33:03 -05002863 state->sx = 0;
2864 state->sy = 0;
2865 state->newly_attached = 0;
2866 state->buffer_viewport.changed = 0;
Pekka Paalanen8e159182012-10-10 12:49:25 +03002867
Derek Foreman152254b2015-11-26 14:17:48 -06002868 /* wl_surface.damage and wl_surface.damage_buffer */
Pekka Paalanenb5026542014-11-12 15:09:24 +02002869 if (weston_timeline_enabled_ &&
Derek Foreman152254b2015-11-26 14:17:48 -06002870 (pixman_region32_not_empty(&state->damage_surface) ||
2871 pixman_region32_not_empty(&state->damage_buffer)))
Pekka Paalanenb5026542014-11-12 15:09:24 +02002872 TL_POINT("core_commit_damage", TLP_SURFACE(surface), TLP_END);
Derek Foreman152254b2015-11-26 14:17:48 -06002873
Pekka Paalanen8e159182012-10-10 12:49:25 +03002874 pixman_region32_union(&surface->damage, &surface->damage,
Derek Foreman152254b2015-11-26 14:17:48 -06002875 &state->damage_surface);
2876
2877 apply_damage_buffer(&surface->damage, surface, state);
2878
Kristian Høgsberg4d0214c2012-11-08 11:36:02 -05002879 pixman_region32_intersect_rect(&surface->damage, &surface->damage,
Jason Ekstrandef540082014-06-26 10:37:36 -07002880 0, 0, surface->width, surface->height);
Derek Foreman152254b2015-11-26 14:17:48 -06002881 pixman_region32_clear(&state->damage_surface);
Pekka Paalanen512dde82012-10-10 12:49:27 +03002882
2883 /* wl_surface.set_opaque_region */
Jason Ekstrand7b982072014-05-20 14:33:03 -05002884 pixman_region32_init(&opaque);
2885 pixman_region32_intersect_rect(&opaque, &state->opaque,
2886 0, 0, surface->width, surface->height);
Ander Conselvan de Oliveira5df8eca2012-10-30 17:44:01 +02002887
2888 if (!pixman_region32_equal(&opaque, &surface->opaque)) {
2889 pixman_region32_copy(&surface->opaque, &opaque);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002890 wl_list_for_each(view, &surface->views, surface_link)
2891 weston_view_geometry_dirty(view);
Ander Conselvan de Oliveira5df8eca2012-10-30 17:44:01 +02002892 }
2893
2894 pixman_region32_fini(&opaque);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03002895
2896 /* wl_surface.set_input_region */
Jason Ekstrand7b982072014-05-20 14:33:03 -05002897 pixman_region32_intersect_rect(&surface->input, &state->input,
2898 0, 0, surface->width, surface->height);
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03002899
Pekka Paalanenbc106382012-10-10 12:49:31 +03002900 /* wl_surface.frame */
2901 wl_list_insert_list(&surface->frame_callback_list,
Jason Ekstrand7b982072014-05-20 14:33:03 -05002902 &state->frame_callback_list);
2903 wl_list_init(&state->frame_callback_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -04002904
2905 /* XXX:
2906 * What should happen with a feedback request, if there
2907 * is no wl_buffer attached for this commit?
2908 */
2909
2910 /* presentation.feedback */
2911 wl_list_insert_list(&surface->feedback_list,
2912 &state->feedback_list);
2913 wl_list_init(&state->feedback_list);
Jason Ekstrand7b982072014-05-20 14:33:03 -05002914}
2915
2916static void
2917weston_surface_commit(struct weston_surface *surface)
2918{
2919 weston_surface_commit_state(surface, &surface->pending);
Pekka Paalanenbc106382012-10-10 12:49:31 +03002920
Pekka Paalanene67858b2013-04-25 13:57:42 +03002921 weston_surface_commit_subsurface_order(surface);
2922
Pekka Paalanen0cbd3b52012-10-10 12:49:28 +03002923 weston_surface_schedule_repaint(surface);
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002924}
2925
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02002926static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03002927weston_subsurface_commit(struct weston_subsurface *sub);
2928
2929static void
2930weston_subsurface_parent_commit(struct weston_subsurface *sub,
2931 int parent_is_synchronized);
2932
2933static void
2934surface_commit(struct wl_client *client, struct wl_resource *resource)
2935{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002936 struct weston_surface *surface = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03002937 struct weston_subsurface *sub = weston_surface_to_subsurface(surface);
2938
2939 if (sub) {
2940 weston_subsurface_commit(sub);
2941 return;
2942 }
2943
2944 weston_surface_commit(surface);
2945
2946 wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
2947 if (sub->surface != surface)
2948 weston_subsurface_parent_commit(sub, 0);
2949 }
2950}
2951
2952static void
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02002953surface_set_buffer_transform(struct wl_client *client,
2954 struct wl_resource *resource, int transform)
2955{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002956 struct weston_surface *surface = wl_resource_get_user_data(resource);
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02002957
Jonny Lamba55f1392014-05-30 12:07:15 +02002958 /* if wl_output.transform grows more members this will need to be updated. */
2959 if (transform < 0 ||
2960 transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) {
2961 wl_resource_post_error(resource,
2962 WL_SURFACE_ERROR_INVALID_TRANSFORM,
2963 "buffer transform must be a valid transform "
2964 "('%d' specified)", transform);
2965 return;
2966 }
2967
Pekka Paalanen952b6c82014-03-14 14:38:15 +02002968 surface->pending.buffer_viewport.buffer.transform = transform;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002969 surface->pending.buffer_viewport.changed = 1;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02002970}
2971
Alexander Larsson4ea95522013-05-22 14:41:37 +02002972static void
2973surface_set_buffer_scale(struct wl_client *client,
2974 struct wl_resource *resource,
Alexander Larssonedddbd12013-05-24 13:09:43 +02002975 int32_t scale)
Alexander Larsson4ea95522013-05-22 14:41:37 +02002976{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05002977 struct weston_surface *surface = wl_resource_get_user_data(resource);
Alexander Larsson4ea95522013-05-22 14:41:37 +02002978
Jonny Lamba55f1392014-05-30 12:07:15 +02002979 if (scale < 1) {
2980 wl_resource_post_error(resource,
2981 WL_SURFACE_ERROR_INVALID_SCALE,
2982 "buffer scale must be at least one "
2983 "('%d' specified)", scale);
2984 return;
2985 }
2986
Pekka Paalanen952b6c82014-03-14 14:38:15 +02002987 surface->pending.buffer_viewport.buffer.scale = scale;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02002988 surface->pending.buffer_viewport.changed = 1;
Alexander Larsson4ea95522013-05-22 14:41:37 +02002989}
2990
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002991static const struct wl_surface_interface surface_interface = {
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05002992 surface_destroy,
2993 surface_attach,
Kristian Høgsberg33418202011-08-16 23:01:28 -04002994 surface_damage,
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05002995 surface_frame,
2996 surface_set_opaque_region,
Pekka Paalanen5df44de2012-10-10 12:49:23 +03002997 surface_set_input_region,
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02002998 surface_commit,
Alexander Larsson4ea95522013-05-22 14:41:37 +02002999 surface_set_buffer_transform,
Derek Foreman152254b2015-11-26 14:17:48 -06003000 surface_set_buffer_scale,
3001 surface_damage_buffer
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003002};
3003
3004static void
3005compositor_create_surface(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -04003006 struct wl_resource *resource, uint32_t id)
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003007{
Kristian Høgsbergc2d70422013-06-25 15:34:33 -04003008 struct weston_compositor *ec = wl_resource_get_user_data(resource);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003009 struct weston_surface *surface;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003010
Kristian Høgsberg18c93002012-01-27 11:58:31 -05003011 surface = weston_surface_create(ec);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04003012 if (surface == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -04003013 wl_resource_post_no_memory(resource);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003014 return;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04003015 }
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003016
Jason Ekstranda85118c2013-06-27 20:17:02 -05003017 surface->resource =
3018 wl_resource_create(client, &wl_surface_interface,
3019 wl_resource_get_version(resource), id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07003020 if (surface->resource == NULL) {
3021 weston_surface_destroy(surface);
3022 wl_resource_post_no_memory(resource);
3023 return;
3024 }
Jason Ekstranda85118c2013-06-27 20:17:02 -05003025 wl_resource_set_implementation(surface->resource, &surface_interface,
3026 surface, destroy_surface);
Kristian Høgsbergf03a04a2014-04-06 22:04:50 -07003027
3028 wl_signal_emit(&ec->create_surface_signal, surface);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003029}
3030
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003031static void
3032destroy_region(struct wl_resource *resource)
3033{
Jason Ekstrand8895efc2013-06-14 10:07:56 -05003034 struct weston_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003035
3036 pixman_region32_fini(&region->region);
3037 free(region);
3038}
3039
3040static void
3041region_destroy(struct wl_client *client, struct wl_resource *resource)
3042{
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003043 wl_resource_destroy(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003044}
3045
3046static void
3047region_add(struct wl_client *client, struct wl_resource *resource,
3048 int32_t x, int32_t y, int32_t width, int32_t height)
3049{
Jason Ekstrand8895efc2013-06-14 10:07:56 -05003050 struct weston_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003051
3052 pixman_region32_union_rect(&region->region, &region->region,
3053 x, y, width, height);
3054}
3055
3056static void
3057region_subtract(struct wl_client *client, struct wl_resource *resource,
3058 int32_t x, int32_t y, int32_t width, int32_t height)
3059{
Jason Ekstrand8895efc2013-06-14 10:07:56 -05003060 struct weston_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003061 pixman_region32_t rect;
3062
3063 pixman_region32_init_rect(&rect, x, y, width, height);
3064 pixman_region32_subtract(&region->region, &region->region, &rect);
3065 pixman_region32_fini(&rect);
3066}
3067
3068static const struct wl_region_interface region_interface = {
3069 region_destroy,
3070 region_add,
3071 region_subtract
3072};
3073
3074static void
3075compositor_create_region(struct wl_client *client,
3076 struct wl_resource *resource, uint32_t id)
3077{
3078 struct weston_region *region;
3079
3080 region = malloc(sizeof *region);
3081 if (region == NULL) {
3082 wl_resource_post_no_memory(resource);
3083 return;
3084 }
3085
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003086 pixman_region32_init(&region->region);
3087
Jason Ekstranda85118c2013-06-27 20:17:02 -05003088 region->resource =
3089 wl_resource_create(client, &wl_region_interface, 1, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07003090 if (region->resource == NULL) {
3091 free(region);
3092 wl_resource_post_no_memory(resource);
3093 return;
3094 }
Jason Ekstranda85118c2013-06-27 20:17:02 -05003095 wl_resource_set_implementation(region->resource, &region_interface,
3096 region, destroy_region);
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003097}
3098
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04003099static const struct wl_compositor_interface compositor_interface = {
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003100 compositor_create_surface,
Kristian Høgsberg5e7e6f22012-02-23 16:11:59 -05003101 compositor_create_region
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05003102};
3103
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003104static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03003105weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
3106{
3107 struct weston_surface *surface = sub->surface;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003108
Jason Ekstrand7b982072014-05-20 14:33:03 -05003109 weston_surface_commit_state(surface, &sub->cached);
3110 weston_buffer_reference(&sub->cached_buffer_ref, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003111
3112 weston_surface_commit_subsurface_order(surface);
3113
3114 weston_surface_schedule_repaint(surface);
3115
Jason Ekstrand7b982072014-05-20 14:33:03 -05003116 sub->has_cached_data = 0;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003117}
3118
3119static void
3120weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
3121{
3122 struct weston_surface *surface = sub->surface;
3123
3124 /*
3125 * If this commit would cause the surface to move by the
3126 * attach(dx, dy) parameters, the old damage region must be
3127 * translated to correspond to the new surface coordinate system
Chris Michael062edf22015-11-26 11:30:00 -05003128 * origin.
Pekka Paalanene67858b2013-04-25 13:57:42 +03003129 */
Derek Foreman152254b2015-11-26 14:17:48 -06003130 pixman_region32_translate(&sub->cached.damage_surface,
Pekka Paalanene67858b2013-04-25 13:57:42 +03003131 -surface->pending.sx, -surface->pending.sy);
Derek Foreman152254b2015-11-26 14:17:48 -06003132 pixman_region32_union(&sub->cached.damage_surface,
3133 &sub->cached.damage_surface,
3134 &surface->pending.damage_surface);
3135 pixman_region32_clear(&surface->pending.damage_surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003136
3137 if (surface->pending.newly_attached) {
3138 sub->cached.newly_attached = 1;
Jason Ekstrand7b982072014-05-20 14:33:03 -05003139 weston_surface_state_set_buffer(&sub->cached,
3140 surface->pending.buffer);
3141 weston_buffer_reference(&sub->cached_buffer_ref,
Pekka Paalanene67858b2013-04-25 13:57:42 +03003142 surface->pending.buffer);
Pekka Paalanen133e4392014-09-23 22:08:46 -04003143 weston_presentation_feedback_discard_list(
3144 &sub->cached.feedback_list);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003145 }
3146 sub->cached.sx += surface->pending.sx;
3147 sub->cached.sy += surface->pending.sy;
Pekka Paalanen260ba382014-03-14 14:38:12 +02003148
Derek Foreman152254b2015-11-26 14:17:48 -06003149 apply_damage_buffer(&sub->cached.damage_surface, surface, &surface->pending);
3150
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003151 sub->cached.buffer_viewport.changed |=
3152 surface->pending.buffer_viewport.changed;
3153 sub->cached.buffer_viewport.buffer =
3154 surface->pending.buffer_viewport.buffer;
3155 sub->cached.buffer_viewport.surface =
3156 surface->pending.buffer_viewport.surface;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003157
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02003158 weston_surface_reset_pending_buffer(surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003159
3160 pixman_region32_copy(&sub->cached.opaque, &surface->pending.opaque);
3161
3162 pixman_region32_copy(&sub->cached.input, &surface->pending.input);
3163
3164 wl_list_insert_list(&sub->cached.frame_callback_list,
3165 &surface->pending.frame_callback_list);
3166 wl_list_init(&surface->pending.frame_callback_list);
3167
Pekka Paalanen133e4392014-09-23 22:08:46 -04003168 wl_list_insert_list(&sub->cached.feedback_list,
3169 &surface->pending.feedback_list);
3170 wl_list_init(&surface->pending.feedback_list);
3171
Jason Ekstrand7b982072014-05-20 14:33:03 -05003172 sub->has_cached_data = 1;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003173}
3174
Derek Foreman280e7dd2014-10-03 13:13:42 -05003175static bool
Pekka Paalanene67858b2013-04-25 13:57:42 +03003176weston_subsurface_is_synchronized(struct weston_subsurface *sub)
3177{
3178 while (sub) {
3179 if (sub->synchronized)
Derek Foreman280e7dd2014-10-03 13:13:42 -05003180 return true;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003181
3182 if (!sub->parent)
Derek Foreman280e7dd2014-10-03 13:13:42 -05003183 return false;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003184
3185 sub = weston_surface_to_subsurface(sub->parent);
3186 }
3187
Carlos Olmedo Escobar61a9bf52014-11-04 14:38:39 +01003188 return false;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003189}
3190
3191static void
3192weston_subsurface_commit(struct weston_subsurface *sub)
3193{
3194 struct weston_surface *surface = sub->surface;
3195 struct weston_subsurface *tmp;
3196
3197 /* Recursive check for effectively synchronized. */
3198 if (weston_subsurface_is_synchronized(sub)) {
3199 weston_subsurface_commit_to_cache(sub);
3200 } else {
Jason Ekstrand7b982072014-05-20 14:33:03 -05003201 if (sub->has_cached_data) {
Pekka Paalanene67858b2013-04-25 13:57:42 +03003202 /* flush accumulated state from cache */
3203 weston_subsurface_commit_to_cache(sub);
3204 weston_subsurface_commit_from_cache(sub);
3205 } else {
3206 weston_surface_commit(surface);
3207 }
3208
3209 wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
3210 if (tmp->surface != surface)
3211 weston_subsurface_parent_commit(tmp, 0);
3212 }
3213 }
3214}
3215
3216static void
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003217weston_subsurface_synchronized_commit(struct weston_subsurface *sub)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003218{
3219 struct weston_surface *surface = sub->surface;
3220 struct weston_subsurface *tmp;
3221
Pekka Paalanene67858b2013-04-25 13:57:42 +03003222 /* From now on, commit_from_cache the whole sub-tree, regardless of
3223 * the synchronized mode of each child. This sub-surface or some
3224 * of its ancestors were synchronized, so we are synchronized
3225 * all the way down.
3226 */
3227
Jason Ekstrand7b982072014-05-20 14:33:03 -05003228 if (sub->has_cached_data)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003229 weston_subsurface_commit_from_cache(sub);
3230
3231 wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
3232 if (tmp->surface != surface)
3233 weston_subsurface_parent_commit(tmp, 1);
3234 }
3235}
3236
3237static void
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003238weston_subsurface_parent_commit(struct weston_subsurface *sub,
3239 int parent_is_synchronized)
3240{
Jason Ekstranda7af7042013-10-12 22:38:11 -05003241 struct weston_view *view;
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003242 if (sub->position.set) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05003243 wl_list_for_each(view, &sub->surface->views, surface_link)
3244 weston_view_set_position(view,
3245 sub->position.x,
3246 sub->position.y);
3247
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003248 sub->position.set = 0;
3249 }
3250
3251 if (parent_is_synchronized || sub->synchronized)
3252 weston_subsurface_synchronized_commit(sub);
3253}
3254
Pekka Paalanen8274d902014-08-06 19:36:51 +03003255static int
3256subsurface_get_label(struct weston_surface *surface, char *buf, size_t len)
3257{
3258 return snprintf(buf, len, "sub-surface");
3259}
3260
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003261static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003262subsurface_configure(struct weston_surface *surface, int32_t dx, int32_t dy)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003263{
3264 struct weston_compositor *compositor = surface->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003265 struct weston_view *view;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003266
Jason Ekstranda7af7042013-10-12 22:38:11 -05003267 wl_list_for_each(view, &surface->views, surface_link)
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003268 weston_view_set_position(view,
3269 view->geometry.x + dx,
3270 view->geometry.y + dy);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003271
3272 /* No need to check parent mappedness, because if parent is not
3273 * mapped, parent is not in a visible layer, so this sub-surface
3274 * will not be drawn either.
3275 */
3276 if (!weston_surface_is_mapped(surface)) {
Pekka Paalaneneb3cf222014-06-30 11:52:07 +03003277 struct weston_output *output;
3278
Derek Foreman4b1a0a12014-09-10 15:37:33 -05003279 /* Cannot call weston_view_update_transform(),
Pekka Paalanene67858b2013-04-25 13:57:42 +03003280 * because that would call it also for the parent surface,
3281 * which might not be mapped yet. That would lead to
3282 * inconsistent state, where the window could never be
3283 * mapped.
3284 *
Derek Foreman4b1a0a12014-09-10 15:37:33 -05003285 * Instead just assign any output, to make
Pekka Paalanene67858b2013-04-25 13:57:42 +03003286 * weston_surface_is_mapped() return true, so that when the
3287 * parent surface does get mapped, this one will get
Pekka Paalaneneb3cf222014-06-30 11:52:07 +03003288 * included, too. See view_list_add().
Pekka Paalanene67858b2013-04-25 13:57:42 +03003289 */
3290 assert(!wl_list_empty(&compositor->output_list));
Pekka Paalaneneb3cf222014-06-30 11:52:07 +03003291 output = container_of(compositor->output_list.next,
3292 struct weston_output, link);
3293
3294 surface->output = output;
Bryce Harrington89324ce2015-12-23 18:38:07 -08003295 weston_surface_update_output_mask(surface, 1u << output->id);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003296 }
3297}
3298
3299static struct weston_subsurface *
3300weston_surface_to_subsurface(struct weston_surface *surface)
3301{
3302 if (surface->configure == subsurface_configure)
3303 return surface->configure_private;
3304
3305 return NULL;
3306}
3307
Pekka Paalanen01388e22013-04-25 13:57:44 +03003308WL_EXPORT struct weston_surface *
3309weston_surface_get_main_surface(struct weston_surface *surface)
3310{
3311 struct weston_subsurface *sub;
3312
3313 while (surface && (sub = weston_surface_to_subsurface(surface)))
3314 surface = sub->parent;
3315
3316 return surface;
3317}
3318
Pekka Paalanen50b67472014-10-01 15:02:41 +03003319WL_EXPORT int
3320weston_surface_set_role(struct weston_surface *surface,
3321 const char *role_name,
3322 struct wl_resource *error_resource,
3323 uint32_t error_code)
3324{
3325 assert(role_name);
3326
3327 if (surface->role_name == NULL ||
3328 surface->role_name == role_name ||
3329 strcmp(surface->role_name, role_name) == 0) {
3330 surface->role_name = role_name;
3331
3332 return 0;
3333 }
3334
3335 wl_resource_post_error(error_resource, error_code,
3336 "Cannot assign role %s to wl_surface@%d,"
3337 " already has role %s\n",
3338 role_name,
3339 wl_resource_get_id(surface->resource),
3340 surface->role_name);
3341 return -1;
3342}
3343
Pekka Paalanen8274d902014-08-06 19:36:51 +03003344WL_EXPORT void
3345weston_surface_set_label_func(struct weston_surface *surface,
3346 int (*desc)(struct weston_surface *,
3347 char *, size_t))
3348{
3349 surface->get_label = desc;
Pekka Paalanenb5026542014-11-12 15:09:24 +02003350 surface->timeline.force_refresh = 1;
Pekka Paalanen8274d902014-08-06 19:36:51 +03003351}
3352
Pekka Paalanenc647ed72015-02-09 13:16:57 +02003353/** Get the size of surface contents
3354 *
3355 * \param surface The surface to query.
3356 * \param width Returns the width of raw contents.
3357 * \param height Returns the height of raw contents.
3358 *
3359 * Retrieves the raw surface content size in pixels for the given surface.
3360 * This is the whole content size in buffer pixels. If the surface
3361 * has no content or the renderer does not implement this feature,
3362 * zeroes are returned.
3363 *
3364 * This function is used to determine the buffer size needed for
3365 * a weston_surface_copy_content() call.
3366 */
3367WL_EXPORT void
3368weston_surface_get_content_size(struct weston_surface *surface,
3369 int *width, int *height)
3370{
3371 struct weston_renderer *rer = surface->compositor->renderer;
3372
3373 if (!rer->surface_get_content_size) {
3374 *width = 0;
3375 *height = 0;
3376 return;
3377 }
3378
3379 rer->surface_get_content_size(surface, width, height);
3380}
3381
3382/** Copy surface contents to system memory.
3383 *
3384 * \param surface The surface to copy from.
3385 * \param target Pointer to the target memory buffer.
3386 * \param size Size of the target buffer in bytes.
3387 * \param src_x X location on contents to copy from.
3388 * \param src_y Y location on contents to copy from.
3389 * \param width Width in pixels of the area to copy.
3390 * \param height Height in pixels of the area to copy.
3391 * \return 0 for success, -1 for failure.
3392 *
3393 * Surface contents are maintained by the renderer. They can be in a
3394 * reserved weston_buffer or as a copy, e.g. a GL texture, or something
3395 * else.
3396 *
3397 * Surface contents are copied into memory pointed to by target,
3398 * which has size bytes of space available. The target memory
3399 * may be larger than needed, but being smaller returns an error.
3400 * The extra bytes in target may or may not be written; their content is
3401 * unspecified. Size must be large enough to hold the image.
3402 *
3403 * The image in the target memory will be arranged in rows from
3404 * top to bottom, and pixels on a row from left to right. The pixel
3405 * format is PIXMAN_a8b8g8r8, 4 bytes per pixel, and stride is exactly
3406 * width * 4.
3407 *
3408 * Parameters src_x and src_y define the upper-left corner in buffer
3409 * coordinates (pixels) to copy from. Parameters width and height
3410 * define the size of the area to copy in pixels.
3411 *
3412 * The rectangle defined by src_x, src_y, width, height must fit in
3413 * the surface contents. Otherwise an error is returned.
3414 *
3415 * Use surface_get_data_size to determine the content size; the
3416 * needed target buffer size and rectangle limits.
3417 *
3418 * CURRENT IMPLEMENTATION RESTRICTIONS:
3419 * - the machine must be little-endian due to Pixman formats.
3420 *
3421 * NOTE: Pixman formats are premultiplied.
3422 */
3423WL_EXPORT int
3424weston_surface_copy_content(struct weston_surface *surface,
3425 void *target, size_t size,
3426 int src_x, int src_y,
3427 int width, int height)
3428{
3429 struct weston_renderer *rer = surface->compositor->renderer;
3430 int cw, ch;
3431 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
3432
3433 if (!rer->surface_copy_content)
3434 return -1;
3435
3436 weston_surface_get_content_size(surface, &cw, &ch);
3437
3438 if (src_x < 0 || src_y < 0)
3439 return -1;
3440
3441 if (width <= 0 || height <= 0)
3442 return -1;
3443
3444 if (src_x + width > cw || src_y + height > ch)
3445 return -1;
3446
3447 if (width * bytespp * height > size)
3448 return -1;
3449
3450 return rer->surface_copy_content(surface, target, size,
3451 src_x, src_y, width, height);
3452}
3453
Pekka Paalanene67858b2013-04-25 13:57:42 +03003454static void
3455subsurface_set_position(struct wl_client *client,
3456 struct wl_resource *resource, int32_t x, int32_t y)
3457{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003458 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003459
3460 if (!sub)
3461 return;
3462
3463 sub->position.x = x;
3464 sub->position.y = y;
3465 sub->position.set = 1;
3466}
3467
3468static struct weston_subsurface *
3469subsurface_from_surface(struct weston_surface *surface)
3470{
3471 struct weston_subsurface *sub;
3472
3473 sub = weston_surface_to_subsurface(surface);
3474 if (sub)
3475 return sub;
3476
3477 wl_list_for_each(sub, &surface->subsurface_list, parent_link)
3478 if (sub->surface == surface)
3479 return sub;
3480
3481 return NULL;
3482}
3483
3484static struct weston_subsurface *
3485subsurface_sibling_check(struct weston_subsurface *sub,
3486 struct weston_surface *surface,
3487 const char *request)
3488{
3489 struct weston_subsurface *sibling;
3490
3491 sibling = subsurface_from_surface(surface);
3492
3493 if (!sibling) {
3494 wl_resource_post_error(sub->resource,
3495 WL_SUBSURFACE_ERROR_BAD_SURFACE,
3496 "%s: wl_surface@%d is not a parent or sibling",
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003497 request, wl_resource_get_id(surface->resource));
Pekka Paalanene67858b2013-04-25 13:57:42 +03003498 return NULL;
3499 }
3500
3501 if (sibling->parent != sub->parent) {
3502 wl_resource_post_error(sub->resource,
3503 WL_SUBSURFACE_ERROR_BAD_SURFACE,
3504 "%s: wl_surface@%d has a different parent",
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003505 request, wl_resource_get_id(surface->resource));
Pekka Paalanene67858b2013-04-25 13:57:42 +03003506 return NULL;
3507 }
3508
3509 return sibling;
3510}
3511
3512static void
3513subsurface_place_above(struct wl_client *client,
3514 struct wl_resource *resource,
3515 struct wl_resource *sibling_resource)
3516{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003517 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003518 struct weston_surface *surface =
3519 wl_resource_get_user_data(sibling_resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003520 struct weston_subsurface *sibling;
3521
3522 if (!sub)
3523 return;
3524
3525 sibling = subsurface_sibling_check(sub, surface, "place_above");
3526 if (!sibling)
3527 return;
3528
3529 wl_list_remove(&sub->parent_link_pending);
3530 wl_list_insert(sibling->parent_link_pending.prev,
3531 &sub->parent_link_pending);
3532}
3533
3534static void
3535subsurface_place_below(struct wl_client *client,
3536 struct wl_resource *resource,
3537 struct wl_resource *sibling_resource)
3538{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003539 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003540 struct weston_surface *surface =
3541 wl_resource_get_user_data(sibling_resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003542 struct weston_subsurface *sibling;
3543
3544 if (!sub)
3545 return;
3546
3547 sibling = subsurface_sibling_check(sub, surface, "place_below");
3548 if (!sibling)
3549 return;
3550
3551 wl_list_remove(&sub->parent_link_pending);
3552 wl_list_insert(&sibling->parent_link_pending,
3553 &sub->parent_link_pending);
3554}
3555
3556static void
3557subsurface_set_sync(struct wl_client *client, struct wl_resource *resource)
3558{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003559 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003560
3561 if (sub)
3562 sub->synchronized = 1;
3563}
3564
3565static void
3566subsurface_set_desync(struct wl_client *client, struct wl_resource *resource)
3567{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003568 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003569
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003570 if (sub && sub->synchronized) {
Pekka Paalanene67858b2013-04-25 13:57:42 +03003571 sub->synchronized = 0;
Pekka Paalanen16abf6a2013-05-17 16:46:05 +03003572
3573 /* If sub became effectively desynchronized, flush. */
3574 if (!weston_subsurface_is_synchronized(sub))
3575 weston_subsurface_synchronized_commit(sub);
3576 }
Pekka Paalanene67858b2013-04-25 13:57:42 +03003577}
3578
3579static void
Pekka Paalanene67858b2013-04-25 13:57:42 +03003580weston_subsurface_unlink_parent(struct weston_subsurface *sub)
3581{
3582 wl_list_remove(&sub->parent_link);
3583 wl_list_remove(&sub->parent_link_pending);
3584 wl_list_remove(&sub->parent_destroy_listener.link);
3585 sub->parent = NULL;
3586}
3587
3588static void
3589weston_subsurface_destroy(struct weston_subsurface *sub);
3590
3591static void
3592subsurface_handle_surface_destroy(struct wl_listener *listener, void *data)
3593{
3594 struct weston_subsurface *sub =
3595 container_of(listener, struct weston_subsurface,
3596 surface_destroy_listener);
Pekka Paalanenca790762015-04-17 14:23:38 +03003597 assert(data == sub->surface);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003598
3599 /* The protocol object (wl_resource) is left inert. */
3600 if (sub->resource)
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003601 wl_resource_set_user_data(sub->resource, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003602
3603 weston_subsurface_destroy(sub);
3604}
3605
3606static void
3607subsurface_handle_parent_destroy(struct wl_listener *listener, void *data)
3608{
3609 struct weston_subsurface *sub =
3610 container_of(listener, struct weston_subsurface,
3611 parent_destroy_listener);
Pekka Paalanenca790762015-04-17 14:23:38 +03003612 assert(data == sub->parent);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003613 assert(sub->surface != sub->parent);
3614
3615 if (weston_surface_is_mapped(sub->surface))
3616 weston_surface_unmap(sub->surface);
3617
3618 weston_subsurface_unlink_parent(sub);
3619}
3620
3621static void
3622subsurface_resource_destroy(struct wl_resource *resource)
3623{
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003624 struct weston_subsurface *sub = wl_resource_get_user_data(resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003625
3626 if (sub)
3627 weston_subsurface_destroy(sub);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003628}
3629
3630static void
3631subsurface_destroy(struct wl_client *client, struct wl_resource *resource)
3632{
3633 wl_resource_destroy(resource);
3634}
3635
3636static void
3637weston_subsurface_link_parent(struct weston_subsurface *sub,
3638 struct weston_surface *parent)
3639{
3640 sub->parent = parent;
3641 sub->parent_destroy_listener.notify = subsurface_handle_parent_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003642 wl_signal_add(&parent->destroy_signal,
Pekka Paalanene67858b2013-04-25 13:57:42 +03003643 &sub->parent_destroy_listener);
3644
3645 wl_list_insert(&parent->subsurface_list, &sub->parent_link);
3646 wl_list_insert(&parent->subsurface_list_pending,
3647 &sub->parent_link_pending);
3648}
3649
3650static void
3651weston_subsurface_link_surface(struct weston_subsurface *sub,
3652 struct weston_surface *surface)
3653{
3654 sub->surface = surface;
3655 sub->surface_destroy_listener.notify =
3656 subsurface_handle_surface_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003657 wl_signal_add(&surface->destroy_signal,
Pekka Paalanene67858b2013-04-25 13:57:42 +03003658 &sub->surface_destroy_listener);
3659}
3660
3661static void
3662weston_subsurface_destroy(struct weston_subsurface *sub)
3663{
Jason Ekstranda7af7042013-10-12 22:38:11 -05003664 struct weston_view *view, *next;
3665
Pekka Paalanene67858b2013-04-25 13:57:42 +03003666 assert(sub->surface);
3667
3668 if (sub->resource) {
3669 assert(weston_surface_to_subsurface(sub->surface) == sub);
3670 assert(sub->parent_destroy_listener.notify ==
3671 subsurface_handle_parent_destroy);
3672
George Kiagiadakised04d382014-06-13 18:10:26 +02003673 wl_list_for_each_safe(view, next, &sub->surface->views, surface_link) {
3674 weston_view_unmap(view);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003675 weston_view_destroy(view);
George Kiagiadakised04d382014-06-13 18:10:26 +02003676 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05003677
Pekka Paalanene67858b2013-04-25 13:57:42 +03003678 if (sub->parent)
3679 weston_subsurface_unlink_parent(sub);
3680
Jason Ekstrand7b982072014-05-20 14:33:03 -05003681 weston_surface_state_fini(&sub->cached);
3682 weston_buffer_reference(&sub->cached_buffer_ref, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003683
3684 sub->surface->configure = NULL;
3685 sub->surface->configure_private = NULL;
Pekka Paalanen8274d902014-08-06 19:36:51 +03003686 weston_surface_set_label_func(sub->surface, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003687 } else {
3688 /* the dummy weston_subsurface for the parent itself */
3689 assert(sub->parent_destroy_listener.notify == NULL);
3690 wl_list_remove(&sub->parent_link);
3691 wl_list_remove(&sub->parent_link_pending);
3692 }
3693
3694 wl_list_remove(&sub->surface_destroy_listener.link);
3695 free(sub);
3696}
3697
3698static const struct wl_subsurface_interface subsurface_implementation = {
3699 subsurface_destroy,
3700 subsurface_set_position,
3701 subsurface_place_above,
3702 subsurface_place_below,
3703 subsurface_set_sync,
3704 subsurface_set_desync
3705};
3706
3707static struct weston_subsurface *
3708weston_subsurface_create(uint32_t id, struct weston_surface *surface,
3709 struct weston_surface *parent)
3710{
3711 struct weston_subsurface *sub;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003712 struct wl_client *client = wl_resource_get_client(surface->resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003713
Bryce Harringtonde16d892014-11-20 22:21:57 -08003714 sub = zalloc(sizeof *sub);
3715 if (sub == NULL)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003716 return NULL;
3717
Jason Ekstranda7af7042013-10-12 22:38:11 -05003718 wl_list_init(&sub->unused_views);
3719
Jason Ekstranda85118c2013-06-27 20:17:02 -05003720 sub->resource =
3721 wl_resource_create(client, &wl_subsurface_interface, 1, id);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003722 if (!sub->resource) {
3723 free(sub);
3724 return NULL;
3725 }
3726
Jason Ekstranda85118c2013-06-27 20:17:02 -05003727 wl_resource_set_implementation(sub->resource,
3728 &subsurface_implementation,
3729 sub, subsurface_resource_destroy);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003730 weston_subsurface_link_surface(sub, surface);
3731 weston_subsurface_link_parent(sub, parent);
Jason Ekstrand7b982072014-05-20 14:33:03 -05003732 weston_surface_state_init(&sub->cached);
3733 sub->cached_buffer_ref.buffer = NULL;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003734 sub->synchronized = 1;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003735
3736 return sub;
3737}
3738
3739/* Create a dummy subsurface for having the parent itself in its
3740 * sub-surface lists. Makes stacking order manipulation easy.
3741 */
3742static struct weston_subsurface *
3743weston_subsurface_create_for_parent(struct weston_surface *parent)
3744{
3745 struct weston_subsurface *sub;
3746
Bryce Harringtonde16d892014-11-20 22:21:57 -08003747 sub = zalloc(sizeof *sub);
3748 if (sub == NULL)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003749 return NULL;
3750
3751 weston_subsurface_link_surface(sub, parent);
3752 sub->parent = parent;
3753 wl_list_insert(&parent->subsurface_list, &sub->parent_link);
3754 wl_list_insert(&parent->subsurface_list_pending,
3755 &sub->parent_link_pending);
3756
3757 return sub;
3758}
3759
3760static void
3761subcompositor_get_subsurface(struct wl_client *client,
3762 struct wl_resource *resource,
3763 uint32_t id,
3764 struct wl_resource *surface_resource,
3765 struct wl_resource *parent_resource)
3766{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003767 struct weston_surface *surface =
3768 wl_resource_get_user_data(surface_resource);
3769 struct weston_surface *parent =
3770 wl_resource_get_user_data(parent_resource);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003771 struct weston_subsurface *sub;
3772 static const char where[] = "get_subsurface: wl_subsurface@";
3773
3774 if (surface == parent) {
3775 wl_resource_post_error(resource,
3776 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
3777 "%s%d: wl_surface@%d cannot be its own parent",
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003778 where, id, wl_resource_get_id(surface_resource));
Pekka Paalanene67858b2013-04-25 13:57:42 +03003779 return;
3780 }
3781
3782 if (weston_surface_to_subsurface(surface)) {
3783 wl_resource_post_error(resource,
3784 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
3785 "%s%d: wl_surface@%d is already a sub-surface",
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003786 where, id, wl_resource_get_id(surface_resource));
Pekka Paalanene67858b2013-04-25 13:57:42 +03003787 return;
3788 }
3789
Pekka Paalanen50b67472014-10-01 15:02:41 +03003790 if (weston_surface_set_role(surface, "wl_subsurface", resource,
3791 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE) < 0)
Pekka Paalanene67858b2013-04-25 13:57:42 +03003792 return;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003793
Pekka Paalanen86c8ca02013-05-17 16:46:07 +03003794 if (weston_surface_get_main_surface(parent) == surface) {
3795 wl_resource_post_error(resource,
3796 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
3797 "%s%d: wl_surface@%d is an ancestor of parent",
Jason Ekstrand0bd587e2013-06-14 10:08:02 -05003798 where, id, wl_resource_get_id(surface_resource));
Pekka Paalanen86c8ca02013-05-17 16:46:07 +03003799 return;
3800 }
3801
Pekka Paalanene67858b2013-04-25 13:57:42 +03003802 /* make sure the parent is in its own list */
3803 if (wl_list_empty(&parent->subsurface_list)) {
3804 if (!weston_subsurface_create_for_parent(parent)) {
3805 wl_resource_post_no_memory(resource);
3806 return;
3807 }
3808 }
3809
3810 sub = weston_subsurface_create(id, surface, parent);
3811 if (!sub) {
3812 wl_resource_post_no_memory(resource);
3813 return;
3814 }
3815
3816 surface->configure = subsurface_configure;
3817 surface->configure_private = sub;
Pekka Paalanen8274d902014-08-06 19:36:51 +03003818 weston_surface_set_label_func(surface, subsurface_get_label);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003819}
3820
3821static void
3822subcompositor_destroy(struct wl_client *client, struct wl_resource *resource)
3823{
3824 wl_resource_destroy(resource);
3825}
3826
3827static const struct wl_subcompositor_interface subcompositor_interface = {
3828 subcompositor_destroy,
3829 subcompositor_get_subsurface
3830};
3831
3832static void
3833bind_subcompositor(struct wl_client *client,
3834 void *data, uint32_t version, uint32_t id)
3835{
3836 struct weston_compositor *compositor = data;
Jason Ekstranda85118c2013-06-27 20:17:02 -05003837 struct wl_resource *resource;
Pekka Paalanene67858b2013-04-25 13:57:42 +03003838
Jason Ekstranda85118c2013-06-27 20:17:02 -05003839 resource =
3840 wl_resource_create(client, &wl_subcompositor_interface, 1, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07003841 if (resource == NULL) {
3842 wl_client_post_no_memory(client);
3843 return;
3844 }
3845 wl_resource_set_implementation(resource, &subcompositor_interface,
3846 compositor, NULL);
Pekka Paalanene67858b2013-04-25 13:57:42 +03003847}
3848
Bryce Harringtonc9626a32015-12-11 13:11:38 -08003849/** Set a DPMS mode on all of the compositor's outputs
3850 *
3851 * \param compositor The compositor instance
3852 * \param state The DPMS state the outputs will be set to
3853 */
Pekka Paalanene67858b2013-04-25 13:57:42 +03003854static void
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003855weston_compositor_dpms(struct weston_compositor *compositor,
3856 enum dpms_enum state)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003857{
3858 struct weston_output *output;
3859
3860 wl_list_for_each(output, &compositor->output_list, link)
3861 if (output->set_dpms)
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003862 output->set_dpms(output, state);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003863}
3864
Bryce Harringtonc9626a32015-12-11 13:11:38 -08003865/** Restores the compositor to active status
3866 *
3867 * \param compositor The compositor instance
3868 *
3869 * If the compositor was in a sleeping mode, all outputs are powered
3870 * back on via DPMS. Otherwise if the compositor was inactive
3871 * (idle/locked, offscreen, or sleeping) then the compositor's wake
3872 * signal will fire.
3873 *
3874 * Restarts the idle timer.
3875 */
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02003876WL_EXPORT void
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003877weston_compositor_wake(struct weston_compositor *compositor)
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02003878{
Neil Roberts8b62e202013-09-30 13:14:47 +01003879 uint32_t old_state = compositor->state;
3880
3881 /* The state needs to be changed before emitting the wake
3882 * signal because that may try to schedule a repaint which
3883 * will not work if the compositor is still sleeping */
3884 compositor->state = WESTON_COMPOSITOR_ACTIVE;
3885
3886 switch (old_state) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003887 case WESTON_COMPOSITOR_SLEEPING:
3888 weston_compositor_dpms(compositor, WESTON_DPMS_ON);
3889 /* fall through */
3890 case WESTON_COMPOSITOR_IDLE:
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01003891 case WESTON_COMPOSITOR_OFFSCREEN:
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02003892 wl_signal_emit(&compositor->wake_signal, compositor);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003893 /* fall through */
3894 default:
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003895 wl_event_source_timer_update(compositor->idle_source,
3896 compositor->idle_time * 1000);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02003897 }
3898}
3899
Bryce Harringtonc9626a32015-12-11 13:11:38 -08003900/** Turns off rendering and frame events for the compositor.
3901 *
3902 * \param compositor The compositor instance
3903 *
3904 * This is used for example to prevent further rendering while the
3905 * compositor is shutting down.
3906 *
3907 * \note When offscreen state is entered, outputs will be powered
3908 * back on if they were sleeping (in DPMS off mode), even though
3909 * no rendering will be performed.
3910 *
3911 * Stops the idle timer.
3912 */
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003913WL_EXPORT void
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01003914weston_compositor_offscreen(struct weston_compositor *compositor)
3915{
3916 switch (compositor->state) {
3917 case WESTON_COMPOSITOR_OFFSCREEN:
3918 return;
3919 case WESTON_COMPOSITOR_SLEEPING:
3920 weston_compositor_dpms(compositor, WESTON_DPMS_ON);
3921 /* fall through */
3922 default:
3923 compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
3924 wl_event_source_timer_update(compositor->idle_source, 0);
3925 }
3926}
3927
Bryce Harringtonc9626a32015-12-11 13:11:38 -08003928/** Powers down all attached output devices
3929 *
3930 * \param compositor The compositor instance
3931 *
3932 * Causes rendering to the outputs to cease, and no frame events to be
3933 * sent. Only powers down the outputs if the compositor is not already
3934 * in sleep mode.
3935 *
3936 * Stops the idle timer.
3937 */
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01003938WL_EXPORT void
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003939weston_compositor_sleep(struct weston_compositor *compositor)
3940{
3941 if (compositor->state == WESTON_COMPOSITOR_SLEEPING)
3942 return;
3943
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01003944 wl_event_source_timer_update(compositor->idle_source, 0);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003945 compositor->state = WESTON_COMPOSITOR_SLEEPING;
3946 weston_compositor_dpms(compositor, WESTON_DPMS_OFF);
3947}
3948
Bryce Harringtonc9626a32015-12-11 13:11:38 -08003949/** Sets compositor to idle mode
3950 *
3951 * \param data The compositor instance
3952 *
3953 * This is called when the idle timer fires. Once the compositor is in
3954 * idle mode it requires a wake action (e.g. via
3955 * weston_compositor_wake()) to restore it. The compositor's
3956 * idle_signal will be triggered when the idle event occurs.
3957 *
3958 * Idleness can be inhibited by setting the compositor's idle_inhibit
3959 * property.
3960 */
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04003961static int
3962idle_handler(void *data)
3963{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003964 struct weston_compositor *compositor = data;
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04003965
3966 if (compositor->idle_inhibit)
3967 return 1;
3968
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02003969 compositor->state = WESTON_COMPOSITOR_IDLE;
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02003970 wl_signal_emit(&compositor->idle_signal, compositor);
Kristian Høgsberge10a5d92011-04-22 14:01:18 -04003971
3972 return 1;
3973}
3974
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003975WL_EXPORT void
Xiong Zhang97116532013-10-23 13:58:31 +08003976weston_plane_init(struct weston_plane *plane,
3977 struct weston_compositor *ec,
3978 int32_t x, int32_t y)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003979{
3980 pixman_region32_init(&plane->damage);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02003981 pixman_region32_init(&plane->clip);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003982 plane->x = x;
3983 plane->y = y;
Xiong Zhang97116532013-10-23 13:58:31 +08003984 plane->compositor = ec;
Ander Conselvan de Oliveira3c36bf32013-07-05 16:05:26 +03003985
3986 /* Init the link so that the call to wl_list_remove() when releasing
3987 * the plane without ever stacking doesn't lead to a crash */
3988 wl_list_init(&plane->link);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003989}
3990
3991WL_EXPORT void
3992weston_plane_release(struct weston_plane *plane)
3993{
Xiong Zhang97116532013-10-23 13:58:31 +08003994 struct weston_view *view;
3995
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003996 pixman_region32_fini(&plane->damage);
Ander Conselvan de Oliveirae1bd5a02013-03-05 17:30:29 +02003997 pixman_region32_fini(&plane->clip);
Ander Conselvan de Oliveira3c36bf32013-07-05 16:05:26 +03003998
Xiong Zhang97116532013-10-23 13:58:31 +08003999 wl_list_for_each(view, &plane->compositor->view_list, link) {
4000 if (view->plane == plane)
4001 view->plane = NULL;
4002 }
4003
Ander Conselvan de Oliveira3c36bf32013-07-05 16:05:26 +03004004 wl_list_remove(&plane->link);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04004005}
4006
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02004007WL_EXPORT void
4008weston_compositor_stack_plane(struct weston_compositor *ec,
4009 struct weston_plane *plane,
4010 struct weston_plane *above)
4011{
4012 if (above)
4013 wl_list_insert(above->link.prev, &plane->link);
4014 else
4015 wl_list_insert(&ec->plane_list, &plane->link);
4016}
4017
Casey Dahlin9074db52012-04-19 22:50:09 -04004018static void unbind_resource(struct wl_resource *resource)
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04004019{
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05004020 wl_list_remove(wl_resource_get_link(resource));
Kristian Høgsbergd2baf1f2011-10-11 22:20:37 -04004021}
4022
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004023static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004024bind_output(struct wl_client *client,
4025 void *data, uint32_t version, uint32_t id)
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05004026{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004027 struct weston_output *output = data;
4028 struct weston_mode *mode;
Kristian Høgsbergfd07fb72011-08-29 15:03:09 -04004029 struct wl_resource *resource;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05004030
Jason Ekstranda85118c2013-06-27 20:17:02 -05004031 resource = wl_resource_create(client, &wl_output_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06004032 version, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07004033 if (resource == NULL) {
4034 wl_client_post_no_memory(client);
4035 return;
4036 }
Kristian Høgsbergfd07fb72011-08-29 15:03:09 -04004037
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05004038 wl_list_insert(&output->resource_list, wl_resource_get_link(resource));
Jason Ekstranda85118c2013-06-27 20:17:02 -05004039 wl_resource_set_implementation(resource, NULL, data, unbind_resource);
Casey Dahlin9074db52012-04-19 22:50:09 -04004040
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05004041 wl_output_send_geometry(resource,
4042 output->x,
4043 output->y,
4044 output->mm_width,
4045 output->mm_height,
4046 output->subpixel,
Kristian Høgsberg0e696472012-07-22 15:49:57 -04004047 output->make, output->model,
Kristian Høgsberg05890dc2012-08-10 10:09:20 -04004048 output->transform);
Jasper St. Pierre0013a292014-08-07 16:43:11 -04004049 if (version >= WL_OUTPUT_SCALE_SINCE_VERSION)
Alexander Larsson4ea95522013-05-22 14:41:37 +02004050 wl_output_send_scale(resource,
Hardeningff39efa2013-09-18 23:56:35 +02004051 output->current_scale);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004052
4053 wl_list_for_each (mode, &output->mode_list, link) {
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05004054 wl_output_send_mode(resource,
4055 mode->flags,
4056 mode->width,
4057 mode->height,
4058 mode->refresh);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004059 }
Alexander Larsson4ea95522013-05-22 14:41:37 +02004060
Jasper St. Pierre0013a292014-08-07 16:43:11 -04004061 if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
Alexander Larsson4ea95522013-05-22 14:41:37 +02004062 wl_output_send_done(resource);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05004063}
4064
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02004065/* Move other outputs when one is removed so the space remains contiguos. */
4066static void
4067weston_compositor_remove_output(struct weston_compositor *compositor,
4068 struct weston_output *remove_output)
4069{
4070 struct weston_output *output;
4071 int offset = 0;
4072
4073 wl_list_for_each(output, &compositor->output_list, link) {
4074 if (output == remove_output) {
4075 offset = output->width;
4076 continue;
4077 }
4078
4079 if (offset > 0) {
4080 weston_output_move(output,
4081 output->x - offset, output->y);
4082 output->dirty = 1;
4083 }
4084 }
4085}
4086
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004087WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004088weston_output_destroy(struct weston_output *output)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04004089{
Giulio Camuffo00535ce2014-09-06 16:18:02 +03004090 struct wl_resource *resource;
Giulio Camuffo2f2a70c2015-07-12 10:52:32 +03004091 struct weston_view *view;
Giulio Camuffo00535ce2014-09-06 16:18:02 +03004092
Ander Conselvan de Oliveirae1e23522013-12-13 22:10:55 +02004093 output->destroying = 1;
4094
Giulio Camuffo2f2a70c2015-07-12 10:52:32 +03004095 wl_list_for_each(view, &output->compositor->view_list, link) {
Bryce Harrington89324ce2015-12-23 18:38:07 -08004096 if (view->output_mask & (1u << output->id))
Giulio Camuffo2f2a70c2015-07-12 10:52:32 +03004097 weston_view_assign_output(view);
4098 }
4099
Pekka Paalanen0513a952014-05-21 16:17:27 +03004100 wl_event_source_remove(output->repaint_timer);
4101
Pekka Paalanen133e4392014-09-23 22:08:46 -04004102 weston_presentation_feedback_discard_list(&output->feedback_list);
4103
Zhang, Xiong Ya4b54c02013-12-13 22:10:51 +02004104 weston_compositor_remove_output(output->compositor, output);
Ander Conselvan de Oliveiraf749fc32013-12-13 22:10:50 +02004105 wl_list_remove(&output->link);
4106
Ander Conselvan de Oliveiraf84327a2014-01-29 18:47:51 +02004107 wl_signal_emit(&output->compositor->output_destroyed_signal, output);
Richard Hughes64ddde12013-05-01 21:52:10 +01004108 wl_signal_emit(&output->destroy_signal, output);
4109
Richard Hughesafe690c2013-05-02 10:10:04 +01004110 free(output->name);
Kristian Høgsberge75cb7f2011-06-21 15:27:41 -04004111 pixman_region32_fini(&output->region);
Ander Conselvan de Oliveirab8fcca92012-11-16 17:23:52 +02004112 pixman_region32_fini(&output->previous_damage);
Bryce Harrington89324ce2015-12-23 18:38:07 -08004113 output->compositor->output_id_pool &= ~(1u << output->id);
Benjamin Franzkeb6879402012-04-10 18:28:54 +02004114
Giulio Camuffo00535ce2014-09-06 16:18:02 +03004115 wl_resource_for_each(resource, &output->resource_list) {
4116 wl_resource_set_destructor(resource, NULL);
4117 }
4118
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04004119 wl_global_destroy(output->global);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004120}
4121
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004122WL_EXPORT void
Scott Moreauccbf29d2012-02-22 14:21:41 -07004123weston_output_update_matrix(struct weston_output *output)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004124{
Scott Moreau850ca422012-05-21 15:21:25 -06004125 float magnification;
Kristian Høgsberg31bd6c72011-02-13 13:00:51 -05004126
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004127 weston_matrix_init(&output->matrix);
Jason Ekstrandfb23df72014-10-16 10:55:21 -05004128 weston_matrix_translate(&output->matrix, -output->x, -output->y, 0);
Scott Moreau1bad5db2012-08-18 01:04:05 -06004129
Scott Moreauccbf29d2012-02-22 14:21:41 -07004130 if (output->zoom.active) {
Scott Moreaue6603982012-06-11 13:07:51 -06004131 magnification = 1 / (1 - output->zoom.spring_z.current);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004132 weston_output_update_zoom(output);
Neil Roberts1e40a7e2014-04-25 13:19:37 +01004133 weston_matrix_translate(&output->matrix, -output->zoom.trans_x,
Jason Ekstrandfb23df72014-10-16 10:55:21 -05004134 -output->zoom.trans_y, 0);
Neil Roberts1e40a7e2014-04-25 13:19:37 +01004135 weston_matrix_scale(&output->matrix, magnification,
4136 magnification, 1.0);
Scott Moreauccbf29d2012-02-22 14:21:41 -07004137 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04004138
Jason Ekstrandfb23df72014-10-16 10:55:21 -05004139 switch (output->transform) {
4140 case WL_OUTPUT_TRANSFORM_FLIPPED:
4141 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
4142 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
4143 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
4144 weston_matrix_translate(&output->matrix, -output->width, 0, 0);
4145 weston_matrix_scale(&output->matrix, -1, 1, 1);
4146 break;
4147 }
4148
4149 switch (output->transform) {
4150 default:
4151 case WL_OUTPUT_TRANSFORM_NORMAL:
4152 case WL_OUTPUT_TRANSFORM_FLIPPED:
4153 break;
4154 case WL_OUTPUT_TRANSFORM_90:
4155 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
4156 weston_matrix_translate(&output->matrix, 0, -output->height, 0);
4157 weston_matrix_rotate_xy(&output->matrix, 0, 1);
4158 break;
4159 case WL_OUTPUT_TRANSFORM_180:
4160 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
4161 weston_matrix_translate(&output->matrix,
4162 -output->width, -output->height, 0);
4163 weston_matrix_rotate_xy(&output->matrix, -1, 0);
4164 break;
4165 case WL_OUTPUT_TRANSFORM_270:
4166 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
4167 weston_matrix_translate(&output->matrix, -output->width, 0, 0);
4168 weston_matrix_rotate_xy(&output->matrix, 0, -1);
4169 break;
4170 }
4171
4172 if (output->current_scale != 1)
4173 weston_matrix_scale(&output->matrix,
4174 output->current_scale,
4175 output->current_scale, 1);
Neil Roberts6c3b01f2014-05-06 19:04:15 +01004176
Scott Moreauccbf29d2012-02-22 14:21:41 -07004177 output->dirty = 0;
Derek Foremanc0023212015-03-24 11:36:13 -05004178
4179 weston_matrix_invert(&output->inverse_matrix, &output->matrix);
Scott Moreauccbf29d2012-02-22 14:21:41 -07004180}
4181
Scott Moreau1bad5db2012-08-18 01:04:05 -06004182static void
Alexander Larsson0b135062013-05-28 16:23:36 +02004183weston_output_transform_scale_init(struct weston_output *output, uint32_t transform, uint32_t scale)
Scott Moreau1bad5db2012-08-18 01:04:05 -06004184{
4185 output->transform = transform;
Pekka Paalanen59987fa2016-04-26 15:50:59 +03004186 output->native_scale = scale;
4187 output->current_scale = scale;
Scott Moreau1bad5db2012-08-18 01:04:05 -06004188
Pekka Paalanen59987fa2016-04-26 15:50:59 +03004189 convert_size_by_transform_scale(&output->width, &output->height,
4190 output->current_mode->width,
4191 output->current_mode->height,
4192 transform, scale);
Alexander Larsson4ea95522013-05-22 14:41:37 +02004193}
4194
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004195static void
4196weston_output_init_geometry(struct weston_output *output, int x, int y)
Scott Moreauccbf29d2012-02-22 14:21:41 -07004197{
4198 output->x = x;
4199 output->y = y;
4200
Ander Conselvan de Oliveirab8fcca92012-11-16 17:23:52 +02004201 pixman_region32_init(&output->previous_damage);
Scott Moreauccbf29d2012-02-22 14:21:41 -07004202 pixman_region32_init_rect(&output->region, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06004203 output->width,
4204 output->height);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004205}
4206
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004207WL_EXPORT void
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004208weston_output_move(struct weston_output *output, int x, int y)
4209{
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004210 struct wl_resource *resource;
4211
4212 output->move_x = x - output->x;
4213 output->move_y = y - output->y;
4214
4215 if (output->move_x == 0 && output->move_y == 0)
4216 return;
4217
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004218 weston_output_init_geometry(output, x, y);
4219
4220 output->dirty = 1;
4221
4222 /* Move views on this output. */
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02004223 wl_signal_emit(&output->compositor->output_moved_signal, output);
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004224
4225 /* Notify clients of the change for output position. */
Quanxian Wangb2c86362014-03-14 09:16:25 +08004226 wl_resource_for_each(resource, &output->resource_list) {
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004227 wl_output_send_geometry(resource,
4228 output->x,
4229 output->y,
4230 output->mm_width,
4231 output->mm_height,
4232 output->subpixel,
4233 output->make,
4234 output->model,
4235 output->transform);
Quanxian Wangb2c86362014-03-14 09:16:25 +08004236
4237 if (wl_resource_get_version(resource) >= 2)
4238 wl_output_send_done(resource);
4239 }
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004240}
4241
Bryce Harrington3f650b82015-12-23 11:01:58 -08004242/** Initialize a weston_output object's parameters
4243 *
4244 * \param output The weston_output object to initialize
4245 * \param c The output's compositor
4246 * \param x x coordinate for the output in global coordinate space
4247 * \param y y coordinate for the output in global coordinate space
4248 * \param mm_width Physical width of the output as reported by the backend
4249 * \param mm_height Physical height of the output as reported by the backend
4250 * \param transform Rotation of the output
4251 * \param scale Native scaling factor for the output
4252 *
4253 * Sets up the transformation, zoom, and geometry of the output using
4254 * the input properties.
4255 *
4256 * Establishes a repaint timer for the output with the relevant display
4257 * object's event loop. See output_repaint_timer_handler().
4258 *
4259 * The output is assigned an ID. Weston can support up to 32 distinct
4260 * outputs, with IDs numbered from 0-31; the compositor's output_id_pool
4261 * is referred to and used to find the first available ID number, and
4262 * then this ID is marked as used in output_id_pool.
4263 *
4264 * The output is also assigned a Wayland global with the wl_output
4265 * external interface.
4266 */
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004267WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004268weston_output_init(struct weston_output *output, struct weston_compositor *c,
Alexander Larsson0b135062013-05-28 16:23:36 +02004269 int x, int y, int mm_width, int mm_height, uint32_t transform,
Alexander Larssonedddbd12013-05-24 13:09:43 +02004270 int32_t scale)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004271{
Pekka Paalanen0513a952014-05-21 16:17:27 +03004272 struct wl_event_loop *loop;
4273
Bryce Harrington18e45732015-12-23 20:53:53 -08004274 /* Verify we haven't reached the limit of 32 available output IDs */
4275 assert(ffs(~c->output_id_pool) > 0);
4276
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004277 output->compositor = c;
4278 output->x = x;
4279 output->y = y;
Alexander Larsson0b135062013-05-28 16:23:36 +02004280 output->mm_width = mm_width;
4281 output->mm_height = mm_height;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004282 output->dirty = 1;
Hardeningff39efa2013-09-18 23:56:35 +02004283 output->original_scale = scale;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004284
Alexander Larsson0b135062013-05-28 16:23:36 +02004285 weston_output_transform_scale_init(output, transform, scale);
Scott Moreau429490d2012-06-17 18:10:59 -06004286 weston_output_init_zoom(output);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004287
Zhang, Xiong Yf3012412013-12-13 22:10:53 +02004288 weston_output_init_geometry(output, x, y);
Benjamin Franzke78db8482012-04-10 18:35:33 +02004289 weston_output_damage(output);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004290
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -04004291 wl_signal_init(&output->frame_signal);
Richard Hughes64ddde12013-05-01 21:52:10 +01004292 wl_signal_init(&output->destroy_signal);
Scott Moreau9d1b1122012-06-08 19:40:53 -06004293 wl_list_init(&output->animation_list);
Casey Dahlin9074db52012-04-19 22:50:09 -04004294 wl_list_init(&output->resource_list);
Pekka Paalanen133e4392014-09-23 22:08:46 -04004295 wl_list_init(&output->feedback_list);
Dawid Gajownik2f7d33d2015-08-06 21:04:16 -03004296 wl_list_init(&output->link);
Benjamin Franzke06286262011-05-06 19:12:33 +02004297
Pekka Paalanen0513a952014-05-21 16:17:27 +03004298 loop = wl_display_get_event_loop(c->wl_display);
4299 output->repaint_timer = wl_event_loop_add_timer(loop,
4300 output_repaint_timer_handler, output);
4301
Bryce Harrington3f650b82015-12-23 11:01:58 -08004302 /* Invert the output id pool and look for the lowest numbered
4303 * switch (the least significant bit). Take that bit's position
4304 * as our ID, and mark it used in the compositor's output_id_pool.
4305 */
Casey Dahlin58ba1372012-04-19 22:50:08 -04004306 output->id = ffs(~output->compositor->output_id_pool) - 1;
Bryce Harrington89324ce2015-12-23 18:38:07 -08004307 output->compositor->output_id_pool |= 1u << output->id;
Casey Dahlin58ba1372012-04-19 22:50:08 -04004308
Benjamin Franzkeb6879402012-04-10 18:28:54 +02004309 output->global =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04004310 wl_global_create(c->wl_display, &wl_output_interface, 2,
4311 output, bind_output);
Giulio Camuffob1147152015-05-06 21:41:57 +03004312}
4313
4314/** Adds an output to the compositor's output list and
4315 * send the compositor's output_created signal.
4316 *
4317 * \param compositor The compositor instance.
4318 * \param output The output to be added.
4319 */
4320WL_EXPORT void
4321weston_compositor_add_output(struct weston_compositor *compositor,
4322 struct weston_output *output)
4323{
4324 wl_list_insert(compositor->output_list.prev, &output->link);
4325 wl_signal_emit(&compositor->output_created_signal, output);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04004326}
4327
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07004328WL_EXPORT void
4329weston_output_transform_coordinate(struct weston_output *output,
Giulio Camuffo90a6fc62016-03-22 17:44:54 +02004330 double device_x, double device_y,
4331 double *x, double *y)
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07004332{
Derek Foreman0f679412014-10-02 13:41:17 -05004333 struct weston_vector p = { {
Giulio Camuffo90a6fc62016-03-22 17:44:54 +02004334 device_x,
4335 device_y,
Derek Foreman0f679412014-10-02 13:41:17 -05004336 0.0,
4337 1.0 } };
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07004338
Derek Foreman67a18b92015-03-24 11:36:14 -05004339 weston_matrix_transform(&output->inverse_matrix, &p);
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07004340
Giulio Camuffo90a6fc62016-03-22 17:44:54 +02004341 *x = p.f[0] / p.f[3];
4342 *y = p.f[1] / p.f[3];
Kristian Høgsberg98c774f2013-07-22 14:33:42 -07004343}
4344
Benjamin Franzke315b3dc2011-03-08 11:32:57 +01004345static void
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004346destroy_viewport(struct wl_resource *resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01004347{
Jonny Lamb74130762013-11-26 18:19:46 +01004348 struct weston_surface *surface =
4349 wl_resource_get_user_data(resource);
4350
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004351 surface->viewport_resource = NULL;
Pekka Paalanenf0cad482014-03-14 14:38:16 +02004352 surface->pending.buffer_viewport.buffer.src_width =
4353 wl_fixed_from_int(-1);
4354 surface->pending.buffer_viewport.surface.width = -1;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02004355 surface->pending.buffer_viewport.changed = 1;
Jonny Lamb8ae35902013-11-26 18:19:45 +01004356}
4357
4358static void
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004359viewport_destroy(struct wl_client *client,
4360 struct wl_resource *resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01004361{
4362 wl_resource_destroy(resource);
4363}
4364
4365static void
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004366viewport_set(struct wl_client *client,
4367 struct wl_resource *resource,
4368 wl_fixed_t src_x,
4369 wl_fixed_t src_y,
4370 wl_fixed_t src_width,
4371 wl_fixed_t src_height,
4372 int32_t dst_width,
4373 int32_t dst_height)
Jonny Lamb8ae35902013-11-26 18:19:45 +01004374{
Jonny Lamb74130762013-11-26 18:19:46 +01004375 struct weston_surface *surface =
4376 wl_resource_get_user_data(resource);
4377
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004378 assert(surface->viewport_resource != NULL);
Jonny Lamb74130762013-11-26 18:19:46 +01004379
Jonny Lamb8ae35902013-11-26 18:19:45 +01004380 if (wl_fixed_to_double(src_width) < 0 ||
4381 wl_fixed_to_double(src_height) < 0) {
4382 wl_resource_post_error(resource,
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004383 WL_VIEWPORT_ERROR_BAD_VALUE,
Jonny Lamb8ae35902013-11-26 18:19:45 +01004384 "source dimensions must be non-negative (%fx%f)",
4385 wl_fixed_to_double(src_width),
4386 wl_fixed_to_double(src_height));
4387 return;
4388 }
4389
4390 if (dst_width <= 0 || dst_height <= 0) {
4391 wl_resource_post_error(resource,
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004392 WL_VIEWPORT_ERROR_BAD_VALUE,
Jonny Lamb8ae35902013-11-26 18:19:45 +01004393 "destination dimensions must be positive (%dx%d)",
4394 dst_width, dst_height);
4395 return;
4396 }
4397
Pekka Paalanen952b6c82014-03-14 14:38:15 +02004398 surface->pending.buffer_viewport.buffer.src_x = src_x;
4399 surface->pending.buffer_viewport.buffer.src_y = src_y;
4400 surface->pending.buffer_viewport.buffer.src_width = src_width;
4401 surface->pending.buffer_viewport.buffer.src_height = src_height;
4402 surface->pending.buffer_viewport.surface.width = dst_width;
4403 surface->pending.buffer_viewport.surface.height = dst_height;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02004404 surface->pending.buffer_viewport.changed = 1;
Jonny Lamb8ae35902013-11-26 18:19:45 +01004405}
4406
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004407static void
4408viewport_set_source(struct wl_client *client,
4409 struct wl_resource *resource,
4410 wl_fixed_t src_x,
4411 wl_fixed_t src_y,
4412 wl_fixed_t src_width,
4413 wl_fixed_t src_height)
4414{
4415 struct weston_surface *surface =
4416 wl_resource_get_user_data(resource);
4417
4418 assert(surface->viewport_resource != NULL);
4419
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03004420 if (src_width == wl_fixed_from_int(-1) &&
4421 src_height == wl_fixed_from_int(-1)) {
4422 /* unset source size */
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004423 surface->pending.buffer_viewport.buffer.src_width =
4424 wl_fixed_from_int(-1);
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02004425 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03004426 return;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004427 }
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03004428
4429 if (src_width <= 0 || src_height <= 0) {
4430 wl_resource_post_error(resource,
4431 WL_VIEWPORT_ERROR_BAD_VALUE,
4432 "source size must be positive (%fx%f)",
4433 wl_fixed_to_double(src_width),
4434 wl_fixed_to_double(src_height));
4435 return;
4436 }
4437
4438 surface->pending.buffer_viewport.buffer.src_x = src_x;
4439 surface->pending.buffer_viewport.buffer.src_y = src_y;
4440 surface->pending.buffer_viewport.buffer.src_width = src_width;
4441 surface->pending.buffer_viewport.buffer.src_height = src_height;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02004442 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004443}
4444
4445static void
4446viewport_set_destination(struct wl_client *client,
4447 struct wl_resource *resource,
4448 int32_t dst_width,
4449 int32_t dst_height)
4450{
4451 struct weston_surface *surface =
4452 wl_resource_get_user_data(resource);
4453
4454 assert(surface->viewport_resource != NULL);
4455
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03004456 if (dst_width == -1 && dst_height == -1) {
4457 /* unset destination size */
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004458 surface->pending.buffer_viewport.surface.width = -1;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02004459 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03004460 return;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004461 }
Pekka Paalanen2c8b5f52014-04-04 14:22:12 +03004462
4463 if (dst_width <= 0 || dst_height <= 0) {
4464 wl_resource_post_error(resource,
4465 WL_VIEWPORT_ERROR_BAD_VALUE,
4466 "destination size must be positive (%dx%d)",
4467 dst_width, dst_height);
4468 return;
4469 }
4470
4471 surface->pending.buffer_viewport.surface.width = dst_width;
4472 surface->pending.buffer_viewport.surface.height = dst_height;
George Kiagiadakis8f9e87f2014-06-13 18:14:20 +02004473 surface->pending.buffer_viewport.changed = 1;
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004474}
4475
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004476static const struct wl_viewport_interface viewport_interface = {
4477 viewport_destroy,
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004478 viewport_set,
4479 viewport_set_source,
4480 viewport_set_destination
Jonny Lamb8ae35902013-11-26 18:19:45 +01004481};
4482
4483static void
4484scaler_destroy(struct wl_client *client,
4485 struct wl_resource *resource)
4486{
4487 wl_resource_destroy(resource);
4488}
4489
4490static void
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004491scaler_get_viewport(struct wl_client *client,
4492 struct wl_resource *scaler,
4493 uint32_t id,
4494 struct wl_resource *surface_resource)
Jonny Lamb8ae35902013-11-26 18:19:45 +01004495{
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004496 int version = wl_resource_get_version(scaler);
4497 struct weston_surface *surface =
4498 wl_resource_get_user_data(surface_resource);
Jonny Lamb8ae35902013-11-26 18:19:45 +01004499 struct wl_resource *resource;
4500
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004501 if (surface->viewport_resource) {
Jonny Lamb74130762013-11-26 18:19:46 +01004502 wl_resource_post_error(scaler,
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004503 WL_SCALER_ERROR_VIEWPORT_EXISTS,
4504 "a viewport for that surface already exists");
Jonny Lamb74130762013-11-26 18:19:46 +01004505 return;
4506 }
4507
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004508 resource = wl_resource_create(client, &wl_viewport_interface,
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004509 version, id);
Jonny Lamb8ae35902013-11-26 18:19:45 +01004510 if (resource == NULL) {
4511 wl_client_post_no_memory(client);
4512 return;
4513 }
4514
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004515 wl_resource_set_implementation(resource, &viewport_interface,
4516 surface, destroy_viewport);
Jonny Lamb74130762013-11-26 18:19:46 +01004517
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004518 surface->viewport_resource = resource;
Jonny Lamb8ae35902013-11-26 18:19:45 +01004519}
4520
4521static const struct wl_scaler_interface scaler_interface = {
4522 scaler_destroy,
Pekka Paalanenb0420ae2014-01-08 15:39:17 +02004523 scaler_get_viewport
Jonny Lamb8ae35902013-11-26 18:19:45 +01004524};
4525
4526static void
4527bind_scaler(struct wl_client *client,
4528 void *data, uint32_t version, uint32_t id)
4529{
4530 struct wl_resource *resource;
4531
4532 resource = wl_resource_create(client, &wl_scaler_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06004533 version, id);
Jonny Lamb8ae35902013-11-26 18:19:45 +01004534 if (resource == NULL) {
4535 wl_client_post_no_memory(client);
4536 return;
4537 }
4538
4539 wl_resource_set_implementation(resource, &scaler_interface,
4540 NULL, NULL);
4541}
4542
4543static void
Pekka Paalanen133e4392014-09-23 22:08:46 -04004544destroy_presentation_feedback(struct wl_resource *feedback_resource)
4545{
4546 struct weston_presentation_feedback *feedback;
4547
4548 feedback = wl_resource_get_user_data(feedback_resource);
4549
4550 wl_list_remove(&feedback->link);
4551 free(feedback);
4552}
4553
4554static void
Pekka Paalanen31f7d782014-09-23 22:08:43 -04004555presentation_destroy(struct wl_client *client, struct wl_resource *resource)
4556{
4557 wl_resource_destroy(resource);
4558}
4559
4560static void
4561presentation_feedback(struct wl_client *client,
Pekka Paalanen133e4392014-09-23 22:08:46 -04004562 struct wl_resource *presentation_resource,
4563 struct wl_resource *surface_resource,
Pekka Paalanen31f7d782014-09-23 22:08:43 -04004564 uint32_t callback)
4565{
Pekka Paalanen133e4392014-09-23 22:08:46 -04004566 struct weston_surface *surface;
4567 struct weston_presentation_feedback *feedback;
4568
4569 surface = wl_resource_get_user_data(surface_resource);
4570
Bryce Harringtonde16d892014-11-20 22:21:57 -08004571 feedback = zalloc(sizeof *feedback);
4572 if (feedback == NULL)
Pekka Paalanen133e4392014-09-23 22:08:46 -04004573 goto err_calloc;
4574
4575 feedback->resource = wl_resource_create(client,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02004576 &wp_presentation_feedback_interface,
Pekka Paalanen133e4392014-09-23 22:08:46 -04004577 1, callback);
4578 if (!feedback->resource)
4579 goto err_create;
4580
4581 wl_resource_set_implementation(feedback->resource, NULL, feedback,
4582 destroy_presentation_feedback);
4583
4584 wl_list_insert(&surface->pending.feedback_list, &feedback->link);
4585
4586 return;
4587
4588err_create:
4589 free(feedback);
4590
4591err_calloc:
4592 wl_client_post_no_memory(client);
Pekka Paalanen31f7d782014-09-23 22:08:43 -04004593}
4594
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02004595static const struct wp_presentation_interface presentation_implementation = {
Pekka Paalanen31f7d782014-09-23 22:08:43 -04004596 presentation_destroy,
4597 presentation_feedback
4598};
4599
4600static void
4601bind_presentation(struct wl_client *client,
4602 void *data, uint32_t version, uint32_t id)
4603{
4604 struct weston_compositor *compositor = data;
4605 struct wl_resource *resource;
4606
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02004607 resource = wl_resource_create(client, &wp_presentation_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06004608 version, id);
Pekka Paalanen31f7d782014-09-23 22:08:43 -04004609 if (resource == NULL) {
4610 wl_client_post_no_memory(client);
4611 return;
4612 }
4613
4614 wl_resource_set_implementation(resource, &presentation_implementation,
4615 compositor, NULL);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02004616 wp_presentation_send_clock_id(resource, compositor->presentation_clock);
Pekka Paalanen31f7d782014-09-23 22:08:43 -04004617}
4618
4619static void
Kristian Høgsberga8873122011-11-23 10:39:34 -05004620compositor_bind(struct wl_client *client,
4621 void *data, uint32_t version, uint32_t id)
4622{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004623 struct weston_compositor *compositor = data;
Jason Ekstranda85118c2013-06-27 20:17:02 -05004624 struct wl_resource *resource;
Kristian Høgsberga8873122011-11-23 10:39:34 -05004625
Jason Ekstranda85118c2013-06-27 20:17:02 -05004626 resource = wl_resource_create(client, &wl_compositor_interface,
Derek Foreman1909c102015-11-26 14:17:47 -06004627 version, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07004628 if (resource == NULL) {
4629 wl_client_post_no_memory(client);
4630 return;
4631 }
4632
4633 wl_resource_set_implementation(resource, &compositor_interface,
4634 compositor, NULL);
Kristian Høgsberga8873122011-11-23 10:39:34 -05004635}
4636
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004637WL_EXPORT int
Ander Conselvan de Oliveiracbdebc22013-02-21 18:35:16 +02004638weston_environment_get_fd(const char *env)
4639{
4640 char *e, *end;
4641 int fd, flags;
4642
4643 e = getenv(env);
4644 if (!e)
4645 return -1;
4646 fd = strtol(e, &end, 0);
4647 if (*end != '\0')
4648 return -1;
4649
4650 flags = fcntl(fd, F_GETFD);
4651 if (flags == -1)
4652 return -1;
4653
4654 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
4655 unsetenv(env);
4656
4657 return fd;
4658}
4659
Pekka Paalanenb5026542014-11-12 15:09:24 +02004660static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05004661timeline_key_binding_handler(struct weston_keyboard *keyboard, uint32_t time,
Pekka Paalanenb5026542014-11-12 15:09:24 +02004662 uint32_t key, void *data)
4663{
4664 struct weston_compositor *compositor = data;
4665
4666 if (weston_timeline_enabled_)
4667 weston_timeline_close();
4668 else
4669 weston_timeline_open(compositor);
4670}
4671
Giulio Camuffo459137b2014-10-11 23:56:24 +03004672/** Create the compositor.
4673 *
4674 * This functions creates and initializes a compositor instance.
4675 *
4676 * \param display The Wayland display to be used.
4677 * \param user_data A pointer to an object that can later be retrieved
4678 * using the \ref weston_compositor_get_user_data function.
4679 * \return The compositor instance on success or NULL on failure.
4680 */
4681WL_EXPORT struct weston_compositor *
4682weston_compositor_create(struct wl_display *display, void *user_data)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04004683{
Giulio Camuffo459137b2014-10-11 23:56:24 +03004684 struct weston_compositor *ec;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05004685 struct wl_event_loop *loop;
Ossama Othmana50e6e42013-05-14 09:48:26 -07004686
Giulio Camuffo459137b2014-10-11 23:56:24 +03004687 ec = zalloc(sizeof *ec);
4688 if (!ec)
4689 return NULL;
4690
4691 ec->wl_display = display;
4692 ec->user_data = user_data;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04004693 wl_signal_init(&ec->destroy_signal);
Kristian Høgsbergf03a04a2014-04-06 22:04:50 -07004694 wl_signal_init(&ec->create_surface_signal);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04004695 wl_signal_init(&ec->activate_signal);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03004696 wl_signal_init(&ec->transform_signal);
Tiago Vignatti1d01b012012-09-27 17:48:36 +03004697 wl_signal_init(&ec->kill_signal);
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004698 wl_signal_init(&ec->idle_signal);
4699 wl_signal_init(&ec->wake_signal);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02004700 wl_signal_init(&ec->show_input_panel_signal);
4701 wl_signal_init(&ec->hide_input_panel_signal);
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02004702 wl_signal_init(&ec->update_input_panel_signal);
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +01004703 wl_signal_init(&ec->seat_created_signal);
Richard Hughes59d5da72013-05-01 21:52:11 +01004704 wl_signal_init(&ec->output_created_signal);
Ander Conselvan de Oliveiraf84327a2014-01-29 18:47:51 +02004705 wl_signal_init(&ec->output_destroyed_signal);
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02004706 wl_signal_init(&ec->output_moved_signal);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07004707 wl_signal_init(&ec->session_signal);
4708 ec->session_active = 1;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04004709
Casey Dahlin58ba1372012-04-19 22:50:08 -04004710 ec->output_id_pool = 0;
Giulio Camuffobab996e2014-10-12 00:24:25 +03004711 ec->repaint_msec = DEFAULT_REPAINT_WINDOW;
Casey Dahlin58ba1372012-04-19 22:50:08 -04004712
Derek Foreman152254b2015-11-26 14:17:48 -06004713 if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 4,
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04004714 ec, compositor_bind))
Giulio Camuffo459137b2014-10-11 23:56:24 +03004715 goto fail;
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05004716
Giulio Camuffo954f1832014-10-11 18:27:30 +03004717 if (!wl_global_create(ec->wl_display, &wl_subcompositor_interface, 1,
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04004718 ec, bind_subcompositor))
Giulio Camuffo459137b2014-10-11 23:56:24 +03004719 goto fail;
Pekka Paalanene67858b2013-04-25 13:57:42 +03004720
Pekka Paalanen0b4c5352014-03-14 14:38:17 +02004721 if (!wl_global_create(ec->wl_display, &wl_scaler_interface, 2,
Jonny Lamb8ae35902013-11-26 18:19:45 +01004722 ec, bind_scaler))
Giulio Camuffo459137b2014-10-11 23:56:24 +03004723 goto fail;
Jonny Lamb8ae35902013-11-26 18:19:45 +01004724
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02004725 if (!wl_global_create(ec->wl_display, &wp_presentation_interface, 1,
Pekka Paalanen31f7d782014-09-23 22:08:43 -04004726 ec, bind_presentation))
Giulio Camuffo459137b2014-10-11 23:56:24 +03004727 goto fail;
Pekka Paalanen31f7d782014-09-23 22:08:43 -04004728
Jason Ekstranda7af7042013-10-12 22:38:11 -05004729 wl_list_init(&ec->view_list);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02004730 wl_list_init(&ec->plane_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01004731 wl_list_init(&ec->layer_list);
4732 wl_list_init(&ec->seat_list);
4733 wl_list_init(&ec->output_list);
4734 wl_list_init(&ec->key_binding_list);
Daniel Stone96d47c02013-11-19 11:37:12 +01004735 wl_list_init(&ec->modifier_binding_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01004736 wl_list_init(&ec->button_binding_list);
Neil Robertsa28c6932013-10-03 16:43:04 +01004737 wl_list_init(&ec->touch_binding_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01004738 wl_list_init(&ec->axis_binding_list);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02004739 wl_list_init(&ec->debug_binding_list);
Daniel Stone725c2c32012-06-22 14:04:36 +01004740
Xiong Zhang97116532013-10-23 13:58:31 +08004741 weston_plane_init(&ec->primary_plane, ec, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02004742 weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04004743
Giulio Camuffo459137b2014-10-11 23:56:24 +03004744 wl_data_device_manager_init(ec->wl_display);
4745
4746 wl_display_init_shm(ec->wl_display);
4747
4748 loop = wl_display_get_event_loop(ec->wl_display);
4749 ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
Giulio Camuffo459137b2014-10-11 23:56:24 +03004750
Giulio Camuffo459137b2014-10-11 23:56:24 +03004751 weston_layer_init(&ec->fade_layer, &ec->layer_list);
4752 weston_layer_init(&ec->cursor_layer, &ec->fade_layer.link);
4753
4754 weston_compositor_add_debug_binding(ec, KEY_T,
4755 timeline_key_binding_handler, ec);
4756
Giulio Camuffo459137b2014-10-11 23:56:24 +03004757 return ec;
4758
4759fail:
4760 free(ec);
4761 return NULL;
4762}
4763
Benjamin Franzkeb8263022011-08-30 11:32:47 +02004764WL_EXPORT void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004765weston_compositor_shutdown(struct weston_compositor *ec)
Matt Roper361d2ad2011-08-29 13:52:23 -07004766{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004767 struct weston_output *output, *next;
Matt Roper361d2ad2011-08-29 13:52:23 -07004768
Pekka Paalanend1591ae2012-01-02 16:06:56 +02004769 wl_event_source_remove(ec->idle_source);
4770
Matt Roper361d2ad2011-08-29 13:52:23 -07004771 /* Destroy all outputs associated with this compositor */
Tiago Vignattib303a1d2011-12-18 22:27:40 +02004772 wl_list_for_each_safe(output, next, &ec->output_list, link)
Matt Roper361d2ad2011-08-29 13:52:23 -07004773 output->destroy(output);
Pekka Paalanen4738f3b2012-01-02 15:47:07 +02004774
Ander Conselvan de Oliveira18536762013-12-20 21:07:00 +02004775 if (ec->renderer)
4776 ec->renderer->destroy(ec);
4777
Daniel Stone325fc2d2012-05-30 16:31:58 +01004778 weston_binding_list_destroy_all(&ec->key_binding_list);
Ryo Munakata27135af2015-07-17 13:07:42 +09004779 weston_binding_list_destroy_all(&ec->modifier_binding_list);
Daniel Stone325fc2d2012-05-30 16:31:58 +01004780 weston_binding_list_destroy_all(&ec->button_binding_list);
Neil Robertsa28c6932013-10-03 16:43:04 +01004781 weston_binding_list_destroy_all(&ec->touch_binding_list);
Daniel Stone325fc2d2012-05-30 16:31:58 +01004782 weston_binding_list_destroy_all(&ec->axis_binding_list);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02004783 weston_binding_list_destroy_all(&ec->debug_binding_list);
Pekka Paalanend1591ae2012-01-02 16:06:56 +02004784
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04004785 weston_plane_release(&ec->primary_plane);
Matt Roper361d2ad2011-08-29 13:52:23 -07004786}
4787
Kristian Høgsbergaf4f2aa2013-02-15 20:53:20 -05004788WL_EXPORT void
Frederic Plourdec336f062014-10-29 14:44:33 -04004789weston_compositor_exit_with_code(struct weston_compositor *compositor,
4790 int exit_code)
4791{
Pekka Paalanenf5ef88f2014-11-18 15:57:04 +02004792 if (compositor->exit_code == EXIT_SUCCESS)
4793 compositor->exit_code = exit_code;
4794
Giulio Camuffo459137b2014-10-11 23:56:24 +03004795 weston_compositor_exit(compositor);
Frederic Plourdec336f062014-10-29 14:44:33 -04004796}
4797
4798WL_EXPORT void
Giulio Camuffocdb4d292013-11-14 23:42:53 +01004799weston_compositor_set_default_pointer_grab(struct weston_compositor *ec,
4800 const struct weston_pointer_grab_interface *interface)
4801{
4802 struct weston_seat *seat;
4803
4804 ec->default_pointer_grab = interface;
4805 wl_list_for_each(seat, &ec->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -05004806 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
4807
4808 if (pointer)
4809 weston_pointer_set_default_grab(pointer, interface);
Giulio Camuffocdb4d292013-11-14 23:42:53 +01004810 }
4811}
4812
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04004813WL_EXPORT int
4814weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
4815 clockid_t clk_id)
4816{
4817 struct timespec ts;
4818
4819 if (clock_gettime(clk_id, &ts) < 0)
4820 return -1;
4821
4822 compositor->presentation_clock = clk_id;
4823
4824 return 0;
4825}
4826
4827/*
4828 * For choosing the software clock, when the display hardware or API
4829 * does not expose a compatible presentation timestamp.
4830 */
4831WL_EXPORT int
4832weston_compositor_set_presentation_clock_software(
4833 struct weston_compositor *compositor)
4834{
4835 /* In order of preference */
4836 static const clockid_t clocks[] = {
4837 CLOCK_MONOTONIC_RAW, /* no jumps, no crawling */
4838 CLOCK_MONOTONIC_COARSE, /* no jumps, may crawl, fast & coarse */
4839 CLOCK_MONOTONIC, /* no jumps, may crawl */
4840 CLOCK_REALTIME_COARSE, /* may jump and crawl, fast & coarse */
4841 CLOCK_REALTIME /* may jump and crawl */
4842 };
4843 unsigned i;
4844
4845 for (i = 0; i < ARRAY_LENGTH(clocks); i++)
4846 if (weston_compositor_set_presentation_clock(compositor,
4847 clocks[i]) == 0)
4848 return 0;
4849
4850 weston_log("Error: no suitable presentation clock available.\n");
4851
4852 return -1;
4853}
4854
Pekka Paalanen662f3842015-03-18 12:17:26 +02004855/** Read the current time from the Presentation clock
4856 *
4857 * \param compositor
4858 * \param ts[out] The current time.
4859 *
4860 * \note Reading the current time in user space is always imprecise to some
4861 * degree.
4862 *
4863 * This function is never meant to fail. If reading the clock does fail,
4864 * an error message is logged and a zero time is returned. Callers are not
4865 * supposed to detect or react to failures.
4866 */
4867WL_EXPORT void
4868weston_compositor_read_presentation_clock(
4869 const struct weston_compositor *compositor,
4870 struct timespec *ts)
4871{
4872 static bool warned;
4873 int ret;
4874
4875 ret = clock_gettime(compositor->presentation_clock, ts);
4876 if (ret < 0) {
4877 ts->tv_sec = 0;
4878 ts->tv_nsec = 0;
4879
4880 if (!warned)
4881 weston_log("Error: failure to read "
4882 "the presentation clock %#x: '%m' (%d)\n",
4883 compositor->presentation_clock, errno);
4884 warned = true;
4885 }
4886}
4887
Pekka Paalanen230f3b12014-09-29 14:18:40 -04004888/** Import dmabuf buffer into current renderer
4889 *
4890 * \param compositor
4891 * \param buffer the dmabuf buffer to import
4892 * \return true on usable buffers, false otherwise
4893 *
4894 * This function tests that the linux_dmabuf_buffer is usable
4895 * for the current renderer. Returns false on unusable buffers. Usually
4896 * usability is tested by importing the dmabufs for composition.
4897 *
4898 * This hook is also used for detecting if the renderer supports
4899 * dmabufs at all. If the renderer hook is NULL, dmabufs are not
4900 * supported.
4901 * */
4902WL_EXPORT bool
4903weston_compositor_import_dmabuf(struct weston_compositor *compositor,
4904 struct linux_dmabuf_buffer *buffer)
4905{
4906 struct weston_renderer *renderer;
4907
4908 renderer = compositor->renderer;
4909
4910 if (renderer->import_dmabuf == NULL)
4911 return false;
4912
4913 return renderer->import_dmabuf(compositor, buffer);
4914}
4915
Giulio Camuffocdb4d292013-11-14 23:42:53 +01004916WL_EXPORT void
Kristian Høgsbergaf4f2aa2013-02-15 20:53:20 -05004917weston_version(int *major, int *minor, int *micro)
4918{
4919 *major = WESTON_VERSION_MAJOR;
4920 *minor = WESTON_VERSION_MINOR;
4921 *micro = WESTON_VERSION_MICRO;
4922}
4923
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03004924WL_EXPORT void *
4925weston_load_module(const char *name, const char *entrypoint)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004926{
Derek Foreman3f86e502015-06-08 11:46:54 -05004927 const char *builddir = getenv("WESTON_BUILD_DIR");
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004928 char path[PATH_MAX];
4929 void *module, *init;
4930
U. Artie Eoff2e2384a2014-01-17 13:19:01 -08004931 if (name == NULL)
4932 return NULL;
4933
Derek Foreman3f86e502015-06-08 11:46:54 -05004934 if (name[0] != '/') {
4935 if (builddir)
4936 snprintf(path, sizeof path, "%s/.libs/%s", builddir, name);
4937 else
4938 snprintf(path, sizeof path, "%s/%s", MODULEDIR, name);
4939 } else {
Benjamin Franzkeb7acce62011-05-06 23:19:22 +02004940 snprintf(path, sizeof path, "%s", name);
Derek Foreman3f86e502015-06-08 11:46:54 -05004941 }
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004942
Kristian Høgsberga6813d22012-09-12 12:21:01 -04004943 module = dlopen(path, RTLD_NOW | RTLD_NOLOAD);
4944 if (module) {
4945 weston_log("Module '%s' already loaded\n", path);
4946 dlclose(module);
4947 return NULL;
4948 }
4949
Pekka Paalanen1b3c1ea2012-06-11 14:06:04 +03004950 weston_log("Loading module '%s'\n", path);
Kristian Høgsberg1acd9f82012-07-26 11:39:26 -04004951 module = dlopen(path, RTLD_NOW);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004952 if (!module) {
Pekka Paalanen1b3c1ea2012-06-11 14:06:04 +03004953 weston_log("Failed to load module: %s\n", dlerror());
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004954 return NULL;
4955 }
4956
4957 init = dlsym(module, entrypoint);
4958 if (!init) {
Pekka Paalanen1b3c1ea2012-06-11 14:06:04 +03004959 weston_log("Failed to lookup init function: %s\n", dlerror());
Rob Bradfordc9e64ab2012-12-05 18:47:10 +00004960 dlclose(module);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004961 return NULL;
4962 }
4963
4964 return init;
4965}
4966
Giulio Camuffo459137b2014-10-11 23:56:24 +03004967
4968/** Destroys the compositor.
4969 *
4970 * This function cleans up the compositor state and destroys it.
4971 *
4972 * \param compositor The compositor to be destroyed.
4973 */
4974WL_EXPORT void
4975weston_compositor_destroy(struct weston_compositor *compositor)
4976{
4977 /* prevent further rendering while shutting down */
4978 compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
4979
4980 wl_signal_emit(&compositor->destroy_signal, compositor);
4981
4982 weston_compositor_xkb_destroy(compositor);
4983
Giulio Camuffo2d24e642015-10-03 16:25:15 +03004984 if (compositor->backend)
4985 compositor->backend->destroy(compositor);
Giulio Camuffo459137b2014-10-11 23:56:24 +03004986 free(compositor);
4987}
4988
4989/** Instruct the compositor to exit.
4990 *
4991 * This functions does not directly destroy the compositor object, it merely
4992 * command it to start the tear down process. It is not guaranteed that the
4993 * tear down will happen immediately.
4994 *
4995 * \param compositor The compositor to tear down.
4996 */
4997WL_EXPORT void
4998weston_compositor_exit(struct weston_compositor *compositor)
4999{
5000 compositor->exit(compositor);
5001}
5002
5003/** Return the user data stored in the compositor.
5004 *
5005 * This function returns the user data pointer set with user_data parameter
5006 * to the \ref weston_compositor_create function.
5007 */
5008WL_EXPORT void *
5009weston_compositor_get_user_data(struct weston_compositor *compositor)
5010{
5011 return compositor->user_data;
5012}