|  |  |  | @ -32,28 +32,28 @@ static int max(int fst, int snd) { | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_state_reset_buffer(struct wlr_surface_state *state) { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (state->buffer) { | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_list_remove(&state->buffer_destroy_listener.link); | 
			
		
	
		
			
				
					|  |  |  |  | 		state->buffer = NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (state->buffer_resource) { | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_list_remove(&state->buffer_destroy.link); | 
			
		
	
		
			
				
					|  |  |  |  | 		state->buffer_resource = NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_handle_buffer_destroy(struct wl_listener *listener, | 
			
		
	
		
			
				
					|  |  |  |  | 		void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface_state *state = | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_container_of(listener, state, buffer_destroy_listener); | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_container_of(listener, state, buffer_destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_reset_buffer(state); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_state_set_buffer(struct wlr_surface_state *state, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wl_resource *buffer) { | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wl_resource *buffer_resource) { | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_reset_buffer(state); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	state->buffer = buffer; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (buffer) { | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_resource_add_destroy_listener(buffer, | 
			
		
	
		
			
				
					|  |  |  |  | 			&state->buffer_destroy_listener); | 
			
		
	
		
			
				
					|  |  |  |  | 		state->buffer_destroy_listener.notify = surface_handle_buffer_destroy; | 
			
		
	
		
			
				
					|  |  |  |  | 	state->buffer_resource = buffer_resource; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (buffer_resource != NULL) { | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_resource_add_destroy_listener(buffer_resource, | 
			
		
	
		
			
				
					|  |  |  |  | 			&state->buffer_destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 		state->buffer_destroy.notify = surface_handle_buffer_destroy; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -64,13 +64,13 @@ static void surface_destroy(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_attach(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wl_resource *resource, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wl_resource *buffer, int32_t sx, int32_t sy) { | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wl_resource *buffer, int32_t dx, int32_t dy) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface *surface = wlr_surface_from_resource(resource); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->invalid |= WLR_SURFACE_INVALID_BUFFER; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->sx = sx; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->sy = sy; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_set_buffer(surface->pending, buffer); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.committed |= WLR_SURFACE_STATE_BUFFER; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.dx = dx; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.dy = dy; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_set_buffer(&surface->pending, buffer); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_damage(struct wl_client *client, | 
			
		
	
	
		
			
				
					|  |  |  | @ -80,9 +80,9 @@ static void surface_damage(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 	if (width < 0 || height < 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->invalid |= WLR_SURFACE_INVALID_SURFACE_DAMAGE; | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_union_rect(&surface->pending->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		&surface->pending->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.committed |= WLR_SURFACE_STATE_SURFACE_DAMAGE; | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_union_rect(&surface->pending.surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		&surface->pending.surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		x, y, width, height); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -103,192 +103,172 @@ static void surface_frame(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_resource_set_implementation(callback_resource, NULL, NULL, | 
			
		
	
		
			
				
					|  |  |  |  | 		callback_handle_resource_destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_insert(surface->pending->frame_callback_list.prev, | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_insert(surface->pending.frame_callback_list.prev, | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_resource_get_link(callback_resource)); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->invalid |= WLR_SURFACE_INVALID_FRAME_CALLBACK_LIST; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.committed |= WLR_SURFACE_STATE_FRAME_CALLBACK_LIST; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_set_opaque_region(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wl_resource *resource, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wl_resource *region_resource) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface *surface = wlr_surface_from_resource(resource); | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((surface->pending->invalid & WLR_SURFACE_INVALID_OPAQUE_REGION)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&surface->pending->opaque); | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((surface->pending.committed & WLR_SURFACE_STATE_OPAQUE_REGION)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&surface->pending.opaque); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->invalid |= WLR_SURFACE_INVALID_OPAQUE_REGION; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.committed |= WLR_SURFACE_STATE_OPAQUE_REGION; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (region_resource) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_t *region = wlr_region_from_resource(region_resource); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&surface->pending->opaque, region); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&surface->pending.opaque, region); | 
			
		
	
		
			
				
					|  |  |  |  | 	} else { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&surface->pending->opaque); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&surface->pending.opaque); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_set_input_region(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wl_resource *resource, struct wl_resource *region_resource) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface *surface = wlr_surface_from_resource(resource); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->invalid |= WLR_SURFACE_INVALID_INPUT_REGION; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.committed |= WLR_SURFACE_STATE_INPUT_REGION; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (region_resource) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_t *region = wlr_region_from_resource(region_resource); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&surface->pending->input, region); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&surface->pending.input, region); | 
			
		
	
		
			
				
					|  |  |  |  | 	} else { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_fini(&surface->pending->input); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_init_rect(&surface->pending->input, | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_fini(&surface->pending.input); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_init_rect(&surface->pending.input, | 
			
		
	
		
			
				
					|  |  |  |  | 			INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static bool surface_update_size(struct wlr_surface *surface, | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_state_finalize(struct wlr_surface *surface, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_surface_state *state) { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (!state->buffer) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union_rect(&state->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&state->surface_damage, 0, 0, state->width, state->height); | 
			
		
	
		
			
				
					|  |  |  |  | 		state->height = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 		state->width = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 		return true; | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((state->committed & WLR_SURFACE_STATE_BUFFER)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		if (state->buffer_resource != NULL) { | 
			
		
	
		
			
				
					|  |  |  |  | 			wlr_buffer_get_resource_size(state->buffer_resource, | 
			
		
	
		
			
				
					|  |  |  |  | 				surface->renderer, &state->buffer_width, &state->buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			state->buffer_width = state->buffer_height = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	int scale = state->scale; | 
			
		
	
		
			
				
					|  |  |  |  | 	enum wl_output_transform transform = state->transform; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wlr_buffer_get_resource_size(state->buffer, surface->renderer, | 
			
		
	
		
			
				
					|  |  |  |  | 		&state->buffer_width, &state->buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	int width = state->buffer_width / scale; | 
			
		
	
		
			
				
					|  |  |  |  | 	int height = state->buffer_height / scale; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (transform == WL_OUTPUT_TRANSFORM_90 || | 
			
		
	
		
			
				
					|  |  |  |  | 		transform == WL_OUTPUT_TRANSFORM_270 || | 
			
		
	
		
			
				
					|  |  |  |  | 		transform == WL_OUTPUT_TRANSFORM_FLIPPED_90 || | 
			
		
	
		
			
				
					|  |  |  |  | 		transform == WL_OUTPUT_TRANSFORM_FLIPPED_270) { | 
			
		
	
		
			
				
					|  |  |  |  | 	int width = state->buffer_width / state->scale; | 
			
		
	
		
			
				
					|  |  |  |  | 	int height = state->buffer_height / state->scale; | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((state->transform & WL_OUTPUT_TRANSFORM_90) != 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 		int tmp = width; | 
			
		
	
		
			
				
					|  |  |  |  | 		width = height; | 
			
		
	
		
			
				
					|  |  |  |  | 		height = tmp; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	bool update_damage = false; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (width != state->width || height != state->height) { | 
			
		
	
		
			
				
					|  |  |  |  | 		// Damage the whole surface on resize
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// This isn't in the spec, but Weston does it and QT expects it
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union_rect(&state->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&state->surface_damage, 0, 0, state->width, state->height); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union_rect(&state->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&state->surface_damage, 0, 0, width, height); | 
			
		
	
		
			
				
					|  |  |  |  | 		update_damage = true; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	state->width = width; | 
			
		
	
		
			
				
					|  |  |  |  | 	state->height = height; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	return update_damage; | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_intersect_rect(&state->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		&state->surface_damage, 0, 0, state->width, state->height); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_intersect_rect(&state->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		&state->buffer_damage, 0, 0, state->buffer_width, | 
			
		
	
		
			
				
					|  |  |  |  | 		state->buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | /**
 | 
			
		
	
		
			
				
					|  |  |  |  |  * Append pending state to current state and clear pending state. | 
			
		
	
		
			
				
					|  |  |  |  |  */ | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_move_state(struct wlr_surface *surface, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_surface_state *next, struct wlr_surface_state *state) { | 
			
		
	
		
			
				
					|  |  |  |  | 	bool update_damage = false; | 
			
		
	
		
			
				
					|  |  |  |  | 	bool update_size = false; | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_update_damage(pixman_region32_t *buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_surface_state *previous, struct wlr_surface_state *current) { | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_clear(buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (current->buffer_width != previous->buffer_width || | 
			
		
	
		
			
				
					|  |  |  |  | 			current->buffer_height != previous->buffer_height || | 
			
		
	
		
			
				
					|  |  |  |  | 			current->dx != 0 || current->dy != 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 		// Damage the whole surface on resize or move
 | 
			
		
	
		
			
				
					|  |  |  |  | 		int prev_x = -current->dx; | 
			
		
	
		
			
				
					|  |  |  |  | 		int prev_y = -current->dy; | 
			
		
	
		
			
				
					|  |  |  |  | 		if ((previous->transform & WL_OUTPUT_TRANSFORM_90) != 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 			int tmp = prev_x; | 
			
		
	
		
			
				
					|  |  |  |  | 			prev_x = prev_y; | 
			
		
	
		
			
				
					|  |  |  |  | 			prev_y = tmp; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union_rect(buffer_damage, buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			prev_x * previous->scale, prev_y * previous->scale, | 
			
		
	
		
			
				
					|  |  |  |  | 			previous->buffer_width, previous->buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union_rect(buffer_damage, buffer_damage, 0, 0, | 
			
		
	
		
			
				
					|  |  |  |  | 			current->buffer_width, current->buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 	} else { | 
			
		
	
		
			
				
					|  |  |  |  | 		// Copy over surface damage + buffer damage
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union(buffer_damage, buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			¤t->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_t surface_damage; | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_init(&surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&surface_damage, ¤t->surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_region_transform(&surface_damage, &surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			current->transform, current->buffer_width, current->buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_region_scale(&surface_damage, &surface_damage, current->scale); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union(buffer_damage, buffer_damage, &surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_fini(&surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	int oldw = state->width; | 
			
		
	
		
			
				
					|  |  |  |  | 	int oldh = state->height; | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_state_copy(struct wlr_surface_state *state, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_surface_state *next) { | 
			
		
	
		
			
				
					|  |  |  |  | 	state->width = next->width; | 
			
		
	
		
			
				
					|  |  |  |  | 	state->height = next->height; | 
			
		
	
		
			
				
					|  |  |  |  | 	state->buffer_width = next->buffer_width; | 
			
		
	
		
			
				
					|  |  |  |  | 	state->buffer_height = next->buffer_height; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((next->invalid & WLR_SURFACE_INVALID_SCALE)) { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_SCALE) { | 
			
		
	
		
			
				
					|  |  |  |  | 		state->scale = next->scale; | 
			
		
	
		
			
				
					|  |  |  |  | 		update_size = true; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((next->invalid & WLR_SURFACE_INVALID_TRANSFORM)) { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_TRANSFORM) { | 
			
		
	
		
			
				
					|  |  |  |  | 		state->transform = next->transform; | 
			
		
	
		
			
				
					|  |  |  |  | 		update_size = true; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((next->invalid & WLR_SURFACE_INVALID_BUFFER)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_state_set_buffer(state, next->buffer); | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_state_reset_buffer(next); | 
			
		
	
		
			
				
					|  |  |  |  | 		state->sx = next->sx; | 
			
		
	
		
			
				
					|  |  |  |  | 		state->sy = next->sy; | 
			
		
	
		
			
				
					|  |  |  |  | 		update_size = true; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if (update_size) { | 
			
		
	
		
			
				
					|  |  |  |  | 		update_damage = surface_update_size(surface, state); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((next->invalid & WLR_SURFACE_INVALID_SURFACE_DAMAGE)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_intersect_rect(&next->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&next->surface_damage, 0, 0, state->width, state->height); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union(&state->surface_damage, &state->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&next->surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&next->surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		update_damage = true; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((next->invalid & WLR_SURFACE_INVALID_BUFFER_DAMAGE)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_intersect_rect(&next->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&next->buffer_damage, 0, 0, state->buffer_width, | 
			
		
	
		
			
				
					|  |  |  |  | 			state->buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union(&state->buffer_damage, &state->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&next->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&next->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		update_damage = true; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_BUFFER) { | 
			
		
	
		
			
				
					|  |  |  |  | 		state->dx = next->dx; | 
			
		
	
		
			
				
					|  |  |  |  | 		state->dy = next->dy; | 
			
		
	
		
			
				
					|  |  |  |  | 	} else { | 
			
		
	
		
			
				
					|  |  |  |  | 		state->dx = state->dy = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if (update_damage) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_t buffer_damage, surface_damage; | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_init(&buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_init(&surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// Surface to buffer damage
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&buffer_damage, &state->surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_region_transform(&buffer_damage, &buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			wlr_output_transform_invert(state->transform), | 
			
		
	
		
			
				
					|  |  |  |  | 			state->width, state->height); | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_region_scale(&buffer_damage, &buffer_damage, state->scale); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// Buffer to surface damage
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&surface_damage, &state->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_region_transform(&surface_damage, &surface_damage, state->transform, | 
			
		
	
		
			
				
					|  |  |  |  | 			state->buffer_width, state->buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_region_scale(&surface_damage, &surface_damage, 1.0f/state->scale); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union(&state->buffer_damage, &state->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union(&state->surface_damage, &state->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_fini(&buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_fini(&surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_SURFACE_DAMAGE) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&state->surface_damage, &next->surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	} else { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&state->surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((next->invalid & WLR_SURFACE_INVALID_OPAQUE_REGION)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		// TODO: process buffer
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&next->opaque); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_BUFFER_DAMAGE) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&state->buffer_damage, &next->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	} else { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&state->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((next->invalid & WLR_SURFACE_INVALID_INPUT_REGION)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		// TODO: process buffer
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_OPAQUE_REGION) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&state->opaque, &next->opaque); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_INPUT_REGION) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&state->input, &next->input); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((next->invalid & WLR_SURFACE_INVALID_SUBSURFACE_POSITION)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		// Subsurface has moved
 | 
			
		
	
		
			
				
					|  |  |  |  | 		int dx = state->subsurface_position.x - next->subsurface_position.x; | 
			
		
	
		
			
				
					|  |  |  |  | 		int dy = state->subsurface_position.y - next->subsurface_position.y; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		state->subsurface_position.x = next->subsurface_position.x; | 
			
		
	
		
			
				
					|  |  |  |  | 		state->subsurface_position.y = next->subsurface_position.y; | 
			
		
	
		
			
				
					|  |  |  |  | 		next->subsurface_position.x = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 		next->subsurface_position.y = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (dx != 0 || dy != 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 			pixman_region32_union_rect(&state->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 				&state->surface_damage, dx, dy, oldw, oldh); | 
			
		
	
		
			
				
					|  |  |  |  | 			pixman_region32_union_rect(&state->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 				&state->surface_damage, 0, 0, state->width, state->height); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	state->committed |= next->committed; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | /**
 | 
			
		
	
		
			
				
					|  |  |  |  |  * Append pending state to current state and clear pending state. | 
			
		
	
		
			
				
					|  |  |  |  |  */ | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_state_move(struct wlr_surface_state *state, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_surface_state *next) { | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_copy(state, next); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_BUFFER) { | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_state_set_buffer(state, next->buffer_resource); | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_state_reset_buffer(next); | 
			
		
	
		
			
				
					|  |  |  |  | 		next->dx = next->dy = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if ((next->invalid & WLR_SURFACE_INVALID_FRAME_CALLBACK_LIST)) { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_SURFACE_DAMAGE) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&next->surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_BUFFER_DAMAGE) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_clear(&next->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if (next->committed & WLR_SURFACE_STATE_FRAME_CALLBACK_LIST) { | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_list_insert_list(&state->frame_callback_list, | 
			
		
	
		
			
				
					|  |  |  |  | 			&next->frame_callback_list); | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_list_init(&next->frame_callback_list); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	state->invalid |= next->invalid; | 
			
		
	
		
			
				
					|  |  |  |  | 	next->invalid = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 	next->committed = 0; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_damage_subsurfaces(struct wlr_subsurface *subsurface) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -297,10 +277,9 @@ static void surface_damage_subsurfaces(struct wlr_subsurface *subsurface) { | 
			
		
	
		
			
				
					|  |  |  |  | 	// seems to work ok. See the comment on weston_surface_damage for more info
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// about a better approach.
 | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface *surface = subsurface->surface; | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_union_rect(&surface->current->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		&surface->current->surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		0, 0, surface->current->width, | 
			
		
	
		
			
				
					|  |  |  |  | 		surface->current->height); | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_union_rect(&surface->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		&surface->buffer_damage, 0, 0, | 
			
		
	
		
			
				
					|  |  |  |  | 		surface->current.buffer_width, surface->current.buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	subsurface->reordered = false; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -311,7 +290,7 @@ static void surface_damage_subsurfaces(struct wlr_subsurface *subsurface) { | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_apply_damage(struct wlr_surface *surface) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wl_resource *resource = surface->current->buffer; | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wl_resource *resource = surface->current.buffer_resource; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (resource == NULL) { | 
			
		
	
		
			
				
					|  |  |  |  | 		// NULL commit
 | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_buffer_unref(surface->buffer); | 
			
		
	
	
		
			
				
					|  |  |  | @ -322,9 +301,21 @@ static void surface_apply_damage(struct wlr_surface *surface) { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (surface->buffer != NULL && surface->buffer->released) { | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_t damage; | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_init(&damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&damage, &surface->current->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&damage, &surface->current.buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_t surface_damage; | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_init(&surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_copy(&surface_damage, &surface->current.surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_region_transform(&surface_damage, &surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			surface->current.transform, | 
			
		
	
		
			
				
					|  |  |  |  | 			surface->current.buffer_width, surface->current.buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_region_scale(&surface_damage, &surface_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			surface->current.scale); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union(&damage, &damage, &surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_fini(&surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_intersect_rect(&damage, &damage, 0, 0, | 
			
		
	
		
			
				
					|  |  |  |  | 			surface->current->buffer_width, surface->current->buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 			surface->current.buffer_width, surface->current.buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_buffer *updated_buffer = | 
			
		
	
		
			
				
					|  |  |  |  | 			wlr_buffer_apply_damage(surface->buffer, resource, &damage); | 
			
		
	
	
		
			
				
					|  |  |  | @ -350,9 +341,17 @@ static void surface_apply_damage(struct wlr_surface *surface) { | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_commit_pending(struct wlr_surface *surface) { | 
			
		
	
		
			
				
					|  |  |  |  | 	bool invalid_buffer = surface->pending->invalid & WLR_SURFACE_INVALID_BUFFER; | 
			
		
	
		
			
				
					|  |  |  |  | 	bool invalid_buffer = surface->pending.committed & WLR_SURFACE_STATE_BUFFER; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_finalize(surface, &surface->pending); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_move_state(surface, surface->pending, surface->current); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->sx += surface->pending.dx; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->sy += surface->pending.dy; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_update_damage(&surface->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		&surface->current, &surface->pending); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_copy(&surface->previous, &surface->current); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_move(&surface->current, &surface->pending); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (invalid_buffer) { | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_apply_damage(surface); | 
			
		
	
	
		
			
				
					|  |  |  | @ -375,11 +374,7 @@ static void surface_commit_pending(struct wlr_surface *surface) { | 
			
		
	
		
			
				
					|  |  |  |  | 		surface->role_committed(surface, surface->role_data); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// TODO: add the invalid bitfield to this callback
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wlr_signal_emit_safe(&surface->events.commit, surface); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_clear(&surface->current->surface_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_clear(&surface->current->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static bool subsurface_is_synchronized(struct wlr_subsurface *subsurface) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -406,18 +401,18 @@ static bool subsurface_is_synchronized(struct wlr_subsurface *subsurface) { | 
			
		
	
		
			
				
					|  |  |  |  |  */ | 
			
		
	
		
			
				
					|  |  |  |  | static void subsurface_parent_commit(struct wlr_subsurface *subsurface, | 
			
		
	
		
			
				
					|  |  |  |  | 		bool synchronized) { | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_surface *surface = subsurface->surface; | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface *surface = subsurface->surface; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (synchronized || subsurface->synchronized) { | 
			
		
	
		
			
				
					|  |  |  |  | 		if (subsurface->has_cache) { | 
			
		
	
		
			
				
					|  |  |  |  | 			surface_move_state(surface, subsurface->cached, surface->pending); | 
			
		
	
		
			
				
					|  |  |  |  | 			surface_state_move(&surface->pending, &subsurface->cached); | 
			
		
	
		
			
				
					|  |  |  |  | 			surface_commit_pending(surface); | 
			
		
	
		
			
				
					|  |  |  |  | 			subsurface->has_cache = false; | 
			
		
	
		
			
				
					|  |  |  |  | 			subsurface->cached->invalid = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 			subsurface->cached.committed = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_subsurface *tmp; | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_list_for_each(tmp, &surface->subsurfaces, parent_link) { | 
			
		
	
		
			
				
					|  |  |  |  | 			subsurface_parent_commit(tmp, true); | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_subsurface *subsurface; | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { | 
			
		
	
		
			
				
					|  |  |  |  | 			subsurface_parent_commit(subsurface, true); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
	
		
			
				
					|  |  |  | @ -426,22 +421,16 @@ static void subsurface_commit(struct wlr_subsurface *subsurface) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface *surface = subsurface->surface; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (subsurface_is_synchronized(subsurface)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_move_state(surface, surface->pending, subsurface->cached); | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_state_move(&subsurface->cached, &surface->pending); | 
			
		
	
		
			
				
					|  |  |  |  | 		subsurface->has_cache = true; | 
			
		
	
		
			
				
					|  |  |  |  | 	} else { | 
			
		
	
		
			
				
					|  |  |  |  | 		if (subsurface->has_cache) { | 
			
		
	
		
			
				
					|  |  |  |  | 			surface_move_state(surface, subsurface->cached, surface->pending); | 
			
		
	
		
			
				
					|  |  |  |  | 			surface_state_move(&surface->pending, &subsurface->cached); | 
			
		
	
		
			
				
					|  |  |  |  | 			surface_commit_pending(surface); | 
			
		
	
		
			
				
					|  |  |  |  | 			subsurface->has_cache = false; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			surface_commit_pending(surface); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_subsurface *tmp; | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_list_for_each(tmp, &surface->subsurfaces, parent_link) { | 
			
		
	
		
			
				
					|  |  |  |  | 			subsurface_parent_commit(tmp, false); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -453,30 +442,29 @@ static void surface_commit(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_subsurface *subsurface = | 
			
		
	
		
			
				
					|  |  |  |  | 			wlr_subsurface_from_wlr_surface(surface); | 
			
		
	
		
			
				
					|  |  |  |  | 		subsurface_commit(subsurface); | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} else { | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_commit_pending(surface); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_commit_pending(surface); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_subsurface *tmp; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_for_each(tmp, &surface->subsurfaces, parent_link) { | 
			
		
	
		
			
				
					|  |  |  |  | 		subsurface_parent_commit(tmp, false); | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_subsurface *subsurface; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { | 
			
		
	
		
			
				
					|  |  |  |  | 		subsurface_parent_commit(subsurface, false); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_set_buffer_transform(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wl_resource *resource, int transform) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface *surface = wlr_surface_from_resource(resource); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->invalid |= WLR_SURFACE_INVALID_TRANSFORM; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->transform = transform; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.committed |= WLR_SURFACE_STATE_TRANSFORM; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.transform = transform; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_set_buffer_scale(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wl_resource *resource, | 
			
		
	
		
			
				
					|  |  |  |  | 		int32_t scale) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface *surface = wlr_surface_from_resource(resource); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->invalid |= WLR_SURFACE_INVALID_SCALE; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->scale = scale; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.committed |= WLR_SURFACE_STATE_SCALE; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.scale = scale; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_damage_buffer(struct wl_client *client, | 
			
		
	
	
		
			
				
					|  |  |  | @ -487,9 +475,9 @@ static void surface_damage_buffer(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 	if (width < 0 || height < 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->invalid |= WLR_SURFACE_INVALID_BUFFER_DAMAGE; | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_union_rect(&surface->pending->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		&surface->pending->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending.committed |= WLR_SURFACE_STATE_BUFFER_DAMAGE; | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_union_rect(&surface->pending.buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		&surface->pending.buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 		x, y, width, height); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -512,12 +500,7 @@ struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) { | 
			
		
	
		
			
				
					|  |  |  |  | 	return wl_resource_get_user_data(resource); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static struct wlr_surface_state *surface_state_create(void) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface_state *state = | 
			
		
	
		
			
				
					|  |  |  |  | 		calloc(1, sizeof(struct wlr_surface_state)); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (state == NULL) { | 
			
		
	
		
			
				
					|  |  |  |  | 		return NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_state_init(struct wlr_surface_state *state) { | 
			
		
	
		
			
				
					|  |  |  |  | 	state->scale = 1; | 
			
		
	
		
			
				
					|  |  |  |  | 	state->transform = WL_OUTPUT_TRANSFORM_NORMAL; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -528,12 +511,11 @@ static struct wlr_surface_state *surface_state_create(void) { | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_init(&state->opaque); | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_init_rect(&state->input, | 
			
		
	
		
			
				
					|  |  |  |  | 		INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	return state; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_state_destroy(struct wlr_surface_state *state) { | 
			
		
	
		
			
				
					|  |  |  |  | static void surface_state_finish(struct wlr_surface_state *state) { | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_reset_buffer(state); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wl_resource *resource, *tmp; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list) { | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_resource_destroy(resource); | 
			
		
	
	
		
			
				
					|  |  |  | @ -543,8 +525,6 @@ static void surface_state_destroy(struct wlr_surface_state *state) { | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_fini(&state->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_fini(&state->opaque); | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_fini(&state->input); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	free(state); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void subsurface_destroy(struct wlr_subsurface *subsurface) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -555,7 +535,7 @@ static void subsurface_destroy(struct wlr_subsurface *subsurface) { | 
			
		
	
		
			
				
					|  |  |  |  | 	wlr_signal_emit_safe(&subsurface->events.destroy, subsurface); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&subsurface->surface_destroy.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_destroy(subsurface->cached); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_finish(&subsurface->cached); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (subsurface->parent) { | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_list_remove(&subsurface->parent_link); | 
			
		
	
	
		
			
				
					|  |  |  | @ -578,8 +558,10 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) { | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(wl_resource_get_link(surface->resource)); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&surface->renderer_destroy.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_destroy(surface->pending); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_destroy(surface->current); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_finish(&surface->pending); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_finish(&surface->current); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_finish(&surface->previous); | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_fini(&surface->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 	wlr_buffer_unref(surface->buffer); | 
			
		
	
		
			
				
					|  |  |  |  | 	free(surface); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
	
		
			
				
					|  |  |  | @ -615,14 +597,16 @@ struct wlr_surface *wlr_surface_create(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->renderer = renderer; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->current = surface_state_create(); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending = surface_state_create(); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_init(&surface->current); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_init(&surface->pending); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_init(&surface->previous); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_init(&surface->events.commit); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_init(&surface->events.destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_init(&surface->events.new_subsurface); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_init(&surface->subsurfaces); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_init(&surface->subsurface_pending_list); | 
			
		
	
		
			
				
					|  |  |  |  | 	pixman_region32_init(&surface->buffer_damage); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&renderer->events.destroy, &surface->renderer_destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->renderer_destroy.notify = surface_handle_renderer_destroy; | 
			
		
	
	
		
			
				
					|  |  |  | @ -696,10 +680,8 @@ static void subsurface_handle_set_position(struct wl_client *client, | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_surface *surface = subsurface->surface; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->invalid |= WLR_SURFACE_INVALID_SUBSURFACE_POSITION; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->subsurface_position.x = x; | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->pending->subsurface_position.y = y; | 
			
		
	
		
			
				
					|  |  |  |  | 	subsurface->pending.x = x; | 
			
		
	
		
			
				
					|  |  |  |  | 	subsurface->pending.y = y; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static struct wlr_subsurface *subsurface_find_sibling( | 
			
		
	
	
		
			
				
					|  |  |  | @ -806,6 +788,34 @@ static const struct wl_subsurface_interface subsurface_implementation = { | 
			
		
	
		
			
				
					|  |  |  |  | 	.set_desync = subsurface_handle_set_desync, | 
			
		
	
		
			
				
					|  |  |  |  | }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void subsurface_role_committed(struct wlr_surface *surface, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_subsurface *subsurface = data; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (subsurface->current.x != subsurface->pending.x || | 
			
		
	
		
			
				
					|  |  |  |  | 			subsurface->current.y != subsurface->pending.y) { | 
			
		
	
		
			
				
					|  |  |  |  | 		// Subsurface has moved
 | 
			
		
	
		
			
				
					|  |  |  |  | 		int dx = subsurface->current.x - subsurface->pending.x; | 
			
		
	
		
			
				
					|  |  |  |  | 		int dy = subsurface->current.y - subsurface->pending.y; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		subsurface->current.x = subsurface->pending.x; | 
			
		
	
		
			
				
					|  |  |  |  | 		subsurface->current.y = subsurface->pending.y; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if ((surface->current.transform & WL_OUTPUT_TRANSFORM_90) != 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 			int tmp = dx; | 
			
		
	
		
			
				
					|  |  |  |  | 			dx = dy; | 
			
		
	
		
			
				
					|  |  |  |  | 			dy = tmp; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union_rect(&surface->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&surface->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			dx * surface->previous.scale, dy * surface->previous.scale, | 
			
		
	
		
			
				
					|  |  |  |  | 			surface->previous.buffer_width, surface->previous.buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_union_rect(&surface->buffer_damage, | 
			
		
	
		
			
				
					|  |  |  |  | 			&surface->buffer_damage, 0, 0, | 
			
		
	
		
			
				
					|  |  |  |  | 			surface->current.buffer_width, surface->current.buffer_height); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void subsurface_handle_parent_destroy(struct wl_listener *listener, | 
			
		
	
		
			
				
					|  |  |  |  | 		void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_subsurface *subsurface = | 
			
		
	
	
		
			
				
					|  |  |  | @ -836,18 +846,13 @@ struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface, | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_client_post_no_memory(client); | 
			
		
	
		
			
				
					|  |  |  |  | 		return NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	subsurface->cached = surface_state_create(); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (subsurface->cached == NULL) { | 
			
		
	
		
			
				
					|  |  |  |  | 		free(subsurface); | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_client_post_no_memory(client); | 
			
		
	
		
			
				
					|  |  |  |  | 		return NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	surface_state_init(&subsurface->cached); | 
			
		
	
		
			
				
					|  |  |  |  | 	subsurface->synchronized = true; | 
			
		
	
		
			
				
					|  |  |  |  | 	subsurface->surface = surface; | 
			
		
	
		
			
				
					|  |  |  |  | 	subsurface->resource = | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_resource_create(client, &wl_subsurface_interface, version, id); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (subsurface->resource == NULL) { | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_state_destroy(subsurface->cached); | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_state_finish(&subsurface->cached); | 
			
		
	
		
			
				
					|  |  |  |  | 		free(subsurface); | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_client_post_no_memory(client); | 
			
		
	
		
			
				
					|  |  |  |  | 		return NULL; | 
			
		
	
	
		
			
				
					|  |  |  | @ -869,7 +874,8 @@ struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface, | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_insert(parent->subsurface_pending_list.prev, | 
			
		
	
		
			
				
					|  |  |  |  | 		&subsurface->parent_pending_link); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	surface->role_data = subsurface; | 
			
		
	
		
			
				
					|  |  |  |  | 	wlr_surface_set_role_committed(surface, subsurface_role_committed, | 
			
		
	
		
			
				
					|  |  |  |  | 		subsurface); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wl_list *resource_link = wl_resource_get_link(subsurface->resource); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (resource_list != NULL) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -895,17 +901,17 @@ struct wlr_surface *wlr_surface_get_root_surface(struct wlr_surface *surface) { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | bool wlr_surface_point_accepts_input(struct wlr_surface *surface, | 
			
		
	
		
			
				
					|  |  |  |  | 		double sx, double sy) { | 
			
		
	
		
			
				
					|  |  |  |  | 	return sx >= 0 && sx < surface->current->width && | 
			
		
	
		
			
				
					|  |  |  |  | 		sy >= 0 && sy < surface->current->height && | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_contains_point(&surface->current->input, sx, sy, NULL); | 
			
		
	
		
			
				
					|  |  |  |  | 	return sx >= 0 && sx < surface->current.width && | 
			
		
	
		
			
				
					|  |  |  |  | 		sy >= 0 && sy < surface->current.height && | 
			
		
	
		
			
				
					|  |  |  |  | 		pixman_region32_contains_point(&surface->current.input, sx, sy, NULL); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface, | 
			
		
	
		
			
				
					|  |  |  |  | 		double sx, double sy, double *sub_x, double *sub_y) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_subsurface *subsurface; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_for_each_reverse(subsurface, &surface->subsurfaces, parent_link) { | 
			
		
	
		
			
				
					|  |  |  |  | 		double _sub_x = subsurface->surface->current->subsurface_position.x; | 
			
		
	
		
			
				
					|  |  |  |  | 		double _sub_y = subsurface->surface->current->subsurface_position.y; | 
			
		
	
		
			
				
					|  |  |  |  | 		double _sub_x = subsurface->current.x; | 
			
		
	
		
			
				
					|  |  |  |  | 		double _sub_y = subsurface->current.y; | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_surface *sub = wlr_surface_surface_at(subsurface->surface, | 
			
		
	
		
			
				
					|  |  |  |  | 			sx - _sub_x, sy - _sub_y, sub_x, sub_y); | 
			
		
	
		
			
				
					|  |  |  |  | 		if (sub != NULL) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -952,7 +958,7 @@ void wlr_surface_send_frame_done(struct wlr_surface *surface, | 
			
		
	
		
			
				
					|  |  |  |  | 		const struct timespec *when) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wl_resource *resource, *tmp; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_resource_for_each_safe(resource, tmp, | 
			
		
	
		
			
				
					|  |  |  |  | 			&surface->current->frame_callback_list) { | 
			
		
	
		
			
				
					|  |  |  |  | 			&surface->current.frame_callback_list) { | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_callback_send_done(resource, timespec_to_msec(when)); | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_resource_destroy(resource); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
	
		
			
				
					|  |  |  | @ -971,9 +977,9 @@ static void surface_for_each_surface(struct wlr_surface *surface, int x, int y, | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_subsurface *subsurface; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_surface_state *state = subsurface->surface->current; | 
			
		
	
		
			
				
					|  |  |  |  | 		int sx = state->subsurface_position.x; | 
			
		
	
		
			
				
					|  |  |  |  | 		int sy = state->subsurface_position.y; | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_subsurface_state *state = &subsurface->current; | 
			
		
	
		
			
				
					|  |  |  |  | 		int sx = state->x; | 
			
		
	
		
			
				
					|  |  |  |  | 		int sy = state->y; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		surface_for_each_surface(subsurface->surface, x + sx, y + sy, | 
			
		
	
		
			
				
					|  |  |  |  | 			iterator, user_data); | 
			
		
	
	
		
			
				
					|  |  |  | @ -997,16 +1003,16 @@ static void handle_bounding_box_surface(struct wlr_surface *surface, | 
			
		
	
		
			
				
					|  |  |  |  | 	acc->min_x = min(x, acc->min_x); | 
			
		
	
		
			
				
					|  |  |  |  | 	acc->min_y = min(y, acc->min_y); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	acc->max_x = max(x + surface->current->width, acc->max_x); | 
			
		
	
		
			
				
					|  |  |  |  | 	acc->max_y = max(y + surface->current->height, acc->max_y); | 
			
		
	
		
			
				
					|  |  |  |  | 	acc->max_x = max(x + surface->current.width, acc->max_x); | 
			
		
	
		
			
				
					|  |  |  |  | 	acc->max_y = max(y + surface->current.height, acc->max_y); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct bound_acc acc = { | 
			
		
	
		
			
				
					|  |  |  |  | 		.min_x = 0, | 
			
		
	
		
			
				
					|  |  |  |  | 		.min_y = 0, | 
			
		
	
		
			
				
					|  |  |  |  | 		.max_x = surface->current->width, | 
			
		
	
		
			
				
					|  |  |  |  | 		.max_y = surface->current->height, | 
			
		
	
		
			
				
					|  |  |  |  | 		.max_x = surface->current.width, | 
			
		
	
		
			
				
					|  |  |  |  | 		.max_y = surface->current.height, | 
			
		
	
		
			
				
					|  |  |  |  | 	}; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wlr_surface_for_each_surface(surface, handle_bounding_box_surface, &acc); | 
			
		
	
	
		
			
				
					|  |  |  | 
 |