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.zh...@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 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel