1 #define _POSIX_C_SOURCE 200809L
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <tgmath.h>
6 #include <time.h>
7 #include <wayland-server-core.h>
8 #include <wlr/interfaces/wlr_output.h>
9 #include <wlr/render/interface.h>
10 #include <wlr/render/wlr_renderer.h>
11 #include <wlr/types/wlr_box.h>
12 #include <wlr/types/wlr_matrix.h>
13 #include <wlr/types/wlr_output.h>
14 #include <wlr/types/wlr_seat.h>
15 #include <wlr/types/wlr_surface.h>
16 #include <wlr/util/log.h>
17 #include <wlr/util/region.h>
18 #include "util/global.h"
19 #include "util/signal.h"
20 
21 #define OUTPUT_VERSION 3
22 
send_geometry(struct wl_resource * resource)23 static void send_geometry(struct wl_resource *resource) {
24 	struct wlr_output *output = wlr_output_from_resource(resource);
25 	wl_output_send_geometry(resource, 0, 0,
26 		output->phys_width, output->phys_height, output->subpixel,
27 		output->make, output->model, output->transform);
28 }
29 
send_current_mode(struct wl_resource * resource)30 static void send_current_mode(struct wl_resource *resource) {
31 	struct wlr_output *output = wlr_output_from_resource(resource);
32 	if (output->current_mode != NULL) {
33 		struct wlr_output_mode *mode = output->current_mode;
34 		wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT,
35 			mode->width, mode->height, mode->refresh);
36 	} else {
37 		// Output has no mode
38 		wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT, output->width,
39 			output->height, output->refresh);
40 	}
41 }
42 
send_scale(struct wl_resource * resource)43 static void send_scale(struct wl_resource *resource) {
44 	struct wlr_output *output = wlr_output_from_resource(resource);
45 	uint32_t version = wl_resource_get_version(resource);
46 	if (version >= WL_OUTPUT_SCALE_SINCE_VERSION) {
47 		wl_output_send_scale(resource, (uint32_t)ceil(output->scale));
48 	}
49 }
50 
send_done(struct wl_resource * resource)51 static void send_done(struct wl_resource *resource) {
52 	uint32_t version = wl_resource_get_version(resource);
53 	if (version >= WL_OUTPUT_DONE_SINCE_VERSION) {
54 		wl_output_send_done(resource);
55 	}
56 }
57 
output_handle_resource_destroy(struct wl_resource * resource)58 static void output_handle_resource_destroy(struct wl_resource *resource) {
59 	wl_list_remove(wl_resource_get_link(resource));
60 }
61 
output_handle_release(struct wl_client * client,struct wl_resource * resource)62 static void output_handle_release(struct wl_client *client,
63 		struct wl_resource *resource) {
64 	wl_resource_destroy(resource);
65 }
66 
67 static const struct wl_output_interface output_impl = {
68 	.release = output_handle_release,
69 };
70 
output_bind(struct wl_client * wl_client,void * data,uint32_t version,uint32_t id)71 static void output_bind(struct wl_client *wl_client, void *data,
72 		uint32_t version, uint32_t id) {
73 	// `output` can be NULL if the output global is being destroyed
74 	struct wlr_output *output = data;
75 
76 	struct wl_resource *resource = wl_resource_create(wl_client,
77 		&wl_output_interface, version, id);
78 	if (resource == NULL) {
79 		wl_client_post_no_memory(wl_client);
80 		return;
81 	}
82 	wl_resource_set_implementation(resource, &output_impl, output,
83 		output_handle_resource_destroy);
84 
85 	if (output == NULL) {
86 		wl_list_init(wl_resource_get_link(resource));
87 		return;
88 	}
89 
90 	wl_list_insert(&output->resources, wl_resource_get_link(resource));
91 
92 	send_geometry(resource);
93 	send_current_mode(resource);
94 	send_scale(resource);
95 	send_done(resource);
96 }
97 
wlr_output_create_global(struct wlr_output * output)98 void wlr_output_create_global(struct wlr_output *output) {
99 	if (output->global != NULL) {
100 		return;
101 	}
102 	output->global = wl_global_create(output->display,
103 		&wl_output_interface, OUTPUT_VERSION, output, output_bind);
104 	if (output->global == NULL) {
105 		wlr_log(WLR_ERROR, "Failed to allocate wl_output global");
106 	}
107 }
108 
wlr_output_destroy_global(struct wlr_output * output)109 void wlr_output_destroy_global(struct wlr_output *output) {
110 	if (output->global == NULL) {
111 		return;
112 	}
113 
114 	// Make all output resources inert
115 	struct wl_resource *resource, *tmp;
116 	wl_resource_for_each_safe(resource, tmp, &output->resources) {
117 		wl_resource_set_user_data(resource, NULL);
118 		wl_list_remove(wl_resource_get_link(resource));
119 		wl_list_init(wl_resource_get_link(resource));
120 	}
121 
122 	wlr_global_destroy_safe(output->global, output->display);
123 	output->global = NULL;
124 }
125 
wlr_output_update_enabled(struct wlr_output * output,bool enabled)126 void wlr_output_update_enabled(struct wlr_output *output, bool enabled) {
127 	if (output->enabled == enabled) {
128 		return;
129 	}
130 
131 	output->enabled = enabled;
132 	wlr_signal_emit_safe(&output->events.enable, output);
133 }
134 
output_update_matrix(struct wlr_output * output)135 static void output_update_matrix(struct wlr_output *output) {
136 	wlr_matrix_projection(output->transform_matrix, output->width,
137 		output->height, output->transform);
138 }
139 
wlr_output_enable(struct wlr_output * output,bool enable)140 void wlr_output_enable(struct wlr_output *output, bool enable) {
141 	if (output->enabled == enable) {
142 		output->pending.committed &= ~WLR_OUTPUT_STATE_ENABLED;
143 		return;
144 	}
145 
146 	output->pending.committed |= WLR_OUTPUT_STATE_ENABLED;
147 	output->pending.enabled = enable;
148 }
149 
output_state_clear_mode(struct wlr_output_state * state)150 static void output_state_clear_mode(struct wlr_output_state *state) {
151 	if (!(state->committed & WLR_OUTPUT_STATE_MODE)) {
152 		return;
153 	}
154 
155 	state->mode = NULL;
156 
157 	state->committed &= ~WLR_OUTPUT_STATE_MODE;
158 }
159 
wlr_output_set_mode(struct wlr_output * output,struct wlr_output_mode * mode)160 void wlr_output_set_mode(struct wlr_output *output,
161 		struct wlr_output_mode *mode) {
162 	output_state_clear_mode(&output->pending);
163 
164 	if (output->current_mode == mode) {
165 		return;
166 	}
167 
168 	output->pending.committed |= WLR_OUTPUT_STATE_MODE;
169 	output->pending.mode_type = WLR_OUTPUT_STATE_MODE_FIXED;
170 	output->pending.mode = mode;
171 }
172 
wlr_output_set_custom_mode(struct wlr_output * output,int32_t width,int32_t height,int32_t refresh)173 void wlr_output_set_custom_mode(struct wlr_output *output, int32_t width,
174 		int32_t height, int32_t refresh) {
175 	output_state_clear_mode(&output->pending);
176 
177 	if (output->width == width && output->height == height &&
178 			output->refresh == refresh) {
179 		return;
180 	}
181 
182 	output->pending.committed |= WLR_OUTPUT_STATE_MODE;
183 	output->pending.mode_type = WLR_OUTPUT_STATE_MODE_CUSTOM;
184 	output->pending.custom_mode.width = width;
185 	output->pending.custom_mode.height = height;
186 	output->pending.custom_mode.refresh = refresh;
187 }
188 
wlr_output_update_mode(struct wlr_output * output,struct wlr_output_mode * mode)189 void wlr_output_update_mode(struct wlr_output *output,
190 		struct wlr_output_mode *mode) {
191 	output->current_mode = mode;
192 	if (mode != NULL) {
193 		wlr_output_update_custom_mode(output, mode->width, mode->height,
194 			mode->refresh);
195 	} else {
196 		wlr_output_update_custom_mode(output, 0, 0, 0);
197 	}
198 }
199 
wlr_output_update_custom_mode(struct wlr_output * output,int32_t width,int32_t height,int32_t refresh)200 void wlr_output_update_custom_mode(struct wlr_output *output, int32_t width,
201 		int32_t height, int32_t refresh) {
202 	if (output->width == width && output->height == height &&
203 			output->refresh == refresh) {
204 		return;
205 	}
206 
207 	output->width = width;
208 	output->height = height;
209 	output_update_matrix(output);
210 
211 	output->refresh = refresh;
212 
213 	struct wl_resource *resource;
214 	wl_resource_for_each(resource, &output->resources) {
215 		send_current_mode(resource);
216 	}
217 	wlr_output_schedule_done(output);
218 
219 	wlr_signal_emit_safe(&output->events.mode, output);
220 }
221 
wlr_output_set_transform(struct wlr_output * output,enum wl_output_transform transform)222 void wlr_output_set_transform(struct wlr_output *output,
223 		enum wl_output_transform transform) {
224 	if (output->transform == transform) {
225 		output->pending.committed &= ~WLR_OUTPUT_STATE_TRANSFORM;
226 		return;
227 	}
228 
229 	output->pending.committed |= WLR_OUTPUT_STATE_TRANSFORM;
230 	output->pending.transform = transform;
231 }
232 
wlr_output_set_scale(struct wlr_output * output,float scale)233 void wlr_output_set_scale(struct wlr_output *output, float scale) {
234 	if (output->scale == scale) {
235 		output->pending.committed &= ~WLR_OUTPUT_STATE_SCALE;
236 		return;
237 	}
238 
239 	output->pending.committed |= WLR_OUTPUT_STATE_SCALE;
240 	output->pending.scale = scale;
241 }
242 
wlr_output_enable_adaptive_sync(struct wlr_output * output,bool enabled)243 void wlr_output_enable_adaptive_sync(struct wlr_output *output, bool enabled) {
244 	bool currently_enabled =
245 		output->adaptive_sync_status != WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
246 	if (currently_enabled == enabled) {
247 		output->pending.committed &= ~WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
248 		return;
249 	}
250 
251 	output->pending.committed |= WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
252 	output->pending.adaptive_sync_enabled = enabled;
253 }
254 
wlr_output_set_subpixel(struct wlr_output * output,enum wl_output_subpixel subpixel)255 void wlr_output_set_subpixel(struct wlr_output *output,
256 		enum wl_output_subpixel subpixel) {
257 	if (output->subpixel == subpixel) {
258 		return;
259 	}
260 
261 	output->subpixel = subpixel;
262 
263 	struct wl_resource *resource;
264 	wl_resource_for_each(resource, &output->resources) {
265 		send_geometry(resource);
266 	}
267 	wlr_output_schedule_done(output);
268 }
269 
wlr_output_set_description(struct wlr_output * output,const char * desc)270 void wlr_output_set_description(struct wlr_output *output, const char *desc) {
271 	if (output->description != NULL && desc != NULL &&
272 			strcmp(output->description, desc) == 0) {
273 		return;
274 	}
275 
276 	free(output->description);
277 	if (desc != NULL) {
278 		output->description = strdup(desc);
279 	} else {
280 		output->description = NULL;
281 	}
282 
283 	wlr_signal_emit_safe(&output->events.description, output);
284 }
285 
schedule_done_handle_idle_timer(void * data)286 static void schedule_done_handle_idle_timer(void *data) {
287 	struct wlr_output *output = data;
288 	output->idle_done = NULL;
289 
290 	struct wl_resource *resource;
291 	wl_resource_for_each(resource, &output->resources) {
292 		uint32_t version = wl_resource_get_version(resource);
293 		if (version >= WL_OUTPUT_DONE_SINCE_VERSION) {
294 			wl_output_send_done(resource);
295 		}
296 	}
297 }
298 
wlr_output_schedule_done(struct wlr_output * output)299 void wlr_output_schedule_done(struct wlr_output *output) {
300 	if (output->idle_done != NULL) {
301 		return; // Already scheduled
302 	}
303 
304 	struct wl_event_loop *ev = wl_display_get_event_loop(output->display);
305 	output->idle_done =
306 		wl_event_loop_add_idle(ev, schedule_done_handle_idle_timer, output);
307 }
308 
handle_display_destroy(struct wl_listener * listener,void * data)309 static void handle_display_destroy(struct wl_listener *listener, void *data) {
310 	struct wlr_output *output =
311 		wl_container_of(listener, output, display_destroy);
312 	wlr_output_destroy_global(output);
313 }
314 
wlr_output_init(struct wlr_output * output,struct wlr_backend * backend,const struct wlr_output_impl * impl,struct wl_display * display)315 void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend,
316 		const struct wlr_output_impl *impl, struct wl_display *display) {
317 	assert(impl->attach_render && impl->rollback_render && impl->commit);
318 	if (impl->set_cursor || impl->move_cursor) {
319 		assert(impl->set_cursor && impl->move_cursor);
320 	}
321 	output->backend = backend;
322 	output->impl = impl;
323 	output->display = display;
324 	wl_list_init(&output->modes);
325 	output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
326 	output->scale = 1;
327 	output->commit_seq = 0;
328 	wl_list_init(&output->cursors);
329 	wl_list_init(&output->resources);
330 	wl_signal_init(&output->events.frame);
331 	wl_signal_init(&output->events.damage);
332 	wl_signal_init(&output->events.needs_frame);
333 	wl_signal_init(&output->events.precommit);
334 	wl_signal_init(&output->events.commit);
335 	wl_signal_init(&output->events.present);
336 	wl_signal_init(&output->events.enable);
337 	wl_signal_init(&output->events.mode);
338 	wl_signal_init(&output->events.scale);
339 	wl_signal_init(&output->events.transform);
340 	wl_signal_init(&output->events.description);
341 	wl_signal_init(&output->events.destroy);
342 	pixman_region32_init(&output->pending.damage);
343 
344 	const char *no_hardware_cursors = getenv("WLR_NO_HARDWARE_CURSORS");
345 	if (no_hardware_cursors != NULL && strcmp(no_hardware_cursors, "1") == 0) {
346 		wlr_log(WLR_DEBUG,
347 			"WLR_NO_HARDWARE_CURSORS set, forcing software cursors");
348 		output->software_cursor_locks = 1;
349 	}
350 
351 	output->display_destroy.notify = handle_display_destroy;
352 	wl_display_add_destroy_listener(display, &output->display_destroy);
353 
354 	output->frame_pending = true;
355 }
356 
wlr_output_destroy(struct wlr_output * output)357 void wlr_output_destroy(struct wlr_output *output) {
358 	if (!output) {
359 		return;
360 	}
361 
362 	wl_list_remove(&output->display_destroy.link);
363 	wlr_output_destroy_global(output);
364 
365 	wlr_signal_emit_safe(&output->events.destroy, output);
366 
367 	// The backend is responsible for free-ing the list of modes
368 
369 	struct wlr_output_cursor *cursor, *tmp_cursor;
370 	wl_list_for_each_safe(cursor, tmp_cursor, &output->cursors, link) {
371 		wlr_output_cursor_destroy(cursor);
372 	}
373 
374 	if (output->idle_frame != NULL) {
375 		wl_event_source_remove(output->idle_frame);
376 	}
377 
378 	if (output->idle_done != NULL) {
379 		wl_event_source_remove(output->idle_done);
380 	}
381 
382 	free(output->description);
383 
384 	pixman_region32_fini(&output->pending.damage);
385 
386 	if (output->impl && output->impl->destroy) {
387 		output->impl->destroy(output);
388 	} else {
389 		free(output);
390 	}
391 }
392 
wlr_output_transformed_resolution(struct wlr_output * output,int * width,int * height)393 void wlr_output_transformed_resolution(struct wlr_output *output,
394 		int *width, int *height) {
395 	if (output->transform % 2 == 0) {
396 		*width = output->width;
397 		*height = output->height;
398 	} else {
399 		*width = output->height;
400 		*height = output->width;
401 	}
402 }
403 
wlr_output_effective_resolution(struct wlr_output * output,int * width,int * height)404 void wlr_output_effective_resolution(struct wlr_output *output,
405 		int *width, int *height) {
406 	wlr_output_transformed_resolution(output, width, height);
407 	*width /= output->scale;
408 	*height /= output->scale;
409 }
410 
wlr_output_preferred_mode(struct wlr_output * output)411 struct wlr_output_mode *wlr_output_preferred_mode(struct wlr_output *output) {
412 	if (wl_list_empty(&output->modes)) {
413 		return NULL;
414 	}
415 
416 	struct wlr_output_mode *mode;
417 	wl_list_for_each(mode, &output->modes, link) {
418 		if (mode->preferred) {
419 			return mode;
420 		}
421 	}
422 
423 	// No preferred mode, choose the last one
424 	return wl_container_of(output->modes.prev, mode, link);
425 }
426 
output_state_clear_buffer(struct wlr_output_state * state)427 static void output_state_clear_buffer(struct wlr_output_state *state) {
428 	if (!(state->committed & WLR_OUTPUT_STATE_BUFFER)) {
429 		return;
430 	}
431 
432 	wlr_buffer_unlock(state->buffer);
433 	state->buffer = NULL;
434 
435 	state->committed &= ~WLR_OUTPUT_STATE_BUFFER;
436 }
437 
wlr_output_attach_render(struct wlr_output * output,int * buffer_age)438 bool wlr_output_attach_render(struct wlr_output *output, int *buffer_age) {
439 	if (!output->impl->attach_render(output, buffer_age)) {
440 		return false;
441 	}
442 
443 	output_state_clear_buffer(&output->pending);
444 	output->pending.committed |= WLR_OUTPUT_STATE_BUFFER;
445 	output->pending.buffer_type = WLR_OUTPUT_STATE_BUFFER_RENDER;
446 	return true;
447 }
448 
wlr_output_preferred_read_format(struct wlr_output * output,enum wl_shm_format * fmt)449 bool wlr_output_preferred_read_format(struct wlr_output *output,
450 		enum wl_shm_format *fmt) {
451 	struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
452 	if (!renderer->impl->preferred_read_format || !renderer->impl->read_pixels) {
453 		return false;
454 	}
455 
456 	if (!output->impl->attach_render(output, NULL)) {
457 		return false;
458 	}
459 	*fmt = renderer->impl->preferred_read_format(renderer);
460 	output->impl->rollback_render(output);
461 	return true;
462 }
463 
wlr_output_set_damage(struct wlr_output * output,pixman_region32_t * damage)464 void wlr_output_set_damage(struct wlr_output *output,
465 		pixman_region32_t *damage) {
466 	pixman_region32_intersect_rect(&output->pending.damage, damage,
467 		0, 0, output->width, output->height);
468 	output->pending.committed |= WLR_OUTPUT_STATE_DAMAGE;
469 }
470 
output_state_clear_gamma_lut(struct wlr_output_state * state)471 static void output_state_clear_gamma_lut(struct wlr_output_state *state) {
472 	free(state->gamma_lut);
473 	state->gamma_lut = NULL;
474 	state->committed &= ~WLR_OUTPUT_STATE_GAMMA_LUT;
475 }
476 
output_state_clear(struct wlr_output_state * state)477 static void output_state_clear(struct wlr_output_state *state) {
478 	output_state_clear_buffer(state);
479 	output_state_clear_gamma_lut(state);
480 	pixman_region32_clear(&state->damage);
481 	state->committed = 0;
482 }
483 
output_pending_resolution(struct wlr_output * output,int * width,int * height)484 static void output_pending_resolution(struct wlr_output *output, int *width,
485 		int *height) {
486 	if (output->pending.committed & WLR_OUTPUT_STATE_MODE) {
487 		switch (output->pending.mode_type) {
488 		case WLR_OUTPUT_STATE_MODE_FIXED:
489 			*width = output->pending.mode->width;
490 			*height = output->pending.mode->height;
491 			return;
492 		case WLR_OUTPUT_STATE_MODE_CUSTOM:
493 			*width = output->pending.custom_mode.width;
494 			*height = output->pending.custom_mode.height;
495 			return;
496 		}
497 		abort();
498 	} else {
499 		*width = output->width;
500 		*height = output->height;
501 	}
502 }
503 
output_basic_test(struct wlr_output * output)504 static bool output_basic_test(struct wlr_output *output) {
505 	if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
506 		if (output->frame_pending) {
507 			wlr_log(WLR_DEBUG, "Tried to commit a buffer while a frame is pending");
508 			return false;
509 		}
510 
511 		if (output->pending.buffer_type == WLR_OUTPUT_STATE_BUFFER_SCANOUT) {
512 			if (output->attach_render_locks > 0) {
513 				return false;
514 			}
515 
516 			// If the output has at least one software cursor, refuse to attach the
517 			// buffer
518 			struct wlr_output_cursor *cursor;
519 			wl_list_for_each(cursor, &output->cursors, link) {
520 				if (cursor->enabled && cursor->visible &&
521 						cursor != output->hardware_cursor) {
522 					return false;
523 				}
524 			}
525 
526 			// If the size doesn't match, reject buffer (scaling is not
527 			// supported)
528 			int pending_width, pending_height;
529 			output_pending_resolution(output, &pending_width, &pending_height);
530 			if (output->pending.buffer->width != pending_width ||
531 					output->pending.buffer->height != pending_height) {
532 				return false;
533 			}
534 		}
535 	}
536 
537 	bool enabled = output->enabled;
538 	if (output->pending.committed & WLR_OUTPUT_STATE_ENABLED) {
539 		enabled = output->pending.enabled;
540 	}
541 
542 	if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
543 		wlr_log(WLR_DEBUG, "Tried to commit a buffer on a disabled output");
544 		return false;
545 	}
546 	if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_MODE) {
547 		wlr_log(WLR_DEBUG, "Tried to modeset a disabled output");
548 		return false;
549 	}
550 	if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) {
551 		wlr_log(WLR_DEBUG, "Tried to enable adaptive sync on a disabled output");
552 		return false;
553 	}
554 	if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
555 		wlr_log(WLR_DEBUG, "Tried to set the gamma lut on a disabled output");
556 		return false;
557 	}
558 
559 	return true;
560 }
561 
wlr_output_test(struct wlr_output * output)562 bool wlr_output_test(struct wlr_output *output) {
563 	if (!output_basic_test(output)) {
564 		return false;
565 	}
566 	return output->impl->test(output);
567 }
568 
wlr_output_commit(struct wlr_output * output)569 bool wlr_output_commit(struct wlr_output *output) {
570 	if (!output_basic_test(output)) {
571 		wlr_log(WLR_ERROR, "Basic output test failed");
572 		return false;
573 	}
574 
575 	if ((output->pending.committed & WLR_OUTPUT_STATE_BUFFER) &&
576 			output->idle_frame != NULL) {
577 		wl_event_source_remove(output->idle_frame);
578 		output->idle_frame = NULL;
579 	}
580 
581 	struct timespec now;
582 	clock_gettime(CLOCK_MONOTONIC, &now);
583 
584 	struct wlr_output_event_precommit pre_event = {
585 		.output = output,
586 		.when = &now,
587 	};
588 	wlr_signal_emit_safe(&output->events.precommit, &pre_event);
589 
590 	if (!output->impl->commit(output)) {
591 		output_state_clear(&output->pending);
592 		return false;
593 	}
594 
595 	if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
596 		struct wlr_output_cursor *cursor;
597 		wl_list_for_each(cursor, &output->cursors, link) {
598 			if (!cursor->enabled || !cursor->visible || cursor->surface == NULL) {
599 				continue;
600 			}
601 			wlr_surface_send_frame_done(cursor->surface, &now);
602 		}
603 	}
604 
605 	output->commit_seq++;
606 
607 	struct wlr_output_event_commit event = {
608 		.output = output,
609 		.committed = output->pending.committed,
610 		.when = &now,
611 	};
612 	wlr_signal_emit_safe(&output->events.commit, &event);
613 
614 	bool scale_updated = output->pending.committed & WLR_OUTPUT_STATE_SCALE;
615 	if (scale_updated) {
616 		output->scale = output->pending.scale;
617 		wlr_signal_emit_safe(&output->events.scale, output);
618 	}
619 
620 	if (output->pending.committed & WLR_OUTPUT_STATE_TRANSFORM) {
621 		output->transform = output->pending.transform;
622 		output_update_matrix(output);
623 		wlr_signal_emit_safe(&output->events.transform, output);
624 	}
625 
626 	bool geometry_updated = output->pending.committed &
627 		(WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM);
628 	if (geometry_updated || scale_updated) {
629 		struct wl_resource *resource;
630 		wl_resource_for_each(resource, &output->resources) {
631 			if (geometry_updated) {
632 				send_geometry(resource);
633 			}
634 			if (scale_updated) {
635 				send_scale(resource);
636 			}
637 		}
638 		wlr_output_schedule_done(output);
639 	}
640 
641 	if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
642 		output->frame_pending = true;
643 		output->needs_frame = false;
644 	}
645 
646 	output_state_clear(&output->pending);
647 	return true;
648 }
649 
wlr_output_rollback(struct wlr_output * output)650 void wlr_output_rollback(struct wlr_output *output) {
651 	if (output->impl->rollback_render &&
652 			(output->pending.committed & WLR_OUTPUT_STATE_BUFFER) &&
653 			output->pending.buffer_type == WLR_OUTPUT_STATE_BUFFER_RENDER) {
654 		output->impl->rollback_render(output);
655 	}
656 
657 	output_state_clear(&output->pending);
658 }
659 
wlr_output_attach_buffer(struct wlr_output * output,struct wlr_buffer * buffer)660 void wlr_output_attach_buffer(struct wlr_output *output,
661 		struct wlr_buffer *buffer) {
662 	output_state_clear_buffer(&output->pending);
663 	output->pending.committed |= WLR_OUTPUT_STATE_BUFFER;
664 	output->pending.buffer_type = WLR_OUTPUT_STATE_BUFFER_SCANOUT;
665 	output->pending.buffer = wlr_buffer_lock(buffer);
666 }
667 
wlr_output_send_frame(struct wlr_output * output)668 void wlr_output_send_frame(struct wlr_output *output) {
669 	output->frame_pending = false;
670 	wlr_signal_emit_safe(&output->events.frame, output);
671 }
672 
schedule_frame_handle_idle_timer(void * data)673 static void schedule_frame_handle_idle_timer(void *data) {
674 	struct wlr_output *output = data;
675 	output->idle_frame = NULL;
676 	if (!output->frame_pending) {
677 		wlr_output_send_frame(output);
678 	}
679 }
680 
wlr_output_schedule_frame(struct wlr_output * output)681 void wlr_output_schedule_frame(struct wlr_output *output) {
682 	// Make sure the compositor commits a new frame. This is necessary to make
683 	// clients which ask for frame callbacks without submitting a new buffer
684 	// work.
685 	wlr_output_update_needs_frame(output);
686 
687 	if (output->frame_pending || output->idle_frame != NULL) {
688 		return;
689 	}
690 
691 	// We're using an idle timer here in case a buffer swap happens right after
692 	// this function is called
693 	struct wl_event_loop *ev = wl_display_get_event_loop(output->display);
694 	output->idle_frame =
695 		wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output);
696 }
697 
wlr_output_send_present(struct wlr_output * output,struct wlr_output_event_present * event)698 void wlr_output_send_present(struct wlr_output *output,
699 		struct wlr_output_event_present *event) {
700 	struct wlr_output_event_present _event = {0};
701 	if (event == NULL) {
702 		event = &_event;
703 		event->commit_seq = output->commit_seq + 1;
704 	}
705 
706 	event->output = output;
707 
708 	struct timespec now;
709 	if (event->when == NULL) {
710 		clockid_t clock = wlr_backend_get_presentation_clock(output->backend);
711 		errno = 0;
712 		if (clock_gettime(clock, &now) != 0) {
713 			wlr_log_errno(WLR_ERROR, "failed to send output present event: "
714 				"failed to read clock");
715 			return;
716 		}
717 		event->when = &now;
718 	}
719 
720 	wlr_signal_emit_safe(&output->events.present, event);
721 }
722 
wlr_output_set_gamma(struct wlr_output * output,size_t size,const uint16_t * r,const uint16_t * g,const uint16_t * b)723 void wlr_output_set_gamma(struct wlr_output *output, size_t size,
724 		const uint16_t *r, const uint16_t *g, const uint16_t *b) {
725 	output_state_clear_gamma_lut(&output->pending);
726 
727 	output->pending.gamma_lut_size = size;
728 	output->pending.gamma_lut = malloc(3 * size * sizeof(uint16_t));
729 	if (output->pending.gamma_lut == NULL) {
730 		wlr_log_errno(WLR_ERROR, "Allocation failed");
731 		return;
732 	}
733 	memcpy(output->pending.gamma_lut, r, size * sizeof(uint16_t));
734 	memcpy(output->pending.gamma_lut + size, g, size * sizeof(uint16_t));
735 	memcpy(output->pending.gamma_lut + 2 * size, b, size * sizeof(uint16_t));
736 
737 	output->pending.committed |= WLR_OUTPUT_STATE_GAMMA_LUT;
738 }
739 
wlr_output_get_gamma_size(struct wlr_output * output)740 size_t wlr_output_get_gamma_size(struct wlr_output *output) {
741 	if (!output->impl->get_gamma_size) {
742 		return 0;
743 	}
744 	return output->impl->get_gamma_size(output);
745 }
746 
wlr_output_export_dmabuf(struct wlr_output * output,struct wlr_dmabuf_attributes * attribs)747 bool wlr_output_export_dmabuf(struct wlr_output *output,
748 		struct wlr_dmabuf_attributes *attribs) {
749 	if (!output->impl->export_dmabuf) {
750 		return false;
751 	}
752 	return output->impl->export_dmabuf(output, attribs);
753 }
754 
wlr_output_update_needs_frame(struct wlr_output * output)755 void wlr_output_update_needs_frame(struct wlr_output *output) {
756 	if (output->needs_frame) {
757 		return;
758 	}
759 	output->needs_frame = true;
760 	wlr_signal_emit_safe(&output->events.needs_frame, output);
761 }
762 
wlr_output_damage_whole(struct wlr_output * output)763 void wlr_output_damage_whole(struct wlr_output *output) {
764 	int width, height;
765 	wlr_output_transformed_resolution(output, &width, &height);
766 
767 	pixman_region32_t damage;
768 	pixman_region32_init_rect(&damage, 0, 0, width, height);
769 
770 	struct wlr_output_event_damage event = {
771 		.output = output,
772 		.damage = &damage,
773 	};
774 	wlr_signal_emit_safe(&output->events.damage, &event);
775 
776 	pixman_region32_fini(&damage);
777 }
778 
wlr_output_from_resource(struct wl_resource * resource)779 struct wlr_output *wlr_output_from_resource(struct wl_resource *resource) {
780 	assert(wl_resource_instance_of(resource, &wl_output_interface,
781 		&output_impl));
782 	return wl_resource_get_user_data(resource);
783 }
784 
wlr_output_lock_attach_render(struct wlr_output * output,bool lock)785 void wlr_output_lock_attach_render(struct wlr_output *output, bool lock) {
786 	if (lock) {
787 		++output->attach_render_locks;
788 	} else {
789 		assert(output->attach_render_locks > 0);
790 		--output->attach_render_locks;
791 	}
792 	wlr_log(WLR_DEBUG, "%s direct scan-out on output '%s' (locks: %d)",
793 		lock ? "Disabling" : "Enabling", output->name,
794 		output->attach_render_locks);
795 }
796 
797 static void output_cursor_damage_whole(struct wlr_output_cursor *cursor);
798 
wlr_output_lock_software_cursors(struct wlr_output * output,bool lock)799 void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock) {
800 	if (lock) {
801 		++output->software_cursor_locks;
802 	} else {
803 		assert(output->software_cursor_locks > 0);
804 		--output->software_cursor_locks;
805 	}
806 	wlr_log(WLR_DEBUG, "%s hardware cursors on output '%s' (locks: %d)",
807 		lock ? "Disabling" : "Enabling", output->name,
808 		output->software_cursor_locks);
809 
810 	if (output->software_cursor_locks > 0 && output->hardware_cursor != NULL) {
811 		assert(output->impl->set_cursor);
812 		output->impl->set_cursor(output, NULL, 1,
813 			WL_OUTPUT_TRANSFORM_NORMAL, 0, 0, true);
814 		output_cursor_damage_whole(output->hardware_cursor);
815 		output->hardware_cursor = NULL;
816 	}
817 
818 	// If it's possible to use hardware cursors again, don't switch immediately
819 	// since a recorder is likely to lock software cursors for the next frame
820 	// again.
821 }
822 
output_scissor(struct wlr_output * output,pixman_box32_t * rect)823 static void output_scissor(struct wlr_output *output, pixman_box32_t *rect) {
824 	struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
825 	assert(renderer);
826 
827 	struct wlr_box box = {
828 		.x = rect->x1,
829 		.y = rect->y1,
830 		.width = rect->x2 - rect->x1,
831 		.height = rect->y2 - rect->y1,
832 	};
833 
834 	int ow, oh;
835 	wlr_output_transformed_resolution(output, &ow, &oh);
836 
837 	enum wl_output_transform transform =
838 		wlr_output_transform_invert(output->transform);
839 	wlr_box_transform(&box, &box, transform, ow, oh);
840 
841 	wlr_renderer_scissor(renderer, &box);
842 }
843 
844 static void output_cursor_get_box(struct wlr_output_cursor *cursor,
845 	struct wlr_box *box);
846 
output_cursor_render(struct wlr_output_cursor * cursor,pixman_region32_t * damage)847 static void output_cursor_render(struct wlr_output_cursor *cursor,
848 		pixman_region32_t *damage) {
849 	struct wlr_renderer *renderer =
850 		wlr_backend_get_renderer(cursor->output->backend);
851 	assert(renderer);
852 
853 	struct wlr_texture *texture = cursor->texture;
854 	if (cursor->surface != NULL) {
855 		texture = wlr_surface_get_texture(cursor->surface);
856 	}
857 	if (texture == NULL) {
858 		return;
859 	}
860 
861 	struct wlr_box box;
862 	output_cursor_get_box(cursor, &box);
863 
864 	pixman_region32_t surface_damage;
865 	pixman_region32_init(&surface_damage);
866 	pixman_region32_union_rect(&surface_damage, &surface_damage, box.x, box.y,
867 		box.width, box.height);
868 	pixman_region32_intersect(&surface_damage, &surface_damage, damage);
869 	if (!pixman_region32_not_empty(&surface_damage)) {
870 		goto surface_damage_finish;
871 	}
872 
873 	float matrix[9];
874 	wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
875 		cursor->output->transform_matrix);
876 
877 	int nrects;
878 	pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects);
879 	for (int i = 0; i < nrects; ++i) {
880 		output_scissor(cursor->output, &rects[i]);
881 		wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f);
882 	}
883 	wlr_renderer_scissor(renderer, NULL);
884 
885 surface_damage_finish:
886 	pixman_region32_fini(&surface_damage);
887 }
888 
wlr_output_render_software_cursors(struct wlr_output * output,pixman_region32_t * damage)889 void wlr_output_render_software_cursors(struct wlr_output *output,
890 		pixman_region32_t *damage) {
891 	int width, height;
892 	wlr_output_transformed_resolution(output, &width, &height);
893 
894 	pixman_region32_t render_damage;
895 	pixman_region32_init(&render_damage);
896 	pixman_region32_union_rect(&render_damage, &render_damage, 0, 0,
897 		width, height);
898 	if (damage != NULL) {
899 		// Damage tracking supported
900 		pixman_region32_intersect(&render_damage, &render_damage, damage);
901 	}
902 
903 	if (pixman_region32_not_empty(&render_damage)) {
904 		struct wlr_output_cursor *cursor;
905 		wl_list_for_each(cursor, &output->cursors, link) {
906 			if (!cursor->enabled || !cursor->visible ||
907 					output->hardware_cursor == cursor) {
908 				continue;
909 			}
910 			output_cursor_render(cursor, &render_damage);
911 		}
912 	}
913 
914 	pixman_region32_fini(&render_damage);
915 }
916 
917 
918 /**
919  * Returns the cursor box, scaled for its output.
920  */
output_cursor_get_box(struct wlr_output_cursor * cursor,struct wlr_box * box)921 static void output_cursor_get_box(struct wlr_output_cursor *cursor,
922 		struct wlr_box *box) {
923 	box->x = cursor->x - cursor->hotspot_x;
924 	box->y = cursor->y - cursor->hotspot_y;
925 	box->width = cursor->width;
926 	box->height = cursor->height;
927 }
928 
output_cursor_damage_whole(struct wlr_output_cursor * cursor)929 static void output_cursor_damage_whole(struct wlr_output_cursor *cursor) {
930 	struct wlr_box box;
931 	output_cursor_get_box(cursor, &box);
932 
933 	pixman_region32_t damage;
934 	pixman_region32_init_rect(&damage, box.x, box.y, box.width, box.height);
935 
936 	struct wlr_output_event_damage event = {
937 		.output = cursor->output,
938 		.damage = &damage,
939 	};
940 	wlr_signal_emit_safe(&cursor->output->events.damage, &event);
941 
942 	pixman_region32_fini(&damage);
943 }
944 
output_cursor_reset(struct wlr_output_cursor * cursor)945 static void output_cursor_reset(struct wlr_output_cursor *cursor) {
946 	if (cursor->output->hardware_cursor != cursor) {
947 		output_cursor_damage_whole(cursor);
948 	}
949 	if (cursor->surface != NULL) {
950 		wl_list_remove(&cursor->surface_commit.link);
951 		wl_list_remove(&cursor->surface_destroy.link);
952 		if (cursor->visible) {
953 			wlr_surface_send_leave(cursor->surface, cursor->output);
954 		}
955 		cursor->surface = NULL;
956 	}
957 }
958 
output_cursor_update_visible(struct wlr_output_cursor * cursor)959 static void output_cursor_update_visible(struct wlr_output_cursor *cursor) {
960 	struct wlr_box output_box;
961 	output_box.x = output_box.y = 0;
962 	wlr_output_transformed_resolution(cursor->output, &output_box.width,
963 		&output_box.height);
964 
965 	struct wlr_box cursor_box;
966 	output_cursor_get_box(cursor, &cursor_box);
967 
968 	struct wlr_box intersection;
969 	bool visible =
970 		wlr_box_intersection(&intersection, &output_box, &cursor_box);
971 
972 	if (cursor->surface != NULL) {
973 		if (cursor->visible && !visible) {
974 			wlr_surface_send_leave(cursor->surface, cursor->output);
975 		}
976 		if (!cursor->visible && visible) {
977 			wlr_surface_send_enter(cursor->surface, cursor->output);
978 		}
979 	}
980 
981 	cursor->visible = visible;
982 }
983 
output_cursor_attempt_hardware(struct wlr_output_cursor * cursor)984 static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
985 	float scale = cursor->output->scale;
986 	enum wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
987 	struct wlr_texture *texture = cursor->texture;
988 	if (cursor->surface != NULL) {
989 		texture = wlr_surface_get_texture(cursor->surface);
990 		scale = cursor->surface->current.scale;
991 		transform = cursor->surface->current.transform;
992 	}
993 
994 	if (cursor->output->software_cursor_locks > 0) {
995 		return false;
996 	}
997 
998 	struct wlr_output_cursor *hwcur = cursor->output->hardware_cursor;
999 	if (cursor->output->impl->set_cursor && (hwcur == NULL || hwcur == cursor)) {
1000 		// If the cursor was hidden or was a software cursor, the hardware
1001 		// cursor position is outdated
1002 		assert(cursor->output->impl->move_cursor);
1003 		cursor->output->impl->move_cursor(cursor->output,
1004 			(int)cursor->x, (int)cursor->y);
1005 		if (cursor->output->impl->set_cursor(cursor->output, texture,
1006 				scale, transform, cursor->hotspot_x, cursor->hotspot_y, true)) {
1007 			cursor->output->hardware_cursor = cursor;
1008 			return true;
1009 		}
1010 	}
1011 	return false;
1012 }
1013 
wlr_output_cursor_set_image(struct wlr_output_cursor * cursor,const uint8_t * pixels,int32_t stride,uint32_t width,uint32_t height,int32_t hotspot_x,int32_t hotspot_y)1014 bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
1015 		const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height,
1016 		int32_t hotspot_x, int32_t hotspot_y) {
1017 	struct wlr_renderer *renderer =
1018 		wlr_backend_get_renderer(cursor->output->backend);
1019 	if (!renderer) {
1020 		// if the backend has no renderer, we can't draw a cursor, but this is
1021 		// actually okay, for ex. with the noop backend
1022 		return true;
1023 	}
1024 
1025 	output_cursor_reset(cursor);
1026 
1027 	cursor->width = width;
1028 	cursor->height = height;
1029 	cursor->hotspot_x = hotspot_x;
1030 	cursor->hotspot_y = hotspot_y;
1031 	output_cursor_update_visible(cursor);
1032 
1033 	wlr_texture_destroy(cursor->texture);
1034 	cursor->texture = NULL;
1035 
1036 	cursor->enabled = false;
1037 	if (pixels != NULL) {
1038 		cursor->texture = wlr_texture_from_pixels(renderer,
1039 			WL_SHM_FORMAT_ARGB8888, stride, width, height, pixels);
1040 		if (cursor->texture == NULL) {
1041 			return false;
1042 		}
1043 		cursor->enabled = true;
1044 	}
1045 
1046 	if (output_cursor_attempt_hardware(cursor)) {
1047 		return true;
1048 	}
1049 
1050 	wlr_log(WLR_DEBUG, "Falling back to software cursor on output '%s'",
1051 		cursor->output->name);
1052 	output_cursor_damage_whole(cursor);
1053 	return true;
1054 }
1055 
output_cursor_commit(struct wlr_output_cursor * cursor,bool update_hotspot)1056 static void output_cursor_commit(struct wlr_output_cursor *cursor,
1057 		bool update_hotspot) {
1058 	if (cursor->output->hardware_cursor != cursor) {
1059 		output_cursor_damage_whole(cursor);
1060 	}
1061 
1062 	struct wlr_surface *surface = cursor->surface;
1063 	assert(surface != NULL);
1064 
1065 	// Some clients commit a cursor surface with a NULL buffer to hide it.
1066 	cursor->enabled = wlr_surface_has_buffer(surface);
1067 	cursor->width = surface->current.width * cursor->output->scale;
1068 	cursor->height = surface->current.height * cursor->output->scale;
1069 	output_cursor_update_visible(cursor);
1070 	if (update_hotspot) {
1071 		cursor->hotspot_x -= surface->current.dx * cursor->output->scale;
1072 		cursor->hotspot_y -= surface->current.dy * cursor->output->scale;
1073 	}
1074 
1075 	if (output_cursor_attempt_hardware(cursor)) {
1076 		return;
1077 	}
1078 
1079 	// Fallback to software cursor
1080 	output_cursor_damage_whole(cursor);
1081 }
1082 
output_cursor_handle_commit(struct wl_listener * listener,void * data)1083 static void output_cursor_handle_commit(struct wl_listener *listener,
1084 		void *data) {
1085 	struct wlr_output_cursor *cursor =
1086 		wl_container_of(listener, cursor, surface_commit);
1087 	output_cursor_commit(cursor, true);
1088 }
1089 
output_cursor_handle_destroy(struct wl_listener * listener,void * data)1090 static void output_cursor_handle_destroy(struct wl_listener *listener,
1091 		void *data) {
1092 	struct wlr_output_cursor *cursor = wl_container_of(listener, cursor,
1093 		surface_destroy);
1094 	output_cursor_reset(cursor);
1095 }
1096 
wlr_output_cursor_set_surface(struct wlr_output_cursor * cursor,struct wlr_surface * surface,int32_t hotspot_x,int32_t hotspot_y)1097 void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor,
1098 		struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y) {
1099 	hotspot_x *= cursor->output->scale;
1100 	hotspot_y *= cursor->output->scale;
1101 
1102 	if (surface && surface == cursor->surface) {
1103 		// Only update the hotspot: surface hasn't changed
1104 
1105 		if (cursor->output->hardware_cursor != cursor) {
1106 			output_cursor_damage_whole(cursor);
1107 		}
1108 		cursor->hotspot_x = hotspot_x;
1109 		cursor->hotspot_y = hotspot_y;
1110 		if (cursor->output->hardware_cursor != cursor) {
1111 			output_cursor_damage_whole(cursor);
1112 		} else {
1113 			assert(cursor->output->impl->set_cursor);
1114 			cursor->output->impl->set_cursor(cursor->output, NULL,
1115 				1, WL_OUTPUT_TRANSFORM_NORMAL, hotspot_x, hotspot_y, false);
1116 		}
1117 		return;
1118 	}
1119 
1120 	output_cursor_reset(cursor);
1121 
1122 	cursor->surface = surface;
1123 	cursor->hotspot_x = hotspot_x;
1124 	cursor->hotspot_y = hotspot_y;
1125 
1126 	if (surface != NULL) {
1127 		wl_signal_add(&surface->events.commit, &cursor->surface_commit);
1128 		wl_signal_add(&surface->events.destroy, &cursor->surface_destroy);
1129 
1130 		cursor->visible = false;
1131 		output_cursor_commit(cursor, false);
1132 	} else {
1133 		cursor->enabled = false;
1134 		cursor->width = 0;
1135 		cursor->height = 0;
1136 
1137 		if (cursor->output->hardware_cursor == cursor) {
1138 			assert(cursor->output->impl->set_cursor);
1139 			cursor->output->impl->set_cursor(cursor->output, NULL, 1,
1140 				WL_OUTPUT_TRANSFORM_NORMAL, 0, 0, true);
1141 		}
1142 	}
1143 }
1144 
wlr_output_cursor_move(struct wlr_output_cursor * cursor,double x,double y)1145 bool wlr_output_cursor_move(struct wlr_output_cursor *cursor,
1146 		double x, double y) {
1147 	if (cursor->x == x && cursor->y == y) {
1148 		return true;
1149 	}
1150 
1151 	if (cursor->output->hardware_cursor != cursor) {
1152 		output_cursor_damage_whole(cursor);
1153 	}
1154 
1155 	bool was_visible = cursor->visible;
1156 	x *= cursor->output->scale;
1157 	y *= cursor->output->scale;
1158 	cursor->x = x;
1159 	cursor->y = y;
1160 	output_cursor_update_visible(cursor);
1161 
1162 	if (!was_visible && !cursor->visible) {
1163 		// Cursor is still hidden, do nothing
1164 		return true;
1165 	}
1166 
1167 	if (cursor->output->hardware_cursor != cursor) {
1168 		output_cursor_damage_whole(cursor);
1169 		return true;
1170 	}
1171 
1172 	assert(cursor->output->impl->move_cursor);
1173 	return cursor->output->impl->move_cursor(cursor->output, (int)x, (int)y);
1174 }
1175 
wlr_output_cursor_create(struct wlr_output * output)1176 struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output) {
1177 	struct wlr_output_cursor *cursor =
1178 		calloc(1, sizeof(struct wlr_output_cursor));
1179 	if (cursor == NULL) {
1180 		return NULL;
1181 	}
1182 	cursor->output = output;
1183 	wl_signal_init(&cursor->events.destroy);
1184 	wl_list_init(&cursor->surface_commit.link);
1185 	cursor->surface_commit.notify = output_cursor_handle_commit;
1186 	wl_list_init(&cursor->surface_destroy.link);
1187 	cursor->surface_destroy.notify = output_cursor_handle_destroy;
1188 	wl_list_insert(&output->cursors, &cursor->link);
1189 	cursor->visible = true; // default position is at (0, 0)
1190 	return cursor;
1191 }
1192 
wlr_output_cursor_destroy(struct wlr_output_cursor * cursor)1193 void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) {
1194 	if (cursor == NULL) {
1195 		return;
1196 	}
1197 	output_cursor_reset(cursor);
1198 	wlr_signal_emit_safe(&cursor->events.destroy, cursor);
1199 	if (cursor->output->hardware_cursor == cursor) {
1200 		// If this cursor was the hardware cursor, disable it
1201 		if (cursor->output->impl->set_cursor) {
1202 			cursor->output->impl->set_cursor(cursor->output, NULL, 1,
1203 				WL_OUTPUT_TRANSFORM_NORMAL, 0, 0, true);
1204 		}
1205 		cursor->output->hardware_cursor = NULL;
1206 	}
1207 	wlr_texture_destroy(cursor->texture);
1208 	wl_list_remove(&cursor->link);
1209 	free(cursor);
1210 }
1211 
1212 
wlr_output_transform_invert(enum wl_output_transform tr)1213 enum wl_output_transform wlr_output_transform_invert(
1214 		enum wl_output_transform tr) {
1215 	if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED)) {
1216 		tr ^= WL_OUTPUT_TRANSFORM_180;
1217 	}
1218 	return tr;
1219 }
1220 
wlr_output_transform_compose(enum wl_output_transform tr_a,enum wl_output_transform tr_b)1221 enum wl_output_transform wlr_output_transform_compose(
1222 		enum wl_output_transform tr_a, enum wl_output_transform tr_b) {
1223 	uint32_t flipped = (tr_a ^ tr_b) & WL_OUTPUT_TRANSFORM_FLIPPED;
1224 	uint32_t rotation_mask = WL_OUTPUT_TRANSFORM_90 | WL_OUTPUT_TRANSFORM_180;
1225 	uint32_t rotated;
1226 	if (tr_b & WL_OUTPUT_TRANSFORM_FLIPPED) {
1227 		// When a rotation of k degrees is followed by a flip, the
1228 		// equivalent transform is a flip followed by a rotation of
1229 		// -k degrees.
1230 		rotated = (tr_b - tr_a) & rotation_mask;
1231 	} else {
1232 		rotated = (tr_a + tr_b) & rotation_mask;
1233 	}
1234 	return flipped | rotated;
1235 }
1236