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

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


if the unplugged output isn't the default output, move cursor surface
and APP widow to default output

V2: the surface->geometry of child window is a relative coordinate to
    parent surface, no need to move child surface. Moving parent surface
    will mark child surface dirty, so the child surface will be redrawed
    on next repainted

Signed-off-by: Xiong Zhang <xiong.y.zhang at intel.com>
---
 src/compositor-drm.c |   2 +
 src/shell.c          | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 141 insertions(+)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index b5c3051..654b082 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -2221,6 +2221,8 @@ 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/shell.c b/src/shell.c
index 2a9c024..e75bbbe 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -4470,15 +4470,154 @@ workspace_move_surface_down_binding(struct weston_seat *seat, uint32_t time,
 	take_surface_to_workspace_by_seat(shell, seat, new_index);
 }
 
+/* if (*x, *y) will be moved beyong target_output, clamp it*/
+static int
+clamp_coordinate(struct weston_output *target_output,
+			struct weston_output *original_output,
+			float *x, float *y)
+{
+	int32_t rel_x, rel_y;
+	int result = 0;
+
+	rel_x = *x - original_output->x;
+	rel_y = *y - original_output->y;
+
+	if (rel_x > target_output->width) {
+		*x = original_output->x + target_output->width / 4;
+		result = 1;
+	}
+	if (rel_y > target_output->height) {
+		*y = original_output->y + target_output->height / 4;
+		result = 1;
+	}
+	return result;
+}
+
+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;
+
+	/* the surface->geometry of child window is a relative coordinate to */
+	/* parent surface, no need to move child_surface */
+	if (surface->geometry.parent)
+		return;
+
+	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);
+}
+
 static void
 handle_output_destroy(struct wl_listener *listener, void *data)
 {
 	struct shell_output *output_listener =
 		container_of(listener, struct shell_output, destroy_listener);
+	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_surface  *surface;
+	unsigned int i;
+	struct workspace *ws;
+	struct shell_surface *shsurf;
+	enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
+	struct weston_seat *seat;
+	wl_fixed_t dx, dy;
+	float pointer_x, pointer_y;
+	struct wl_client *client;
 
 	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))
+		return;
+
+	target_output = default_output;
+
+	/*if surface on destroyed output, move it to target output*/
+	for (i = 0; i < shell->workspaces.num; i++) {
+		ws = get_workspace(shell, i);
+		wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
+			if (surface->output == output) {
+				surface_type = get_shell_surface_type(surface);
+				handle_surface_on_destroyed_output(surface, target_output);
+				/*if surface is maximized, resize it to target output*/
+				if (surface_type == SHELL_SURFACE_MAXIMIZED) {
+					shsurf = get_shell_surface(surface);
+					shsurf->type = SHELL_SURFACE_NONE;
+					client = wl_resource_get_client(shsurf->resource);
+					shell_surface_set_maximized(client,
+												shsurf->resource,
+						wl_resource_find_for_client(&target_output->resource_list, client));
+				}
+			}
+		}
+	}
+
+	/*if surface on destroyed output is fullscreen, resize it and associated black_surface */
+	/*to target_output */
+	shsurf = NULL;
+	wl_list_for_each(surface, &shell->fullscreen_layer.surface_list, layer_link) {
+		/* fullscreen.black_surface followed fullscreen.surface */
+		if (shsurf && shsurf->fullscreen.black_surface == surface) {
+			handle_surface_on_destroyed_output(surface, target_output);
+			weston_surface_configure(surface, target_output->x, target_output->y,
+									target_output->width, target_output->height);
+			pixman_region32_fini(&surface->opaque);
+			pixman_region32_init_rect(&surface->opaque, 0, 0,
+									target_output->width, target_output->height);
+			pixman_region32_fini(&surface->input);
+			pixman_region32_init_rect(&surface->input, 0, 0,
+									target_output->width, target_output->height);
+			continue;
+		}
+		shsurf = get_shell_surface(surface);
+		if (shsurf->fullscreen_output == output) {
+			handle_surface_on_destroyed_output(surface, target_output);
+			shsurf->type = SHELL_SURFACE_NONE;
+			set_fullscreen(shsurf,
+						   shsurf->fullscreen.type,
+						   shsurf->fullscreen.framerate,
+						   target_output);
+		}
+	}
+
+	/*if cursor exist in destroyed output, issue a fake motion to move cursor to target_output*/
+	wl_list_for_each(seat, &wc->seat_list, link) {
+		if (seat->pointer) {
+			pointer_x = wl_fixed_to_double(seat->pointer->x);
+			pointer_y = wl_fixed_to_double(seat->pointer->y);
+			if (pixman_region32_contains_point(&output->region,
+								pointer_x, pointer_y, NULL)) {
+				if (clamp_coordinate(target_output, output, &pointer_x, &pointer_y)) {
+					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);
+				seat->pointer->grab->interface->focus(seat->pointer->grab);
+				seat->pointer->grab->interface->motion(seat->pointer->grab,
+									weston_compositor_get_time());
+			}
+		}
+	}
 }
 
 static void
-- 
1.8.3.2



More information about the wayland-devel mailing list