1 #include <assert.h>
2 #include <stdlib.h>
3 #include <wayland-server-core.h>
4 #include <wlr/render/interface.h>
5 #include <wlr/types/wlr_buffer.h>
6 #include <wlr/types/wlr_compositor.h>
7 #include <wlr/types/wlr_matrix.h>
8 #include <wlr/types/wlr_region.h>
9 #include <wlr/types/wlr_surface.h>
10 #include <wlr/types/wlr_output.h>
11 #include <wlr/util/log.h>
12 #include <wlr/util/region.h>
13 #include "util/signal.h"
14 #include "util/time.h"
15
16 #define CALLBACK_VERSION 1
17 #define SURFACE_VERSION 4
18 #define SUBSURFACE_VERSION 1
19
min(int fst,int snd)20 static int min(int fst, int snd) {
21 if (fst < snd) {
22 return fst;
23 } else {
24 return snd;
25 }
26 }
27
max(int fst,int snd)28 static int max(int fst, int snd) {
29 if (fst > snd) {
30 return fst;
31 } else {
32 return snd;
33 }
34 }
35
surface_state_reset_buffer(struct wlr_surface_state * state)36 static void surface_state_reset_buffer(struct wlr_surface_state *state) {
37 if (state->buffer_resource) {
38 wl_list_remove(&state->buffer_destroy.link);
39 state->buffer_resource = NULL;
40 }
41 }
42
surface_handle_buffer_destroy(struct wl_listener * listener,void * data)43 static void surface_handle_buffer_destroy(struct wl_listener *listener,
44 void *data) {
45 struct wlr_surface_state *state =
46 wl_container_of(listener, state, buffer_destroy);
47 surface_state_reset_buffer(state);
48 }
49
surface_state_set_buffer(struct wlr_surface_state * state,struct wl_resource * buffer_resource)50 static void surface_state_set_buffer(struct wlr_surface_state *state,
51 struct wl_resource *buffer_resource) {
52 surface_state_reset_buffer(state);
53
54 state->buffer_resource = buffer_resource;
55 if (buffer_resource != NULL) {
56 wl_resource_add_destroy_listener(buffer_resource,
57 &state->buffer_destroy);
58 state->buffer_destroy.notify = surface_handle_buffer_destroy;
59 }
60 }
61
surface_destroy(struct wl_client * client,struct wl_resource * resource)62 static void surface_destroy(struct wl_client *client,
63 struct wl_resource *resource) {
64 wl_resource_destroy(resource);
65 }
66
surface_attach(struct wl_client * client,struct wl_resource * resource,struct wl_resource * buffer,int32_t dx,int32_t dy)67 static void surface_attach(struct wl_client *client,
68 struct wl_resource *resource,
69 struct wl_resource *buffer, int32_t dx, int32_t dy) {
70 struct wlr_surface *surface = wlr_surface_from_resource(resource);
71
72 surface->pending.committed |= WLR_SURFACE_STATE_BUFFER;
73 surface->pending.dx = dx;
74 surface->pending.dy = dy;
75 surface_state_set_buffer(&surface->pending, buffer);
76 }
77
surface_damage(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)78 static void surface_damage(struct wl_client *client,
79 struct wl_resource *resource,
80 int32_t x, int32_t y, int32_t width, int32_t height) {
81 struct wlr_surface *surface = wlr_surface_from_resource(resource);
82 if (width < 0 || height < 0) {
83 return;
84 }
85 surface->pending.committed |= WLR_SURFACE_STATE_SURFACE_DAMAGE;
86 pixman_region32_union_rect(&surface->pending.surface_damage,
87 &surface->pending.surface_damage,
88 x, y, width, height);
89 }
90
callback_handle_resource_destroy(struct wl_resource * resource)91 static void callback_handle_resource_destroy(struct wl_resource *resource) {
92 wl_list_remove(wl_resource_get_link(resource));
93 }
94
surface_frame(struct wl_client * client,struct wl_resource * resource,uint32_t callback)95 static void surface_frame(struct wl_client *client,
96 struct wl_resource *resource, uint32_t callback) {
97 struct wlr_surface *surface = wlr_surface_from_resource(resource);
98
99 struct wl_resource *callback_resource = wl_resource_create(client,
100 &wl_callback_interface, CALLBACK_VERSION, callback);
101 if (callback_resource == NULL) {
102 wl_resource_post_no_memory(resource);
103 return;
104 }
105 wl_resource_set_implementation(callback_resource, NULL, NULL,
106 callback_handle_resource_destroy);
107
108 wl_list_insert(surface->pending.frame_callback_list.prev,
109 wl_resource_get_link(callback_resource));
110
111 surface->pending.committed |= WLR_SURFACE_STATE_FRAME_CALLBACK_LIST;
112 }
113
surface_set_opaque_region(struct wl_client * client,struct wl_resource * resource,struct wl_resource * region_resource)114 static void surface_set_opaque_region(struct wl_client *client,
115 struct wl_resource *resource,
116 struct wl_resource *region_resource) {
117 struct wlr_surface *surface = wlr_surface_from_resource(resource);
118 surface->pending.committed |= WLR_SURFACE_STATE_OPAQUE_REGION;
119 if (region_resource) {
120 pixman_region32_t *region = wlr_region_from_resource(region_resource);
121 pixman_region32_copy(&surface->pending.opaque, region);
122 } else {
123 pixman_region32_clear(&surface->pending.opaque);
124 }
125 }
126
surface_set_input_region(struct wl_client * client,struct wl_resource * resource,struct wl_resource * region_resource)127 static void surface_set_input_region(struct wl_client *client,
128 struct wl_resource *resource,
129 struct wl_resource *region_resource) {
130 struct wlr_surface *surface = wlr_surface_from_resource(resource);
131 surface->pending.committed |= WLR_SURFACE_STATE_INPUT_REGION;
132 if (region_resource) {
133 pixman_region32_t *region = wlr_region_from_resource(region_resource);
134 pixman_region32_copy(&surface->pending.input, region);
135 } else {
136 pixman_region32_fini(&surface->pending.input);
137 pixman_region32_init_rect(&surface->pending.input,
138 INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX);
139 }
140 }
141
142 /**
143 * Computes the surface viewport source size, ie. the size after applying the
144 * surface's scale, transform and cropping (via the viewport's source
145 * rectangle) but before applying the viewport scaling (via the viewport's
146 * destination rectangle).
147 */
surface_state_viewport_src_size(struct wlr_surface_state * state,int * out_width,int * out_height)148 static void surface_state_viewport_src_size(struct wlr_surface_state *state,
149 int *out_width, int *out_height) {
150 if (state->buffer_width == 0 && state->buffer_height == 0) {
151 *out_width = *out_height = 0;
152 return;
153 }
154
155 if (state->viewport.has_src) {
156 *out_width = state->viewport.src.width;
157 *out_height = state->viewport.src.height;
158 } else {
159 int width = state->buffer_width / state->scale;
160 int height = state->buffer_height / state->scale;
161 if ((state->transform & WL_OUTPUT_TRANSFORM_90) != 0) {
162 int tmp = width;
163 width = height;
164 height = tmp;
165 }
166 *out_width = width;
167 *out_height = height;
168 }
169 }
170
surface_state_finalize(struct wlr_surface * surface,struct wlr_surface_state * state)171 static void surface_state_finalize(struct wlr_surface *surface,
172 struct wlr_surface_state *state) {
173 if ((state->committed & WLR_SURFACE_STATE_BUFFER)) {
174 if (state->buffer_resource != NULL) {
175 wlr_resource_get_buffer_size(state->buffer_resource,
176 surface->renderer, &state->buffer_width, &state->buffer_height);
177 } else {
178 state->buffer_width = state->buffer_height = 0;
179 }
180 }
181
182 if (state->viewport.has_dst) {
183 if (state->buffer_width == 0 && state->buffer_height == 0) {
184 state->width = state->height = 0;
185 } else {
186 state->width = state->viewport.dst_width;
187 state->height = state->viewport.dst_height;
188 }
189 } else {
190 surface_state_viewport_src_size(state,
191 &state->width, &state->height);
192 }
193
194 pixman_region32_intersect_rect(&state->surface_damage,
195 &state->surface_damage, 0, 0, state->width, state->height);
196
197 pixman_region32_intersect_rect(&state->buffer_damage,
198 &state->buffer_damage, 0, 0, state->buffer_width,
199 state->buffer_height);
200 }
201
surface_update_damage(pixman_region32_t * buffer_damage,struct wlr_surface_state * current,struct wlr_surface_state * pending)202 static void surface_update_damage(pixman_region32_t *buffer_damage,
203 struct wlr_surface_state *current, struct wlr_surface_state *pending) {
204 pixman_region32_clear(buffer_damage);
205
206 if (pending->width != current->width ||
207 pending->height != current->height) {
208 // Damage the whole buffer on resize
209 pixman_region32_union_rect(buffer_damage, buffer_damage, 0, 0,
210 pending->buffer_width, pending->buffer_height);
211 } else {
212 // Copy over surface damage + buffer damage
213 pixman_region32_t surface_damage;
214 pixman_region32_init(&surface_damage);
215
216 pixman_region32_copy(&surface_damage, &pending->surface_damage);
217
218 if (pending->viewport.has_dst) {
219 int src_width, src_height;
220 surface_state_viewport_src_size(pending, &src_width, &src_height);
221 float scale_x = (float)pending->viewport.dst_width / src_width;
222 float scale_y = (float)pending->viewport.dst_height / src_height;
223 wlr_region_scale_xy(&surface_damage, &surface_damage,
224 1.0 / scale_x, 1.0 / scale_y);
225 }
226 if (pending->viewport.has_src) {
227 // This is lossy: do a best-effort conversion
228 pixman_region32_translate(&surface_damage,
229 floor(pending->viewport.src.x),
230 floor(pending->viewport.src.y));
231 }
232
233 wlr_region_transform(&surface_damage, &surface_damage,
234 wlr_output_transform_invert(pending->transform),
235 pending->width, pending->height);
236 wlr_region_scale(&surface_damage, &surface_damage, pending->scale);
237
238 pixman_region32_union(buffer_damage,
239 &pending->buffer_damage, &surface_damage);
240
241 pixman_region32_fini(&surface_damage);
242 }
243 }
244
surface_state_copy(struct wlr_surface_state * state,struct wlr_surface_state * next)245 static void surface_state_copy(struct wlr_surface_state *state,
246 struct wlr_surface_state *next) {
247 state->width = next->width;
248 state->height = next->height;
249 state->buffer_width = next->buffer_width;
250 state->buffer_height = next->buffer_height;
251
252 if (next->committed & WLR_SURFACE_STATE_SCALE) {
253 state->scale = next->scale;
254 }
255 if (next->committed & WLR_SURFACE_STATE_TRANSFORM) {
256 state->transform = next->transform;
257 }
258 if (next->committed & WLR_SURFACE_STATE_BUFFER) {
259 state->dx = next->dx;
260 state->dy = next->dy;
261 } else {
262 state->dx = state->dy = 0;
263 }
264 if (next->committed & WLR_SURFACE_STATE_SURFACE_DAMAGE) {
265 pixman_region32_copy(&state->surface_damage, &next->surface_damage);
266 } else {
267 pixman_region32_clear(&state->surface_damage);
268 }
269 if (next->committed & WLR_SURFACE_STATE_BUFFER_DAMAGE) {
270 pixman_region32_copy(&state->buffer_damage, &next->buffer_damage);
271 } else {
272 pixman_region32_clear(&state->buffer_damage);
273 }
274 if (next->committed & WLR_SURFACE_STATE_OPAQUE_REGION) {
275 pixman_region32_copy(&state->opaque, &next->opaque);
276 }
277 if (next->committed & WLR_SURFACE_STATE_INPUT_REGION) {
278 pixman_region32_copy(&state->input, &next->input);
279 }
280 if (next->committed & WLR_SURFACE_STATE_VIEWPORT) {
281 memcpy(&state->viewport, &next->viewport, sizeof(state->viewport));
282 }
283
284 state->committed |= next->committed;
285 }
286
287 /**
288 * Append pending state to current state and clear pending state.
289 */
surface_state_move(struct wlr_surface_state * state,struct wlr_surface_state * next)290 static void surface_state_move(struct wlr_surface_state *state,
291 struct wlr_surface_state *next) {
292 surface_state_copy(state, next);
293
294 if (next->committed & WLR_SURFACE_STATE_BUFFER) {
295 surface_state_set_buffer(state, next->buffer_resource);
296 surface_state_reset_buffer(next);
297 next->dx = next->dy = 0;
298 }
299 if (next->committed & WLR_SURFACE_STATE_SURFACE_DAMAGE) {
300 pixman_region32_clear(&next->surface_damage);
301 }
302 if (next->committed & WLR_SURFACE_STATE_BUFFER_DAMAGE) {
303 pixman_region32_clear(&next->buffer_damage);
304 }
305 if (next->committed & WLR_SURFACE_STATE_FRAME_CALLBACK_LIST) {
306 wl_list_insert_list(&state->frame_callback_list,
307 &next->frame_callback_list);
308 wl_list_init(&next->frame_callback_list);
309 }
310
311 next->committed = 0;
312 }
313
surface_damage_subsurfaces(struct wlr_subsurface * subsurface)314 static void surface_damage_subsurfaces(struct wlr_subsurface *subsurface) {
315 // XXX: This is probably the wrong way to do it, because this damage should
316 // come from the client, but weston doesn't do it correctly either and it
317 // seems to work ok. See the comment on weston_surface_damage for more info
318 // about a better approach.
319 struct wlr_surface *surface = subsurface->surface;
320 pixman_region32_union_rect(&surface->buffer_damage,
321 &surface->buffer_damage, 0, 0,
322 surface->current.buffer_width, surface->current.buffer_height);
323
324 subsurface->reordered = false;
325
326 struct wlr_subsurface *child;
327 wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) {
328 surface_damage_subsurfaces(child);
329 }
330 }
331
surface_apply_damage(struct wlr_surface * surface)332 static void surface_apply_damage(struct wlr_surface *surface) {
333 struct wl_resource *resource = surface->current.buffer_resource;
334 if (resource == NULL) {
335 // NULL commit
336 if (surface->buffer != NULL) {
337 wlr_buffer_unlock(&surface->buffer->base);
338 }
339 surface->buffer = NULL;
340 return;
341 }
342
343 if (surface->buffer != NULL && surface->buffer->resource_released) {
344 struct wlr_client_buffer *updated_buffer =
345 wlr_client_buffer_apply_damage(surface->buffer, resource,
346 &surface->buffer_damage);
347 if (updated_buffer != NULL) {
348 surface->buffer = updated_buffer;
349 return;
350 }
351 }
352
353 struct wlr_client_buffer *buffer =
354 wlr_client_buffer_import(surface->renderer, resource);
355 if (buffer == NULL) {
356 wlr_log(WLR_ERROR, "Failed to upload buffer");
357 return;
358 }
359
360 if (surface->buffer != NULL) {
361 wlr_buffer_unlock(&surface->buffer->base);
362 }
363 surface->buffer = buffer;
364 }
365
surface_update_opaque_region(struct wlr_surface * surface)366 static void surface_update_opaque_region(struct wlr_surface *surface) {
367 struct wlr_texture *texture = wlr_surface_get_texture(surface);
368 if (texture == NULL) {
369 pixman_region32_clear(&surface->opaque_region);
370 return;
371 }
372
373 if (wlr_texture_is_opaque(texture)) {
374 pixman_region32_init_rect(&surface->opaque_region,
375 0, 0, surface->current.width, surface->current.height);
376 return;
377 }
378
379 pixman_region32_intersect_rect(&surface->opaque_region,
380 &surface->current.opaque,
381 0, 0, surface->current.width, surface->current.height);
382 }
383
surface_update_input_region(struct wlr_surface * surface)384 static void surface_update_input_region(struct wlr_surface *surface) {
385 pixman_region32_intersect_rect(&surface->input_region,
386 &surface->current.input,
387 0, 0, surface->current.width, surface->current.height);
388 }
389
surface_commit_pending(struct wlr_surface * surface)390 static void surface_commit_pending(struct wlr_surface *surface) {
391 surface_state_finalize(surface, &surface->pending);
392
393 if (surface->role && surface->role->precommit) {
394 surface->role->precommit(surface);
395 }
396
397 bool invalid_buffer = surface->pending.committed & WLR_SURFACE_STATE_BUFFER;
398
399 surface->sx += surface->pending.dx;
400 surface->sy += surface->pending.dy;
401 surface_update_damage(&surface->buffer_damage,
402 &surface->current, &surface->pending);
403
404 surface_state_copy(&surface->previous, &surface->current);
405 surface_state_move(&surface->current, &surface->pending);
406
407 if (invalid_buffer) {
408 surface_apply_damage(surface);
409 }
410 surface_update_opaque_region(surface);
411 surface_update_input_region(surface);
412
413 // commit subsurface order
414 struct wlr_subsurface *subsurface;
415 wl_list_for_each_reverse(subsurface, &surface->subsurface_pending_list,
416 parent_pending_link) {
417 wl_list_remove(&subsurface->parent_link);
418 wl_list_insert(&surface->subsurfaces, &subsurface->parent_link);
419
420 if (subsurface->reordered) {
421 // TODO: damage all the subsurfaces
422 surface_damage_subsurfaces(subsurface);
423 }
424 }
425
426 if (surface->role && surface->role->commit) {
427 surface->role->commit(surface);
428 }
429
430 wlr_signal_emit_safe(&surface->events.commit, surface);
431 }
432
subsurface_is_synchronized(struct wlr_subsurface * subsurface)433 static bool subsurface_is_synchronized(struct wlr_subsurface *subsurface) {
434 while (subsurface != NULL) {
435 if (subsurface->synchronized) {
436 return true;
437 }
438
439 if (!subsurface->parent) {
440 return false;
441 }
442
443 if (!wlr_surface_is_subsurface(subsurface->parent)) {
444 break;
445 }
446 subsurface = wlr_subsurface_from_wlr_surface(subsurface->parent);
447 }
448
449 return false;
450 }
451
452 /**
453 * Recursive function to commit the effectively synchronized children.
454 */
subsurface_parent_commit(struct wlr_subsurface * subsurface,bool synchronized)455 static void subsurface_parent_commit(struct wlr_subsurface *subsurface,
456 bool synchronized) {
457 struct wlr_surface *surface = subsurface->surface;
458 if (synchronized || subsurface->synchronized) {
459 if (subsurface->has_cache) {
460 surface_state_move(&surface->pending, &subsurface->cached);
461 surface_commit_pending(surface);
462 subsurface->has_cache = false;
463 subsurface->cached.committed = 0;
464 }
465
466 struct wlr_subsurface *subsurface;
467 wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) {
468 subsurface_parent_commit(subsurface, true);
469 }
470 }
471 }
472
subsurface_commit(struct wlr_subsurface * subsurface)473 static void subsurface_commit(struct wlr_subsurface *subsurface) {
474 struct wlr_surface *surface = subsurface->surface;
475
476 if (subsurface_is_synchronized(subsurface)) {
477 surface_state_move(&subsurface->cached, &surface->pending);
478 subsurface->has_cache = true;
479 } else {
480 if (subsurface->has_cache) {
481 surface_state_move(&surface->pending, &subsurface->cached);
482 surface_commit_pending(surface);
483 subsurface->has_cache = false;
484 } else {
485 surface_commit_pending(surface);
486 }
487 }
488 }
489
surface_commit(struct wl_client * client,struct wl_resource * resource)490 static void surface_commit(struct wl_client *client,
491 struct wl_resource *resource) {
492 struct wlr_surface *surface = wlr_surface_from_resource(resource);
493
494 struct wlr_subsurface *subsurface = wlr_surface_is_subsurface(surface) ?
495 wlr_subsurface_from_wlr_surface(surface) : NULL;
496 if (subsurface != NULL) {
497 subsurface_commit(subsurface);
498 } else {
499 surface_commit_pending(surface);
500 }
501
502 wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) {
503 subsurface_parent_commit(subsurface, false);
504 }
505 }
506
surface_set_buffer_transform(struct wl_client * client,struct wl_resource * resource,int32_t transform)507 static void surface_set_buffer_transform(struct wl_client *client,
508 struct wl_resource *resource, int32_t transform) {
509 if (transform < WL_OUTPUT_TRANSFORM_NORMAL ||
510 transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) {
511 wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_TRANSFORM,
512 "Specified transform value (%d) is invalid", transform);
513 return;
514 }
515 struct wlr_surface *surface = wlr_surface_from_resource(resource);
516 surface->pending.committed |= WLR_SURFACE_STATE_TRANSFORM;
517 surface->pending.transform = transform;
518 }
519
surface_set_buffer_scale(struct wl_client * client,struct wl_resource * resource,int32_t scale)520 static void surface_set_buffer_scale(struct wl_client *client,
521 struct wl_resource *resource, int32_t scale) {
522 if (scale <= 0) {
523 wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_SCALE,
524 "Specified scale value (%d) is not positive", scale);
525 return;
526 }
527 struct wlr_surface *surface = wlr_surface_from_resource(resource);
528 surface->pending.committed |= WLR_SURFACE_STATE_SCALE;
529 surface->pending.scale = scale;
530 }
531
surface_damage_buffer(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)532 static void surface_damage_buffer(struct wl_client *client,
533 struct wl_resource *resource,
534 int32_t x, int32_t y, int32_t width,
535 int32_t height) {
536 struct wlr_surface *surface = wlr_surface_from_resource(resource);
537 if (width < 0 || height < 0) {
538 return;
539 }
540 surface->pending.committed |= WLR_SURFACE_STATE_BUFFER_DAMAGE;
541 pixman_region32_union_rect(&surface->pending.buffer_damage,
542 &surface->pending.buffer_damage,
543 x, y, width, height);
544 }
545
546 static const struct wl_surface_interface surface_interface = {
547 .destroy = surface_destroy,
548 .attach = surface_attach,
549 .damage = surface_damage,
550 .frame = surface_frame,
551 .set_opaque_region = surface_set_opaque_region,
552 .set_input_region = surface_set_input_region,
553 .commit = surface_commit,
554 .set_buffer_transform = surface_set_buffer_transform,
555 .set_buffer_scale = surface_set_buffer_scale,
556 .damage_buffer = surface_damage_buffer
557 };
558
wlr_surface_from_resource(struct wl_resource * resource)559 struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) {
560 assert(wl_resource_instance_of(resource, &wl_surface_interface,
561 &surface_interface));
562 return wl_resource_get_user_data(resource);
563 }
564
surface_state_init(struct wlr_surface_state * state)565 static void surface_state_init(struct wlr_surface_state *state) {
566 state->scale = 1;
567 state->transform = WL_OUTPUT_TRANSFORM_NORMAL;
568
569 wl_list_init(&state->frame_callback_list);
570
571 pixman_region32_init(&state->surface_damage);
572 pixman_region32_init(&state->buffer_damage);
573 pixman_region32_init(&state->opaque);
574 pixman_region32_init_rect(&state->input,
575 INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX);
576 }
577
surface_state_finish(struct wlr_surface_state * state)578 static void surface_state_finish(struct wlr_surface_state *state) {
579 surface_state_reset_buffer(state);
580
581 struct wl_resource *resource, *tmp;
582 wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list) {
583 wl_resource_destroy(resource);
584 }
585
586 pixman_region32_fini(&state->surface_damage);
587 pixman_region32_fini(&state->buffer_damage);
588 pixman_region32_fini(&state->opaque);
589 pixman_region32_fini(&state->input);
590 }
591
592 static void subsurface_unmap(struct wlr_subsurface *subsurface);
593
subsurface_destroy(struct wlr_subsurface * subsurface)594 static void subsurface_destroy(struct wlr_subsurface *subsurface) {
595 if (subsurface == NULL) {
596 return;
597 }
598
599 subsurface_unmap(subsurface);
600
601 wlr_signal_emit_safe(&subsurface->events.destroy, subsurface);
602
603 wl_list_remove(&subsurface->surface_destroy.link);
604 surface_state_finish(&subsurface->cached);
605
606 if (subsurface->parent) {
607 wl_list_remove(&subsurface->parent_link);
608 wl_list_remove(&subsurface->parent_pending_link);
609 wl_list_remove(&subsurface->parent_destroy.link);
610 }
611
612 wl_resource_set_user_data(subsurface->resource, NULL);
613 if (subsurface->surface) {
614 subsurface->surface->role_data = NULL;
615 }
616 free(subsurface);
617 }
618
surface_handle_resource_destroy(struct wl_resource * resource)619 static void surface_handle_resource_destroy(struct wl_resource *resource) {
620 struct wlr_surface *surface = wlr_surface_from_resource(resource);
621
622 wlr_signal_emit_safe(&surface->events.destroy, surface);
623
624 wl_list_remove(wl_resource_get_link(surface->resource));
625
626 wl_list_remove(&surface->renderer_destroy.link);
627 surface_state_finish(&surface->pending);
628 surface_state_finish(&surface->current);
629 surface_state_finish(&surface->previous);
630 pixman_region32_fini(&surface->buffer_damage);
631 pixman_region32_fini(&surface->opaque_region);
632 pixman_region32_fini(&surface->input_region);
633 if (surface->buffer != NULL) {
634 wlr_buffer_unlock(&surface->buffer->base);
635 }
636 free(surface);
637 }
638
surface_handle_renderer_destroy(struct wl_listener * listener,void * data)639 static void surface_handle_renderer_destroy(struct wl_listener *listener,
640 void *data) {
641 struct wlr_surface *surface =
642 wl_container_of(listener, surface, renderer_destroy);
643 wl_resource_destroy(surface->resource);
644 }
645
wlr_surface_create(struct wl_client * client,uint32_t version,uint32_t id,struct wlr_renderer * renderer,struct wl_list * resource_list)646 struct wlr_surface *wlr_surface_create(struct wl_client *client,
647 uint32_t version, uint32_t id, struct wlr_renderer *renderer,
648 struct wl_list *resource_list) {
649 assert(version <= SURFACE_VERSION);
650
651 struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface));
652 if (!surface) {
653 wl_client_post_no_memory(client);
654 return NULL;
655 }
656 surface->resource = wl_resource_create(client, &wl_surface_interface,
657 version, id);
658 if (surface->resource == NULL) {
659 free(surface);
660 wl_client_post_no_memory(client);
661 return NULL;
662 }
663 wl_resource_set_implementation(surface->resource, &surface_interface,
664 surface, surface_handle_resource_destroy);
665
666 wlr_log(WLR_DEBUG, "New wlr_surface %p (res %p)", surface, surface->resource);
667
668 surface->renderer = renderer;
669
670 surface_state_init(&surface->current);
671 surface_state_init(&surface->pending);
672 surface_state_init(&surface->previous);
673
674 wl_signal_init(&surface->events.commit);
675 wl_signal_init(&surface->events.destroy);
676 wl_signal_init(&surface->events.new_subsurface);
677 wl_list_init(&surface->subsurfaces);
678 wl_list_init(&surface->subsurface_pending_list);
679 pixman_region32_init(&surface->buffer_damage);
680 pixman_region32_init(&surface->opaque_region);
681 pixman_region32_init(&surface->input_region);
682
683 wl_signal_add(&renderer->events.destroy, &surface->renderer_destroy);
684 surface->renderer_destroy.notify = surface_handle_renderer_destroy;
685
686 struct wl_list *resource_link = wl_resource_get_link(surface->resource);
687 if (resource_list != NULL) {
688 wl_list_insert(resource_list, resource_link);
689 } else {
690 wl_list_init(resource_link);
691 }
692
693 return surface;
694 }
695
wlr_surface_get_texture(struct wlr_surface * surface)696 struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface) {
697 if (surface->buffer == NULL) {
698 return NULL;
699 }
700 return surface->buffer->texture;
701 }
702
wlr_surface_has_buffer(struct wlr_surface * surface)703 bool wlr_surface_has_buffer(struct wlr_surface *surface) {
704 return wlr_surface_get_texture(surface) != NULL;
705 }
706
wlr_surface_set_role(struct wlr_surface * surface,const struct wlr_surface_role * role,void * role_data,struct wl_resource * error_resource,uint32_t error_code)707 bool wlr_surface_set_role(struct wlr_surface *surface,
708 const struct wlr_surface_role *role, void *role_data,
709 struct wl_resource *error_resource, uint32_t error_code) {
710 assert(role != NULL);
711
712 if (surface->role != NULL && surface->role != role) {
713 if (error_resource != NULL) {
714 wl_resource_post_error(error_resource, error_code,
715 "Cannot assign role %s to wl_surface@%" PRIu32 ", already has role %s\n",
716 role->name, wl_resource_get_id(surface->resource),
717 surface->role->name);
718 }
719 return false;
720 }
721 if (surface->role_data != NULL && surface->role_data != role_data) {
722 wl_resource_post_error(error_resource, error_code,
723 "Cannot reassign role %s to wl_surface@%" PRIu32 ","
724 "role object still exists", role->name,
725 wl_resource_get_id(surface->resource));
726 return false;
727 }
728
729 surface->role = role;
730 surface->role_data = role_data;
731 return true;
732 }
733
734 static const struct wl_subsurface_interface subsurface_implementation;
735
subsurface_from_resource(struct wl_resource * resource)736 static struct wlr_subsurface *subsurface_from_resource(
737 struct wl_resource *resource) {
738 assert(wl_resource_instance_of(resource, &wl_subsurface_interface,
739 &subsurface_implementation));
740 return wl_resource_get_user_data(resource);
741 }
742
subsurface_resource_destroy(struct wl_resource * resource)743 static void subsurface_resource_destroy(struct wl_resource *resource) {
744 struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
745 wl_list_remove(wl_resource_get_link(resource));
746 subsurface_destroy(subsurface);
747 }
748
subsurface_handle_destroy(struct wl_client * client,struct wl_resource * resource)749 static void subsurface_handle_destroy(struct wl_client *client,
750 struct wl_resource *resource) {
751 wl_resource_destroy(resource);
752 }
753
subsurface_handle_set_position(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y)754 static void subsurface_handle_set_position(struct wl_client *client,
755 struct wl_resource *resource, int32_t x, int32_t y) {
756 struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
757 if (subsurface == NULL) {
758 return;
759 }
760
761 subsurface->pending.x = x;
762 subsurface->pending.y = y;
763 }
764
subsurface_find_sibling(struct wlr_subsurface * subsurface,struct wlr_surface * surface)765 static struct wlr_subsurface *subsurface_find_sibling(
766 struct wlr_subsurface *subsurface, struct wlr_surface *surface) {
767 struct wlr_surface *parent = subsurface->parent;
768
769 struct wlr_subsurface *sibling;
770 wl_list_for_each(sibling, &parent->subsurfaces, parent_link) {
771 if (sibling->surface == surface && sibling != subsurface) {
772 return sibling;
773 }
774 }
775
776 return NULL;
777 }
778
subsurface_handle_place_above(struct wl_client * client,struct wl_resource * resource,struct wl_resource * sibling_resource)779 static void subsurface_handle_place_above(struct wl_client *client,
780 struct wl_resource *resource, struct wl_resource *sibling_resource) {
781 struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
782 if (subsurface == NULL) {
783 return;
784 }
785
786 struct wlr_surface *sibling_surface =
787 wlr_surface_from_resource(sibling_resource);
788 struct wlr_subsurface *sibling =
789 subsurface_find_sibling(subsurface, sibling_surface);
790
791 if (!sibling) {
792 wl_resource_post_error(subsurface->resource,
793 WL_SUBSURFACE_ERROR_BAD_SURFACE,
794 "%s: wl_surface@%" PRIu32 "is not a parent or sibling",
795 "place_above", wl_resource_get_id(sibling_surface->resource));
796 return;
797 }
798
799 wl_list_remove(&subsurface->parent_pending_link);
800 wl_list_insert(&sibling->parent_pending_link,
801 &subsurface->parent_pending_link);
802
803 subsurface->reordered = true;
804 }
805
subsurface_handle_place_below(struct wl_client * client,struct wl_resource * resource,struct wl_resource * sibling_resource)806 static void subsurface_handle_place_below(struct wl_client *client,
807 struct wl_resource *resource, struct wl_resource *sibling_resource) {
808 struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
809 if (subsurface == NULL) {
810 return;
811 }
812
813 struct wlr_surface *sibling_surface =
814 wlr_surface_from_resource(sibling_resource);
815 struct wlr_subsurface *sibling =
816 subsurface_find_sibling(subsurface, sibling_surface);
817
818 if (!sibling) {
819 wl_resource_post_error(subsurface->resource,
820 WL_SUBSURFACE_ERROR_BAD_SURFACE,
821 "%s: wl_surface@%" PRIu32 " is not a parent or sibling",
822 "place_below", wl_resource_get_id(sibling_surface->resource));
823 return;
824 }
825
826 wl_list_remove(&subsurface->parent_pending_link);
827 wl_list_insert(sibling->parent_pending_link.prev,
828 &subsurface->parent_pending_link);
829
830 subsurface->reordered = true;
831 }
832
subsurface_handle_set_sync(struct wl_client * client,struct wl_resource * resource)833 static void subsurface_handle_set_sync(struct wl_client *client,
834 struct wl_resource *resource) {
835 struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
836 if (subsurface == NULL) {
837 return;
838 }
839
840 subsurface->synchronized = true;
841 }
842
subsurface_handle_set_desync(struct wl_client * client,struct wl_resource * resource)843 static void subsurface_handle_set_desync(struct wl_client *client,
844 struct wl_resource *resource) {
845 struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
846 if (subsurface == NULL) {
847 return;
848 }
849
850 if (subsurface->synchronized) {
851 subsurface->synchronized = false;
852
853 if (!subsurface_is_synchronized(subsurface)) {
854 // TODO: do a synchronized commit to flush the cache
855 subsurface_parent_commit(subsurface, true);
856 }
857 }
858 }
859
860 static const struct wl_subsurface_interface subsurface_implementation = {
861 .destroy = subsurface_handle_destroy,
862 .set_position = subsurface_handle_set_position,
863 .place_above = subsurface_handle_place_above,
864 .place_below = subsurface_handle_place_below,
865 .set_sync = subsurface_handle_set_sync,
866 .set_desync = subsurface_handle_set_desync,
867 };
868
869 /**
870 * Checks if this subsurface needs to be marked as mapped. This can happen if:
871 * - The subsurface has a buffer
872 * - Its parent is mapped
873 */
subsurface_consider_map(struct wlr_subsurface * subsurface,bool check_parent)874 static void subsurface_consider_map(struct wlr_subsurface *subsurface,
875 bool check_parent) {
876 if (subsurface->mapped || !wlr_surface_has_buffer(subsurface->surface)) {
877 return;
878 }
879
880 if (check_parent) {
881 if (subsurface->parent == NULL) {
882 return;
883 }
884 if (wlr_surface_is_subsurface(subsurface->parent)) {
885 struct wlr_subsurface *parent =
886 wlr_subsurface_from_wlr_surface(subsurface->parent);
887 if (parent == NULL || !parent->mapped) {
888 return;
889 }
890 }
891 }
892
893 // Now we can map the subsurface
894 wlr_signal_emit_safe(&subsurface->events.map, subsurface);
895 subsurface->mapped = true;
896
897 // Try mapping all children too
898 struct wlr_subsurface *child;
899 wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) {
900 subsurface_consider_map(child, false);
901 }
902 }
903
subsurface_unmap(struct wlr_subsurface * subsurface)904 static void subsurface_unmap(struct wlr_subsurface *subsurface) {
905 if (!subsurface->mapped) {
906 return;
907 }
908
909 wlr_signal_emit_safe(&subsurface->events.unmap, subsurface);
910 subsurface->mapped = false;
911
912 // Unmap all children
913 struct wlr_subsurface *child;
914 wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) {
915 subsurface_unmap(child);
916 }
917 }
918
subsurface_role_commit(struct wlr_surface * surface)919 static void subsurface_role_commit(struct wlr_surface *surface) {
920 struct wlr_subsurface *subsurface =
921 wlr_subsurface_from_wlr_surface(surface);
922 if (subsurface == NULL) {
923 return;
924 }
925
926 if (subsurface->current.x != subsurface->pending.x ||
927 subsurface->current.y != subsurface->pending.y) {
928 // Subsurface has moved
929 int dx = subsurface->current.x - subsurface->pending.x;
930 int dy = subsurface->current.y - subsurface->pending.y;
931
932 subsurface->current.x = subsurface->pending.x;
933 subsurface->current.y = subsurface->pending.y;
934
935 if ((surface->current.transform & WL_OUTPUT_TRANSFORM_90) != 0) {
936 int tmp = dx;
937 dx = dy;
938 dy = tmp;
939 }
940
941 pixman_region32_union_rect(&surface->buffer_damage,
942 &surface->buffer_damage,
943 dx * surface->previous.scale, dy * surface->previous.scale,
944 surface->previous.buffer_width, surface->previous.buffer_height);
945 pixman_region32_union_rect(&surface->buffer_damage,
946 &surface->buffer_damage, 0, 0,
947 surface->current.buffer_width, surface->current.buffer_height);
948 }
949
950 subsurface_consider_map(subsurface, true);
951 }
952
subsurface_role_precommit(struct wlr_surface * surface)953 static void subsurface_role_precommit(struct wlr_surface *surface) {
954 struct wlr_subsurface *subsurface =
955 wlr_subsurface_from_wlr_surface(surface);
956 if (subsurface == NULL) {
957 return;
958 }
959
960 if (surface->pending.committed & WLR_SURFACE_STATE_BUFFER &&
961 surface->pending.buffer_resource == NULL) {
962 // This is a NULL commit
963 subsurface_unmap(subsurface);
964 }
965 }
966
967 const struct wlr_surface_role subsurface_role = {
968 .name = "wl_subsurface",
969 .commit = subsurface_role_commit,
970 .precommit = subsurface_role_precommit,
971 };
972
subsurface_handle_parent_destroy(struct wl_listener * listener,void * data)973 static void subsurface_handle_parent_destroy(struct wl_listener *listener,
974 void *data) {
975 struct wlr_subsurface *subsurface =
976 wl_container_of(listener, subsurface, parent_destroy);
977 subsurface_unmap(subsurface);
978 wl_list_remove(&subsurface->parent_link);
979 wl_list_remove(&subsurface->parent_pending_link);
980 wl_list_remove(&subsurface->parent_destroy.link);
981 subsurface->parent = NULL;
982 }
983
subsurface_handle_surface_destroy(struct wl_listener * listener,void * data)984 static void subsurface_handle_surface_destroy(struct wl_listener *listener,
985 void *data) {
986 struct wlr_subsurface *subsurface =
987 wl_container_of(listener, subsurface, surface_destroy);
988 subsurface_destroy(subsurface);
989 }
990
wlr_subsurface_create(struct wlr_surface * surface,struct wlr_surface * parent,uint32_t version,uint32_t id,struct wl_list * resource_list)991 struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface,
992 struct wlr_surface *parent, uint32_t version, uint32_t id,
993 struct wl_list *resource_list) {
994 assert(version <= SUBSURFACE_VERSION);
995
996 struct wl_client *client = wl_resource_get_client(surface->resource);
997
998 struct wlr_subsurface *subsurface =
999 calloc(1, sizeof(struct wlr_subsurface));
1000 if (!subsurface) {
1001 wl_client_post_no_memory(client);
1002 return NULL;
1003 }
1004 surface_state_init(&subsurface->cached);
1005 subsurface->synchronized = true;
1006 subsurface->surface = surface;
1007 subsurface->resource =
1008 wl_resource_create(client, &wl_subsurface_interface, version, id);
1009 if (subsurface->resource == NULL) {
1010 surface_state_finish(&subsurface->cached);
1011 free(subsurface);
1012 wl_client_post_no_memory(client);
1013 return NULL;
1014 }
1015 wl_resource_set_implementation(subsurface->resource,
1016 &subsurface_implementation, subsurface,
1017 subsurface_resource_destroy);
1018
1019 wl_signal_init(&subsurface->events.destroy);
1020 wl_signal_init(&subsurface->events.map);
1021 wl_signal_init(&subsurface->events.unmap);
1022
1023 wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy);
1024 subsurface->surface_destroy.notify = subsurface_handle_surface_destroy;
1025
1026 // link parent
1027 subsurface->parent = parent;
1028 wl_signal_add(&parent->events.destroy, &subsurface->parent_destroy);
1029 subsurface->parent_destroy.notify = subsurface_handle_parent_destroy;
1030 wl_list_insert(parent->subsurfaces.prev, &subsurface->parent_link);
1031 wl_list_insert(parent->subsurface_pending_list.prev,
1032 &subsurface->parent_pending_link);
1033
1034 surface->role_data = subsurface;
1035
1036 struct wl_list *resource_link = wl_resource_get_link(subsurface->resource);
1037 if (resource_list != NULL) {
1038 wl_list_insert(resource_list, resource_link);
1039 } else {
1040 wl_list_init(resource_link);
1041 }
1042
1043 wlr_signal_emit_safe(&parent->events.new_subsurface, subsurface);
1044
1045 return subsurface;
1046 }
1047
1048
wlr_surface_get_root_surface(struct wlr_surface * surface)1049 struct wlr_surface *wlr_surface_get_root_surface(struct wlr_surface *surface) {
1050 while (wlr_surface_is_subsurface(surface)) {
1051 struct wlr_subsurface *subsurface =
1052 wlr_subsurface_from_wlr_surface(surface);
1053 if (subsurface == NULL) {
1054 break;
1055 }
1056 surface = subsurface->parent;
1057 }
1058 return surface;
1059 }
1060
wlr_surface_point_accepts_input(struct wlr_surface * surface,double sx,double sy)1061 bool wlr_surface_point_accepts_input(struct wlr_surface *surface,
1062 double sx, double sy) {
1063 return sx >= 0 && sx < surface->current.width &&
1064 sy >= 0 && sy < surface->current.height &&
1065 pixman_region32_contains_point(&surface->current.input, floor(sx), floor(sy), NULL);
1066 }
1067
wlr_surface_surface_at(struct wlr_surface * surface,double sx,double sy,double * sub_x,double * sub_y)1068 struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface,
1069 double sx, double sy, double *sub_x, double *sub_y) {
1070 struct wlr_subsurface *subsurface;
1071 wl_list_for_each_reverse(subsurface, &surface->subsurfaces, parent_link) {
1072 double _sub_x = subsurface->current.x;
1073 double _sub_y = subsurface->current.y;
1074 struct wlr_surface *sub = wlr_surface_surface_at(subsurface->surface,
1075 sx - _sub_x, sy - _sub_y, sub_x, sub_y);
1076 if (sub != NULL) {
1077 return sub;
1078 }
1079 }
1080
1081 if (wlr_surface_point_accepts_input(surface, sx, sy)) {
1082 if (sub_x) {
1083 *sub_x = sx;
1084 }
1085 if (sub_y) {
1086 *sub_y = sy;
1087 }
1088 return surface;
1089 }
1090
1091 return NULL;
1092 }
1093
wlr_surface_send_enter(struct wlr_surface * surface,struct wlr_output * output)1094 void wlr_surface_send_enter(struct wlr_surface *surface,
1095 struct wlr_output *output) {
1096 struct wl_client *client = wl_resource_get_client(surface->resource);
1097 struct wl_resource *resource;
1098 wl_resource_for_each(resource, &output->resources) {
1099 if (client == wl_resource_get_client(resource)) {
1100 wl_surface_send_enter(surface->resource, resource);
1101 }
1102 }
1103 }
1104
wlr_surface_send_leave(struct wlr_surface * surface,struct wlr_output * output)1105 void wlr_surface_send_leave(struct wlr_surface *surface,
1106 struct wlr_output *output) {
1107 struct wl_client *client = wl_resource_get_client(surface->resource);
1108 struct wl_resource *resource;
1109 wl_resource_for_each(resource, &output->resources) {
1110 if (client == wl_resource_get_client(resource)) {
1111 wl_surface_send_leave(surface->resource, resource);
1112 }
1113 }
1114 }
1115
wlr_surface_send_frame_done(struct wlr_surface * surface,const struct timespec * when)1116 void wlr_surface_send_frame_done(struct wlr_surface *surface,
1117 const struct timespec *when) {
1118 struct wl_resource *resource, *tmp;
1119 wl_resource_for_each_safe(resource, tmp,
1120 &surface->current.frame_callback_list) {
1121 wl_callback_send_done(resource, timespec_to_msec(when));
1122 wl_resource_destroy(resource);
1123 }
1124 }
1125
surface_for_each_surface(struct wlr_surface * surface,int x,int y,wlr_surface_iterator_func_t iterator,void * user_data)1126 static void surface_for_each_surface(struct wlr_surface *surface, int x, int y,
1127 wlr_surface_iterator_func_t iterator, void *user_data) {
1128 iterator(surface, x, y, user_data);
1129
1130 struct wlr_subsurface *subsurface;
1131 wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) {
1132 struct wlr_subsurface_state *state = &subsurface->current;
1133 int sx = state->x;
1134 int sy = state->y;
1135
1136 surface_for_each_surface(subsurface->surface, x + sx, y + sy,
1137 iterator, user_data);
1138 }
1139 }
1140
wlr_surface_for_each_surface(struct wlr_surface * surface,wlr_surface_iterator_func_t iterator,void * user_data)1141 void wlr_surface_for_each_surface(struct wlr_surface *surface,
1142 wlr_surface_iterator_func_t iterator, void *user_data) {
1143 surface_for_each_surface(surface, 0, 0, iterator, user_data);
1144 }
1145
1146 struct bound_acc {
1147 int32_t min_x, min_y;
1148 int32_t max_x, max_y;
1149 };
1150
handle_bounding_box_surface(struct wlr_surface * surface,int x,int y,void * data)1151 static void handle_bounding_box_surface(struct wlr_surface *surface,
1152 int x, int y, void *data) {
1153 struct bound_acc *acc = data;
1154
1155 acc->min_x = min(x, acc->min_x);
1156 acc->min_y = min(y, acc->min_y);
1157
1158 acc->max_x = max(x + surface->current.width, acc->max_x);
1159 acc->max_y = max(y + surface->current.height, acc->max_y);
1160 }
1161
wlr_surface_get_extends(struct wlr_surface * surface,struct wlr_box * box)1162 void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box) {
1163 struct bound_acc acc = {
1164 .min_x = 0,
1165 .min_y = 0,
1166 .max_x = surface->current.width,
1167 .max_y = surface->current.height,
1168 };
1169
1170 wlr_surface_for_each_surface(surface, handle_bounding_box_surface, &acc);
1171
1172 box->x = acc.min_x;
1173 box->y = acc.min_y;
1174 box->width = acc.max_x - acc.min_x;
1175 box->height = acc.max_y - acc.min_y;
1176 }
1177
crop_region(pixman_region32_t * dst,pixman_region32_t * src,const struct wlr_box * box)1178 static void crop_region(pixman_region32_t *dst, pixman_region32_t *src,
1179 const struct wlr_box *box) {
1180 pixman_region32_intersect_rect(dst, src,
1181 box->x, box->y, box->width, box->height);
1182 pixman_region32_translate(dst, -box->x, -box->y);
1183 }
1184
wlr_surface_get_effective_damage(struct wlr_surface * surface,pixman_region32_t * damage)1185 void wlr_surface_get_effective_damage(struct wlr_surface *surface,
1186 pixman_region32_t *damage) {
1187 pixman_region32_clear(damage);
1188
1189 // Transform and copy the buffer damage in terms of surface coordinates.
1190 wlr_region_transform(damage, &surface->buffer_damage,
1191 surface->current.transform, surface->current.buffer_width,
1192 surface->current.buffer_height);
1193 wlr_region_scale(damage, damage, 1.0 / (float)surface->current.scale);
1194
1195 if (surface->current.viewport.has_src) {
1196 struct wlr_box src_box = {
1197 .x = floor(surface->current.viewport.src.x),
1198 .y = floor(surface->current.viewport.src.y),
1199 .width = ceil(surface->current.viewport.src.width),
1200 .height = ceil(surface->current.viewport.src.height),
1201 };
1202 crop_region(damage, damage, &src_box);
1203 }
1204 if (surface->current.viewport.has_dst) {
1205 int src_width, src_height;
1206 surface_state_viewport_src_size(&surface->current,
1207 &src_width, &src_height);
1208 float scale_x = (float)surface->current.viewport.dst_width / src_width;
1209 float scale_y = (float)surface->current.viewport.dst_height / src_height;
1210 wlr_region_scale_xy(damage, damage, scale_x, scale_y);
1211 }
1212
1213 // On resize, damage the previous bounds of the surface. The current bounds
1214 // have already been damaged in surface_update_damage.
1215 if (surface->previous.width > surface->current.width ||
1216 surface->previous.height > surface->current.height) {
1217 pixman_region32_union_rect(damage, damage, 0, 0,
1218 surface->previous.width, surface->previous.height);
1219 }
1220
1221 // On move, damage where the surface was with its old dimensions.
1222 if (surface->current.dx != 0 || surface->current.dy != 0) {
1223 int prev_x = -surface->current.dx;
1224 int prev_y = -surface->current.dy;
1225 if ((surface->previous.transform & WL_OUTPUT_TRANSFORM_90) != 0) {
1226 int temp = prev_x;
1227 prev_x = prev_y;
1228 prev_y = temp;
1229 }
1230 pixman_region32_union_rect(damage, damage, prev_x, prev_y,
1231 surface->previous.width, surface->previous.height);
1232 }
1233 }
1234
wlr_surface_get_buffer_source_box(struct wlr_surface * surface,struct wlr_fbox * box)1235 void wlr_surface_get_buffer_source_box(struct wlr_surface *surface,
1236 struct wlr_fbox *box) {
1237 box->x = box->y = 0;
1238 box->width = surface->current.buffer_width;
1239 box->height = surface->current.buffer_height;
1240
1241 if (surface->current.viewport.has_src) {
1242 box->x = surface->current.viewport.src.x * surface->current.scale;
1243 box->y = surface->current.viewport.src.y * surface->current.scale;
1244 box->width = surface->current.viewport.src.width * surface->current.scale;
1245 box->height = surface->current.viewport.src.height * surface->current.scale;
1246 if ((surface->current.transform & WL_OUTPUT_TRANSFORM_90) != 0) {
1247 double tmp = box->x;
1248 box->x = box->y;
1249 box->y = tmp;
1250
1251 tmp = box->width;
1252 box->width = box->height;
1253 box->height = tmp;
1254 }
1255 }
1256 }
1257