From 4539b0874f8e8f21d402ef2c3894e52c3513973b Mon Sep 17 00:00:00 2001 From: Alex Wu Date: Thu, 1 Mar 2012 12:57:46 +0800 Subject: [PATCH 01/10] shell: Add implementation of fullscreen. Undo fullscreen in shell_unset_fullscreen(), do all the stacking order in shell_stack_fullscreen(), and configure black surface, method in shell_configure_fullscreen(). Signed-off-by: Alex Wu Signed-off-by: Juan Zhao --- src/shell.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 176 insertions(+), 21 deletions(-) diff --git a/src/shell.c b/src/shell.c index 01e5cf63..accc1c56 100644 --- a/src/shell.c +++ b/src/shell.c @@ -94,6 +94,7 @@ struct shell_surface { enum shell_surface_type type; int32_t saved_x, saved_y; + bool saved_position_valid; struct { struct weston_transform transform; @@ -108,6 +109,13 @@ struct shell_surface { int32_t initial_up; } popup; + struct { + enum wl_shell_surface_fullscreen_method type; + struct weston_transform transform; /* matrix from x, y */ + uint32_t framerate; + struct weston_surface *black_surface; + } fullscreen; + struct weston_output *fullscreen_output; struct weston_output *output; struct wl_list link; @@ -133,6 +141,10 @@ struct rotate_grab { } center; }; +static void +center_on_output(struct weston_surface *surface, + struct weston_output *output); + static void shell_configuration(struct wl_shell *shell) { @@ -303,7 +315,8 @@ weston_surface_resize(struct shell_surface *shsurf, { struct weston_resize_grab *resize; - /* FIXME: Reject if fullscreen */ + if (shsurf->type == SHELL_SURFACE_FULLSCREEN) + return 0; if (edges == 0 || edges > 15 || (edges & 3) == 3 || (edges & 12) == 12) @@ -334,7 +347,8 @@ shell_surface_resize(struct wl_client *client, struct wl_resource *resource, struct weston_input_device *wd = input_resource->data; struct shell_surface *shsurf = resource->data; - /* FIXME: Reject if fullscreen */ + if (shsurf->type == SHELL_SURFACE_FULLSCREEN) + return; if (wd->input_device.button_count == 0 || wd->input_device.grab_time != time || @@ -352,15 +366,28 @@ get_default_output(struct weston_compositor *compositor) struct weston_output, link); } +static void +shell_unset_fullscreen(struct shell_surface *shsurf) +{ + /* undo all fullscreen things here */ + shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT; + shsurf->fullscreen.framerate = 0; + wl_list_remove(&shsurf->fullscreen.transform.link); + wl_list_init(&shsurf->fullscreen.transform.link); + weston_surface_destroy(shsurf->fullscreen.black_surface); + shsurf->fullscreen.black_surface = NULL; + shsurf->fullscreen_output = NULL; + shsurf->surface->force_configure = 1; + weston_surface_set_position(shsurf->surface, + shsurf->saved_x, shsurf->saved_y); +} + static int reset_shell_surface_type(struct shell_surface *surface) { switch (surface->type) { case SHELL_SURFACE_FULLSCREEN: - weston_surface_set_position(surface->surface, - surface->saved_x, - surface->saved_y); - surface->fullscreen_output = NULL; + shell_unset_fullscreen(surface); break; case SHELL_SURFACE_MAXIMIZED: surface->output = get_default_output(surface->surface->compositor); @@ -417,7 +444,7 @@ shell_surface_set_transient(struct wl_client *client, if (reset_shell_surface_type(shsurf)) return; - /* assign to parents output */ + /* assign to parents output */ shsurf->output = pes->output; weston_surface_set_position(es, pes->geometry.x + x, pes->geometry.y + y); @@ -474,6 +501,7 @@ shell_surface_set_maximized(struct wl_client *client, shsurf->saved_x = es->geometry.x; shsurf->saved_y = es->geometry.y; + shsurf->saved_position_valid = true; wlshell = shell_surface_get_shell(shsurf); panel_height = get_output_panel_height(wlshell, es->output); @@ -487,6 +515,96 @@ shell_surface_set_maximized(struct wl_client *client, shsurf->type = SHELL_SURFACE_MAXIMIZED; } +static struct weston_surface * +create_black_surface(struct weston_compositor *ec, + GLfloat x, GLfloat y, int w, int h) +{ + struct weston_surface *surface = NULL; + + surface = weston_surface_create(ec); + if (surface == NULL) { + fprintf(stderr, "no memory\n"); + return NULL; + } + + weston_surface_configure(surface, x, y, w, h); + weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1); + return surface; +} + +/* Create black surface and append it to the associated fullscreen surface. + * Handle size dismatch and positioning according to the method. */ +static void +shell_configure_fullscreen(struct shell_surface *shsurf) +{ + struct weston_output *output = shsurf->fullscreen_output; + struct weston_surface *surface = shsurf->surface; + struct weston_matrix *matrix; + float scale; + + center_on_output(surface, output); + + if (!shsurf->fullscreen.black_surface) + shsurf->fullscreen.black_surface = create_black_surface(surface->compositor, + output->x, output->y, + output->current->width, output->current->height); + wl_list_remove(&shsurf->fullscreen.black_surface->link); + wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link); + shsurf->fullscreen.black_surface->output = output; + + switch (shsurf->fullscreen.type) { + case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT: + break; + case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE: + matrix = &shsurf->fullscreen.transform.matrix; + weston_matrix_init(matrix); + scale = (float)output->current->width/(float)surface->geometry.width; + weston_matrix_scale(matrix, scale, scale, 1); + wl_list_remove(&shsurf->fullscreen.transform.link); + wl_list_insert(surface->geometry.transformation_list.prev, + &shsurf->fullscreen.transform.link); + weston_surface_set_position(surface, output->x, output->y); + break; + case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER: + break; + case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL: + break; + default: + break; + } +} + +/* make the fullscreen and black surface at the top */ +static void +shell_stack_fullscreen(struct shell_surface *shsurf) +{ + struct weston_surface *surface = shsurf->surface; + struct wl_shell *shell = shell_surface_get_shell(shsurf); + struct wl_list *list; + + wl_list_remove(&surface->link); + wl_list_remove(&shsurf->fullscreen.black_surface->link); + + if (shell->locked) { + wl_list_insert(&shell->hidden_surface_list, &surface->link); + wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link); + } else { + list = weston_compositor_top(surface->compositor); + wl_list_insert(list, &surface->link); + wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link); + + weston_surface_damage(surface); + weston_surface_damage(shsurf->fullscreen.black_surface); + } +} + +static void +shell_map_fullscreen(struct shell_surface *shsurf) +{ + shell_configure_fullscreen(shsurf); + shell_stack_fullscreen(shsurf); +} + static void shell_surface_set_fullscreen(struct wl_client *client, struct wl_resource *resource, @@ -496,20 +614,26 @@ shell_surface_set_fullscreen(struct wl_client *client, { struct shell_surface *shsurf = resource->data; struct weston_surface *es = shsurf->surface; - struct weston_output *output; + + if (output_resource) + shsurf->output = output_resource->data; + else + shsurf->output = get_default_output(es->compositor); if (reset_shell_surface_type(shsurf)) return; - /* FIXME: Fullscreen on first output */ - /* FIXME: Handle output going away */ - output = get_default_output(es->compositor); + shsurf->fullscreen_output = shsurf->output; + shsurf->fullscreen.type = method; + shsurf->fullscreen.framerate = framerate; + shsurf->type = SHELL_SURFACE_FULLSCREEN; shsurf->saved_x = es->geometry.x; shsurf->saved_y = es->geometry.y; - shsurf->output = output; - shsurf->fullscreen_output = output; - shsurf->type = SHELL_SURFACE_FULLSCREEN; + shsurf->saved_position_valid = true; + + if (es->output) + shsurf->surface->force_configure = 1; wl_resource_post_event(resource, WL_SHELL_SURFACE_CONFIGURE, @@ -715,7 +839,13 @@ shell_get_shell_surface(struct wl_client *client, (void (**)(void)) &shell_surface_implementation; shsurf->resource.data = shsurf; + shsurf->saved_position_valid = false; shsurf->surface = surface; + shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT; + shsurf->fullscreen.framerate = 0; + shsurf->fullscreen.black_surface = NULL; + wl_list_init(&shsurf->fullscreen.transform.link); + shsurf->surface_destroy_listener.func = shell_handle_surface_destroy; wl_list_insert(surface->surface.resource.destroy_listener_list.prev, &shsurf->surface_destroy_listener.link); @@ -1274,6 +1404,9 @@ activate(struct weston_shell *base, struct weston_surface *es, &es->link); } break; + case SHELL_SURFACE_FULLSCREEN: + /* should on top of panels */ + break; default: if (!shell->locked) { list = weston_compositor_top(compositor); @@ -1290,14 +1423,23 @@ activate(struct weston_shell *base, struct weston_surface *es, static void click_to_activate_binding(struct wl_input_device *device, - uint32_t time, uint32_t key, + uint32_t time, uint32_t key, uint32_t button, uint32_t state, void *data) { struct weston_input_device *wd = (struct weston_input_device *) device; struct weston_compositor *compositor = data; struct weston_surface *focus; + struct weston_surface *upper; focus = (struct weston_surface *) device->pointer_focus; + upper = container_of(focus->link.prev, struct weston_surface, link); + if (focus->link.prev != &compositor->surface_list && + get_shell_surface_type(upper) == SHELL_SURFACE_FULLSCREEN) { + printf("%s: focus is black surface, raise its fullscreen surface\n", __func__); + shell_stack_fullscreen(get_shell_surface(upper)); + focus = upper; + } + if (state && focus && device->pointer_grab == &device->default_pointer_grab) activate(compositor->shell, focus, wd, time); } @@ -1444,11 +1586,13 @@ map(struct weston_shell *base, struct weston_surface *surface, 10 + random() % 400); break; case SHELL_SURFACE_SCREENSAVER: - case SHELL_SURFACE_FULLSCREEN: center_on_output(surface, shsurf->fullscreen_output); break; + case SHELL_SURFACE_FULLSCREEN: + shell_map_fullscreen(shsurf); + break; case SHELL_SURFACE_MAXIMIZED: - /*use surface configure to set the geometry*/ + /* use surface configure to set the geometry */ panel_height = get_output_panel_height(shell,surface->output); weston_surface_set_position(surface, surface->output->x, surface->output->y + panel_height); @@ -1496,6 +1640,9 @@ map(struct weston_shell *base, struct weston_surface *surface, } do_configure = 0; break; + case SHELL_SURFACE_FULLSCREEN: + do_configure = 1; + break; case SHELL_SURFACE_NONE: do_configure = 0; break; @@ -1526,7 +1673,7 @@ map(struct weston_shell *base, struct weston_surface *surface, if (!shell->locked) activate(base, surface, (struct weston_input_device *) - compositor->input_device, + compositor->input_device, weston_compositor_get_time()); break; default: @@ -1543,6 +1690,7 @@ configure(struct weston_shell *base, struct weston_surface *surface, { struct wl_shell *shell = container_of(base, struct wl_shell, shell); enum shell_surface_type surface_type = SHELL_SURFACE_NONE; + enum shell_surface_type prev_surface_type = SHELL_SURFACE_NONE; struct shell_surface *shsurf; shsurf = get_shell_surface(surface); @@ -1557,22 +1705,29 @@ configure(struct weston_shell *base, struct weston_surface *surface, switch (surface_type) { case SHELL_SURFACE_SCREENSAVER: - case SHELL_SURFACE_FULLSCREEN: center_on_output(surface, shsurf->fullscreen_output); break; + case SHELL_SURFACE_FULLSCREEN: + shell_configure_fullscreen(shsurf); + if (prev_surface_type != SHELL_SURFACE_FULLSCREEN) + shell_stack_fullscreen(shsurf); + break; case SHELL_SURFACE_MAXIMIZED: - /*setting x, y and using configure to change that geometry*/ + /* setting x, y and using configure to change that geometry */ surface->geometry.x = surface->output->x; surface->geometry.y = surface->output->y + get_output_panel_height(shell,surface->output); break; + case SHELL_SURFACE_TOPLEVEL: + break; default: break; } - /* XXX: would a fullscreen surface need the same handling? */ + /* XXX: would a fullscreen surface need the same handling? */ if (surface->output) { weston_surface_assign_output(surface); + weston_compositor_repick(surface->compositor); if (surface_type == SHELL_SURFACE_SCREENSAVER) surface->output = shsurf->output; From 6ddcdaeb983edb3b952e32909d27458e28bdedb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 28 Feb 2012 22:31:58 -0500 Subject: [PATCH 02/10] compositor: Store opaque clip for previous frame in weston_surface --- src/compositor-drm.c | 5 +++-- src/compositor-wayland.c | 5 +++-- src/compositor-x11.c | 5 +++-- src/compositor.c | 48 ++++++++++++++++++++-------------------- src/compositor.h | 9 +++++--- 5 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index cfaad15d..d2a5652b 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -214,7 +214,8 @@ drm_output_prepare_scanout_surface(struct drm_output *output) } static void -drm_output_repaint(struct weston_output *output_base) +drm_output_repaint(struct weston_output *output_base, + pixman_region32_t *damage) { struct drm_output *output = (struct drm_output *) output_base; struct drm_compositor *compositor = @@ -235,7 +236,7 @@ drm_output_repaint(struct weston_output *output_base) drm_output_prepare_scanout_surface(output); wl_list_for_each_reverse(surface, &compositor->base.surface_list, link) - weston_surface_draw(surface, &output->base); + weston_surface_draw(surface, &output->base, damage); glFlush(); diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c index f8b5a32c..f23c357c 100644 --- a/src/compositor-wayland.c +++ b/src/compositor-wayland.c @@ -329,7 +329,8 @@ static const struct wl_callback_listener frame_listener = { }; static void -wayland_output_repaint(struct weston_output *output_base) +wayland_output_repaint(struct weston_output *output_base, + pixman_region32_t *damage) { struct wayland_output *output = (struct wayland_output *) output_base; struct wayland_compositor *compositor = @@ -344,7 +345,7 @@ wayland_output_repaint(struct weston_output *output_base) } wl_list_for_each_reverse(surface, &compositor->base.surface_list, link) - weston_surface_draw(surface, &output->base); + weston_surface_draw(surface, &output->base, damage); draw_border(output); diff --git a/src/compositor-x11.c b/src/compositor-x11.c index 53998d24..c227063b 100644 --- a/src/compositor-x11.c +++ b/src/compositor-x11.c @@ -186,7 +186,8 @@ x11_compositor_fini_egl(struct x11_compositor *compositor) } static void -x11_output_repaint(struct weston_output *output_base) +x11_output_repaint(struct weston_output *output_base, + pixman_region32_t *damage) { struct x11_output *output = (struct x11_output *)output_base; struct x11_compositor *compositor = @@ -200,7 +201,7 @@ x11_output_repaint(struct weston_output *output_base) } wl_list_for_each_reverse(surface, &compositor->base.surface_list, link) - weston_surface_draw(surface, &output->base); + weston_surface_draw(surface, &output->base, damage); eglSwapBuffers(compositor->base.display, output->egl_surface); diff --git a/src/compositor.c b/src/compositor.c index 069ea74d..434c4931 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -225,6 +225,7 @@ weston_surface_create(struct weston_compositor *compositor) pixman_region32_init(&surface->damage); pixman_region32_init(&surface->opaque); + pixman_region32_init(&surface->clip); undef_region(&surface->input); pixman_region32_init(&surface->transform.opaque); wl_list_init(&surface->frame_callback_list); @@ -647,6 +648,7 @@ destroy_surface(struct wl_resource *resource) pixman_region32_fini(&surface->transform.boundingbox); pixman_region32_fini(&surface->damage); pixman_region32_fini(&surface->opaque); + pixman_region32_fini(&surface->clip); if (!region_is_undefined(&surface->input)) pixman_region32_fini(&surface->input); @@ -762,7 +764,8 @@ texture_region(struct weston_surface *es, pixman_region32_t *region) } WL_EXPORT void -weston_surface_draw(struct weston_surface *es, struct weston_output *output) +weston_surface_draw(struct weston_surface *es, struct weston_output *output, + pixman_region32_t *damage) { struct weston_compositor *ec = es->compositor; GLfloat *v; @@ -771,12 +774,9 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output) int n; pixman_region32_init(&repaint); - pixman_region32_intersect(&repaint, &es->transform.boundingbox, - &output->region); - pixman_region32_intersect(&repaint, &repaint, &es->damage); - - /* Clear damage, assume outputs do not overlap. */ - pixman_region32_subtract(&es->damage, &es->damage, &output->region); + pixman_region32_intersect(&repaint, + &es->transform.boundingbox, damage); + pixman_region32_subtract(&repaint, &repaint, &es->clip); if (!pixman_region32_not_empty(&repaint)) goto out; @@ -937,7 +937,7 @@ weston_output_repaint(struct weston_output *output, int msecs) struct weston_surface *es; struct weston_animation *animation, *next; struct weston_frame_callback *cb, *cnext; - pixman_region32_t opaque, new_damage, total_damage; + pixman_region32_t opaque, new_damage, output_damage; int32_t width, height; weston_compositor_update_drag_surfaces(ec); @@ -948,9 +948,6 @@ weston_output_repaint(struct weston_output *output, int msecs) output->border.top + output->border.bottom; glViewport(0, 0, width, height); - pixman_region32_init(&new_damage); - pixman_region32_init(&opaque); - wl_list_for_each(es, &ec->surface_list, link) /* Update surface transform now to avoid calling it ever * again from the repaint sub-functions. */ @@ -965,33 +962,36 @@ weston_output_repaint(struct weston_output *output, int msecs) */ output->assign_planes(output); + pixman_region32_init(&new_damage); + pixman_region32_init(&opaque); + wl_list_for_each(es, &ec->surface_list, link) { pixman_region32_subtract(&es->damage, &es->damage, &opaque); pixman_region32_union(&new_damage, &new_damage, &es->damage); + empty_region(&es->damage); + pixman_region32_copy(&es->clip, &opaque); pixman_region32_union(&opaque, &opaque, &es->transform.opaque); } - pixman_region32_init(&total_damage); - pixman_region32_union(&total_damage, &new_damage, - &output->previous_damage); - pixman_region32_intersect(&output->previous_damage, - &new_damage, &output->region); + pixman_region32_union(&ec->damage, &ec->damage, &new_damage); + + pixman_region32_init(&output_damage); + pixman_region32_union(&output_damage, + &ec->damage, &output->previous_damage); + pixman_region32_copy(&output->previous_damage, &ec->damage); + pixman_region32_intersect(&output_damage, + &output_damage, &output->region); + pixman_region32_subtract(&ec->damage, &ec->damage, &output->region); pixman_region32_fini(&opaque); pixman_region32_fini(&new_damage); - wl_list_for_each(es, &ec->surface_list, link) { - pixman_region32_copy(&es->damage, &total_damage); - pixman_region32_subtract(&total_damage, - &total_damage, &es->transform.opaque); - } - if (output->dirty) weston_output_update_matrix(output); - output->repaint(output); + output->repaint(output, &output_damage); - pixman_region32_fini(&total_damage); + pixman_region32_fini(&output_damage); output->repaint_needed = 0; diff --git a/src/compositor.h b/src/compositor.h index 8c57e4f4..9f29c4b5 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -91,7 +91,8 @@ struct weston_output { struct weston_mode *current; struct wl_list mode_list; - void (*repaint)(struct weston_output *output); + void (*repaint)(struct weston_output *output, + pixman_region32_t *damage); void (*destroy)(struct weston_output *output); void (*assign_planes)(struct weston_output *output); @@ -198,8 +199,8 @@ struct weston_compositor { int idle_time; /* effective timeout, s */ /* Repaint state. */ - struct timespec previous_swap; struct wl_array vertices, indices; + pixman_region32_t damage; uint32_t focus; @@ -260,6 +261,7 @@ struct weston_surface { struct wl_surface surface; struct weston_compositor *compositor; GLuint texture; + pixman_region32_t clip; pixman_region32_t damage; pixman_region32_t opaque; pixman_region32_t input; @@ -341,7 +343,8 @@ void weston_surface_activate(struct weston_surface *surface, struct weston_input_device *device, uint32_t time); void -weston_surface_draw(struct weston_surface *es, struct weston_output *output); +weston_surface_draw(struct weston_surface *es, + struct weston_output *output, pixman_region32_t *damage); void notify_motion(struct wl_input_device *device, From 1e8321213d92097682ab4bb692c19c6289fe72fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 28 Feb 2012 22:47:14 -0500 Subject: [PATCH 03/10] compositor: Implement damage_below by using the new compositor->damage We can now clip the surface bounding box against the previous frame opaque clip, and then just union the result (visible damage) into compositor->damage immediately. --- src/compositor.c | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 434c4931..7e4e7a60 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -282,17 +282,15 @@ surface_to_global_float(struct weston_surface *surface, WL_EXPORT void weston_surface_damage_below(struct weston_surface *surface) { - struct weston_surface *below; - - if (surface->output == NULL) - return; - - if (surface->link.next == &surface->compositor->surface_list) - return; + struct weston_compositor *compositor = surface->compositor; + pixman_region32_t damage; - below = container_of(surface->link.next, struct weston_surface, link); - pixman_region32_union(&below->damage, &below->damage, - &surface->transform.boundingbox); + pixman_region32_init(&damage); + pixman_region32_subtract(&damage, &surface->transform.boundingbox, + &surface->clip); + pixman_region32_union(&compositor->damage, + &compositor->damage, &damage); + pixman_region32_fini(&damage); } static void @@ -511,21 +509,6 @@ weston_surface_damage(struct weston_surface *surface) weston_compositor_schedule_repaint(surface->compositor); } -static void -weston_surface_flush_damage(struct weston_surface *surface) -{ - struct weston_surface *below; - - if (surface->output && - surface->link.next != &surface->compositor->surface_list) { - below = container_of(surface->link.next, - struct weston_surface, link); - - pixman_region32_union(&below->damage, - &below->damage, &surface->damage); - } -} - WL_EXPORT void weston_surface_configure(struct weston_surface *surface, GLfloat x, GLfloat y, int width, int height) @@ -615,7 +598,6 @@ static void weston_surface_unmap(struct weston_surface *surface) { weston_surface_damage_below(surface); - weston_surface_flush_damage(surface); surface->output = NULL; wl_list_remove(&surface->link); weston_compositor_repick(surface->compositor); From 944236a71234d8ecd86c43b6204a4972f003eb68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 28 Feb 2012 23:07:47 -0500 Subject: [PATCH 04/10] compositor: Just damage compositor->damage in weston_output_damage() --- src/compositor.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 7e4e7a60..679894b7 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -865,14 +865,9 @@ WL_EXPORT void weston_output_damage(struct weston_output *output) { struct weston_compositor *compositor = output->compositor; - struct weston_surface *es; - - if (wl_list_empty(&compositor->surface_list)) - return; - es = container_of(compositor->surface_list.next, - struct weston_surface, link); - pixman_region32_union(&es->damage, &es->damage, &output->region); + pixman_region32_union(&compositor->damage, + &compositor->damage, &output->region); weston_compositor_schedule_repaint(compositor); } From 3be2ce9e494aa371b4ab37d7c6afd9d235b64bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 29 Feb 2012 12:42:35 -0500 Subject: [PATCH 05/10] compositor: Organize surface stack using new struct weston_layer The surface data structure is now a list of list of surfaces. The core compositor defines the fade and cursor layer, and it's up to the shell to provide more layers for the various surface types it implements. --- src/compositor.c | 71 ++++++++--------- src/compositor.h | 16 ++++ src/shell.c | 198 +++++++++++++++++------------------------------ 3 files changed, 123 insertions(+), 162 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 679894b7..95513da1 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -211,6 +211,7 @@ weston_surface_create(struct weston_compositor *compositor) wl_list_init(&surface->surface.resource.destroy_listener_list); wl_list_init(&surface->link); + wl_list_init(&surface->layer_link); wl_list_init(&surface->buffer_link); surface->surface.resource.client = NULL; @@ -600,6 +601,7 @@ weston_surface_unmap(struct weston_surface *surface) weston_surface_damage_below(surface); surface->output = NULL; wl_list_remove(&surface->link); + wl_list_remove(&surface->layer_link); weston_compositor_repick(surface->compositor); weston_compositor_schedule_repaint(surface->compositor); } @@ -808,37 +810,15 @@ out: pixman_region32_fini(&repaint); } -WL_EXPORT struct wl_list * -weston_compositor_top(struct weston_compositor *compositor) -{ - struct weston_input_device *input_device; - struct wl_list *list; - - input_device = (struct weston_input_device *) compositor->input_device; - - /* Insert below pointer */ - list = &compositor->surface_list; - if (compositor->fade.surface && - list->next == &compositor->fade.surface->link) - list = list->next; - if (list->next == &input_device->sprite->link) - list = list->next; - if (input_device->drag_surface && - list->next == &input_device->drag_surface->link) - list = list->next; - - return list; -} - -static void -weston_surface_raise(struct weston_surface *surface) +WL_EXPORT void +weston_surface_restack(struct weston_surface *surface, struct wl_list *below) { struct weston_compositor *compositor = surface->compositor; - struct wl_list *list = weston_compositor_top(compositor); - wl_list_remove(&surface->link); - wl_list_insert(list, &surface->link); + wl_list_remove(&surface->layer_link); + wl_list_insert(below, &surface->layer_link); weston_compositor_repick(compositor); + weston_surface_damage_below(surface); weston_surface_damage(surface); } @@ -912,6 +892,7 @@ weston_output_repaint(struct weston_output *output, int msecs) { struct weston_compositor *ec = output->compositor; struct weston_surface *es; + struct weston_layer *layer; struct weston_animation *animation, *next; struct weston_frame_callback *cb, *cnext; pixman_region32_t opaque, new_damage, output_damage; @@ -925,10 +906,14 @@ weston_output_repaint(struct weston_output *output, int msecs) output->border.top + output->border.bottom; glViewport(0, 0, width, height); - wl_list_for_each(es, &ec->surface_list, link) - /* Update surface transform now to avoid calling it ever - * again from the repaint sub-functions. */ - weston_surface_update_transform(es); + /* Rebuild the surface list and update surface transforms up front. */ + wl_list_init(&ec->surface_list); + wl_list_for_each(layer, &ec->layer_list, link) { + wl_list_for_each(es, &layer->surface_list, layer_link) { + weston_surface_update_transform(es); + wl_list_insert(ec->surface_list.prev, &es->link); + } + } if (output->assign_planes) /* @@ -1002,6 +987,13 @@ weston_output_finish_frame(struct weston_output *output, int msecs) output->repaint_scheduled = 0; } +WL_EXPORT void +weston_layer_init(struct weston_layer *layer, struct wl_list *below) +{ + wl_list_init(&layer->surface_list); + wl_list_insert(below, &layer->link); +} + WL_EXPORT void weston_compositor_schedule_repaint(struct weston_compositor *compositor) { @@ -1041,7 +1033,8 @@ weston_compositor_fade(struct weston_compositor *compositor, float tint) surface = weston_surface_create(compositor); weston_surface_configure(surface, 0, 0, 8192, 8192); weston_surface_set_color(surface, 0.0, 0.0, 0.0, 0.0); - wl_list_insert(&compositor->surface_list, &surface->link); + wl_list_insert(&compositor->fade_layer.surface_list, + &surface->layer_link); weston_surface_assign_output(surface); compositor->fade.surface = surface; pixman_region32_init(&surface->input); @@ -1489,7 +1482,6 @@ WL_EXPORT void weston_surface_activate(struct weston_surface *surface, struct weston_input_device *device, uint32_t time) { - weston_surface_raise(surface); wl_input_device_set_keyboard_focus(&device->input_device, &surface->surface, time); wl_data_device_set_keyboard_focus(&device->input_device); @@ -1814,13 +1806,14 @@ input_device_attach(struct wl_client *client, if (!buffer_resource && device->sprite->output) { wl_list_remove(&device->sprite->link); + wl_list_remove(&device->sprite->layer_link); device->sprite->output = NULL; return; } if (!device->sprite->output) { - wl_list_insert(&compositor->surface_list, - &device->sprite->link); + wl_list_insert(&compositor->cursor_layer.surface_list, + &device->sprite->layer_link); weston_surface_assign_output(device->sprite); } @@ -1924,8 +1917,8 @@ weston_input_update_drag_surface(struct wl_input_device *input_device, if (device->drag_surface->output == NULL && device->drag_surface->buffer) { - wl_list_insert(&device->sprite->link, - &device->drag_surface->link); + wl_list_insert(&device->sprite->layer_link, + &device->drag_surface->layer_link); weston_surface_assign_output(device->drag_surface); empty_region(&device->drag_surface->input); } @@ -2270,6 +2263,7 @@ weston_compositor_init(struct weston_compositor *ec, struct wl_display *display) ec->bind_display(ec->display, ec->wl_display); wl_list_init(&ec->surface_list); + wl_list_init(&ec->layer_list); wl_list_init(&ec->input_device_list); wl_list_init(&ec->output_list); wl_list_init(&ec->binding_list); @@ -2278,6 +2272,9 @@ weston_compositor_init(struct weston_compositor *ec, struct wl_display *display) ec->fade.animation.frame = fade_frame; wl_list_init(&ec->fade.animation.link); + weston_layer_init(&ec->fade_layer, &ec->layer_list); + weston_layer_init(&ec->cursor_layer, &ec->fade_layer.link); + ec->screenshooter = screenshooter_create(ec); wl_data_device_manager_init(ec->wl_display); diff --git a/src/compositor.h b/src/compositor.h index 9f29c4b5..d0b7206d 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -163,6 +163,11 @@ enum { struct screenshooter; +struct weston_layer { + struct wl_list surface_list; + struct wl_list link; +}; + struct weston_compositor { struct wl_shm *shm; struct weston_xserver *wxs; @@ -181,8 +186,12 @@ struct weston_compositor { /* There can be more than one, but not right now... */ struct wl_input_device *input_device; + struct weston_layer fade_layer; + struct weston_layer cursor_layer; + struct wl_list output_list; struct wl_list input_device_list; + struct wl_list layer_list; struct wl_list surface_list; struct wl_list binding_list; struct wl_list animation_list; @@ -267,6 +276,7 @@ struct weston_surface { pixman_region32_t input; int32_t pitch; struct wl_list link; + struct wl_list layer_link; struct wl_list buffer_link; struct weston_shader *shader; GLfloat color[4]; @@ -371,6 +381,9 @@ void notify_touch(struct wl_input_device *device, uint32_t time, int touch_id, int x, int y, int touch_type); +void +weston_layer_init(struct weston_layer *layer, struct wl_list *below); + void weston_output_finish_frame(struct weston_output *output, int msecs); void @@ -423,6 +436,9 @@ void weston_surface_configure(struct weston_surface *surface, GLfloat x, GLfloat y, int width, int height); +void +weston_surface_restack(struct weston_surface *surface, struct wl_list *below); + void weston_surface_set_position(struct weston_surface *surface, GLfloat x, GLfloat y); diff --git a/src/shell.c b/src/shell.c index accc1c56..6afdf3ae 100644 --- a/src/shell.c +++ b/src/shell.c @@ -42,6 +42,12 @@ struct wl_shell { struct weston_compositor *compositor; struct weston_shell shell; + struct weston_layer fullscreen_layer; + struct weston_layer panel_layer; + struct weston_layer toplevel_layer; + struct weston_layer background_layer; + struct weston_layer lock_layer; + struct { struct weston_process process; struct wl_client *client; @@ -56,7 +62,6 @@ struct wl_shell { struct shell_surface *lock_surface; struct wl_listener lock_surface_listener; - struct wl_list hidden_surface_list; struct wl_list backgrounds; struct wl_list panels; @@ -545,11 +550,15 @@ shell_configure_fullscreen(struct shell_surface *shsurf) center_on_output(surface, output); if (!shsurf->fullscreen.black_surface) - shsurf->fullscreen.black_surface = create_black_surface(surface->compositor, - output->x, output->y, - output->current->width, output->current->height); - wl_list_remove(&shsurf->fullscreen.black_surface->link); - wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link); + shsurf->fullscreen.black_surface = + create_black_surface(surface->compositor, + output->x, output->y, + output->current->width, + output->current->height); + + wl_list_remove(&shsurf->fullscreen.black_surface->layer_link); + wl_list_insert(&surface->layer_link, + &shsurf->fullscreen.black_surface->layer_link); shsurf->fullscreen.black_surface->output = output; switch (shsurf->fullscreen.type) { @@ -580,22 +589,17 @@ shell_stack_fullscreen(struct shell_surface *shsurf) { struct weston_surface *surface = shsurf->surface; struct wl_shell *shell = shell_surface_get_shell(shsurf); - struct wl_list *list; - wl_list_remove(&surface->link); - wl_list_remove(&shsurf->fullscreen.black_surface->link); + wl_list_remove(&surface->layer_link); + wl_list_remove(&shsurf->fullscreen.black_surface->layer_link); - if (shell->locked) { - wl_list_insert(&shell->hidden_surface_list, &surface->link); - wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link); - } else { - list = weston_compositor_top(surface->compositor); - wl_list_insert(list, &surface->link); - wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link); + wl_list_insert(&shell->fullscreen_layer.surface_list, + &surface->layer_link); + wl_list_insert(&surface->layer_link, + &shsurf->fullscreen.black_surface->layer_link); - weston_surface_damage(surface); - weston_surface_damage(shsurf->fullscreen.black_surface); - } + weston_surface_damage(surface); + weston_surface_damage(shsurf->fullscreen.black_surface); } static void @@ -902,12 +906,12 @@ show_screensaver(struct wl_shell *shell, struct shell_surface *surface) struct wl_list *list; if (shell->lock_surface) - list = &shell->lock_surface->surface->link; + list = &shell->lock_surface->surface->layer_link; else - list = &shell->compositor->surface_list; + list = &shell->lock_layer.surface_list; - wl_list_remove(&surface->surface->link); - wl_list_insert(list, &surface->surface->link); + wl_list_remove(&surface->surface->layer_link); + wl_list_insert(list, &surface->surface->layer_link); surface->surface->output = surface->output; weston_surface_damage(surface->surface); } @@ -915,8 +919,8 @@ show_screensaver(struct wl_shell *shell, struct shell_surface *surface) static void hide_screensaver(struct wl_shell *shell, struct shell_surface *surface) { - wl_list_remove(&surface->surface->link); - wl_list_init(&surface->surface->link); + wl_list_remove(&surface->surface->layer_link); + wl_list_init(&surface->surface->layer_link); surface->surface->output = NULL; } @@ -937,7 +941,7 @@ desktop_shell_set_background(struct wl_client *client, wl_list_for_each(priv, &shell->backgrounds, link) { if (priv->output == output_resource->data) { priv->surface->output = NULL; - wl_list_remove(&priv->surface->link); + wl_list_remove(&priv->surface->layer_link); wl_list_remove(&priv->link); break; } @@ -975,7 +979,7 @@ desktop_shell_set_panel(struct wl_client *client, wl_list_for_each(priv, &shell->panels, link) { if (priv->output == output_resource->data) { priv->surface->output = NULL; - wl_list_remove(&priv->surface->link); + wl_list_remove(&priv->surface->layer_link); wl_list_remove(&priv->link); break; } @@ -1035,8 +1039,6 @@ desktop_shell_set_lock_surface(struct wl_client *client, static void resume_desktop(struct wl_shell *shell) { - struct weston_surface *surface; - struct wl_list *list; struct shell_surface *tmp; wl_list_for_each(tmp, &shell->screensaver.surfaces, link) @@ -1044,21 +1046,12 @@ resume_desktop(struct wl_shell *shell) terminate_screensaver(shell); - wl_list_for_each(surface, &shell->hidden_surface_list, link) - weston_surface_assign_output(surface); - - if (wl_list_empty(&shell->backgrounds)) { - list = &shell->compositor->surface_list; - } else { - struct shell_surface *background; - background = container_of(shell->backgrounds.prev, - struct shell_surface, link); - list = background->surface->link.prev; - } - - if (!wl_list_empty(&shell->hidden_surface_list)) - wl_list_insert_list(list, &shell->hidden_surface_list); - wl_list_init(&shell->hidden_surface_list); + wl_list_remove(&shell->lock_layer.link); + wl_list_insert(&shell->compositor->cursor_layer.link, + &shell->fullscreen_layer.link); + wl_list_insert(&shell->fullscreen_layer.link, + &shell->panel_layer.link); + wl_list_insert(&shell->panel_layer.link, &shell->toplevel_layer.link); shell->locked = false; weston_compositor_repick(shell->compositor); @@ -1380,7 +1373,6 @@ activate(struct weston_shell *base, struct weston_surface *es, { struct wl_shell *shell = container_of(base, struct wl_shell, shell); struct weston_compositor *compositor = shell->compositor; - struct wl_list *list; weston_surface_activate(es, device, time); @@ -1389,35 +1381,23 @@ activate(struct weston_shell *base, struct weston_surface *es, switch (get_shell_surface_type(es)) { case SHELL_SURFACE_BACKGROUND: - /* put background back to bottom */ - wl_list_remove(&es->link); - wl_list_insert(compositor->surface_list.prev, &es->link); - break; case SHELL_SURFACE_PANEL: - /* already put on top */ + case SHELL_SURFACE_LOCK: break; + case SHELL_SURFACE_SCREENSAVER: /* always below lock surface */ - if (shell->lock_surface) { - wl_list_remove(&es->link); - wl_list_insert(&shell->lock_surface->surface->link, - &es->link); - } + if (shell->lock_surface) + weston_surface_restack(es, + &shell->lock_surface->surface->layer_link); break; case SHELL_SURFACE_FULLSCREEN: /* should on top of panels */ break; default: - if (!shell->locked) { - list = weston_compositor_top(compositor); - - /* bring panel back to top */ - struct shell_surface *panel; - wl_list_for_each(panel, &shell->panels, link) { - wl_list_remove(&panel->surface->link); - wl_list_insert(list, &panel->surface->link); - } - } + weston_surface_restack(es, + &shell->toplevel_layer.surface_list); + break; } } @@ -1448,9 +1428,6 @@ static void lock(struct weston_shell *base) { struct wl_shell *shell = container_of(base, struct wl_shell, shell); - struct wl_list *surface_list = &shell->compositor->surface_list; - struct weston_surface *cur; - struct weston_surface *tmp; struct weston_input_device *device; struct shell_surface *shsurf; struct weston_output *output; @@ -1466,28 +1443,15 @@ lock(struct weston_shell *base) shell->locked = true; - /* Move all surfaces from compositor's list to our hidden list, - * except the background. This way nothing else can show or - * receive input events while we are locked. */ + /* Hide all surfaces by removing the fullscreen, panel and + * toplevel layers. This way nothing else can show or receive + * input events while we are locked. */ - if (!wl_list_empty(&shell->hidden_surface_list)) { - fprintf(stderr, - "%s: Assertion failed: hidden_surface_list is not empty.\n", - __func__); - } - - wl_list_for_each_safe(cur, tmp, surface_list, link) { - /* skip input device sprites, cur->surface is uninitialised */ - if (cur->surface.resource.client == NULL) - continue; - - if (get_shell_surface_type(cur) == SHELL_SURFACE_BACKGROUND) - continue; - - cur->output = NULL; - wl_list_remove(&cur->link); - wl_list_insert(shell->hidden_surface_list.prev, &cur->link); - } + wl_list_remove(&shell->panel_layer.link); + wl_list_remove(&shell->toplevel_layer.link); + wl_list_remove(&shell->fullscreen_layer.link); + wl_list_insert(&shell->compositor->cursor_layer.link, + &shell->lock_layer.link); launch_screensaver(shell); @@ -1555,24 +1519,14 @@ map(struct weston_shell *base, struct weston_surface *surface, { struct wl_shell *shell = container_of(base, struct wl_shell, shell); struct weston_compositor *compositor = shell->compositor; - struct wl_list *list; struct shell_surface *shsurf; enum shell_surface_type surface_type = SHELL_SURFACE_NONE; - int do_configure; int panel_height = 0; shsurf = get_shell_surface(surface); if (shsurf) surface_type = shsurf->type; - if (shell->locked) { - list = &shell->hidden_surface_list; - do_configure = 0; - } else { - list = weston_compositor_top(compositor); - do_configure = 1; - } - surface->geometry.width = width; surface->geometry.height = height; surface->geometry.dirty = 1; @@ -1615,19 +1569,19 @@ map(struct weston_shell *base, struct weston_surface *surface, switch (surface_type) { case SHELL_SURFACE_BACKGROUND: /* background always visible, at the bottom */ - wl_list_insert(compositor->surface_list.prev, &surface->link); - do_configure = 1; + wl_list_insert(&shell->background_layer.surface_list, + &surface->layer_link); break; case SHELL_SURFACE_PANEL: /* panel always on top, hidden while locked */ - wl_list_insert(list, &surface->link); + wl_list_insert(&shell->panel_layer.surface_list, + &surface->layer_link); break; case SHELL_SURFACE_LOCK: /* lock surface always visible, on top */ - wl_list_insert(&compositor->surface_list, &surface->link); - + wl_list_insert(&shell->lock_layer.surface_list, + &surface->layer_link); weston_compositor_wake(compositor); - do_configure = 1; break; case SHELL_SURFACE_SCREENSAVER: /* If locked, show it. */ @@ -1638,32 +1592,20 @@ map(struct weston_shell *base, struct weston_surface *surface, if (!shell->lock_surface) compositor->state = WESTON_COMPOSITOR_IDLE; } - do_configure = 0; break; case SHELL_SURFACE_FULLSCREEN: - do_configure = 1; - break; case SHELL_SURFACE_NONE: - do_configure = 0; break; default: - /* everything else just below the panel */ - if (!wl_list_empty(&shell->panels)) { - struct shell_surface *panel = - container_of(shell->panels.prev, - struct shell_surface, link); - wl_list_insert(&panel->surface->link, &surface->link); - } else { - wl_list_insert(list, &surface->link); - } + wl_list_insert(&shell->toplevel_layer.surface_list, + &surface->layer_link); + break; } - if (do_configure) { - weston_surface_assign_output(surface); - weston_compositor_repick(compositor); - if (surface_type == SHELL_SURFACE_MAXIMIZED) - surface->output = shsurf->output; - } + weston_surface_assign_output(surface); + weston_compositor_repick(compositor); + if (surface_type == SHELL_SURFACE_MAXIMIZED) + surface->output = shsurf->output; switch (surface_type) { case SHELL_SURFACE_TOPLEVEL: @@ -2054,11 +1996,17 @@ shell_init(struct weston_compositor *ec) shell->shell.configure = configure; shell->shell.destroy = shell_destroy; - wl_list_init(&shell->hidden_surface_list); wl_list_init(&shell->backgrounds); wl_list_init(&shell->panels); wl_list_init(&shell->screensaver.surfaces); + weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link); + weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link); + weston_layer_init(&shell->toplevel_layer, &shell->panel_layer.link); + weston_layer_init(&shell->background_layer, + &shell->toplevel_layer.link); + wl_list_init(&shell->lock_layer.surface_list); + shell_configuration(shell); if (wl_display_add_global(ec->wl_display, &wl_shell_interface, From c5fb9a7de99e43c8133bfee5b5f9cd68c3241dd4 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Thu, 1 Mar 2012 14:09:44 +0200 Subject: [PATCH 06/10] compositor: fix crash when a drag surface is destroyed during the drag This can happen for instance if the client that started the drag crashes. Weston would crash because of the invalid surface pointed by device->drag_surface. Fix this by reseting the drag surface to nil on a destroy listener. --- src/compositor.c | 17 +++++++++++++++++ src/compositor.h | 1 + 2 files changed, 18 insertions(+) diff --git a/src/compositor.c b/src/compositor.c index 95513da1..fe945233 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1832,6 +1832,18 @@ const static struct wl_input_device_interface input_device_interface = { input_device_attach, }; +static void +handle_drag_surface_destroy(struct wl_listener *listener, + struct wl_resource *resource, uint32_t time) +{ + struct weston_input_device *device; + + device = container_of(listener, struct weston_input_device, + drag_surface_destroy_listener); + + device->drag_surface = NULL; +} + static void unbind_input_device(struct wl_resource *resource) { wl_list_remove(&resource->link); @@ -1868,6 +1880,8 @@ weston_input_device_init(struct weston_input_device *device, device->modifier_state = 0; device->num_tp = 0; + device->drag_surface_destroy_listener.func = handle_drag_surface_destroy; + wl_list_insert(ec->input_device_list.prev, &device->link); } @@ -1902,6 +1916,7 @@ weston_input_update_drag_surface(struct wl_input_device *input_device, if (!input_device->drag_surface || surface_changed) { undef_region(&device->drag_surface->input); + wl_list_remove(&device->drag_surface_destroy_listener.link); device->drag_surface = NULL; if (!surface_changed) return; @@ -1913,6 +1928,8 @@ weston_input_update_drag_surface(struct wl_input_device *input_device, weston_surface_set_position(device->drag_surface, input_device->x, input_device->y); + wl_list_insert(device->drag_surface->surface.resource.destroy_listener_list.prev, + &device->drag_surface_destroy_listener.link); } if (device->drag_surface->output == NULL && diff --git a/src/compositor.h b/src/compositor.h index d0b7206d..6f462493 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -107,6 +107,7 @@ struct weston_input_device { struct weston_compositor *compositor; struct weston_surface *sprite; struct weston_surface *drag_surface; + struct wl_listener drag_surface_destroy_listener; int32_t hotspot_x, hotspot_y; struct wl_list link; uint32_t modifier_state; From 3e3bb3216ed0dd5ac35162b91cdd3d0fe3f0e037 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Thu, 1 Mar 2012 14:09:44 +0200 Subject: [PATCH 07/10] compositor: split drag surface update into smaller functions --- src/compositor.c | 58 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index fe945233..c4bdf251 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1897,6 +1897,42 @@ weston_input_device_release(struct weston_input_device *device) wl_input_device_release(&device->input_device); } +static void +device_setup_new_drag_surface(struct weston_input_device *device, + struct weston_surface *surface) +{ + struct wl_input_device *input_device = &device->input_device; + + device->drag_surface = surface; + + weston_surface_set_position(device->drag_surface, + input_device->x, input_device->y); + + wl_list_insert(surface->surface.resource.destroy_listener_list.prev, + &device->drag_surface_destroy_listener.link); +} + +static void +device_release_drag_surface(struct weston_input_device *device) +{ + undef_region(&device->drag_surface->input); + wl_list_remove(&device->drag_surface_destroy_listener.link); + device->drag_surface = NULL; +} + +static void +device_map_drag_surface(struct weston_input_device *device) +{ + if (device->drag_surface->output || + !device->drag_surface->buffer) + return; + + wl_list_insert(&device->sprite->layer_link, + &device->drag_surface->layer_link); + weston_surface_assign_output(device->drag_surface); + empty_region(&device->drag_surface->input); +} + static void weston_input_update_drag_surface(struct wl_input_device *input_device, int dx, int dy) @@ -1915,30 +1951,20 @@ weston_input_update_drag_surface(struct wl_input_device *input_device, surface_changed = 1; if (!input_device->drag_surface || surface_changed) { - undef_region(&device->drag_surface->input); - wl_list_remove(&device->drag_surface_destroy_listener.link); - device->drag_surface = NULL; + device_release_drag_surface(device); if (!surface_changed) return; } if (!device->drag_surface || surface_changed) { - device->drag_surface = (struct weston_surface *) + struct weston_surface *surface = (struct weston_surface *) input_device->drag_surface; - - weston_surface_set_position(device->drag_surface, - input_device->x, input_device->y); - wl_list_insert(device->drag_surface->surface.resource.destroy_listener_list.prev, - &device->drag_surface_destroy_listener.link); + device_setup_new_drag_surface(device, surface); } - if (device->drag_surface->output == NULL && - device->drag_surface->buffer) { - wl_list_insert(&device->sprite->layer_link, - &device->drag_surface->layer_link); - weston_surface_assign_output(device->drag_surface); - empty_region(&device->drag_surface->input); - } + /* the client may not have attached a buffer to the drag surface + * when we setup it up, so check if map is needed on every update */ + device_map_drag_surface(device); /* the client may have attached a buffer with a different size to * the drag surface, causing the input region to be reset */ From 867dec7ff09e1060f9b45e284bd809c06e2193f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Thu, 1 Mar 2012 17:09:37 -0500 Subject: [PATCH 08/10] compositor: Post keyboard leave before destroying surface We may want to move this into wayland-server. --- src/compositor.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/compositor.c b/src/compositor.c index c4bdf251..09519b78 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -598,11 +598,18 @@ weston_compositor_repick(struct weston_compositor *compositor) static void weston_surface_unmap(struct weston_surface *surface) { + struct wl_input_device *device = surface->compositor->input_device; + weston_surface_damage_below(surface); surface->output = NULL; wl_list_remove(&surface->link); wl_list_remove(&surface->layer_link); weston_compositor_repick(surface->compositor); + + if (device->keyboard_focus == &surface->surface) + wl_input_device_set_keyboard_focus(device, NULL, + weston_compositor_get_time()); + weston_compositor_schedule_repaint(surface->compositor); } From 525696851ebe96ab4a2b0e5529705454c5a1a5f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Thu, 1 Mar 2012 17:10:25 -0500 Subject: [PATCH 09/10] compositor: Damage sprite surface on attach Normally the client is responsible for damaging the surface after attach, but the sprite surface is an internal surface. --- src/compositor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compositor.c b/src/compositor.c index 09519b78..0c99a5f4 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1833,6 +1833,7 @@ input_device_attach(struct wl_client *client, buffer->width, buffer->height); weston_buffer_attach(buffer, &device->sprite->surface); + weston_surface_damage(device->sprite); } const static struct wl_input_device_interface input_device_interface = { From 32bed57d5a27aee6ba6df1a5b101f5fbd1af44b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Thu, 1 Mar 2012 17:11:36 -0500 Subject: [PATCH 10/10] shell: Don't launch a new screensaver if the old one is still running --- src/shell.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shell.c b/src/shell.c index 6afdf3ae..2b61202c 100644 --- a/src/shell.c +++ b/src/shell.c @@ -885,6 +885,11 @@ launch_screensaver(struct wl_shell *shell) if (!shell->screensaver.path) return; + if (shell->screensaver.process.pid != 0) { + fprintf(stderr, "old screensaver still running\n"); + return; + } + weston_client_launch(shell->compositor, &shell->screensaver.process, shell->screensaver.path,