[PATCH 5/9] compositor: Output unplug in clone mode

Xiong Zhang xiong.y.zhang at intel.com
Thu Feb 13 23:17:40 PST 2014


If unplugged output is a slave output, no need to restore views.

If unplugged output is a master output which doesn't have slave
output related it, views will be restored the same as extend mode.

If unplugged output is a master output which have slave output
related it, one slave output will be upgraded to master output,
moving output following unplugged output isn't necessay,
views on unplugged output will be marked as dirty.

Signed-off-by: Xiong Zhang <xiong.y.zhang at intel.com>
---
 desktop-shell/shell.c |  13 ++++++-
 src/compositor-drm.c  | 103 +++++++++++++++++++++++++++++++++++++++++++++++---
 src/compositor.c      |  15 ++++++--
 src/compositor.h      |   1 +
 4 files changed, 122 insertions(+), 10 deletions(-)

diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 1e4a255..85987e5 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -5600,6 +5600,9 @@ handle_output_destroy(struct wl_listener *listener, void *data)
 	wl_list_remove(&output_listener->role_change_listener.link);
 	wl_list_remove(&output_listener->link);
 	free(output_listener);
+
+	/* Trigger compositor repaint */
+	weston_compositor_schedule_repaint(output_listener->output->compositor);
 }
 
 static void
@@ -5676,10 +5679,18 @@ setup_output_destroy_handler(struct weston_compositor *ec,
 							struct desktop_shell *shell)
 {
 	struct weston_output *output;
+	struct weston_output *clone_output;
 
 	wl_list_init(&shell->output_list);
-	wl_list_for_each(output, &ec->output_list, link)
+	wl_list_for_each(output, &ec->output_list, link) {
 		create_shell_output(shell, output);
+		if (!output->is_slave) {
+			wl_list_for_each(clone_output,
+					 &output->clone_output_list,
+					 link)
+				create_shell_output(shell, clone_output);
+		}
+	}
 
 	shell->output_create_listener.notify = handle_output_create;
 	wl_signal_add(&ec->output_created_signal,
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 1d8c983..842710f 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -1217,6 +1217,8 @@ drm_assign_planes(struct weston_output *output)
 
 static void
 drm_output_fini_pixman(struct drm_output *output);
+static void
+drm_output_destroy_with_slave(struct drm_output *output);
 
 static void
 drm_output_destroy(struct weston_output *output_base)
@@ -1259,6 +1261,15 @@ drm_output_destroy(struct weston_output *output_base)
 	weston_plane_release(&output->fb_plane);
 	weston_plane_release(&output->cursor_plane);
 
+	if (!output->base.is_slave &&
+	    !wl_list_empty(&output->base.clone_output_list)) {
+		drm_output_destroy_with_slave(output);
+
+		/* One slave is upgraded to master, Don't move
+		 * the following output.*/
+		output_base.dont_move = 1;
+	}
+
 	weston_output_destroy(&output->base);
 
 	free(output);
@@ -2420,6 +2431,73 @@ drm_output_add_slave(struct drm_compositor *ec)
 	}
 }
 
+/* The output with max width will be new_master. */
+static struct weston_output *
+find_new_master(struct weston_output *master)
+{
+	struct weston_output *new_master, *output;
+	int32_t max_width = 0;
+
+	new_master = NULL;
+	wl_list_for_each(output, &master->clone_output_list,
+			 link) {
+		if (output->current_mode->width > max_width) {
+			max_width = output->current_mode->width;
+			new_master = output;
+		}
+	}
+
+	return new_master;
+}
+
+/* If a master is unplugged, a output will be chosen from
+ * master->clone_output_list to replace the unplugged master.*/
+static void
+drm_output_destroy_with_slave(struct drm_output *output)
+{
+	struct weston_output *new_master, *tmp;
+	struct drm_output *clone_output, *next;
+	int    offset, move;
+
+	new_master = find_new_master(&output->base);
+
+	/* When old master's width is different from new master's
+	 * width, move the output following the old master. */
+	offset = output->base.width - new_master->width;
+	if (offset != 0) {
+		move = 0;
+		wl_list_for_each(tmp, &new_master->compositor->output_list,
+				 link) {
+			if (move == 1)
+				weston_output_move(tmp,
+						tmp->x - offset, tmp->y);
+
+			if (tmp == &output->base)
+				move = 1;
+		}
+	}
+
+	wl_list_remove(&new_master->link);
+	wl_list_insert(output->base.link.prev,
+		       &new_master->link);
+	new_master->is_slave = 0;
+
+	/* Link the remained clone output to new master */
+	wl_list_for_each_safe(clone_output, next,
+			 &output->base.clone_output_list,
+			 base.link) {
+		clone_output->base.master_output = new_master;
+		if (clone_output_need_adjust_mode(&clone_output->base))
+			adjust_clone_output_mode(&clone_output->base);
+
+		wl_list_remove(&clone_output->base.link);
+		wl_list_insert(new_master->clone_output_list.prev,
+			       &clone_output->base.link);
+	}
+
+	wl_signal_emit(&new_master->role_change_signal, new_master);
+}
+
 static int
 create_outputs(struct drm_compositor *ec, uint32_t option_connector,
 	       struct udev_device *drm_device)
@@ -2489,6 +2567,7 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 	struct drm_output *output, *next;
 	uint32_t connected = 0, disconnects = 0;
 	int i;
+	struct drm_output *clone_output, *found_output;
 
 	resources = drmModeGetResources(ec->drm.fd);
 	if (!resources) {
@@ -2525,12 +2604,26 @@ 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 (disconnects & (1 << output->connector_id)) {
-				disconnects &= ~(1 << output->connector_id);
-				weston_log("connector %d disconnected\n",
-				       output->connector_id);
-				drm_output_destroy(&output->base);
+			found_output = NULL;
+			if (disconnects & (1 << output->connector_id))
+				found_output = output;
+			else if (!output->base.is_slave) {
+				wl_list_for_each(clone_output,
+						 &output->base.clone_output_list,
+						 base.link) {
+					if (disconnects &
+					    (1 << clone_output->connector_id))
+						found_output = clone_output;
+				}
 			}
+
+			if (!found_output)
+				continue;
+
+			disconnects &= ~(1 << found_output->connector_id);
+			weston_log("connector %d disconnected\n",
+				   found_output->connector_id);
+			drm_output_destroy(&found_output->base);
 		}
 	}
 
diff --git a/src/compositor.c b/src/compositor.c
index 5c0f67d..5020fcf 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -3056,6 +3056,9 @@ weston_compositor_remove_output(struct weston_compositor *compositor,
 	struct weston_output *output;
 	int offset = 0;
 
+	if (remove_output->dont_move == 1)
+		return;
+
 	wl_list_for_each(output, &compositor->output_list, link) {
 		if (output == remove_output) {
 			offset = output->width;
@@ -3227,8 +3230,8 @@ weston_output_init_geometry(struct weston_output *output, int x, int y)
 WL_EXPORT void
 weston_output_move(struct weston_output *output, int x, int y)
 {
-	pixman_region32_t old_region;
 	struct wl_resource *resource;
+	struct weston_output *clone_output;
 
 	output->move_x = x - output->x;
 	output->move_y = y - output->y;
@@ -3236,9 +3239,6 @@ weston_output_move(struct weston_output *output, int x, int y)
 	if (output->move_x == 0 && output->move_y == 0)
 		return;
 
-	pixman_region32_init(&old_region);
-	pixman_region32_copy(&old_region, &output->region);
-
 	weston_output_init_geometry(output, x, y);
 
 	output->dirty = 1;
@@ -3257,6 +3257,13 @@ weston_output_move(struct weston_output *output, int x, int y)
 					output->make,
 					output->model,
 					output->transform);
+
+	/* Move slave_output associated with it. */
+	if (!output->is_slave) {
+		wl_list_for_each(clone_output, &output->clone_output_list,
+				 link)
+			weston_output_move(clone_output, x, y);
+	}
 }
 
 WL_EXPORT void
diff --git a/src/compositor.h b/src/compositor.h
index 0938078..6701081 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -217,6 +217,7 @@ struct weston_output {
 	struct weston_output *master_output;
 	struct wl_list clone_output_list;
 	struct wl_signal role_change_signal;
+	uint32_t dont_move;
 
 	void (*start_repaint_loop)(struct weston_output *output);
 	int (*repaint)(struct weston_output *output,
-- 
1.8.3.2



More information about the wayland-devel mailing list