1/* swc: surface.c
2 *
3 * Copyright (c) 2013-2020 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "surface.h"
25#include "event.h"
26#include "internal.h"
27#include "output.h"
28#include "region.h"
29#include "screen.h"
30#include "subsurface.h"
31#include "util.h"
32#include "view.h"
33#include "wayland_buffer.h"
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <wld/wld.h>
38
39/**
40 * Removes a buffer from a surface state.
41 */
42static void
43handle_buffer_destroy(struct wl_listener *listener, void *data)
44{
45 struct surface_state *state;
46
47 state = wl_container_of(listener, state, buffer_destroy_listener);
48 state->buffer = NULL;
49 state->buffer_resource = NULL;
50}
51
52static void
53handle_role_destroy(struct wl_listener *listener, void *data)
54{
55 struct surface *surface = wl_container_of(listener, surface, role_destroy_listener);
56
57 (void)data;
58
59 surface->role = NULL;
60}
61
62static void
63state_initialize(struct surface_state *state)
64{
65 state->buffer = NULL;
66 /*layer-shell rejects surfaces with a pre-existing buffer */
67 state->buffer_resource = NULL;
68 state->buffer_destroy_listener.notify = &handle_buffer_destroy;
69
70 pixman_region32_init(&state->damage);
71 pixman_region32_init(&state->opaque);
72 pixman_region32_init_with_extents(&state->input, &infinite_extents);
73
74 wl_list_init(&state->frame_callbacks);
75 wl_list_init(&state->subsurfaces_below);
76 wl_list_init(&state->subsurfaces_above);
77}
78
79static void
80state_finalize(struct surface_state *state)
81{
82 struct wl_resource *resource, *tmp;
83
84 if (state->buffer) {
85 wl_list_remove(&state->buffer_destroy_listener.link);
86 }
87
88 pixman_region32_fini(&state->damage);
89 pixman_region32_fini(&state->opaque);
90 pixman_region32_fini(&state->input);
91
92 /* Remove all leftover callbacks. */
93 wl_list_for_each_safe(resource, tmp, &state->frame_callbacks, link)
94 wl_resource_destroy(resource);
95}
96
97/**
98 * In order to set the buffer of a surface state (current or pending), we need
99 * to manage the destroy listeners we have for the new and old buffer.
100 */
101static void
102state_set_buffer(struct surface_state *state, struct wl_resource *resource)
103{
104 struct wld_buffer *buffer = resource ? wayland_buffer_get(resource) : NULL;
105
106 if (state->buffer) {
107 wl_list_remove(&state->buffer_destroy_listener.link);
108 }
109
110 if (buffer) {
111 wl_resource_add_destroy_listener(resource,
112 &state->buffer_destroy_listener);
113 }
114
115 state->buffer = buffer;
116 state->buffer_resource = resource;
117}
118
119static void
120handle_frame(struct view_handler *handler, uint32_t time)
121{
122 struct surface *surface = wl_container_of(handler, surface, view_handler);
123 struct wl_resource *resource, *tmp;
124
125 wl_list_for_each_safe(resource, tmp, &surface->state.frame_callbacks, link)
126 {
127 wl_callback_send_done(resource, time);
128 wl_resource_destroy(resource);
129 }
130
131 wl_list_init(&surface->state.frame_callbacks);
132}
133
134static void
135handle_screens(struct view_handler *handler, uint32_t entered, uint32_t left)
136{
137 struct surface *surface = wl_container_of(handler, surface, view_handler);
138 struct screen *screen;
139 struct output *output;
140 struct wl_client *client;
141 struct wl_resource *resource;
142
143 client = wl_resource_get_client(surface->resource);
144
145 wl_list_for_each(screen, &swc.screens, link)
146 {
147 if (!((entered | left) & screen_mask(screen))) {
148 continue;
149 }
150
151 wl_list_for_each(output, &screen->outputs, link)
152 {
153 resource = wl_resource_find_for_client(&output->resources, client);
154
155 if (resource) {
156 if (entered & screen_mask(screen)) {
157 wl_surface_send_enter(surface->resource, resource);
158 } else if (left & screen_mask(screen)) {
159 wl_surface_send_leave(surface->resource, resource);
160 }
161 }
162 }
163 }
164}
165
166static const struct view_handler_impl view_handler_impl = {
167 .frame = handle_frame,
168 .screens = handle_screens,
169};
170
171static void
172attach(struct wl_client *client, struct wl_resource *resource,
173 struct wl_resource *buffer_resource, int32_t x, int32_t y)
174{
175 struct surface *surface = wl_resource_get_user_data(resource);
176
177 surface->pending.commit |= SURFACE_COMMIT_ATTACH;
178
179 state_set_buffer(&surface->pending.state, buffer_resource);
180 surface->pending.x = x;
181 surface->pending.y = y;
182}
183
184static void
185damage(struct wl_client *client, struct wl_resource *resource, int32_t x,
186 int32_t y, int32_t width, int32_t height)
187{
188 struct surface *surface = wl_resource_get_user_data(resource);
189
190 surface->pending.commit |= SURFACE_COMMIT_DAMAGE;
191 pixman_region32_union_rect(&surface->pending.state.damage,
192 &surface->pending.state.damage, x, y, width,
193 height);
194}
195
196static void
197frame(struct wl_client *client, struct wl_resource *resource, uint32_t id)
198{
199 struct surface *surface = wl_resource_get_user_data(resource);
200 struct wl_resource *callback_resource;
201
202 callback_resource =
203 wl_resource_create(client, &wl_callback_interface, 1, id);
204 if (!callback_resource) {
205 wl_resource_post_no_memory(resource);
206 return;
207 }
208 surface->pending.commit |= SURFACE_COMMIT_FRAME;
209 wl_resource_set_implementation(callback_resource, NULL, NULL,
210 &remove_resource);
211 wl_list_insert(surface->pending.state.frame_callbacks.prev,
212 wl_resource_get_link(callback_resource));
213}
214
215static void
216set_opaque_region(struct wl_client *client, struct wl_resource *resource,
217 struct wl_resource *region_resource)
218{
219 struct surface *surface = wl_resource_get_user_data(resource);
220
221 surface->pending.commit |= SURFACE_COMMIT_OPAQUE;
222
223 if (region_resource) {
224 pixman_region32_t *region = wl_resource_get_user_data(region_resource);
225 pixman_region32_copy(&surface->pending.state.opaque, region);
226 } else {
227 pixman_region32_clear(&surface->pending.state.opaque);
228 }
229}
230
231static void
232set_input_region(struct wl_client *client, struct wl_resource *resource,
233 struct wl_resource *region_resource)
234{
235 struct surface *surface = wl_resource_get_user_data(resource);
236
237 surface->pending.commit |= SURFACE_COMMIT_INPUT;
238
239 if (region_resource) {
240 pixman_region32_t *region = wl_resource_get_user_data(region_resource);
241 pixman_region32_copy(&surface->pending.state.input, region);
242 } else {
243 pixman_region32_reset(&surface->pending.state.input, &infinite_extents);
244 }
245}
246
247static inline void
248trim_region(pixman_region32_t *region, struct wld_buffer *buffer)
249{
250 pixman_region32_intersect_rect(region, region, 0, 0,
251 buffer ? buffer->width : 0,
252 buffer ? buffer->height : 0);
253}
254
255static void
256surface_apply_pending(struct surface *surface, bool flush_children)
257{
258 struct wld_buffer *buffer;
259
260 /* Attach */
261 if (surface->pending.commit & SURFACE_COMMIT_ATTACH) {
262 if (surface->state.buffer &&
263 surface->state.buffer != surface->pending.state.buffer) {
264 wl_buffer_send_release(surface->state.buffer_resource);
265 }
266
267 state_set_buffer(&surface->state,
268 surface->pending.state.buffer_resource);
269 }
270
271 buffer = surface->state.buffer;
272
273 /* Damage */
274 if (surface->pending.commit & SURFACE_COMMIT_DAMAGE) {
275 pixman_region32_union(&surface->state.damage, &surface->state.damage,
276 &surface->pending.state.damage);
277 pixman_region32_clear(&surface->pending.state.damage);
278 }
279
280 /* Opaque */
281 if (surface->pending.commit & SURFACE_COMMIT_OPAQUE) {
282 pixman_region32_copy(&surface->state.opaque,
283 &surface->pending.state.opaque);
284 }
285
286 /* Input */
287 if (surface->pending.commit & SURFACE_COMMIT_INPUT) {
288 pixman_region32_copy(&surface->state.input,
289 &surface->pending.state.input);
290 }
291
292 /* Frame */
293 if (surface->pending.commit & SURFACE_COMMIT_FRAME) {
294 wl_list_insert_list(&surface->state.frame_callbacks,
295 &surface->pending.state.frame_callbacks);
296 wl_list_init(&surface->pending.state.frame_callbacks);
297 }
298
299 trim_region(&surface->state.damage, buffer);
300 trim_region(&surface->state.opaque, buffer);
301
302 if (surface->view) {
303 if (surface->pending.commit & SURFACE_COMMIT_ATTACH) {
304 view_attach(surface->view, buffer);
305 }
306 view_update(surface->view);
307 }
308
309 surface->pending.commit = 0;
310
311 if (surface->subsurface) {
312 surface->subsurface->pending = false;
313 }
314
315 if (surface->subsurface) {
316 subsurface_update_visibility(surface->subsurface);
317 }
318
319 subsurface_parent_commit(surface);
320 wl_signal_emit(&surface->signal.commit, surface);
321
322 if (flush_children) {
323 struct subsurface *child;
324 wl_list_for_each(child, &surface->subsurfaces, link)
325 {
326 if (!child->pending || !subsurface_is_synchronized(child)) {
327 continue;
328 }
329 if (child->surface) {
330 surface_apply_pending(child->surface, true);
331 }
332 }
333 }
334}
335
336static void
337commit(struct wl_client *client, struct wl_resource *resource)
338{
339 struct surface *surface = wl_resource_get_user_data(resource);
340
341 if (surface->subsurface &&
342 subsurface_is_synchronized(surface->subsurface)) {
343 surface->subsurface->pending = true;
344 return;
345 }
346
347 surface_apply_pending(surface, true);
348}
349
350static void
351set_buffer_transform(struct wl_client *client, struct wl_resource *surface,
352 int32_t transform)
353{
354 if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
355 wl_resource_post_error(surface, WL_SURFACE_ERROR_INVALID_TRANSFORM,
356 "buffer transform %" PRId32 " not supported",
357 transform);
358 }
359}
360
361static void
362set_buffer_scale(struct wl_client *client, struct wl_resource *surface,
363 int32_t scale)
364{
365 if (scale != 1) {
366 wl_resource_post_error(surface, WL_SURFACE_ERROR_INVALID_SCALE,
367 "buffer scale not supported");
368 }
369}
370
371static void
372damage_buffer(struct wl_client *client, struct wl_resource *surface, int32_t x,
373 int32_t y, int32_t w, int32_t h)
374{
375 damage(client, surface, x, y, w, h);
376}
377
378static const struct wl_surface_interface surface_impl = {
379 .destroy = destroy_resource,
380 .attach = attach,
381 .damage = damage,
382 .frame = frame,
383 .set_opaque_region = set_opaque_region,
384 .set_input_region = set_input_region,
385 .commit = commit,
386 .set_buffer_transform = set_buffer_transform,
387 .set_buffer_scale = set_buffer_scale,
388 .damage_buffer = damage_buffer,
389};
390
391static void
392surface_destroy(struct wl_resource *resource)
393{
394 struct surface *surface = wl_resource_get_user_data(resource);
395
396 state_finalize(&surface->state);
397 state_finalize(&surface->pending.state);
398
399 if (surface->view) {
400 wl_list_remove(&surface->view_handler.link);
401 }
402 if (surface->role) {
403 wl_list_remove(&surface->role_destroy_listener.link);
404 }
405
406 free(surface);
407}
408
409/**
410 * Construct a new surface, adding it to the given client as id.
411 *
412 * The surface will be free'd automatically when its resource is destroyed.
413 *
414 * @return The newly allocated surface.
415 */
416struct surface *
417surface_new(struct wl_client *client, uint32_t version, uint32_t id)
418{
419 struct surface *surface;
420
421 surface = malloc(sizeof(*surface));
422 if (!surface) {
423 goto error0;
424 }
425
426 surface->resource =
427 wl_resource_create(client, &wl_surface_interface, version, id);
428 if (!surface->resource) {
429 goto error1;
430 }
431 wl_resource_set_implementation(surface->resource, &surface_impl, surface,
432 &surface_destroy);
433
434 /* Initialize the surface. */
435 surface->pending.commit = 0;
436 wl_signal_init(&surface->signal.commit);
437 surface->view = NULL;
438 surface->view_handler.impl = &view_handler_impl;
439 surface->role = NULL;
440 surface->role_destroy_listener.notify = handle_role_destroy;
441 surface->subsurface = NULL;
442 wl_list_init(&surface->subsurfaces);
443 surface->has_window_geometry = false;
444 surface->window_x = 0;
445 surface->window_y = 0;
446 surface->window_width = 0;
447 surface->window_height = 0;
448 surface->window_geometry_applied = false;
449
450 state_initialize(&surface->state);
451 state_initialize(&surface->pending.state);
452
453 return surface;
454
455error1:
456 free(surface);
457error0:
458 return NULL;
459}
460
461void
462surface_set_view(struct surface *surface, struct view *view)
463{
464 if (surface->view == view) {
465 return;
466 }
467
468 if (surface->view) {
469 wl_list_remove(&surface->view_handler.link);
470 }
471
472 surface->view = view;
473
474 if (view) {
475 wl_list_insert(&view->handlers, &surface->view_handler.link);
476 view_attach(view, surface->state.buffer);
477 view_update(view);
478 }
479}
480
481bool
482surface_set_role(struct surface *surface, struct wl_resource *role)
483{
484 if (surface->role) {
485 return false;
486 }
487
488 surface->role = role;
489 wl_resource_add_destroy_listener(role, &surface->role_destroy_listener);
490 return true;
491}
492
493bool
494surface_has_buffer(struct surface *surface)
495{
496 return surface->state.buffer_resource ||
497 ((surface->pending.commit & SURFACE_COMMIT_ATTACH) &&
498 surface->pending.state.buffer_resource);
499}
500
501void
502surface_commit_pending(struct surface *surface)
503{
504 surface_apply_pending(surface, true);
505}