From 9826223a1bd7a3629986a1e9bcc6d57d19d905f2 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 1 Dec 2011 10:42:22 +0200 Subject: [PATCH] shell: handle surface type reassignment So far nothing prevented a client for registering a surface as one type and then as another type. With some special types, this would lead to corrupted wl_lists. Add a function, that either resets the surface type or posts an error to the client. In case of an error, the set type operation must be aborted. Change the type name SHELL_SURFACE_NORMAL to SHELL_SURFACE_NONE, as there is nothing normal in the "none" type which just means uninitialised. Signed-off-by: Pekka Paalanen --- compositor/shell.c | 70 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/compositor/shell.c b/compositor/shell.c index 395d5455..35723300 100644 --- a/compositor/shell.c +++ b/compositor/shell.c @@ -59,7 +59,7 @@ struct wl_shell { }; enum shell_surface_type { - SHELL_SURFACE_NORMAL, + SHELL_SURFACE_NONE, SHELL_SURFACE_PANEL, SHELL_SURFACE_BACKGROUND, @@ -288,22 +288,47 @@ shell_surface_resize(struct wl_client *client, struct wl_resource *resource, wl_resource_post_no_memory(resource); } +static int +reset_shell_surface_type(struct shell_surface *surface) +{ + switch (surface->type) { + case SHELL_SURFACE_FULLSCREEN: + surface->surface->x = surface->saved_x; + surface->surface->y = surface->saved_y; + surface->surface->fullscreen_output = NULL; + break; + case SHELL_SURFACE_PANEL: + case SHELL_SURFACE_BACKGROUND: + wl_list_remove(&surface->link); + wl_list_init(&surface->link); + break; + case SHELL_SURFACE_LOCK: + wl_resource_post_error(&surface->resource, + WL_DISPLAY_ERROR_INVALID_METHOD, + "cannot reassign lock surface type"); + return -1; + case SHELL_SURFACE_NONE: + case SHELL_SURFACE_TOPLEVEL: + case SHELL_SURFACE_TRANSIENT: + break; + } + + surface->type = SHELL_SURFACE_NONE; + return 0; +} + static void shell_surface_set_toplevel(struct wl_client *client, struct wl_resource *resource) { - struct shell_surface *shsurf = resource->data; - struct wlsc_surface *es = shsurf->surface; + struct shell_surface *surface = resource->data; - if (shsurf->type == SHELL_SURFACE_FULLSCREEN) { - es->x = shsurf->saved_x; - es->y = shsurf->saved_y; - } + if (reset_shell_surface_type(surface)) + return; - wlsc_surface_damage(es); - shsurf->type = SHELL_SURFACE_TOPLEVEL; - es->fullscreen_output = NULL; + wlsc_surface_damage(surface->surface); + surface->type = SHELL_SURFACE_TOPLEVEL; } static void @@ -317,6 +342,9 @@ shell_surface_set_transient(struct wl_client *client, struct shell_surface *pshsurf = parent_resource->data; struct wlsc_surface *pes = pshsurf->surface; + if (reset_shell_surface_type(shsurf)) + return; + /* assign to parents output */ es->output = pes->output; @@ -336,6 +364,9 @@ shell_surface_set_fullscreen(struct wl_client *client, struct wlsc_surface *es = shsurf->surface; struct wlsc_output *output; + if (reset_shell_surface_type(shsurf)) + return; + /* FIXME: Fullscreen on first output */ /* FIXME: Handle output going away */ output = container_of(es->compositor->output_list.next, @@ -438,7 +469,7 @@ shell_get_shell_surface(struct wl_client *client, /* init link so its safe to always remove it in destroy_shell_surface */ wl_list_init(&shsurf->link); - shsurf->type = SHELL_SURFACE_NORMAL; + shsurf->type = SHELL_SURFACE_NONE; wl_client_add_resource(client, &shsurf->resource); } @@ -458,6 +489,9 @@ desktop_shell_set_background(struct wl_client *client, struct wlsc_surface *surface = shsurf->surface; struct shell_surface *priv; + if (reset_shell_surface_type(shsurf)) + return; + wl_list_for_each(priv, &shell->backgrounds, link) { if (priv->output == output_resource->data) { priv->surface->output = NULL; @@ -493,6 +527,9 @@ desktop_shell_set_panel(struct wl_client *client, struct wlsc_surface *surface = shsurf->surface; struct shell_surface *priv; + if (reset_shell_surface_type(shsurf)) + return; + wl_list_for_each(priv, &shell->panels, link) { if (priv->output == output_resource->data) { priv->surface->output = NULL; @@ -534,13 +571,17 @@ desktop_shell_set_lock_surface(struct wl_client *client, struct wl_resource *surface_resource) { struct wl_shell *shell = resource->data; + struct shell_surface *surface = surface_resource->data; + + if (reset_shell_surface_type(surface)) + return; shell->prepare_event_sent = false; if (!shell->locked) return; - shell->lock_surface = surface_resource->data; + shell->lock_surface = surface; shell->lock_surface_listener.func = handle_lock_surface_destroy; wl_list_insert(&surface_resource->destroy_listener_list, @@ -603,7 +644,7 @@ get_shell_surface_type(struct wlsc_surface *surface) shsurf = get_shell_surface(surface); if (!shsurf) - return SHELL_SURFACE_NORMAL; + return SHELL_SURFACE_NONE; return shsurf->type; } @@ -945,6 +986,9 @@ screensaver_set_surface(struct wl_client *client, struct shell_surface *surface = shell_surface_resource->data; struct wlsc_output *output = output_resource->data; + if (reset_shell_surface_type(surface)) + return; + /* TODO */ }