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>
diff --git a/compositor/shell.c b/compositor/shell.c
index 395d545..3572330 100644
--- a/compositor/shell.c
+++ b/compositor/shell.c
@@ -59,7 +59,7 @@
};
enum shell_surface_type {
- SHELL_SURFACE_NORMAL,
+ SHELL_SURFACE_NONE,
SHELL_SURFACE_PANEL,
SHELL_SURFACE_BACKGROUND,
@@ -288,22 +288,47 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
shsurf = get_shell_surface(surface);
if (!shsurf)
- return SHELL_SURFACE_NORMAL;
+ return SHELL_SURFACE_NONE;
return shsurf->type;
}
@@ -945,6 +986,9 @@
struct shell_surface *surface = shell_surface_resource->data;
struct wlsc_output *output = output_resource->data;
+ if (reset_shell_surface_type(surface))
+ return;
+
/* TODO */
}