[PATCH weston 1/2] compositor, shell: surface transform inheritance

Pekka Paalanen ppaalanen at gmail.com
Mon Mar 4 07:28:11 PST 2013


Implements surface transform inheritance. A 'parent' pointer is added to
weston_surface::geometry, and is automatically used by
weston_surface_update_transform(). When updating the transform, the
parent transform is updated as needed, too.

shell_map_popup() is converted to use the new
weston_surface_set_transform_parent() function. Now, if we moved the
popup's parent surface while the popup is open, the popup surface will
stick to the parent properly.

Signed-off-by: Pekka Paalanen <ppaalanen at gmail.com>

---

This is a new suggestion for the transform inheritance. Personally I
like this a lot better than the weston_matrix_pointer hassle, but I
haven't yet ported sub-surfaces on top of this.

Seems to work fine with menus.
---
 src/compositor.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++----
 src/compositor.h | 18 ++++++++++++++++--
 src/shell.c      | 28 +---------------------------
 3 files changed, 65 insertions(+), 33 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index 8037195..3bc6b11 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -625,6 +625,7 @@ weston_surface_update_transform_disable(struct weston_surface *surface)
 static int
 weston_surface_update_transform_enable(struct weston_surface *surface)
 {
+	struct weston_surface *parent = surface->geometry.parent;
 	struct weston_matrix *matrix = &surface->transform.matrix;
 	struct weston_matrix *inverse = &surface->transform.inverse;
 	struct weston_transform *tform;
@@ -640,6 +641,9 @@ weston_surface_update_transform_enable(struct weston_surface *surface)
 	wl_list_for_each(tform, &surface->geometry.transformation_list, link)
 		weston_matrix_multiply(matrix, &tform->matrix);
 
+	if (parent)
+		weston_matrix_multiply(matrix, &parent->transform.matrix);
+
 	if (weston_matrix_invert(inverse, matrix) < 0) {
 		/* Oops, bad total transformation, not invertible */
 		weston_log("error: weston_surface %p"
@@ -654,11 +658,17 @@ weston_surface_update_transform_enable(struct weston_surface *surface)
 	return 0;
 }
 
-WL_EXPORT void
+WL_EXPORT int
 weston_surface_update_transform(struct weston_surface *surface)
 {
-	if (!surface->geometry.dirty)
-		return;
+	struct weston_surface *parent = surface->geometry.parent;
+	int was_dirty = 0;
+
+	if (parent)
+		was_dirty = weston_surface_update_transform(parent);
+
+	if (!was_dirty && !surface->geometry.dirty)
+		return 0;
 
 	surface->geometry.dirty = 0;
 
@@ -672,7 +682,8 @@ weston_surface_update_transform(struct weston_surface *surface)
 	if (surface->geometry.transformation_list.next ==
 	    &surface->transform.position.link &&
 	    surface->geometry.transformation_list.prev ==
-	    &surface->transform.position.link) {
+	    &surface->transform.position.link &&
+	    !parent) {
 		weston_surface_update_transform_disable(surface);
 	} else {
 		if (weston_surface_update_transform_enable(surface) < 0)
@@ -682,6 +693,8 @@ weston_surface_update_transform(struct weston_surface *surface)
 	weston_surface_damage_below(surface);
 
 	weston_surface_assign_output(surface);
+
+	return 1;
 }
 
 WL_EXPORT void
@@ -791,6 +804,35 @@ weston_surface_set_position(struct weston_surface *surface,
 	surface->geometry.dirty = 1;
 }
 
+static void
+transform_parent_handle_parent_destroy(struct wl_listener *listener,
+				       void *data)
+{
+	struct weston_surface *surface =
+		container_of(listener, struct weston_surface,
+			     geometry.parent_destroy_listener);
+
+	weston_surface_set_transform_parent(surface, NULL);
+}
+
+WL_EXPORT void
+weston_surface_set_transform_parent(struct weston_surface *surface,
+				    struct weston_surface *parent)
+{
+	if (surface->geometry.parent)
+		wl_list_remove(&surface->geometry.parent_destroy_listener.link);
+
+	surface->geometry.parent = parent;
+
+	surface->geometry.parent_destroy_listener.notify =
+		transform_parent_handle_parent_destroy;
+	if (parent)
+		wl_signal_add(&parent->surface.resource.destroy_signal,
+			      &surface->geometry.parent_destroy_listener);
+
+	surface->geometry.dirty = 1;
+}
+
 WL_EXPORT int
 weston_surface_is_mapped(struct weston_surface *surface)
 {
@@ -967,6 +1009,8 @@ destroy_surface(struct wl_resource *resource)
 	wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link)
 		wl_resource_destroy(&cb->resource);
 
+	weston_surface_set_transform_parent(surface, NULL);
+
 	free(surface);
 }
 
diff --git a/src/compositor.h b/src/compositor.h
index 00d3b22..4167ef0 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -386,6 +386,11 @@ struct weston_region {
  * If you want to apply a transformation in local coordinates, add your
  * weston_transform to the head of the list. If you want to apply a
  * transformation in global coordinates, add it to the tail of the list.
+ *
+ * If surface->geometry.parent is set, the total transformation of this
+ * surface will be the parent's total transformation and this transformation
+ * combined:
+ *    Mparent * Mn * ... * M2 * M1
  */
 
 struct weston_surface {
@@ -404,12 +409,17 @@ struct weston_surface {
 
 	/* Surface geometry state, mutable.
 	 * If you change anything, set dirty = 1.
-	 * That includes the transformations referenced from the list.
+	 * That includes the transformations referenced from the list,
+	 * and the parent pointer, but excludes the parent's state.
 	 */
 	struct {
 		float x, y; /* surface translation on display */
 		int32_t width, height;
 
+		/* If not NULL, inherit transformation, and add to it. */
+		struct weston_surface *parent;
+		struct wl_listener parent_destroy_listener;
+
 		/* struct weston_transform */
 		struct wl_list transformation_list;
 
@@ -494,7 +504,7 @@ enum weston_key_state_update {
 void
 weston_version(int *major, int *minor, int *micro);
 
-void
+int
 weston_surface_update_transform(struct weston_surface *surface);
 
 void
@@ -679,6 +689,10 @@ void
 weston_surface_set_position(struct weston_surface *surface,
 			    float x, float y);
 
+void
+weston_surface_set_transform_parent(struct weston_surface *surface,
+				    struct weston_surface *parent);
+
 int
 weston_surface_is_mapped(struct weston_surface *surface);
 
diff --git a/src/shell.c b/src/shell.c
index 3da5321..299c60e 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -190,7 +190,6 @@ struct shell_surface {
 	struct {
 		struct wl_pointer_grab grab;
 		int32_t x, y;
-		struct weston_transform parent_transform;
 		int32_t initial_up;
 		struct wl_seat *seat;
 		uint32_t serial;
@@ -1909,35 +1908,11 @@ shell_map_popup(struct shell_surface *shsurf)
 	struct weston_surface *es = shsurf->surface;
 	struct weston_surface *parent = shsurf->parent;
 
-	/* Remove the old transform. We don't want to add it twice
-	 * otherwise Weston will go into an infinite loop when going
-	 * through the transforms. */
-	if (!wl_list_empty(&shsurf->popup.parent_transform.link)) {
-		wl_list_remove(&shsurf->popup.parent_transform.link);
-		wl_list_init(&shsurf->popup.parent_transform.link);
-	}
-
 	es->output = parent->output;
 	shsurf->popup.grab.interface = &popup_grab_interface;
 
-	weston_surface_update_transform(parent);
-	if (parent->transform.enabled) {
-		shsurf->popup.parent_transform.matrix =
-			parent->transform.matrix;
-	} else {
-		/* construct x, y translation matrix */
-		weston_matrix_init(&shsurf->popup.parent_transform.matrix);
-		shsurf->popup.parent_transform.matrix.type =
-			WESTON_MATRIX_TRANSFORM_TRANSLATE;
-		shsurf->popup.parent_transform.matrix.d[12] =
-			parent->geometry.x;
-		shsurf->popup.parent_transform.matrix.d[13] =
-			parent->geometry.y;
-	}
-	wl_list_insert(es->geometry.transformation_list.prev,
-		       &shsurf->popup.parent_transform.link);
-
 	shsurf->popup.initial_up = 0;
+	weston_surface_set_transform_parent(es, parent);
 	weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
 	weston_surface_update_transform(es);
 
@@ -2087,7 +2062,6 @@ create_shell_surface(void *shell, struct weston_surface *surface,
 	weston_matrix_init(&shsurf->rotation.rotation);
 
 	wl_list_init(&shsurf->workspace_transform.link);
-	wl_list_init(&shsurf->popup.parent_transform.link);
 
 	shsurf->type = SHELL_SURFACE_NONE;
 	shsurf->next_type = SHELL_SURFACE_NONE;
-- 
1.7.12.4



More information about the wayland-devel mailing list