if the unplugged output isn't the default output, move cursor and APP widow to default output
Signed-off-by: Xiong Zhang <xiong.y.zh...@intel.com> --- src/shell.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 186 insertions(+), 4 deletions(-) diff --git a/src/shell.c b/src/shell.c index dfcb525..16d22f1 100644 --- a/src/shell.c +++ b/src/shell.c @@ -6061,15 +6061,197 @@ 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_view_on_destroyed_output(struct weston_view *view, + struct weston_output *target_output) +{ + float new_x, new_y, original_x, original_y; + + /* the child window's view->geometry is a relative coordinate to */ + /* parent view, no need to move child_view */ + if (view->geometry.parent) + return; + + original_x = view->geometry.x; + original_y = view->geometry.y; + + 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); +} + +static void +normal_view_on_destroyed_output(struct shell_output *shell_output, + struct weston_output *target_output) +{ + struct weston_output *del_output = shell_output->output; + struct desktop_shell *shell = shell_output->shell; + struct weston_view *view; + unsigned int i; + struct workspace *ws; + struct shell_surface *shsurf; + enum shell_surface_type surface_type = SHELL_SURFACE_NONE; + struct wl_client *client; + + /*if view 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(view, &ws->layer.view_list, layer_link) { + if (view->output == del_output) { + handle_view_on_destroyed_output(view, target_output); + surface_type = get_shell_surface_type(view->surface); + /*if surface is maximized, resize it to target output*/ + if (surface_type == SHELL_SURFACE_MAXIMIZED) { + shsurf = get_shell_surface(view->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)); + } + } + } + } +} + +static void +full_screen_view_on_destroyed_output(struct shell_output *shell_output, + struct weston_output *target_output) +{ + struct weston_output *del_output = shell_output->output; + struct desktop_shell *shell = shell_output->shell; + struct weston_view *view; + struct shell_surface *shsurf; + + /*if view on destroyed output is fullscreen, resize it and associated black_view */ + /*to target_output */ + shsurf = NULL; + 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); + weston_view_configure(view, target_output->x, target_output->y, + target_output->width, target_output->height); + pixman_region32_fini(&view->surface->opaque); + pixman_region32_init_rect(&view->surface->opaque, 0, 0, + target_output->width, target_output->height); + pixman_region32_fini(&view->surface->input); + pixman_region32_init_rect(&view->surface->input, 0, 0, + target_output->width, target_output->height); + continue; + } + shsurf = get_shell_surface(view->surface); + if (shsurf->fullscreen_output == del_output) { + handle_view_on_destroyed_output(view, target_output); + shsurf->type = SHELL_SURFACE_NONE; + set_fullscreen(shsurf, + shsurf->fullscreen.type, + shsurf->fullscreen.framerate, + target_output); + } + } +} + +static void +pointer_on_destroyed_output(struct shell_output *shell_output, + struct weston_output *target_output) +{ + struct weston_output *del_output = shell_output->output; + struct weston_compositor *wc = del_output->compositor; + struct weston_seat *seat; + struct weston_pointer *pointer; + wl_fixed_t dx, dy; + float pointer_x, pointer_y; + struct wl_list *resource_list; + struct wl_resource *resource; + + /*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) + continue; + pointer = seat->pointer; + pointer_x = wl_fixed_to_double(pointer->x); + pointer_y = wl_fixed_to_double(pointer->y); + if (!pixman_region32_contains_point(&del_output->region, + pointer_x, pointer_y, NULL)) + continue; + if (clamp_coordinate(target_output, del_output, &pointer_x, &pointer_y)) { + 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 (pointer->sprite) + handle_view_on_destroyed_output(pointer->sprite, target_output); + pointer->grab->interface->focus(pointer->grab); + resource_list = &pointer->focus_resource_list; + wl_resource_for_each(resource, resource_list) { + weston_view_from_global_fixed(pointer->focus, + pointer->x, pointer->y, + &dx, &dy); + wl_pointer_send_motion(resource, + weston_compositor_get_time(), + dx, dy); + } + } +} + static void handle_output_destroy(struct wl_listener *listener, void *data) { - struct shell_output *output_listener = + struct shell_output *shell_output = 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; + + 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)) + goto exit_handler; + + target_output = default_output; + + 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); + + weston_output_schedule_repaint(target_output); - wl_list_remove(&output_listener->destroy_listener.link); - wl_list_remove(&output_listener->link); - free(output_listener); +exit_handler: + wl_list_remove(&shell_output->destroy_listener.link); + wl_list_remove(&shell_output->link); + free(shell_output); } static void -- 1.8.3.2 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel