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 <ppaalanen@gmail.com>
This commit is contained in:
Pekka Paalanen 2011-12-01 10:42:22 +02:00
parent 696f959a4b
commit 9826223a1b

View file

@ -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 */
}