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 views will reassign output and get the right output. when we move output, the views on moved output should be moved also. Because of the page flip intervention, the weston_output_destroy() maybe asynchronous with update_outputs(). So we should change moving following outputs to output_destroy handler.
Signed-off-by: Xiong Zhang <[email protected]> --- src/compositor-drm.c | 8 ----- src/compositor.c | 18 +++++++++++ src/shell.c | 88 ++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 80 insertions(+), 34 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index c34fc1c..158a05f 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -2223,7 +2223,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; @@ -2273,17 +2272,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); } } diff --git a/src/compositor.c b/src/compositor.c index 32e72b1..246b02b 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -3128,6 +3128,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_view *view; + 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; @@ -3135,6 +3142,17 @@ 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(view, &layer->view_list, layer_link) { + if (view->output == output && + view->geometry.parent == NULL) + weston_view_set_position(view, + view->geometry.x + offset_x, + view->geometry.y + offset_y); + } + } } WL_EXPORT void diff --git a/src/shell.c b/src/shell.c index 16d22f1..3cf87fd 100644 --- a/src/shell.c +++ b/src/shell.c @@ -6084,11 +6084,17 @@ clamp_coordinate(struct weston_output *target_output, return result; } +/* if destroyed output is default output, marking views on this output */ +/* are dirty, so the next repaint will assign a new output to these views */ +/* if destroyed output isn't default output, move views on this output */ +/* to default output */ static void handle_view_on_destroyed_output(struct weston_view *view, - struct weston_output *target_output) + struct weston_output *target_output, + unsigned int move) { float new_x, new_y, original_x, original_y; + int result; /* the child window's view->geometry is a relative coordinate to */ /* parent view, no need to move child_view */ @@ -6098,17 +6104,23 @@ handle_view_on_destroyed_output(struct weston_view *view, original_x = view->geometry.x; original_y = view->geometry.y; - clamp_coordinate(target_output, view->output, - &original_x, &original_y); + result = clamp_coordinate(target_output, view->output, + &original_x, &original_y); - new_x = target_output->x + original_x - view->output->x; - new_y = target_output->y + original_y - view->output->y; - weston_view_set_position(view, new_x, new_y); + if (move) { + new_x = target_output->x + original_x - view->output->x; + new_y = target_output->y + original_y - view->output->y; + weston_view_set_position(view, new_x, new_y); + } else if (result) + weston_view_set_position(view, original_x, original_y); + else + weston_view_geometry_dirty(view); } static void normal_view_on_destroyed_output(struct shell_output *shell_output, - struct weston_output *target_output) + struct weston_output *target_output, + unsigned int move) { struct weston_output *del_output = shell_output->output; struct desktop_shell *shell = shell_output->shell; @@ -6142,7 +6154,8 @@ normal_view_on_destroyed_output(struct shell_output *shell_output, static void full_screen_view_on_destroyed_output(struct shell_output *shell_output, - struct weston_output *target_output) + struct weston_output *target_output, + unsigned int move) { struct weston_output *del_output = shell_output->output; struct desktop_shell *shell = shell_output->shell; @@ -6155,7 +6168,7 @@ full_screen_view_on_destroyed_output(struct shell_output *shell_output, wl_list_for_each(view, &shell->fullscreen_layer.view_list, layer_link) { /* fullscreen.black_view followed fullscreen.view */ if (shsurf && shsurf->fullscreen.black_view == view) { - handle_view_on_destroyed_output(view, target_output); + handle_view_on_destroyed_output(view, target_output, move); weston_view_configure(view, target_output->x, target_output->y, target_output->width, target_output->height); pixman_region32_fini(&view->surface->opaque); @@ -6168,7 +6181,7 @@ full_screen_view_on_destroyed_output(struct shell_output *shell_output, } shsurf = get_shell_surface(view->surface); if (shsurf->fullscreen_output == del_output) { - handle_view_on_destroyed_output(view, target_output); + handle_view_on_destroyed_output(view, target_output, move); shsurf->type = SHELL_SURFACE_NONE; set_fullscreen(shsurf, shsurf->fullscreen.type, @@ -6180,7 +6193,8 @@ full_screen_view_on_destroyed_output(struct shell_output *shell_output, static void pointer_on_destroyed_output(struct shell_output *shell_output, - struct weston_output *target_output) + struct weston_output *target_output, + unsigned int move) { struct weston_output *del_output = shell_output->output; struct weston_compositor *wc = del_output->compositor; @@ -6205,12 +6219,15 @@ pointer_on_destroyed_output(struct shell_output *shell_output, pointer->x = wl_fixed_from_double(pointer_x); pointer->y = wl_fixed_from_double(pointer_y); } - dx = wl_fixed_from_int(target_output->x - del_output->x); - dy = wl_fixed_from_int(target_output->y - del_output->y); - pointer->x += dx; - pointer->y += dy; + if (move) { + dx = wl_fixed_from_int(target_output->x - del_output->x); + dy = wl_fixed_from_int(target_output->y - del_output->y); + pointer->x += dx; + pointer->y += dy; + } if (pointer->sprite) - handle_view_on_destroyed_output(pointer->sprite, target_output); + handle_view_on_destroyed_output(pointer->sprite, + target_output, move); pointer->grab->interface->focus(pointer->grab); resource_list = &pointer->focus_resource_list; wl_resource_for_each(resource, resource_list) { @@ -6231,22 +6248,41 @@ handle_output_destroy(struct wl_listener *listener, void *data) container_of(listener, struct shell_output, destroy_listener); struct weston_output *output = (struct weston_output *)data; struct weston_compositor *wc = output->compositor; - struct weston_output *default_output, *target_output = NULL; + struct weston_output *default_output, *target_output = NULL, *tmp; + unsigned int move; + int x_offset = 0, y_offset = 0; 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) goto exit_handler; - target_output = default_output; + if (default_output != output) { + target_output = default_output; + move = 1; + } else { + target_output = container_of(output->link.next, + struct weston_output, link); + move = 0; + } + + normal_view_on_destroyed_output(shell_output, target_output, move); + full_screen_view_on_destroyed_output(shell_output, target_output, move); + pointer_on_destroyed_output(shell_output, target_output, move); - normal_view_on_destroyed_output(shell_output, target_output); - full_screen_view_on_destroyed_output(shell_output, target_output); - pointer_on_destroyed_output(shell_output, target_output); + if (move) + weston_output_schedule_repaint(target_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_damage(tmp); + } + if (tmp == output) + x_offset = output->width; + } exit_handler: wl_list_remove(&shell_output->destroy_listener.link); -- 1.8.3.2 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
