[RFC weston] compositor: Implement runtime output transform changes

Ilia Bozhinov ammen99 at gmail.com
Mon Jun 26 11:23:10 UTC 2017


From: Ilia Bozhinov <iliyabo at hotmail.com>

Up to now we could set the transform only on output initialization.
However, on certain situations(like tablets and convertible laptops),
screen orientation can change while the compositor is running and thus
the need for change of the output transform arises.

When the transform changes, we must update the output geometry,
output->region and output->previous_damage, as well as send this change
to clients. We also have to check whether any of the pointers are inside
the output which is being rotated. If this is the case, they are moved
to the new center, because otherwise the pointer is stuck outside of the
screen ans "lost" to the user.

What is more, after calling this function compositors should check if
any view is now outside of the screen and move it according to their
wish.

Signed-off-by: Ilia Bozhinov <iliyabo at hotmail.com>
---
 libweston/compositor.c | 65 +++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 57 insertions(+), 8 deletions(-)

diff --git a/libweston/compositor.c b/libweston/compositor.c
index 2a3074db..ca77bdfc 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -4587,9 +4587,6 @@ weston_output_set_scale(struct weston_output *output,
  * \param output    The weston_output object that the transform is set for.
  * \param transform Transform value for the given output.
  *
- * It only supports setting transform for an output that is
- * not enabled and it can only be ran once.
- *
  * Refer to wl_output::transform section located at
  * https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_output
  * for list of values that can be passed to this function.
@@ -4598,13 +4595,65 @@ WL_EXPORT void
 weston_output_set_transform(struct weston_output *output,
 			    uint32_t transform)
 {
-	/* We can only set transform on a disabled output */
-	assert(!output->enabled);
+	struct weston_pointer_motion_event ev;
+	struct wl_resource *resource;
+	struct weston_seat *seat;
+	pixman_region32_t old_region;
+	int mid_x, mid_y;
+
+	if (!output->enabled && output->transform == UINT32_MAX) {
+		output->transform = transform;
+		return;
+	}
 
-	/* We only want to set transform once */
-	assert(output->transform == UINT32_MAX);
+	if (transform == output->transform)
+		return;
 
-	output->transform = transform;
+	weston_output_transform_scale_init(output, transform, output->scale);
+
+	pixman_region32_init(&old_region);
+	pixman_region32_copy(&old_region, &output->region);
+
+	pixman_region32_fini(&output->region);
+	pixman_region32_fini(&output->previous_damage);
+
+	weston_output_init_geometry(output, output->x, output->y);
+
+	output->dirty = 1;
+
+	/* Notify clients of the change for output transform. */
+	wl_resource_for_each(resource, &output->resource_list) {
+		wl_output_send_geometry(resource,
+					output->x,
+					output->y,
+					output->mm_width,
+					output->mm_height,
+					output->subpixel,
+					output->make,
+					output->model,
+					output->transform);
+
+		if (wl_resource_get_version(resource) >= WL_OUTPUT_DONE_SINCE_VERSION)
+			wl_output_send_done(resource);
+	}
+
+	/* we must ensure that pointers are inside output, otherwise they disappear */
+	mid_x = output->x + output->width / 2;
+	mid_y = output->y + output->height / 2;
+
+	ev.mask = WESTON_POINTER_MOTION_ABS;
+	ev.x = wl_fixed_to_double(wl_fixed_from_int(mid_x));
+	ev.y = wl_fixed_to_double(wl_fixed_from_int(mid_y));
+
+	wl_list_for_each(seat, &output->compositor->seat_list, link) {
+		struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+		if (pointer && pixman_region32_contains_point(&old_region,
+							      wl_fixed_to_int(pointer->x),
+							      wl_fixed_to_int(pointer->y),
+							      NULL))
+			weston_pointer_move(pointer, &ev);
+	}
 }
 
 /** Initializes a weston_output object with enough data so
-- 
2.13.0



More information about the wayland-devel mailing list