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

Signed-off-by: Xiong Zhang <xiong.y.zh...@intel.com>
---
 src/compositor-drm.c |   2 +
 src/shell.c          | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 137 insertions(+)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index ffdec89..e1da204 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 5ff27e7..c9035d4 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -4470,15 +4470,150 @@ 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)
+{
+       int32_t rel_x, rel_y;
+
+       clamp_coordinate(target_output, surface->output,
+                       &surface->geometry.x,
+                       &surface->geometry.y);
+
+       rel_x = surface->geometry.x - surface->output->x;
+       rel_y = surface->geometry.y - surface->output->y;
+
+       weston_surface_set_position(surface,
+                               target_output->x + rel_x,
+                               target_output->y + rel_y);
+}
+
 static void
 handle_output_destroy(struct wl_listener *listener, void *data)
 {
        struct output_destroy_listener *output_listener =
                container_of(listener, struct output_destroy_listener, 
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

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to