[PATCH v2 4/6] shell: restroe app run on default and unplugged output

Xiong Zhang xiong.y.zhang at intel.com
Wed Oct 23 07:58:34 CEST 2013


if the unplugged output is the first default output, the second
output will move to the first working as default output. Mark
the surface on unplaugged output as dirty, so on the next output
repaint, these surface will reassign output and get the right
output.
At the same time when moving output, the surface on moved output
should be moved also.

V2: because of the page flip intervention, the weston_output_destroy()
    maybe asynchronous with update_outputs(). So move
	weston_output_move() calling function from update_outputs()
	to handle_output_destroy()

Signed-off-by: Xiong Zhang <xiong.y.zhang at intel.com>
---
 src/compositor-drm.c | 10 --------
 src/compositor.c     | 17 +++++++++++++
 src/shell.c          | 71 ++++++++++++++++++++++++++++++++++++++--------------
 3 files changed, 69 insertions(+), 29 deletions(-)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 654b082..4481f33 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -2152,7 +2152,6 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 	drmModeRes *resources;
 	struct drm_output *output, *next;
 	int x = 0, y = 0;
-	int x_offset = 0, y_offset = 0;
 	uint32_t connected = 0, disconnects = 0;
 	int i;
 
@@ -2202,17 +2201,10 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 	if (disconnects) {
 		wl_list_for_each_safe(output, next, &ec->base.output_list,
 				      base.link) {
-			if (x_offset != 0 || y_offset != 0) {
-				weston_output_move(&output->base,
-						 output->base.x - x_offset,
-						 output->base.y - y_offset);
-			}
-
 			if (disconnects & (1 << output->connector_id)) {
 				disconnects &= ~(1 << output->connector_id);
 				weston_log("connector %d disconnected\n",
 				       output->connector_id);
-				x_offset += output->base.width;
 				drm_output_destroy(&output->base);
 			}
 		}
@@ -2221,8 +2213,6 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 	/* FIXME: handle zero outputs, without terminating */	
 	if (ec->connector_allocator == 0)
 		wl_display_terminate(ec->base.wl_display);
-	else
-		weston_compositor_schedule_repaint(&ec->base);
 }
 
 static int
diff --git a/src/compositor.c b/src/compositor.c
index 9eb3d5d..c67c3b4 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2832,6 +2832,13 @@ weston_output_transform_scale_init(struct weston_output *output, uint32_t transf
 WL_EXPORT void
 weston_output_move(struct weston_output *output, int x, int y)
 {
+	struct weston_surface *surface;
+	struct weston_layer   *layer;
+	int offset_x, offset_y;
+
+	offset_x = x - output->x;
+	offset_y = y - output->y;
+
 	output->x = x;
 	output->y = y;
 
@@ -2839,6 +2846,16 @@ weston_output_move(struct weston_output *output, int x, int y)
 	pixman_region32_init_rect(&output->region, x, y,
 				  output->width,
 				  output->height);
+	output->dirty = 1;
+
+	wl_list_for_each(layer, &output->compositor->layer_list, link) {
+		wl_list_for_each(surface, &layer->surface_list, layer_link) {
+			if (surface->output == output)
+				weston_surface_set_position(surface,
+						surface->geometry.x + offset_x,
+						surface->geometry.y + offset_y);
+		}
+	}
 }
 
 WL_EXPORT void
diff --git a/src/shell.c b/src/shell.c
index e75bbbe..0a95243 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -4493,26 +4493,41 @@ clamp_coordinate(struct weston_output *target_output,
 	return result;
 }
 
+/* if destroyed output is default output, marking surface run on this output */
+/* is dirty, so that the next repaint will assign this surface to right output */
+/* if destroyed output isn't default output, move surface run on this output */
+/* to default output */
 static void
 handle_surface_on_destroyed_output(struct weston_surface *surface,
 					struct weston_output *target_output)
 {
 	float new_x, new_y, original_x, original_y;
+	struct weston_output *default_output;
+	int result;
 
 	/* the surface->geometry of child window is a relative coordinate to */
 	/* parent surface, no need to move child_surface */
 	if (surface->geometry.parent)
 		return;
 
+	default_output = get_default_output(surface->compositor);
+
 	original_x = surface->geometry.x;
 	original_y = surface->geometry.y;
 
-	clamp_coordinate(target_output, surface->output,
-			&original_x, &original_y);
-
-	new_x = target_output->x + original_x - surface->output->x;
-	new_y = target_output->y + original_y - surface->output->y;
-	weston_surface_set_position(surface, new_x, new_y);
+	result = clamp_coordinate(target_output, surface->output,
+						&original_x, &original_y);
+
+	if (target_output == default_output) {
+		new_x = target_output->x + original_x - surface->output->x;
+		new_y = target_output->y + original_y - surface->output->y;
+		weston_surface_set_position(surface, new_x, new_y);
+	} else if (result) {
+		new_x = original_x;
+		new_y = original_y;
+		weston_surface_set_position(surface, new_x, new_y);
+	} else
+		weston_surface_geometry_dirty(surface);
 }
 
 static void
@@ -4523,7 +4538,7 @@ handle_output_destroy(struct wl_listener *listener, void *data)
 	struct weston_output *output = (struct weston_output *)data;
 	struct desktop_shell *shell = output_listener->shell;
 	struct weston_compositor *wc = output->compositor;
-	struct weston_output *default_output, *target_output = NULL;
+	struct weston_output *default_output, *target_output = NULL, *tmp;
 	struct weston_surface  *surface;
 	unsigned int i;
 	struct workspace *ws;
@@ -4533,19 +4548,22 @@ handle_output_destroy(struct wl_listener *listener, void *data)
 	wl_fixed_t dx, dy;
 	float pointer_x, pointer_y;
 	struct wl_client *client;
+	int x_offset = 0, y_offset = 0;
 
 	wl_list_remove(&output_listener->destroy_listener.link);
 	wl_list_remove(&output_listener->link);
 	free(output_listener);
 
 	default_output = get_default_output(wc);
-	/* if default output is the only output in output_list, or destroyed
-	   output is default output, return*/
-	if ((default_output->link.prev == default_output->link.next) ||
-		(default_output == output))
+	/* if default output is the only output in output_list, return*/
+	if (default_output->link.prev == default_output->link.next)
 		return;
 
-	target_output = default_output;
+	if (default_output != output)
+		target_output = default_output;
+	else
+		target_output = container_of(output->link.next,
+					struct weston_output, link);
 
 	/*if surface on destroyed output, move it to target output*/
 	for (i = 0; i < shell->workspaces.num; i++) {
@@ -4606,18 +4624,33 @@ handle_output_destroy(struct wl_listener *listener, void *data)
 					seat->pointer->x = wl_fixed_from_double(pointer_x);
 					seat->pointer->y = wl_fixed_from_double(pointer_y);
 				}
-				dx = wl_fixed_from_int(target_output->x - output->x);
-				dy = wl_fixed_from_int(target_output->y - output->y);
-				seat->pointer->x += dx;
-				seat->pointer->y += dy;
-				if (seat->pointer->sprite)
-					handle_surface_on_destroyed_output(seat->pointer->sprite, target_output);
+				if (target_output == default_output) {
+					dx = wl_fixed_from_int(target_output->x - output->x);
+					dy = wl_fixed_from_int(target_output->y - output->y);
+					seat->pointer->x += dx;
+					seat->pointer->y += dy;
+					if (seat->pointer->sprite)
+						handle_surface_on_destroyed_output(seat->pointer->sprite, target_output);
+				}
 				seat->pointer->grab->interface->focus(seat->pointer->grab);
 				seat->pointer->grab->interface->motion(seat->pointer->grab,
-									weston_compositor_get_time());
+										weston_compositor_get_time());
 			}
 		}
 	}
+
+	if (target_output == default_output)
+		weston_output_schedule_repaint(target_output);
+
+	/* move the following output */
+	wl_list_for_each(tmp, &wc->output_list, link) {
+		if (x_offset != 0 || y_offset != 0) {
+			weston_output_move(tmp, tmp->x - x_offset, tmp->y - y_offset);
+			weston_output_schedule_repaint(tmp);
+		}
+		if (tmp == output)
+			x_offset = output->width;
+	}
 }
 
 static void
-- 
1.8.3.2



More information about the wayland-devel mailing list